windows-development-sandbox 1.11.6 → 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/projects/projects.def.js +1 -1
- package/dist/app/features/settings/settings.run.d.ts +3 -0
- package/dist/app/features/settings/settings.run.js +16 -2
- package/dist/app/features/updates/update-lines.d.ts +1 -1
- package/dist/app/features/updates/update-lines.js +3 -7
- package/dist/app/features/updates/updates.def.js +1 -1
- 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/host/update/decision.d.ts +3 -2
- package/dist/host/update/decision.js +2 -3
- package/dist/host/update/updater.d.ts +4 -1
- package/dist/host/update/updater.js +11 -6
- 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/selftest/update-service.test.js +0 -7
- package/dist/selftest/update.test.js +4 -4
- 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-QL7KHCEE.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/daemon.js
CHANGED
|
@@ -25560,14 +25560,19 @@ var NetworkSchema = external_exports.strictObject({
|
|
|
25560
25560
|
});
|
|
25561
25561
|
var AuditSchema = external_exports.strictObject({
|
|
25562
25562
|
enabled: external_exports.boolean().describe(
|
|
25563
|
-
"Keep an audit log on this PC of what
|
|
25563
|
+
"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."
|
|
25564
|
+
),
|
|
25565
|
+
days: external_exports.number().int().min(1).max(365).describe(
|
|
25566
|
+
"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."
|
|
25564
25567
|
),
|
|
25565
|
-
days: external_exports.number().int().min(1).max(365).describe("Days the audit log is kept."),
|
|
25566
25568
|
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."),
|
|
25567
25569
|
processes: external_exports.boolean().describe(
|
|
25568
25570
|
"Record every program started in the sandbox with its command line (Windows process auditing; repeated runs are counted, not listed)."
|
|
25569
25571
|
),
|
|
25570
|
-
files: external_exports.boolean().describe("Record the files changed in the
|
|
25572
|
+
files: external_exports.boolean().describe("Record the files changed in the projects while the sandbox runs."),
|
|
25573
|
+
commits: external_exports.boolean().describe(
|
|
25574
|
+
"Record the git commits made in the projects while the sandbox runs (read from each project's .git folder on this PC)."
|
|
25575
|
+
)
|
|
25571
25576
|
});
|
|
25572
25577
|
var WorkspaceFilterSchema = external_exports.strictObject({
|
|
25573
25578
|
enabled: external_exports.boolean().describe(
|
|
@@ -25770,7 +25775,100 @@ var ToolchainsSchema = external_exports.strictObject({
|
|
|
25770
25775
|
|
|
25771
25776
|
// src/shared/apps/catalogue.ts
|
|
25772
25777
|
var gh = (github, asset) => ({ github, asset });
|
|
25778
|
+
var RTK_VERSION = "1.0.1";
|
|
25779
|
+
var RTK_URL = "https://github.com/rtk-ai/rtk/releases/download/v" + RTK_VERSION + "/rtk-oss-x86_64-pc-windows-msvc.zip";
|
|
25780
|
+
var RTK_SHA256 = "0e53e2eca471e15fbd3636e64e6bc0b182cbc278ed0339c80450a2dd03f4cd6b";
|
|
25781
|
+
var HEADROOM_VERSION = "0.41.0";
|
|
25782
|
+
var CCUSAGE_VERSION = "20.0.36";
|
|
25783
|
+
var PLAYWRIGHT_MCP_VERSION = "0.0.83";
|
|
25784
|
+
var CONTEXT7_MCP_VERSION = "4.4.2";
|
|
25773
25785
|
var APPS = [
|
|
25786
|
+
// ---- agent add-ons
|
|
25787
|
+
{
|
|
25788
|
+
id: "rtk",
|
|
25789
|
+
name: "rtk (Rust Token Killer)",
|
|
25790
|
+
category: "agents",
|
|
25791
|
+
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.",
|
|
25792
|
+
size: "6 MB",
|
|
25793
|
+
source: { url: RTK_URL, sha256: RTK_SHA256 },
|
|
25794
|
+
exe: "rtk.exe",
|
|
25795
|
+
cli: true,
|
|
25796
|
+
plugsInto: "Claude Code through a hook in the sandbox's managed settings; other agents are told to use it",
|
|
25797
|
+
userOnly: true
|
|
25798
|
+
},
|
|
25799
|
+
{
|
|
25800
|
+
id: "headroom",
|
|
25801
|
+
name: "Headroom",
|
|
25802
|
+
category: "agents",
|
|
25803
|
+
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.",
|
|
25804
|
+
size: "150 MB",
|
|
25805
|
+
source: { locked: "uv", package: "headroom-ai", version: HEADROOM_VERSION },
|
|
25806
|
+
exe: "headroom.exe",
|
|
25807
|
+
service: true,
|
|
25808
|
+
plugsInto: "Claude Code: the sandbox starts the proxy and points Claude Code at it (managed settings)",
|
|
25809
|
+
userOnly: true
|
|
25810
|
+
},
|
|
25811
|
+
{
|
|
25812
|
+
id: "ccusage",
|
|
25813
|
+
name: "ccusage",
|
|
25814
|
+
category: "agents",
|
|
25815
|
+
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).",
|
|
25816
|
+
size: "5 MB",
|
|
25817
|
+
source: { locked: "npm", package: "ccusage", version: CCUSAGE_VERSION },
|
|
25818
|
+
exe: "ccusage.cmd",
|
|
25819
|
+
cli: true,
|
|
25820
|
+
plugsInto: "Reads Claude Code's session logs in the sandbox; changes nothing",
|
|
25821
|
+
userOnly: true
|
|
25822
|
+
},
|
|
25823
|
+
{
|
|
25824
|
+
id: "playwright-mcp",
|
|
25825
|
+
name: "Playwright MCP",
|
|
25826
|
+
category: "agents",
|
|
25827
|
+
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.",
|
|
25828
|
+
size: "20 MB",
|
|
25829
|
+
source: { locked: "npm", package: "@playwright/mcp", version: PLAYWRIGHT_MCP_VERSION },
|
|
25830
|
+
exe: "playwright-mcp.cmd",
|
|
25831
|
+
service: true,
|
|
25832
|
+
mcp: { name: "sbx-playwright", script: "node_modules/@playwright/mcp/cli.js", args: ["--browser", "msedge"] },
|
|
25833
|
+
plugsInto: "Claude Code as the MCP server sbx-playwright (the sandbox's Claude settings)",
|
|
25834
|
+
userOnly: true
|
|
25835
|
+
},
|
|
25836
|
+
{
|
|
25837
|
+
id: "context7",
|
|
25838
|
+
name: "Context7 MCP",
|
|
25839
|
+
category: "agents",
|
|
25840
|
+
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.",
|
|
25841
|
+
size: "55 MB",
|
|
25842
|
+
source: { locked: "npm", package: "@upstash/context7-mcp", version: CONTEXT7_MCP_VERSION },
|
|
25843
|
+
exe: "context7-mcp.cmd",
|
|
25844
|
+
service: true,
|
|
25845
|
+
mcp: { name: "sbx-context7", script: "node_modules/@upstash/context7-mcp/dist/index.js" },
|
|
25846
|
+
plugsInto: "Claude Code as the MCP server sbx-context7 (the sandbox's Claude settings)",
|
|
25847
|
+
userOnly: true
|
|
25848
|
+
},
|
|
25849
|
+
{
|
|
25850
|
+
id: "claude-mem",
|
|
25851
|
+
name: "claude-mem",
|
|
25852
|
+
category: "agents",
|
|
25853
|
+
about: "Persistent memory for Claude Code (a plugin you install on this PC): its database is brought into the sandbox.",
|
|
25854
|
+
size: "",
|
|
25855
|
+
source: { resolve: "setting" },
|
|
25856
|
+
exe: "",
|
|
25857
|
+
setting: "claudeProfile.syncClaudeMem",
|
|
25858
|
+
plugsInto: "Claude Code, with your Claude settings copied from this PC",
|
|
25859
|
+
userOnly: true
|
|
25860
|
+
},
|
|
25861
|
+
{
|
|
25862
|
+
id: "rea",
|
|
25863
|
+
name: "REA (Reverse Engineer Anything)",
|
|
25864
|
+
category: "agents",
|
|
25865
|
+
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+.",
|
|
25866
|
+
size: "8 MB",
|
|
25867
|
+
source: { npm: "rea-agents" },
|
|
25868
|
+
exe: "rea.cmd",
|
|
25869
|
+
cli: true,
|
|
25870
|
+
plugsInto: "Claude Code and Codex as an MCP server, after `rea setup`"
|
|
25871
|
+
},
|
|
25774
25872
|
// ---- editors
|
|
25775
25873
|
{
|
|
25776
25874
|
id: "vscode",
|
|
@@ -26232,16 +26330,6 @@ var APPS = [
|
|
|
26232
26330
|
cli: true
|
|
26233
26331
|
},
|
|
26234
26332
|
// ---- reverse engineering
|
|
26235
|
-
{
|
|
26236
|
-
id: "rea",
|
|
26237
|
-
name: "REA (Reverse Engineer Anything)",
|
|
26238
|
-
category: "reversing",
|
|
26239
|
-
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+.",
|
|
26240
|
-
size: "8 MB",
|
|
26241
|
-
source: { npm: "rea-agents" },
|
|
26242
|
-
exe: "rea.cmd",
|
|
26243
|
-
cli: true
|
|
26244
|
-
},
|
|
26245
26333
|
{
|
|
26246
26334
|
id: "ghidra",
|
|
26247
26335
|
name: "Ghidra",
|
|
@@ -26554,13 +26642,39 @@ function appsToInstall(apps, gitAccess) {
|
|
|
26554
26642
|
const needs7zip = allowed.some((e) => e.needs?.includes("7zip") || e.unpack === "nsis") && !allowed.some((e) => e.id === "7zip");
|
|
26555
26643
|
return { entries: [...needs7zip ? [appById("7zip")] : [], ...allowed], skipped };
|
|
26556
26644
|
}
|
|
26645
|
+
function appsNeedUv(apps) {
|
|
26646
|
+
return Boolean(
|
|
26647
|
+
apps?.install.some((id) => {
|
|
26648
|
+
const source = appById(id)?.source;
|
|
26649
|
+
return source !== void 0 && "locked" in source && source.locked === "uv";
|
|
26650
|
+
})
|
|
26651
|
+
);
|
|
26652
|
+
}
|
|
26557
26653
|
function appsNeedMesa(apps) {
|
|
26558
26654
|
return Boolean(apps?.install.some((id) => appById(id)?.needs?.includes("mesa")));
|
|
26559
26655
|
}
|
|
26560
26656
|
|
|
26657
|
+
// src/shared/apps/agent-addons.ts
|
|
26658
|
+
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`).";
|
|
26659
|
+
var HEADROOM_PORT = 8787;
|
|
26660
|
+
function headroomUrl(port = HEADROOM_PORT) {
|
|
26661
|
+
return "http://127.0.0.1:" + port;
|
|
26662
|
+
}
|
|
26663
|
+
function headroomGuideLine(logFile2) {
|
|
26664
|
+
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.";
|
|
26665
|
+
}
|
|
26666
|
+
function addonGuideLine(mcpNames, ccusage) {
|
|
26667
|
+
return [
|
|
26668
|
+
...mcpNames.length ? ["- MCP servers in Claude Code from Apps: " + mcpNames.join(", ") + "."] : [],
|
|
26669
|
+
...ccusage ? ["- ccusage is on PATH: `ccusage daily` (or `monthly`, `session`) reports token use and cost."] : []
|
|
26670
|
+
];
|
|
26671
|
+
}
|
|
26672
|
+
|
|
26561
26673
|
// src/core/schema/apps.ts
|
|
26562
26674
|
var CATALOGUE_IDS = APPS.filter((a) => !a.setting).map((a) => a.id);
|
|
26563
26675
|
var AppIdSchema = external_exports.enum(CATALOGUE_IDS);
|
|
26676
|
+
var PROJECT_IDS = APPS.filter((a) => !a.setting && !a.userOnly).map((a) => a.id);
|
|
26677
|
+
var ProjectAppIdSchema = external_exports.enum(PROJECT_IDS);
|
|
26564
26678
|
var CustomAppIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, "lower-case letters, digits and - only");
|
|
26565
26679
|
var compiles = (pattern) => {
|
|
26566
26680
|
try {
|
|
@@ -26584,6 +26698,11 @@ var CustomAppSchema = external_exports.strictObject({
|
|
|
26584
26698
|
}).refine((a) => a.github && a.asset ? !a.url : Boolean(a.url) && !a.github && !a.asset, {
|
|
26585
26699
|
message: "give github + asset, or url (not both)"
|
|
26586
26700
|
});
|
|
26701
|
+
var ProjectAppsSchema = external_exports.strictObject({
|
|
26702
|
+
install: external_exports.array(ProjectAppIdSchema).describe(
|
|
26703
|
+
"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)."
|
|
26704
|
+
)
|
|
26705
|
+
});
|
|
26587
26706
|
var AppsSchema = external_exports.strictObject({
|
|
26588
26707
|
install: external_exports.array(AppIdSchema).describe(
|
|
26589
26708
|
"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."
|
|
@@ -26748,8 +26867,8 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26748
26867
|
attach: AttachSchema.partial(),
|
|
26749
26868
|
personalization: toggle("Copy your desktop look into the sandbox.").partial(),
|
|
26750
26869
|
// Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add
|
|
26751
|
-
// them.
|
|
26752
|
-
apps:
|
|
26870
|
+
// them, nor agent add-ons that are yours only (rtk hooks every agent command, Headroom sits in its API path).
|
|
26871
|
+
apps: ProjectAppsSchema.partial(),
|
|
26753
26872
|
claudeProfile: ClaudeProfileSchema.pick({
|
|
26754
26873
|
enabled: true,
|
|
26755
26874
|
overwrite: true,
|
|
@@ -27599,9 +27718,29 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
27599
27718
|
"usoclient.exe",
|
|
27600
27719
|
"musnotification.exe"
|
|
27601
27720
|
]);
|
|
27721
|
+
var ROOT_SLACK_MS = 5e3;
|
|
27722
|
+
var MAX_KNOWN = 5e4;
|
|
27723
|
+
var Attributor = class {
|
|
27724
|
+
owner = /* @__PURE__ */ new Map();
|
|
27725
|
+
/** The session of a new process (pid, started by ppid at time t), or undefined. */
|
|
27726
|
+
attribute(e, roots) {
|
|
27727
|
+
const root = roots.find(
|
|
27728
|
+
(r) => r.pid === e.ppid && e.t >= r.from - ROOT_SLACK_MS && (r.to === void 0 || e.t <= r.to + ROOT_SLACK_MS)
|
|
27729
|
+
);
|
|
27730
|
+
const session2 = root?.session ?? this.owner.get(e.ppid) ?? void 0;
|
|
27731
|
+
this.owner.delete(e.pid);
|
|
27732
|
+
this.owner.set(e.pid, session2 ?? null);
|
|
27733
|
+
if (this.owner.size > MAX_KNOWN) this.owner.delete(this.owner.keys().next().value);
|
|
27734
|
+
return session2;
|
|
27735
|
+
}
|
|
27736
|
+
};
|
|
27602
27737
|
var decode3 = (s) => s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
27603
27738
|
var field = (event, name) => decode3(new RegExp("<Data Name='" + name + "'>([^<]*)</Data>").exec(event)?.[1] ?? "");
|
|
27604
|
-
|
|
27739
|
+
var pidOf = (text) => {
|
|
27740
|
+
const n = /^0x[0-9a-f]{1,8}$/i.test(text) ? parseInt(text, 16) : /^\d{1,10}$/.test(text) ? Number(text) : 0;
|
|
27741
|
+
return Number.isSafeInteger(n) ? n : 0;
|
|
27742
|
+
};
|
|
27743
|
+
function parseProcessEvents(xml, attribution) {
|
|
27605
27744
|
const lines = [];
|
|
27606
27745
|
let last = 0;
|
|
27607
27746
|
for (const event of xml.split("</Event>")) {
|
|
@@ -27609,15 +27748,19 @@ function parseProcessEvents(xml) {
|
|
|
27609
27748
|
if (!id) continue;
|
|
27610
27749
|
last = Math.max(last, id);
|
|
27611
27750
|
const program = field(event, "NewProcessName");
|
|
27612
|
-
if (!program || NOISE.has(path15.win32.basename(program).toLowerCase())) continue;
|
|
27613
27751
|
const t = /SystemTime='([^']+)'/.exec(event)?.[1] ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
27752
|
+
const pid = pidOf(field(event, "NewProcessId"));
|
|
27753
|
+
const ppid = pidOf(field(event, "ProcessId"));
|
|
27754
|
+
const session2 = attribution && pid && ppid ? attribution.attributor.attribute({ pid, ppid, t: Date.parse(t) || Date.now() }, attribution.roots) : void 0;
|
|
27755
|
+
if (!program || NOISE.has(path15.win32.basename(program).toLowerCase())) continue;
|
|
27614
27756
|
lines.push(
|
|
27615
27757
|
JSON.stringify({
|
|
27616
27758
|
t,
|
|
27617
27759
|
k: "proc",
|
|
27618
27760
|
p: program.slice(0, 1024),
|
|
27619
27761
|
c: field(event, "CommandLine").slice(0, 2e3),
|
|
27620
|
-
pp: field(event, "ParentProcessName").slice(0, 1024)
|
|
27762
|
+
pp: field(event, "ParentProcessName").slice(0, 1024),
|
|
27763
|
+
...session2 ? { s: session2 } : {}
|
|
27621
27764
|
})
|
|
27622
27765
|
);
|
|
27623
27766
|
}
|
|
@@ -27645,9 +27788,10 @@ var newestRecord = () => {
|
|
|
27645
27788
|
});
|
|
27646
27789
|
return parseProcessEvents(r.stdout ?? "").last;
|
|
27647
27790
|
};
|
|
27648
|
-
function startProcessCollector() {
|
|
27791
|
+
function startProcessCollector(roots = () => []) {
|
|
27649
27792
|
if (!auditOn()) return;
|
|
27650
27793
|
let last = newestRecord();
|
|
27794
|
+
const attributor = new Attributor();
|
|
27651
27795
|
const pass = () => {
|
|
27652
27796
|
try {
|
|
27653
27797
|
const r = spawnSync(
|
|
@@ -27661,7 +27805,7 @@ function startProcessCollector() {
|
|
|
27661
27805
|
],
|
|
27662
27806
|
{ encoding: "utf8", windowsHide: true, maxBuffer: 64 * 1024 * 1024 }
|
|
27663
27807
|
);
|
|
27664
|
-
const { lines, last: newest } = parseProcessEvents(r.stdout ?? "");
|
|
27808
|
+
const { lines, last: newest } = parseProcessEvents(r.stdout ?? "", { attributor, roots: roots() });
|
|
27665
27809
|
if (newest) last = newest;
|
|
27666
27810
|
if (lines.length)
|
|
27667
27811
|
fs12.writeFileSync(
|
|
@@ -28281,18 +28425,76 @@ function readBootEnv() {
|
|
|
28281
28425
|
}
|
|
28282
28426
|
|
|
28283
28427
|
// src/guest/boot/guide.ts
|
|
28428
|
+
import fs19 from "node:fs";
|
|
28429
|
+
import path27 from "node:path";
|
|
28430
|
+
|
|
28431
|
+
// src/guest/apps/find-exe.ts
|
|
28284
28432
|
import fs18 from "node:fs";
|
|
28285
28433
|
import path25 from "node:path";
|
|
28434
|
+
var MAX_DEPTH = 7;
|
|
28435
|
+
var MAX_ENTRIES = 5e4;
|
|
28436
|
+
var X64_FOLDER = /(^|[\\/])(amd64|x64|x86_64|win64)([\\/]|$)/i;
|
|
28437
|
+
function findExe(root, exe) {
|
|
28438
|
+
const match = exeMatcher(exe);
|
|
28439
|
+
const best = (hits) => hits.find((h) => X64_FOLDER.test(path25.relative(root, h))) ?? hits[0] ?? null;
|
|
28440
|
+
let queue = [root];
|
|
28441
|
+
let seen = 0;
|
|
28442
|
+
for (let depth = 0; depth < MAX_DEPTH && queue.length; depth++) {
|
|
28443
|
+
const next = [];
|
|
28444
|
+
const hits = [];
|
|
28445
|
+
for (const dir of queue) {
|
|
28446
|
+
let entries2;
|
|
28447
|
+
try {
|
|
28448
|
+
entries2 = fs18.readdirSync(dir, { withFileTypes: true });
|
|
28449
|
+
} catch {
|
|
28450
|
+
continue;
|
|
28451
|
+
}
|
|
28452
|
+
const hit = entries2.find((e) => e.isFile() && match(e.name));
|
|
28453
|
+
if (hit) hits.push(path25.join(dir, hit.name));
|
|
28454
|
+
else
|
|
28455
|
+
next.push(...entries2.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path25.join(dir, e.name)));
|
|
28456
|
+
if ((seen += entries2.length) > MAX_ENTRIES) return best(hits);
|
|
28457
|
+
}
|
|
28458
|
+
if (hits.length) return best(hits);
|
|
28459
|
+
queue = next;
|
|
28460
|
+
}
|
|
28461
|
+
return null;
|
|
28462
|
+
}
|
|
28463
|
+
|
|
28464
|
+
// src/guest/toolchains/tool-env.ts
|
|
28465
|
+
import path26 from "node:path";
|
|
28466
|
+
function emptyEnv() {
|
|
28467
|
+
return { vars: {}, prepend: [], append: [], summary: [] };
|
|
28468
|
+
}
|
|
28469
|
+
var arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
28470
|
+
function tool(...parts2) {
|
|
28471
|
+
return path26.join(toolsDir, ...parts2);
|
|
28472
|
+
}
|
|
28473
|
+
function versionOf(exe, args = ["--version"], options = {}) {
|
|
28474
|
+
return /\d+\.\d+\.\d+\S*/.exec(execOutput(exe, args, options))?.[0] ?? "installed";
|
|
28475
|
+
}
|
|
28476
|
+
|
|
28477
|
+
// src/guest/setup/agent-addons.ts
|
|
28478
|
+
function installedAddon(id) {
|
|
28479
|
+
const entry = appById(id);
|
|
28480
|
+
if (dryRun || !entry || !(session.apps?.install ?? []).includes(id)) return null;
|
|
28481
|
+
return findExe(tool("apps", id), entry.exe);
|
|
28482
|
+
}
|
|
28483
|
+
function installedRtk() {
|
|
28484
|
+
return installedAddon("rtk");
|
|
28485
|
+
}
|
|
28486
|
+
|
|
28487
|
+
// src/guest/boot/guide.ts
|
|
28286
28488
|
var BEGIN = "<!-- agent-sandbox:begin (generated every boot, do not edit) -->";
|
|
28287
28489
|
var END = "<!-- agent-sandbox:end -->";
|
|
28288
28490
|
var mirrorLine = () => {
|
|
28289
|
-
const drives = (session.substDrives ?? []).filter((d) =>
|
|
28491
|
+
const drives = (session.substDrives ?? []).filter((d) => fs19.existsSync(d.letter + ":\\"));
|
|
28290
28492
|
if (!drives.length) return [];
|
|
28291
28493
|
return [
|
|
28292
28494
|
"- " + 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)."
|
|
28293
28495
|
];
|
|
28294
28496
|
};
|
|
28295
|
-
function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
|
|
28497
|
+
function sandboxGuide(toolSummary, lan = "blocked", projects = [], addons = []) {
|
|
28296
28498
|
return [
|
|
28297
28499
|
BEGIN,
|
|
28298
28500
|
"## Sandbox manifest \u2014 you are in a DISPOSABLE Windows Sandbox",
|
|
@@ -28302,11 +28504,13 @@ function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
|
|
|
28302
28504
|
...projects.map(
|
|
28303
28505
|
(p) => "- RW, persists: `" + p.guest + "` = host folder " + p.host + " (another project in this sandbox; your own is `%AGENT_WORKSPACE%`)"
|
|
28304
28506
|
),
|
|
28305
|
-
"- RW, persists: `" + toolsDir + "` (toolchains) \u2014 put portable exes in `" +
|
|
28306
|
-
"- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" +
|
|
28507
|
+
"- RW, persists: `" + toolsDir + "` (toolchains) \u2014 put portable exes in `" + path27.join(toolsDir, "bin") + "` (on PATH)",
|
|
28508
|
+
"- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" + path27.join(dataDir, "logs") + "`",
|
|
28307
28509
|
"- RO: `" + launchDir + "` (this boot's scripts) \xB7 lost on close: everything else, incl. `C:\\nvm` (Node symlink)",
|
|
28308
28510
|
...mirrorLine(),
|
|
28309
28511
|
"- Tools: " + toolSummary.join(" \xB7 "),
|
|
28512
|
+
// Agent add-ons that change how the agent works (rtk, Headroom, MCP servers, ccusage).
|
|
28513
|
+
...addons,
|
|
28310
28514
|
"- 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).",
|
|
28311
28515
|
"- 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`).",
|
|
28312
28516
|
"- 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.",
|
|
@@ -28314,37 +28518,54 @@ function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
|
|
|
28314
28518
|
].join("\n");
|
|
28315
28519
|
}
|
|
28316
28520
|
function upsertGuide(file3, guide) {
|
|
28317
|
-
|
|
28318
|
-
const current =
|
|
28521
|
+
fs19.mkdirSync(path27.dirname(file3), { recursive: true });
|
|
28522
|
+
const current = fs19.existsSync(file3) ? fs19.readFileSync(file3, "utf8") : "";
|
|
28319
28523
|
const start = current.indexOf(BEGIN);
|
|
28320
28524
|
const end = current.indexOf(END);
|
|
28321
28525
|
const without = start >= 0 && end > start ? current.slice(0, start) + current.slice(end + END.length) : current;
|
|
28322
|
-
|
|
28526
|
+
fs19.writeFileSync(file3, without.trimEnd() + (without.trim() ? "\n\n" : "") + guide + "\n", "utf8");
|
|
28323
28527
|
}
|
|
28324
28528
|
function managedClaudeMd() {
|
|
28325
|
-
return
|
|
28326
|
-
process.env.AGENT_MANAGED_DIR ??
|
|
28529
|
+
return path27.join(
|
|
28530
|
+
process.env.AGENT_MANAGED_DIR ?? path27.join(process.env.ProgramFiles ?? "C:\\Program Files", "ClaudeCode"),
|
|
28327
28531
|
"CLAUDE.md"
|
|
28328
28532
|
);
|
|
28329
28533
|
}
|
|
28534
|
+
var headroomRuns = () => {
|
|
28535
|
+
try {
|
|
28536
|
+
const file3 = path27.join(path27.dirname(managedClaudeMd()), "managed-settings.json");
|
|
28537
|
+
const settings = JSON.parse(fs19.readFileSync(file3, "utf8"));
|
|
28538
|
+
return typeof settings.env?.ANTHROPIC_BASE_URL === "string";
|
|
28539
|
+
} catch {
|
|
28540
|
+
return false;
|
|
28541
|
+
}
|
|
28542
|
+
};
|
|
28543
|
+
function addonLines() {
|
|
28544
|
+
const mcp = APPS.flatMap((a) => a.mcp && installedAddon(a.id) ? [a.mcp.name] : []);
|
|
28545
|
+
return [
|
|
28546
|
+
...installedRtk() ? [RTK_GUIDE_LINE] : [],
|
|
28547
|
+
...installedAddon("headroom") && headroomRuns() ? [headroomGuideLine(path27.join(logsDir, "headroom.log"))] : [],
|
|
28548
|
+
...addonGuideLine(mcp, Boolean(installedAddon("ccusage")))
|
|
28549
|
+
];
|
|
28550
|
+
}
|
|
28330
28551
|
function writeGuides(toolSummary, lan, projects = []) {
|
|
28331
|
-
const guide = sandboxGuide(toolSummary, lan, projects);
|
|
28552
|
+
const guide = sandboxGuide(toolSummary, lan, projects, addonLines());
|
|
28332
28553
|
const managed = managedClaudeMd();
|
|
28333
|
-
|
|
28334
|
-
|
|
28335
|
-
|
|
28336
|
-
upsertGuide(
|
|
28337
|
-
upsertGuide(
|
|
28338
|
-
removeGuide(
|
|
28554
|
+
fs19.mkdirSync(path27.dirname(managed), { recursive: true });
|
|
28555
|
+
fs19.writeFileSync(managed, guide + "\n", "utf8");
|
|
28556
|
+
fs19.writeFileSync(path27.join(dataDir, "SANDBOX.md"), guide + "\n", "utf8");
|
|
28557
|
+
upsertGuide(path27.join(stateDir, "codex", "AGENTS.md"), guide);
|
|
28558
|
+
upsertGuide(path27.join(stateDir, "gemini", ".gemini", "GEMINI.md"), guide);
|
|
28559
|
+
removeGuide(path27.join(claudeDir, "CLAUDE.md"));
|
|
28339
28560
|
return managed;
|
|
28340
28561
|
}
|
|
28341
28562
|
var removeGuide = (file3) => {
|
|
28342
|
-
if (!
|
|
28343
|
-
const current =
|
|
28563
|
+
if (!fs19.existsSync(file3)) return;
|
|
28564
|
+
const current = fs19.readFileSync(file3, "utf8");
|
|
28344
28565
|
const start = current.indexOf(BEGIN);
|
|
28345
28566
|
const end = current.indexOf(END);
|
|
28346
28567
|
if (start >= 0 && end > start)
|
|
28347
|
-
|
|
28568
|
+
fs19.writeFileSync(file3, (current.slice(0, start) + current.slice(end + END.length)).trim() + "\n", "utf8");
|
|
28348
28569
|
};
|
|
28349
28570
|
|
|
28350
28571
|
// src/guest/runtime/project-context.ts
|
|
@@ -28381,11 +28602,11 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
|
|
|
28381
28602
|
}
|
|
28382
28603
|
|
|
28383
28604
|
// src/guest/setup/hooks.ts
|
|
28384
|
-
import
|
|
28385
|
-
import
|
|
28605
|
+
import fs20 from "node:fs";
|
|
28606
|
+
import path28 from "node:path";
|
|
28386
28607
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
28387
28608
|
var commandFor = (file3) => {
|
|
28388
|
-
const ext =
|
|
28609
|
+
const ext = path28.extname(file3).toLowerCase();
|
|
28389
28610
|
if (ext === ".mjs" || ext === ".js") return [process.execPath, [file3]];
|
|
28390
28611
|
if (!isWin) return null;
|
|
28391
28612
|
if (ext === ".ps1")
|
|
@@ -28393,18 +28614,18 @@ var commandFor = (file3) => {
|
|
|
28393
28614
|
if (ext === ".cmd" || ext === ".bat") return [SYSTEM.cmd(), ["/d", "/c", file3]];
|
|
28394
28615
|
return null;
|
|
28395
28616
|
};
|
|
28396
|
-
var BOOT = { root:
|
|
28617
|
+
var BOOT = { root: path28.join(launchDir, "hooks"), cwd: workspace };
|
|
28397
28618
|
function projectHooks(name, cwd) {
|
|
28398
28619
|
return {
|
|
28399
|
-
root:
|
|
28620
|
+
root: path28.join(launchDir, "projects", name, "hooks"),
|
|
28400
28621
|
cwd
|
|
28401
28622
|
};
|
|
28402
28623
|
}
|
|
28403
28624
|
var hooksOf = (stage, target) => {
|
|
28404
|
-
const dir =
|
|
28625
|
+
const dir = path28.join(target.root, stage);
|
|
28405
28626
|
if (!exists(dir)) return [];
|
|
28406
|
-
return
|
|
28407
|
-
const command = commandFor(
|
|
28627
|
+
return fs20.readdirSync(dir).sort().flatMap((name) => {
|
|
28628
|
+
const command = commandFor(path28.join(dir, name));
|
|
28408
28629
|
return command ? [{ name, command }] : [];
|
|
28409
28630
|
});
|
|
28410
28631
|
};
|
|
@@ -28433,26 +28654,109 @@ async function runHooksAsync(stage, env, target) {
|
|
|
28433
28654
|
}
|
|
28434
28655
|
}
|
|
28435
28656
|
|
|
28436
|
-
// src/guest/
|
|
28437
|
-
import
|
|
28438
|
-
|
|
28439
|
-
|
|
28440
|
-
|
|
28441
|
-
|
|
28442
|
-
|
|
28443
|
-
|
|
28657
|
+
// src/guest/apps/app-installer.ts
|
|
28658
|
+
import fs24 from "node:fs";
|
|
28659
|
+
import path33 from "node:path";
|
|
28660
|
+
|
|
28661
|
+
// src/guest/toolchains/runtimes.ts
|
|
28662
|
+
import path29 from "node:path";
|
|
28663
|
+
|
|
28664
|
+
// src/guest/toolchains/install.ts
|
|
28665
|
+
import fs21 from "node:fs";
|
|
28666
|
+
async function downloadFile(url2, file3, sha256 = null) {
|
|
28667
|
+
const part = file3 + ".part";
|
|
28668
|
+
try {
|
|
28669
|
+
await downloader.file(url2, part, sha256);
|
|
28670
|
+
fs21.rmSync(file3, { force: true });
|
|
28671
|
+
fs21.renameSync(part, file3);
|
|
28672
|
+
} finally {
|
|
28673
|
+
fs21.rmSync(part, { force: true });
|
|
28674
|
+
}
|
|
28444
28675
|
}
|
|
28445
|
-
function
|
|
28446
|
-
|
|
28676
|
+
async function installFromGithub(repo, pattern, o) {
|
|
28677
|
+
const asset = await githubAsset(repo, pattern, o.searchOlder);
|
|
28678
|
+
log("Downloading " + (typeof o.what === "string" ? o.what : o.what(asset)) + " ...");
|
|
28679
|
+
await downloader.archive(asset.url, o.dest, {
|
|
28680
|
+
sha256: asset.sha256,
|
|
28681
|
+
fileName: asset.name,
|
|
28682
|
+
...o.locate ? { locate: o.locate } : {},
|
|
28683
|
+
...o.up ? { up: o.up } : {}
|
|
28684
|
+
});
|
|
28447
28685
|
}
|
|
28448
28686
|
|
|
28449
|
-
// src/guest/
|
|
28450
|
-
|
|
28451
|
-
|
|
28687
|
+
// src/guest/toolchains/runtimes.ts
|
|
28688
|
+
async function setupSingleExe(env, name, repo, pattern, exeName, dir, options = {}) {
|
|
28689
|
+
if (dryRun) {
|
|
28690
|
+
log("(dry run) would provision " + name);
|
|
28691
|
+
return;
|
|
28692
|
+
}
|
|
28693
|
+
const bin = options.subdir ? path29.join(dir, options.subdir) : dir;
|
|
28694
|
+
const exe = path29.join(bin, exeName);
|
|
28695
|
+
if (!exists(exe) || options.refresh) {
|
|
28696
|
+
const size = options.size ? ", ~" + options.size : "";
|
|
28697
|
+
await installFromGithub(repo, pattern, {
|
|
28698
|
+
dest: dir,
|
|
28699
|
+
what: (a) => name + " (" + a.name + size + " once)",
|
|
28700
|
+
...options.subdir ? {} : { locate: exeName }
|
|
28701
|
+
});
|
|
28702
|
+
}
|
|
28703
|
+
if (!exists(exe)) throw new Error(exeName + " missing after installing " + name);
|
|
28704
|
+
env.prepend.push(bin);
|
|
28705
|
+
env.summary.push(name + ": " + versionOf(exe, options.versionArgs) + (options.note ?? ""));
|
|
28706
|
+
}
|
|
28707
|
+
async function setupBun(env) {
|
|
28708
|
+
await setupSingleExe(
|
|
28709
|
+
env,
|
|
28710
|
+
"bun",
|
|
28711
|
+
"oven-sh/bun",
|
|
28712
|
+
arch === "arm64" ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/,
|
|
28713
|
+
"bun.exe",
|
|
28714
|
+
tool("bun", "bin"),
|
|
28715
|
+
{ size: "35 MB" }
|
|
28716
|
+
);
|
|
28717
|
+
Object.assign(env.vars, {
|
|
28718
|
+
BUN_INSTALL: tool("bun"),
|
|
28719
|
+
BUN_INSTALL_CACHE_DIR: path29.join(localDir, "bun-cache"),
|
|
28720
|
+
BUN_TMPDIR: path29.join(localDir, "bun-tmp")
|
|
28721
|
+
});
|
|
28722
|
+
}
|
|
28723
|
+
async function setupDeno(env) {
|
|
28724
|
+
await setupSingleExe(
|
|
28725
|
+
env,
|
|
28726
|
+
"deno",
|
|
28727
|
+
"denoland/deno",
|
|
28728
|
+
arch === "arm64" ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/,
|
|
28729
|
+
"deno.exe",
|
|
28730
|
+
tool("deno", "bin"),
|
|
28731
|
+
{ size: "40 MB" }
|
|
28732
|
+
);
|
|
28733
|
+
Object.assign(env.vars, { DENO_DIR: tool("deno-cache"), DENO_INSTALL_ROOT: tool("deno"), DENO_NO_UPDATE_CHECK: "1" });
|
|
28734
|
+
}
|
|
28735
|
+
function uvVars() {
|
|
28736
|
+
return {
|
|
28737
|
+
UV_CACHE_DIR: tool("uv-cache"),
|
|
28738
|
+
UV_PYTHON_INSTALL_DIR: tool("uv-python"),
|
|
28739
|
+
UV_TOOL_DIR: tool("uv-tools"),
|
|
28740
|
+
UV_TOOL_BIN_DIR: tool("uv-bin")
|
|
28741
|
+
};
|
|
28742
|
+
}
|
|
28743
|
+
async function setupUv(env) {
|
|
28744
|
+
await setupSingleExe(
|
|
28745
|
+
env,
|
|
28746
|
+
"uv",
|
|
28747
|
+
"astral-sh/uv",
|
|
28748
|
+
arch === "arm64" ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/,
|
|
28749
|
+
"uv.exe",
|
|
28750
|
+
tool("uv"),
|
|
28751
|
+
{ size: "20 MB" }
|
|
28752
|
+
);
|
|
28753
|
+
Object.assign(env.vars, uvVars());
|
|
28754
|
+
env.prepend.push(mkdirp(tool("uv-bin")));
|
|
28755
|
+
}
|
|
28452
28756
|
|
|
28453
28757
|
// src/guest/apps/after-install.ts
|
|
28454
|
-
import
|
|
28455
|
-
import
|
|
28758
|
+
import fs22 from "node:fs";
|
|
28759
|
+
import path30 from "node:path";
|
|
28456
28760
|
var SYSINTERNALS_TOOLS = [
|
|
28457
28761
|
"Process Explorer",
|
|
28458
28762
|
"Process Monitor",
|
|
@@ -28473,16 +28777,16 @@ var SYSINTERNALS_TOOLS = [
|
|
|
28473
28777
|
"ZoomIt"
|
|
28474
28778
|
];
|
|
28475
28779
|
async function afterInstall(entry, exe) {
|
|
28476
|
-
const dir =
|
|
28780
|
+
const dir = path30.dirname(exe);
|
|
28477
28781
|
if (entry.needs?.includes("mesa")) {
|
|
28478
28782
|
const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
|
|
28479
28783
|
for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
|
|
28480
|
-
if (exists(
|
|
28481
|
-
|
|
28784
|
+
if (exists(path30.join(mesa, dll)) && !exists(path30.join(dir, dll)))
|
|
28785
|
+
fs22.copyFileSync(path30.join(mesa, dll), path30.join(dir, dll));
|
|
28482
28786
|
}
|
|
28483
28787
|
}
|
|
28484
|
-
if (entry.id === "godot" && !exists(
|
|
28485
|
-
if (entry.id === "sublime") mkdirp(
|
|
28788
|
+
if (entry.id === "godot" && !exists(path30.join(dir, "._sc_"))) fs22.writeFileSync(path30.join(dir, "._sc_"), "");
|
|
28789
|
+
if (entry.id === "sublime") mkdirp(path30.join(dir, "Data"));
|
|
28486
28790
|
if (entry.id === "sysinternals") {
|
|
28487
28791
|
for (const name of SYSINTERNALS_TOOLS) {
|
|
28488
28792
|
await execAsync(
|
|
@@ -28494,47 +28798,14 @@ async function afterInstall(entry, exe) {
|
|
|
28494
28798
|
}
|
|
28495
28799
|
}
|
|
28496
28800
|
|
|
28497
|
-
// src/guest/apps/find-exe.ts
|
|
28498
|
-
import fs21 from "node:fs";
|
|
28499
|
-
import path29 from "node:path";
|
|
28500
|
-
var MAX_DEPTH = 7;
|
|
28501
|
-
var MAX_ENTRIES = 5e4;
|
|
28502
|
-
var X64_FOLDER = /(^|[\\/])(amd64|x64|x86_64|win64)([\\/]|$)/i;
|
|
28503
|
-
function findExe(root, exe) {
|
|
28504
|
-
const match = exeMatcher(exe);
|
|
28505
|
-
const best = (hits) => hits.find((h) => X64_FOLDER.test(path29.relative(root, h))) ?? hits[0] ?? null;
|
|
28506
|
-
let queue = [root];
|
|
28507
|
-
let seen = 0;
|
|
28508
|
-
for (let depth = 0; depth < MAX_DEPTH && queue.length; depth++) {
|
|
28509
|
-
const next = [];
|
|
28510
|
-
const hits = [];
|
|
28511
|
-
for (const dir of queue) {
|
|
28512
|
-
let entries2;
|
|
28513
|
-
try {
|
|
28514
|
-
entries2 = fs21.readdirSync(dir, { withFileTypes: true });
|
|
28515
|
-
} catch {
|
|
28516
|
-
continue;
|
|
28517
|
-
}
|
|
28518
|
-
const hit = entries2.find((e) => e.isFile() && match(e.name));
|
|
28519
|
-
if (hit) hits.push(path29.join(dir, hit.name));
|
|
28520
|
-
else
|
|
28521
|
-
next.push(...entries2.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path29.join(dir, e.name)));
|
|
28522
|
-
if ((seen += entries2.length) > MAX_ENTRIES) return best(hits);
|
|
28523
|
-
}
|
|
28524
|
-
if (hits.length) return best(hits);
|
|
28525
|
-
queue = next;
|
|
28526
|
-
}
|
|
28527
|
-
return null;
|
|
28528
|
-
}
|
|
28529
|
-
|
|
28530
28801
|
// src/guest/apps/shortcuts.ts
|
|
28531
28802
|
import os5 from "node:os";
|
|
28532
|
-
import
|
|
28803
|
+
import path31 from "node:path";
|
|
28533
28804
|
function shortcuts(apps) {
|
|
28534
28805
|
if (!apps.length) return;
|
|
28535
|
-
const desktop =
|
|
28536
|
-
const start =
|
|
28537
|
-
process.env.APPDATA ??
|
|
28806
|
+
const desktop = path31.join(os5.homedir(), "Desktop");
|
|
28807
|
+
const start = path31.join(
|
|
28808
|
+
process.env.APPDATA ?? path31.join(os5.homedir(), "AppData", "Roaming"),
|
|
28538
28809
|
"Microsoft",
|
|
28539
28810
|
"Windows",
|
|
28540
28811
|
"Start Menu",
|
|
@@ -28544,9 +28815,9 @@ function shortcuts(apps) {
|
|
|
28544
28815
|
const links = apps.flatMap((app) => {
|
|
28545
28816
|
const name = app.name.replace(/[\\/:*?"<>|]/g, "");
|
|
28546
28817
|
return [desktop, start].map((folder) => ({
|
|
28547
|
-
link:
|
|
28818
|
+
link: path31.join(folder, name + ".lnk"),
|
|
28548
28819
|
target: app.exe,
|
|
28549
|
-
workingDirectory:
|
|
28820
|
+
workingDirectory: path31.dirname(app.exe)
|
|
28550
28821
|
}));
|
|
28551
28822
|
});
|
|
28552
28823
|
runScriptWithJson("new-shortcuts.ps1", "ListFile", links);
|
|
@@ -28671,19 +28942,19 @@ async function resolve(entry) {
|
|
|
28671
28942
|
}
|
|
28672
28943
|
if ("url" in s) {
|
|
28673
28944
|
const name = decodeURIComponent(new URL(s.url).pathname.split("/").pop() || entry.id);
|
|
28674
|
-
return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip" };
|
|
28945
|
+
return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip", sha256: s.sha256 };
|
|
28675
28946
|
}
|
|
28676
28947
|
if ("resolve" in s && RESOLVERS[s.resolve]) return RESOLVERS[s.resolve]();
|
|
28677
28948
|
throw new Error("no download source for " + entry.name);
|
|
28678
28949
|
}
|
|
28679
28950
|
|
|
28680
28951
|
// src/guest/apps/unpack.ts
|
|
28681
|
-
import
|
|
28682
|
-
import
|
|
28952
|
+
import fs23 from "node:fs";
|
|
28953
|
+
import path32 from "node:path";
|
|
28683
28954
|
var sevenZip = () => tool("apps", "7zip", "7z.exe");
|
|
28684
28955
|
async function unpack(entry, file3, out, d) {
|
|
28685
28956
|
if (entry.id === "7zip") {
|
|
28686
|
-
const sevenZr =
|
|
28957
|
+
const sevenZr = path32.join(path32.dirname(file3), "7zr.exe");
|
|
28687
28958
|
const zr = await githubAsset("ip7z/7zip", /^7zr\.exe$/);
|
|
28688
28959
|
await downloader.file(zr.url, sevenZr, zr.sha256);
|
|
28689
28960
|
await execAsync(sevenZr, ["x", "-y", "-o" + out, file3], { stdio: "ignore" });
|
|
@@ -28692,17 +28963,17 @@ async function unpack(entry, file3, out, d) {
|
|
|
28692
28963
|
switch (entry.unpack ?? "archive") {
|
|
28693
28964
|
case "file": {
|
|
28694
28965
|
mkdirp(out);
|
|
28695
|
-
|
|
28966
|
+
fs23.renameSync(file3, path32.join(out, /^\//.test(entry.exe) ? path32.basename(file3) : entry.exe));
|
|
28696
28967
|
return;
|
|
28697
28968
|
}
|
|
28698
28969
|
case "nsis": {
|
|
28699
28970
|
if (!exists(sevenZip()))
|
|
28700
28971
|
throw new Error("7-Zip is needed to unpack " + entry.name + " and could not be installed");
|
|
28701
|
-
const raw =
|
|
28972
|
+
const raw = path32.join(path32.dirname(out), "raw");
|
|
28702
28973
|
await execAsync(sevenZip(), ["x", "-y", "-o" + raw, file3], { stdio: "ignore" });
|
|
28703
28974
|
const inner = findExe(raw, "/^app-64\\.7z$/");
|
|
28704
28975
|
if (inner) await execAsync(sevenZip(), ["x", "-y", "-o" + out, inner], { stdio: "ignore" });
|
|
28705
|
-
else
|
|
28976
|
+
else fs23.renameSync(raw, out);
|
|
28706
28977
|
return;
|
|
28707
28978
|
}
|
|
28708
28979
|
case "msi": {
|
|
@@ -28752,12 +29023,12 @@ var AppInstaller = class {
|
|
|
28752
29023
|
async installOne(entry) {
|
|
28753
29024
|
try {
|
|
28754
29025
|
const dest = tool("apps", ...entry.id.split("/"));
|
|
28755
|
-
if (!exists(
|
|
29026
|
+
if (!exists(path33.join(dest, MARKER)) || this.options.refresh) await this.download(entry, dest);
|
|
28756
29027
|
const exe = findExe(dest, entry.exe);
|
|
28757
29028
|
if (!exe) throw new Error(entry.exe + " not found in the download");
|
|
28758
29029
|
await afterInstall(entry, exe);
|
|
28759
|
-
if (entry.cli || entry.id === "sysinternals") this.env.prepend.push(
|
|
28760
|
-
if (!entry.cli) this.gui.push({ name: entry.name, exe });
|
|
29030
|
+
if (!entry.service && (entry.cli || entry.id === "sysinternals")) this.env.prepend.push(path33.dirname(exe));
|
|
29031
|
+
if (!entry.cli && !entry.service) this.gui.push({ name: entry.name, exe });
|
|
28761
29032
|
this.installed.push(entry.name);
|
|
28762
29033
|
} catch (e) {
|
|
28763
29034
|
warn(
|
|
@@ -28769,10 +29040,13 @@ var AppInstaller = class {
|
|
|
28769
29040
|
/** Downloads and unpacks one entry into its folder (replaced in one step: never half there). */
|
|
28770
29041
|
async download(entry, dest) {
|
|
28771
29042
|
const work = stagingFolder(dest);
|
|
28772
|
-
const out =
|
|
29043
|
+
const out = path33.join(work, "out");
|
|
28773
29044
|
try {
|
|
28774
|
-
if ("
|
|
28775
|
-
|
|
29045
|
+
if ("locked" in entry.source) {
|
|
29046
|
+
log("Installing " + entry.name + " " + entry.source.version + " (pinned, every file checked) ...");
|
|
29047
|
+
await installLocked(entry.id, entry.source.locked, mkdirp(out));
|
|
29048
|
+
} else if ("npm" in entry.source) {
|
|
29049
|
+
const npmCli = path33.join(path33.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
28776
29050
|
log("Installing " + entry.name + " (npm) ...");
|
|
28777
29051
|
await execAsync(process.execPath, [
|
|
28778
29052
|
npmCli,
|
|
@@ -28787,17 +29061,60 @@ var AppInstaller = class {
|
|
|
28787
29061
|
} else {
|
|
28788
29062
|
const d = await resolve(entry);
|
|
28789
29063
|
log("Downloading " + entry.name + " (" + d.fileName + ", ~" + entry.size + " once) ...");
|
|
28790
|
-
const file3 =
|
|
29064
|
+
const file3 = path33.join(mkdirp(work), d.fileName.replace(/[\\/:*?"<>|]/g, "_"));
|
|
28791
29065
|
await downloader.file(d.url, file3, { sha256: d.sha256 ?? null });
|
|
28792
29066
|
await unpack(entry, file3, out, d);
|
|
28793
29067
|
}
|
|
28794
|
-
|
|
29068
|
+
fs24.writeFileSync(path33.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
28795
29069
|
moveIntoPlace(out, dest);
|
|
28796
29070
|
} finally {
|
|
28797
|
-
safeRemove(work,
|
|
29071
|
+
safeRemove(work, path33.dirname(work));
|
|
28798
29072
|
}
|
|
28799
29073
|
}
|
|
28800
29074
|
};
|
|
29075
|
+
var LOCKED_PYTHON = "3.13";
|
|
29076
|
+
async function installLocked(id, kind, out) {
|
|
29077
|
+
const lock = path33.join(launchDir, "sandbox", "addons", id);
|
|
29078
|
+
if (kind === "npm") {
|
|
29079
|
+
for (const f of ["package.json", "package-lock.json"]) fs24.copyFileSync(path33.join(lock, f), path33.join(out, f));
|
|
29080
|
+
const npmCli = path33.join(path33.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
29081
|
+
await execAsync(
|
|
29082
|
+
process.execPath,
|
|
29083
|
+
[npmCli, "ci", "--ignore-scripts", "--no-audit", "--no-fund", "--loglevel=error"],
|
|
29084
|
+
{ cwd: out }
|
|
29085
|
+
);
|
|
29086
|
+
return;
|
|
29087
|
+
}
|
|
29088
|
+
const uv = findExe(tool("uv"), "uv.exe");
|
|
29089
|
+
if (!uv) throw new Error("uv is not installed (the uv step failed)");
|
|
29090
|
+
const env = { ...process.env, ...uvVars() };
|
|
29091
|
+
const venv = path33.join(out, "venv");
|
|
29092
|
+
await execAsync(
|
|
29093
|
+
uv,
|
|
29094
|
+
["venv", "--relocatable", "--python", LOCKED_PYTHON, "--python-preference", "only-managed", venv],
|
|
29095
|
+
{
|
|
29096
|
+
env
|
|
29097
|
+
}
|
|
29098
|
+
);
|
|
29099
|
+
await execAsync(
|
|
29100
|
+
uv,
|
|
29101
|
+
[
|
|
29102
|
+
"pip",
|
|
29103
|
+
"install",
|
|
29104
|
+
"--python",
|
|
29105
|
+
path33.join(venv, "Scripts", "python.exe"),
|
|
29106
|
+
"--require-hashes",
|
|
29107
|
+
"--no-deps",
|
|
29108
|
+
"--only-binary",
|
|
29109
|
+
":all:",
|
|
29110
|
+
"--link-mode",
|
|
29111
|
+
"copy",
|
|
29112
|
+
"-r",
|
|
29113
|
+
path33.join(lock, "requirements.txt")
|
|
29114
|
+
],
|
|
29115
|
+
{ env }
|
|
29116
|
+
);
|
|
29117
|
+
}
|
|
28801
29118
|
async function setupApps(env, apps, o) {
|
|
28802
29119
|
const { entries: entries2, skipped } = appsToInstall(apps, o.gitAccess);
|
|
28803
29120
|
for (const s of skipped) env.summary.push("app skipped: " + s);
|
|
@@ -28809,8 +29126,8 @@ async function setupApps(env, apps, o) {
|
|
|
28809
29126
|
}
|
|
28810
29127
|
|
|
28811
29128
|
// src/guest/toolchains/detect.ts
|
|
28812
|
-
import
|
|
28813
|
-
import
|
|
29129
|
+
import fs25 from "node:fs";
|
|
29130
|
+
import path34 from "node:path";
|
|
28814
29131
|
|
|
28815
29132
|
// src/core/detect/versions.ts
|
|
28816
29133
|
function pickNodeVersion(releases, spec) {
|
|
@@ -28942,14 +29259,14 @@ function workspaceEntries() {
|
|
|
28942
29259
|
if (known) return known;
|
|
28943
29260
|
const list = (dir) => {
|
|
28944
29261
|
try {
|
|
28945
|
-
return
|
|
29262
|
+
return fs25.readdirSync(dir, { withFileTypes: true });
|
|
28946
29263
|
} catch {
|
|
28947
29264
|
return [];
|
|
28948
29265
|
}
|
|
28949
29266
|
};
|
|
28950
29267
|
const top = list(workspace2);
|
|
28951
29268
|
const below = top.filter((d) => d.isDirectory() && !d.name.startsWith(".") && !SKIP_DIRS.has(d.name.toLowerCase())).flatMap(
|
|
28952
|
-
(d) => list(
|
|
29269
|
+
(d) => list(path34.join(workspace2, d.name)).filter((f) => f.isFile()).map((f) => d.name + "/" + f.name)
|
|
28953
29270
|
);
|
|
28954
29271
|
const found = [...top.filter((d) => d.isFile()).map((d) => d.name), ...below];
|
|
28955
29272
|
entries.set(workspace2.toLowerCase(), found);
|
|
@@ -28960,9 +29277,9 @@ function wanted(setting, toolchain) {
|
|
|
28960
29277
|
}
|
|
28961
29278
|
function versionFromFiles(files, parse5 = (t) => specFromVersionFile(t)) {
|
|
28962
29279
|
for (const name of files) {
|
|
28963
|
-
const file3 =
|
|
29280
|
+
const file3 = path34.join(projectWorkspace(), name);
|
|
28964
29281
|
if (!exists(file3)) continue;
|
|
28965
|
-
const spec = parse5(
|
|
29282
|
+
const spec = parse5(fs25.readFileSync(file3, "utf8"), name);
|
|
28966
29283
|
if (spec) return { spec, source: name };
|
|
28967
29284
|
}
|
|
28968
29285
|
return null;
|
|
@@ -29035,22 +29352,22 @@ var DatabaseServer = class {
|
|
|
29035
29352
|
};
|
|
29036
29353
|
|
|
29037
29354
|
// src/guest/databases/dynamodb.ts
|
|
29038
|
-
import
|
|
29039
|
-
import
|
|
29355
|
+
import fs30 from "node:fs";
|
|
29356
|
+
import path37 from "node:path";
|
|
29040
29357
|
import { spawn as spawn3 } from "node:child_process";
|
|
29041
29358
|
|
|
29042
29359
|
// src/guest/toolchains/languages/java.ts
|
|
29043
|
-
import
|
|
29044
|
-
import
|
|
29360
|
+
import fs28 from "node:fs";
|
|
29361
|
+
import path35 from "node:path";
|
|
29045
29362
|
|
|
29046
29363
|
// src/guest/toolchains/version-cache.ts
|
|
29047
|
-
import
|
|
29364
|
+
import fs27 from "node:fs";
|
|
29048
29365
|
|
|
29049
29366
|
// src/guest/toolchains/state-file.ts
|
|
29050
|
-
import
|
|
29367
|
+
import fs26 from "node:fs";
|
|
29051
29368
|
function readState(file3, schema, empty) {
|
|
29052
29369
|
try {
|
|
29053
|
-
return schema.safeParse(JSON.parse(
|
|
29370
|
+
return schema.safeParse(JSON.parse(fs26.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""))).data ?? empty;
|
|
29054
29371
|
} catch {
|
|
29055
29372
|
return empty;
|
|
29056
29373
|
}
|
|
@@ -29085,7 +29402,7 @@ var VersionCache = class {
|
|
|
29085
29402
|
return cached2.value;
|
|
29086
29403
|
try {
|
|
29087
29404
|
const value = await resolve2();
|
|
29088
|
-
|
|
29405
|
+
fs27.mkdirSync(toolsDir, { recursive: true });
|
|
29089
29406
|
writeJsonAtomic(this.file(), { ...this.remembered(), [key2]: { value, at: Date.now() } });
|
|
29090
29407
|
return value;
|
|
29091
29408
|
} catch (e) {
|
|
@@ -29138,7 +29455,7 @@ var setupJdk = async (env, config2) => {
|
|
|
29138
29455
|
const { major, source } = await javaMajor(config2);
|
|
29139
29456
|
const release = await resolveCached("java:" + major, async () => (await temurin(major)).release_name);
|
|
29140
29457
|
const home = tool("java", release.replace(/[^A-Za-z0-9.-]/g, "_"));
|
|
29141
|
-
if (!exists(
|
|
29458
|
+
if (!exists(path35.join(home, "bin", "java.exe"))) {
|
|
29142
29459
|
const asset = await temurin(major);
|
|
29143
29460
|
log("Downloading Java " + release + " (JDK, ~200 MB once) ...");
|
|
29144
29461
|
await downloader.archive(asset.binary.package.link, home, {
|
|
@@ -29148,13 +29465,13 @@ var setupJdk = async (env, config2) => {
|
|
|
29148
29465
|
});
|
|
29149
29466
|
}
|
|
29150
29467
|
env.vars.JAVA_HOME = home;
|
|
29151
|
-
env.prepend.push(
|
|
29468
|
+
env.prepend.push(path35.join(home, "bin"));
|
|
29152
29469
|
env.summary.push("java: " + release + " (Temurin, from " + source + ")");
|
|
29153
29470
|
};
|
|
29154
29471
|
async function ensureJdk() {
|
|
29155
29472
|
const root = tool("java");
|
|
29156
|
-
const installed = exists(root) ?
|
|
29157
|
-
if (installed.length) return
|
|
29473
|
+
const installed = exists(root) ? fs28.readdirSync(root).filter((d) => exists(path35.join(root, d, "bin", "java.exe"))).sort((a, b) => b.localeCompare(a, void 0, { numeric: true })) : [];
|
|
29474
|
+
if (installed.length) return path35.join(root, installed[0]);
|
|
29158
29475
|
const scratch = emptyEnv();
|
|
29159
29476
|
await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false });
|
|
29160
29477
|
return scratch.vars.JAVA_HOME;
|
|
@@ -29167,7 +29484,7 @@ var setupMaven = async (env) => {
|
|
|
29167
29484
|
return pickPackageVersion(versions, "3") ?? Promise.reject(new Error("No Maven 3 release found"));
|
|
29168
29485
|
});
|
|
29169
29486
|
const home = tool("maven", version2);
|
|
29170
|
-
if (!exists(
|
|
29487
|
+
if (!exists(path35.join(home, "bin", "mvn.cmd"))) {
|
|
29171
29488
|
const url2 = MAVEN + version2 + "/apache-maven-" + version2 + "-bin.zip";
|
|
29172
29489
|
log("Downloading Maven " + version2 + " (~10 MB once) ...");
|
|
29173
29490
|
await downloader.archive(url2, home, {
|
|
@@ -29177,7 +29494,7 @@ var setupMaven = async (env) => {
|
|
|
29177
29494
|
}
|
|
29178
29495
|
const repo = tool("maven-repository");
|
|
29179
29496
|
Object.assign(env.vars, { MAVEN_HOME: home, M2_HOME: home, MAVEN_OPTS: "-Dmaven.repo.local=" + repo });
|
|
29180
|
-
env.prepend.push(
|
|
29497
|
+
env.prepend.push(path35.join(home, "bin"));
|
|
29181
29498
|
env.summary.push("maven: " + version2);
|
|
29182
29499
|
};
|
|
29183
29500
|
var setupGradle = async (env) => {
|
|
@@ -29189,7 +29506,7 @@ var setupGradle = async (env) => {
|
|
|
29189
29506
|
async () => current?.version ?? Promise.reject(new Error("Gradle version lookup failed"))
|
|
29190
29507
|
);
|
|
29191
29508
|
const home = tool("gradle", version2);
|
|
29192
|
-
if (!exists(
|
|
29509
|
+
if (!exists(path35.join(home, "bin", "gradle.bat"))) {
|
|
29193
29510
|
if (!current || current.version !== version2)
|
|
29194
29511
|
throw new Error("Gradle " + version2 + " is not installed and cannot be downloaded right now");
|
|
29195
29512
|
log("Downloading Gradle " + version2 + " (~130 MB once) ...");
|
|
@@ -29200,13 +29517,13 @@ var setupGradle = async (env) => {
|
|
|
29200
29517
|
});
|
|
29201
29518
|
}
|
|
29202
29519
|
const userHome = tool("gradle-home");
|
|
29203
|
-
|
|
29520
|
+
fs28.mkdirSync(userHome, { recursive: true });
|
|
29204
29521
|
Object.assign(env.vars, {
|
|
29205
29522
|
GRADLE_HOME: home,
|
|
29206
29523
|
GRADLE_USER_HOME: userHome,
|
|
29207
29524
|
GRADLE_OPTS: "-Dorg.gradle.vfs.watch=false"
|
|
29208
29525
|
});
|
|
29209
|
-
env.prepend.push(
|
|
29526
|
+
env.prepend.push(path35.join(home, "bin"));
|
|
29210
29527
|
env.summary.push("gradle: " + version2);
|
|
29211
29528
|
};
|
|
29212
29529
|
async function setupJava(env, config2) {
|
|
@@ -29230,29 +29547,29 @@ async function setupJava(env, config2) {
|
|
|
29230
29547
|
}
|
|
29231
29548
|
|
|
29232
29549
|
// src/guest/databases/server.ts
|
|
29233
|
-
import
|
|
29234
|
-
import
|
|
29550
|
+
import fs29 from "node:fs";
|
|
29551
|
+
import path36 from "node:path";
|
|
29235
29552
|
import { spawn as spawn2 } from "node:child_process";
|
|
29236
29553
|
function dataFor(name) {
|
|
29237
|
-
return
|
|
29554
|
+
return path36.join(dataDir, "databases", name);
|
|
29238
29555
|
}
|
|
29239
29556
|
async function startServer(name, exe, args, port) {
|
|
29240
29557
|
if (await portOpen(port)) throw new Error("port " + port + " is already in use (change databases." + name + ".port)");
|
|
29241
|
-
const logFile2 =
|
|
29242
|
-
const out =
|
|
29558
|
+
const logFile2 = path36.join(logsDir, name + ".log");
|
|
29559
|
+
const out = fs29.openSync(logFile2, "a");
|
|
29243
29560
|
spawn2(exe, args, { detached: true, stdio: ["ignore", out, out], windowsHide: true }).unref();
|
|
29244
|
-
|
|
29561
|
+
fs29.closeSync(out);
|
|
29245
29562
|
if (!await waitForPort(port, 60))
|
|
29246
29563
|
throw new Error(name + " did not start listening on port " + port + "; see " + logFile2);
|
|
29247
29564
|
}
|
|
29248
29565
|
async function clearStaleLocks(dir, files, port) {
|
|
29249
29566
|
if (await portOpen(port)) return;
|
|
29250
|
-
for (const f of files)
|
|
29567
|
+
for (const f of files) fs29.rmSync(path36.join(dir, f), { force: true });
|
|
29251
29568
|
}
|
|
29252
29569
|
async function createOnce(data, marker, create) {
|
|
29253
|
-
if (exists(
|
|
29570
|
+
if (exists(path36.join(data, marker))) return;
|
|
29254
29571
|
const existed = exists(data);
|
|
29255
|
-
mkdirp(
|
|
29572
|
+
mkdirp(path36.dirname(data));
|
|
29256
29573
|
try {
|
|
29257
29574
|
await create();
|
|
29258
29575
|
} catch (e) {
|
|
@@ -29276,9 +29593,9 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29276
29593
|
* local endpoint up from AWS_ENDPOINT_URL_DYNAMODB, with dummy credentials (real ones never reach the sandbox).
|
|
29277
29594
|
*/
|
|
29278
29595
|
async start(env, plan2) {
|
|
29279
|
-
const java =
|
|
29596
|
+
const java = path37.join(await ensureJdk(), "bin", "java.exe");
|
|
29280
29597
|
const home = tool("dynamodb-local");
|
|
29281
|
-
if (!exists(
|
|
29598
|
+
if (!exists(path37.join(home, "DynamoDBLocal.jar"))) {
|
|
29282
29599
|
log("Downloading DynamoDB Local (~60 MB once) ...");
|
|
29283
29600
|
const sha256 = (await fetchText(DYNAMO_ZIP + ".sha256")).trim().split(/\s+/)[0];
|
|
29284
29601
|
await downloader.archive(DYNAMO_ZIP, home, {
|
|
@@ -29292,9 +29609,9 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29292
29609
|
"dynamodb",
|
|
29293
29610
|
java,
|
|
29294
29611
|
[
|
|
29295
|
-
"-Djava.library.path=" +
|
|
29612
|
+
"-Djava.library.path=" + path37.join(home, "DynamoDBLocal_lib"),
|
|
29296
29613
|
"-jar",
|
|
29297
|
-
|
|
29614
|
+
path37.join(home, "DynamoDBLocal.jar"),
|
|
29298
29615
|
"-sharedDb",
|
|
29299
29616
|
"-dbPath",
|
|
29300
29617
|
data,
|
|
@@ -29318,10 +29635,10 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29318
29635
|
);
|
|
29319
29636
|
if (!plan2.adminPort) return;
|
|
29320
29637
|
const prefix = tool("dynamodb-admin");
|
|
29321
|
-
const script =
|
|
29638
|
+
const script = path37.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
|
|
29322
29639
|
if (!exists(script)) {
|
|
29323
29640
|
log("Installing dynamodb-admin, the DynamoDB web UI (~20 MB once) ...");
|
|
29324
|
-
const npmCli =
|
|
29641
|
+
const npmCli = path37.join(path37.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
29325
29642
|
await execAsync(
|
|
29326
29643
|
process.execPath,
|
|
29327
29644
|
[npmCli, "install", "--global", "--prefix", prefix, "dynamodb-admin", "--no-fund", "--no-audit"],
|
|
@@ -29334,15 +29651,15 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29334
29651
|
);
|
|
29335
29652
|
return;
|
|
29336
29653
|
}
|
|
29337
|
-
const out =
|
|
29654
|
+
const out = fs30.openSync(path37.join(logsDir, "dynamodb-admin.log"), "a");
|
|
29338
29655
|
spawn3(
|
|
29339
29656
|
process.execPath,
|
|
29340
29657
|
[script, "--port", String(plan2.adminPort), "--dynamo-endpoint", endpoint, "--skip-default-credentials"],
|
|
29341
29658
|
{ detached: true, stdio: ["ignore", out, out], windowsHide: true, env: { ...process.env, ...aws } }
|
|
29342
29659
|
).unref();
|
|
29343
|
-
|
|
29660
|
+
fs30.closeSync(out);
|
|
29344
29661
|
if (!await waitForPort(plan2.adminPort, 30))
|
|
29345
|
-
throw new Error("dynamodb-admin did not start; see " +
|
|
29662
|
+
throw new Error("dynamodb-admin did not start; see " + path37.join(logsDir, "dynamodb-admin.log"));
|
|
29346
29663
|
env.summary.push(
|
|
29347
29664
|
"dynamodb-admin: http://localhost:" + plan2.adminPort + " (browse and edit tables in the sandbox's browser)"
|
|
29348
29665
|
);
|
|
@@ -29350,32 +29667,7 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29350
29667
|
};
|
|
29351
29668
|
|
|
29352
29669
|
// src/guest/databases/mongodb.ts
|
|
29353
|
-
import
|
|
29354
|
-
|
|
29355
|
-
// src/guest/toolchains/install.ts
|
|
29356
|
-
import fs30 from "node:fs";
|
|
29357
|
-
async function downloadFile(url2, file3, sha256 = null) {
|
|
29358
|
-
const part = file3 + ".part";
|
|
29359
|
-
try {
|
|
29360
|
-
await downloader.file(url2, part, sha256);
|
|
29361
|
-
fs30.rmSync(file3, { force: true });
|
|
29362
|
-
fs30.renameSync(part, file3);
|
|
29363
|
-
} finally {
|
|
29364
|
-
fs30.rmSync(part, { force: true });
|
|
29365
|
-
}
|
|
29366
|
-
}
|
|
29367
|
-
async function installFromGithub(repo, pattern, o) {
|
|
29368
|
-
const asset = await githubAsset(repo, pattern, o.searchOlder);
|
|
29369
|
-
log("Downloading " + (typeof o.what === "string" ? o.what : o.what(asset)) + " ...");
|
|
29370
|
-
await downloader.archive(asset.url, o.dest, {
|
|
29371
|
-
sha256: asset.sha256,
|
|
29372
|
-
fileName: asset.name,
|
|
29373
|
-
...o.locate ? { locate: o.locate } : {},
|
|
29374
|
-
...o.up ? { up: o.up } : {}
|
|
29375
|
-
});
|
|
29376
|
-
}
|
|
29377
|
-
|
|
29378
|
-
// src/guest/databases/mongodb.ts
|
|
29670
|
+
import path38 from "node:path";
|
|
29379
29671
|
var MongoServer = class extends DatabaseServer {
|
|
29380
29672
|
id = "mongodb";
|
|
29381
29673
|
async start(env, plan2) {
|
|
@@ -29390,13 +29682,13 @@ var MongoServer = class extends DatabaseServer {
|
|
|
29390
29682
|
};
|
|
29391
29683
|
const version2 = await resolveCached("mongodb:" + plan2.version, async () => (await find()).version);
|
|
29392
29684
|
const home = tool("mongodb", version2);
|
|
29393
|
-
if (!exists(
|
|
29685
|
+
if (!exists(path38.join(home, "bin", "mongod.exe"))) {
|
|
29394
29686
|
const { archive } = await find();
|
|
29395
29687
|
log("Downloading MongoDB " + version2 + " (~400 MB once) ...");
|
|
29396
29688
|
await downloader.archive(archive.url, home, { sha256: archive.sha256, locate: "mongod.exe", up: 1 });
|
|
29397
29689
|
}
|
|
29398
29690
|
const shell = tool("mongosh");
|
|
29399
|
-
if (!exists(
|
|
29691
|
+
if (!exists(path38.join(shell, "mongosh.exe"))) {
|
|
29400
29692
|
await installFromGithub("mongodb-js/mongosh", /^mongosh-[\d.]+-win32-x64\.zip$/, {
|
|
29401
29693
|
dest: shell,
|
|
29402
29694
|
what: "mongosh, the MongoDB shell (~50 MB once)",
|
|
@@ -29407,17 +29699,17 @@ var MongoServer = class extends DatabaseServer {
|
|
|
29407
29699
|
await clearStaleLocks(data, ["mongod.lock"], plan2.port);
|
|
29408
29700
|
await startServer(
|
|
29409
29701
|
"mongodb",
|
|
29410
|
-
|
|
29702
|
+
path38.join(home, "bin", "mongod.exe"),
|
|
29411
29703
|
["--dbpath", data, "--bind_ip", "127.0.0.1", "--port", String(plan2.port)],
|
|
29412
29704
|
plan2.port
|
|
29413
29705
|
);
|
|
29414
|
-
env.prepend.push(
|
|
29706
|
+
env.prepend.push(path38.join(home, "bin"), shell);
|
|
29415
29707
|
env.summary.push("mongodb " + version2 + ": mongodb://127.0.0.1:" + plan2.port + " (mongosh on PATH)");
|
|
29416
29708
|
}
|
|
29417
29709
|
};
|
|
29418
29710
|
|
|
29419
29711
|
// src/guest/databases/mysql.ts
|
|
29420
|
-
import
|
|
29712
|
+
import path39 from "node:path";
|
|
29421
29713
|
var MARIA = "https://downloads.mariadb.org/rest-api/mariadb/";
|
|
29422
29714
|
var MysqlServer = class extends DatabaseServer {
|
|
29423
29715
|
id = "mysql";
|
|
@@ -29435,8 +29727,8 @@ var MysqlServer = class extends DatabaseServer {
|
|
|
29435
29727
|
};
|
|
29436
29728
|
const version2 = await resolveCached("mariadb-version:" + series, async () => (await latest()).version);
|
|
29437
29729
|
const home = tool("mariadb", version2);
|
|
29438
|
-
const bin =
|
|
29439
|
-
if (!exists(
|
|
29730
|
+
const bin = path39.join(home, "bin");
|
|
29731
|
+
if (!exists(path39.join(bin, "mariadbd.exe"))) {
|
|
29440
29732
|
const { zip } = await latest();
|
|
29441
29733
|
log("Downloading MariaDB " + version2 + " (~90 MB once) ...");
|
|
29442
29734
|
await downloader.archive(zip.file_download_url.replace(/^http:/, "https:"), home, {
|
|
@@ -29449,13 +29741,13 @@ var MysqlServer = class extends DatabaseServer {
|
|
|
29449
29741
|
const data = dataFor("mariadb");
|
|
29450
29742
|
await createOnce(data, "mysql", async () => {
|
|
29451
29743
|
log("Creating the MariaDB database (first start) ...");
|
|
29452
|
-
await execAsync(
|
|
29744
|
+
await execAsync(path39.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], {
|
|
29453
29745
|
stdio: "ignore"
|
|
29454
29746
|
});
|
|
29455
29747
|
});
|
|
29456
29748
|
await startServer(
|
|
29457
29749
|
"mysql",
|
|
29458
|
-
|
|
29750
|
+
path39.join(bin, "mariadbd.exe"),
|
|
29459
29751
|
["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"],
|
|
29460
29752
|
plan2.port
|
|
29461
29753
|
);
|
|
@@ -29469,7 +29761,7 @@ var MysqlServer = class extends DatabaseServer {
|
|
|
29469
29761
|
|
|
29470
29762
|
// src/guest/databases/postgres.ts
|
|
29471
29763
|
import fs31 from "node:fs";
|
|
29472
|
-
import
|
|
29764
|
+
import path40 from "node:path";
|
|
29473
29765
|
function postgresData(version2) {
|
|
29474
29766
|
return dataFor("postgres-" + version2.split(".")[0]);
|
|
29475
29767
|
}
|
|
@@ -29484,8 +29776,8 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29484
29776
|
return hit ? hit.major + "." + hit.latestMinor : Promise.reject(new Error("No supported PostgreSQL " + plan2.version));
|
|
29485
29777
|
});
|
|
29486
29778
|
const home = tool("postgres", exact);
|
|
29487
|
-
const bin =
|
|
29488
|
-
if (!exists(
|
|
29779
|
+
const bin = path40.join(home, "bin");
|
|
29780
|
+
if (!exists(path40.join(bin, "pg_ctl.exe"))) {
|
|
29489
29781
|
log("Downloading PostgreSQL " + exact + " (~330 MB once) ...");
|
|
29490
29782
|
await downloader.archive(
|
|
29491
29783
|
"https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip",
|
|
@@ -29502,7 +29794,7 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29502
29794
|
await createOnce(data, "PG_VERSION", async () => {
|
|
29503
29795
|
log("Creating the PostgreSQL database (first start) ...");
|
|
29504
29796
|
await execAsync(
|
|
29505
|
-
|
|
29797
|
+
path40.join(bin, "initdb.exe"),
|
|
29506
29798
|
["-D", data, "-U", "postgres", "-A", "trust", "-E", "UTF8", "--locale=C"],
|
|
29507
29799
|
{ stdio: "ignore" }
|
|
29508
29800
|
);
|
|
@@ -29511,7 +29803,7 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29511
29803
|
throw new Error("port " + plan2.port + " is already in use (change databases.postgres.port)");
|
|
29512
29804
|
await clearStaleLocks(data, ["postmaster.pid"], plan2.port);
|
|
29513
29805
|
await execAsync(
|
|
29514
|
-
|
|
29806
|
+
path40.join(bin, "pg_ctl.exe"),
|
|
29515
29807
|
[
|
|
29516
29808
|
"start",
|
|
29517
29809
|
"-D",
|
|
@@ -29520,7 +29812,7 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29520
29812
|
"-t",
|
|
29521
29813
|
"60",
|
|
29522
29814
|
"-l",
|
|
29523
|
-
|
|
29815
|
+
path40.join(logsDir, "postgres.log"),
|
|
29524
29816
|
"-o",
|
|
29525
29817
|
"-p " + plan2.port + " -c listen_addresses=localhost"
|
|
29526
29818
|
],
|
|
@@ -29537,8 +29829,8 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29537
29829
|
if (exists(tool("postgres"))) {
|
|
29538
29830
|
for (const version2 of fs31.readdirSync(tool("postgres"))) {
|
|
29539
29831
|
const data = postgresData(version2);
|
|
29540
|
-
const pgCtl =
|
|
29541
|
-
if (exists(
|
|
29832
|
+
const pgCtl = path40.join(tool("postgres", version2), "bin", "pg_ctl.exe");
|
|
29833
|
+
if (exists(path40.join(data, "postmaster.pid")) && exists(pgCtl))
|
|
29542
29834
|
await execAsync(pgCtl, ["stop", "-D", data, "-m", "fast", "-w"], { stdio: "ignore" });
|
|
29543
29835
|
}
|
|
29544
29836
|
}
|
|
@@ -29547,12 +29839,12 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29547
29839
|
};
|
|
29548
29840
|
|
|
29549
29841
|
// src/guest/databases/redis.ts
|
|
29550
|
-
import
|
|
29842
|
+
import path41 from "node:path";
|
|
29551
29843
|
var RedisServer = class extends DatabaseServer {
|
|
29552
29844
|
id = "redis";
|
|
29553
29845
|
async start(env, plan2) {
|
|
29554
29846
|
const home = tool("redis");
|
|
29555
|
-
if (!exists(
|
|
29847
|
+
if (!exists(path41.join(home, "redis-server.exe"))) {
|
|
29556
29848
|
await installFromGithub("redis-windows/redis-windows", /^Redis-[\d.]+-Windows-x64-msys2\.zip$/, {
|
|
29557
29849
|
dest: home,
|
|
29558
29850
|
what: (a) => "Redis (" + a.name + ", ~10 MB once)",
|
|
@@ -29562,7 +29854,7 @@ var RedisServer = class extends DatabaseServer {
|
|
|
29562
29854
|
const data = mkdirp(dataFor("redis"));
|
|
29563
29855
|
await startServer(
|
|
29564
29856
|
"redis",
|
|
29565
|
-
|
|
29857
|
+
path41.join(home, "redis-server.exe"),
|
|
29566
29858
|
["--port", String(plan2.port), "--bind", "127.0.0.1", "--dir", data.replace(/\\/g, "/"), "--appendonly", "yes"],
|
|
29567
29859
|
plan2.port
|
|
29568
29860
|
);
|
|
@@ -29601,15 +29893,15 @@ async function setupDatabase(env, plan2) {
|
|
|
29601
29893
|
|
|
29602
29894
|
// src/guest/toolchains/tools/git.ts
|
|
29603
29895
|
import fs33 from "node:fs";
|
|
29604
|
-
import
|
|
29896
|
+
import path43 from "node:path";
|
|
29605
29897
|
|
|
29606
29898
|
// src/guest/runtime/csc.ts
|
|
29607
29899
|
import fs32 from "node:fs";
|
|
29608
29900
|
import os6 from "node:os";
|
|
29609
|
-
import
|
|
29901
|
+
import path42 from "node:path";
|
|
29610
29902
|
import crypto3 from "node:crypto";
|
|
29611
29903
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
29612
|
-
var CSC =
|
|
29904
|
+
var CSC = path42.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
|
|
29613
29905
|
var SOURCES = {
|
|
29614
29906
|
ptyhost: "PtyHost.cs",
|
|
29615
29907
|
gitshim: "GitShim.cs",
|
|
@@ -29621,17 +29913,17 @@ var SOURCES = {
|
|
|
29621
29913
|
memgov: "MemGov.cs"
|
|
29622
29914
|
};
|
|
29623
29915
|
function sourceOf(name) {
|
|
29624
|
-
return
|
|
29916
|
+
return path42.join(launchDir, "sandbox", "csharp", SOURCES[name]);
|
|
29625
29917
|
}
|
|
29626
29918
|
function sourceHash(name) {
|
|
29627
29919
|
return crypto3.createHash("sha256").update(fs32.readFileSync(sourceOf(name))).digest("hex").slice(0, 12);
|
|
29628
29920
|
}
|
|
29629
29921
|
function ensureCompiled(name) {
|
|
29630
|
-
const exe =
|
|
29922
|
+
const exe = path42.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
|
|
29631
29923
|
if (exists(exe)) return exe;
|
|
29632
29924
|
if (!exists(CSC))
|
|
29633
29925
|
throw new Error("The .NET Framework C# compiler was not found at " + CSC + " (it ships with Windows 10/11).");
|
|
29634
|
-
mkdirp(
|
|
29926
|
+
mkdirp(path42.dirname(exe));
|
|
29635
29927
|
const result = spawnSync5(CSC, ["/nologo", "/optimize", "/target:exe", "/out:" + exe, sourceOf(name)], {
|
|
29636
29928
|
encoding: "utf8",
|
|
29637
29929
|
windowsHide: true
|
|
@@ -29670,18 +29962,18 @@ var installPortableGit = async (root) => {
|
|
|
29670
29962
|
};
|
|
29671
29963
|
var installGuard = (env, access, realGit) => {
|
|
29672
29964
|
const dir = mkdirp(tool("gitguard"));
|
|
29673
|
-
const guard =
|
|
29674
|
-
if (duringSession() && (exists(
|
|
29965
|
+
const guard = path43.join(launchDir, "runtime", "gitguard.js");
|
|
29966
|
+
if (duringSession() && (exists(path43.join(dir, "git.exe")) || exists(path43.join(dir, "git.cmd")))) {
|
|
29675
29967
|
} else
|
|
29676
29968
|
try {
|
|
29677
|
-
fs33.copyFileSync(ensureCompiled("gitshim"),
|
|
29678
|
-
fs33.rmSync(
|
|
29969
|
+
fs33.copyFileSync(ensureCompiled("gitshim"), path43.join(dir, "git.exe"));
|
|
29970
|
+
fs33.rmSync(path43.join(dir, "git.cmd"), { force: true });
|
|
29679
29971
|
} catch (e) {
|
|
29680
29972
|
warn("git guard: falling back to git.cmd (" + errMsg(e) + ")");
|
|
29681
|
-
fs33.writeFileSync(
|
|
29973
|
+
fs33.writeFileSync(path43.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
|
|
29682
29974
|
}
|
|
29683
29975
|
fs33.writeFileSync(
|
|
29684
|
-
|
|
29976
|
+
path43.join(dir, "bashenv.sh"),
|
|
29685
29977
|
'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n'
|
|
29686
29978
|
);
|
|
29687
29979
|
env.prepend.unshift(dir);
|
|
@@ -29690,13 +29982,13 @@ var installGuard = (env, access, realGit) => {
|
|
|
29690
29982
|
AGENT_REAL_GIT: access === "readonly" ? realGit : "",
|
|
29691
29983
|
AGENT_GUARD_NODE: process.execPath,
|
|
29692
29984
|
AGENT_GUARD_SCRIPT: guard,
|
|
29693
|
-
BASH_ENV: posix(
|
|
29985
|
+
BASH_ENV: posix(path43.join(dir, "bashenv.sh"))
|
|
29694
29986
|
});
|
|
29695
29987
|
if (access === "readonly") {
|
|
29696
|
-
const hooks = mkdirp(
|
|
29988
|
+
const hooks = mkdirp(path43.join(dir, "hooks"));
|
|
29697
29989
|
for (const hook of BLOCKED_HOOKS)
|
|
29698
29990
|
fs33.writeFileSync(
|
|
29699
|
-
|
|
29991
|
+
path43.join(hooks, hook),
|
|
29700
29992
|
'#!/bin/sh\necho "git is read-only in this sandbox: ' + hook + ' refused." >&2\nexit 1\n'
|
|
29701
29993
|
);
|
|
29702
29994
|
Object.assign(env.vars, {
|
|
@@ -29705,12 +29997,12 @@ var installGuard = (env, access, realGit) => {
|
|
|
29705
29997
|
GIT_CONFIG_VALUE_0: posix(hooks)
|
|
29706
29998
|
});
|
|
29707
29999
|
} else {
|
|
29708
|
-
env.vars.GIT_DIR =
|
|
30000
|
+
env.vars.GIT_DIR = path43.join(dataDir, "git-disabled");
|
|
29709
30001
|
}
|
|
29710
30002
|
};
|
|
29711
30003
|
var pointAtOwnCertificates = (root) => {
|
|
29712
|
-
const config2 =
|
|
29713
|
-
const bundle =
|
|
30004
|
+
const config2 = path43.join(root, "etc", "gitconfig");
|
|
30005
|
+
const bundle = path43.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
|
|
29714
30006
|
if (!exists(config2) || !exists(bundle)) return;
|
|
29715
30007
|
const text = fs33.readFileSync(config2, "utf8");
|
|
29716
30008
|
const fixed = text.replace(/^(\s*sslCAInfo\s*=\s*).*$/gim, (_m, key2) => key2 + posix(bundle));
|
|
@@ -29718,9 +30010,9 @@ var pointAtOwnCertificates = (root) => {
|
|
|
29718
30010
|
};
|
|
29719
30011
|
async function setupGit(env, hostCopy, refresh, access) {
|
|
29720
30012
|
const root = tool("git");
|
|
29721
|
-
const bash =
|
|
29722
|
-
const gitExe =
|
|
29723
|
-
const hostGit =
|
|
30013
|
+
const bash = path43.join(root, "bin", "bash.exe");
|
|
30014
|
+
const gitExe = path43.join(root, "cmd", "git.exe");
|
|
30015
|
+
const hostGit = path43.join(hostToolsDir, "git");
|
|
29724
30016
|
if (exists(root) && !exists(bash)) {
|
|
29725
30017
|
log("Replacing the old MinGit (no bash) with full Git for Windows.");
|
|
29726
30018
|
safeRemove(root, toolsDir);
|
|
@@ -29734,11 +30026,11 @@ async function setupGit(env, hostCopy, refresh, access) {
|
|
|
29734
30026
|
}
|
|
29735
30027
|
const work = stagingFolder(root);
|
|
29736
30028
|
try {
|
|
29737
|
-
if (hostCopy && exists(
|
|
30029
|
+
if (hostCopy && exists(path43.join(hostGit, "bin", "bash.exe"))) {
|
|
29738
30030
|
log("Copying Git for Windows from this PC ...");
|
|
29739
30031
|
robocopy(hostGit, work);
|
|
29740
30032
|
} else await installPortableGit(work);
|
|
29741
|
-
if (!exists(
|
|
30033
|
+
if (!exists(path43.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
|
|
29742
30034
|
moveIntoPlace(work, root);
|
|
29743
30035
|
} finally {
|
|
29744
30036
|
safeRemove(work, toolsDir);
|
|
@@ -29747,10 +30039,10 @@ async function setupGit(env, hostCopy, refresh, access) {
|
|
|
29747
30039
|
if (!exists(bash)) throw new Error("bash.exe missing after installing Git");
|
|
29748
30040
|
pointAtOwnCertificates(root);
|
|
29749
30041
|
env.vars.CLAUDE_CODE_GIT_BASH_PATH = bash;
|
|
29750
|
-
env.append.push(
|
|
30042
|
+
env.append.push(path43.join(root, "usr", "bin"));
|
|
29751
30043
|
const version2 = execOutput(gitExe, ["--version"]).replace(/^git version /, "");
|
|
29752
30044
|
if (access === "full") {
|
|
29753
|
-
env.prepend.push(
|
|
30045
|
+
env.prepend.push(path43.join(root, "cmd"));
|
|
29754
30046
|
env.summary.push("git: " + version2);
|
|
29755
30047
|
return;
|
|
29756
30048
|
}
|
|
@@ -29762,7 +30054,7 @@ async function setupGit(env, hostCopy, refresh, access) {
|
|
|
29762
30054
|
|
|
29763
30055
|
// src/guest/toolchains/languages/go.ts
|
|
29764
30056
|
import fs34 from "node:fs";
|
|
29765
|
-
import
|
|
30057
|
+
import path44 from "node:path";
|
|
29766
30058
|
|
|
29767
30059
|
// src/guest/toolchains/package-ledger.ts
|
|
29768
30060
|
var LedgerSchema = external_exports.record(external_exports.string(), external_exports.string());
|
|
@@ -29816,7 +30108,7 @@ async function setupGo(env, config2) {
|
|
|
29816
30108
|
}
|
|
29817
30109
|
const version2 = await resolveCached("go:" + config2.version, async () => (await findRelease(config2.version)).version);
|
|
29818
30110
|
const root = tool("go", version2);
|
|
29819
|
-
if (!exists(
|
|
30111
|
+
if (!exists(path44.join(root, "bin", "go.exe"))) {
|
|
29820
30112
|
const goArch = arch === "arm64" ? "arm64" : "amd64";
|
|
29821
30113
|
const file3 = (await findRelease(version2)).files.find(
|
|
29822
30114
|
(f) => f.os === "windows" && f.arch === goArch && f.kind === "archive"
|
|
@@ -29833,16 +30125,16 @@ async function setupGo(env, config2) {
|
|
|
29833
30125
|
const vars = {
|
|
29834
30126
|
GOROOT: root,
|
|
29835
30127
|
GOPATH,
|
|
29836
|
-
GOBIN:
|
|
29837
|
-
GOMODCACHE:
|
|
30128
|
+
GOBIN: path44.join(GOPATH, "bin"),
|
|
30129
|
+
GOMODCACHE: path44.join(GOPATH, "pkg", "mod"),
|
|
29838
30130
|
GOCACHE: tool("go-cache"),
|
|
29839
30131
|
GOTOOLCHAIN: "auto",
|
|
29840
30132
|
GOTELEMETRY: "off"
|
|
29841
30133
|
};
|
|
29842
30134
|
fs34.mkdirSync(vars.GOBIN, { recursive: true });
|
|
29843
30135
|
Object.assign(env.vars, vars);
|
|
29844
|
-
env.prepend.push(
|
|
29845
|
-
const go =
|
|
30136
|
+
env.prepend.push(path44.join(root, "bin"), vars.GOBIN);
|
|
30137
|
+
const go = path44.join(root, "bin", "go.exe");
|
|
29846
30138
|
env.summary.push("go: " + versionOf(go, ["version"]));
|
|
29847
30139
|
await installOnce(
|
|
29848
30140
|
env,
|
|
@@ -29900,77 +30192,6 @@ function decideCli(settings, ctx) {
|
|
|
29900
30192
|
return Object.fromEntries(CLI_NAMES.map((name) => [name, decide2(name)]));
|
|
29901
30193
|
}
|
|
29902
30194
|
|
|
29903
|
-
// src/guest/toolchains/runtimes.ts
|
|
29904
|
-
import path44 from "node:path";
|
|
29905
|
-
async function setupSingleExe(env, name, repo, pattern, exeName, dir, options = {}) {
|
|
29906
|
-
if (dryRun) {
|
|
29907
|
-
log("(dry run) would provision " + name);
|
|
29908
|
-
return;
|
|
29909
|
-
}
|
|
29910
|
-
const bin = options.subdir ? path44.join(dir, options.subdir) : dir;
|
|
29911
|
-
const exe = path44.join(bin, exeName);
|
|
29912
|
-
if (!exists(exe) || options.refresh) {
|
|
29913
|
-
const size = options.size ? ", ~" + options.size : "";
|
|
29914
|
-
await installFromGithub(repo, pattern, {
|
|
29915
|
-
dest: dir,
|
|
29916
|
-
what: (a) => name + " (" + a.name + size + " once)",
|
|
29917
|
-
...options.subdir ? {} : { locate: exeName }
|
|
29918
|
-
});
|
|
29919
|
-
}
|
|
29920
|
-
if (!exists(exe)) throw new Error(exeName + " missing after installing " + name);
|
|
29921
|
-
env.prepend.push(bin);
|
|
29922
|
-
env.summary.push(name + ": " + versionOf(exe, options.versionArgs) + (options.note ?? ""));
|
|
29923
|
-
}
|
|
29924
|
-
async function setupBun(env) {
|
|
29925
|
-
await setupSingleExe(
|
|
29926
|
-
env,
|
|
29927
|
-
"bun",
|
|
29928
|
-
"oven-sh/bun",
|
|
29929
|
-
arch === "arm64" ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/,
|
|
29930
|
-
"bun.exe",
|
|
29931
|
-
tool("bun", "bin"),
|
|
29932
|
-
{ size: "35 MB" }
|
|
29933
|
-
);
|
|
29934
|
-
Object.assign(env.vars, {
|
|
29935
|
-
BUN_INSTALL: tool("bun"),
|
|
29936
|
-
BUN_INSTALL_CACHE_DIR: path44.join(localDir, "bun-cache"),
|
|
29937
|
-
BUN_TMPDIR: path44.join(localDir, "bun-tmp")
|
|
29938
|
-
});
|
|
29939
|
-
}
|
|
29940
|
-
async function setupDeno(env) {
|
|
29941
|
-
await setupSingleExe(
|
|
29942
|
-
env,
|
|
29943
|
-
"deno",
|
|
29944
|
-
"denoland/deno",
|
|
29945
|
-
arch === "arm64" ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/,
|
|
29946
|
-
"deno.exe",
|
|
29947
|
-
tool("deno", "bin"),
|
|
29948
|
-
{ size: "40 MB" }
|
|
29949
|
-
);
|
|
29950
|
-
Object.assign(env.vars, { DENO_DIR: tool("deno-cache"), DENO_INSTALL_ROOT: tool("deno"), DENO_NO_UPDATE_CHECK: "1" });
|
|
29951
|
-
}
|
|
29952
|
-
function uvVars() {
|
|
29953
|
-
return {
|
|
29954
|
-
UV_CACHE_DIR: tool("uv-cache"),
|
|
29955
|
-
UV_PYTHON_INSTALL_DIR: tool("uv-python"),
|
|
29956
|
-
UV_TOOL_DIR: tool("uv-tools"),
|
|
29957
|
-
UV_TOOL_BIN_DIR: tool("uv-bin")
|
|
29958
|
-
};
|
|
29959
|
-
}
|
|
29960
|
-
async function setupUv(env) {
|
|
29961
|
-
await setupSingleExe(
|
|
29962
|
-
env,
|
|
29963
|
-
"uv",
|
|
29964
|
-
"astral-sh/uv",
|
|
29965
|
-
arch === "arm64" ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/,
|
|
29966
|
-
"uv.exe",
|
|
29967
|
-
tool("uv"),
|
|
29968
|
-
{ size: "20 MB" }
|
|
29969
|
-
);
|
|
29970
|
-
Object.assign(env.vars, uvVars());
|
|
29971
|
-
env.prepend.push(mkdirp(tool("uv-bin")));
|
|
29972
|
-
}
|
|
29973
|
-
|
|
29974
30195
|
// src/guest/toolchains/tools/cli.ts
|
|
29975
30196
|
function ghConfigDir() {
|
|
29976
30197
|
return path45.join(stateDir, "gh");
|
|
@@ -31610,7 +31831,12 @@ function plan(config2, versions, o) {
|
|
|
31610
31831
|
},
|
|
31611
31832
|
{ name: "Deno", enabled: wanted(config2.deno.enabled, "deno"), install: (env) => setupDeno(env) },
|
|
31612
31833
|
{ name: "Bun", enabled: wanted(config2.bun.enabled, "bun"), install: (env) => setupBun(env) },
|
|
31613
|
-
|
|
31834
|
+
// Headroom (an agent add-on) installs with uv: the uv step runs for it too, before the apps.
|
|
31835
|
+
{
|
|
31836
|
+
name: "uv",
|
|
31837
|
+
enabled: wanted(config2.uv.enabled, "uv") || appsNeedUv(o.apps),
|
|
31838
|
+
install: (env) => setupUv(env)
|
|
31839
|
+
},
|
|
31614
31840
|
{ name: "PowerShell 7", enabled: wanted(config2.pwsh.enabled, "pwsh"), install: (env) => setupPwsh(env, o.refresh) },
|
|
31615
31841
|
// The openssl tool comes from Git's install: after Git.
|
|
31616
31842
|
{
|
|
@@ -31636,7 +31862,7 @@ function plan(config2, versions, o) {
|
|
|
31636
31862
|
name: "Apps",
|
|
31637
31863
|
enabled: apps,
|
|
31638
31864
|
shared: true,
|
|
31639
|
-
after: ["Mesa 3D", "Visual C++ runtime"],
|
|
31865
|
+
after: ["Mesa 3D", "Visual C++ runtime", "uv"],
|
|
31640
31866
|
install: (env) => setupApps(env, o.apps, { gitAccess: o.gitAccess, refresh: o.refresh })
|
|
31641
31867
|
},
|
|
31642
31868
|
{
|
|
@@ -32330,6 +32556,7 @@ var IdleShutdown = class {
|
|
|
32330
32556
|
};
|
|
32331
32557
|
|
|
32332
32558
|
// src/guest/daemon/sessions.ts
|
|
32559
|
+
var ROOTS_KEPT_MS = 10 * 60 * 1e3;
|
|
32333
32560
|
function terminalTab(id, title, cwd) {
|
|
32334
32561
|
const view = [process.execPath, path68.join(path68.dirname(process.argv[1]), "view.js"), id];
|
|
32335
32562
|
const wt = path68.join(toolsDir, "terminal", "wt.exe");
|
|
@@ -32374,7 +32601,7 @@ function writeBudget(cpus, memoryGb, jobs, env) {
|
|
|
32374
32601
|
warn("budget.json could not be written: " + errMsg(e));
|
|
32375
32602
|
}
|
|
32376
32603
|
}
|
|
32377
|
-
var launchPtyHost = async (req, remote, env, say, sessions2) => {
|
|
32604
|
+
var launchPtyHost = async (req, remote, env, say, sessions2, onSpawn) => {
|
|
32378
32605
|
const harness = harnessFor(req);
|
|
32379
32606
|
say("Preparing " + req.harness);
|
|
32380
32607
|
await agents.provision(req.harness, harness, env, false);
|
|
@@ -32395,6 +32622,7 @@ var launchPtyHost = async (req, remote, env, say, sessions2) => {
|
|
|
32395
32622
|
command: commandLine(launch.file, [...base, ...req.args]),
|
|
32396
32623
|
restartCommand: commandLine(launch.file, [...base, ...harness.resumeArguments ?? []])
|
|
32397
32624
|
});
|
|
32625
|
+
onSpawn(child);
|
|
32398
32626
|
try {
|
|
32399
32627
|
await waitForPtyHost(child, port, 15e3);
|
|
32400
32628
|
} catch (e) {
|
|
@@ -32434,10 +32662,26 @@ var SessionManager = class {
|
|
|
32434
32662
|
/** Sessions and projects being set up right now (a headless sandbox must not shut down under them). */
|
|
32435
32663
|
starting = 0;
|
|
32436
32664
|
idle = new IdleShutdown(() => this.live.size > 0 || this.starting > 0);
|
|
32665
|
+
/** Each session's ptyhost (process id and when it ran), for linking the programs it starts to it (audit). */
|
|
32666
|
+
ptyHosts = /* @__PURE__ */ new Map();
|
|
32437
32667
|
/** How many sessions are running. */
|
|
32438
32668
|
get count() {
|
|
32439
32669
|
return this.live.size;
|
|
32440
32670
|
}
|
|
32671
|
+
/** The sessions' ptyhosts, running or ended within ROOTS_KEPT_MS (audit events arrive after they happen). */
|
|
32672
|
+
roots() {
|
|
32673
|
+
const cutoff = Date.now() - ROOTS_KEPT_MS;
|
|
32674
|
+
for (const [id, r] of this.ptyHosts) if (r.to !== void 0 && r.to < cutoff) this.ptyHosts.delete(id);
|
|
32675
|
+
return [...this.ptyHosts.values()];
|
|
32676
|
+
}
|
|
32677
|
+
rootStarted(id, child, from) {
|
|
32678
|
+
if (child.pid) this.ptyHosts.set(id, { session: id, pid: child.pid, from });
|
|
32679
|
+
child.once("exit", () => this.rootEnded(id));
|
|
32680
|
+
}
|
|
32681
|
+
rootEnded(id) {
|
|
32682
|
+
const r = this.ptyHosts.get(id);
|
|
32683
|
+
if (r && r.to === void 0) this.ptyHosts.set(id, { ...r, to: Date.now() });
|
|
32684
|
+
}
|
|
32441
32685
|
/** `session` requests: an agent in its own ptyhost, in the launch folder's project or a registered one. */
|
|
32442
32686
|
async start(req) {
|
|
32443
32687
|
let status = {
|
|
@@ -32462,7 +32706,15 @@ var SessionManager = class {
|
|
|
32462
32706
|
try {
|
|
32463
32707
|
const place = await placeFor(req, say);
|
|
32464
32708
|
const remote = session.networking && session.attach.enabled;
|
|
32465
|
-
const
|
|
32709
|
+
const from = Date.now();
|
|
32710
|
+
const { child, port, token } = await launchPtyHost(
|
|
32711
|
+
req,
|
|
32712
|
+
remote,
|
|
32713
|
+
place.env,
|
|
32714
|
+
say,
|
|
32715
|
+
this.live.size + 1,
|
|
32716
|
+
(c) => this.rootStarted(req.id, c, from)
|
|
32717
|
+
);
|
|
32466
32718
|
const resumed = req.harness === "claude" ? resumedConversation(req.args) : void 0;
|
|
32467
32719
|
const running = {
|
|
32468
32720
|
...status,
|
|
@@ -32480,6 +32732,7 @@ var SessionManager = class {
|
|
|
32480
32732
|
"Session " + req.id + " started (" + req.harness + " in " + req.cwd + ", project " + place.project + ", port " + port + ")"
|
|
32481
32733
|
);
|
|
32482
32734
|
} catch (e) {
|
|
32735
|
+
this.rootEnded(req.id);
|
|
32483
32736
|
saveStatus({ ...status, phase: "failed", message: errMsg(e) });
|
|
32484
32737
|
warn("Session " + req.id + " failed: " + errMsg(e));
|
|
32485
32738
|
this.idle.check();
|
|
@@ -33070,7 +33323,7 @@ process.on("unhandledRejection", (e) => warn("daemon: unexpected error (continui
|
|
|
33070
33323
|
adoptBootSecrets();
|
|
33071
33324
|
log("Session daemon started (pid " + process.pid + ").");
|
|
33072
33325
|
safely("port forwards", startRelays);
|
|
33073
|
-
safely("audit", startProcessCollector);
|
|
33326
|
+
safely("audit", () => startProcessCollector(() => sessions.roots()));
|
|
33074
33327
|
safely("memory governor", () => governor.start());
|
|
33075
33328
|
log("Memory governor: " + governor.describe());
|
|
33076
33329
|
new Daemon().start();
|