windows-development-sandbox 1.27.0 → 1.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/features/unreal/unreal.run.js +13 -3
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-ZXCAVVS4.js → chunk-4TLSWPG7.js} +1 -1
- package/dist/bin/{chunk-JXL6ZOO3.js → chunk-QUHNXHVG.js} +1 -1
- package/dist/bin/{chunk-6WWMBCT2.js → chunk-RSIX7C6D.js} +60 -17
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/commands/launch/launch.js +2 -1
- package/dist/guest/setup/unity-agent.js +4 -1
- package/dist/guest/toolchains/engines/epic-launcher.d.ts +1 -1
- package/dist/guest/toolchains/engines/epic-launcher.js +11 -7
- package/dist/guest/toolchains/engines/unreal-status.js +1 -1
- package/dist/guest/toolchains/native/mesa.js +35 -11
- package/dist/guest/toolchains/native/unreal.js +1 -0
- package/dist/host/accounts/deliver.d.ts +3 -0
- package/dist/host/accounts/deliver.js +19 -0
- package/dist/host/accounts/source.d.ts +2 -0
- package/dist/host/accounts/source.js +2 -0
- package/dist/host/pc-installs/discover.js +3 -2
- package/dist/host/pc-installs/epic.js +3 -0
- package/dist/host/pc-installs/unity.d.ts +2 -0
- package/dist/host/pc-installs/unity.js +12 -3
- package/dist/host/pc-installs/unreal.d.ts +2 -0
- package/dist/host/pc-installs/unreal.js +24 -8
- package/dist/runtime/daemon.js +38 -14
- package/dist/runtime/main.js +38 -14
- package/dist/selftest/engines.test.js +30 -1
- package/dist/selftest/mixamo.test.js +1 -1
- package/dist/selftest/service-accounts.test.js +12 -1
- package/dist/shared/unreal/status.d.ts +1 -0
- package/dist/shared/unreal/status.js +2 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/package.json +1 -1
|
@@ -19,7 +19,11 @@ import { ConfigFile } from '../settings/index.js';
|
|
|
19
19
|
import { forgetEngineFolder, openEpicLauncher, registerEngineFolder, unrealOverview, } from './unreal.def.js';
|
|
20
20
|
const win = path.win32;
|
|
21
21
|
/** The launcher the sandbox installs (the 64-bit one of launcher 17 and later). */
|
|
22
|
-
|
|
22
|
+
/** Where the launcher installs in the sandbox: Program Files for newer launchers, (x86) for older ones. */
|
|
23
|
+
const GUEST_LAUNCHERS = [
|
|
24
|
+
'C:\\Program Files\\Epic Games\\Launcher\\Portal\\Binaries\\Win64\\EpicGamesLauncher.exe',
|
|
25
|
+
'C:\\Program Files (x86)\\Epic Games\\Launcher\\Portal\\Binaries\\Win64\\EpicGamesLauncher.exe',
|
|
26
|
+
];
|
|
23
27
|
const MAX_PACKS_SHOWN = 40;
|
|
24
28
|
const s = (text) => safeText(text);
|
|
25
29
|
const sn = (text) => (text === null ? null : safeText(text));
|
|
@@ -204,10 +208,16 @@ export const openEpicLauncherRun = implement(openEpicLauncher, async (ctx, _inpu
|
|
|
204
208
|
const status = new RunDir(ctx.dataPath).readSandboxStatus();
|
|
205
209
|
if (status?.phase !== 'ready')
|
|
206
210
|
fail('The sandbox is not ready yet.', 'Try again in a moment.');
|
|
207
|
-
|
|
211
|
+
const launcher = readStatus(ctx.dataPath)?.launcher;
|
|
212
|
+
if (!launcher?.installed)
|
|
208
213
|
fail('The Epic Games Launcher is not installed in this sandbox.', 'It is installed when the sandbox is set up for Unreal with the licence accepted (Unreal set-up settings).');
|
|
209
214
|
io.progress('Opening the Epic Games Launcher in the sandbox…');
|
|
210
|
-
const result = await new SandboxChannel(ctx.dataPath).exec(
|
|
215
|
+
const result = await new SandboxChannel(ctx.dataPath).exec(
|
|
216
|
+
// The guest's status only picks one of the known paths.
|
|
217
|
+
[
|
|
218
|
+
'C:\\Windows\\explorer.exe',
|
|
219
|
+
GUEST_LAUNCHERS.find((p) => p.toLowerCase() === launcher.exe?.toLowerCase()) ?? GUEST_LAUNCHERS[0],
|
|
220
|
+
], status.guestWorkspace ?? 'C:\\', 30);
|
|
211
221
|
// explorer.exe returns 1 even when it started the program.
|
|
212
222
|
if (!result.ok && result.exitCode !== 1)
|
|
213
223
|
fail('The sandbox could not open it: ' + safeText(result.message));
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/agent-sandbox.ts
|
|
9
9
|
run(process.argv.slice(2));
|
|
@@ -62605,7 +62605,8 @@ function pcEnv() {
|
|
|
62605
62605
|
programData: env.ProgramData ?? env.PROGRAMDATA ?? "C:\\ProgramData",
|
|
62606
62606
|
programFiles: env.ProgramFiles ?? "C:\\Program Files",
|
|
62607
62607
|
env,
|
|
62608
|
-
userVariable: savedUserVariable
|
|
62608
|
+
userVariable: savedUserVariable,
|
|
62609
|
+
drives: () => diskUsage(env.ProgramData ?? "C:\\").map((d) => d.drive)
|
|
62609
62610
|
};
|
|
62610
62611
|
}
|
|
62611
62612
|
function notAvailableYet(kind) {
|
|
@@ -62926,6 +62927,18 @@ function howToSave(spec) {
|
|
|
62926
62927
|
if (spec.returns) return "sign in once in this sandbox, or: sandbox account import " + spec.kind;
|
|
62927
62928
|
return spec.sources.includes("typed") ? "save one: sandbox account login " + spec.kind : "save one: sandbox account import " + spec.kind + " --from <file>";
|
|
62928
62929
|
}
|
|
62930
|
+
function takeFromPc(kind, pc, store) {
|
|
62931
|
+
const source = HOST_SOURCES[kind];
|
|
62932
|
+
if (!pc || !source.fromPc) return null;
|
|
62933
|
+
let payload = null;
|
|
62934
|
+
try {
|
|
62935
|
+
payload = source.fromPc(pc);
|
|
62936
|
+
} catch {
|
|
62937
|
+
return null;
|
|
62938
|
+
}
|
|
62939
|
+
if (payload) store.save(kind, payload, "pc", source.summary(payload));
|
|
62940
|
+
return payload;
|
|
62941
|
+
}
|
|
62929
62942
|
function prepareServiceAccounts(i) {
|
|
62930
62943
|
const store = i.store ?? new ServiceAccountStore(i.storageRoot);
|
|
62931
62944
|
const leases = i.leases ?? new AccountLeases(i.storageRoot);
|
|
@@ -62955,6 +62968,7 @@ function prepareServiceAccounts(i) {
|
|
|
62955
62968
|
} catch {
|
|
62956
62969
|
unreadable = true;
|
|
62957
62970
|
}
|
|
62971
|
+
if (!payload && !unreadable) payload = takeFromPc(kind, i.pc, store);
|
|
62958
62972
|
if (spec.singleHolder) {
|
|
62959
62973
|
const claim2 = leases.claim(kind, dataSet, i.launchId, payload ? fingerprint(payload) : null, i.isRunning);
|
|
62960
62974
|
if (!claim2.ok) {
|
|
@@ -63275,6 +63289,8 @@ var UnrealStatusSchema = external_exports.object({
|
|
|
63275
63289
|
).max(64),
|
|
63276
63290
|
launcher: external_exports.object({
|
|
63277
63291
|
installed: external_exports.boolean(),
|
|
63292
|
+
/** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
|
|
63293
|
+
exe: Text3().nullable().default(null),
|
|
63278
63294
|
/** Where the launcher installs engines; null when it could not be set. */
|
|
63279
63295
|
installLocation: Text3().nullable(),
|
|
63280
63296
|
/** Why engines would not go to the data disk (shown loudly), null when they do. */
|
|
@@ -63394,6 +63410,7 @@ function findEpicGames(text, wanted) {
|
|
|
63394
63410
|
const found = [];
|
|
63395
63411
|
for (const i of text ? launcherInstallations(text) : []) {
|
|
63396
63412
|
if (!APP.test(i.appName) || /^\.+$/.test(i.appName) || /^UE_\d/.test(i.appName)) continue;
|
|
63413
|
+
if (i.ids?.namespaceId.toLowerCase() === "ue" || /^UE_\d/i.test(path117.win32.basename(i.installLocation))) continue;
|
|
63397
63414
|
if (names && !names.has(i.appName.toLowerCase())) continue;
|
|
63398
63415
|
if (found.some((f) => f.id.toLowerCase() === i.appName.toLowerCase())) continue;
|
|
63399
63416
|
found.push({
|
|
@@ -63804,10 +63821,12 @@ function listedEditors(files) {
|
|
|
63804
63821
|
}
|
|
63805
63822
|
function findUnityEditorsOnPc(files, wanted) {
|
|
63806
63823
|
const candidates = [];
|
|
63807
|
-
const hubFolders = [
|
|
63808
|
-
(
|
|
63809
|
-
|
|
63810
|
-
|
|
63824
|
+
const hubFolders = [
|
|
63825
|
+
win8.join(files.programFiles, "Unity", "Hub", "Editor"),
|
|
63826
|
+
secondaryRoot(files),
|
|
63827
|
+
...files.otherHubFolders ?? []
|
|
63828
|
+
].filter((d) => d !== null);
|
|
63829
|
+
for (const folder of new Set(hubFolders.map((d) => win8.resolve(d))))
|
|
63811
63830
|
for (const name2 of files.list(folder).slice(0, MAX_LISTED).sort())
|
|
63812
63831
|
if (UNITY_VERSION.test(name2)) candidates.push({ version: name2, root: win8.join(folder, name2) });
|
|
63813
63832
|
candidates.push(...listedEditors(files));
|
|
@@ -63853,7 +63872,11 @@ function unityPcFiles(pc) {
|
|
|
63853
63872
|
isDir,
|
|
63854
63873
|
list: listDir,
|
|
63855
63874
|
appData: pc.appData,
|
|
63856
|
-
programFiles: pc.programFiles ?? "C:\\Program Files"
|
|
63875
|
+
programFiles: pc.programFiles ?? "C:\\Program Files",
|
|
63876
|
+
otherHubFolders: (pc.drives?.() ?? []).flatMap((d) => [
|
|
63877
|
+
win8.join(d, "Program Files", "Unity", "Hub", "Editor"),
|
|
63878
|
+
win8.join(d, "Unity", "Hub", "Editor")
|
|
63879
|
+
])
|
|
63857
63880
|
};
|
|
63858
63881
|
}
|
|
63859
63882
|
function assetCacheEnv(pc) {
|
|
@@ -63924,10 +63947,17 @@ function findUnrealInstalls(files, wanted) {
|
|
|
63924
63947
|
...ids ? { launcher: ids } : {}
|
|
63925
63948
|
});
|
|
63926
63949
|
};
|
|
63927
|
-
|
|
63928
|
-
|
|
63929
|
-
|
|
63930
|
-
|
|
63950
|
+
const listed = files.launcherInstalled ? launcherInstallations(files.launcherInstalled) : [];
|
|
63951
|
+
for (const i of listed) if (APP_NAME.test(i.appName)) installed3(i.installLocation, i.ids ?? void 0);
|
|
63952
|
+
const roots = [files.defaultRoot, ...files.otherRoots ?? [], ...listed.map((i) => win9.dirname(i.installLocation))];
|
|
63953
|
+
const seen = /* @__PURE__ */ new Set();
|
|
63954
|
+
for (const root of roots) {
|
|
63955
|
+
const key3 = win9.resolve(root).toLowerCase();
|
|
63956
|
+
if (seen.has(key3) || seen.size >= 32) continue;
|
|
63957
|
+
seen.add(key3);
|
|
63958
|
+
for (const name2 of files.list(root).filter((n) => APP_NAME.test(n)).sort())
|
|
63959
|
+
installed3(win9.join(root, name2));
|
|
63960
|
+
}
|
|
63931
63961
|
return found;
|
|
63932
63962
|
}
|
|
63933
63963
|
function pcSourceBuilds(files) {
|
|
@@ -63983,6 +64013,10 @@ function unrealPcFiles(pc) {
|
|
|
63983
64013
|
launcherInstalled: dat ? dat.toString("utf8") : null,
|
|
63984
64014
|
builds: query.status === 0 ? String(query.stdout ?? "") : "",
|
|
63985
64015
|
defaultRoot: win9.join(pc.programFiles ?? "C:\\Program Files", "Epic Games"),
|
|
64016
|
+
otherRoots: (pc.drives?.() ?? []).flatMap((d) => [
|
|
64017
|
+
win9.join(d, "Program Files", "Epic Games"),
|
|
64018
|
+
win9.join(d, "Epic Games")
|
|
64019
|
+
]),
|
|
63986
64020
|
list: listDir2,
|
|
63987
64021
|
read: readBoundedFile
|
|
63988
64022
|
};
|
|
@@ -64066,11 +64100,11 @@ var unrealVault = {
|
|
|
64066
64100
|
// src/host/pc-installs/discover.ts
|
|
64067
64101
|
var MAX_PC_INSTALLS = 40;
|
|
64068
64102
|
var PC_INSTALL_SOURCES = [
|
|
64069
|
-
steamInstalls,
|
|
64070
|
-
epicInstalls,
|
|
64071
64103
|
unrealFolders,
|
|
64072
64104
|
unrealInstalls,
|
|
64073
64105
|
unrealVault,
|
|
64106
|
+
steamInstalls,
|
|
64107
|
+
epicInstalls,
|
|
64074
64108
|
unityInstalls,
|
|
64075
64109
|
unityAssets
|
|
64076
64110
|
];
|
|
@@ -83686,7 +83720,10 @@ var unrealView = defineView({
|
|
|
83686
83720
|
// src/app/features/unreal/unreal.run.ts
|
|
83687
83721
|
import path192 from "node:path";
|
|
83688
83722
|
var win10 = path192.win32;
|
|
83689
|
-
var
|
|
83723
|
+
var GUEST_LAUNCHERS = [
|
|
83724
|
+
"C:\\Program Files\\Epic Games\\Launcher\\Portal\\Binaries\\Win64\\EpicGamesLauncher.exe",
|
|
83725
|
+
"C:\\Program Files (x86)\\Epic Games\\Launcher\\Portal\\Binaries\\Win64\\EpicGamesLauncher.exe"
|
|
83726
|
+
];
|
|
83690
83727
|
var MAX_PACKS_SHOWN = 40;
|
|
83691
83728
|
var s = (text) => safeText(text);
|
|
83692
83729
|
var sn = (text) => text === null ? null : safeText(text);
|
|
@@ -83848,14 +83885,19 @@ var openEpicLauncherRun = implement(openEpicLauncher, async (ctx, _input, io) =>
|
|
|
83848
83885
|
fail("No sandbox is running.", "Start one for a project with a .uproject; the launcher opens in its window.");
|
|
83849
83886
|
const status = new RunDir(ctx.dataPath).readSandboxStatus();
|
|
83850
83887
|
if (status?.phase !== "ready") fail("The sandbox is not ready yet.", "Try again in a moment.");
|
|
83851
|
-
|
|
83888
|
+
const launcher = readStatus(ctx.dataPath)?.launcher;
|
|
83889
|
+
if (!launcher?.installed)
|
|
83852
83890
|
fail(
|
|
83853
83891
|
"The Epic Games Launcher is not installed in this sandbox.",
|
|
83854
83892
|
"It is installed when the sandbox is set up for Unreal with the licence accepted (Unreal set-up settings)."
|
|
83855
83893
|
);
|
|
83856
83894
|
io.progress("Opening the Epic Games Launcher in the sandbox\u2026");
|
|
83857
83895
|
const result = await new SandboxChannel(ctx.dataPath).exec(
|
|
83858
|
-
|
|
83896
|
+
// The guest's status only picks one of the known paths.
|
|
83897
|
+
[
|
|
83898
|
+
"C:\\Windows\\explorer.exe",
|
|
83899
|
+
GUEST_LAUNCHERS.find((p) => p.toLowerCase() === launcher.exe?.toLowerCase()) ?? GUEST_LAUNCHERS[0]
|
|
83900
|
+
],
|
|
83859
83901
|
status.guestWorkspace ?? "C:\\",
|
|
83860
83902
|
30
|
|
83861
83903
|
);
|
|
@@ -85146,7 +85188,7 @@ async function attachOpened(ctx, session) {
|
|
|
85146
85188
|
nextStep("sandbox attach " + session);
|
|
85147
85189
|
return 0;
|
|
85148
85190
|
}
|
|
85149
|
-
const { attach: attach2 } = await import("./chunk-
|
|
85191
|
+
const { attach: attach2 } = await import("./chunk-4TLSWPG7.js");
|
|
85150
85192
|
return attach2({ ...ctx, options: { ...ctx.options, positionals: [session] } });
|
|
85151
85193
|
}
|
|
85152
85194
|
function definitionHandler(def) {
|
|
@@ -85694,7 +85736,8 @@ var Launcher = class {
|
|
|
85694
85736
|
dataPath: run3.dataPath,
|
|
85695
85737
|
launchId,
|
|
85696
85738
|
// A new launch needs no sandbox running, so a lease held elsewhere is from one that stopped.
|
|
85697
|
-
isRunning: () => isSandboxRunning()
|
|
85739
|
+
isRunning: () => isSandboxRunning(),
|
|
85740
|
+
pc: pcEnv()
|
|
85698
85741
|
});
|
|
85699
85742
|
const store = generateOnly ? null : await prepareStorePackages(storeApps(config3.apps.install), {
|
|
85700
85743
|
storageRoot: ctx.storageRoot,
|
package/dist/bin/claude-host.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/claude-host.ts
|
|
9
9
|
var args = process.argv.slice(2);
|
package/dist/bin/claude-sbx.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/claude-sbx.ts
|
|
9
9
|
run(process.argv.slice(2), { harness: "claude" });
|
package/dist/bin/codex-sbx.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/codex-sbx.ts
|
|
9
9
|
run(process.argv.slice(2), { harness: "codex" });
|
package/dist/bin/gemini-sbx.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/gemini-sbx.ts
|
|
9
9
|
run(process.argv.slice(2), { harness: "gemini" });
|
package/dist/bin/sandbox.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/sandbox.ts
|
|
9
9
|
run(process.argv.slice(2));
|
package/dist/bin/sbx-hide.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/sbx-hide.ts
|
|
9
9
|
run(process.argv.slice(2), { command: "hide" });
|
package/dist/bin/sbx-show.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
run
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QUHNXHVG.js";
|
|
6
|
+
import "./chunk-RSIX7C6D.js";
|
|
7
7
|
|
|
8
8
|
// src/bin/sbx-show.ts
|
|
9
9
|
run(process.argv.slice(2), { command: "show" });
|
|
@@ -10,7 +10,7 @@ import { findSecretFiles } from '../../../host/profile/index.js';
|
|
|
10
10
|
import { RepoGuardStore } from '../../../host/guard/index.js';
|
|
11
11
|
import { hostPublicIp, prepareVpn, readVpnLine, vpnNotes } from '../../../host/vpn/index.js';
|
|
12
12
|
import { prepareGithubToken } from '../../../host/github/index.js';
|
|
13
|
-
import { prepareServiceAccounts } from '../../../host/accounts/index.js';
|
|
13
|
+
import { pcEnv, prepareServiceAccounts } from '../../../host/accounts/index.js';
|
|
14
14
|
import { prepareStorePackages } from '../../../host/apps/index.js';
|
|
15
15
|
import { storeApps } from '../../../shared/apps/index.js';
|
|
16
16
|
import { discoverPcInstalls } from '../../../host/pc-installs/index.js';
|
|
@@ -194,6 +194,7 @@ class Launcher {
|
|
|
194
194
|
launchId,
|
|
195
195
|
// A new launch needs no sandbox running, so a lease held elsewhere is from one that stopped.
|
|
196
196
|
isRunning: () => isSandboxRunning(),
|
|
197
|
+
pc: pcEnv(),
|
|
197
198
|
});
|
|
198
199
|
// Store apps (apps.install): their packages are fetched with this PC's own Store tooling.
|
|
199
200
|
const store = generateOnly
|
|
@@ -10,7 +10,10 @@ import { setEngineMcp, writeAddonMcpServers } from './addon-mcp.js';
|
|
|
10
10
|
async function syncSkills(unityExe, agent) {
|
|
11
11
|
const home = agent === 'claude' ? { CLAUDE_CONFIG_DIR: claudeDir } : { CODEX_HOME: path.join(stateDir, 'codex') };
|
|
12
12
|
try {
|
|
13
|
-
|
|
13
|
+
// The Unity CLI's client names: claude-code, codex.
|
|
14
|
+
await execAsync(unityExe, ['skill', 'sync', agent === 'claude' ? 'claude-code' : 'codex'], {
|
|
15
|
+
env: { ...process.env, ...UNITY_CLI_ENV, ...home },
|
|
16
|
+
});
|
|
14
17
|
return true;
|
|
15
18
|
}
|
|
16
19
|
catch (e) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type LauncherEntry } from '../../../shared/unreal/index.js';
|
|
2
|
-
/** The launcher's program
|
|
2
|
+
/** The launcher's program: newer MSIs install into Program Files, older ones into Program Files (x86). */
|
|
3
3
|
export declare function launcherExe(): string | null;
|
|
4
4
|
/** Downloads the launcher's MSI ahead of the install (once). */
|
|
5
5
|
export declare function fetchLauncher(): Promise<void>;
|
|
@@ -22,14 +22,18 @@ const SAVED_MANIFESTS = path.join(SAVED_DIR, 'Manifests');
|
|
|
22
22
|
const SAVED_ENTRIES = path.join(SAVED_DIR, 'LauncherInstalled.json');
|
|
23
23
|
const programData = () => process.env.ProgramData ?? 'C:\\ProgramData';
|
|
24
24
|
const localAppData = () => process.env.LOCALAPPDATA ?? '';
|
|
25
|
-
/** The launcher's program
|
|
25
|
+
/** The launcher's program: newer MSIs install into Program Files, older ones into Program Files (x86). */
|
|
26
26
|
export function launcherExe() {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const roots = [
|
|
28
|
+
process.env.ProgramFiles ?? 'C:\\Program Files',
|
|
29
|
+
process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)',
|
|
30
|
+
];
|
|
31
|
+
for (const root of roots)
|
|
32
|
+
for (const arch of ['Win64', 'Win32']) {
|
|
33
|
+
const exe = path.join(root, 'Epic Games', 'Launcher', 'Portal', 'Binaries', arch, 'EpicGamesLauncher.exe');
|
|
34
|
+
if (exists(exe))
|
|
35
|
+
return exe;
|
|
36
|
+
}
|
|
33
37
|
return null;
|
|
34
38
|
}
|
|
35
39
|
/** Downloads the launcher's MSI ahead of the install (once). */
|
|
@@ -18,7 +18,7 @@ const EMPTY = {
|
|
|
18
18
|
updatedAt: '',
|
|
19
19
|
engines: [],
|
|
20
20
|
projects: [],
|
|
21
|
-
launcher: { installed: false, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
|
|
21
|
+
launcher: { installed: false, exe: null, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
|
|
22
22
|
visualStudio: { version: '', path: '', how: '', check: '', ok: false },
|
|
23
23
|
debugger: null,
|
|
24
24
|
ddc: { mode: 'local', dir: null },
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Mesa for running OpenGL and Vulkan programs without a GPU (llvmpipe, lavapipe).
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { downloader } from '../../../shared/download/index.js';
|
|
3
|
+
import { downloader, fetchJson } from '../../../shared/download/index.js';
|
|
4
4
|
import { SYSTEM } from '../../../shared/system.js';
|
|
5
5
|
import { dryRun } from '../../runtime/paths.js';
|
|
6
6
|
import { execAsync, scriptOutput } from '../../runtime/process.js';
|
|
7
7
|
import { exists } from '../../runtime/fs.js';
|
|
8
|
-
import { log
|
|
8
|
+
import { log } from '../../runtime/log.js';
|
|
9
9
|
import { errMsg } from '../../../core/util/errors.js';
|
|
10
10
|
import { arch, tool } from '../tool-env.js';
|
|
11
11
|
import { installFromGithub } from '../install.js';
|
|
@@ -33,9 +33,28 @@ export async function setupMesa(env, config) {
|
|
|
33
33
|
if (config.vulkan)
|
|
34
34
|
await setupLavapipe(env, dir);
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
36
|
+
/** LunarG's newest SDK version per platform ({"windows": "1.4.363.1", ...}). */
|
|
37
|
+
const VULKAN_LATEST = 'https://vulkan.lunarg.com/sdk/latest.json';
|
|
38
|
+
const runtimeUrl = (version) => 'https://sdk.lunarg.com/sdk/download/' + version + '/windows/vulkan-runtime-components.zip';
|
|
39
|
+
/** Known to have the runtime zip: used when LunarG cannot be asked, or none of its versions has one. */
|
|
40
|
+
const VULKAN_PINNED = '1.4.363.0';
|
|
41
|
+
/**
|
|
42
|
+
* The versions to try for the runtime zip, newest first: LunarG's latest, its x.y.z.0 (a point release such as
|
|
43
|
+
* 1.4.363.1 reissues the SDK without the runtime zip), then the pinned one.
|
|
44
|
+
*/
|
|
45
|
+
async function runtimeVersions() {
|
|
46
|
+
let latest = null;
|
|
47
|
+
try {
|
|
48
|
+
const value = (await fetchJson(VULKAN_LATEST)).windows;
|
|
49
|
+
if (typeof value === 'string' && /^\d{1,2}\.\d{1,2}\.\d{1,4}\.\d{1,3}$/.test(value))
|
|
50
|
+
latest = value;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// LunarG not reachable: the pinned version.
|
|
54
|
+
}
|
|
55
|
+
const found = latest ? [latest, latest.replace(/\.\d+$/, '.0')] : [];
|
|
56
|
+
return [...new Set([...found, VULKAN_PINNED])];
|
|
57
|
+
}
|
|
39
58
|
/**
|
|
40
59
|
* Software Vulkan: Mesa's lavapipe plus the Khronos loader (vulkan-1.dll, from LunarG's runtime components; Windows
|
|
41
60
|
* Sandbox has no Vulkan loader). The loader ignores VK_DRIVER_FILES in elevated processes, and everything in the
|
|
@@ -52,12 +71,17 @@ const setupLavapipe = async (env, mesaDir) => {
|
|
|
52
71
|
// LunarG publishes no checksum for this zip; it comes over HTTPS from LunarG, the Khronos SDK's maintainer.
|
|
53
72
|
// The zip has x86 and x64 folders: only the 64-bit loader (and vulkaninfo) is extracted.
|
|
54
73
|
const fetchRuntime = (url) => downloader.archive(url, dir, { locate: 'vulkan-1.dll', fileName: 'vulkan-runtime.zip', members: ['*/x64/*'] });
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
const versions = await runtimeVersions();
|
|
75
|
+
for (const [n, version] of versions.entries()) {
|
|
76
|
+
try {
|
|
77
|
+
await fetchRuntime(runtimeUrl(version));
|
|
78
|
+
log('Vulkan loader ' + version + ' installed');
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
if (n === versions.length - 1)
|
|
83
|
+
throw new Error('the Vulkan loader could not be downloaded (' + errMsg(e) + ')');
|
|
84
|
+
}
|
|
61
85
|
}
|
|
62
86
|
}
|
|
63
87
|
const register = (file) => execAsync(SYSTEM.reg(), ['add', 'HKLM\\SOFTWARE\\Khronos\\Vulkan\\Drivers', '/v', file, '/t', 'REG_DWORD', '/d', '0', '/f'], { stdio: 'ignore' });
|
|
@@ -2,6 +2,7 @@ import type { BootWant } from '../../core/local-config/index.js';
|
|
|
2
2
|
import type { Config } from '../../core/types.js';
|
|
3
3
|
import { type Payloads, type ServiceKind, type UsedBy } from '../../shared/accounts/index.js';
|
|
4
4
|
import { AccountLeases } from './leases.js';
|
|
5
|
+
import type { PcEnv } from './source.js';
|
|
5
6
|
import { ServiceAccountStore } from './store.js';
|
|
6
7
|
export interface AccountDelivery {
|
|
7
8
|
readonly payloads: Payloads;
|
|
@@ -22,5 +23,7 @@ export interface DeliveryInput {
|
|
|
22
23
|
readonly isRunning: (dataSet: string) => boolean;
|
|
23
24
|
readonly store?: ServiceAccountStore;
|
|
24
25
|
readonly leases?: AccountLeases;
|
|
26
|
+
/** This PC's folders: a shared kind with nothing saved takes this PC's own sign-in (left out: never). */
|
|
27
|
+
readonly pc?: PcEnv;
|
|
25
28
|
}
|
|
26
29
|
export declare function prepareServiceAccounts(i: DeliveryInput): AccountDelivery;
|
|
@@ -2,6 +2,7 @@ import { fingerprint, SERVICE_KINDS, SERVICE_SPECS, serviceWanted, } from '../..
|
|
|
2
2
|
import { setNameOf } from '../storage/index.js';
|
|
3
3
|
import { takeHandoffs } from './handoff.js';
|
|
4
4
|
import { AccountLeases } from './leases.js';
|
|
5
|
+
import { HOST_SOURCES } from './sources.js';
|
|
5
6
|
import { ServiceAccountStore } from './store.js';
|
|
6
7
|
/** How to get a first sign-in of a kind, for the note when none is saved. */
|
|
7
8
|
function howToSave(spec) {
|
|
@@ -21,6 +22,22 @@ function howToSave(spec) {
|
|
|
21
22
|
? 'save one: sandbox account login ' + spec.kind
|
|
22
23
|
: 'save one: sandbox account import ' + spec.kind + ' --from <file>';
|
|
23
24
|
}
|
|
25
|
+
/** The first time a shared kind has nothing saved: this PC's own sign-in, saved like `sandbox account import`. */
|
|
26
|
+
function takeFromPc(kind, pc, store) {
|
|
27
|
+
const source = HOST_SOURCES[kind];
|
|
28
|
+
if (!pc || !source.fromPc)
|
|
29
|
+
return null;
|
|
30
|
+
let payload = null;
|
|
31
|
+
try {
|
|
32
|
+
payload = source.fromPc(pc);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null; // This PC's program has no usable sign-in: the note says how to save one.
|
|
36
|
+
}
|
|
37
|
+
if (payload)
|
|
38
|
+
store.save(kind, payload, 'pc', source.summary(payload));
|
|
39
|
+
return payload;
|
|
40
|
+
}
|
|
24
41
|
export function prepareServiceAccounts(i) {
|
|
25
42
|
const store = i.store ?? new ServiceAccountStore(i.storageRoot);
|
|
26
43
|
const leases = i.leases ?? new AccountLeases(i.storageRoot);
|
|
@@ -53,6 +70,8 @@ export function prepareServiceAccounts(i) {
|
|
|
53
70
|
catch {
|
|
54
71
|
unreadable = true;
|
|
55
72
|
}
|
|
73
|
+
if (!payload && !unreadable)
|
|
74
|
+
payload = takeFromPc(kind, i.pc, store);
|
|
56
75
|
if (spec.singleHolder) {
|
|
57
76
|
const claim = leases.claim(kind, dataSet, i.launchId, payload ? fingerprint(payload) : null, i.isRunning);
|
|
58
77
|
if (!claim.ok) {
|
|
@@ -10,6 +10,8 @@ export interface PcEnv {
|
|
|
10
10
|
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
11
11
|
/** A variable of this Windows user's saved environment (HKCU\Environment), or null when it is not set. */
|
|
12
12
|
readonly userVariable?: (name: string) => string | null;
|
|
13
|
+
/** This PC's local drives ("D:\\"), asked only by the searches that look on every drive. */
|
|
14
|
+
readonly drives?: () => readonly string[];
|
|
13
15
|
}
|
|
14
16
|
/** The value of `name` in `reg query <key> /v <name>` output, or null. */
|
|
15
17
|
export declare function parseRegValue(text: string, name: string): string | null;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// (fromFile, `sandbox account import <kind> --from <file>`), or typed (fromAnswers, `sandbox account login <kind>`).
|
|
3
3
|
// One module per kind under kinds/; sources.ts lists them.
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { diskUsage } from '../../core/disk.js';
|
|
5
6
|
import { fail } from '../../core/util/index.js';
|
|
6
7
|
import { SYSTEM } from '../../shared/system.js';
|
|
7
8
|
import { refuseInSelfTest } from '../test-guard.js';
|
|
@@ -35,6 +36,7 @@ export function pcEnv() {
|
|
|
35
36
|
programFiles: env.ProgramFiles ?? 'C:\\Program Files',
|
|
36
37
|
env,
|
|
37
38
|
userVariable: savedUserVariable,
|
|
39
|
+
drives: () => diskUsage(env.ProgramData ?? 'C:\\').map((d) => d.drive),
|
|
38
40
|
};
|
|
39
41
|
}
|
|
40
42
|
/** What a kind whose host side is not written yet says. */
|
|
@@ -10,12 +10,13 @@ import { unrealFolders, unrealInstalls } from './unreal.js';
|
|
|
10
10
|
import { unrealVault } from './unreal-vault.js';
|
|
11
11
|
/** At most this many installs are mapped (each one is a mapping in the .wsb). */
|
|
12
12
|
export const MAX_PC_INSTALLS = 40;
|
|
13
|
+
// Engines first: a folder is mapped once, as the first source that finds it.
|
|
13
14
|
export const PC_INSTALL_SOURCES = [
|
|
14
|
-
steamInstalls,
|
|
15
|
-
epicInstalls,
|
|
16
15
|
unrealFolders,
|
|
17
16
|
unrealInstalls,
|
|
18
17
|
unrealVault,
|
|
18
|
+
steamInstalls,
|
|
19
|
+
epicInstalls,
|
|
19
20
|
unityInstalls,
|
|
20
21
|
unityAssets,
|
|
21
22
|
];
|
|
@@ -11,6 +11,9 @@ export function findEpicGames(text, wanted) {
|
|
|
11
11
|
for (const i of text ? launcherInstallations(text) : []) {
|
|
12
12
|
if (!APP.test(i.appName) || /^\.+$/.test(i.appName) || /^UE_\d/.test(i.appName))
|
|
13
13
|
continue;
|
|
14
|
+
// Engines and what the launcher puts into one (the Fab plugin lists the engine's folder) are unreal.ts's.
|
|
15
|
+
if (i.ids?.namespaceId.toLowerCase() === 'ue' || /^UE_\d/i.test(path.win32.basename(i.installLocation)))
|
|
16
|
+
continue;
|
|
14
17
|
if (names && !names.has(i.appName.toLowerCase()))
|
|
15
18
|
continue;
|
|
16
19
|
if (found.some((f) => f.id.toLowerCase() === i.appName.toLowerCase()))
|
|
@@ -10,6 +10,8 @@ export interface UnityPcFiles {
|
|
|
10
10
|
list(dir: string): string[];
|
|
11
11
|
readonly appData: string;
|
|
12
12
|
readonly programFiles: string;
|
|
13
|
+
/** Hub's folder on every other drive (D:\Program Files\Unity\Hub\Editor, D:\Unity\Hub\Editor ...). */
|
|
14
|
+
readonly otherHubFolders?: readonly string[];
|
|
13
15
|
}
|
|
14
16
|
/** The editors of this PC: all of them (true) or the listed versions. Each version once, each folder once. */
|
|
15
17
|
export declare function findUnityEditorsOnPc(files: UnityPcFiles, wanted: true | readonly string[]): PcInstall[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// Unity editors of this PC (pcInstalls.unityEditors): Unity Hub's default folder
|
|
1
|
+
// Unity editors of this PC (pcInstalls.unityEditors): Unity Hub's default folder on every drive
|
|
2
|
+
// (<drive>\Program Files\Unity\Hub\Editor, <drive>\Unity\Hub\Editor),
|
|
2
3
|
// the folder named by %APPDATA%\UnityHub\secondaryInstallPath.json and the editors in editors-v2.json. An editor counts
|
|
3
4
|
// only with Editor\Unity.exe; its folder is mapped read-only at C:\PcInstalls\unity\<version>. Every file is read
|
|
4
5
|
// bounded and every name is checked: what Hub wrote is data, never trusted.
|
|
@@ -67,8 +68,12 @@ function listedEditors(files) {
|
|
|
67
68
|
/** The editors of this PC: all of them (true) or the listed versions. Each version once, each folder once. */
|
|
68
69
|
export function findUnityEditorsOnPc(files, wanted) {
|
|
69
70
|
const candidates = [];
|
|
70
|
-
const hubFolders = [
|
|
71
|
-
|
|
71
|
+
const hubFolders = [
|
|
72
|
+
win.join(files.programFiles, 'Unity', 'Hub', 'Editor'),
|
|
73
|
+
secondaryRoot(files),
|
|
74
|
+
...(files.otherHubFolders ?? []),
|
|
75
|
+
].filter((d) => d !== null);
|
|
76
|
+
for (const folder of new Set(hubFolders.map((d) => win.resolve(d))))
|
|
72
77
|
for (const name of files.list(folder).slice(0, MAX_LISTED).sort())
|
|
73
78
|
if (UNITY_VERSION.test(name))
|
|
74
79
|
candidates.push({ version: name, root: win.join(folder, name) });
|
|
@@ -125,6 +130,10 @@ export function unityPcFiles(pc) {
|
|
|
125
130
|
list: listDir,
|
|
126
131
|
appData: pc.appData,
|
|
127
132
|
programFiles: pc.programFiles ?? 'C:\\Program Files',
|
|
133
|
+
otherHubFolders: (pc.drives?.() ?? []).flatMap((d) => [
|
|
134
|
+
win.join(d, 'Program Files', 'Unity', 'Hub', 'Editor'),
|
|
135
|
+
win.join(d, 'Unity', 'Hub', 'Editor'),
|
|
136
|
+
]),
|
|
128
137
|
};
|
|
129
138
|
}
|
|
130
139
|
/** The cache root the environment names: this terminal's variable, else the saved user one. */
|
|
@@ -11,6 +11,8 @@ export interface UnrealPcFiles {
|
|
|
11
11
|
readonly builds: string;
|
|
12
12
|
/** The launcher's default engines folder (<Program Files>\Epic Games). */
|
|
13
13
|
readonly defaultRoot: string;
|
|
14
|
+
/** More folders that may hold UE_x.y folders: the same places on every drive (D:\Program Files\Epic Games ...). */
|
|
15
|
+
readonly otherRoots?: readonly string[];
|
|
14
16
|
readonly list: (dir: string) => string[];
|
|
15
17
|
readonly read: (file: string, max: number) => Buffer | null;
|
|
16
18
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Unreal Engine versions of this PC (pcInstalls.unrealEngines): the launcher's LauncherInstalled.dat (engines it
|
|
2
|
-
// installed, with its own ids) and the launcher's default
|
|
3
|
-
//
|
|
2
|
+
// installed, with its own ids) and folders named UE_x.y in the launcher's default places on every drive
|
|
3
|
+
// (<drive>\Program Files\Epic Games, <drive>\Epic Games) and next to what it lists (an install whose entry is gone).
|
|
4
|
+
// Each must hold Engine\Build\Build.version; it is mapped read-only at
|
|
4
5
|
// C:\PcInstalls\unreal\UE_5.4. Source builds (HKCU\Software\Epic Games\Unreal Engine\Builds) are NOT mapped by
|
|
5
6
|
// themselves, as UBT writes inside an engine. pcInstalls.unrealEngineFolders: folders you registered, mapped writable
|
|
6
7
|
// (dir-<name>; a source build of this PC keeps its build id). Every file is read bounded.
|
|
@@ -54,14 +55,25 @@ export function findUnrealInstalls(files, wanted) {
|
|
|
54
55
|
...(ids ? { launcher: ids } : {}),
|
|
55
56
|
});
|
|
56
57
|
};
|
|
57
|
-
|
|
58
|
+
const listed = files.launcherInstalled ? launcherInstallations(files.launcherInstalled) : [];
|
|
59
|
+
for (const i of listed)
|
|
58
60
|
if (APP_NAME.test(i.appName))
|
|
59
61
|
installed(i.installLocation, i.ids ?? undefined);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
// Folders named like an engine: the default places, and the folders that hold what the launcher installed (an
|
|
63
|
+
// engine whose entry is gone often sits next to one that is listed, or next to a game).
|
|
64
|
+
const roots = [files.defaultRoot, ...(files.otherRoots ?? []), ...listed.map((i) => win.dirname(i.installLocation))];
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
for (const root of roots) {
|
|
67
|
+
const key = win.resolve(root).toLowerCase();
|
|
68
|
+
if (seen.has(key) || seen.size >= 32)
|
|
69
|
+
continue;
|
|
70
|
+
seen.add(key);
|
|
71
|
+
for (const name of files
|
|
72
|
+
.list(root)
|
|
73
|
+
.filter((n) => APP_NAME.test(n))
|
|
74
|
+
.sort())
|
|
75
|
+
installed(win.join(root, name));
|
|
76
|
+
}
|
|
65
77
|
return found;
|
|
66
78
|
}
|
|
67
79
|
/** Source builds this PC registered (the Builds key). They are not mapped by themselves: UBT writes inside them. */
|
|
@@ -130,6 +142,10 @@ export function unrealPcFiles(pc) {
|
|
|
130
142
|
launcherInstalled: dat ? dat.toString('utf8') : null,
|
|
131
143
|
builds: query.status === 0 ? String(query.stdout ?? '') : '',
|
|
132
144
|
defaultRoot: win.join(pc.programFiles ?? 'C:\\Program Files', 'Epic Games'),
|
|
145
|
+
otherRoots: (pc.drives?.() ?? []).flatMap((d) => [
|
|
146
|
+
win.join(d, 'Program Files', 'Epic Games'),
|
|
147
|
+
win.join(d, 'Epic Games'),
|
|
148
|
+
]),
|
|
133
149
|
list: listDir,
|
|
134
150
|
read: readBoundedFile,
|
|
135
151
|
};
|
package/dist/runtime/daemon.js
CHANGED
|
@@ -30451,6 +30451,8 @@ var UnrealStatusSchema = external_exports.object({
|
|
|
30451
30451
|
).max(64),
|
|
30452
30452
|
launcher: external_exports.object({
|
|
30453
30453
|
installed: external_exports.boolean(),
|
|
30454
|
+
/** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
|
|
30455
|
+
exe: Text2().nullable().default(null),
|
|
30454
30456
|
/** Where the launcher installs engines; null when it could not be set. */
|
|
30455
30457
|
installLocation: Text2().nullable(),
|
|
30456
30458
|
/** Why engines would not go to the data disk (shown loudly), null when they do. */
|
|
@@ -31568,7 +31570,7 @@ var EMPTY = {
|
|
|
31568
31570
|
updatedAt: "",
|
|
31569
31571
|
engines: [],
|
|
31570
31572
|
projects: [],
|
|
31571
|
-
launcher: { installed: false, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
|
|
31573
|
+
launcher: { installed: false, exe: null, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
|
|
31572
31574
|
visualStudio: { version: "", path: "", how: "", check: "", ok: false },
|
|
31573
31575
|
debugger: null,
|
|
31574
31576
|
ddc: { mode: "local", dir: null },
|
|
@@ -31596,11 +31598,15 @@ var SAVED_ENTRIES = path44.join(SAVED_DIR, "LauncherInstalled.json");
|
|
|
31596
31598
|
var programData = () => process.env.ProgramData ?? "C:\\ProgramData";
|
|
31597
31599
|
var localAppData2 = () => process.env.LOCALAPPDATA ?? "";
|
|
31598
31600
|
function launcherExe() {
|
|
31599
|
-
const
|
|
31600
|
-
|
|
31601
|
-
|
|
31602
|
-
|
|
31603
|
-
|
|
31601
|
+
const roots = [
|
|
31602
|
+
process.env.ProgramFiles ?? "C:\\Program Files",
|
|
31603
|
+
process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)"
|
|
31604
|
+
];
|
|
31605
|
+
for (const root of roots)
|
|
31606
|
+
for (const arch2 of ["Win64", "Win32"]) {
|
|
31607
|
+
const exe = path44.join(root, "Epic Games", "Launcher", "Portal", "Binaries", arch2, "EpicGamesLauncher.exe");
|
|
31608
|
+
if (exists(exe)) return exe;
|
|
31609
|
+
}
|
|
31604
31610
|
return null;
|
|
31605
31611
|
}
|
|
31606
31612
|
async function fetchLauncher() {
|
|
@@ -34573,8 +34579,19 @@ async function setupMesa(env, config2) {
|
|
|
34573
34579
|
);
|
|
34574
34580
|
if (config2.vulkan) await setupLavapipe(env, dir);
|
|
34575
34581
|
}
|
|
34576
|
-
var
|
|
34577
|
-
var
|
|
34582
|
+
var VULKAN_LATEST = "https://vulkan.lunarg.com/sdk/latest.json";
|
|
34583
|
+
var runtimeUrl = (version2) => "https://sdk.lunarg.com/sdk/download/" + version2 + "/windows/vulkan-runtime-components.zip";
|
|
34584
|
+
var VULKAN_PINNED = "1.4.363.0";
|
|
34585
|
+
async function runtimeVersions() {
|
|
34586
|
+
let latest = null;
|
|
34587
|
+
try {
|
|
34588
|
+
const value = (await fetchJson(VULKAN_LATEST)).windows;
|
|
34589
|
+
if (typeof value === "string" && /^\d{1,2}\.\d{1,2}\.\d{1,4}\.\d{1,3}$/.test(value)) latest = value;
|
|
34590
|
+
} catch {
|
|
34591
|
+
}
|
|
34592
|
+
const found = latest ? [latest, latest.replace(/\.\d+$/, ".0")] : [];
|
|
34593
|
+
return [.../* @__PURE__ */ new Set([...found, VULKAN_PINNED])];
|
|
34594
|
+
}
|
|
34578
34595
|
var setupLavapipe = async (env, mesaDir) => {
|
|
34579
34596
|
const icd = path74.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
|
|
34580
34597
|
if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path74.basename(icd) + ")");
|
|
@@ -34582,11 +34599,15 @@ var setupLavapipe = async (env, mesaDir) => {
|
|
|
34582
34599
|
if (!exists(path74.join(dir, "vulkan-1.dll")) || !exists(path74.join(dir, "vulkaninfo.exe"))) {
|
|
34583
34600
|
log("Downloading the Vulkan loader (~20 MB once) ...");
|
|
34584
34601
|
const fetchRuntime = (url2) => downloader.archive(url2, dir, { locate: "vulkan-1.dll", fileName: "vulkan-runtime.zip", members: ["*/x64/*"] });
|
|
34585
|
-
|
|
34586
|
-
|
|
34587
|
-
|
|
34588
|
-
|
|
34589
|
-
|
|
34602
|
+
const versions = await runtimeVersions();
|
|
34603
|
+
for (const [n, version2] of versions.entries()) {
|
|
34604
|
+
try {
|
|
34605
|
+
await fetchRuntime(runtimeUrl(version2));
|
|
34606
|
+
log("Vulkan loader " + version2 + " installed");
|
|
34607
|
+
break;
|
|
34608
|
+
} catch (e) {
|
|
34609
|
+
if (n === versions.length - 1) throw new Error("the Vulkan loader could not be downloaded (" + errMsg(e) + ")");
|
|
34610
|
+
}
|
|
34590
34611
|
}
|
|
34591
34612
|
}
|
|
34592
34613
|
const register = (file3) => execAsync(
|
|
@@ -35702,6 +35723,7 @@ async function setupUnreal(env, config2, _ctx) {
|
|
|
35702
35723
|
...s,
|
|
35703
35724
|
launcher: {
|
|
35704
35725
|
installed: launcher !== null,
|
|
35726
|
+
exe: launcher,
|
|
35705
35727
|
installLocation: place.installLocation,
|
|
35706
35728
|
problem: place.problem,
|
|
35707
35729
|
freeBytes: place.freeBytes,
|
|
@@ -36960,7 +36982,9 @@ import path97 from "node:path";
|
|
|
36960
36982
|
async function syncSkills(unityExe, agent) {
|
|
36961
36983
|
const home = agent === "claude" ? { CLAUDE_CONFIG_DIR: claudeDir } : { CODEX_HOME: path97.join(stateDir, "codex") };
|
|
36962
36984
|
try {
|
|
36963
|
-
await execAsync(unityExe, ["skill", "sync", agent
|
|
36985
|
+
await execAsync(unityExe, ["skill", "sync", agent === "claude" ? "claude-code" : "codex"], {
|
|
36986
|
+
env: { ...process.env, ...UNITY_CLI_ENV, ...home }
|
|
36987
|
+
});
|
|
36964
36988
|
return true;
|
|
36965
36989
|
} catch (e) {
|
|
36966
36990
|
warn("Unity skills for " + agent + " were not synced: " + (e instanceof Error ? e.message : String(e)));
|
package/dist/runtime/main.js
CHANGED
|
@@ -29528,6 +29528,8 @@ var UnrealStatusSchema = external_exports.object({
|
|
|
29528
29528
|
).max(64),
|
|
29529
29529
|
launcher: external_exports.object({
|
|
29530
29530
|
installed: external_exports.boolean(),
|
|
29531
|
+
/** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
|
|
29532
|
+
exe: Text2().nullable().default(null),
|
|
29531
29533
|
/** Where the launcher installs engines; null when it could not be set. */
|
|
29532
29534
|
installLocation: Text2().nullable(),
|
|
29533
29535
|
/** Why engines would not go to the data disk (shown loudly), null when they do. */
|
|
@@ -30875,7 +30877,7 @@ var EMPTY = {
|
|
|
30875
30877
|
updatedAt: "",
|
|
30876
30878
|
engines: [],
|
|
30877
30879
|
projects: [],
|
|
30878
|
-
launcher: { installed: false, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
|
|
30880
|
+
launcher: { installed: false, exe: null, installLocation: null, problem: null, freeBytes: null, needBytes: 0 },
|
|
30879
30881
|
visualStudio: { version: "", path: "", how: "", check: "", ok: false },
|
|
30880
30882
|
debugger: null,
|
|
30881
30883
|
ddc: { mode: "local", dir: null },
|
|
@@ -30903,11 +30905,15 @@ var SAVED_ENTRIES = path34.join(SAVED_DIR, "LauncherInstalled.json");
|
|
|
30903
30905
|
var programData = () => process.env.ProgramData ?? "C:\\ProgramData";
|
|
30904
30906
|
var localAppData2 = () => process.env.LOCALAPPDATA ?? "";
|
|
30905
30907
|
function launcherExe() {
|
|
30906
|
-
const
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
30908
|
+
const roots = [
|
|
30909
|
+
process.env.ProgramFiles ?? "C:\\Program Files",
|
|
30910
|
+
process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)"
|
|
30911
|
+
];
|
|
30912
|
+
for (const root of roots)
|
|
30913
|
+
for (const arch2 of ["Win64", "Win32"]) {
|
|
30914
|
+
const exe = path34.join(root, "Epic Games", "Launcher", "Portal", "Binaries", arch2, "EpicGamesLauncher.exe");
|
|
30915
|
+
if (exists(exe)) return exe;
|
|
30916
|
+
}
|
|
30911
30917
|
return null;
|
|
30912
30918
|
}
|
|
30913
30919
|
async function fetchLauncher() {
|
|
@@ -33859,8 +33865,19 @@ async function setupMesa(env, config3) {
|
|
|
33859
33865
|
);
|
|
33860
33866
|
if (config3.vulkan) await setupLavapipe(env, dir);
|
|
33861
33867
|
}
|
|
33862
|
-
var
|
|
33863
|
-
var
|
|
33868
|
+
var VULKAN_LATEST = "https://vulkan.lunarg.com/sdk/latest.json";
|
|
33869
|
+
var runtimeUrl = (version2) => "https://sdk.lunarg.com/sdk/download/" + version2 + "/windows/vulkan-runtime-components.zip";
|
|
33870
|
+
var VULKAN_PINNED = "1.4.363.0";
|
|
33871
|
+
async function runtimeVersions() {
|
|
33872
|
+
let latest = null;
|
|
33873
|
+
try {
|
|
33874
|
+
const value = (await fetchJson(VULKAN_LATEST)).windows;
|
|
33875
|
+
if (typeof value === "string" && /^\d{1,2}\.\d{1,2}\.\d{1,4}\.\d{1,3}$/.test(value)) latest = value;
|
|
33876
|
+
} catch {
|
|
33877
|
+
}
|
|
33878
|
+
const found = latest ? [latest, latest.replace(/\.\d+$/, ".0")] : [];
|
|
33879
|
+
return [.../* @__PURE__ */ new Set([...found, VULKAN_PINNED])];
|
|
33880
|
+
}
|
|
33864
33881
|
var setupLavapipe = async (env, mesaDir) => {
|
|
33865
33882
|
const icd = path64.join(mesaDir, arch === "arm64" ? "lvp_icd.aarch64.json" : "lvp_icd.x86_64.json");
|
|
33866
33883
|
if (!exists(icd)) throw new Error("this Mesa build has no lavapipe (" + path64.basename(icd) + ")");
|
|
@@ -33868,11 +33885,15 @@ var setupLavapipe = async (env, mesaDir) => {
|
|
|
33868
33885
|
if (!exists(path64.join(dir, "vulkan-1.dll")) || !exists(path64.join(dir, "vulkaninfo.exe"))) {
|
|
33869
33886
|
log("Downloading the Vulkan loader (~20 MB once) ...");
|
|
33870
33887
|
const fetchRuntime = (url2) => downloader.archive(url2, dir, { locate: "vulkan-1.dll", fileName: "vulkan-runtime.zip", members: ["*/x64/*"] });
|
|
33871
|
-
|
|
33872
|
-
|
|
33873
|
-
|
|
33874
|
-
|
|
33875
|
-
|
|
33888
|
+
const versions = await runtimeVersions();
|
|
33889
|
+
for (const [n, version2] of versions.entries()) {
|
|
33890
|
+
try {
|
|
33891
|
+
await fetchRuntime(runtimeUrl(version2));
|
|
33892
|
+
log("Vulkan loader " + version2 + " installed");
|
|
33893
|
+
break;
|
|
33894
|
+
} catch (e) {
|
|
33895
|
+
if (n === versions.length - 1) throw new Error("the Vulkan loader could not be downloaded (" + errMsg(e) + ")");
|
|
33896
|
+
}
|
|
33876
33897
|
}
|
|
33877
33898
|
}
|
|
33878
33899
|
const register = (file3) => execAsync(
|
|
@@ -34940,6 +34961,7 @@ async function setupUnreal(env, config3, _ctx) {
|
|
|
34940
34961
|
...s,
|
|
34941
34962
|
launcher: {
|
|
34942
34963
|
installed: launcher !== null,
|
|
34964
|
+
exe: launcher,
|
|
34943
34965
|
installLocation: place.installLocation,
|
|
34944
34966
|
problem: place.problem,
|
|
34945
34967
|
freeBytes: place.freeBytes,
|
|
@@ -37670,7 +37692,9 @@ import path87 from "node:path";
|
|
|
37670
37692
|
async function syncSkills(unityExe, agent) {
|
|
37671
37693
|
const home = agent === "claude" ? { CLAUDE_CONFIG_DIR: claudeDir } : { CODEX_HOME: path87.join(stateDir, "codex") };
|
|
37672
37694
|
try {
|
|
37673
|
-
await execAsync(unityExe, ["skill", "sync", agent
|
|
37695
|
+
await execAsync(unityExe, ["skill", "sync", agent === "claude" ? "claude-code" : "codex"], {
|
|
37696
|
+
env: { ...process.env, ...UNITY_CLI_ENV, ...home }
|
|
37697
|
+
});
|
|
37674
37698
|
return true;
|
|
37675
37699
|
} catch (e) {
|
|
37676
37700
|
warn("Unity skills for " + agent + " were not synced: " + (e instanceof Error ? e.message : String(e)));
|
|
@@ -255,6 +255,7 @@ export const enginesSuite = {
|
|
|
255
255
|
projects: [{ workspace: 'C:\\Projects\\Work\\MyGame', engine: pcEngine, reason: 'the project asks for 5.4' }],
|
|
256
256
|
launcher: {
|
|
257
257
|
installed: true,
|
|
258
|
+
exe: null,
|
|
258
259
|
installLocation: enginesRoot,
|
|
259
260
|
problem: null,
|
|
260
261
|
freeBytes: null,
|
|
@@ -380,6 +381,14 @@ export const enginesSuite = {
|
|
|
380
381
|
AppVersion: 'v',
|
|
381
382
|
AppName: 'UE_5.3',
|
|
382
383
|
},
|
|
384
|
+
{
|
|
385
|
+
InstallLocation: pcLauncher,
|
|
386
|
+
NamespaceId: 'ue',
|
|
387
|
+
ItemId: 'fab',
|
|
388
|
+
ArtifactId: 'FabPlugin_5.4',
|
|
389
|
+
AppVersion: '5.4.4-1+++UE5+Release-5.4-0.0.21',
|
|
390
|
+
AppName: 'FabPlugin_5.4',
|
|
391
|
+
},
|
|
383
392
|
],
|
|
384
393
|
});
|
|
385
394
|
const reg = '\r\nHKEY_CURRENT_USER\\Software\\Epic Games\\Unreal Engine\\Builds\r\n {2D9FCA5D-4E7B-4C12-8B6E-1A2B3C4D5E6F} REG_SZ ' +
|
|
@@ -401,13 +410,33 @@ export const enginesSuite = {
|
|
|
401
410
|
t.check(pcFound.every((i) => i.host !== path.join(pcRoot, 'gone')), 'an entry whose folder is gone is left out');
|
|
402
411
|
t.equal(findUnrealInstalls(files, ['5.6']).map((i) => i.host), [pcDefault], 'a list maps only those versions');
|
|
403
412
|
t.equal(findUnrealInstalls({ ...files, launcherInstalled: null, builds: '' }, true).map((i) => i.id), ['UE_5.4', 'UE_5.6'], 'no LauncherInstalled.dat: the default folders');
|
|
413
|
+
const otherDrive = makeEngine(path.join(pcRoot, 'F', 'Program Files', 'Epic Games', 'UE_5.8'), [5, 8, 0], true);
|
|
414
|
+
t.equal(findUnrealInstalls({
|
|
415
|
+
...files,
|
|
416
|
+
launcherInstalled: null,
|
|
417
|
+
defaultRoot: path.join(pcRoot, 'none'),
|
|
418
|
+
otherRoots: [path.join(pcRoot, 'F', 'Program Files', 'Epic Games')],
|
|
419
|
+
}, true).map((i) => i.host), [otherDrive], 'an engine in the default place on another drive is found');
|
|
420
|
+
const nextTo = JSON.stringify({
|
|
421
|
+
InstallationList: [
|
|
422
|
+
{
|
|
423
|
+
InstallLocation: path.join(pcRoot, 'F', 'Program Files', 'Epic Games', 'SomeGame'),
|
|
424
|
+
NamespaceId: 'fn',
|
|
425
|
+
ItemId: 'g',
|
|
426
|
+
ArtifactId: 'SomeGame',
|
|
427
|
+
AppVersion: '1',
|
|
428
|
+
AppName: 'SomeGame',
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
});
|
|
432
|
+
t.equal(findUnrealInstalls({ ...files, launcherInstalled: nextTo, defaultRoot: path.join(pcRoot, 'none') }, true).map((i) => i.id), ['UE_5.8'], 'and one next to what the launcher lists');
|
|
404
433
|
const folders = findEngineFolders({ read: DISK.read, builds: reg }, [
|
|
405
434
|
pcSource,
|
|
406
435
|
path.join(pcRoot, 'nothing'),
|
|
407
436
|
'relative',
|
|
408
437
|
]);
|
|
409
438
|
t.equal(folders.map((f) => [f.id, f.writable]), [['dir-UnrealEngine', true]], 'a registered folder is mapped writable; one without an engine is left out');
|
|
410
|
-
t.equal(findEpicGames(dat, true).map((g) => g.id), ['Fortnite'], "the launcher's games are the epic-game installs (engines are not)");
|
|
439
|
+
t.equal(findEpicGames(dat, true).map((g) => g.id), ['Fortnite'], "the launcher's games are the epic-game installs (engines and the Fab plugin in one are not)");
|
|
411
440
|
t.equal(findEpicGames(dat, ['nothing']), [], 'a list maps only those games');
|
|
412
441
|
t.check(engineFolderProblem(pcSource, DISK.read) === null, 'Register an engine folder accepts an engine folder');
|
|
413
442
|
t.includes(engineFolderProblem(pcRoot, DISK.read) ?? '', 'not an Unreal Engine folder', 'and refuses one without Build.version');
|
|
@@ -18,7 +18,7 @@ function statusWith(version) {
|
|
|
18
18
|
},
|
|
19
19
|
],
|
|
20
20
|
projects: [{ workspace: PROJECT.workspace, engine: 'C:\\E', reason: 'test' }],
|
|
21
|
-
launcher: { installed: false, installLocation: null, problem: null, freeBytes: null, needBytes: 1 },
|
|
21
|
+
launcher: { installed: false, exe: null, installLocation: null, problem: null, freeBytes: null, needBytes: 1 },
|
|
22
22
|
visualStudio: { version: '17.14', path: 'C:/VS', how: 'kept', check: 'ok', ok: true },
|
|
23
23
|
debugger: null,
|
|
24
24
|
ddc: { mode: 'persisted', dir: null },
|
|
@@ -18,7 +18,7 @@ import { clearSecrets, SecretStore } from '../host/secrets/index.js';
|
|
|
18
18
|
import { applyServiceAccounts, readDelivered } from '../guest/accounts/apply.js';
|
|
19
19
|
import { AccountWatch } from '../guest/accounts/watch.js';
|
|
20
20
|
import { epicAdapter } from '../guest/accounts/kinds/epic.js';
|
|
21
|
-
import { epicSettingsFile, fingerprint, readEpicLogin, SERVICE_KINDS, SERVICE_SPECS, serviceWanted, withEpicLogin, } from '../shared/accounts/index.js';
|
|
21
|
+
import { epicSettingsFile, epicSettingsFiles, fingerprint, readEpicLogin, SERVICE_KINDS, SERVICE_SPECS, serviceWanted, withEpicLogin, } from '../shared/accounts/index.js';
|
|
22
22
|
import { RunDir } from '../shared/channel/index.js';
|
|
23
23
|
import { decodeText, encodeText, readBoundedFile } from '../shared/io/index.js';
|
|
24
24
|
const SIGN_IN = 'PlantedEpicSignIn' + 'AbCdEf0123456789+/'.repeat(6) + '==';
|
|
@@ -141,6 +141,17 @@ export const serviceAccountsSuite = {
|
|
|
141
141
|
signIns.remove('epic');
|
|
142
142
|
const first = deliver();
|
|
143
143
|
t.check(!first.payloads.epic && first.leased.includes('epic') && launchLeases.holder('epic')?.launchId === 'L-boot', 'nothing saved yet: the lease is claimed anyway, so a first sign-in made there can come back');
|
|
144
|
+
const pcLocal = t.dir('svc-pc-local');
|
|
145
|
+
for (const file of epicSettingsFiles(pcLocal)) {
|
|
146
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
147
|
+
fs.writeFileSync(file, INI);
|
|
148
|
+
}
|
|
149
|
+
const thisPc = { localAppData: pcLocal, appData: t.dir('svc-pc-roaming'), programData: t.dir('svc-pc-data') };
|
|
150
|
+
signIns.remove('epic');
|
|
151
|
+
const fromPc = deliver({ pc: thisPc });
|
|
152
|
+
t.check(fromPc.payloads.epic?.data === SIGN_IN && signIns.info('epic')?.source === 'pc', "shared with nothing saved: this PC's own sign-in is taken and saved, as import would");
|
|
153
|
+
signIns.remove('epic');
|
|
154
|
+
t.check(!deliver().payloads.epic, 'without this PC (pc left out) nothing is taken');
|
|
144
155
|
const sharedRun = await f.run({}, config);
|
|
145
156
|
const launched = generateSandbox({
|
|
146
157
|
packageRoot: t.packageRoot,
|
|
@@ -28,6 +28,7 @@ export declare const UnrealStatusSchema: z.ZodObject<{
|
|
|
28
28
|
}, z.core.$strip>>;
|
|
29
29
|
launcher: z.ZodObject<{
|
|
30
30
|
installed: z.ZodBoolean;
|
|
31
|
+
exe: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
31
32
|
installLocation: z.ZodNullable<z.ZodString>;
|
|
32
33
|
problem: z.ZodNullable<z.ZodString>;
|
|
33
34
|
freeBytes: z.ZodNullable<z.ZodNumber>;
|
|
@@ -30,6 +30,8 @@ export const UnrealStatusSchema = z.object({
|
|
|
30
30
|
.max(64),
|
|
31
31
|
launcher: z.object({
|
|
32
32
|
installed: z.boolean(),
|
|
33
|
+
/** Its program (Program Files or Program Files (x86), by launcher version); null when there is none. */
|
|
34
|
+
exe: Text().nullable().default(null),
|
|
33
35
|
/** Where the launcher installs engines; null when it could not be set. */
|
|
34
36
|
installLocation: Text().nullable(),
|
|
35
37
|
/** Why engines would not go to the data disk (shown loudly), null when they do. */
|
|
@@ -8,9 +8,9 @@ using System.Runtime.InteropServices;
|
|
|
8
8
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
9
9
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
10
10
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
11
|
-
[assembly: AssemblyVersion("1.27.
|
|
12
|
-
[assembly: AssemblyFileVersion("1.27.
|
|
13
|
-
[assembly: AssemblyInformationalVersion("1.27.
|
|
11
|
+
[assembly: AssemblyVersion("1.27.1.0")]
|
|
12
|
+
[assembly: AssemblyFileVersion("1.27.1.0")]
|
|
13
|
+
[assembly: AssemblyInformationalVersion("1.27.1")]
|
|
14
14
|
[assembly: ComVisible(false)]
|
|
15
15
|
// computecore.dll and computestorage.dll are not KnownDLLs: load them from System32 only, never from the exe's folder.
|
|
16
16
|
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
|
@@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|
|
8
8
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
9
9
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
10
10
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
11
|
-
[assembly: AssemblyVersion("1.27.
|
|
12
|
-
[assembly: AssemblyFileVersion("1.27.
|
|
13
|
-
[assembly: AssemblyInformationalVersion("1.27.
|
|
11
|
+
[assembly: AssemblyVersion("1.27.1.0")]
|
|
12
|
+
[assembly: AssemblyFileVersion("1.27.1.0")]
|
|
13
|
+
[assembly: AssemblyInformationalVersion("1.27.1")]
|
|
14
14
|
[assembly: ComVisible(false)]
|
|
@@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
|
|
|
9
9
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
10
10
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
11
11
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
12
|
-
[assembly: AssemblyVersion("1.27.
|
|
13
|
-
[assembly: AssemblyFileVersion("1.27.
|
|
14
|
-
[assembly: AssemblyInformationalVersion("1.27.
|
|
12
|
+
[assembly: AssemblyVersion("1.27.1.0")]
|
|
13
|
+
[assembly: AssemblyFileVersion("1.27.1.0")]
|
|
14
|
+
[assembly: AssemblyInformationalVersion("1.27.1")]
|
|
15
15
|
[assembly: ComVisible(false)]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "windows-development-sandbox",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.1",
|
|
4
4
|
"description": "A disposable Windows Sandbox for development, with or without an AI agent (Claude Code, Codex, Gemini, opencode, ...): the folder you run it from is the workspace, toolchains and databases for your project install themselves, and nothing else on your PC is reachable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|