windows-development-sandbox 1.11.7 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +12 -6
  2. package/config.example.json +4 -3
  3. package/dist/app/features/apps/apps-rows.d.ts +4 -1
  4. package/dist/app/features/apps/apps-rows.js +7 -2
  5. package/dist/app/features/apps/apps.def.d.ts +19 -0
  6. package/dist/app/features/apps/apps.def.js +49 -12
  7. package/dist/app/features/apps/apps.run.d.ts +2 -0
  8. package/dist/app/features/apps/apps.run.js +1 -1
  9. package/dist/app/features/audit/audit.def.d.ts +341 -0
  10. package/dist/app/features/audit/audit.def.js +454 -0
  11. package/dist/app/features/audit/audit.run.d.ts +107 -0
  12. package/dist/app/features/audit/audit.run.js +133 -0
  13. package/dist/app/features/audit/index.d.ts +2 -0
  14. package/dist/app/features/audit/index.js +3 -0
  15. package/dist/app/features/defs.d.ts +194 -1
  16. package/dist/app/features/defs.js +4 -0
  17. package/dist/app/features/settings/settings.run.d.ts +3 -0
  18. package/dist/app/features/settings/settings.run.js +16 -2
  19. package/dist/app/kernel/define.d.ts +12 -1
  20. package/dist/app/registry.js +2 -0
  21. package/dist/cli/args.d.ts +0 -3
  22. package/dist/cli/args.js +3 -4
  23. package/dist/cli/commands/index.d.ts +1 -1
  24. package/dist/cli/commands/index.js +1 -1
  25. package/dist/cli/commands/launch/prepare.js +1 -1
  26. package/dist/cli/commands/maintenance/index.d.ts +0 -1
  27. package/dist/cli/commands/maintenance/index.js +0 -1
  28. package/dist/cli/commands/registry.js +1 -2
  29. package/dist/cli/manifest.d.ts +0 -41
  30. package/dist/cli/manifest.js +0 -14
  31. package/dist/cli/menu/pages/apps-page.js +2 -15
  32. package/dist/cli/menu/pages/maintenance-page.d.ts +4 -0
  33. package/dist/cli/menu/pages/maintenance-page.js +51 -8
  34. package/dist/cli/menu/views.js +2 -0
  35. package/dist/core/config/defaults.js +1 -1
  36. package/dist/core/schema/apps.d.ts +9 -0
  37. package/dist/core/schema/apps.js +9 -0
  38. package/dist/core/schema/config.d.ts +1 -0
  39. package/dist/core/schema/config.js +3 -3
  40. package/dist/core/schema/sandbox.d.ts +1 -0
  41. package/dist/core/schema/sandbox.js +11 -3
  42. package/dist/guest/apps/app-installer.js +50 -4
  43. package/dist/guest/apps/index.d.ts +1 -1
  44. package/dist/guest/apps/index.js +1 -1
  45. package/dist/guest/apps/sources.js +1 -1
  46. package/dist/guest/audit/parse.d.ts +32 -2
  47. package/dist/guest/audit/parse.js +43 -5
  48. package/dist/guest/audit/process-audit.d.ts +3 -1
  49. package/dist/guest/audit/process-audit.js +9 -6
  50. package/dist/guest/boot/boot.js +12 -3
  51. package/dist/guest/boot/guide.d.ts +1 -1
  52. package/dist/guest/boot/guide.js +27 -3
  53. package/dist/guest/daemon/sessions.d.ts +7 -0
  54. package/dist/guest/daemon/sessions.js +27 -2
  55. package/dist/guest/entries/daemon.js +2 -1
  56. package/dist/guest/setup/addon-mcp.d.ts +2 -0
  57. package/dist/guest/setup/addon-mcp.js +49 -0
  58. package/dist/guest/setup/agent-addons.d.ts +9 -0
  59. package/dist/guest/setup/agent-addons.js +22 -0
  60. package/dist/guest/setup/headroom.d.ts +7 -0
  61. package/dist/guest/setup/headroom.js +60 -0
  62. package/dist/guest/setup/managed-policy.d.ts +2 -1
  63. package/dist/guest/setup/managed-policy.js +15 -6
  64. package/dist/guest/toolchains/plan.js +8 -3
  65. package/dist/host/audit/attribute.d.ts +46 -0
  66. package/dist/host/audit/attribute.js +76 -0
  67. package/dist/host/audit/collect.d.ts +29 -3
  68. package/dist/host/audit/collect.js +256 -61
  69. package/dist/host/audit/git-commits.d.ts +29 -0
  70. package/dist/host/audit/git-commits.js +157 -0
  71. package/dist/host/audit/index.d.ts +5 -0
  72. package/dist/host/audit/index.js +6 -0
  73. package/dist/host/audit/log.d.ts +44 -7
  74. package/dist/host/audit/log.js +148 -45
  75. package/dist/host/audit/redact.d.ts +2 -0
  76. package/dist/host/audit/redact.js +67 -0
  77. package/dist/runtime/agent.js +110 -15
  78. package/dist/runtime/daemon.js +569 -316
  79. package/dist/runtime/db.js +110 -15
  80. package/dist/runtime/main.js +1011 -672
  81. package/dist/runtime/netproxy.js +110 -15
  82. package/dist/runtime/view.js +110 -15
  83. package/dist/selftest/app.test.js +25 -1
  84. package/dist/selftest/audit.test.js +354 -47
  85. package/dist/selftest/hcs.test.js +35 -0
  86. package/dist/selftest/menu-screens.js +1 -1
  87. package/dist/selftest/menu.test.js +3 -3
  88. package/dist/selftest/support/engine-golden.js +9 -0
  89. package/dist/selftest/support/fixtures.d.ts +1 -0
  90. package/dist/selftest/support/web-preview.js +94 -0
  91. package/dist/selftest/toolchains.test.js +147 -2
  92. package/dist/shared/apps/agent-addons.d.ts +64 -0
  93. package/dist/shared/apps/agent-addons.js +95 -0
  94. package/dist/shared/apps/catalogue.d.ts +33 -2
  95. package/dist/shared/apps/catalogue.js +102 -11
  96. package/dist/shared/apps/index.d.ts +3 -2
  97. package/dist/shared/apps/index.js +3 -2
  98. package/dist/shared/apps/selection.d.ts +2 -0
  99. package/dist/shared/apps/selection.js +7 -0
  100. package/dist/sync/watcher.js +9 -1
  101. package/dist/web/index.html +2 -2
  102. package/dist/web/{main-RQFN4WBY.css → main-UAQPI5XD.css} +1 -1
  103. package/dist/web/{main-K2JMCAZI.js → main-UD4QCXZR.js} +66 -66
  104. package/native/csharp/HcsHost/AssemblyInfo.cs +5 -3
  105. package/native/csharp/HcsHost/Hcs.cs +9 -0
  106. package/native/csharp/HcsHost/Program.cs +26 -1
  107. package/native/csharp/HcsHost/Share.cs +173 -0
  108. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  109. package/package.json +1 -1
  110. package/sandbox/addons/ccusage/package-lock.json +111 -0
  111. package/sandbox/addons/ccusage/package.json +7 -0
  112. package/sandbox/addons/context7/package-lock.json +1313 -0
  113. package/sandbox/addons/context7/package.json +7 -0
  114. package/sandbox/addons/headroom/requirements.in +1 -0
  115. package/sandbox/addons/headroom/requirements.txt +2922 -0
  116. package/sandbox/addons/playwright-mcp/package-lock.json +56 -0
  117. package/sandbox/addons/playwright-mcp/package.json +7 -0
  118. package/schemas/config.schema.json +13 -4
  119. package/schemas/sandbox-config.schema.json +2 -2
  120. package/dist/cli/commands/maintenance/audit.d.ts +0 -3
  121. package/dist/cli/commands/maintenance/audit.js +0 -58
@@ -1363,11 +1363,11 @@ var require_lodash = __commonJS({
1363
1363
  return isFunction(object2[key]);
1364
1364
  });
1365
1365
  }
