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.
- package/README.md +12 -6
- package/config.example.json +4 -3
- package/dist/app/features/apps/apps-rows.d.ts +4 -1
- package/dist/app/features/apps/apps-rows.js +7 -2
- package/dist/app/features/apps/apps.def.d.ts +19 -0
- package/dist/app/features/apps/apps.def.js +49 -12
- package/dist/app/features/apps/apps.run.d.ts +2 -0
- package/dist/app/features/apps/apps.run.js +1 -1
- package/dist/app/features/audit/audit.def.d.ts +341 -0
- package/dist/app/features/audit/audit.def.js +454 -0
- package/dist/app/features/audit/audit.run.d.ts +107 -0
- package/dist/app/features/audit/audit.run.js +133 -0
- package/dist/app/features/audit/index.d.ts +2 -0
- package/dist/app/features/audit/index.js +3 -0
- package/dist/app/features/defs.d.ts +194 -1
- package/dist/app/features/defs.js +4 -0
- package/dist/app/features/settings/settings.run.d.ts +3 -0
- package/dist/app/features/settings/settings.run.js +16 -2
- package/dist/app/kernel/define.d.ts +12 -1
- package/dist/app/registry.js +2 -0
- package/dist/cli/args.d.ts +0 -3
- package/dist/cli/args.js +3 -4
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/launch/prepare.js +1 -1
- package/dist/cli/commands/maintenance/index.d.ts +0 -1
- package/dist/cli/commands/maintenance/index.js +0 -1
- package/dist/cli/commands/registry.js +1 -2
- package/dist/cli/manifest.d.ts +0 -41
- package/dist/cli/manifest.js +0 -14
- package/dist/cli/menu/pages/apps-page.js +2 -15
- package/dist/cli/menu/pages/maintenance-page.d.ts +4 -0
- package/dist/cli/menu/pages/maintenance-page.js +51 -8
- package/dist/cli/menu/views.js +2 -0
- package/dist/core/config/defaults.js +1 -1
- package/dist/core/schema/apps.d.ts +9 -0
- package/dist/core/schema/apps.js +9 -0
- package/dist/core/schema/config.d.ts +1 -0
- package/dist/core/schema/config.js +3 -3
- package/dist/core/schema/sandbox.d.ts +1 -0
- package/dist/core/schema/sandbox.js +11 -3
- package/dist/guest/apps/app-installer.js +50 -4
- package/dist/guest/apps/index.d.ts +1 -1
- package/dist/guest/apps/index.js +1 -1
- package/dist/guest/apps/sources.js +1 -1
- package/dist/guest/audit/parse.d.ts +32 -2
- package/dist/guest/audit/parse.js +43 -5
- package/dist/guest/audit/process-audit.d.ts +3 -1
- package/dist/guest/audit/process-audit.js +9 -6
- package/dist/guest/boot/boot.js +12 -3
- package/dist/guest/boot/guide.d.ts +1 -1
- package/dist/guest/boot/guide.js +27 -3
- package/dist/guest/daemon/sessions.d.ts +7 -0
- package/dist/guest/daemon/sessions.js +27 -2
- package/dist/guest/entries/daemon.js +2 -1
- package/dist/guest/setup/addon-mcp.d.ts +2 -0
- package/dist/guest/setup/addon-mcp.js +49 -0
- package/dist/guest/setup/agent-addons.d.ts +9 -0
- package/dist/guest/setup/agent-addons.js +22 -0
- package/dist/guest/setup/headroom.d.ts +7 -0
- package/dist/guest/setup/headroom.js +60 -0
- package/dist/guest/setup/managed-policy.d.ts +2 -1
- package/dist/guest/setup/managed-policy.js +15 -6
- package/dist/guest/toolchains/plan.js +8 -3
- package/dist/host/audit/attribute.d.ts +46 -0
- package/dist/host/audit/attribute.js +76 -0
- package/dist/host/audit/collect.d.ts +29 -3
- package/dist/host/audit/collect.js +256 -61
- package/dist/host/audit/git-commits.d.ts +29 -0
- package/dist/host/audit/git-commits.js +157 -0
- package/dist/host/audit/index.d.ts +5 -0
- package/dist/host/audit/index.js +6 -0
- package/dist/host/audit/log.d.ts +44 -7
- package/dist/host/audit/log.js +148 -45
- package/dist/host/audit/redact.d.ts +2 -0
- package/dist/host/audit/redact.js +67 -0
- package/dist/runtime/agent.js +110 -15
- package/dist/runtime/daemon.js +569 -316
- package/dist/runtime/db.js +110 -15
- package/dist/runtime/main.js +1011 -672
- package/dist/runtime/netproxy.js +110 -15
- package/dist/runtime/view.js +110 -15
- package/dist/selftest/app.test.js +25 -1
- package/dist/selftest/audit.test.js +354 -47
- package/dist/selftest/hcs.test.js +35 -0
- package/dist/selftest/menu-screens.js +1 -1
- package/dist/selftest/menu.test.js +3 -3
- package/dist/selftest/support/engine-golden.js +9 -0
- package/dist/selftest/support/fixtures.d.ts +1 -0
- package/dist/selftest/support/web-preview.js +94 -0
- package/dist/selftest/toolchains.test.js +147 -2
- package/dist/shared/apps/agent-addons.d.ts +64 -0
- package/dist/shared/apps/agent-addons.js +95 -0
- package/dist/shared/apps/catalogue.d.ts +33 -2
- package/dist/shared/apps/catalogue.js +102 -11
- package/dist/shared/apps/index.d.ts +3 -2
- package/dist/shared/apps/index.js +3 -2
- package/dist/shared/apps/selection.d.ts +2 -0
- package/dist/shared/apps/selection.js +7 -0
- package/dist/sync/watcher.js +9 -1
- package/dist/web/index.html +2 -2
- package/dist/web/{main-RQFN4WBY.css → main-UAQPI5XD.css} +1 -1
- package/dist/web/{main-K2JMCAZI.js → main-UD4QCXZR.js} +66 -66
- package/native/csharp/HcsHost/AssemblyInfo.cs +5 -3
- package/native/csharp/HcsHost/Hcs.cs +9 -0
- package/native/csharp/HcsHost/Program.cs +26 -1
- package/native/csharp/HcsHost/Share.cs +173 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/package.json +1 -1
- package/sandbox/addons/ccusage/package-lock.json +111 -0
- package/sandbox/addons/ccusage/package.json +7 -0
- package/sandbox/addons/context7/package-lock.json +1313 -0
- package/sandbox/addons/context7/package.json +7 -0
- package/sandbox/addons/headroom/requirements.in +1 -0
- package/sandbox/addons/headroom/requirements.txt +2922 -0
- package/sandbox/addons/playwright-mcp/package-lock.json +56 -0
- package/sandbox/addons/playwright-mcp/package.json +7 -0
- package/schemas/config.schema.json +13 -4
- package/schemas/sandbox-config.schema.json +2 -2
- package/dist/cli/commands/maintenance/audit.d.ts +0 -3
- package/dist/cli/commands/maintenance/audit.js +0 -58
package/dist/runtime/main.js
CHANGED
|
@@ -1363,11 +1363,11 @@ var require_lodash = __commonJS({
|
|
|
1363
1363
|
return isFunction(object2[key]);
|
|
1364
1364
|
});
|
|
1365
1365
|
}
|
|
1366
|
-
function baseGet(object2,
|
|
1367
|
-
|
|
1368
|
-
var index = 0, 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(
|
|
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,
|
|
1435
|
-
|
|
1436
|
-
object2 = parent(object2,
|
|
1437
|
-
var func = object2 == null ? object2 : object2[toKey(last(
|
|
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(
|
|
1594
|
-
if (isKey(
|
|
1595
|
-
return matchesStrictComparable(toKey(
|
|
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,
|
|
1599
|
-
return objValue === undefined2 && objValue === srcValue ? hasIn(object2,
|
|
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,
|
|
1697
|
-
return hasIn(object2,
|
|
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
|
|
1704
|
-
if (predicate(value,
|
|
1705
|
-
baseSet(result2, castPath(
|
|
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(
|
|
1710
|
+
function basePropertyDeep(path77) {
|
|
1711
1711
|
return function(object2) {
|
|
1712
|
-
return baseGet(object2,
|
|
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,
|
|
1786
|
+
function baseSet(object2, path77, value, customizer) {
|
|
1787
1787
|
if (!isObject2(object2)) {
|
|
1788
1788
|
return object2;
|
|
1789
1789
|
}
|
|
1790
|
-
|
|
1791
|
-
var index = -1, length =
|
|
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(
|
|
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(
|
|
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,
|
|
1968
|
-
|
|
1969
|
-
var index = -1, 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(
|
|
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,
|
|
1983
|
-
return obj == null || delete obj[toKey(last(
|
|
1982
|
+
var obj = parent(object2, path77);
|
|
1983
|
+
return obj == null || delete obj[toKey(last(path77))];
|
|
1984
1984
|
}
|
|
1985
|
-
function baseUpdate(object2,
|
|
1986
|
-
return baseSet(object2,
|
|
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,
|
|
2870
|
-
|
|
2871
|
-
var index = -1, length =
|
|
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(
|
|
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,
|
|
3076
|
-
return
|
|
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,
|
|
3712
|
-
var index = -1, isFunc = typeof
|
|
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(
|
|
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,
|
|
4367
|
-
var result2 = object2 == null ? undefined2 : baseGet(object2,
|
|
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,
|
|
4371
|
-
return object2 != null && hasPath(object2,
|
|
4370
|
+
function has(object2, path77) {
|
|
4371
|
+
return object2 != null && hasPath(object2, path77, baseHas);
|
|
4372
4372
|
}
|
|
4373
|
-
function hasIn(object2,
|
|
4374
|
-
return object2 != null && hasPath(object2,
|
|
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(
|
|
4428
|
-
|
|
4429
|
-
isDeep || (isDeep =
|
|
4430
|
-
return
|
|
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,
|
|
4457
|
-
return predicate(value,
|
|
4456
|
+
return basePickBy(object2, props, function(value, path77) {
|
|
4457
|
+
return predicate(value, path77[0]);
|
|
4458
4458
|
});
|
|
4459
4459
|
}
|
|
4460
|
-
function result(object2,
|
|
4461
|
-
|
|
4462
|
-
var index = -1, 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(
|
|
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,
|
|
4478
|
-
return object2 == null ? object2 : baseSet(object2,
|
|
4477
|
+
function set2(object2, path77, value) {
|
|
4478
|
+
return object2 == null ? object2 : baseSet(object2, path77, value);
|
|
4479
4479
|
}
|
|
4480
|
-
function setWith(object2,
|
|
4480
|
+
function setWith(object2, path77, value, customizer) {
|
|
4481
4481
|
customizer = typeof customizer == "function" ? customizer : undefined2;
|
|
4482
|
-
return object2 == null ? object2 : baseSet(object2,
|
|
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,
|
|
4505
|
-
return object2 == null ? true : baseUnset(object2,
|
|
4504
|
+
function unset(object2, path77) {
|
|
4505
|
+
return object2 == null ? true : baseUnset(object2, path77);
|
|
4506
4506
|
}
|
|
4507
|
-
function update(object2,
|
|
4508
|
-
return object2 == null ? object2 : baseUpdate(object2,
|
|
4507
|
+
function update(object2, path77, updater) {
|
|
4508
|
+
return object2 == null ? object2 : baseUpdate(object2, path77, castFunction(updater));
|
|
4509
4509
|
}
|
|
4510
|
-
function updateWith(object2,
|
|
4510
|
+
function updateWith(object2, path77, updater, customizer) {
|
|
4511
4511
|
customizer = typeof customizer == "function" ? customizer : undefined2;
|
|
4512
|
-
return object2 == null ? object2 : baseUpdate(object2,
|
|
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(
|
|
4899
|
-
return baseMatchesProperty(
|
|
4898
|
+
function matchesProperty(path77, srcValue) {
|
|
4899
|
+
return baseMatchesProperty(path77, baseClone(srcValue, CLONE_DEEP_FLAG));
|
|
4900
4900
|
}
|
|
4901
|
-
var method = baseRest(function(
|
|
4901
|
+
var method = baseRest(function(path77, args) {
|
|
4902
4902
|
return function(object2) {
|
|
4903
|
-
return baseInvoke(object2,
|
|
4903
|
+
return baseInvoke(object2, path77, args);
|
|
4904
4904
|
};
|
|
4905
4905
|
});
|
|
4906
4906
|
var methodOf = baseRest(function(object2, args) {
|
|
4907
|
-
return function(
|
|
4908
|
-
return baseInvoke(object2,
|
|
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(
|
|
4956
|
-
return isKey(
|
|
4955
|
+
function property(path77) {
|
|
4956
|
+
return isKey(path77) ? baseProperty(toKey(path77)) : basePropertyDeep(path77);
|
|
4957
4957
|
}
|
|
4958
4958
|
function propertyOf(object2) {
|
|
4959
|
-
return function(
|
|
4960
|
-
return object2 == null ? undefined2 : baseGet(object2,
|
|
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(
|
|
5414
|
-
if (typeof
|
|
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,
|
|
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
|
|
5536
|
-
import
|
|
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,
|
|
6362
|
-
if (!
|
|
6361
|
+
function getElementAtPath(obj, path77) {
|
|
6362
|
+
if (!path77)
|
|
6363
6363
|
return obj;
|
|
6364
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 }, [...
|
|
7161
|
+
issue2.errors.map((issues) => processError({ issues }, [...path77, ...issue2.path]));
|
|
7162
7162
|
} else if (issue2.code === "invalid_key") {
|
|
7163
|
-
processError({ issues: issue2.issues }, [...
|
|
7163
|
+
processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
|
|
7164
7164
|
} else if (issue2.code === "invalid_element") {
|
|
7165
|
-
processError({ issues: issue2.issues }, [...
|
|
7165
|
+
processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
|
|
7166
7166
|
} else {
|
|
7167
|
-
const fullpath = [...
|
|
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,
|
|
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 }, [...
|
|
7210
|
+
issue2.errors.map((issues) => processError({ issues }, [...path77, ...issue2.path]));
|
|
7211
7211
|
} else if (issue2.code === "invalid_key") {
|
|
7212
|
-
processError({ issues: issue2.issues }, [...
|
|
7212
|
+
processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
|
|
7213
7213
|
} else if (issue2.code === "invalid_element") {
|
|
7214
|
-
processError({ issues: issue2.issues }, [...
|
|
7214
|
+
processError({ issues: issue2.issues }, [...path77, ...issue2.path]);
|
|
7215
7215
|
} else {
|
|
7216
|
-
const fullpath = [...
|
|
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
|
|
7256
|
-
for (const seg of
|
|
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
|
|
24359
|
-
if (
|
|
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 (
|
|
24364
|
-
const key =
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
27535
|
-
import
|
|
27536
|
-
import { spawn as
|
|
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
|
|
27782
|
-
import
|
|
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(
|
|
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 =
|
|
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(
|
|
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) =>
|
|
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
|
|
28112
|
+
import path20 from "node:path";
|
|
27816
28113
|
function shortcuts(apps) {
|
|
27817
28114
|
if (!apps.length) return;
|
|
27818
|
-
const desktop =
|
|
27819
|
-
const start =
|
|
27820
|
-
process.env.APPDATA ??
|
|
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:
|
|
28127
|
+
link: path20.join(folder, name + ".lnk"),
|
|
27831
28128
|
target: app.exe,
|
|
27832
|
-
workingDirectory:
|
|
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
|
|
27965
|
-
import
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
28352
|
+
const out = path22.join(work, "out");
|
|
28056
28353
|
try {
|
|
28057
|
-
if ("
|
|
28058
|
-
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
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
|
|
28096
|
-
import
|
|
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
|
|
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(
|
|
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 =
|
|
28599
|
+
const file3 = path23.join(projectWorkspace(), name);
|
|
28257
28600
|
if (!exists(file3)) continue;
|
|
28258
|
-
const spec = parse5(
|
|
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
|
|
28322
|
-
import
|
|
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
|
|
28327
|
-
import
|
|
28669
|
+
import fs21 from "node:fs";
|
|
28670
|
+
import path24 from "node:path";
|
|
28328
28671
|
|
|
28329
28672
|
// src/guest/toolchains/version-cache.ts
|
|
28330
|
-
import
|
|
28673
|
+
import fs20 from "node:fs";
|
|
28331
28674
|
|
|
28332
28675
|
// src/guest/toolchains/state-file.ts
|
|
28333
|
-
import
|
|
28676
|
+
import fs19 from "node:fs";
|
|
28334
28677
|
function readState(file3, schema, empty) {
|
|
28335
28678
|
try {
|
|
28336
|
-
return schema.safeParse(JSON.parse(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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) ?
|
|
28440
|
-
if (installed.length) return
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
28517
|
-
import
|
|
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
|
|
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 =
|
|
28525
|
-
const out =
|
|
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
|
-
|
|
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)
|
|
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(
|
|
28879
|
+
if (exists(path25.join(data, marker))) return;
|
|
28537
28880
|
const existed = exists(data);
|
|
28538
|
-
mkdirp(
|
|
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 =
|
|
28905
|
+
const java = path26.join(await ensureJdk(), "bin", "java.exe");
|
|
28563
28906
|
const home = tool("dynamodb-local");
|
|
28564
|
-
if (!exists(
|
|
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=" +
|
|
28921
|
+
"-Djava.library.path=" + path26.join(home, "DynamoDBLocal_lib"),
|
|
28579
28922
|
"-jar",
|
|
28580
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
28969
|
+
fs23.closeSync(out);
|
|
28627
28970
|
if (!await waitForPort(plan2.adminPort, 30))
|
|
28628
|
-
throw new Error("dynamodb-admin did not start; see " +
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
28722
|
-
if (!exists(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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 =
|
|
28771
|
-
if (!exists(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
28824
|
-
if (exists(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
28957
|
-
if (duringSession() && (exists(
|
|
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"),
|
|
28961
|
-
fs26.rmSync(
|
|
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(
|
|
29282
|
+
fs26.writeFileSync(path32.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
|
|
28965
29283
|
}
|
|
28966
29284
|
fs26.writeFileSync(
|
|
28967
|
-
|
|
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(
|
|
29294
|
+
BASH_ENV: posix(path32.join(dir, "bashenv.sh"))
|
|
28977
29295
|
});
|
|
28978
29296
|
if (access === "readonly") {
|
|
28979
|
-
const hooks = mkdirp(
|
|
29297
|
+
const hooks = mkdirp(path32.join(dir, "hooks"));
|
|
28980
29298
|
for (const hook of BLOCKED_HOOKS)
|
|
28981
29299
|
fs26.writeFileSync(
|
|
28982
|
-
|
|
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 =
|
|
29309
|
+
env.vars.GIT_DIR = path32.join(dataDir, "git-disabled");
|
|
28992
29310
|
}
|
|
28993
29311
|
};
|
|
28994
29312
|
var pointAtOwnCertificates = (root) => {
|
|
28995
|
-
const config2 =
|
|
28996
|
-
const bundle =
|
|
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 =
|
|
29005
|
-
const gitExe =
|
|
29006
|
-
const hostGit =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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:
|
|
29120
|
-
GOMODCACHE:
|
|
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(
|
|
29128
|
-
const go =
|
|
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,
|
|
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
|
|
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
|
|
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 (
|
|
31654
|
-
lastSegment =
|
|
31655
|
-
parent = findNodeAtLocation(root,
|
|
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,
|
|
31842
|
-
return setProperty(text,
|
|
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
|
-
|
|
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
|
|
33502
|
-
|
|
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(
|
|
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/
|
|
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 =
|
|
33849
|
+
const dir = path66.join(launchDir, "personalize");
|
|
33516
33850
|
if (!session.personalization || !exists(dir) || dryRun || !isWin) return;
|
|
33517
|
-
exec(SYSTEM.reg(), ["import",
|
|
33518
|
-
const wallpaper =
|
|
33519
|
-
const local = wallpaper ?
|
|
33520
|
-
if (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
|
|
33860
|
+
import fs54 from "node:fs";
|
|
33527
33861
|
import os11 from "node:os";
|
|
33528
|
-
import
|
|
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 =
|
|
33533
|
-
if (exists(source))
|
|
33534
|
-
const git =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
33644
|
-
import
|
|
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
|
|
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(
|
|
33988
|
+
for (const legacy of ["ptyhost", "gitshim"]) safeRemove(path68.join(toolsDir, legacy), toolsDir);
|
|
33655
33989
|
for (const top of entries2(toolsDir)) {
|
|
33656
|
-
const dir =
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
34029
|
+
import fs60 from "node:fs";
|
|
33696
34030
|
import net3 from "node:net";
|
|
33697
34031
|
import os14 from "node:os";
|
|
33698
|
-
import
|
|
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
|
|
34222
|
-
import
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
34288
|
-
import
|
|
34621
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
34622
|
+
import fs58 from "node:fs";
|
|
34289
34623
|
import os12 from "node:os";
|
|
34290
|
-
import
|
|
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 =
|
|
34307
|
-
const auth =
|
|
34308
|
-
const logFile2 =
|
|
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
|
-
|
|
34312
|
-
|
|
34645
|
+
fs58.mkdirSync(logsDir, { recursive: true });
|
|
34646
|
+
fs58.copyFileSync(logFile2, path71.join(logsDir, "openvpn.log"));
|
|
34313
34647
|
} catch {
|
|
34314
34648
|
}
|
|
34315
34649
|
};
|
|
34316
|
-
|
|
34650
|
+
fs58.writeFileSync(auth, o.username + "\r\n" + o.password + "\r\n", "utf8");
|
|
34317
34651
|
try {
|
|
34318
|
-
const child =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
34695
|
+
import fs59 from "node:fs";
|
|
34362
34696
|
import os13 from "node:os";
|
|
34363
|
-
import
|
|
34697
|
+
import path72 from "node:path";
|
|
34364
34698
|
var WIREGUARD_TUNNEL = "sandbox";
|
|
34365
34699
|
function wireguardDir(env = process.env) {
|
|
34366
|
-
return
|
|
34700
|
+
return path72.join(env.ProgramFiles ?? "C:\\Program Files", "WireGuard");
|
|
34367
34701
|
}
|
|
34368
34702
|
function wireguardExe(env = process.env) {
|
|
34369
|
-
return
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
34421
|
-
const dir =
|
|
34422
|
-
const file3 =
|
|
34423
|
-
|
|
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
|
-
|
|
34778
|
+
fs59.rmSync(dir, { recursive: true, force: true });
|
|
34445
34779
|
}
|
|
34446
34780
|
}
|
|
34447
34781
|
async function waitForHandshake(exe, poke, timeoutMs = 3e4) {
|
|
34448
|
-
const wg =
|
|
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 =
|
|
34584
|
-
const remotes = assertSafeOvpn(
|
|
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
|
|
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 =
|
|
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
|
|
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 = () =>
|
|
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
|
|
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 (
|
|
35171
|
-
text =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
35227
|
-
const db =
|
|
35228
|
-
|
|
35229
|
-
|
|
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:
|
|
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
|
-
|
|
35239
|
-
|
|
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 (!
|
|
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
|
-
|
|
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: " +
|
|
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
|
});
|