1366
- function baseGet(object2, path75) {
1367
- path75 = castPath(path75, object2);
1368
- var index = 0, length = path75.length;
1366
+ function baseGet(object2, path77) {
1367
+ path77 = castPath(path77, object2);
1368
+ var index = 0, length = path77.length;
1369
1369
  while (object2 != null && index < length) {
1370
- object2 = object2[toKey(path75[index++])];
1370
+ object2 = object2[toKey(path77[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, path75, args) {
1435
- path75 = castPath(path75, object2);
1436
- object2 = parent(object2, path75);
1437
- var func = object2 == null ? object2 : object2[toKey(last(path75))];
1434
+ function baseInvoke(object2, path77, args) {
1435
+ path77 = castPath(path77, object2);
1436
+ object2 = parent(object2, path77);
1437
+ var func = object2 == null ? object2 : object2[toKey(last(path77))];
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(path75, srcValue) {
1594
- if (isKey(path75) && isStrictComparable(srcValue)) {
1595
- return matchesStrictComparable(toKey(path75), srcValue);
1593
+ function baseMatchesProperty(path77, srcValue) {
1594
+ if (isKey(path77) && isStrictComparable(srcValue)) {
1595
+ return matchesStrictComparable(toKey(path77), srcValue);
1596
1596
  }
1597
1597
  return function(object2) {
1598
- var objValue = get(object2, path75);
1599
- return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path75) : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
1598
+ var objValue = get(object2, path77);
1599
+ return objValue === undefined2 && objValue === srcValue ? hasIn(object2, path77) : 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, path75) {
1697
- return hasIn(object2, path75);
1696
+ return basePickBy(object2, paths, function(value, path77) {
1697
+ return hasIn(object2, path77);
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 path75 = paths[index], value = baseGet(object2, path75);
1704
- if (predicate(value, path75)) {
1705
- baseSet(result2, castPath(path75, object2), value);
1703
+ var path77 = paths[index], value = baseGet(object2, path77);
1704
+ if (predicate(value, path77)) {
1705
+ baseSet(result2, castPath(path77, object2), value);
1706
1706
  }
1707
1707
  }
1708
1708
  return result2;
1709
1709
  }
1710
- function basePropertyDeep(path75) {
1710
+ function basePropertyDeep(path77) {
1711
1711
  return function(object2) {
1712
- return baseGet(object2, path75);
1712
+ return baseGet(object2, path77);
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, path75, value, customizer) {
1786
+ function baseSet(object2, path77, value, customizer) {
1787
1787
  if (!isObject2(object2)) {
1788
1788
  return object2;
1789
1789
  }
1790
- path75 = castPath(path75, object2);
1791
- var index = -1, length = path75.length, lastIndex = length - 1, nested = object2;
1790
+ path77 = castPath(path77, object2);
1791
+ var index = -1, length = path77.length, lastIndex = length - 1, nested = object2;
1792
1792
  while (nested != null && ++index < length) {
1793
- var key = toKey(path75[index]), newValue = value;
1793
+ var key = toKey(path77[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(path75[index + 1]) ? [] : {};
1801
+ newValue = isObject2(objValue) ? objValue : isIndex(path77[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, path75) {
1968
- path75 = castPath(path75, object2);
1969
- var index = -1, length = path75.length;
1967
+ function baseUnset(object2, path77) {
1968
+ path77 = castPath(path77, object2);
1969
+ var index = -1, length = path77.length;
1970
1970
  if (!length) {
1971
1971
  return true;
1972
1972
  }
1973
1973
  while (++index < length) {
1974
- var key = toKey(path75[index]);
1974
+ var key = toKey(path77[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, path75);
1983
- return obj == null || delete obj[toKey(last(path75))];
1982
+ var obj = parent(object2, path77);
1983
+ return obj == null || delete obj[toKey(last(path77))];
1984
1984
  }
1985
- function baseUpdate(object2, path75, updater, customizer) {
1986
- return baseSet(object2, path75, updater(baseGet(object2, path75)), customizer);
1985
+ function baseUpdate(object2, path77, updater, customizer) {
1986
+ return baseSet(object2, path77, updater(baseGet(object2, path77)), 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, path75, hasFunc) {
2870
- path75 = castPath(path75, object2);
2871
- var index = -1, length = path75.length, result2 = false;
2869
+ function hasPath(object2, path77, hasFunc) {
2870
+ path77 = castPath(path77, object2);
2871
+ var index = -1, length = path77.length, result2 = false;
2872
2872
  while (++index < length) {
2873
- var key = toKey(path75[index]);
2873
+ var key = toKey(path77[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, path75) {
3076
- return path75.length < 2 ? object2 : baseGet(object2, baseSlice(path75, 0, -1));
3075
+ function parent(object2, path77) {
3076
+ return path77.length < 2 ? object2 : baseGet(object2, baseSlice(path77, 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, path75, args) {
3712
- var index = -1, isFunc = typeof path75 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3711
+ var invokeMap = baseRest(function(collection, path77, args) {
3712
+ var index = -1, isFunc = typeof path77 == "function", result2 = isArrayLike(collection) ? Array2(collection.length) : [];
3713
3713
  baseEach(collection, function(value) {
3714
- result2[++index] = isFunc ? apply(path75, value, args) : baseInvoke(value, path75, args);
3714
+ result2[++index] = isFunc ? apply(path77, value, args) : baseInvoke(value, path77, args);
3715
3715
  });
3716
3716
  return result2;
3717
3717
  });
@@ -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, path75, defaultValue) {
4367
- var result2 = object2 == null ? undefined2 : baseGet(object2, path75);
4366
+ function get(object2, path77, defaultValue) {
4367
+ var result2 = object2 == null ? undefined2 : baseGet(object2, path77);
4368
4368
  return result2 === undefined2 ? defaultValue : result2;
4369
4369
  }
4370
- function has(object2, path75) {
4371
- return object2 != null && hasPath(object2, path75, baseHas);
4370
+ function has(object2, path77) {
4371
+ return object2 != null && hasPath(object2, path77, baseHas);
4372
4372
  }
4373
- function hasIn(object2, path75) {
4374
- return object2 != null && hasPath(object2, path75, baseHasIn);
4373
+ function hasIn(object2, path77) {
4374
+ return object2 != null && hasPath(object2, path77, 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(path75) {
4428
- path75 = castPath(path75, object2);
4429
- isDeep || (isDeep = path75.length > 1);
4430
- return path75;
4427
+ paths = arrayMap(paths, function(path77) {
4428
+ path77 = castPath(path77, object2);
4429
+ isDeep || (isDeep = path77.length > 1);
4430
+ return path77;
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, path75) {
4457
- return predicate(value, path75[0]);
4456
+ return basePickBy(object2, props, function(value, path77) {
4457
+ return predicate(value, path77[0]);
4458
4458
  });
4459
4459
  }
4460
- function result(object2, path75, defaultValue) {
4461
- path75 = castPath(path75, object2);
4462
- var index = -1, length = path75.length;
4460
+ function result(object2, path77, defaultValue) {
4461
+ path77 = castPath(path77, object2);
4462
+ var index = -1, length = path77.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(path75[index])];
4468
+ var value = object2 == null ? undefined2 : object2[toKey(path77[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, path75, value) {
4478
- return object2 == null ? object2 : baseSet(object2, path75, value);
4477
+ function set2(object2, path77, value) {
4478
+ return object2 == null ? object2 : baseSet(object2, path77, value);
4479
4479
  }
4480
- function setWith(object2, path75, value, customizer) {
4480
+ function setWith(object2, path77, value, customizer) {
4481
4481
  customizer = typeof customizer == "function" ? customizer : undefined2;
4482
- return object2 == null ? object2 : baseSet(object2, path75, value, customizer);
4482
+ return object2 == null ? object2 : baseSet(object2, path77, 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, path75) {
4505
- return object2 == null ? true : baseUnset(object2, path75);
4504
+ function unset(object2, path77) {
4505
+ return object2 == null ? true : baseUnset(object2, path77);
4506
4506
  }
4507
- function update(object2, path75, updater) {
4508
- return object2 == null ? object2 : baseUpdate(object2, path75, castFunction(updater));
4507
+ function update(object2, path77, updater) {
4508
+ return object2 == null ? object2 : baseUpdate(object2, path77, castFunction(updater));
4509
4509
  }
4510
- function updateWith(object2, path75, updater, customizer) {
4510
+ function updateWith(object2, path77, updater, customizer) {
4511
4511
  customizer = typeof customizer == "function" ? customizer : undefined2;
4512
- return object2 == null ? object2 : baseUpdate(object2, path75, castFunction(updater), customizer);
4512
+ return object2 == null ? object2 : baseUpdate(object2, path77, 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(path75, srcValue) {
4899
- return baseMatchesProperty(path75, baseClone(srcValue, CLONE_DEEP_FLAG));
4898
+ function matchesProperty(path77, srcValue) {
4899
+ return baseMatchesProperty(path77, baseClone(srcValue, CLONE_DEEP_FLAG));
4900
4900
  }
4901
- var method = baseRest(function(path75, args) {
4901
+ var method = baseRest(function(path77, args) {
4902
4902
  return function(object2) {
4903
- return baseInvoke(object2, path75, args);
4903
+ return baseInvoke(object2, path77, args);
4904
4904
  };
4905
4905
  });
4906
4906
  var methodOf = baseRest(function(object2, args) {
4907
- return function(path75) {
4908
- return baseInvoke(object2, path75, args);
4907
+ return function(path77) {
4908
+ return baseInvoke(object2, path77, 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(path75) {
4956
- return isKey(path75) ? baseProperty(toKey(path75)) : basePropertyDeep(path75);
4955
+ function property(path77) {
4956
+ return isKey(path77) ? baseProperty(toKey(path77)) : basePropertyDeep(path77);
4957
4957
  }
4958
4958
  function propertyOf(object2) {
4959
- return function(path75) {
4960
- return object2 == null ? undefined2 : baseGet(object2, path75);
4959
+ return function(path77) {
4960
+ return object2 == null ? undefined2 : baseGet(object2, path77);
4961
4961
  };
4962
4962
  }
4963
4963
  var range = createRange();
@@ -5410,12 +5410,12 @@ var require_lodash = __commonJS({
5410
5410
  LazyWrapper.prototype.findLast = function(predicate) {
5411
5411
  return this.reverse().find(predicate);
5412
5412
  };
5413
- LazyWrapper.prototype.invokeMap = baseRest(function(path75, args) {
5414
- if (typeof path75 == "function") {
5413
+ LazyWrapper.prototype.invokeMap = baseRest(function(path77, args) {
5414
+ if (typeof path77 == "function") {
5415
5415
  return new LazyWrapper(this);
5416
5416
  }
5417
5417
  return this.map(function(value) {
5418
- return baseInvoke(value, path75, args);
5418
+ return baseInvoke(value, path77, args);
5419
5419
  });
5420
5420
  });
5421
5421
  LazyWrapper.prototype.reject = function(predicate) {
@@ -5532,8 +5532,8 @@ var require_lodash = __commonJS({
5532
5532
  });
5533
5533
 
5534
5534
  // src/guest/entries/main.ts
5535
- import fs61 from "node:fs";
5536
- import path74 from "node:path";
5535
+ import fs63 from "node:fs";
5536
+ import path76 from "node:path";
5537
5537
 
5538
5538
  // src/guest/runtime/paths.ts
5539
5539
  import path7 from "node:path";
@@ -6358,10 +6358,10 @@ function mergeDefs(...defs) {
6358
6358
  function cloneDef(schema) {
6359
6359
  return mergeDefs(schema._zod.def);
6360
6360
  }
6361
- function getElementAtPath(obj, path75) {
6362
- if (!path75)
6361
+ function getElementAtPath(obj, path77) {
6362
+ if (!path77)
6363
6363
  return obj;
6364
- return path75.reduce((acc, key) => acc?.[key], obj);
6364
+ return path77.reduce((acc, key) => acc?.[key], obj);
6365
6365
  }
6366
6366
  function promiseAllObject(promisesObj) {
6367
6367
  const keys = Object.keys(promisesObj);
@@ -6701,11 +6701,11 @@ function explicitlyAborted(x, startIndex = 0) {
6701
6701
  }
6702
6702
  return false;
6703
6703
  }
6704
- function prefixIssues(path75, issues) {
6704
+ function prefixIssues(path77, issues) {
6705
6705
  return issues.map((iss) => {
6706
6706
  var _a3;
6707
6707
  (_a3 = iss).path ?? (_a3.path = []);
6708
- iss.path.unshift(path75);
6708
+ iss.path.unshift(path77);
6709
6709
  return iss;
6710
6710
  });
6711
6711
  }
@@ -7155,16 +7155,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
7155
7155
  }
7156
7156
  function formatError(error62, mapper = (issue2) => issue2.message) {
7157
7157
  const fieldErrors = { _errors: [] };
7158
- const processError = (error63, path75 = []) => {
7158
+ const processError = (error63, path77 = []) => {
7159
7159
  for (const issue2 of error63.issues) {
7160
7160
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7161
- issue2.errors.map((issues) => processError({ issues }, [...path75, ...issue2.path]));
7161
+ issue2.errors.map((issues) => processError({ issues }, [...path77, ...issue2.path]));
7162
7162
  } else if (issue2.code === "invalid_key") {
7163
- processError({ issues: issue2.issues }, [...path75, ...issue2.path]);
7163
+ processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
7164
7164
  } else if (issue2.code === "invalid_element") {
7165
- processError({ issues: issue2.issues }, [...path75, ...issue2.path]);
7165
+ processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
7166
7166
  } else {
7167
- const fullpath = [...path75, ...issue2.path];
7167
+ const fullpath = [...path77, ...issue2.path];
7168
7168
  if (fullpath.length === 0) {
7169
7169
  fieldErrors._errors.push(mapper(issue2));
7170
7170
  } else {
@@ -7203,17 +7203,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
7203
7203
  }
7204
7204
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
7205
7205
  const result = { errors: [] };
7206
- const processError = (error63, path75 = []) => {
7206
+ const processError = (error63, path77 = []) => {
7207
7207
  var _a3;
7208
7208
  for (const issue2 of error63.issues) {
7209
7209
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7210
- issue2.errors.map((issues) => processError({ issues }, [...path75, ...issue2.path]));
7210
+ issue2.errors.map((issues) => processError({ issues }, [...path77, ...issue2.path]));
7211
7211
  } else if (issue2.code === "invalid_key") {
7212
- processError({ issues: issue2.issues }, [...path75, ...issue2.path]);
7212
+ processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
7213
7213
  } else if (issue2.code === "invalid_element") {
7214
- processError({ issues: issue2.issues }, [...path75, ...issue2.path]);
7214
+ processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
7215
7215
  } else {
7216
- const fullpath = [...path75, ...issue2.path];
7216
+ const fullpath = [...path77, ...issue2.path];
7217
7217
  if (fullpath.length === 0) {
7218
7218
  result.errors.push(mapper(issue2));
7219
7219
  continue;
@@ -7252,8 +7252,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
7252
7252
  }
7253
7253
  function toDotPath(_path) {
7254
7254
  const segs = [];
7255
- const path75 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7256
- for (const seg of path75) {
7255
+ const path77 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
7256
+ for (const seg of path77) {
7257
7257
  if (typeof seg === "number")
7258
7258
  segs.push(`[${seg}]`);
7259
7259
  else if (typeof seg === "symbol")
@@ -24355,13 +24355,13 @@ function resolveRef(ref, ctx) {
24355
24355
  if (!ref.startsWith("#")) {
24356
24356
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24357
24357
  }
24358
- const path75 = ref.slice(1).split("/").filter(Boolean);
24359
- if (path75.length === 0) {
24358
+ const path77 = ref.slice(1).split("/").filter(Boolean);
24359
+ if (path77.length === 0) {
24360
24360
  return ctx.rootSchema;
24361
24361
  }
24362
24362
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24363
- if (path75[0] === defsKey) {
24364
- const key = path75[1] === void 0 ? void 0 : decodeJSONPointerSegment(path75[1]);
24363
+ if (path77[0] === defsKey) {
24364
+ const key = path77[1] === void 0 ? void 0 : decodeJSONPointerSegment(path77[1]);
24365
24365
  if (!key || !ctx.defs[key]) {
24366
24366
  throw new Error(`Reference not found: ${ref}`);
24367
24367
  }
@@ -25534,14 +25534,19 @@ var NetworkSchema = external_exports.strictObject({
25534
25534
  });
25535
25535
  var AuditSchema = external_exports.strictObject({
25536
25536
  enabled: external_exports.boolean().describe(
25537
- "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."
25537
+ "Keep an audit log on this PC of what your agents did: programs started (with their command lines, secrets hidden), files changed in the projects, git commits, sessions, and what the repo guard caught, each linked to the agent session that did it where that can be known. The sandbox cannot change it. Read it with sandbox audit or on the Activity page."
25538
+ ),
25539
+ days: external_exports.number().int().min(1).max(365).describe(
25540
+ "Days the audit log is kept (1 to 30; a larger number keeps 30); older days are deleted when a sandbox starts and once a day."
25538
25541
  ),
25539
- days: external_exports.number().int().min(1).max(365).describe("Days the audit log is kept."),
25540
25542
  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."),
25541
25543
  processes: external_exports.boolean().describe(
25542
25544
  "Record every program started in the sandbox with its command line (Windows process auditing; repeated runs are counted, not listed)."
25543
25545
  ),
25544
- files: external_exports.boolean().describe("Record the files changed in the project while the sandbox runs.")
25546
+ files: external_exports.boolean().describe("Record the files changed in the projects while the sandbox runs."),
25547
+ commits: external_exports.boolean().describe(
25548
+ "Record the git commits made in the projects while the sandbox runs (read from each project's .git folder on this PC)."
25549
+ )
25545
25550
  });
25546
25551
  var WorkspaceFilterSchema = external_exports.strictObject({
25547
25552
  enabled: external_exports.boolean().describe(
@@ -25744,7 +25749,100 @@ var ToolchainsSchema = external_exports.strictObject({
25744
25749
 
25745
25750
  // src/shared/apps/catalogue.ts
25746
25751
  var gh = (github, asset) => ({ github, asset });
25752
+ var RTK_VERSION = "1.0.1";
25753
+ var RTK_URL = "https://github.com/rtk-ai/rtk/releases/download/v" + RTK_VERSION + "/rtk-oss-x86_64-pc-windows-msvc.zip";
25754
+ var RTK_SHA256 = "0e53e2eca471e15fbd3636e64e6bc0b182cbc278ed0339c80450a2dd03f4cd6b";
25755
+ var HEADROOM_VERSION = "0.41.0";
25756
+ var CCUSAGE_VERSION = "20.0.36";
25757
+ var PLAYWRIGHT_MCP_VERSION = "0.0.83";
25758
+ var CONTEXT7_MCP_VERSION = "4.4.2";
25747
25759
  var APPS = [
25760
+ // ---- agent add-ons
25761
+ {
25762
+ id: "rtk",
25763
+ name: "rtk (Rust Token Killer)",
25764
+ category: "agents",
25765
+ about: "Compacts the output of shell commands (git, tests, builds, ls ...) before the agent reads it, so it uses fewer tokens. Claude Code's Bash commands go through it on their own.",
25766
+ size: "6 MB",
25767
+ source: { url: RTK_URL, sha256: RTK_SHA256 },
25768
+ exe: "rtk.exe",
25769
+ cli: true,
25770
+ plugsInto: "Claude Code through a hook in the sandbox's managed settings; other agents are told to use it",
25771
+ userOnly: true
25772
+ },
25773
+ {
25774
+ id: "headroom",
25775
+ name: "Headroom",
25776
+ category: "agents",
25777
+ about: "Compresses what Claude Code sends to the model (tool output, logs, files) so it uses fewer tokens: a local proxy on 127.0.0.1:8787 that sits in Claude Code's API path, offline apart from forwarding to api.anthropic.com.",
25778
+ size: "150 MB",
25779
+ source: { locked: "uv", package: "headroom-ai", version: HEADROOM_VERSION },
25780
+ exe: "headroom.exe",
25781
+ service: true,
25782
+ plugsInto: "Claude Code: the sandbox starts the proxy and points Claude Code at it (managed settings)",
25783
+ userOnly: true
25784
+ },
25785
+ {
25786
+ id: "ccusage",
25787
+ name: "ccusage",
25788
+ category: "agents",
25789
+ about: "Reports the agents' token use and cost by day, month or session from their logs in the sandbox (`ccusage daily`; add --offline to skip fetching prices).",
25790
+ size: "5 MB",
25791
+ source: { locked: "npm", package: "ccusage", version: CCUSAGE_VERSION },
25792
+ exe: "ccusage.cmd",
25793
+ cli: true,
25794
+ plugsInto: "Reads Claude Code's session logs in the sandbox; changes nothing",
25795
+ userOnly: true
25796
+ },
25797
+ {
25798
+ id: "playwright-mcp",
25799
+ name: "Playwright MCP",
25800
+ category: "agents",
25801
+ about: "Lets Claude Code drive a browser (Microsoft Edge, already in the sandbox) to open pages, click, fill forms and take screenshots: the MCP server of microsoft/playwright-mcp.",
25802
+ size: "20 MB",
25803
+ source: { locked: "npm", package: "@playwright/mcp", version: PLAYWRIGHT_MCP_VERSION },
25804
+ exe: "playwright-mcp.cmd",
25805
+ service: true,
25806
+ mcp: { name: "sbx-playwright", script: "node_modules/@playwright/mcp/cli.js", args: ["--browser", "msedge"] },
25807
+ plugsInto: "Claude Code as the MCP server sbx-playwright (the sandbox's Claude settings)",
25808
+ userOnly: true
25809
+ },
25810
+ {
25811
+ id: "context7",
25812
+ name: "Context7 MCP",
25813
+ category: "agents",
25814
+ about: "Up-to-date documentation and code examples for libraries, looked up by Claude Code while it works (upstash/context7). The library names and questions go to Upstash's context7.com.",
25815
+ size: "55 MB",
25816
+ source: { locked: "npm", package: "@upstash/context7-mcp", version: CONTEXT7_MCP_VERSION },
25817
+ exe: "context7-mcp.cmd",
25818
+ service: true,
25819
+ mcp: { name: "sbx-context7", script: "node_modules/@upstash/context7-mcp/dist/index.js" },
25820
+ plugsInto: "Claude Code as the MCP server sbx-context7 (the sandbox's Claude settings)",
25821
+ userOnly: true
25822
+ },
25823
+ {
25824
+ id: "claude-mem",
25825
+ name: "claude-mem",
25826
+ category: "agents",
25827
+ about: "Persistent memory for Claude Code (a plugin you install on this PC): its database is brought into the sandbox.",
25828
+ size: "",
25829
+ source: { resolve: "setting" },
25830
+ exe: "",
25831
+ setting: "claudeProfile.syncClaudeMem",
25832
+ plugsInto: "Claude Code, with your Claude settings copied from this PC",
25833
+ userOnly: true
25834
+ },
25835
+ {
25836
+ id: "rea",
25837
+ name: "REA (Reverse Engineer Anything)",
25838
+ category: "agents",
25839
+ about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
25840
+ size: "8 MB",
25841
+ source: { npm: "rea-agents" },
25842
+ exe: "rea.cmd",
25843
+ cli: true,
25844
+ plugsInto: "Claude Code and Codex as an MCP server, after `rea setup`"
25845
+ },
25748
25846
  // ---- editors
25749
25847
  {
25750
25848
  id: "vscode",
@@ -26206,16 +26304,6 @@ var APPS = [
26206
26304
  cli: true
26207
26305
  },
26208
26306
  // ---- reverse engineering
26209
- {
26210
- id: "rea",
26211
- name: "REA (Reverse Engineer Anything)",
26212
- category: "reversing",
26213
- about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
26214
- size: "8 MB",
26215
- source: { npm: "rea-agents" },
26216
- exe: "rea.cmd",
26217
- cli: true
26218
- },
26219
26307
  {
26220
26308
  id: "ghidra",
26221
26309
  name: "Ghidra",
@@ -26528,13 +26616,87 @@ function appsToInstall(apps, gitAccess) {
26528
26616
  const needs7zip = allowed.some((e) => e.needs?.includes("7zip") || e.unpack === "nsis") && !allowed.some((e) => e.id === "7zip");
26529
26617
  return { entries: [...needs7zip ? [appById("7zip")] : [], ...allowed], skipped };
26530
26618
  }
26619
+ function appsNeedUv(apps) {
26620
+ return Boolean(
26621
+ apps?.install.some((id) => {
26622
+ const source = appById(id)?.source;
26623
+ return source !== void 0 && "locked" in source && source.locked === "uv";
26624
+ })
26625
+ );
26626
+ }
26531
26627
  function appsNeedMesa(apps) {
26532
26628
  return Boolean(apps?.install.some((id) => appById(id)?.needs?.includes("mesa")));
26533
26629
  }
26534
26630
 
26631
+ // src/shared/apps/agent-addons.ts
26632
+ function rtkHookCommand(exe) {
26633
+ return '"' + exe.replace(/\\/g, "/") + '" hook claude';
26634
+ }
26635
+ function claudeManagedSettings(deny, rtkExe, headroomUrl2 = null) {
26636
+ if (!deny.length && !rtkExe && !headroomUrl2) return null;
26637
+ return {
26638
+ ...deny.length ? { permissions: { deny } } : {},
26639
+ ...rtkExe ? { hooks: { PreToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command: rtkHookCommand(rtkExe) }] }] } } : {},
26640
+ ...headroomUrl2 ? { env: { ANTHROPIC_BASE_URL: headroomUrl2 } } : {}
26641
+ };
26642
+ }
26643
+ var RTK_GUIDE_LINE = "- rtk is on PATH and compacts command output: Claude Code's Bash commands go through it on their own; in other agents prefix shell commands with `rtk` (`rtk git status`, `rtk cargo test`, `rtk ls`).";
26644
+ var HEADROOM_PORT = 8787;
26645
+ var HEADROOM_UPSTREAM = "https://api.anthropic.com";
26646
+ function headroomUrl(port = HEADROOM_PORT) {
26647
+ return "http://127.0.0.1:" + port;
26648
+ }
26649
+ function headroomArgs(port = HEADROOM_PORT) {
26650
+ return [
26651
+ "proxy",
26652
+ "--host",
26653
+ "127.0.0.1",
26654
+ "--port",
26655
+ String(port),
26656
+ "--anthropic-api-url",
26657
+ HEADROOM_UPSTREAM,
26658
+ "--no-telemetry"
26659
+ ];
26660
+ }
26661
+ var HEADROOM_ENV = {
26662
+ HEADROOM_OFFLINE: "1",
26663
+ HEADROOM_TELEMETRY: "off",
26664
+ HEADROOM_BEACON: "off",
26665
+ HEADROOM_UPDATE_CHECK: "off",
26666
+ DO_NOT_TRACK: "1",
26667
+ HF_HUB_OFFLINE: "1",
26668
+ PYTHONIOENCODING: "utf-8"
26669
+ };
26670
+ var SECRET_NAME = /(KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)/i;
26671
+ function headroomEnv(base) {
26672
+ const env = {};
26673
+ for (const [name, value] of Object.entries(base))
26674
+ if (value !== void 0 && !SECRET_NAME.test(name) && !/^(ANTHROPIC|OPENAI|CLAUDE)_/i.test(name)) env[name] = value;
26675
+ return { ...env, ...HEADROOM_ENV };
26676
+ }
26677
+ function headroomGuideLine(logFile2) {
26678
+ return "- Headroom compresses Claude Code's requests: Claude Code reaches the API through its proxy on " + headroomUrl() + " (log: `" + logFile2 + "`). If Claude Code cannot reach the API, the proxy stopped: it starts again with the next sandbox, or turn Headroom off in Apps.";
26679
+ }
26680
+ function addonMcpServer(folder, mcp) {
26681
+ const script = folder.replace(/[\\/]+$/, "") + "\\" + mcp.script.replace(/\//g, "\\");
26682
+ return { type: "stdio", command: "node", args: [script, ...mcp.args ?? []], env: {} };
26683
+ }
26684
+ function withAddonMcpServers(current, servers, known) {
26685
+ const kept = Object.fromEntries(Object.entries(current).filter(([name]) => !known.includes(name) || name in servers));
26686
+ return { ...kept, ...servers };
26687
+ }
26688
+ function addonGuideLine(mcpNames, ccusage) {
26689
+ return [
26690
+ ...mcpNames.length ? ["- MCP servers in Claude Code from Apps: " + mcpNames.join(", ") + "."] : [],
26691
+ ...ccusage ? ["- ccusage is on PATH: `ccusage daily` (or `monthly`, `session`) reports token use and cost."] : []
26692
+ ];
26693
+ }
26694
+
26535
26695
  // src/core/schema/apps.ts
26536
26696
  var CATALOGUE_IDS = APPS.filter((a) => !a.setting).map((a) => a.id);
26537
26697
  var AppIdSchema = external_exports.enum(CATALOGUE_IDS);
26698
+ var PROJECT_IDS = APPS.filter((a) => !a.setting && !a.userOnly).map((a) => a.id);
26699
+ var ProjectAppIdSchema = external_exports.enum(PROJECT_IDS);
26538
26700
  var CustomAppIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, "lower-case letters, digits and - only");
26539
26701
  var compiles = (pattern) => {
26540
26702
  try {
@@ -26558,6 +26720,11 @@ var CustomAppSchema = external_exports.strictObject({
26558
26720
  }).refine((a) => a.github && a.asset ? !a.url : Boolean(a.url) && !a.github && !a.asset, {
26559
26721
  message: "give github + asset, or url (not both)"
26560
26722
  });
26723
+ var ProjectAppsSchema = external_exports.strictObject({
26724
+ install: external_exports.array(ProjectAppIdSchema).describe(
26725
+ "Apps from the catalogue this project adds to yours (agent add-ons such as rtk, Headroom and the MCP servers are set in your own settings only)."
26726
+ )
26727
+ });
26561
26728
  var AppsSchema = external_exports.strictObject({
26562
26729
  install: external_exports.array(AppIdSchema).describe(
26563
26730
  "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."
@@ -26722,8 +26889,8 @@ var LocalOverridesSchema = external_exports.strictObject({
26722
26889
  attach: AttachSchema.partial(),
26723
26890
  personalization: toggle("Copy your desktop look into the sandbox.").partial(),
26724
26891
  // Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add
26725
- // them.
26726
- apps: AppsSchema.pick({ install: true }).partial(),
26892
+ // them, nor agent add-ons that are yours only (rtk hooks every agent command, Headroom sits in its API path).
26893
+ apps: ProjectAppsSchema.partial(),
26727
26894
  claudeProfile: ClaudeProfileSchema.pick({
26728
26895
  enabled: true,
26729
26896
  overwrite: true,
@@ -27531,261 +27698,23 @@ function writeStatus(phase, message) {
27531
27698
  }
27532
27699
 
27533
27700
  // src/guest/boot/boot.ts
27534
- import fs60 from "node:fs";
27535
- import path73 from "node:path";
27536
- import { spawn as spawn9 } from "node:child_process";
27701
+ import fs62 from "node:fs";
27702
+ import path75 from "node:path";
27703
+ import { spawn as spawn10 } from "node:child_process";
27537
27704
 
27538
27705
  // src/guest/boot/guide.ts
27539
- import fs10 from "node:fs";
27540
- import path14 from "node:path";
27541
- var BEGIN = "<!-- agent-sandbox:begin (generated every boot, do not edit) -->";
27542
- var END = "<!-- agent-sandbox:end -->";
27543
- var mirrorLine = () => {
27544
- const drives = (session.substDrives ?? []).filter((d) => fs10.existsSync(d.letter + ":\\"));
27545
- if (!drives.length) return [];
27546
- return [
27547
- "- " + drives.map((d) => d.letter + ":").join(", ") + " = mapped folders at their PC paths (subst onto `" + drives.map((d) => d.target).join("`, `") + "`; real-path tools may print that form)."
27548
- ];
27549
- };
27550
- function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
27551
- return [
27552
- BEGIN,
27553
- "## Sandbox manifest \u2014 you are in a DISPOSABLE Windows Sandbox",
27554
- "Wiped on close: everything except the paths below (installers, winget/choco, C:\\Users, Program Files, registry).",
27555
- "- RW, persists: `" + workspace + "` = host folder " + session.workspaceHost,
27556
- // Projects started from other folders while this sandbox runs: every agent here can see them.
27557
- ...projects.map(
27558
- (p) => "- RW, persists: `" + p.guest + "` = host folder " + p.host + " (another project in this sandbox; your own is `%AGENT_WORKSPACE%`)"
27559
- ),
27560
- "- RW, persists: `" + toolsDir + "` (toolchains) \u2014 put portable exes in `" + path14.join(toolsDir, "bin") + "` (on PATH)",
27561
- "- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" + path14.join(dataDir, "logs") + "`",
27562
- "- RO: `" + launchDir + "` (this boot's scripts) \xB7 lost on close: everything else, incl. `C:\\nvm` (Node symlink)",
27563
- ...mirrorLine(),
27564
- "- Tools: " + toolSummary.join(" \xB7 "),
27565
- "- Persistent installs: `npm i -g` (per nvm version), `pip`, `cargo install`, `dotnet tool -g`, `uv tool`, `bun add -g`. Real installers must re-run each boot via a hook (ask the user).",
27566
- "- Mapped folders (workspace, C:\\AgentData) allow NO symlinks or junctions: pnpm runs hoisted (set), npm workspaces / `file:` deps and deno node_modules dirs fail there (use a folder on C:\\ outside them), bun cannot save its lockfile there (`bun install --no-save`).",
27567
- "- Network: " + (lan === "offline" ? "OFF" : lan === "blocked" ? "internet yes, host LAN blocked" : "internet yes, host LAN NOT blocked this time") + ". Other sessions may share this workspace; the user may be typing from the host.",
27568
- END
27569
- ].join("\n");
27570
- }
27571
- function upsertGuide(file3, guide) {
27572
- fs10.mkdirSync(path14.dirname(file3), { recursive: true });
27573
- const current = fs10.existsSync(file3) ? fs10.readFileSync(file3, "utf8") : "";
27574
- const start = current.indexOf(BEGIN);
27575
- const end = current.indexOf(END);
27576
- const without = start >= 0 && end > start ? current.slice(0, start) + current.slice(end + END.length) : current;
27577
- fs10.writeFileSync(file3, without.trimEnd() + (without.trim() ? "\n\n" : "") + guide + "\n", "utf8");
27578
- }
27579
- function managedClaudeMd() {
27580
- return path14.join(
27581
- process.env.AGENT_MANAGED_DIR ?? path14.join(process.env.ProgramFiles ?? "C:\\Program Files", "ClaudeCode"),
27582
- "CLAUDE.md"
27583
- );
27584
- }
27585
- function writeGuides(toolSummary, lan, projects = []) {
27586
- const guide = sandboxGuide(toolSummary, lan, projects);
27587
- const managed = managedClaudeMd();
27588
- fs10.mkdirSync(path14.dirname(managed), { recursive: true });
27589
- fs10.writeFileSync(managed, guide + "\n", "utf8");
27590
- fs10.writeFileSync(path14.join(dataDir, "SANDBOX.md"), guide + "\n", "utf8");
27591
- upsertGuide(path14.join(stateDir, "codex", "AGENTS.md"), guide);
27592
- upsertGuide(path14.join(stateDir, "gemini", ".gemini", "GEMINI.md"), guide);
27593
- removeGuide(path14.join(claudeDir, "CLAUDE.md"));
27594
- return managed;
27595
- }
27596
- var removeGuide = (file3) => {
27597
- if (!fs10.existsSync(file3)) return;
27598
- const current = fs10.readFileSync(file3, "utf8");
27599
- const start = current.indexOf(BEGIN);
27600
- const end = current.indexOf(END);
27601
- if (start >= 0 && end > start)
27602
- fs10.writeFileSync(file3, (current.slice(0, start) + current.slice(end + END.length)).trim() + "\n", "utf8");
27603
- };
27604
-
27605
- // src/guest/runtime/fs.ts
27606
- import fs11 from "node:fs";
27607
- function exists(p) {
27608
- return fs11.existsSync(p);
27609
- }
27610
- function mkdirp(p) {
27611
- fs11.mkdirSync(p, { recursive: true });
27612
- return p;
27613
- }
27614
-
27615
- // src/guest/toolchains/tool-env.ts
27616
- import path16 from "node:path";
27617
-
27618
- // src/guest/runtime/process.ts
27619
27706
  import fs12 from "node:fs";
27620
- import os4 from "node:os";
27621
- import path15 from "node:path";
27622
- import { spawnSync } from "node:child_process";
27623
- function exec(file3, args, options = {}) {
27624
- const result = spawnSync(file3, args, { stdio: "inherit", windowsHide: true, ...options });
27625
- if (result.error) throw result.error;
27626
- if (result.status !== 0)
27627
- throw new Error(path15.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + result.status);
27628
- }
27629
- async function execAsync(file3, args, options = {}) {
27630
- const code = await spawnAsync(file3, args, { stdio: "inherit", ...options });
27631
- if (code !== 0)
27632
- throw new Error(path15.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
27633
- }
27634
- function execOutput(file3, args, options = {}) {
27635
- const result = spawnSync(file3, args, { encoding: "utf8", windowsHide: true, ...options });
27636
- return result.status === 0 ? String(result.stdout ?? "").trim() : "";
27637
- }
27638
- function runScript(name, args = []) {
27639
- const result = spawnSync(SYSTEM.powershell(), scriptArgs(name, args), {
27640
- stdio: ["inherit", "inherit", "pipe"],
27641
- encoding: "utf8",
27642
- windowsHide: true
27643
- });
27644
- if (result.error) throw result.error;
27645
- const errors = String(result.stderr ?? "").trim();
27646
- if (errors) process.stderr.write(errors + "\n");
27647
- if (result.status !== 0)
27648
- throw new Error(name + " failed with exit code " + result.status + (errors ? ": " + errors.slice(0, 400) : ""));
27649
- }
27650
- function scriptOutput(name, args = [], options = {}) {
27651
- return execOutput(SYSTEM.powershell(), scriptArgs(name, args), options);
27652
- }
27653
- function runScriptWithJson(name, param, data, args = []) {
27654
- const dir = fs12.mkdtempSync(path15.join(os4.tmpdir(), "sbx-"));
27655
- const file3 = path15.join(dir, "input.json");
27656
- try {
27657
- fs12.writeFileSync(file3, JSON.stringify(data), "utf8");
27658
- runScript(name, ["-" + param, file3, ...args]);
27659
- } finally {
27660
- fs12.rmSync(dir, { recursive: true, force: true });
27661
- }
27662
- }
27663
- function robocopy(from, to, files = []) {
27664
- if (!isWin) {
27665
- if (!files.length) {
27666
- fs12.cpSync(from, to, { recursive: true });
27667
- return;
27668
- }
27669
- fs12.mkdirSync(to, { recursive: true });
27670
- for (const f of files.filter((f2) => fs12.existsSync(path15.join(from, f2))))
27671
- fs12.copyFileSync(path15.join(from, f), path15.join(to, f));
27672
- return;
27673
- }
27674
- const what = files.length ? files : ["/E"];
27675
- const passes = [
27676
- ["/MT:16", "/R:1", "/W:1"],
27677
- ["/MT:1", "/R:4", "/W:3"]
27678
- ];
27679
- let code = null;
27680
- let output3 = "";
27681
- for (const pass of passes) {
27682
- const result = spawnSync(
27683
- SYSTEM.robocopy(),
27684
- [
27685
- from,
27686
- to,
27687
- ...what,
27688
- ...files.length ? [] : [pass[0]],
27689
- pass[1],
27690
- pass[2],
27691
- "/NFL",
27692
- "/NDL",
27693
- "/NJH",
27694
- "/NJS",
27695
- "/NP",
27696
- "/XJ"
27697
- ],
27698
- { encoding: "utf8", windowsHide: true }
27699
- );
27700
- code = result.status;
27701
- output3 = String(result.stdout ?? "") + String(result.stderr ?? "");
27702
- if (!robocopyFailed(code)) return;
27703
- }
27704
- const why = robocopyErrors(output3);
27705
- throw new Error(
27706
- "robocopy " + from + " -> " + to + " failed (exit " + code + ": " + robocopyMeaning(code) + ")" + (why.length ? ": " + why.join(" | ") : "")
27707
- );
27708
- }
27709
- function copyNode(from, to) {
27710
- const work = stagingFolder(to);
27711
- try {
27712
- robocopy(from, work, ["node.exe", "npm", "npm.cmd", "npx", "npx.cmd"]);
27713
- robocopy(path15.join(from, "node_modules", "npm"), path15.join(work, "node_modules", "npm"));
27714
- moveIntoPlace(work, to);
27715
- } finally {
27716
- safeRemove(work, path15.dirname(work));
27717
- }
27718
- }
27719
-
27720
- // src/guest/toolchains/tool-env.ts
27721
- function emptyEnv() {
27722
- return { vars: {}, prepend: [], append: [], summary: [] };
27723
- }
27724
- var arch = process.arch === "arm64" ? "arm64" : "x64";
27725
- function tool(...parts2) {
27726
- return path16.join(toolsDir, ...parts2);
27727
- }
27728
- function versionOf(exe, args = ["--version"], options = {}) {
27729
- return /\d+\.\d+\.\d+\S*/.exec(execOutput(exe, args, options))?.[0] ?? "installed";
27730
- }
27731
-
27732
- // src/guest/apps/app-installer.ts
27733
- import fs16 from "node:fs";
27734
- import path21 from "node:path";
27735
-
27736
- // src/guest/apps/after-install.ts
27737
- import fs13 from "node:fs";
27738
27707
  import path17 from "node:path";
27739
- var SYSINTERNALS_TOOLS = [
27740
- "Process Explorer",
27741
- "Process Monitor",
27742
- "Autoruns",
27743
- "TCPView",
27744
- "PsExec",
27745
- "PsList",
27746
- "PsKill",
27747
- "Handle",
27748
- "ListDLLs",
27749
- "Sigcheck",
27750
- "Strings",
27751
- "VMMap",
27752
- "RAMMap",
27753
- "DebugView",
27754
- "Disk2vhd",
27755
- "Du",
27756
- "ZoomIt"
27757
- ];
27758
- async function afterInstall(entry, exe) {
27759
- const dir = path17.dirname(exe);
27760
- if (entry.needs?.includes("mesa")) {
27761
- const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
27762
- for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
27763
- if (exists(path17.join(mesa, dll)) && !exists(path17.join(dir, dll)))
27764
- fs13.copyFileSync(path17.join(mesa, dll), path17.join(dir, dll));
27765
- }
27766
- }
27767
- if (entry.id === "godot" && !exists(path17.join(dir, "._sc_"))) fs13.writeFileSync(path17.join(dir, "._sc_"), "");
27768
- if (entry.id === "sublime") mkdirp(path17.join(dir, "Data"));
27769
- if (entry.id === "sysinternals") {
27770
- for (const name of SYSINTERNALS_TOOLS) {
27771
- await execAsync(
27772
- SYSTEM.reg(),
27773
- ["add", "HKCU\\Software\\Sysinternals\\" + name, "/v", "EulaAccepted", "/t", "REG_DWORD", "/d", "1", "/f"],
27774
- { stdio: "ignore" }
27775
- ).catch(() => void 0);
27776
- }
27777
- }
27778
- }
27779
27708
 
27780
27709
  // src/guest/apps/find-exe.ts
27781
- import fs14 from "node:fs";
27782
- import path18 from "node:path";
27710
+ import fs10 from "node:fs";
27711
+ import path14 from "node:path";
27783
27712
  var MAX_DEPTH = 7;
27784
27713
  var MAX_ENTRIES = 5e4;
27785
27714
  var X64_FOLDER = /(^|[\\/])(amd64|x64|x86_64|win64)([\\/]|$)/i;
27786
27715
  function findExe(root, exe) {
27787
27716
  const match = exeMatcher(exe);
27788
- const best = (hits) => hits.find((h) => X64_FOLDER.test(path18.relative(root, h))) ?? hits[0] ?? null;
27717
+ const best = (hits) => hits.find((h) => X64_FOLDER.test(path14.relative(root, h))) ?? hits[0] ?? null;
27789
27718
  let queue = [root];
27790
27719
  let seen = 0;
27791
27720
  for (let depth = 0; depth < MAX_DEPTH && queue.length; depth++) {
@@ -27794,14 +27723,14 @@ function findExe(root, exe) {
27794
27723
  for (const dir of queue) {
27795
27724
  let entries3;
27796
27725
  try {
27797
- entries3 = fs14.readdirSync(dir, { withFileTypes: true });
27726
+ entries3 = fs10.readdirSync(dir, { withFileTypes: true });
27798
27727
  } catch {
27799
27728
  continue;
27800
27729
  }
27801
27730
  const hit = entries3.find((e) => e.isFile() && match(e.name));
27802
- if (hit) hits.push(path18.join(dir, hit.name));
27731
+ if (hit) hits.push(path14.join(dir, hit.name));
27803
27732
  else
27804
- next.push(...entries3.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path18.join(dir, e.name)));
27733
+ next.push(...entries3.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path14.join(dir, e.name)));
27805
27734
  if ((seen += entries3.length) > MAX_ENTRIES) return best(hits);
27806
27735
  }
27807
27736
  if (hits.length) return best(hits);
@@ -27810,14 +27739,382 @@ function findExe(root, exe) {
27810
27739
  return null;
27811
27740
  }
27812
27741
 
27742
+ // src/guest/toolchains/tool-env.ts
27743
+ import path16 from "node:path";
27744
+
27745
+ // src/guest/runtime/process.ts
27746
+ import fs11 from "node:fs";
27747
+ import os4 from "node:os";
27748
+ import path15 from "node:path";
27749
+ import { spawnSync } from "node:child_process";
27750
+ function exec(file3, args, options = {}) {
27751
+ const result = spawnSync(file3, args, { stdio: "inherit", windowsHide: true, ...options });
27752
+ if (result.error) throw result.error;
27753
+ if (result.status !== 0)
27754
+ throw new Error(path15.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + result.status);
27755
+ }
27756
+ async function execAsync(file3, args, options = {}) {
27757
+ const code = await spawnAsync(file3, args, { stdio: "inherit", ...options });
27758
+ if (code !== 0)
27759
+ throw new Error(path15.basename(file3) + " " + args.slice(0, 3).join(" ") + " failed with exit code " + code);
27760
+ }
27761
+ function execOutput(file3, args, options = {}) {
27762
+ const result = spawnSync(file3, args, { encoding: "utf8", windowsHide: true, ...options });
27763
+ return result.status === 0 ? String(result.stdout ?? "").trim() : "";
27764
+ }
27765
+ function runScript(name, args = []) {
27766
+ const result = spawnSync(SYSTEM.powershell(), scriptArgs(name, args), {
27767
+ stdio: ["inherit", "inherit", "pipe"],
27768
+ encoding: "utf8",
27769
+ windowsHide: true
27770
+ });
27771
+ if (result.error) throw result.error;
27772
+ const errors = String(result.stderr ?? "").trim();
27773
+ if (errors) process.stderr.write(errors + "\n");
27774
+ if (result.status !== 0)
27775
+ throw new Error(name + " failed with exit code " + result.status + (errors ? ": " + errors.slice(0, 400) : ""));
27776
+ }
27777
+ function scriptOutput(name, args = [], options = {}) {
27778
+ return execOutput(SYSTEM.powershell(), scriptArgs(name, args), options);
27779
+ }
27780
+ function runScriptWithJson(name, param, data, args = []) {
27781
+ const dir = fs11.mkdtempSync(path15.join(os4.tmpdir(), "sbx-"));
27782
+ const file3 = path15.join(dir, "input.json");
27783
+ try {
27784
+ fs11.writeFileSync(file3, JSON.stringify(data), "utf8");
27785
+ runScript(name, ["-" + param, file3, ...args]);
27786
+ } finally {
27787
+ fs11.rmSync(dir, { recursive: true, force: true });
27788
+ }
27789
+ }
27790
+ function robocopy(from, to, files = []) {
27791
+ if (!isWin) {
27792
+ if (!files.length) {
27793
+ fs11.cpSync(from, to, { recursive: true });
27794
+ return;
27795
+ }
27796
+ fs11.mkdirSync(to, { recursive: true });
27797
+ for (const f of files.filter((f2) => fs11.existsSync(path15.join(from, f2))))
27798
+ fs11.copyFileSync(path15.join(from, f), path15.join(to, f));
27799
+ return;
27800
+ }
27801
+ const what = files.length ? files : ["/E"];
27802
+ const passes = [
27803
+ ["/MT:16", "/R:1", "/W:1"],
27804
+ ["/MT:1", "/R:4", "/W:3"]
27805
+ ];
27806
+ let code = null;
27807
+ let output3 = "";
27808
+ for (const pass of passes) {
27809
+ const result = spawnSync(
27810
+ SYSTEM.robocopy(),
27811
+ [
27812
+ from,
27813
+ to,
27814
+ ...what,
27815
+ ...files.length ? [] : [pass[0]],
27816
+ pass[1],
27817
+ pass[2],
27818
+ "/NFL",
27819
+ "/NDL",
27820
+ "/NJH",
27821
+ "/NJS",
27822
+ "/NP",
27823
+ "/XJ"
27824
+ ],
27825
+ { encoding: "utf8", windowsHide: true }
27826
+ );
27827
+ code = result.status;
27828
+ output3 = String(result.stdout ?? "") + String(result.stderr ?? "");
27829
+ if (!robocopyFailed(code)) return;
27830
+ }
27831
+ const why = robocopyErrors(output3);
27832
+ throw new Error(
27833
+ "robocopy " + from + " -> " + to + " failed (exit " + code + ": " + robocopyMeaning(code) + ")" + (why.length ? ": " + why.join(" | ") : "")
27834
+ );
27835
+ }
27836
+ function copyNode(from, to) {
27837
+ const work = stagingFolder(to);
27838
+ try {
27839
+ robocopy(from, work, ["node.exe", "npm", "npm.cmd", "npx", "npx.cmd"]);
27840
+ robocopy(path15.join(from, "node_modules", "npm"), path15.join(work, "node_modules", "npm"));
27841
+ moveIntoPlace(work, to);
27842
+ } finally {
27843
+ safeRemove(work, path15.dirname(work));
27844
+ }
27845
+ }
27846
+
27847
+ // src/guest/toolchains/tool-env.ts
27848
+ function emptyEnv() {
27849
+ return { vars: {}, prepend: [], append: [], summary: [] };
27850
+ }
27851
+ var arch = process.arch === "arm64" ? "arm64" : "x64";
27852
+ function tool(...parts2) {
27853
+ return path16.join(toolsDir, ...parts2);
27854
+ }
27855
+ function versionOf(exe, args = ["--version"], options = {}) {
27856
+ return /\d+\.\d+\.\d+\S*/.exec(execOutput(exe, args, options))?.[0] ?? "installed";
27857
+ }
27858
+
27859
+ // src/guest/setup/agent-addons.ts
27860
+ function installedAddon(id) {
27861
+ const entry = appById(id);
27862
+ if (dryRun || !entry || !(session.apps?.install ?? []).includes(id)) return null;
27863
+ return findExe(tool("apps", id), entry.exe);
27864
+ }
27865
+ function installedRtk() {
27866
+ return installedAddon("rtk");
27867
+ }
27868
+ function installedMcpAddons() {
27869
+ return APPS.filter((a) => a.mcp && installedAddon(a.id)).map((a) => ({ id: a.id, folder: tool("apps", a.id) }));
27870
+ }
27871
+
27872
+ // src/guest/boot/guide.ts
27873
+ var BEGIN = "<!-- agent-sandbox:begin (generated every boot, do not edit) -->";
27874
+ var END = "<!-- agent-sandbox:end -->";
27875
+ var mirrorLine = () => {
27876
+ const drives = (session.substDrives ?? []).filter((d) => fs12.existsSync(d.letter + ":\\"));
27877
+ if (!drives.length) return [];
27878
+ return [
27879
+ "- " + drives.map((d) => d.letter + ":").join(", ") + " = mapped folders at their PC paths (subst onto `" + drives.map((d) => d.target).join("`, `") + "`; real-path tools may print that form)."
27880
+ ];
27881
+ };
27882
+ function sandboxGuide(toolSummary, lan = "blocked", projects = [], addons = []) {
27883
+ return [
27884
+ BEGIN,
27885
+ "## Sandbox manifest \u2014 you are in a DISPOSABLE Windows Sandbox",
27886
+ "Wiped on close: everything except the paths below (installers, winget/choco, C:\\Users, Program Files, registry).",
27887
+ "- RW, persists: `" + workspace + "` = host folder " + session.workspaceHost,
27888
+ // Projects started from other folders while this sandbox runs: every agent here can see them.
27889
+ ...projects.map(
27890
+ (p) => "- RW, persists: `" + p.guest + "` = host folder " + p.host + " (another project in this sandbox; your own is `%AGENT_WORKSPACE%`)"
27891
+ ),
27892
+ "- RW, persists: `" + toolsDir + "` (toolchains) \u2014 put portable exes in `" + path17.join(toolsDir, "bin") + "` (on PATH)",
27893
+ "- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" + path17.join(dataDir, "logs") + "`",
27894
+ "- RO: `" + launchDir + "` (this boot's scripts) \xB7 lost on close: everything else, incl. `C:\\nvm` (Node symlink)",
27895
+ ...mirrorLine(),
27896
+ "- Tools: " + toolSummary.join(" \xB7 "),
27897
+ // Agent add-ons that change how the agent works (rtk, Headroom, MCP servers, ccusage).
27898
+ ...addons,
27899
+ "- Persistent installs: `npm i -g` (per nvm version), `pip`, `cargo install`, `dotnet tool -g`, `uv tool`, `bun add -g`. Real installers must re-run each boot via a hook (ask the user).",
27900
+ "- Mapped folders (workspace, C:\\AgentData) allow NO symlinks or junctions: pnpm runs hoisted (set), npm workspaces / `file:` deps and deno node_modules dirs fail there (use a folder on C:\\ outside them), bun cannot save its lockfile there (`bun install --no-save`).",
27901
+ "- Network: " + (lan === "offline" ? "OFF" : lan === "blocked" ? "internet yes, host LAN blocked" : "internet yes, host LAN NOT blocked this time") + ". Other sessions may share this workspace; the user may be typing from the host.",
27902
+ END
27903
+ ].join("\n");
27904
+ }
27905
+ function upsertGuide(file3, guide) {
27906
+ fs12.mkdirSync(path17.dirname(file3), { recursive: true });
27907
+ const current = fs12.existsSync(file3) ? fs12.readFileSync(file3, "utf8") : "";
27908
+ const start = current.indexOf(BEGIN);
27909
+ const end = current.indexOf(END);
27910
+ const without = start >= 0 && end > start ? current.slice(0, start) + current.slice(end + END.length) : current;
27911
+ fs12.writeFileSync(file3, without.trimEnd() + (without.trim() ? "\n\n" : "") + guide + "\n", "utf8");
27912
+ }
27913
+ function managedClaudeMd() {
27914
+ return path17.join(
27915
+ process.env.AGENT_MANAGED_DIR ?? path17.join(process.env.ProgramFiles ?? "C:\\Program Files", "ClaudeCode"),
27916
+ "CLAUDE.md"
27917
+ );
27918
+ }
27919
+ var headroomRuns = () => {
27920
+ try {
27921
+ const file3 = path17.join(path17.dirname(managedClaudeMd()), "managed-settings.json");
27922
+ const settings = JSON.parse(fs12.readFileSync(file3, "utf8"));
27923
+ return typeof settings.env?.ANTHROPIC_BASE_URL === "string";
27924
+ } catch {
27925
+ return false;
27926
+ }
27927
+ };
27928
+ function addonLines() {
27929
+ const mcp = APPS.flatMap((a) => a.mcp && installedAddon(a.id) ? [a.mcp.name] : []);
27930
+ return [
27931
+ ...installedRtk() ? [RTK_GUIDE_LINE] : [],
27932
+ ...installedAddon("headroom") && headroomRuns() ? [headroomGuideLine(path17.join(logsDir, "headroom.log"))] : [],
27933
+ ...addonGuideLine(mcp, Boolean(installedAddon("ccusage")))
27934
+ ];
27935
+ }
27936
+ function writeGuides(toolSummary, lan, projects = []) {
27937
+ const guide = sandboxGuide(toolSummary, lan, projects, addonLines());
27938
+ const managed = managedClaudeMd();
27939
+ fs12.mkdirSync(path17.dirname(managed), { recursive: true });
27940
+ fs12.writeFileSync(managed, guide + "\n", "utf8");
27941
+ fs12.writeFileSync(path17.join(dataDir, "SANDBOX.md"), guide + "\n", "utf8");
27942
+ upsertGuide(path17.join(stateDir, "codex", "AGENTS.md"), guide);
27943
+ upsertGuide(path17.join(stateDir, "gemini", ".gemini", "GEMINI.md"), guide);
27944
+ removeGuide(path17.join(claudeDir, "CLAUDE.md"));
27945
+ return managed;
27946
+ }
27947
+ var removeGuide = (file3) => {
27948
+ if (!fs12.existsSync(file3)) return;
27949
+ const current = fs12.readFileSync(file3, "utf8");
27950
+ const start = current.indexOf(BEGIN);
27951
+ const end = current.indexOf(END);
27952
+ if (start >= 0 && end > start)
27953
+ fs12.writeFileSync(file3, (current.slice(0, start) + current.slice(end + END.length)).trim() + "\n", "utf8");
27954
+ };
27955
+
27956
+ // src/guest/runtime/fs.ts
27957
+ import fs13 from "node:fs";
27958
+ function exists(p) {
27959
+ return fs13.existsSync(p);
27960
+ }
27961
+ function mkdirp(p) {
27962
+ fs13.mkdirSync(p, { recursive: true });
27963
+ return p;
27964
+ }
27965
+
27966
+ // src/guest/apps/app-installer.ts
27967
+ import fs17 from "node:fs";
27968
+ import path22 from "node:path";
27969
+
27970
+ // src/guest/toolchains/runtimes.ts
27971
+ import path18 from "node:path";
27972
+
27973
+ // src/guest/toolchains/install.ts
27974
+ import fs14 from "node:fs";
27975
+ async function downloadFile(url2, file3, sha256 = null) {
27976
+ const part = file3 + ".part";
27977
+ try {
27978
+ await downloader.file(url2, part, sha256);
27979
+ fs14.rmSync(file3, { force: true });
27980
+ fs14.renameSync(part, file3);
27981
+ } finally {
27982
+ fs14.rmSync(part, { force: true });
27983
+ }
27984
+ }
27985
+ async function installFromGithub(repo, pattern, o) {
27986
+ const asset = await githubAsset(repo, pattern, o.searchOlder);
27987
+ log("Downloading " + (typeof o.what === "string" ? o.what : o.what(asset)) + " ...");
27988
+ await downloader.archive(asset.url, o.dest, {
27989
+ sha256: asset.sha256,
27990
+ fileName: asset.name,
27991
+ ...o.locate ? { locate: o.locate } : {},
27992
+ ...o.up ? { up: o.up } : {}
27993
+ });
27994
+ }
27995
+
27996
+ // src/guest/toolchains/runtimes.ts
27997
+ async function setupSingleExe(env, name, repo, pattern, exeName, dir, options = {}) {
27998
+ if (dryRun) {
27999
+ log("(dry run) would provision " + name);
28000
+ return;
28001
+ }
28002
+ const bin = options.subdir ? path18.join(dir, options.subdir) : dir;
28003
+ const exe = path18.join(bin, exeName);
28004
+ if (!exists(exe) || options.refresh) {
28005
+ const size = options.size ? ", ~" + options.size : "";
28006
+ await installFromGithub(repo, pattern, {
28007
+ dest: dir,
28008
+ what: (a) => name + " (" + a.name + size + " once)",
28009
+ ...options.subdir ? {} : { locate: exeName }
28010
+ });
28011
+ }
28012
+ if (!exists(exe)) throw new Error(exeName + " missing after installing " + name);
28013
+ env.prepend.push(bin);
28014
+ env.summary.push(name + ": " + versionOf(exe, options.versionArgs) + (options.note ?? ""));
28015
+ }
28016
+ async function setupBun(env) {
28017
+ await setupSingleExe(
28018
+ env,
28019
+ "bun",
28020
+ "oven-sh/bun",
28021
+ arch === "arm64" ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/,
28022
+ "bun.exe",
28023
+ tool("bun", "bin"),
28024
+ { size: "35 MB" }
28025
+ );
28026
+ Object.assign(env.vars, {
28027
+ BUN_INSTALL: tool("bun"),
28028
+ BUN_INSTALL_CACHE_DIR: path18.join(localDir, "bun-cache"),
28029
+ BUN_TMPDIR: path18.join(localDir, "bun-tmp")
28030
+ });
28031
+ }
28032
+ async function setupDeno(env) {
28033
+ await setupSingleExe(
28034
+ env,
28035
+ "deno",
28036
+ "denoland/deno",
28037
+ arch === "arm64" ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/,
28038
+ "deno.exe",
28039
+ tool("deno", "bin"),
28040
+ { size: "40 MB" }
28041
+ );
28042
+ Object.assign(env.vars, { DENO_DIR: tool("deno-cache"), DENO_INSTALL_ROOT: tool("deno"), DENO_NO_UPDATE_CHECK: "1" });
28043
+ }
28044
+ function uvVars() {
28045
+ return {
28046
+ UV_CACHE_DIR: tool("uv-cache"),
28047
+ UV_PYTHON_INSTALL_DIR: tool("uv-python"),
28048
+ UV_TOOL_DIR: tool("uv-tools"),
28049
+ UV_TOOL_BIN_DIR: tool("uv-bin")
28050
+ };
28051
+ }
28052
+ async function setupUv(env) {
28053
+ await setupSingleExe(
28054
+ env,
28055
+ "uv",
28056
+ "astral-sh/uv",
28057
+ arch === "arm64" ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/,
28058
+ "uv.exe",
28059
+ tool("uv"),
28060
+ { size: "20 MB" }
28061
+ );
28062
+ Object.assign(env.vars, uvVars());
28063
+ env.prepend.push(mkdirp(tool("uv-bin")));
28064
+ }
28065
+
28066
+ // src/guest/apps/after-install.ts
28067
+ import fs15 from "node:fs";
28068
+ import path19 from "node:path";
28069
+ var SYSINTERNALS_TOOLS = [
28070
+ "Process Explorer",
28071
+ "Process Monitor",
28072
+ "Autoruns",
28073
+ "TCPView",
28074
+ "PsExec",
28075
+ "PsList",
28076
+ "PsKill",
28077
+ "Handle",
28078
+ "ListDLLs",
28079
+ "Sigcheck",
28080
+ "Strings",
28081
+ "VMMap",
28082
+ "RAMMap",
28083
+ "DebugView",
28084
+ "Disk2vhd",
28085
+ "Du",
28086
+ "ZoomIt"
28087
+ ];
28088
+ async function afterInstall(entry, exe) {
28089
+ const dir = path19.dirname(exe);
28090
+ if (entry.needs?.includes("mesa")) {
28091
+ const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
28092
+ for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
28093
+ if (exists(path19.join(mesa, dll)) && !exists(path19.join(dir, dll)))
28094
+ fs15.copyFileSync(path19.join(mesa, dll), path19.join(dir, dll));
28095
+ }
28096
+ }
28097
+ if (entry.id === "godot" && !exists(path19.join(dir, "._sc_"))) fs15.writeFileSync(path19.join(dir, "._sc_"), "");
28098
+ if (entry.id === "sublime") mkdirp(path19.join(dir, "Data"));
28099
+ if (entry.id === "sysinternals") {
28100
+ for (const name of SYSINTERNALS_TOOLS) {
28101
+ await execAsync(
28102
+ SYSTEM.reg(),
28103
+ ["add", "HKCU\\Software\\Sysinternals\\" + name, "/v", "EulaAccepted", "/t", "REG_DWORD", "/d", "1", "/f"],
28104
+ { stdio: "ignore" }
28105
+ ).catch(() => void 0);
28106
+ }
28107
+ }
28108
+ }
28109
+
27813
28110
  // src/guest/apps/shortcuts.ts
27814
28111
  import os5 from "node:os";
27815
- import path19 from "node:path";
28112
+ import path20 from "node:path";
27816
28113
  function shortcuts(apps) {
27817
28114
  if (!apps.length) return;
27818
- const desktop = path19.join(os5.homedir(), "Desktop");
27819
- const start = path19.join(
27820
- process.env.APPDATA ?? path19.join(os5.homedir(), "AppData", "Roaming"),
28115
+ const desktop = path20.join(os5.homedir(), "Desktop");
28116
+ const start = path20.join(
28117
+ process.env.APPDATA ?? path20.join(os5.homedir(), "AppData", "Roaming"),
27821
28118
  "Microsoft",
27822
28119
  "Windows",
27823
28120
  "Start Menu",
@@ -27827,9 +28124,9 @@ function shortcuts(apps) {
27827
28124
  const links = apps.flatMap((app) => {
27828
28125
  const name = app.name.replace(/[\\/:*?"<>|]/g, "");
27829
28126
  return [desktop, start].map((folder) => ({
27830
- link: path19.join(folder, name + ".lnk"),
28127
+ link: path20.join(folder, name + ".lnk"),
27831
28128
  target: app.exe,
27832
- workingDirectory: path19.dirname(app.exe)
28129
+ workingDirectory: path20.dirname(app.exe)
27833
28130
  }));
27834
28131
  });
27835
28132
  runScriptWithJson("new-shortcuts.ps1", "ListFile", links);
@@ -27954,19 +28251,19 @@ async function resolve(entry) {
27954
28251
  }
27955
28252
  if ("url" in s) {
27956
28253
  const name = decodeURIComponent(new URL(s.url).pathname.split("/").pop() || entry.id);
27957
- return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip" };
28254
+ return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip", sha256: s.sha256 };
27958
28255
  }
27959
28256
  if ("resolve" in s && RESOLVERS[s.resolve]) return RESOLVERS[s.resolve]();
27960
28257
  throw new Error("no download source for " + entry.name);
27961
28258
  }
27962
28259
 
27963
28260
  // src/guest/apps/unpack.ts
27964
- import fs15 from "node:fs";
27965
- import path20 from "node:path";
28261
+ import fs16 from "node:fs";
28262
+ import path21 from "node:path";
27966
28263
  var sevenZip = () => tool("apps", "7zip", "7z.exe");
27967
28264
  async function unpack(entry, file3, out, d) {
27968
28265
  if (entry.id === "7zip") {
27969
- const sevenZr = path20.join(path20.dirname(file3), "7zr.exe");
28266
+ const sevenZr = path21.join(path21.dirname(file3), "7zr.exe");
27970
28267
  const zr = await githubAsset("ip7z/7zip", /^7zr\.exe$/);
27971
28268
  await downloader.file(zr.url, sevenZr, zr.sha256);
27972
28269
  await execAsync(sevenZr, ["x", "-y", "-o" + out, file3], { stdio: "ignore" });
@@ -27975,17 +28272,17 @@ async function unpack(entry, file3, out, d) {
27975
28272
  switch (entry.unpack ?? "archive") {
27976
28273
  case "file": {
27977
28274
  mkdirp(out);
27978
- fs15.renameSync(file3, path20.join(out, /^\//.test(entry.exe) ? path20.basename(file3) : entry.exe));
28275
+ fs16.renameSync(file3, path21.join(out, /^\//.test(entry.exe) ? path21.basename(file3) : entry.exe));
27979
28276
  return;
27980
28277
  }
27981
28278
  case "nsis": {
27982
28279
  if (!exists(sevenZip()))
27983
28280
  throw new Error("7-Zip is needed to unpack " + entry.name + " and could not be installed");
27984
- const raw = path20.join(path20.dirname(out), "raw");
28281
+ const raw = path21.join(path21.dirname(out), "raw");
27985
28282
  await execAsync(sevenZip(), ["x", "-y", "-o" + raw, file3], { stdio: "ignore" });
27986
28283
  const inner = findExe(raw, "/^app-64\\.7z$/");
27987
28284
  if (inner) await execAsync(sevenZip(), ["x", "-y", "-o" + out, inner], { stdio: "ignore" });
27988
- else fs15.renameSync(raw, out);
28285
+ else fs16.renameSync(raw, out);
27989
28286
  return;
27990
28287
  }
27991
28288
  case "msi": {
@@ -28035,12 +28332,12 @@ var AppInstaller = class {
28035
28332
  async installOne(entry) {
28036
28333
  try {
28037
28334
  const dest = tool("apps", ...entry.id.split("/"));
28038
- if (!exists(path21.join(dest, MARKER)) || this.options.refresh) await this.download(entry, dest);
28335
+ if (!exists(path22.join(dest, MARKER)) || this.options.refresh) await this.download(entry, dest);
28039
28336
  const exe = findExe(dest, entry.exe);
28040
28337
  if (!exe) throw new Error(entry.exe + " not found in the download");
28041
28338
  await afterInstall(entry, exe);
28042
- if (entry.cli || entry.id === "sysinternals") this.env.prepend.push(path21.dirname(exe));
28043
- if (!entry.cli) this.gui.push({ name: entry.name, exe });
28339
+ if (!entry.service && (entry.cli || entry.id === "sysinternals")) this.env.prepend.push(path22.dirname(exe));
28340
+ if (!entry.cli && !entry.service) this.gui.push({ name: entry.name, exe });
28044
28341
  this.installed.push(entry.name);
28045
28342
  } catch (e) {
28046
28343
  warn(
@@ -28052,10 +28349,13 @@ var AppInstaller = class {
28052
28349
  /** Downloads and unpacks one entry into its folder (replaced in one step: never half there). */
28053
28350
  async download(entry, dest) {
28054
28351
  const work = stagingFolder(dest);
28055
- const out = path21.join(work, "out");
28352
+ const out = path22.join(work, "out");
28056
28353
  try {
28057
- if ("npm" in entry.source) {
28058
- const npmCli = path21.join(path21.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28354
+ if ("locked" in entry.source) {
28355
+ log("Installing " + entry.name + " " + entry.source.version + " (pinned, every file checked) ...");
28356
+ await installLocked(entry.id, entry.source.locked, mkdirp(out));
28357
+ } else if ("npm" in entry.source) {
28358
+ const npmCli = path22.join(path22.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28059
28359
  log("Installing " + entry.name + " (npm) ...");
28060
28360
  await execAsync(process.execPath, [
28061
28361
  npmCli,
@@ -28070,17 +28370,60 @@ var AppInstaller = class {
28070
28370
  } else {
28071
28371
  const d = await resolve(entry);
28072
28372
  log("Downloading " + entry.name + " (" + d.fileName + ", ~" + entry.size + " once) ...");
28073
- const file3 = path21.join(mkdirp(work), d.fileName.replace(/[\\/:*?"<>|]/g, "_"));
28373
+ const file3 = path22.join(mkdirp(work), d.fileName.replace(/[\\/:*?"<>|]/g, "_"));
28074
28374
  await downloader.file(d.url, file3, { sha256: d.sha256 ?? null });
28075
28375
  await unpack(entry, file3, out, d);
28076
28376
  }
28077
- fs16.writeFileSync(path21.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
28377
+ fs17.writeFileSync(path22.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
28078
28378
  moveIntoPlace(out, dest);
28079
28379
  } finally {
28080
- safeRemove(work, path21.dirname(work));
28380
+ safeRemove(work, path22.dirname(work));
28081
28381
  }
28082
28382
  }
28083
28383
  };
28384
+ var LOCKED_PYTHON = "3.13";
28385
+ async function installLocked(id, kind, out) {
28386
+ const lock = path22.join(launchDir, "sandbox", "addons", id);
28387
+ if (kind === "npm") {
28388
+ for (const f of ["package.json", "package-lock.json"]) fs17.copyFileSync(path22.join(lock, f), path22.join(out, f));
28389
+ const npmCli = path22.join(path22.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28390
+ await execAsync(
28391
+ process.execPath,
28392
+ [npmCli, "ci", "--ignore-scripts", "--no-audit", "--no-fund", "--loglevel=error"],
28393
+ { cwd: out }
28394
+ );
28395
+ return;
28396
+ }
28397
+ const uv = findExe(tool("uv"), "uv.exe");
28398
+ if (!uv) throw new Error("uv is not installed (the uv step failed)");
28399
+ const env = { ...process.env, ...uvVars() };
28400
+ const venv = path22.join(out, "venv");
28401
+ await execAsync(
28402
+ uv,
28403
+ ["venv", "--relocatable", "--python", LOCKED_PYTHON, "--python-preference", "only-managed", venv],
28404
+ {
28405
+ env
28406
+ }
28407
+ );
28408
+ await execAsync(
28409
+ uv,
28410
+ [
28411
+ "pip",
28412
+ "install",
28413
+ "--python",
28414
+ path22.join(venv, "Scripts", "python.exe"),
28415
+ "--require-hashes",
28416
+ "--no-deps",
28417
+ "--only-binary",
28418
+ ":all:",
28419
+ "--link-mode",
28420
+ "copy",
28421
+ "-r",
28422
+ path22.join(lock, "requirements.txt")
28423
+ ],
28424
+ { env }
28425
+ );
28426
+ }
28084
28427
  async function setupApps(env, apps, o) {
28085
28428
  const { entries: entries3, skipped } = appsToInstall(apps, o.gitAccess);
28086
28429
  for (const s of skipped) env.summary.push("app skipped: " + s);
@@ -28092,8 +28435,8 @@ async function setupApps(env, apps, o) {
28092
28435
  }
28093
28436
 
28094
28437
  // src/guest/toolchains/detect.ts
28095
- import fs17 from "node:fs";
28096
- import path22 from "node:path";
28438
+ import fs18 from "node:fs";
28439
+ import path23 from "node:path";
28097
28440
 
28098
28441
  // src/guest/runtime/project-context.ts
28099
28442
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -28235,14 +28578,14 @@ function workspaceEntries() {
28235
28578
  if (known) return known;
28236
28579
  const list = (dir) => {
28237
28580
  try {
28238
- return fs17.readdirSync(dir, { withFileTypes: true });
28581
+ return fs18.readdirSync(dir, { withFileTypes: true });
28239
28582
  } catch {
28240
28583
  return [];
28241
28584
  }
28242
28585
  };
28243
28586
  const top = list(workspace2);
28244
28587
  const below = top.filter((d) => d.isDirectory() && !d.name.startsWith(".") && !SKIP_DIRS.has(d.name.toLowerCase())).flatMap(
28245
- (d) => list(path22.join(workspace2, d.name)).filter((f) => f.isFile()).map((f) => d.name + "/" + f.name)
28588
+ (d) => list(path23.join(workspace2, d.name)).filter((f) => f.isFile()).map((f) => d.name + "/" + f.name)
28246
28589
  );
28247
28590
  const found = [...top.filter((d) => d.isFile()).map((d) => d.name), ...below];
28248
28591
  entries.set(workspace2.toLowerCase(), found);
@@ -28253,9 +28596,9 @@ function wanted(setting, toolchain) {
28253
28596
  }
28254
28597
  function versionFromFiles(files, parse5 = (t) => specFromVersionFile(t)) {
28255
28598
  for (const name of files) {
28256
- const file3 = path22.join(projectWorkspace(), name);
28599
+ const file3 = path23.join(projectWorkspace(), name);
28257
28600
  if (!exists(file3)) continue;
28258
- const spec = parse5(fs17.readFileSync(file3, "utf8"), name);
28601
+ const spec = parse5(fs18.readFileSync(file3, "utf8"), name);
28259
28602
  if (spec) return { spec, source: name };
28260
28603
  }
28261
28604
  return null;
@@ -28318,22 +28661,22 @@ var DatabaseServer = class {
28318
28661
  };
28319
28662
 
28320
28663
  // src/guest/databases/dynamodb.ts
28321
- import fs22 from "node:fs";
28322
- import path25 from "node:path";
28664
+ import fs23 from "node:fs";
28665
+ import path26 from "node:path";
28323
28666
  import { spawn as spawn3 } from "node:child_process";
28324
28667
 
28325
28668
  // src/guest/toolchains/languages/java.ts
28326
- import fs20 from "node:fs";
28327
- import path23 from "node:path";
28669
+ import fs21 from "node:fs";
28670
+ import path24 from "node:path";
28328
28671
 
28329
28672
  // src/guest/toolchains/version-cache.ts
28330
- import fs19 from "node:fs";
28673
+ import fs20 from "node:fs";
28331
28674
 
28332
28675
  // src/guest/toolchains/state-file.ts
28333
- import fs18 from "node:fs";
28676
+ import fs19 from "node:fs";
28334
28677
  function readState(file3, schema, empty) {
28335
28678
  try {
28336
- return schema.safeParse(JSON.parse(fs18.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""))).data ?? empty;
28679
+ return schema.safeParse(JSON.parse(fs19.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""))).data ?? empty;
28337
28680
  } catch {
28338
28681
  return empty;
28339
28682
  }
@@ -28368,7 +28711,7 @@ var VersionCache = class {
28368
28711
  return cached2.value;
28369
28712
  try {
28370
28713
  const value = await resolve2();
28371
- fs19.mkdirSync(toolsDir, { recursive: true });
28714
+ fs20.mkdirSync(toolsDir, { recursive: true });
28372
28715
  writeJsonAtomic(this.file(), { ...this.remembered(), [key]: { value, at: Date.now() } });
28373
28716
  return value;
28374
28717
  } catch (e) {
@@ -28421,7 +28764,7 @@ var setupJdk = async (env, config2) => {
28421
28764
  const { major, source } = await javaMajor(config2);
28422
28765
  const release = await resolveCached("java:" + major, async () => (await temurin(major)).release_name);
28423
28766
  const home = tool("java", release.replace(/[^A-Za-z0-9.-]/g, "_"));
28424
- if (!exists(path23.join(home, "bin", "java.exe"))) {
28767
+ if (!exists(path24.join(home, "bin", "java.exe"))) {
28425
28768
  const asset = await temurin(major);
28426
28769
  log("Downloading Java " + release + " (JDK, ~200 MB once) ...");
28427
28770
  await downloader.archive(asset.binary.package.link, home, {
@@ -28431,13 +28774,13 @@ var setupJdk = async (env, config2) => {
28431
28774
  });
28432
28775
  }
28433
28776
  env.vars.JAVA_HOME = home;
28434
- env.prepend.push(path23.join(home, "bin"));
28777
+ env.prepend.push(path24.join(home, "bin"));
28435
28778
  env.summary.push("java: " + release + " (Temurin, from " + source + ")");
28436
28779
  };
28437
28780
  async function ensureJdk() {
28438
28781
  const root = tool("java");
28439
- const installed = exists(root) ? fs20.readdirSync(root).filter((d) => exists(path23.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
28440
- if (installed.length) return path23.join(root, installed[0]);
28782
+ const installed = exists(root) ? fs21.readdirSync(root).filter((d) => exists(path24.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
28783
+ if (installed.length) return path24.join(root, installed[0]);
28441
28784
  const scratch = emptyEnv();
28442
28785
  await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false });
28443
28786
  return scratch.vars.JAVA_HOME;
@@ -28450,7 +28793,7 @@ var setupMaven = async (env) => {
28450
28793
  return pickPackageVersion(versions, "3") ?? Promise.reject(new Error("No Maven 3 release found"));
28451
28794
  });
28452
28795
  const home = tool("maven", version2);
28453
- if (!exists(path23.join(home, "bin", "mvn.cmd"))) {
28796
+ if (!exists(path24.join(home, "bin", "mvn.cmd"))) {
28454
28797
  const url2 = MAVEN + version2 + "/apache-maven-" + version2 + "-bin.zip";
28455
28798
  log("Downloading Maven " + version2 + " (~10 MB once) ...");
28456
28799
  await downloader.archive(url2, home, {
@@ -28460,7 +28803,7 @@ var setupMaven = async (env) => {
28460
28803
  }
28461
28804
  const repo = tool("maven-repository");
28462
28805
  Object.assign(env.vars, { MAVEN_HOME: home, M2_HOME: home, MAVEN_OPTS: "-Dmaven.repo.local=" + repo });
28463
- env.prepend.push(path23.join(home, "bin"));
28806
+ env.prepend.push(path24.join(home, "bin"));
28464
28807
  env.summary.push("maven: " + version2);
28465
28808
  };
28466
28809
  var setupGradle = async (env) => {
@@ -28472,7 +28815,7 @@ var setupGradle = async (env) => {
28472
28815
  async () => current?.version ?? Promise.reject(new Error("Gradle version lookup failed"))
28473
28816
  );
28474
28817
  const home = tool("gradle", version2);
28475
- if (!exists(path23.join(home, "bin", "gradle.bat"))) {
28818
+ if (!exists(path24.join(home, "bin", "gradle.bat"))) {
28476
28819
  if (!current || current.version !== version2)
28477
28820
  throw new Error("Gradle " + version2 + " is not installed and cannot be downloaded right now");
28478
28821
  log("Downloading Gradle " + version2 + " (~130 MB once) ...");
@@ -28483,13 +28826,13 @@ var setupGradle = async (env) => {
28483
28826
  });
28484
28827
  }
28485
28828
  const userHome = tool("gradle-home");
28486
- fs20.mkdirSync(userHome, { recursive: true });
28829
+ fs21.mkdirSync(userHome, { recursive: true });
28487
28830
  Object.assign(env.vars, {
28488
28831
  GRADLE_HOME: home,
28489
28832
  GRADLE_USER_HOME: userHome,
28490
28833
  GRADLE_OPTS: "-Dorg.gradle.vfs.watch=false"
28491
28834
  });
28492
- env.prepend.push(path23.join(home, "bin"));
28835
+ env.prepend.push(path24.join(home, "bin"));
28493
28836
  env.summary.push("gradle: " + version2);
28494
28837
  };
28495
28838
  async function setupJava(env, config2) {
@@ -28513,29 +28856,29 @@ async function setupJava(env, config2) {
28513
28856
  }
28514
28857
 
28515
28858
  // src/guest/databases/server.ts
28516
- import fs21 from "node:fs";
28517
- import path24 from "node:path";
28859
+ import fs22 from "node:fs";
28860
+ import path25 from "node:path";
28518
28861
  import { spawn as spawn2 } from "node:child_process";
28519
28862
  function dataFor(name) {
28520
- return path24.join(dataDir, "databases", name);
28863
+ return path25.join(dataDir, "databases", name);
28521
28864
  }
28522
28865
  async function startServer(name, exe, args, port) {
28523
28866
  if (await portOpen(port)) throw new Error("port " + port + " is already in use (change databases." + name + ".port)");
28524
- const logFile2 = path24.join(logsDir, name + ".log");
28525
- const out = fs21.openSync(logFile2, "a");
28867
+ const logFile2 = path25.join(logsDir, name + ".log");
28868
+ const out = fs22.openSync(logFile2, "a");
28526
28869
  spawn2(exe, args, { detached: true, stdio: ["ignore", out, out], windowsHide: true }).unref();
28527
- fs21.closeSync(out);
28870
+ fs22.closeSync(out);
28528
28871
  if (!await waitForPort(port, 60))
28529
28872
  throw new Error(name + " did not start listening on port " + port + "; see " + logFile2);
28530
28873
  }
28531
28874
  async function clearStaleLocks(dir, files, port) {
28532
28875
  if (await portOpen(port)) return;
28533
- for (const f of files) fs21.rmSync(path24.join(dir, f), { force: true });
28876
+ for (const f of files) fs22.rmSync(path25.join(dir, f), { force: true });
28534
28877
  }
28535
28878
  async function createOnce(data, marker, create) {
28536
- if (exists(path24.join(data, marker))) return;
28879
+ if (exists(path25.join(data, marker))) return;
28537
28880
  const existed = exists(data);
28538
- mkdirp(path24.dirname(data));
28881
+ mkdirp(path25.dirname(data));
28539
28882
  try {
28540
28883
  await create();
28541
28884
  } catch (e) {
@@ -28559,9 +28902,9 @@ var DynamoServer = class extends DatabaseServer {
28559
28902
  * local endpoint up from AWS_ENDPOINT_URL_DYNAMODB, with dummy credentials (real ones never reach the sandbox).
28560
28903
  */
28561
28904
  async start(env, plan2) {
28562
- const java = path25.join(await ensureJdk(), "bin", "java.exe");
28905
+ const java = path26.join(await ensureJdk(), "bin", "java.exe");
28563
28906
  const home = tool("dynamodb-local");
28564
- if (!exists(path25.join(home, "DynamoDBLocal.jar"))) {
28907
+ if (!exists(path26.join(home, "DynamoDBLocal.jar"))) {
28565
28908
  log("Downloading DynamoDB Local (~60 MB once) ...");
28566
28909
  const sha256 = (await fetchText(DYNAMO_ZIP + ".sha256")).trim().split(/\s+/)[0];
28567
28910
  await downloader.archive(DYNAMO_ZIP, home, {
@@ -28575,9 +28918,9 @@ var DynamoServer = class extends DatabaseServer {
28575
28918
  "dynamodb",
28576
28919
  java,
28577
28920
  [
28578
- "-Djava.library.path=" + path25.join(home, "DynamoDBLocal_lib"),
28921
+ "-Djava.library.path=" + path26.join(home, "DynamoDBLocal_lib"),
28579
28922
  "-jar",
28580
- path25.join(home, "DynamoDBLocal.jar"),
28923
+ path26.join(home, "DynamoDBLocal.jar"),
28581
28924
  "-sharedDb",
28582
28925
  "-dbPath",
28583
28926
  data,
@@ -28601,10 +28944,10 @@ var DynamoServer = class extends DatabaseServer {
28601
28944
  );
28602
28945
  if (!plan2.adminPort) return;
28603
28946
  const prefix = tool("dynamodb-admin");
28604
- const script = path25.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
28947
+ const script = path26.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
28605
28948
  if (!exists(script)) {
28606
28949
  log("Installing dynamodb-admin, the DynamoDB web UI (~20 MB once) ...");
28607
- const npmCli = path25.join(path25.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28950
+ const npmCli = path26.join(path26.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
28608
28951
  await execAsync(
28609
28952
  process.execPath,
28610
28953
  [npmCli, "install", "--global", "--prefix", prefix, "dynamodb-admin", "--no-fund", "--no-audit"],
@@ -28617,15 +28960,15 @@ var DynamoServer = class extends DatabaseServer {
28617
28960
  );
28618
28961
  return;
28619
28962
  }
28620
- const out = fs22.openSync(path25.join(logsDir, "dynamodb-admin.log"), "a");
28963
+ const out = fs23.openSync(path26.join(logsDir, "dynamodb-admin.log"), "a");
28621
28964
  spawn3(
28622
28965
  process.execPath,
28623
28966
  [script, "--port", String(plan2.adminPort), "--dynamo-endpoint", endpoint, "--skip-default-credentials"],
28624
28967
  { detached: true, stdio: ["ignore", out, out], windowsHide: true, env: { ...process.env, ...aws } }
28625
28968
  ).unref();
28626
- fs22.closeSync(out);
28969
+ fs23.closeSync(out);
28627
28970
  if (!await waitForPort(plan2.adminPort, 30))
28628
- throw new Error("dynamodb-admin did not start; see " + path25.join(logsDir, "dynamodb-admin.log"));
28971
+ throw new Error("dynamodb-admin did not start; see " + path26.join(logsDir, "dynamodb-admin.log"));
28629
28972
  env.summary.push(
28630
28973
  "dynamodb-admin: http://localhost:" + plan2.adminPort + " (browse and edit tables in the sandbox's browser)"
28631
28974
  );
@@ -28633,32 +28976,7 @@ var DynamoServer = class extends DatabaseServer {
28633
28976
  };
28634
28977
 
28635
28978
  // src/guest/databases/mongodb.ts
28636
- import path26 from "node:path";
28637
-
28638
- // src/guest/toolchains/install.ts
28639
- import fs23 from "node:fs";
28640
- async function downloadFile(url2, file3, sha256 = null) {
28641
- const part = file3 + ".part";
28642
- try {
28643
- await downloader.file(url2, part, sha256);
28644
- fs23.rmSync(file3, { force: true });
28645
- fs23.renameSync(part, file3);
28646
- } finally {
28647
- fs23.rmSync(part, { force: true });
28648
- }
28649
- }
28650
- async function installFromGithub(repo, pattern, o) {
28651
- const asset = await githubAsset(repo, pattern, o.searchOlder);
28652
- log("Downloading " + (typeof o.what === "string" ? o.what : o.what(asset)) + " ...");
28653
- await downloader.archive(asset.url, o.dest, {
28654
- sha256: asset.sha256,
28655
- fileName: asset.name,
28656
- ...o.locate ? { locate: o.locate } : {},
28657
- ...o.up ? { up: o.up } : {}
28658
- });
28659
- }
28660
-
28661
- // src/guest/databases/mongodb.ts
28979
+ import path27 from "node:path";
28662
28980
  var MongoServer = class extends DatabaseServer {
28663
28981
  id = "mongodb";
28664
28982
  async start(env, plan2) {
@@ -28673,13 +28991,13 @@ var MongoServer = class extends DatabaseServer {
28673
28991
  };
28674
28992
  const version2 = await resolveCached("mongodb:" + plan2.version, async () => (await find()).version);
28675
28993
  const home = tool("mongodb", version2);
28676
- if (!exists(path26.join(home, "bin", "mongod.exe"))) {
28994
+ if (!exists(path27.join(home, "bin", "mongod.exe"))) {
28677
28995
  const { archive } = await find();
28678
28996
  log("Downloading MongoDB " + version2 + " (~400 MB once) ...");
28679
28997
  await downloader.archive(archive.url, home, { sha256: archive.sha256, locate: "mongod.exe", up: 1 });
28680
28998
  }
28681
28999
  const shell = tool("mongosh");
28682
- if (!exists(path26.join(shell, "mongosh.exe"))) {
29000
+ if (!exists(path27.join(shell, "mongosh.exe"))) {
28683
29001
  await installFromGithub("mongodb-js/mongosh", /^mongosh-[\d.]+-win32-x64\.zip$/, {
28684
29002
  dest: shell,
28685
29003
  what: "mongosh, the MongoDB shell (~50 MB once)",
@@ -28690,17 +29008,17 @@ var MongoServer = class extends DatabaseServer {
28690
29008
  await clearStaleLocks(data, ["mongod.lock"], plan2.port);
28691
29009
  await startServer(
28692
29010
  "mongodb",
28693
- path26.join(home, "bin", "mongod.exe"),
29011
+ path27.join(home, "bin", "mongod.exe"),
28694
29012
  ["--dbpath", data, "--bind_ip", "127.0.0.1", "--port", String(plan2.port)],
28695
29013
  plan2.port
28696
29014
  );
28697
- env.prepend.push(path26.join(home, "bin"), shell);
29015
+ env.prepend.push(path27.join(home, "bin"), shell);
28698
29016
  env.summary.push("mongodb " + version2 + ": mongodb://127.0.0.1:" + plan2.port + " (mongosh on PATH)");
28699
29017
  }
28700
29018
  };
28701
29019
 
28702
29020
  // src/guest/databases/mysql.ts
28703
- import path27 from "node:path";
29021
+ import path28 from "node:path";
28704
29022
  var MARIA = "https://downloads.mariadb.org/rest-api/mariadb/";
28705
29023
  var MysqlServer = class extends DatabaseServer {
28706
29024
  id = "mysql";
@@ -28718,8 +29036,8 @@ var MysqlServer = class extends DatabaseServer {
28718
29036
  };
28719
29037
  const version2 = await resolveCached("mariadb-version:" + series, async () => (await latest()).version);
28720
29038
  const home = tool("mariadb", version2);
28721
- const bin = path27.join(home, "bin");
28722
- if (!exists(path27.join(bin, "mariadbd.exe"))) {
29039
+ const bin = path28.join(home, "bin");
29040
+ if (!exists(path28.join(bin, "mariadbd.exe"))) {
28723
29041
  const { zip } = await latest();
28724
29042
  log("Downloading MariaDB " + version2 + " (~90 MB once) ...");
28725
29043
  await downloader.archive(zip.file_download_url.replace(/^http:/, "https:"), home, {
@@ -28732,13 +29050,13 @@ var MysqlServer = class extends DatabaseServer {
28732
29050
  const data = dataFor("mariadb");
28733
29051
  await createOnce(data, "mysql", async () => {
28734
29052
  log("Creating the MariaDB database (first start) ...");
28735
- await execAsync(path27.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], {
29053
+ await execAsync(path28.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], {
28736
29054
  stdio: "ignore"
28737
29055
  });
28738
29056
  });
28739
29057
  await startServer(
28740
29058
  "mysql",
28741
- path27.join(bin, "mariadbd.exe"),
29059
+ path28.join(bin, "mariadbd.exe"),
28742
29060
  ["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"],
28743
29061
  plan2.port
28744
29062
  );
@@ -28752,7 +29070,7 @@ var MysqlServer = class extends DatabaseServer {
28752
29070
 
28753
29071
  // src/guest/databases/postgres.ts
28754
29072
  import fs24 from "node:fs";
28755
- import path28 from "node:path";
29073
+ import path29 from "node:path";
28756
29074
  function postgresData(version2) {
28757
29075
  return dataFor("postgres-" + version2.split(".")[0]);
28758
29076
  }
@@ -28767,8 +29085,8 @@ var PostgresServer = class extends DatabaseServer {
28767
29085
  return hit ? hit.major + "." + hit.latestMinor : Promise.reject(new Error("No supported PostgreSQL " + plan2.version));
28768
29086
  });
28769
29087
  const home = tool("postgres", exact);
28770
- const bin = path28.join(home, "bin");
28771
- if (!exists(path28.join(bin, "pg_ctl.exe"))) {
29088
+ const bin = path29.join(home, "bin");
29089
+ if (!exists(path29.join(bin, "pg_ctl.exe"))) {
28772
29090
  log("Downloading PostgreSQL " + exact + " (~330 MB once) ...");
28773
29091
  await downloader.archive(
28774
29092
  "https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip",
@@ -28785,7 +29103,7 @@ var PostgresServer = class extends DatabaseServer {
28785
29103
  await createOnce(data, "PG_VERSION", async () => {
28786
29104
  log("Creating the PostgreSQL database (first start) ...");
28787
29105
  await execAsync(
28788
- path28.join(bin, "initdb.exe"),
29106
+ path29.join(bin, "initdb.exe"),
28789
29107
  ["-D", data, "-U", "postgres", "-A", "trust", "-E", "UTF8", "--locale=C"],
28790
29108
  { stdio: "ignore" }
28791
29109
  );
@@ -28794,7 +29112,7 @@ var PostgresServer = class extends DatabaseServer {
28794
29112
  throw new Error("port " + plan2.port + " is already in use (change databases.postgres.port)");
28795
29113
  await clearStaleLocks(data, ["postmaster.pid"], plan2.port);
28796
29114
  await execAsync(
28797
- path28.join(bin, "pg_ctl.exe"),
29115
+ path29.join(bin, "pg_ctl.exe"),
28798
29116
  [
28799
29117
  "start",
28800
29118
  "-D",
@@ -28803,7 +29121,7 @@ var PostgresServer = class extends DatabaseServer {
28803
29121
  "-t",
28804
29122
  "60",
28805
29123
  "-l",
28806
- path28.join(logsDir, "postgres.log"),
29124
+ path29.join(logsDir, "postgres.log"),
28807
29125
  "-o",
28808
29126
  "-p " + plan2.port + " -c listen_addresses=localhost"
28809
29127
  ],
@@ -28820,8 +29138,8 @@ var PostgresServer = class extends DatabaseServer {
28820
29138
  if (exists(tool("postgres"))) {
28821
29139
  for (const version2 of fs24.readdirSync(tool("postgres"))) {
28822
29140
  const data = postgresData(version2);
28823
- const pgCtl = path28.join(tool("postgres", version2), "bin", "pg_ctl.exe");
28824
- if (exists(path28.join(data, "postmaster.pid")) && exists(pgCtl))
29141
+ const pgCtl = path29.join(tool("postgres", version2), "bin", "pg_ctl.exe");
29142
+ if (exists(path29.join(data, "postmaster.pid")) && exists(pgCtl))
28825
29143
  await execAsync(pgCtl, ["stop", "-D", data, "-m", "fast", "-w"], { stdio: "ignore" });
28826
29144
  }
28827
29145
  }
@@ -28830,12 +29148,12 @@ var PostgresServer = class extends DatabaseServer {
28830
29148
  };
28831
29149
 
28832
29150
  // src/guest/databases/redis.ts
28833
- import path29 from "node:path";
29151
+ import path30 from "node:path";
28834
29152
  var RedisServer = class extends DatabaseServer {
28835
29153
  id = "redis";
28836
29154
  async start(env, plan2) {
28837
29155
  const home = tool("redis");
28838
- if (!exists(path29.join(home, "redis-server.exe"))) {
29156
+ if (!exists(path30.join(home, "redis-server.exe"))) {
28839
29157
  await installFromGithub("redis-windows/redis-windows", /^Redis-[\d.]+-Windows-x64-msys2\.zip$/, {
28840
29158
  dest: home,
28841
29159
  what: (a) => "Redis (" + a.name + ", ~10 MB once)",
@@ -28845,7 +29163,7 @@ var RedisServer = class extends DatabaseServer {
28845
29163
  const data = mkdirp(dataFor("redis"));
28846
29164
  await startServer(
28847
29165
  "redis",
28848
- path29.join(home, "redis-server.exe"),
29166
+ path30.join(home, "redis-server.exe"),
28849
29167
  ["--port", String(plan2.port), "--bind", "127.0.0.1", "--dir", data.replace(/\\/g, "/"), "--appendonly", "yes"],
28850
29168
  plan2.port
28851
29169
  );
@@ -28884,15 +29202,15 @@ async function setupDatabase(env, plan2) {
28884
29202
 
28885
29203
  // src/guest/toolchains/tools/git.ts
28886
29204
  import fs26 from "node:fs";
28887
- import path31 from "node:path";
29205
+ import path32 from "node:path";
28888
29206
 
28889
29207
  // src/guest/runtime/csc.ts
28890
29208
  import fs25 from "node:fs";
28891
29209
  import os6 from "node:os";
28892
- import path30 from "node:path";
29210
+ import path31 from "node:path";
28893
29211
  import crypto3 from "node:crypto";
28894
29212
  import { spawnSync as spawnSync3 } from "node:child_process";
28895
- var CSC = path30.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
29213
+ var CSC = path31.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
28896
29214
  var SOURCES = {
28897
29215
  ptyhost: "PtyHost.cs",
28898
29216
  gitshim: "GitShim.cs",
@@ -28904,17 +29222,17 @@ var SOURCES = {
28904
29222
  memgov: "MemGov.cs"
28905
29223
  };
28906
29224
  function sourceOf(name) {
28907
- return path30.join(launchDir, "sandbox", "csharp", SOURCES[name]);
29225
+ return path31.join(launchDir, "sandbox", "csharp", SOURCES[name]);
28908
29226
  }
28909
29227
  function sourceHash(name) {
28910
29228
  return crypto3.createHash("sha256").update(fs25.readFileSync(sourceOf(name))).digest("hex").slice(0, 12);
28911
29229
  }
28912
29230
  function ensureCompiled(name) {
28913
- const exe = path30.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
29231
+ const exe = path31.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
28914
29232
  if (exists(exe)) return exe;
28915
29233
  if (!exists(CSC))
28916
29234
  throw new Error("The .NET Framework C# compiler was not found at " + CSC + " (it ships with Windows 10/11).");
28917
- mkdirp(path30.dirname(exe));
29235
+ mkdirp(path31.dirname(exe));
28918
29236
  const result = spawnSync3(CSC, ["/nologo", "/optimize", "/target:exe", "/out:" + exe, sourceOf(name)], {
28919
29237
  encoding: "utf8",
28920
29238
  windowsHide: true
@@ -28953,18 +29271,18 @@ var installPortableGit = async (root) => {
28953
29271
  };
28954
29272
  var installGuard = (env, access, realGit) => {
28955
29273
  const dir = mkdirp(tool("gitguard"));
28956
- const guard = path31.join(launchDir, "runtime", "gitguard.js");
28957
- if (duringSession() && (exists(path31.join(dir, "git.exe")) || exists(path31.join(dir, "git.cmd")))) {
29274
+ const guard = path32.join(launchDir, "runtime", "gitguard.js");
29275
+ if (duringSession() && (exists(path32.join(dir, "git.exe")) || exists(path32.join(dir, "git.cmd")))) {
28958
29276
  } else
28959
29277
  try {
28960
- fs26.copyFileSync(ensureCompiled("gitshim"), path31.join(dir, "git.exe"));
28961
- fs26.rmSync(path31.join(dir, "git.cmd"), { force: true });
29278
+ fs26.copyFileSync(ensureCompiled("gitshim"), path32.join(dir, "git.exe"));
29279
+ fs26.rmSync(path32.join(dir, "git.cmd"), { force: true });
28962
29280
  } catch (e) {
28963
29281
  warn("git guard: falling back to git.cmd (" + errMsg(e) + ")");
28964
- fs26.writeFileSync(path31.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
29282
+ fs26.writeFileSync(path32.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
28965
29283
  }
28966
29284
  fs26.writeFileSync(
28967
- path31.join(dir, "bashenv.sh"),
29285
+ path32.join(dir, "bashenv.sh"),
28968
29286
  'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n'
28969
29287
  );
28970
29288
  env.prepend.unshift(dir);
@@ -28973,13 +29291,13 @@ var installGuard = (env, access, realGit) => {
28973
29291
  AGENT_REAL_GIT: access === "readonly" ? realGit : "",
28974
29292
  AGENT_GUARD_NODE: process.execPath,
28975
29293
  AGENT_GUARD_SCRIPT: guard,
28976
- BASH_ENV: posix(path31.join(dir, "bashenv.sh"))
29294
+ BASH_ENV: posix(path32.join(dir, "bashenv.sh"))
28977
29295
  });
28978
29296
  if (access === "readonly") {
28979
- const hooks = mkdirp(path31.join(dir, "hooks"));
29297
+ const hooks = mkdirp(path32.join(dir, "hooks"));
28980
29298
  for (const hook of BLOCKED_HOOKS)
28981
29299
  fs26.writeFileSync(
28982
- path31.join(hooks, hook),
29300
+ path32.join(hooks, hook),
28983
29301
  '#!/bin/sh\necho "git is read-only in this sandbox: ' + hook + ' refused." >&2\nexit 1\n'
28984
29302
  );
28985
29303
  Object.assign(env.vars, {
@@ -28988,12 +29306,12 @@ var installGuard = (env, access, realGit) => {
28988
29306
  GIT_CONFIG_VALUE_0: posix(hooks)
28989
29307
  });
28990
29308
  } else {
28991
- env.vars.GIT_DIR = path31.join(dataDir, "git-disabled");
29309
+ env.vars.GIT_DIR = path32.join(dataDir, "git-disabled");
28992
29310
  }
28993
29311
  };
28994
29312
  var pointAtOwnCertificates = (root) => {
28995
- const config2 = path31.join(root, "etc", "gitconfig");
28996
- const bundle = path31.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
29313
+ const config2 = path32.join(root, "etc", "gitconfig");
29314
+ const bundle = path32.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
28997
29315
  if (!exists(config2) || !exists(bundle)) return;
28998
29316
  const text = fs26.readFileSync(config2, "utf8");
28999
29317
  const fixed = text.replace(/^(\s*sslCAInfo\s*=\s*).*$/gim, (_m, key) => key + posix(bundle));
@@ -29001,9 +29319,9 @@ var pointAtOwnCertificates = (root) => {
29001
29319
  };
29002
29320
  async function setupGit(env, hostCopy, refresh, access) {
29003
29321
  const root = tool("git");
29004
- const bash = path31.join(root, "bin", "bash.exe");
29005
- const gitExe = path31.join(root, "cmd", "git.exe");
29006
- const hostGit = path31.join(hostToolsDir, "git");
29322
+ const bash = path32.join(root, "bin", "bash.exe");
29323
+ const gitExe = path32.join(root, "cmd", "git.exe");
29324
+ const hostGit = path32.join(hostToolsDir, "git");
29007
29325
  if (exists(root) && !exists(bash)) {
29008
29326
  log("Replacing the old MinGit (no bash) with full Git for Windows.");
29009
29327
  safeRemove(root, toolsDir);
@@ -29017,11 +29335,11 @@ async function setupGit(env, hostCopy, refresh, access) {
29017
29335
  }
29018
29336
  const work = stagingFolder(root);
29019
29337
  try {
29020
- if (hostCopy && exists(path31.join(hostGit, "bin", "bash.exe"))) {
29338
+ if (hostCopy && exists(path32.join(hostGit, "bin", "bash.exe"))) {
29021
29339
  log("Copying Git for Windows from this PC ...");
29022
29340
  robocopy(hostGit, work);
29023
29341
  } else await installPortableGit(work);
29024
- if (!exists(path31.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
29342
+ if (!exists(path32.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
29025
29343
  moveIntoPlace(work, root);
29026
29344
  } finally {
29027
29345
  safeRemove(work, toolsDir);
@@ -29030,10 +29348,10 @@ async function setupGit(env, hostCopy, refresh, access) {
29030
29348
  if (!exists(bash)) throw new Error("bash.exe missing after installing Git");
29031
29349
  pointAtOwnCertificates(root);
29032
29350
  env.vars.CLAUDE_CODE_GIT_BASH_PATH = bash;
29033
- env.append.push(path31.join(root, "usr", "bin"));
29351
+ env.append.push(path32.join(root, "usr", "bin"));
29034
29352
  const version2 = execOutput(gitExe, ["--version"]).replace(/^git version /, "");
29035
29353
  if (access === "full") {
29036
- env.prepend.push(path31.join(root, "cmd"));
29354
+ env.prepend.push(path32.join(root, "cmd"));
29037
29355
  env.summary.push("git: " + version2);
29038
29356
  return;
29039
29357
  }
@@ -29045,7 +29363,7 @@ async function setupGit(env, hostCopy, refresh, access) {
29045
29363
 
29046
29364
  // src/guest/toolchains/languages/go.ts
29047
29365
  import fs27 from "node:fs";
29048
- import path32 from "node:path";
29366
+ import path33 from "node:path";
29049
29367
 
29050
29368
  // src/guest/toolchains/package-ledger.ts
29051
29369
  var LedgerSchema = external_exports.record(external_exports.string(), external_exports.string());
@@ -29099,7 +29417,7 @@ async function setupGo(env, config2) {
29099
29417
  }
29100
29418
  const version2 = await resolveCached("go:" + config2.version, async () => (await findRelease(config2.version)).version);
29101
29419
  const root = tool("go", version2);
29102
- if (!exists(path32.join(root, "bin", "go.exe"))) {
29420
+ if (!exists(path33.join(root, "bin", "go.exe"))) {
29103
29421
  const goArch = arch === "arm64" ? "arm64" : "amd64";
29104
29422
  const file3 = (await findRelease(version2)).files.find(
29105
29423
  (f) => f.os === "windows" && f.arch === goArch && f.kind === "archive"
@@ -29116,16 +29434,16 @@ async function setupGo(env, config2) {
29116
29434
  const vars = {
29117
29435
  GOROOT: root,
29118
29436
  GOPATH,
29119
- GOBIN: path32.join(GOPATH, "bin"),
29120
- GOMODCACHE: path32.join(GOPATH, "pkg", "mod"),
29437
+ GOBIN: path33.join(GOPATH, "bin"),
29438
+ GOMODCACHE: path33.join(GOPATH, "pkg", "mod"),
29121
29439
  GOCACHE: tool("go-cache"),
29122
29440
  GOTOOLCHAIN: "auto",
29123
29441
  GOTELEMETRY: "off"
29124
29442
  };
29125
29443
  fs27.mkdirSync(vars.GOBIN, { recursive: true });
29126
29444
  Object.assign(env.vars, vars);
29127
- env.prepend.push(path32.join(root, "bin"), vars.GOBIN);
29128
- const go = path32.join(root, "bin", "go.exe");
29445
+ env.prepend.push(path33.join(root, "bin"), vars.GOBIN);
29446
+ const go = path33.join(root, "bin", "go.exe");
29129
29447
  env.summary.push("go: " + versionOf(go, ["version"]));
29130
29448
  await installOnce(
29131
29449
  env,
@@ -29183,77 +29501,6 @@ function decideCli(settings, ctx) {
29183
29501
  return Object.fromEntries(CLI_NAMES.map((name) => [name, decide(name)]));
29184
29502
  }
29185
29503
 
29186
- // src/guest/toolchains/runtimes.ts
29187
- import path33 from "node:path";
29188
- async function setupSingleExe(env, name, repo, pattern, exeName, dir, options = {}) {
29189
- if (dryRun) {
29190
- log("(dry run) would provision " + name);
29191
- return;
29192
- }
29193
- const bin = options.subdir ? path33.join(dir, options.subdir) : dir;
29194
- const exe = path33.join(bin, exeName);
29195
- if (!exists(exe) || options.refresh) {
29196
- const size = options.size ? ", ~" + options.size : "";
29197
- await installFromGithub(repo, pattern, {
29198
- dest: dir,
29199
- what: (a) => name + " (" + a.name + size + " once)",
29200
- ...options.subdir ? {} : { locate: exeName }
29201
- });
29202
- }
29203
- if (!exists(exe)) throw new Error(exeName + " missing after installing " + name);
29204
- env.prepend.push(bin);
29205
- env.summary.push(name + ": " + versionOf(exe, options.versionArgs) + (options.note ?? ""));
29206
- }
29207
- async function setupBun(env) {
29208
- await setupSingleExe(
29209
- env,
29210
- "bun",
29211
- "oven-sh/bun",
29212
- arch === "arm64" ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/,
29213
- "bun.exe",
29214
- tool("bun", "bin"),
29215
- { size: "35 MB" }
29216
- );
29217
- Object.assign(env.vars, {
29218
- BUN_INSTALL: tool("bun"),
29219
- BUN_INSTALL_CACHE_DIR: path33.join(localDir, "bun-cache"),
29220
- BUN_TMPDIR: path33.join(localDir, "bun-tmp")
29221
- });
29222
- }
29223
- async function setupDeno(env) {
29224
- await setupSingleExe(
29225
- env,
29226
- "deno",
29227
- "denoland/deno",
29228
- arch === "arm64" ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/,
29229
- "deno.exe",
29230
- tool("deno", "bin"),
29231
- { size: "40 MB" }
29232
- );
29233
- Object.assign(env.vars, { DENO_DIR: tool("deno-cache"), DENO_INSTALL_ROOT: tool("deno"), DENO_NO_UPDATE_CHECK: "1" });
29234
- }
29235
- function uvVars() {
29236
- return {
29237
- UV_CACHE_DIR: tool("uv-cache"),
29238
- UV_PYTHON_INSTALL_DIR: tool("uv-python"),
29239
- UV_TOOL_DIR: tool("uv-tools"),
29240
- UV_TOOL_BIN_DIR: tool("uv-bin")
29241
- };
29242
- }
29243
- async function setupUv(env) {
29244
- await setupSingleExe(
29245
- env,
29246
- "uv",
29247
- "astral-sh/uv",
29248
- arch === "arm64" ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/,
29249
- "uv.exe",
29250
- tool("uv"),
29251
- { size: "20 MB" }
29252
- );
29253
- Object.assign(env.vars, uvVars());
29254
- env.prepend.push(mkdirp(tool("uv-bin")));
29255
- }
29256
-
29257
29504
  // src/guest/toolchains/tools/cli.ts
29258
29505
  function ghConfigDir() {
29259
29506
  return path34.join(stateDir, "gh");
@@ -31286,12 +31533,12 @@ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
31286
31533
  }
31287
31534
  return result;
31288
31535
  }
31289
- function findNodeAtLocation(root, path75) {
31536
+ function findNodeAtLocation(root, path77) {
31290
31537
  if (!root) {
31291
31538
  return void 0;
31292
31539
  }
31293
31540
  let node2 = root;
31294
- for (let segment of path75) {
31541
+ for (let segment of path77) {
31295
31542
  if (typeof segment === "string") {
31296
31543
  if (node2.type !== "object" || !Array.isArray(node2.children)) {
31297
31544
  return void 0;
@@ -31645,14 +31892,14 @@ function getNodeType(value) {
31645
31892
 
31646
31893
  // node_modules/jsonc-parser/lib/esm/impl/edit.js
31647
31894
  function setProperty(text, originalPath, value, options) {
31648
- const path75 = originalPath.slice();
31895
+ const path77 = originalPath.slice();
31649
31896
  const errors = [];
31650
31897
  const root = parseTree(text, errors);
31651
31898
  let parent = void 0;
31652
31899
  let lastSegment = void 0;
31653
- while (path75.length > 0) {
31654
- lastSegment = path75.pop();
31655
- parent = findNodeAtLocation(root, path75);
31900
+ while (path77.length > 0) {
31901
+ lastSegment = path77.pop();
31902
+ parent = findNodeAtLocation(root, path77);
31656
31903
  if (parent === void 0 && value !== void 0) {
31657
31904
  if (typeof lastSegment === "string") {
31658
31905
  value = { [lastSegment]: value };
@@ -31838,8 +32085,8 @@ var ParseErrorCode;
31838
32085
  ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
31839
32086
  ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
31840
32087
  })(ParseErrorCode || (ParseErrorCode = {}));
31841
- function modify(text, path75, value, options) {
31842
- return setProperty(text, path75, value, options);
32088
+ function modify(text, path77, value, options) {
32089
+ return setProperty(text, path77, value, options);
31843
32090
  }
31844
32091
  function applyEdits(text, edits) {
31845
32092
  let sortedEdits = edits.slice(0).sort((a, b) => {
@@ -32232,7 +32479,12 @@ function plan(config2, versions, o) {
32232
32479
  },
32233
32480
  { name: "Deno", enabled: wanted(config2.deno.enabled, "deno"), install: (env) => setupDeno(env) },
32234
32481
  { name: "Bun", enabled: wanted(config2.bun.enabled, "bun"), install: (env) => setupBun(env) },
32235
- { name: "uv", enabled: wanted(config2.uv.enabled, "uv"), install: (env) => setupUv(env) },
32482
+ // Headroom (an agent add-on) installs with uv: the uv step runs for it too, before the apps.
32483
+ {
32484
+ name: "uv",
32485
+ enabled: wanted(config2.uv.enabled, "uv") || appsNeedUv(o.apps),
32486
+ install: (env) => setupUv(env)
32487
+ },
32236
32488
  { name: "PowerShell 7", enabled: wanted(config2.pwsh.enabled, "pwsh"), install: (env) => setupPwsh(env, o.refresh) },
32237
32489
  // The openssl tool comes from Git's install: after Git.
32238
32490
  {
@@ -32258,7 +32510,7 @@ function plan(config2, versions, o) {
32258
32510
  name: "Apps",
32259
32511
  enabled: apps,
32260
32512
  shared: true,
32261
- after: ["Mesa 3D", "Visual C++ runtime"],
32513
+ after: ["Mesa 3D", "Visual C++ runtime", "uv"],
32262
32514
  install: (env) => setupApps(env, o.apps, { gitAccess: o.gitAccess, refresh: o.refresh })
32263
32515
  },
32264
32516
  {
@@ -33496,42 +33748,124 @@ function gitDenyRules(access) {
33496
33748
  function managedSettingsFile() {
33497
33749
  return path63.join(path63.dirname(managedClaudeMd()), "managed-settings.json");
33498
33750
  }
33499
- function writeManagedSettings2(access) {
33751
+ function writeManagedSettings2(access, headroom = null) {
33500
33752
  const file3 = managedSettingsFile();
33501
- const deny = gitDenyRules(access);
33502
- if (deny.length === 0) {
33753
+ const rtk = installedRtk();
33754
+ const settings = claudeManagedSettings(gitDenyRules(access), rtk, headroom);
33755
+ if (!settings) {
33503
33756
  fs50.rmSync(file3, { force: true });
33504
33757
  return;
33505
33758
  }
33506
33759
  fs50.mkdirSync(path63.dirname(file3), { recursive: true });
33507
- fs50.writeFileSync(file3, JSON.stringify({ permissions: { deny } }, null, 2) + "\n", "utf8");
33760
+ fs50.writeFileSync(file3, JSON.stringify(settings, null, 2) + "\n", "utf8");
33761
+ if (rtk) log("rtk: Claude Code's Bash commands go through it (hook in " + file3 + ")");
33508
33762
  }
33509
33763
 
33510
- // src/guest/setup/desktop.ts
33764
+ // src/guest/setup/addon-mcp.ts
33511
33765
  import fs51 from "node:fs";
33512
- import os10 from "node:os";
33513
33766
  import path64 from "node:path";
33767
+ var ADDON_MCP_NAMES = APPS.flatMap((a) => a.mcp ? [a.mcp.name] : []);
33768
+ function writeAddonMcpServers() {
33769
+ const servers = {};
33770
+ for (const { id, folder } of installedMcpAddons()) {
33771
+ const mcp = APPS.find((a) => a.id === id)?.mcp;
33772
+ if (mcp) servers[mcp.name] = addonMcpServer(folder, mcp);
33773
+ }
33774
+ const file3 = path64.join(claudeDir, ".claude.json");
33775
+ let state = {};
33776
+ if (fs51.existsSync(file3)) {
33777
+ try {
33778
+ const text = fs51.readFileSync(file3, "utf8");
33779
+ state = JSON.parse(text.charCodeAt(0) === 65279 ? text.slice(1) : text);
33780
+ } catch {
33781
+ warn("Claude Code MCP servers from Apps: " + file3 + " is not valid JSON, left as it is");
33782
+ return [];
33783
+ }
33784
+ } else if (!Object.keys(servers).length) return [];
33785
+ if (typeof state !== "object" || state === null || Array.isArray(state)) return [];
33786
+ const current = state.mcpServers;
33787
+ const before = current && typeof current === "object" && !Array.isArray(current) ? current : {};
33788
+ const after = withAddonMcpServers(before, servers, ADDON_MCP_NAMES);
33789
+ if (JSON.stringify(before) !== JSON.stringify(after)) {
33790
+ fs51.mkdirSync(claudeDir, { recursive: true });
33791
+ writeJsonAtomic(file3, { ...state, mcpServers: after });
33792
+ }
33793
+ const names = Object.keys(servers);
33794
+ if (names.length) log("Claude Code MCP servers from Apps: " + names.join(", "));
33795
+ return names;
33796
+ }
33797
+
33798
+ // src/guest/setup/headroom.ts
33799
+ import fs52 from "node:fs";
33800
+ import http from "node:http";
33801
+ import path65 from "node:path";
33802
+ import { spawn as spawn7 } from "node:child_process";
33803
+ var HEADROOM_LOG = path65.join(logsDir, "headroom.log");
33804
+ function answersAsHeadroom(port) {
33805
+ return new Promise((resolve2) => {
33806
+ const req = http.get({ host: "127.0.0.1", port, path: "/livez", timeout: 3e3 }, (res) => {
33807
+ let body = "";
33808
+ res.setEncoding("utf8");
33809
+ res.on("data", (chunk) => {
33810
+ if (body.length < 4096) body += chunk;
33811
+ });
33812
+ res.on("end", () => resolve2(res.statusCode === 200 && /"service"\s*:\s*"headroom-proxy"/.test(body)));
33813
+ });
33814
+ req.on("timeout", () => req.destroy());
33815
+ req.on("error", () => resolve2(false));
33816
+ });
33817
+ }
33818
+ async function startHeadroom(env) {
33819
+ const exe = installedAddon("headroom");
33820
+ if (!exe) return null;
33821
+ if (env.ANTHROPIC_BASE_URL) {
33822
+ log("Headroom: not used, ANTHROPIC_BASE_URL is set in the agent environment (" + env.ANTHROPIC_BASE_URL + ")");
33823
+ return null;
33824
+ }
33825
+ const port = HEADROOM_PORT;
33826
+ if (!await portOpen(port)) {
33827
+ const out = fs52.openSync(HEADROOM_LOG, "a");
33828
+ spawn7(exe, headroomArgs(port), {
33829
+ detached: true,
33830
+ stdio: ["ignore", out, out],
33831
+ windowsHide: true,
33832
+ env: headroomEnv(env)
33833
+ }).unref();
33834
+ fs52.closeSync(out);
33835
+ if (!await waitForPort(port, 90))
33836
+ throw new Error("the Headroom proxy did not start on port " + port + "; see " + HEADROOM_LOG);
33837
+ }
33838
+ if (!await answersAsHeadroom(port))
33839
+ throw new Error("port " + port + " is taken by another program; Claude Code talks to the API directly");
33840
+ log("Headroom: Claude Code reaches the API through " + headroomUrl(port) + " (log: " + HEADROOM_LOG + ")");
33841
+ return headroomUrl(port);
33842
+ }
33843
+
33844
+ // src/guest/setup/desktop.ts
33845
+ import fs53 from "node:fs";
33846
+ import os10 from "node:os";
33847
+ import path66 from "node:path";
33514
33848
  function applyPersonalization() {
33515
- const dir = path64.join(launchDir, "personalize");
33849
+ const dir = path66.join(launchDir, "personalize");
33516
33850
  if (!session.personalization || !exists(dir) || dryRun || !isWin) return;
33517
- exec(SYSTEM.reg(), ["import", path64.join(dir, "personalize.reg")], { stdio: "ignore" });
33518
- const wallpaper = fs51.readdirSync(dir).find((f) => f.startsWith("wallpaper"));
33519
- const local = wallpaper ? path64.join(mkdirp(path64.join(os10.homedir(), "Pictures")), wallpaper) : null;
33520
- if (wallpaper && local) fs51.copyFileSync(path64.join(dir, wallpaper), local);
33851
+ exec(SYSTEM.reg(), ["import", path66.join(dir, "personalize.reg")], { stdio: "ignore" });
33852
+ const wallpaper = fs53.readdirSync(dir).find((f) => f.startsWith("wallpaper"));
33853
+ const local = wallpaper ? path66.join(mkdirp(path66.join(os10.homedir(), "Pictures")), wallpaper) : null;
33854
+ if (wallpaper && local) fs53.copyFileSync(path66.join(dir, wallpaper), local);
33521
33855
  runScript("set-desktop.ps1", local ? ["-Wallpaper", local] : []);
33522
33856
  log("Desktop personalisation applied from this PC.");
33523
33857
  }
33524
33858
 
33525
33859
  // src/guest/setup/git-identity.ts
33526
- import fs52 from "node:fs";
33860
+ import fs54 from "node:fs";
33527
33861
  import os11 from "node:os";
33528
- import path65 from "node:path";
33862
+ import path67 from "node:path";
33529
33863
  import { spawnSync as spawnSync7 } from "node:child_process";
33530
33864
  function setupGitConfig(env) {
33531
33865
  if (dryRun) return;
33532
- const source = path65.join(launchDir, "home", ".gitconfig");
33533
- if (exists(source)) fs52.copyFileSync(source, path65.join(os11.homedir(), ".gitconfig"));
33534
- const git = path65.join(toolsDir, "git", "cmd", "git.exe");
33866
+ const source = path67.join(launchDir, "home", ".gitconfig");
33867
+ if (exists(source)) fs54.copyFileSync(source, path67.join(os11.homedir(), ".gitconfig"));
33868
+ const git = path67.join(toolsDir, "git", "cmd", "git.exe");
33535
33869
  if (!exists(git)) return;
33536
33870
  const { GIT_DIR: _gitDir, ...rest } = env;
33537
33871
  spawnSync7(git, ["config", "--global", "--add", "safe.directory", "*"], {
@@ -33544,7 +33878,7 @@ function setupGitConfig(env) {
33544
33878
  }
33545
33879
 
33546
33880
  // src/guest/setup/github-token.ts
33547
- import fs53 from "node:fs";
33881
+ import fs55 from "node:fs";
33548
33882
  import { spawnSync as spawnSync8 } from "node:child_process";
33549
33883
 
33550
33884
  // src/shared/github/token.ts
@@ -33590,7 +33924,7 @@ function ghOutputText(text, token) {
33590
33924
  var GH_TIMEOUT_MS = 6e4;
33591
33925
  function prepareGithubFolder(token) {
33592
33926
  const dir = deliveredGhConfigDir();
33593
- fs53.rmSync(dir, { recursive: true, force: true });
33927
+ fs55.rmSync(dir, { recursive: true, force: true });
33594
33928
  if (!token) return false;
33595
33929
  mkdirp(dir);
33596
33930
  return true;
@@ -33618,7 +33952,7 @@ function loginGithub(token, env) {
33618
33952
  const gh2 = ghExePath();
33619
33953
  const dir = deliveredGhConfigDir();
33620
33954
  if (!exists(gh2) || env.GH_CONFIG_DIR !== dir) {
33621
- fs53.rmSync(dir, { recursive: true, force: true });
33955
+ fs55.rmSync(dir, { recursive: true, force: true });
33622
33956
  log("A GitHub token arrived, but gh is not set up in this sandbox (toolchains.cli.gh), so it is not used.");
33623
33957
  return;
33624
33958
  }
@@ -33626,7 +33960,7 @@ function loginGithub(token, env) {
33626
33960
  runGh(ghLoginCommand(gh2, dir, token, env), token, "gh auth login");
33627
33961
  runGh(ghSetupGitCommand(gh2, dir, env), token, "gh auth setup-git");
33628
33962
  } catch (e) {
33629
- fs53.rmSync(dir, { recursive: true, force: true });
33963
+ fs55.rmSync(dir, { recursive: true, force: true });
33630
33964
  env.GH_CONFIG_DIR = mkdirp(ghConfigDir());
33631
33965
  addMachineEnvironment({ GH_CONFIG_DIR: env.GH_CONFIG_DIR }, []);
33632
33966
  throw e;
@@ -33640,35 +33974,35 @@ function ensurePtyHost() {
33640
33974
  }
33641
33975
 
33642
33976
  // src/guest/toolchains/leftovers.ts
33643
- import fs54 from "node:fs";
33644
- import path66 from "node:path";
33977
+ import fs56 from "node:fs";
33978
+ import path68 from "node:path";
33645
33979
  var STAGING = /\.staging-[0-9a-f]+$/i;
33646
33980
  var entries2 = (dir) => {
33647
33981
  try {
33648
- return fs54.readdirSync(dir, { withFileTypes: true });
33982
+ return fs56.readdirSync(dir, { withFileTypes: true });
33649
33983
  } catch {
33650
33984
  return [];
33651
33985
  }
33652
33986
  };
33653
33987
  function pruneToolLeftovers() {
33654
- for (const legacy of ["ptyhost", "gitshim"]) safeRemove(path66.join(toolsDir, legacy), toolsDir);
33988
+ for (const legacy of ["ptyhost", "gitshim"]) safeRemove(path68.join(toolsDir, legacy), toolsDir);
33655
33989
  for (const top of entries2(toolsDir)) {
33656
- const dir = path66.join(toolsDir, top.name);
33990
+ const dir = path68.join(toolsDir, top.name);
33657
33991
  if (STAGING.test(top.name)) safeRemove(dir, toolsDir);
33658
33992
  else if (top.isDirectory())
33659
- for (const sub of entries2(dir).filter((e) => STAGING.test(e.name))) safeRemove(path66.join(dir, sub.name), dir);
33993
+ for (const sub of entries2(dir).filter((e) => STAGING.test(e.name))) safeRemove(path68.join(dir, sub.name), dir);
33660
33994
  }
33661
33995
  }
33662
33996
 
33663
33997
  // src/guest/audit/process-audit.ts
33664
- import path67 from "node:path";
33998
+ import path69 from "node:path";
33665
33999
  import { spawnSync as spawnSync9 } from "node:child_process";
33666
34000
  var PROCESS_CREATION = "{0CCE922B-69AE-11D9-BED3-505054503030}";
33667
34001
  var auditOn = () => Boolean(session.auditProcesses) && isWin && !dryRun;
33668
34002
  function enableProcessAudit() {
33669
34003
  if (!auditOn()) return;
33670
34004
  spawnSync9(
33671
- path67.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
34005
+ path69.join(process.env.WINDIR ?? "C:\\Windows", "System32", "auditpol.exe"),
33672
34006
  ["/set", "/subcategory:" + PROCESS_CREATION, "/success:enable"],
33673
34007
  { windowsHide: true, stdio: "ignore" }
33674
34008
  );
@@ -33692,10 +34026,10 @@ function enableProcessAudit() {
33692
34026
 
33693
34027
  // src/guest/vpn/vpn.ts
33694
34028
  import dns2 from "node:dns";
33695
- import fs58 from "node:fs";
34029
+ import fs60 from "node:fs";
33696
34030
  import net3 from "node:net";
33697
34031
  import os14 from "node:os";
33698
- import path71 from "node:path";
34032
+ import path73 from "node:path";
33699
34033
 
33700
34034
  // src/shared/vpn/ovpn.ts
33701
34035
  var PROGRAM_DIRECTIVES = [
@@ -34218,8 +34552,8 @@ function tunnelAddressFromLog(log2) {
34218
34552
 
34219
34553
  // src/guest/vpn/openvpn.ts
34220
34554
  import crypto4 from "node:crypto";
34221
- import fs55 from "node:fs";
34222
- import path68 from "node:path";
34555
+ import fs57 from "node:fs";
34556
+ import path70 from "node:path";
34223
34557
 
34224
34558
  // src/shared/vpn/download.ts
34225
34559
  var OPENVPN_MSI = {
@@ -34249,7 +34583,7 @@ var WIREGUARD_MSI = {
34249
34583
 
34250
34584
  // src/guest/vpn/openvpn.ts
34251
34585
  function openvpnExe(env = process.env) {
34252
- return path68.join(env.ProgramFiles ?? "C:\\Program Files", "OpenVPN", "bin", "openvpn.exe");
34586
+ return path70.join(env.ProgramFiles ?? "C:\\Program Files", "OpenVPN", "bin", "openvpn.exe");
34253
34587
  }
34254
34588
  function openvpnDownload(arch2 = process.arch) {
34255
34589
  const entry = arch2 === "arm64" ? OPENVPN_MSI.arm64 : OPENVPN_MSI.x64;
@@ -34260,20 +34594,20 @@ function repairServiceQueries() {
34260
34594
  if (did === "removed") log("VPN: repaired the Windows service queries installers use (a Windows Sandbox gap).");
34261
34595
  else if (did !== "absent" && did !== "kept") warn("VPN: could not check the Windows service queries installers use.");
34262
34596
  }
34263
- var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs55.readFileSync(file3)).digest("hex") === sha256;
34597
+ var hasHash = (file3, sha256) => crypto4.createHash("sha256").update(fs57.readFileSync(file3)).digest("hex") === sha256;
34264
34598
  async function ensureOpenVpn() {
34265
34599
  const exe = openvpnExe();
34266
34600
  if (!isWin || dryRun) return exe;
34267
34601
  if (exists(exe)) return exe;
34268
34602
  const dl = openvpnDownload();
34269
- const msi = path68.join(mkdirp(path68.join(toolsDir, "downloads")), dl.file);
34603
+ const msi = path70.join(mkdirp(path70.join(toolsDir, "downloads")), dl.file);
34270
34604
  if (!exists(msi) || !hasHash(msi, dl.sha256)) {
34271
34605
  log("VPN: downloading OpenVPN " + OPENVPN_MSI.version + " (about 6 MB)");
34272
34606
  await downloader.file(dl.url, msi, dl.sha256);
34273
34607
  }
34274
34608
  repairServiceQueries();
34275
34609
  log("VPN: installing OpenVPN");
34276
- const logFile2 = path68.join(toolsDir, "downloads", "openvpn-install.log");
34610
+ const logFile2 = path70.join(toolsDir, "downloads", "openvpn-install.log");
34277
34611
  const code = await spawnAsync(SYSTEM.msiexec(), ["/i", msi, "/qn", "/norestart", "/l*v", logFile2], {
34278
34612
  stdio: "ignore"
34279
34613
  });
@@ -34284,10 +34618,10 @@ async function ensureOpenVpn() {
34284
34618
  }
34285
34619
 
34286
34620
  // src/guest/vpn/tunnel.ts
34287
- import { spawn as spawn7 } from "node:child_process";
34288
- import fs56 from "node:fs";
34621
+ import { spawn as spawn8 } from "node:child_process";
34622
+ import fs58 from "node:fs";
34289
34623
  import os12 from "node:os";
34290
- import path69 from "node:path";
34624
+ import path71 from "node:path";
34291
34625
  var DONE = "Initialization Sequence Completed";
34292
34626
  function failureReason(text) {
34293
34627
  if (/AUTH_FAILED/i.test(text))
@@ -34303,19 +34637,19 @@ function failureReason(text) {
34303
34637
  }
34304
34638
  var tail = (text, lines = 12) => text.trim().split(/\r?\n/).slice(-lines).join("\n");
34305
34639
  async function startTunnel(o) {
34306
- const dir = fs56.mkdtempSync(path69.join(os12.tmpdir(), "sbx-vpn-"));
34307
- const auth = path69.join(dir, "login.txt");
34308
- const logFile2 = path69.join(dir, "openvpn.log");
34640
+ const dir = fs58.mkdtempSync(path71.join(os12.tmpdir(), "sbx-vpn-"));
34641
+ const auth = path71.join(dir, "login.txt");
34642
+ const logFile2 = path71.join(dir, "openvpn.log");
34309
34643
  const keepLog = () => {
34310
34644
  try {
34311
- fs56.mkdirSync(logsDir, { recursive: true });
34312
- fs56.copyFileSync(logFile2, path69.join(logsDir, "openvpn.log"));
34645
+ fs58.mkdirSync(logsDir, { recursive: true });
34646
+ fs58.copyFileSync(logFile2, path71.join(logsDir, "openvpn.log"));
34313
34647
  } catch {
34314
34648
  }
34315
34649
  };
34316
- fs56.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
34650
+ fs58.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
34317
34651
  try {
34318
- const child = spawn7(
34652
+ const child = spawn8(
34319
34653
  o.exe,
34320
34654
  ["--config", o.profile, "--auth-user-pass", auth, "--auth-nocache", "--verb", "3", "--log", logFile2],
34321
34655
  { detached: true, stdio: "ignore", windowsHide: true }
@@ -34331,7 +34665,7 @@ async function startTunnel(o) {
34331
34665
  child.unref();
34332
34666
  const deadline = Date.now() + (o.timeoutMs ?? 9e4);
34333
34667
  for (; ; ) {
34334
- const text = fs56.existsSync(logFile2) ? fs56.readFileSync(logFile2, "utf8") : "";
34668
+ const text = fs58.existsSync(logFile2) ? fs58.readFileSync(logFile2, "utf8") : "";
34335
34669
  if (text.includes(DONE)) {
34336
34670
  keepLog();
34337
34671
  const tunnelIp = tunnelAddressFromLog(text) ?? void 0;
@@ -34351,41 +34685,41 @@ async function startTunnel(o) {
34351
34685
  await new Promise((r) => setTimeout(r, 500));
34352
34686
  }
34353
34687
  } finally {
34354
- fs56.rmSync(auth, { force: true });
34688
+ fs58.rmSync(auth, { force: true });
34355
34689
  }
34356
34690
  }
34357
34691
 
34358
34692
  // src/guest/vpn/wireguard.ts
34359
34693
  import { execFile } from "node:child_process";
34360
34694
  import crypto5 from "node:crypto";
34361
- import fs57 from "node:fs";
34695
+ import fs59 from "node:fs";
34362
34696
  import os13 from "node:os";
34363
- import path70 from "node:path";
34697
+ import path72 from "node:path";
34364
34698
  var WIREGUARD_TUNNEL = "sandbox";
34365
34699
  function wireguardDir(env = process.env) {
34366
- return path70.join(env.ProgramFiles ?? "C:\\Program Files", "WireGuard");
34700
+ return path72.join(env.ProgramFiles ?? "C:\\Program Files", "WireGuard");
34367
34701
  }
34368
34702
  function wireguardExe(env = process.env) {
34369
- return path70.join(wireguardDir(env), "wireguard.exe");
34703
+ return path72.join(wireguardDir(env), "wireguard.exe");
34370
34704
  }
34371
34705
  function wireguardDownload(arch2 = process.arch) {
34372
34706
  const entry = arch2 === "arm64" ? WIREGUARD_MSI.arm64 : WIREGUARD_MSI.x64;
34373
34707
  return { ...entry, url: WIREGUARD_MSI.base + entry.file };
34374
34708
  }
34375
- var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs57.readFileSync(file3)).digest("hex") === sha256;
34709
+ var hasHash2 = (file3, sha256) => crypto5.createHash("sha256").update(fs59.readFileSync(file3)).digest("hex") === sha256;
34376
34710
  async function ensureWireguard() {
34377
34711
  const exe = wireguardExe();
34378
34712
  if (!isWin || dryRun) return exe;
34379
34713
  if (exists(exe)) return exe;
34380
34714
  const dl = wireguardDownload();
34381
- const msi = path70.join(mkdirp(path70.join(toolsDir, "downloads")), dl.file);
34715
+ const msi = path72.join(mkdirp(path72.join(toolsDir, "downloads")), dl.file);
34382
34716
  if (!exists(msi) || !hasHash2(msi, dl.sha256)) {
34383
34717
  log("VPN: downloading WireGuard " + WIREGUARD_MSI.version + " (about 3 MB)");
34384
34718
  await downloader.file(dl.url, msi, dl.sha256);
34385
34719
  }
34386
34720
  repairServiceQueries();
34387
34721
  log("VPN: installing WireGuard");
34388
- const logFile2 = path70.join(toolsDir, "downloads", "wireguard-install.log");
34722
+ const logFile2 = path72.join(toolsDir, "downloads", "wireguard-install.log");
34389
34723
  const code = await spawnAsync(
34390
34724
  SYSTEM.msiexec(),
34391
34725
  ["/i", msi, "/qn", "/norestart", "DO_NOT_LAUNCH=1", "/l*v", logFile2],
@@ -34417,10 +34751,10 @@ async function removeWireguardTunnel(exe) {
34417
34751
  }
34418
34752
  }
34419
34753
  async function startWireguardTunnel(o) {
34420
- const root = path70.join(process.env.SystemRoot ?? "C:\\Windows", "Temp");
34421
- const dir = fs57.mkdtempSync(path70.join(fs57.existsSync(root) ? root : os13.tmpdir(), "sbx-wg-"));
34422
- const file3 = path70.join(dir, WIREGUARD_TUNNEL + ".conf");
34423
- fs57.writeFileSync(file3, o.config, "utf8");
34754
+ const root = path72.join(process.env.SystemRoot ?? "C:\\Windows", "Temp");
34755
+ const dir = fs59.mkdtempSync(path72.join(fs59.existsSync(root) ? root : os13.tmpdir(), "sbx-wg-"));
34756
+ const file3 = path72.join(dir, WIREGUARD_TUNNEL + ".conf");
34757
+ fs59.writeFileSync(file3, o.config, "utf8");
34424
34758
  const fail = async (message) => {
34425
34759
  await removeWireguardTunnel(o.exe);
34426
34760
  return { ok: false, message };
@@ -34441,11 +34775,11 @@ async function startWireguardTunnel(o) {
34441
34775
  await sleep(500);
34442
34776
  }
34443
34777
  } finally {
34444
- fs57.rmSync(dir, { recursive: true, force: true });
34778
+ fs59.rmSync(dir, { recursive: true, force: true });
34445
34779
  }
34446
34780
  }
34447
34781
  async function waitForHandshake(exe, poke, timeoutMs = 3e4) {
34448
- const wg = path70.join(path70.dirname(exe), "wg.exe");
34782
+ const wg = path72.join(path72.dirname(exe), "wg.exe");
34449
34783
  if (!exists(wg)) return { ok: true, message: "the tunnel service is running (no wg.exe to check the handshake)" };
34450
34784
  const deadline = Date.now() + timeoutMs;
34451
34785
  for (; ; ) {
@@ -34580,8 +34914,8 @@ async function setupVpn(secrets, ptyHostExe) {
34580
34914
  } else {
34581
34915
  const credentials = secrets.vpn;
34582
34916
  if (!credentials) throw new Error("the VPN login did not arrive (start the sandbox again)");
34583
- const profile = path71.join(launchDir, "vpn", "server.ovpn");
34584
- const remotes = assertSafeOvpn(fs58.readFileSync(profile, "utf8"), vpn.server);
34917
+ const profile = path73.join(launchDir, "vpn", "server.ovpn");
34918
+ const remotes = assertSafeOvpn(fs60.readFileSync(profile, "utf8"), vpn.server);
34585
34919
  const exe = await ensureOpenVpn();
34586
34920
  const servers = await serverAddresses(remotes);
34587
34921
  if (servers.length === 0) throw new Error("the VPN server addresses could not be found");
@@ -34834,7 +35168,7 @@ var OutputFilter = class {
34834
35168
  };
34835
35169
 
34836
35170
  // src/shared/pty/console-input.ts
34837
- import { spawn as spawn8 } from "node:child_process";
35171
+ import { spawn as spawn9 } from "node:child_process";
34838
35172
  function enableVtInput() {
34839
35173
  if (process.platform !== "win32" || !process.stdin.isTTY)
34840
35174
  return { ready: Promise.resolve(false), stop: () => Promise.resolve() };
@@ -34842,7 +35176,7 @@ function enableVtInput() {
34842
35176
  let exited = Promise.resolve();
34843
35177
  const ready = new Promise((resolve2) => {
34844
35178
  try {
34845
- child = spawn8(SYSTEM.powershell(), scriptArgs("enable-vt-input.ps1", ["-ProcessId", String(process.pid)]), {
35179
+ child = spawn9(SYSTEM.powershell(), scriptArgs("enable-vt-input.ps1", ["-ProcessId", String(process.pid)]), {
34846
35180
  stdio: "ignore",
34847
35181
  windowsHide: true
34848
35182
  });
@@ -35091,7 +35425,7 @@ async function viewSession(id) {
35091
35425
  }
35092
35426
 
35093
35427
  // src/guest/boot/boot-env.ts
35094
- import path72 from "node:path";
35428
+ import path74 from "node:path";
35095
35429
 
35096
35430
  // src/guest/boot/project-env.ts
35097
35431
  var EnvSchema = external_exports.object({
@@ -35110,7 +35444,7 @@ var BootEnvSchema = external_exports.object({
35110
35444
  });
35111
35445
 
35112
35446
  // src/guest/boot/boot-env.ts
35113
- var file2 = () => path72.join(localDir, "boot-env.json");
35447
+ var file2 = () => path74.join(localDir, "boot-env.json");
35114
35448
  function saveBootEnv(value) {
35115
35449
  try {
35116
35450
  writeJsonAtomic(file2(), value);
@@ -35139,7 +35473,7 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
35139
35473
  }
35140
35474
 
35141
35475
  // src/guest/runtime/secrets.ts
35142
- import fs59 from "node:fs";
35476
+ import fs61 from "node:fs";
35143
35477
 
35144
35478
  // src/shared/channel/secrets.ts
35145
35479
  var Environment = external_exports.record(external_exports.string().max(256), external_exports.string().max(65536));
@@ -35167,12 +35501,12 @@ function takeSecrets(id) {
35167
35501
  const file3 = run.secretFile(id);
35168
35502
  let text;
35169
35503
  try {
35170
- if (fs59.statSync(file3).size > MAX_BYTES) throw new Error("too big");
35171
- text = fs59.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
35504
+ if (fs61.statSync(file3).size > MAX_BYTES) throw new Error("too big");
35505
+ text = fs61.readFileSync(file3, "utf8").replace(/^\uFEFF/, "");
35172
35506
  } catch {
35173
35507
  return {};
35174
35508
  } finally {
35175
- fs59.rmSync(file3, { force: true });
35509
+ fs61.rmSync(file3, { force: true });
35176
35510
  }
35177
35511
  try {
35178
35512
  const parsed = SecretsFileSchema.safeParse(JSON.parse(text));
@@ -35210,7 +35544,7 @@ async function soft(what, work) {
35210
35544
  }
35211
35545
  }
35212
35546
  function startDaemon(env, secrets) {
35213
- spawn9(process.execPath, [path73.join(path73.dirname(process.argv[1]), "daemon.js")], {
35547
+ spawn10(process.execPath, [path75.join(path75.dirname(process.argv[1]), "daemon.js")], {
35214
35548
  detached: true,
35215
35549
  stdio: "ignore",
35216
35550
  windowsHide: true,
@@ -35223,20 +35557,20 @@ function startDaemon(env, secrets) {
35223
35557
  }).unref();
35224
35558
  }
35225
35559
  function writeDbCommand() {
35226
- const dir = mkdirp(path73.join(localDir, "bin"));
35227
- const db = path73.join(path73.dirname(process.argv[1]), "db.js");
35228
- fs60.writeFileSync(
35229
- path73.join(dir, "sbx-db.cmd"),
35560
+ const dir = mkdirp(path75.join(localDir, "bin"));
35561
+ const db = path75.join(path75.dirname(process.argv[1]), "db.js");
35562
+ fs62.writeFileSync(
35563
+ path75.join(dir, "sbx-db.cmd"),
35230
35564
  '@setlocal\r\n@set AGENT_LOG_PREFIX=db\r\n@"' + process.execPath + '" "' + db + '" %*\r\n'
35231
35565
  );
35232
35566
  writeAgentCommands(dir);
35233
35567
  return dir;
35234
35568
  }
35235
35569
  function writeAgentCommands(dir) {
35236
- const install = { node: process.execPath, script: path73.join(path73.dirname(process.argv[1]), "agent.js") };
35570
+ const install = { node: process.execPath, script: path75.join(path75.dirname(process.argv[1]), "agent.js") };
35237
35571
  for (const shim3 of agentShims(toolsDir, session.agents ?? {}))
35238
- fs60.writeFileSync(path73.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
35239
- fs60.writeFileSync(path73.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
35572
+ fs62.writeFileSync(path75.join(dir, shim3.command + ".cmd"), shimText(shim3, install));
35573
+ fs62.writeFileSync(path75.join(dir, "sbx-agent.cmd"), sbxAgentText(install));
35240
35574
  }
35241
35575
  async function waitForPrimary() {
35242
35576
  for (let i = 0; i < PRIMARY_POLLS; i++) {
@@ -35264,7 +35598,7 @@ var Boot = class {
35264
35598
  log(
35265
35599
  "Agent sandbox: " + session.project + " | workspace " + workspace + " | agent " + session.harnessName + " | log " + logPath
35266
35600
  );
35267
- if (!fs60.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
35601
+ if (!fs62.statSync(workspace, { throwIfNoEntry: false })?.isDirectory())
35268
35602
  throw new Error("Workspace folder is missing in the sandbox: " + workspace);
35269
35603
  mkdirp(toolsDir);
35270
35604
  mkdirp(run.root);
@@ -35276,7 +35610,7 @@ var Boot = class {
35276
35610
  const { tools, env } = await this.developerTools();
35277
35611
  await this.vpn();
35278
35612
  await this.gitIdentity(env);
35279
- await this.claude(tools);
35613
+ await this.claude(tools, env);
35280
35614
  await this.agent(env);
35281
35615
  this.preAgentHooks(env);
35282
35616
  await this.start(env);
@@ -35359,15 +35693,20 @@ var Boot = class {
35359
35693
  await soft("GitHub token", () => loginGithub(token, env));
35360
35694
  }
35361
35695
  }
35362
- async claude(tools) {
35696
+ async claude(tools, env) {
35363
35697
  step(6, "Claude settings, history and claude-mem");
35364
35698
  if (session.harnessName === "claude")
35365
35699
  await soft("Claude settings", () => syncClaudeProfile(this.secrets.claudeCredentials));
35366
35700
  await soft("claude-mem restore", restoreClaudeMem);
35367
35701
  await soft("Agent files of the last sandbox", resetMachineBound);
35368
35702
  await soft("Agent databases restore", restoreLocalState);
35703
+ let headroom = null;
35704
+ await soft("MCP servers from Apps", writeAddonMcpServers);
35705
+ await soft("Headroom proxy", async () => {
35706
+ headroom = await startHeadroom(env);
35707
+ });
35708
+ await soft("Claude managed settings", () => writeManagedSettings2(this.gitAccess, headroom));
35369
35709
  await soft("Sandbox guide for the agent", () => writeGuides(tools.summary, this.lan));
35370
- await soft("Claude managed settings", () => writeManagedSettings2(this.gitAccess));
35371
35710
  }
35372
35711
  async agent(env) {
35373
35712
  step(7, "Agent: " + session.harnessName);
@@ -35419,11 +35758,11 @@ runBoot().catch((e) => {
35419
35758
  const message = errMsg(e) + (e instanceof Error && e.stack ? "\n" + e.stack : "");
35420
35759
  try {
35421
35760
  setSandboxStatus("failed", errMsg(e));
35422
- fs61.writeFileSync(path74.join(logsDir, "guest-error.txt"), message);
35761
+ fs63.writeFileSync(path76.join(logsDir, "guest-error.txt"), message);
35423
35762
  } catch {
35424
35763
  }
35425
35764
  console.error(
35426
- "\n\x1B[31mThe sandbox could not start: " + errMsg(e) + "\x1B[0m\nDetails: " + path74.join(logsDir, "guest-error.txt")
35765
+ "\n\x1B[31mThe sandbox could not start: " + errMsg(e) + "\x1B[0m\nDetails: " + path76.join(logsDir, "guest-error.txt")
35427
35766
  );
35428
35767
  process.exitCode = 1;
35429
35768
  });