windows-development-sandbox 1.11.7 → 1.13.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 +13 -6
- package/config.example.json +15 -4
- package/dist/app/features/access/access.def.d.ts +190 -0
- package/dist/app/features/access/access.def.js +273 -0
- package/dist/app/features/access/access.run.d.ts +79 -0
- package/dist/app/features/access/access.run.js +129 -0
- package/dist/app/features/access/index.d.ts +2 -0
- package/dist/app/features/access/index.js +3 -0
- package/dist/app/features/agents/agent-entry.js +5 -0
- package/dist/app/features/agents/agents.def.js +1 -0
- 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 +50 -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 +350 -0
- package/dist/app/features/audit/audit.def.js +457 -0
- package/dist/app/features/audit/audit.run.d.ts +110 -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 +349 -4
- package/dist/app/features/defs.js +16 -1
- package/dist/app/features/files/files.def.js +1 -0
- package/dist/app/features/health/health.def.js +1 -0
- package/dist/app/features/sandbox/sandbox.def.js +3 -0
- package/dist/app/features/sessions/sessions.def.d.ts +36 -0
- package/dist/app/features/sessions/sessions.def.js +77 -9
- package/dist/app/features/sessions/sessions.run.d.ts +25 -2
- package/dist/app/features/sessions/sessions.run.js +71 -3
- package/dist/app/features/settings/settings.def.d.ts +8 -0
- package/dist/app/features/settings/settings.def.js +17 -0
- package/dist/app/features/settings/settings.run.d.ts +3 -0
- package/dist/app/features/settings/settings.run.js +16 -2
- package/dist/app/features/web/web.def.d.ts +9 -0
- package/dist/app/features/web/web.def.js +26 -1
- package/dist/app/features/web/web.run.d.ts +3 -0
- package/dist/app/features/web/web.run.js +11 -3
- package/dist/app/kernel/access.d.ts +33 -0
- package/dist/app/kernel/access.js +44 -0
- package/dist/app/kernel/define.d.ts +26 -2
- package/dist/app/kernel/index.d.ts +1 -0
- package/dist/app/kernel/index.js +1 -0
- package/dist/app/kernel/rpc.d.ts +5 -2
- package/dist/app/registry.d.ts +4 -1
- package/dist/app/registry.js +26 -4
- 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 +3 -2
- package/dist/cli/commands/remote.d.ts +2 -0
- package/dist/cli/commands/remote.js +49 -0
- package/dist/cli/commands/sessions/reopen.js +3 -0
- package/dist/cli/commands/web.js +66 -0
- package/dist/cli/manifest.d.ts +63 -45
- package/dist/cli/manifest.js +33 -18
- package/dist/cli/menu/io-menu.d.ts +5 -3
- package/dist/cli/menu/io-menu.js +12 -5
- 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/remote-menu.d.ts +19 -0
- package/dist/cli/menu/remote-menu.js +108 -0
- package/dist/cli/menu/views.js +4 -0
- package/dist/cli/operations/handler.js +15 -1
- package/dist/cli/services/remote-client.d.ts +16 -0
- package/dist/cli/services/remote-client.js +141 -0
- package/dist/cli/services/sessions-service.d.ts +5 -0
- package/dist/cli/services/sessions-service.js +17 -1
- package/dist/core/config/defaults.js +12 -2
- package/dist/core/local-config/file.js +16 -2
- package/dist/core/local-config/overrides.js +7 -0
- package/dist/core/run/versions.js +9 -8
- package/dist/core/schema/apps.d.ts +9 -0
- package/dist/core/schema/apps.js +9 -0
- package/dist/core/schema/config.d.ts +23 -3
- package/dist/core/schema/config.js +42 -5
- package/dist/core/schema/sandbox.d.ts +1 -0
- package/dist/core/schema/sandbox.js +11 -3
- package/dist/core/schema/web.d.ts +51 -0
- package/dist/core/schema/web.js +46 -1
- package/dist/core/util/fs.d.ts +5 -0
- package/dist/core/util/fs.js +23 -0
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- 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/daemon.js +2 -0
- package/dist/guest/daemon/idle-shutdown.js +2 -1
- package/dist/guest/daemon/sessions.d.ts +23 -2
- package/dist/guest/daemon/sessions.js +151 -20
- package/dist/guest/entries/daemon.js +2 -1
- package/dist/guest/git/decision.js +7 -0
- package/dist/guest/sessions/cmdline.d.ts +14 -0
- package/dist/guest/sessions/cmdline.js +10 -0
- 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/guest/toolchains/setup.js +3 -0
- 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 +45 -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/channel/channel.d.ts +5 -1
- package/dist/host/channel/channel.js +12 -0
- package/dist/host/guard/agent-files.js +7 -1
- package/dist/host/guard/commands.js +13 -1
- package/dist/host/guard/git-config.js +27 -7
- package/dist/host/guard/git-dirs.js +78 -3
- package/dist/host/guard/mark-of-the-web.js +3 -1
- package/dist/host/guard/nested-repos.js +7 -2
- package/dist/host/guard/store.js +1 -0
- package/dist/host/guard/types.d.ts +2 -0
- package/dist/host/launch/mappings.js +11 -1
- package/dist/host/launch/project-scan.js +2 -21
- package/dist/host/launch/stage.js +4 -0
- package/dist/host/life/session-ledger.js +2 -1
- package/dist/host/remote/access-store.d.ts +156 -0
- package/dist/host/remote/access-store.js +308 -0
- package/dist/host/remote/cert.d.ts +20 -0
- package/dist/host/remote/cert.js +103 -0
- package/dist/host/remote/door-client.d.ts +13 -0
- package/dist/host/remote/door-client.js +54 -0
- package/dist/host/remote/firewall.d.ts +44 -0
- package/dist/host/remote/firewall.js +118 -0
- package/dist/host/remote/gate.d.ts +125 -0
- package/dist/host/remote/gate.js +391 -0
- package/dist/host/remote/index.d.ts +8 -0
- package/dist/host/remote/index.js +10 -0
- package/dist/host/remote/lan.d.ts +24 -0
- package/dist/host/remote/lan.js +88 -0
- package/dist/host/remote/tls-store.d.ts +22 -0
- package/dist/host/remote/tls-store.js +63 -0
- package/dist/host/remote/windows-helper.d.ts +67 -0
- package/dist/host/remote/windows-helper.js +129 -0
- package/dist/host/web/bridge.d.ts +5 -1
- package/dist/host/web/bridge.js +6 -2
- package/dist/host/web/browser.js +1 -1
- package/dist/host/web/control.d.ts +4 -1
- package/dist/host/web/control.js +28 -4
- package/dist/host/web/rpc.d.ts +16 -2
- package/dist/host/web/rpc.js +37 -4
- package/dist/host/web/runner.d.ts +4 -0
- package/dist/host/web/runner.js +12 -0
- package/dist/host/web/server.d.ts +18 -2
- package/dist/host/web/server.js +97 -24
- package/dist/host/web/state.d.ts +5 -0
- package/dist/host/web/state.js +8 -0
- package/dist/runtime/agent.js +184 -18
- package/dist/runtime/daemon.js +772 -338
- package/dist/runtime/db.js +184 -18
- package/dist/runtime/gitguard.js +6 -0
- package/dist/runtime/main.js +966 -553
- package/dist/runtime/netproxy.js +184 -18
- package/dist/runtime/view.js +186 -18
- package/dist/selftest/app.test.js +66 -7
- package/dist/selftest/audit.test.js +354 -47
- package/dist/selftest/channel.test.js +16 -0
- package/dist/selftest/cmdline.test.js +16 -0
- package/dist/selftest/git-access.test.js +8 -0
- package/dist/selftest/hcs.test.js +35 -0
- package/dist/selftest/hostile-input.test.js +12 -1
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/live-daemon.test.js +25 -0
- package/dist/selftest/local-config.test.js +30 -0
- package/dist/selftest/menu-screens.js +1 -1
- package/dist/selftest/menu.test.js +3 -3
- package/dist/selftest/remote.test.d.ts +2 -0
- package/dist/selftest/remote.test.js +536 -0
- package/dist/selftest/repo-guard.test.js +56 -2
- package/dist/selftest/resume.test.js +2 -1
- package/dist/selftest/sharing.test.js +9 -2
- package/dist/selftest/support/engine-golden.js +9 -0
- package/dist/selftest/support/fixtures.d.ts +14 -0
- package/dist/selftest/support/web-preview.js +157 -0
- package/dist/selftest/toolchains.test.js +147 -2
- package/dist/selftest/web.test.js +2 -0
- 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/shared/channel/schema.d.ts +23 -0
- package/dist/shared/channel/schema.js +8 -0
- package/dist/shared/pty/protocol.d.ts +2 -0
- package/dist/shared/pty/protocol.js +2 -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-Z2WYAE2Z.js +221 -0
- 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/native/csharp/HostTools/Program.cs +17 -1
- package/native/csharp/HostTools/WebHelper.cs +499 -0
- package/native/scripts/get-network-profile.ps1 +19 -0
- package/native/scripts/set-folder-access.ps1 +11 -0
- package/native/scripts/set-web-firewall.ps1 +103 -0
- 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/sandbox/csharp/PtyHost.cs +20 -0
- package/schemas/config.schema.json +78 -4
- package/schemas/sandbox-config.schema.json +2 -20
- package/dist/cli/commands/maintenance/audit.d.ts +0 -3
- package/dist/cli/commands/maintenance/audit.js +0 -58
- package/dist/web/main-K2JMCAZI.js +0 -219
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."
|
|
@@ -26624,12 +26743,39 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26624
26743
|
});
|
|
26625
26744
|
|
|
26626
26745
|
// src/core/schema/web.ts
|
|
26746
|
+
var REMOTE_ROLES = ["view", "control"];
|
|
26747
|
+
var WindowsUserNameSchema = external_exports.string().trim().min(1).max(120).regex(
|
|
26748
|
+
/^(?:[A-Za-z0-9][A-Za-z0-9._ -]{0,62}\\)?[^\\/"[\]:;|=,+*?<>@]{1,64}$/,
|
|
26749
|
+
"a Windows user name (name or DOMAIN\\name)"
|
|
26750
|
+
);
|
|
26751
|
+
var RemoteUserSchema = external_exports.strictObject({
|
|
26752
|
+
name: WindowsUserNameSchema.describe("The Windows user (name, or DOMAIN\\name)"),
|
|
26753
|
+
role: external_exports.enum(REMOTE_ROLES).describe("view: sees everything, terminals read-only. control: everything but remote access, logins and tokens.")
|
|
26754
|
+
});
|
|
26755
|
+
var WebLanSchema = external_exports.strictObject({
|
|
26756
|
+
enabled: external_exports.boolean().describe(
|
|
26757
|
+
"(Beta) Devices on your network (a phone): an HTTPS address on this PC for devices you pair with a one-time code (sandbox web pair). Needs a firewall rule (sandbox web lan on asks Windows once). Off: every paired device is signed out."
|
|
26758
|
+
),
|
|
26759
|
+
port: external_exports.number().int().min(1024).max(65535).describe("HTTPS port for paired devices on your network."),
|
|
26760
|
+
address: external_exports.string().trim().max(15).regex(/^$|^\d{1,3}(\.\d{1,3}){3}$/, "an IPv4 address or empty").describe("This PC's private address to listen on. Empty: the one of its network adapter (never a public one).")
|
|
26761
|
+
});
|
|
26762
|
+
var WebRemoteSchema = external_exports.strictObject({
|
|
26763
|
+
windowsSignIn: external_exports.boolean().describe(
|
|
26764
|
+
"(Beta) Other Windows users of this PC named in web.remote.users sign in to your web UI (and sandbox remote) with their own Windows account: no password, no link."
|
|
26765
|
+
),
|
|
26766
|
+
users: external_exports.array(RemoteUserSchema).max(32).describe("Who else may sign in with Windows, and their role (view or control)."),
|
|
26767
|
+
rememberDays: external_exports.number().int().min(1).max(90).describe(
|
|
26768
|
+
"How many days a paired device or a Windows sign-in stays signed in (from when it signed in, not renewed)."
|
|
26769
|
+
),
|
|
26770
|
+
lan: WebLanSchema
|
|
26771
|
+
});
|
|
26627
26772
|
var WebSchema = external_exports.strictObject({
|
|
26628
26773
|
enabled: external_exports.boolean().describe(
|
|
26629
26774
|
"(Beta) The web UI: your sandbox sessions in a browser on this PC (http://127.0.0.1:<port>, this PC only). On: every sandbox start also starts it in the background (it keeps running until sandbox web stop or a restart of the PC). Off: only sandbox web start runs it. Open it signed in with sandbox web open."
|
|
26630
26775
|
),
|
|
26631
26776
|
port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken."),
|
|
26632
|
-
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts.")
|
|
26777
|
+
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts."),
|
|
26778
|
+
remote: WebRemoteSchema.describe("(Beta) Access for other Windows users of this PC and for paired devices.")
|
|
26633
26779
|
});
|
|
26634
26780
|
|
|
26635
26781
|
// src/core/schema/vpn.ts
|
|
@@ -26659,6 +26805,36 @@ var GithubSchema = external_exports.strictObject({
|
|
|
26659
26805
|
});
|
|
26660
26806
|
|
|
26661
26807
|
// src/core/schema/config.ts
|
|
26808
|
+
var RESERVED_ENV_PREFIX = /^(AGENT_|GIT_|GH_|GITHUB_|NODE_|NPM_CONFIG_(USERCONFIG|GLOBALCONFIG|PREFIX|SCRIPT_SHELL)|SSL_|CLAUDE|ANTHROPIC_|OPENAI_|CODEX_|GEMINI_|GOOGLE_|COPILOT_|AWS_|AZURE_)/i;
|
|
26809
|
+
var RESERVED_ENV_SUFFIX = /(_PROXY|_BASE_URL|_ENDPOINT|_CA_BUNDLE|_CA_CERTS)$/i;
|
|
26810
|
+
var RESERVED_ENV_NAMES = new Set(
|
|
26811
|
+
[
|
|
26812
|
+
"PATH",
|
|
26813
|
+
"PATHEXT",
|
|
26814
|
+
"BASH_ENV",
|
|
26815
|
+
"ENV",
|
|
26816
|
+
"COMSPEC",
|
|
26817
|
+
"PSMODULEPATH",
|
|
26818
|
+
"PYTHONPATH",
|
|
26819
|
+
"PYTHONSTARTUP",
|
|
26820
|
+
"PERL5OPT",
|
|
26821
|
+
"RUBYOPT",
|
|
26822
|
+
"JAVA_TOOL_OPTIONS",
|
|
26823
|
+
"LD_PRELOAD",
|
|
26824
|
+
"SYSTEMROOT",
|
|
26825
|
+
"WINDIR",
|
|
26826
|
+
"HOME",
|
|
26827
|
+
"USERPROFILE",
|
|
26828
|
+
"APPDATA",
|
|
26829
|
+
"LOCALAPPDATA",
|
|
26830
|
+
"PROGRAMDATA",
|
|
26831
|
+
"TEMP",
|
|
26832
|
+
"TMP"
|
|
26833
|
+
].map((n) => n.toUpperCase())
|
|
26834
|
+
);
|
|
26835
|
+
function reservedEnvName(name) {
|
|
26836
|
+
return RESERVED_ENV_PREFIX.test(name) || RESERVED_ENV_SUFFIX.test(name) || RESERVED_ENV_NAMES.has(name.toUpperCase());
|
|
26837
|
+
}
|
|
26662
26838
|
var ConfigSchema = external_exports.strictObject({
|
|
26663
26839
|
$schema: SchemaRefSchema.optional(),
|
|
26664
26840
|
defaultHarness: NameSchema.describe("Agent started by `sandbox launch` (sandbox claude always runs claude)."),
|
|
@@ -26725,10 +26901,14 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26725
26901
|
scripts: StringsSchema.describe(
|
|
26726
26902
|
"Scripts (.ps1 / .mjs / .cmd, relative to this file) run inside the sandbox before the agent."
|
|
26727
26903
|
),
|
|
26728
|
-
// This PC's resources are yours to share: CPU
|
|
26904
|
+
// This PC's resources are yours to share: CPU, paging file (this PC's disk) and the RAM kept for this PC are not a
|
|
26905
|
+
// project's to set.
|
|
26729
26906
|
sandbox: SandboxSchema.omit({
|
|
26730
26907
|
cpuLimit: true,
|
|
26731
26908
|
pageFileMb: true,
|
|
26909
|
+
reserveHostMb: true,
|
|
26910
|
+
maxMemoryPercent: true,
|
|
26911
|
+
maxMemoryMb: true,
|
|
26732
26912
|
engine: true,
|
|
26733
26913
|
agentMemoryHeadroomMb: true,
|
|
26734
26914
|
pressureResponse: true
|
|
@@ -26742,14 +26922,17 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26742
26922
|
// Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
|
|
26743
26923
|
toolchains: external_exports.strictObject({
|
|
26744
26924
|
...import_lodash.default.mapValues(import_lodash.default.omit(ToolchainsSchema.shape, "environment"), (shape) => shape.partial()),
|
|
26745
|
-
environment: ToolchainsSchema.shape.environment
|
|
26925
|
+
environment: ToolchainsSchema.shape.environment.refine(
|
|
26926
|
+
(env) => !Object.keys(env).some(reservedEnvName),
|
|
26927
|
+
"names the sandbox sets or that carry logins (AGENT_*, GIT_*, PATH, BASH_ENV, NODE_*, proxies, ANTHROPIC_*, CLAUDE_* ...) cannot be set by a project"
|
|
26928
|
+
)
|
|
26746
26929
|
}).partial(),
|
|
26747
26930
|
databases: external_exports.strictObject(import_lodash.default.mapValues(DatabasesSchema.shape, (shape) => shape.partial())).partial(),
|
|
26748
26931
|
attach: AttachSchema.partial(),
|
|
26749
26932
|
personalization: toggle("Copy your desktop look into the sandbox.").partial(),
|
|
26750
26933
|
// Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add
|
|
26751
|
-
// them.
|
|
26752
|
-
apps:
|
|
26934
|
+
// them, nor agent add-ons that are yours only (rtk hooks every agent command, Headroom sits in its API path).
|
|
26935
|
+
apps: ProjectAppsSchema.partial(),
|
|
26753
26936
|
claudeProfile: ClaudeProfileSchema.pick({
|
|
26754
26937
|
enabled: true,
|
|
26755
26938
|
overwrite: true,
|
|
@@ -26812,6 +26995,7 @@ var ProjectSpecSchema = external_exports.strictObject({
|
|
|
26812
26995
|
/** Its hooks were staged in C:\AgentLaunch\projects\<name>\hooks. */
|
|
26813
26996
|
hooks: external_exports.boolean()
|
|
26814
26997
|
});
|
|
26998
|
+
var ShellChoiceSchema = external_exports.enum(["auto", "pwsh", "powershell", "cmd"]);
|
|
26815
26999
|
var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
26816
27000
|
external_exports.strictObject({
|
|
26817
27001
|
kind: external_exports.literal("session"),
|
|
@@ -26821,8 +27005,12 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
26821
27005
|
cwd: Text(),
|
|
26822
27006
|
project: ProjectSpecSchema.optional(),
|
|
26823
27007
|
harnessSpec: HarnessSchema.optional(),
|
|
27008
|
+
/** A plain shell instead of an agent (harness is then "shell" and args are ignored). */
|
|
27009
|
+
shell: ShellChoiceSchema.optional(),
|
|
26824
27010
|
createdAt: TimeSchema
|
|
26825
27011
|
}),
|
|
27012
|
+
/** End a running session (an agent or a shell) and everything it started. */
|
|
27013
|
+
external_exports.strictObject({ kind: external_exports.literal("close"), id: IdSchema, session: IdSchema, createdAt: TimeSchema }),
|
|
26826
27014
|
/** Provision a registered project without starting an agent (sandbox start / exec / db from its folder). */
|
|
26827
27015
|
external_exports.strictObject({ kind: external_exports.literal("project"), id: IdSchema, project: ProjectSpecSchema, createdAt: TimeSchema }),
|
|
26828
27016
|
external_exports.strictObject({
|
|
@@ -26888,6 +27076,8 @@ var SessionStatusSchema = external_exports.object({
|
|
|
26888
27076
|
id: IdSchema,
|
|
26889
27077
|
launchId: Text(64),
|
|
26890
27078
|
harness: Text(64),
|
|
27079
|
+
/** A plain shell (harness is then the shell: pwsh, powershell or cmd); absent: an agent. */
|
|
27080
|
+
kind: external_exports.enum(["agent", "shell"]).optional(),
|
|
26891
27081
|
cwd: Text(),
|
|
26892
27082
|
/** The project it runs in: its hub name, or the launch folder's for the first project. */
|
|
26893
27083
|
project: Text(64).optional(),
|
|
@@ -27599,9 +27789,29 @@ var NOISE = /* @__PURE__ */ new Set([
|
|
|
27599
27789
|
"usoclient.exe",
|
|
27600
27790
|
"musnotification.exe"
|
|
27601
27791
|
]);
|
|
27792
|
+
var ROOT_SLACK_MS = 5e3;
|
|
27793
|
+
var MAX_KNOWN = 5e4;
|
|
27794
|
+
var Attributor = class {
|
|
27795
|
+
owner = /* @__PURE__ */ new Map();
|
|
27796
|
+
/** The session of a new process (pid, started by ppid at time t), or undefined. */
|
|
27797
|
+
attribute(e, roots) {
|
|
27798
|
+
const root = roots.find(
|
|
27799
|
+
(r) => r.pid === e.ppid && e.t >= r.from - ROOT_SLACK_MS && (r.to === void 0 || e.t <= r.to + ROOT_SLACK_MS)
|
|
27800
|
+
);
|
|
27801
|
+
const session2 = root?.session ?? this.owner.get(e.ppid) ?? void 0;
|
|
27802
|
+
this.owner.delete(e.pid);
|
|
27803
|
+
this.owner.set(e.pid, session2 ?? null);
|
|
27804
|
+
if (this.owner.size > MAX_KNOWN) this.owner.delete(this.owner.keys().next().value);
|
|
27805
|
+
return session2;
|
|
27806
|
+
}
|
|
27807
|
+
};
|
|
27602
27808
|
var decode3 = (s) => s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
27603
27809
|
var field = (event, name) => decode3(new RegExp("<Data Name='" + name + "'>([^<]*)</Data>").exec(event)?.[1] ?? "");
|
|
27604
|
-
|
|
27810
|
+
var pidOf = (text) => {
|
|
27811
|
+
const n = /^0x[0-9a-f]{1,8}$/i.test(text) ? parseInt(text, 16) : /^\d{1,10}$/.test(text) ? Number(text) : 0;
|
|
27812
|
+
return Number.isSafeInteger(n) ? n : 0;
|
|
27813
|
+
};
|
|
27814
|
+
function parseProcessEvents(xml, attribution) {
|
|
27605
27815
|
const lines = [];
|
|
27606
27816
|
let last = 0;
|
|
27607
27817
|
for (const event of xml.split("</Event>")) {
|
|
@@ -27609,15 +27819,19 @@ function parseProcessEvents(xml) {
|
|
|
27609
27819
|
if (!id) continue;
|
|
27610
27820
|
last = Math.max(last, id);
|
|
27611
27821
|
const program = field(event, "NewProcessName");
|
|
27612
|
-
if (!program || NOISE.has(path15.win32.basename(program).toLowerCase())) continue;
|
|
27613
27822
|
const t = /SystemTime='([^']+)'/.exec(event)?.[1] ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
27823
|
+
const pid = pidOf(field(event, "NewProcessId"));
|
|
27824
|
+
const ppid = pidOf(field(event, "ProcessId"));
|
|
27825
|
+
const session2 = attribution && pid && ppid ? attribution.attributor.attribute({ pid, ppid, t: Date.parse(t) || Date.now() }, attribution.roots) : void 0;
|
|
27826
|
+
if (!program || NOISE.has(path15.win32.basename(program).toLowerCase())) continue;
|
|
27614
27827
|
lines.push(
|
|
27615
27828
|
JSON.stringify({
|
|
27616
27829
|
t,
|
|
27617
27830
|
k: "proc",
|
|
27618
27831
|
p: program.slice(0, 1024),
|
|
27619
27832
|
c: field(event, "CommandLine").slice(0, 2e3),
|
|
27620
|
-
pp: field(event, "ParentProcessName").slice(0, 1024)
|
|
27833
|
+
pp: field(event, "ParentProcessName").slice(0, 1024),
|
|
27834
|
+
...session2 ? { s: session2 } : {}
|
|
27621
27835
|
})
|
|
27622
27836
|
);
|
|
27623
27837
|
}
|
|
@@ -27645,9 +27859,10 @@ var newestRecord = () => {
|
|
|
27645
27859
|
});
|
|
27646
27860
|
return parseProcessEvents(r.stdout ?? "").last;
|
|
27647
27861
|
};
|
|
27648
|
-
function startProcessCollector() {
|
|
27862
|
+
function startProcessCollector(roots = () => []) {
|
|
27649
27863
|
if (!auditOn()) return;
|
|
27650
27864
|
let last = newestRecord();
|
|
27865
|
+
const attributor = new Attributor();
|
|
27651
27866
|
const pass = () => {
|
|
27652
27867
|
try {
|
|
27653
27868
|
const r = spawnSync(
|
|
@@ -27661,7 +27876,7 @@ function startProcessCollector() {
|
|
|
27661
27876
|
],
|
|
27662
27877
|
{ encoding: "utf8", windowsHide: true, maxBuffer: 64 * 1024 * 1024 }
|
|
27663
27878
|
);
|
|
27664
|
-
const { lines, last: newest } = parseProcessEvents(r.stdout ?? "");
|
|
27879
|
+
const { lines, last: newest } = parseProcessEvents(r.stdout ?? "", { attributor, roots: roots() });
|
|
27665
27880
|
if (newest) last = newest;
|
|
27666
27881
|
if (lines.length)
|
|
27667
27882
|
fs12.writeFileSync(
|
|
@@ -27795,7 +28010,7 @@ function withRequestSecrets(req) {
|
|
|
27795
28010
|
}
|
|
27796
28011
|
|
|
27797
28012
|
// src/guest/daemon/daemon.ts
|
|
27798
|
-
import
|
|
28013
|
+
import fs55 from "node:fs";
|
|
27799
28014
|
|
|
27800
28015
|
// src/guest/setup/claude-mem.ts
|
|
27801
28016
|
import fs15 from "node:fs";
|
|
@@ -28281,18 +28496,76 @@ function readBootEnv() {
|
|
|
28281
28496
|
}
|
|
28282
28497
|
|
|
28283
28498
|
// src/guest/boot/guide.ts
|
|
28499
|
+
import fs19 from "node:fs";
|
|
28500
|
+
import path27 from "node:path";
|
|
28501
|
+
|
|
28502
|
+
// src/guest/apps/find-exe.ts
|
|
28284
28503
|
import fs18 from "node:fs";
|
|
28285
28504
|
import path25 from "node:path";
|
|
28505
|
+
var MAX_DEPTH = 7;
|
|
28506
|
+
var MAX_ENTRIES = 5e4;
|
|
28507
|
+
var X64_FOLDER = /(^|[\\/])(amd64|x64|x86_64|win64)([\\/]|$)/i;
|
|
28508
|
+
function findExe(root, exe) {
|
|
28509
|
+
const match = exeMatcher(exe);
|
|
28510
|
+
const best = (hits) => hits.find((h) => X64_FOLDER.test(path25.relative(root, h))) ?? hits[0] ?? null;
|
|
28511
|
+
let queue = [root];
|
|
28512
|
+
let seen = 0;
|
|
28513
|
+
for (let depth = 0; depth < MAX_DEPTH && queue.length; depth++) {
|
|
28514
|
+
const next = [];
|
|
28515
|
+
const hits = [];
|
|
28516
|
+
for (const dir of queue) {
|
|
28517
|
+
let entries2;
|
|
28518
|
+
try {
|
|
28519
|
+
entries2 = fs18.readdirSync(dir, { withFileTypes: true });
|
|
28520
|
+
} catch {
|
|
28521
|
+
continue;
|
|
28522
|
+
}
|
|
28523
|
+
const hit = entries2.find((e) => e.isFile() && match(e.name));
|
|
28524
|
+
if (hit) hits.push(path25.join(dir, hit.name));
|
|
28525
|
+
else
|
|
28526
|
+
next.push(...entries2.filter((e) => e.isDirectory() && !e.isSymbolicLink()).map((e) => path25.join(dir, e.name)));
|
|
28527
|
+
if ((seen += entries2.length) > MAX_ENTRIES) return best(hits);
|
|
28528
|
+
}
|
|
28529
|
+
if (hits.length) return best(hits);
|
|
28530
|
+
queue = next;
|
|
28531
|
+
}
|
|
28532
|
+
return null;
|
|
28533
|
+
}
|
|
28534
|
+
|
|
28535
|
+
// src/guest/toolchains/tool-env.ts
|
|
28536
|
+
import path26 from "node:path";
|
|
28537
|
+
function emptyEnv() {
|
|
28538
|
+
return { vars: {}, prepend: [], append: [], summary: [] };
|
|
28539
|
+
}
|
|
28540
|
+
var arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
28541
|
+
function tool(...parts2) {
|
|
28542
|
+
return path26.join(toolsDir, ...parts2);
|
|
28543
|
+
}
|
|
28544
|
+
function versionOf(exe, args = ["--version"], options = {}) {
|
|
28545
|
+
return /\d+\.\d+\.\d+\S*/.exec(execOutput(exe, args, options))?.[0] ?? "installed";
|
|
28546
|
+
}
|
|
28547
|
+
|
|
28548
|
+
// src/guest/setup/agent-addons.ts
|
|
28549
|
+
function installedAddon(id) {
|
|
28550
|
+
const entry = appById(id);
|
|
28551
|
+
if (dryRun || !entry || !(session.apps?.install ?? []).includes(id)) return null;
|
|
28552
|
+
return findExe(tool("apps", id), entry.exe);
|
|
28553
|
+
}
|
|
28554
|
+
function installedRtk() {
|
|
28555
|
+
return installedAddon("rtk");
|
|
28556
|
+
}
|
|
28557
|
+
|
|
28558
|
+
// src/guest/boot/guide.ts
|
|
28286
28559
|
var BEGIN = "<!-- agent-sandbox:begin (generated every boot, do not edit) -->";
|
|
28287
28560
|
var END = "<!-- agent-sandbox:end -->";
|
|
28288
28561
|
var mirrorLine = () => {
|
|
28289
|
-
const drives = (session.substDrives ?? []).filter((d) =>
|
|
28562
|
+
const drives = (session.substDrives ?? []).filter((d) => fs19.existsSync(d.letter + ":\\"));
|
|
28290
28563
|
if (!drives.length) return [];
|
|
28291
28564
|
return [
|
|
28292
28565
|
"- " + 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
28566
|
];
|
|
28294
28567
|
};
|
|
28295
|
-
function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
|
|
28568
|
+
function sandboxGuide(toolSummary, lan = "blocked", projects = [], addons = []) {
|
|
28296
28569
|
return [
|
|
28297
28570
|
BEGIN,
|
|
28298
28571
|
"## Sandbox manifest \u2014 you are in a DISPOSABLE Windows Sandbox",
|
|
@@ -28302,11 +28575,13 @@ function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
|
|
|
28302
28575
|
...projects.map(
|
|
28303
28576
|
(p) => "- RW, persists: `" + p.guest + "` = host folder " + p.host + " (another project in this sandbox; your own is `%AGENT_WORKSPACE%`)"
|
|
28304
28577
|
),
|
|
28305
|
-
"- RW, persists: `" + toolsDir + "` (toolchains) \u2014 put portable exes in `" +
|
|
28306
|
-
"- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" +
|
|
28578
|
+
"- RW, persists: `" + toolsDir + "` (toolchains) \u2014 put portable exes in `" + path27.join(toolsDir, "bin") + "` (on PATH)",
|
|
28579
|
+
"- RW, persists: `" + stateDir + "` (agent config/history; do not edit logins) \xB7 logs: `" + path27.join(dataDir, "logs") + "`",
|
|
28307
28580
|
"- RO: `" + launchDir + "` (this boot's scripts) \xB7 lost on close: everything else, incl. `C:\\nvm` (Node symlink)",
|
|
28308
28581
|
...mirrorLine(),
|
|
28309
28582
|
"- Tools: " + toolSummary.join(" \xB7 "),
|
|
28583
|
+
// Agent add-ons that change how the agent works (rtk, Headroom, MCP servers, ccusage).
|
|
28584
|
+
...addons,
|
|
28310
28585
|
"- 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
28586
|
"- 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
28587
|
"- 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 +28589,54 @@ function sandboxGuide(toolSummary, lan = "blocked", projects = []) {
|
|
|
28314
28589
|
].join("\n");
|
|
28315
28590
|
}
|
|
28316
28591
|
function upsertGuide(file3, guide) {
|
|
28317
|
-
|
|
28318
|
-
const current =
|
|
28592
|
+
fs19.mkdirSync(path27.dirname(file3), { recursive: true });
|
|
28593
|
+
const current = fs19.existsSync(file3) ? fs19.readFileSync(file3, "utf8") : "";
|
|
28319
28594
|
const start = current.indexOf(BEGIN);
|
|
28320
28595
|
const end = current.indexOf(END);
|
|
28321
28596
|
const without = start >= 0 && end > start ? current.slice(0, start) + current.slice(end + END.length) : current;
|
|
28322
|
-
|
|
28597
|
+
fs19.writeFileSync(file3, without.trimEnd() + (without.trim() ? "\n\n" : "") + guide + "\n", "utf8");
|
|
28323
28598
|
}
|
|
28324
28599
|
function managedClaudeMd() {
|
|
28325
|
-
return
|
|
28326
|
-
process.env.AGENT_MANAGED_DIR ??
|
|
28600
|
+
return path27.join(
|
|
28601
|
+
process.env.AGENT_MANAGED_DIR ?? path27.join(process.env.ProgramFiles ?? "C:\\Program Files", "ClaudeCode"),
|
|
28327
28602
|
"CLAUDE.md"
|
|
28328
28603
|
);
|
|
28329
28604
|
}
|
|
28605
|
+
var headroomRuns = () => {
|
|
28606
|
+
try {
|
|
28607
|
+
const file3 = path27.join(path27.dirname(managedClaudeMd()), "managed-settings.json");
|
|
28608
|
+
const settings = JSON.parse(fs19.readFileSync(file3, "utf8"));
|
|
28609
|
+
return typeof settings.env?.ANTHROPIC_BASE_URL === "string";
|
|
28610
|
+
} catch {
|
|
28611
|
+
return false;
|
|
28612
|
+
}
|
|
28613
|
+
};
|
|
28614
|
+
function addonLines() {
|
|
28615
|
+
const mcp = APPS.flatMap((a) => a.mcp && installedAddon(a.id) ? [a.mcp.name] : []);
|
|
28616
|
+
return [
|
|
28617
|
+
...installedRtk() ? [RTK_GUIDE_LINE] : [],
|
|
28618
|
+
...installedAddon("headroom") && headroomRuns() ? [headroomGuideLine(path27.join(logsDir, "headroom.log"))] : [],
|
|
28619
|
+
...addonGuideLine(mcp, Boolean(installedAddon("ccusage")))
|
|
28620
|
+
];
|
|
28621
|
+
}
|
|
28330
28622
|
function writeGuides(toolSummary, lan, projects = []) {
|
|
28331
|
-
const guide = sandboxGuide(toolSummary, lan, projects);
|
|
28623
|
+
const guide = sandboxGuide(toolSummary, lan, projects, addonLines());
|
|
28332
28624
|
const managed = managedClaudeMd();
|
|
28333
|
-
|
|
28334
|
-
|
|
28335
|
-
|
|
28336
|
-
upsertGuide(
|
|
28337
|
-
upsertGuide(
|
|
28338
|
-
removeGuide(
|
|
28625
|
+
fs19.mkdirSync(path27.dirname(managed), { recursive: true });
|
|
28626
|
+
fs19.writeFileSync(managed, guide + "\n", "utf8");
|
|
28627
|
+
fs19.writeFileSync(path27.join(dataDir, "SANDBOX.md"), guide + "\n", "utf8");
|
|
28628
|
+
upsertGuide(path27.join(stateDir, "codex", "AGENTS.md"), guide);
|
|
28629
|
+
upsertGuide(path27.join(stateDir, "gemini", ".gemini", "GEMINI.md"), guide);
|
|
28630
|
+
removeGuide(path27.join(claudeDir, "CLAUDE.md"));
|
|
28339
28631
|
return managed;
|
|
28340
28632
|
}
|
|
28341
28633
|
var removeGuide = (file3) => {
|
|
28342
|
-
if (!
|
|
28343
|
-
const current =
|
|
28634
|
+
if (!fs19.existsSync(file3)) return;
|
|
28635
|
+
const current = fs19.readFileSync(file3, "utf8");
|
|
28344
28636
|
const start = current.indexOf(BEGIN);
|
|
28345
28637
|
const end = current.indexOf(END);
|
|
28346
28638
|
if (start >= 0 && end > start)
|
|
28347
|
-
|
|
28639
|
+
fs19.writeFileSync(file3, (current.slice(0, start) + current.slice(end + END.length)).trim() + "\n", "utf8");
|
|
28348
28640
|
};
|
|
28349
28641
|
|
|
28350
28642
|
// src/guest/runtime/project-context.ts
|
|
@@ -28381,11 +28673,11 @@ function saveProjectStatus(name, workspace2, phase, message, databases, summary)
|
|
|
28381
28673
|
}
|
|
28382
28674
|
|
|
28383
28675
|
// src/guest/setup/hooks.ts
|
|
28384
|
-
import
|
|
28385
|
-
import
|
|
28676
|
+
import fs20 from "node:fs";
|
|
28677
|
+
import path28 from "node:path";
|
|
28386
28678
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
28387
28679
|
var commandFor = (file3) => {
|
|
28388
|
-
const ext =
|
|
28680
|
+
const ext = path28.extname(file3).toLowerCase();
|
|
28389
28681
|
if (ext === ".mjs" || ext === ".js") return [process.execPath, [file3]];
|
|
28390
28682
|
if (!isWin) return null;
|
|
28391
28683
|
if (ext === ".ps1")
|
|
@@ -28393,18 +28685,18 @@ var commandFor = (file3) => {
|
|
|
28393
28685
|
if (ext === ".cmd" || ext === ".bat") return [SYSTEM.cmd(), ["/d", "/c", file3]];
|
|
28394
28686
|
return null;
|
|
28395
28687
|
};
|
|
28396
|
-
var BOOT = { root:
|
|
28688
|
+
var BOOT = { root: path28.join(launchDir, "hooks"), cwd: workspace };
|
|
28397
28689
|
function projectHooks(name, cwd) {
|
|
28398
28690
|
return {
|
|
28399
|
-
root:
|
|
28691
|
+
root: path28.join(launchDir, "projects", name, "hooks"),
|
|
28400
28692
|
cwd
|
|
28401
28693
|
};
|
|
28402
28694
|
}
|
|
28403
28695
|
var hooksOf = (stage, target) => {
|
|
28404
|
-
const dir =
|
|
28696
|
+
const dir = path28.join(target.root, stage);
|
|
28405
28697
|
if (!exists(dir)) return [];
|
|
28406
|
-
return
|
|
28407
|
-
const command = commandFor(
|
|
28698
|
+
return fs20.readdirSync(dir).sort().flatMap((name) => {
|
|
28699
|
+
const command = commandFor(path28.join(dir, name));
|
|
28408
28700
|
return command ? [{ name, command }] : [];
|
|
28409
28701
|
});
|
|
28410
28702
|
};
|
|
@@ -28433,26 +28725,109 @@ async function runHooksAsync(stage, env, target) {
|
|
|
28433
28725
|
}
|
|
28434
28726
|
}
|
|
28435
28727
|
|
|
28436
|
-
// src/guest/
|
|
28437
|
-
import
|
|
28438
|
-
|
|
28439
|
-
|
|
28440
|
-
|
|
28441
|
-
|
|
28442
|
-
|
|
28443
|
-
|
|
28728
|
+
// src/guest/apps/app-installer.ts
|
|
28729
|
+
import fs24 from "node:fs";
|
|
28730
|
+
import path33 from "node:path";
|
|
28731
|
+
|
|
28732
|
+
// src/guest/toolchains/runtimes.ts
|
|
28733
|
+
import path29 from "node:path";
|
|
28734
|
+
|
|
28735
|
+
// src/guest/toolchains/install.ts
|
|
28736
|
+
import fs21 from "node:fs";
|
|
28737
|
+
async function downloadFile(url2, file3, sha256 = null) {
|
|
28738
|
+
const part = file3 + ".part";
|
|
28739
|
+
try {
|
|
28740
|
+
await downloader.file(url2, part, sha256);
|
|
28741
|
+
fs21.rmSync(file3, { force: true });
|
|
28742
|
+
fs21.renameSync(part, file3);
|
|
28743
|
+
} finally {
|
|
28744
|
+
fs21.rmSync(part, { force: true });
|
|
28745
|
+
}
|
|
28444
28746
|
}
|
|
28445
|
-
function
|
|
28446
|
-
|
|
28747
|
+
async function installFromGithub(repo, pattern, o) {
|
|
28748
|
+
const asset = await githubAsset(repo, pattern, o.searchOlder);
|
|
28749
|
+
log("Downloading " + (typeof o.what === "string" ? o.what : o.what(asset)) + " ...");
|
|
28750
|
+
await downloader.archive(asset.url, o.dest, {
|
|
28751
|
+
sha256: asset.sha256,
|
|
28752
|
+
fileName: asset.name,
|
|
28753
|
+
...o.locate ? { locate: o.locate } : {},
|
|
28754
|
+
...o.up ? { up: o.up } : {}
|
|
28755
|
+
});
|
|
28447
28756
|
}
|
|
28448
28757
|
|
|
28449
|
-
// src/guest/
|
|
28450
|
-
|
|
28451
|
-
|
|
28758
|
+
// src/guest/toolchains/runtimes.ts
|
|
28759
|
+
async function setupSingleExe(env, name, repo, pattern, exeName, dir, options = {}) {
|
|
28760
|
+
if (dryRun) {
|
|
28761
|
+
log("(dry run) would provision " + name);
|
|
28762
|
+
return;
|
|
28763
|
+
}
|
|
28764
|
+
const bin = options.subdir ? path29.join(dir, options.subdir) : dir;
|
|
28765
|
+
const exe = path29.join(bin, exeName);
|
|
28766
|
+
if (!exists(exe) || options.refresh) {
|
|
28767
|
+
const size = options.size ? ", ~" + options.size : "";
|
|
28768
|
+
await installFromGithub(repo, pattern, {
|
|
28769
|
+
dest: dir,
|
|
28770
|
+
what: (a) => name + " (" + a.name + size + " once)",
|
|
28771
|
+
...options.subdir ? {} : { locate: exeName }
|
|
28772
|
+
});
|
|
28773
|
+
}
|
|
28774
|
+
if (!exists(exe)) throw new Error(exeName + " missing after installing " + name);
|
|
28775
|
+
env.prepend.push(bin);
|
|
28776
|
+
env.summary.push(name + ": " + versionOf(exe, options.versionArgs) + (options.note ?? ""));
|
|
28777
|
+
}
|
|
28778
|
+
async function setupBun(env) {
|
|
28779
|
+
await setupSingleExe(
|
|
28780
|
+
env,
|
|
28781
|
+
"bun",
|
|
28782
|
+
"oven-sh/bun",
|
|
28783
|
+
arch === "arm64" ? /^bun-windows-aarch64\.zip$/ : /^bun-windows-x64\.zip$/,
|
|
28784
|
+
"bun.exe",
|
|
28785
|
+
tool("bun", "bin"),
|
|
28786
|
+
{ size: "35 MB" }
|
|
28787
|
+
);
|
|
28788
|
+
Object.assign(env.vars, {
|
|
28789
|
+
BUN_INSTALL: tool("bun"),
|
|
28790
|
+
BUN_INSTALL_CACHE_DIR: path29.join(localDir, "bun-cache"),
|
|
28791
|
+
BUN_TMPDIR: path29.join(localDir, "bun-tmp")
|
|
28792
|
+
});
|
|
28793
|
+
}
|
|
28794
|
+
async function setupDeno(env) {
|
|
28795
|
+
await setupSingleExe(
|
|
28796
|
+
env,
|
|
28797
|
+
"deno",
|
|
28798
|
+
"denoland/deno",
|
|
28799
|
+
arch === "arm64" ? /^deno-aarch64-pc-windows-msvc[.]zip$/ : /^deno-x86_64-pc-windows-msvc[.]zip$/,
|
|
28800
|
+
"deno.exe",
|
|
28801
|
+
tool("deno", "bin"),
|
|
28802
|
+
{ size: "40 MB" }
|
|
28803
|
+
);
|
|
28804
|
+
Object.assign(env.vars, { DENO_DIR: tool("deno-cache"), DENO_INSTALL_ROOT: tool("deno"), DENO_NO_UPDATE_CHECK: "1" });
|
|
28805
|
+
}
|
|
28806
|
+
function uvVars() {
|
|
28807
|
+
return {
|
|
28808
|
+
UV_CACHE_DIR: tool("uv-cache"),
|
|
28809
|
+
UV_PYTHON_INSTALL_DIR: tool("uv-python"),
|
|
28810
|
+
UV_TOOL_DIR: tool("uv-tools"),
|
|
28811
|
+
UV_TOOL_BIN_DIR: tool("uv-bin")
|
|
28812
|
+
};
|
|
28813
|
+
}
|
|
28814
|
+
async function setupUv(env) {
|
|
28815
|
+
await setupSingleExe(
|
|
28816
|
+
env,
|
|
28817
|
+
"uv",
|
|
28818
|
+
"astral-sh/uv",
|
|
28819
|
+
arch === "arm64" ? /^uv-aarch64-pc-windows-msvc\.zip$/ : /^uv-x86_64-pc-windows-msvc\.zip$/,
|
|
28820
|
+
"uv.exe",
|
|
28821
|
+
tool("uv"),
|
|
28822
|
+
{ size: "20 MB" }
|
|
28823
|
+
);
|
|
28824
|
+
Object.assign(env.vars, uvVars());
|
|
28825
|
+
env.prepend.push(mkdirp(tool("uv-bin")));
|
|
28826
|
+
}
|
|
28452
28827
|
|
|
28453
28828
|
// src/guest/apps/after-install.ts
|
|
28454
|
-
import
|
|
28455
|
-
import
|
|
28829
|
+
import fs22 from "node:fs";
|
|
28830
|
+
import path30 from "node:path";
|
|
28456
28831
|
var SYSINTERNALS_TOOLS = [
|
|
28457
28832
|
"Process Explorer",
|
|
28458
28833
|
"Process Monitor",
|
|
@@ -28473,16 +28848,16 @@ var SYSINTERNALS_TOOLS = [
|
|
|
28473
28848
|
"ZoomIt"
|
|
28474
28849
|
];
|
|
28475
28850
|
async function afterInstall(entry, exe) {
|
|
28476
|
-
const dir =
|
|
28851
|
+
const dir = path30.dirname(exe);
|
|
28477
28852
|
if (entry.needs?.includes("mesa")) {
|
|
28478
28853
|
const mesa = tool("mesa", arch === "arm64" ? "arm64" : "x64");
|
|
28479
28854
|
for (const dll of ["opengl32.dll", "libgallium_wgl.dll", "dxil.dll"]) {
|
|
28480
|
-
if (exists(
|
|
28481
|
-
|
|
28855
|
+
if (exists(path30.join(mesa, dll)) && !exists(path30.join(dir, dll)))
|
|
28856
|
+
fs22.copyFileSync(path30.join(mesa, dll), path30.join(dir, dll));
|
|
28482
28857
|
}
|
|
28483
28858
|
}
|
|
28484
|
-
if (entry.id === "godot" && !exists(
|
|
28485
|
-
if (entry.id === "sublime") mkdirp(
|
|
28859
|
+
if (entry.id === "godot" && !exists(path30.join(dir, "._sc_"))) fs22.writeFileSync(path30.join(dir, "._sc_"), "");
|
|
28860
|
+
if (entry.id === "sublime") mkdirp(path30.join(dir, "Data"));
|
|
28486
28861
|
if (entry.id === "sysinternals") {
|
|
28487
28862
|
for (const name of SYSINTERNALS_TOOLS) {
|
|
28488
28863
|
await execAsync(
|
|
@@ -28494,47 +28869,14 @@ async function afterInstall(entry, exe) {
|
|
|
28494
28869
|
}
|
|
28495
28870
|
}
|
|
28496
28871
|
|
|
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
28872
|
// src/guest/apps/shortcuts.ts
|
|
28531
28873
|
import os5 from "node:os";
|
|
28532
|
-
import
|
|
28874
|
+
import path31 from "node:path";
|
|
28533
28875
|
function shortcuts(apps) {
|
|
28534
28876
|
if (!apps.length) return;
|
|
28535
|
-
const desktop =
|
|
28536
|
-
const start =
|
|
28537
|
-
process.env.APPDATA ??
|
|
28877
|
+
const desktop = path31.join(os5.homedir(), "Desktop");
|
|
28878
|
+
const start = path31.join(
|
|
28879
|
+
process.env.APPDATA ?? path31.join(os5.homedir(), "AppData", "Roaming"),
|
|
28538
28880
|
"Microsoft",
|
|
28539
28881
|
"Windows",
|
|
28540
28882
|
"Start Menu",
|
|
@@ -28544,9 +28886,9 @@ function shortcuts(apps) {
|
|
|
28544
28886
|
const links = apps.flatMap((app) => {
|
|
28545
28887
|
const name = app.name.replace(/[\\/:*?"<>|]/g, "");
|
|
28546
28888
|
return [desktop, start].map((folder) => ({
|
|
28547
|
-
link:
|
|
28889
|
+
link: path31.join(folder, name + ".lnk"),
|
|
28548
28890
|
target: app.exe,
|
|
28549
|
-
workingDirectory:
|
|
28891
|
+
workingDirectory: path31.dirname(app.exe)
|
|
28550
28892
|
}));
|
|
28551
28893
|
});
|
|
28552
28894
|
runScriptWithJson("new-shortcuts.ps1", "ListFile", links);
|
|
@@ -28671,19 +29013,19 @@ async function resolve(entry) {
|
|
|
28671
29013
|
}
|
|
28672
29014
|
if ("url" in s) {
|
|
28673
29015
|
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" };
|
|
29016
|
+
return { url: s.url, fileName: /\.\w{2,5}$/.test(name) ? name : name + ".zip", sha256: s.sha256 };
|
|
28675
29017
|
}
|
|
28676
29018
|
if ("resolve" in s && RESOLVERS[s.resolve]) return RESOLVERS[s.resolve]();
|
|
28677
29019
|
throw new Error("no download source for " + entry.name);
|
|
28678
29020
|
}
|
|
28679
29021
|
|
|
28680
29022
|
// src/guest/apps/unpack.ts
|
|
28681
|
-
import
|
|
28682
|
-
import
|
|
29023
|
+
import fs23 from "node:fs";
|
|
29024
|
+
import path32 from "node:path";
|
|
28683
29025
|
var sevenZip = () => tool("apps", "7zip", "7z.exe");
|
|
28684
29026
|
async function unpack(entry, file3, out, d) {
|
|
28685
29027
|
if (entry.id === "7zip") {
|
|
28686
|
-
const sevenZr =
|
|
29028
|
+
const sevenZr = path32.join(path32.dirname(file3), "7zr.exe");
|
|
28687
29029
|
const zr = await githubAsset("ip7z/7zip", /^7zr\.exe$/);
|
|
28688
29030
|
await downloader.file(zr.url, sevenZr, zr.sha256);
|
|
28689
29031
|
await execAsync(sevenZr, ["x", "-y", "-o" + out, file3], { stdio: "ignore" });
|
|
@@ -28692,17 +29034,17 @@ async function unpack(entry, file3, out, d) {
|
|
|
28692
29034
|
switch (entry.unpack ?? "archive") {
|
|
28693
29035
|
case "file": {
|
|
28694
29036
|
mkdirp(out);
|
|
28695
|
-
|
|
29037
|
+
fs23.renameSync(file3, path32.join(out, /^\//.test(entry.exe) ? path32.basename(file3) : entry.exe));
|
|
28696
29038
|
return;
|
|
28697
29039
|
}
|
|
28698
29040
|
case "nsis": {
|
|
28699
29041
|
if (!exists(sevenZip()))
|
|
28700
29042
|
throw new Error("7-Zip is needed to unpack " + entry.name + " and could not be installed");
|
|
28701
|
-
const raw =
|
|
29043
|
+
const raw = path32.join(path32.dirname(out), "raw");
|
|
28702
29044
|
await execAsync(sevenZip(), ["x", "-y", "-o" + raw, file3], { stdio: "ignore" });
|
|
28703
29045
|
const inner = findExe(raw, "/^app-64\\.7z$/");
|
|
28704
29046
|
if (inner) await execAsync(sevenZip(), ["x", "-y", "-o" + out, inner], { stdio: "ignore" });
|
|
28705
|
-
else
|
|
29047
|
+
else fs23.renameSync(raw, out);
|
|
28706
29048
|
return;
|
|
28707
29049
|
}
|
|
28708
29050
|
case "msi": {
|
|
@@ -28752,12 +29094,12 @@ var AppInstaller = class {
|
|
|
28752
29094
|
async installOne(entry) {
|
|
28753
29095
|
try {
|
|
28754
29096
|
const dest = tool("apps", ...entry.id.split("/"));
|
|
28755
|
-
if (!exists(
|
|
29097
|
+
if (!exists(path33.join(dest, MARKER)) || this.options.refresh) await this.download(entry, dest);
|
|
28756
29098
|
const exe = findExe(dest, entry.exe);
|
|
28757
29099
|
if (!exe) throw new Error(entry.exe + " not found in the download");
|
|
28758
29100
|
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 });
|
|
29101
|
+
if (!entry.service && (entry.cli || entry.id === "sysinternals")) this.env.prepend.push(path33.dirname(exe));
|
|
29102
|
+
if (!entry.cli && !entry.service) this.gui.push({ name: entry.name, exe });
|
|
28761
29103
|
this.installed.push(entry.name);
|
|
28762
29104
|
} catch (e) {
|
|
28763
29105
|
warn(
|
|
@@ -28769,10 +29111,13 @@ var AppInstaller = class {
|
|
|
28769
29111
|
/** Downloads and unpacks one entry into its folder (replaced in one step: never half there). */
|
|
28770
29112
|
async download(entry, dest) {
|
|
28771
29113
|
const work = stagingFolder(dest);
|
|
28772
|
-
const out =
|
|
29114
|
+
const out = path33.join(work, "out");
|
|
28773
29115
|
try {
|
|
28774
|
-
if ("
|
|
28775
|
-
|
|
29116
|
+
if ("locked" in entry.source) {
|
|
29117
|
+
log("Installing " + entry.name + " " + entry.source.version + " (pinned, every file checked) ...");
|
|
29118
|
+
await installLocked(entry.id, entry.source.locked, mkdirp(out));
|
|
29119
|
+
} else if ("npm" in entry.source) {
|
|
29120
|
+
const npmCli = path33.join(path33.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
28776
29121
|
log("Installing " + entry.name + " (npm) ...");
|
|
28777
29122
|
await execAsync(process.execPath, [
|
|
28778
29123
|
npmCli,
|
|
@@ -28787,17 +29132,60 @@ var AppInstaller = class {
|
|
|
28787
29132
|
} else {
|
|
28788
29133
|
const d = await resolve(entry);
|
|
28789
29134
|
log("Downloading " + entry.name + " (" + d.fileName + ", ~" + entry.size + " once) ...");
|
|
28790
|
-
const file3 =
|
|
29135
|
+
const file3 = path33.join(mkdirp(work), d.fileName.replace(/[\\/:*?"<>|]/g, "_"));
|
|
28791
29136
|
await downloader.file(d.url, file3, { sha256: d.sha256 ?? null });
|
|
28792
29137
|
await unpack(entry, file3, out, d);
|
|
28793
29138
|
}
|
|
28794
|
-
|
|
29139
|
+
fs24.writeFileSync(path33.join(out, MARKER), JSON.stringify({ id: entry.id, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
28795
29140
|
moveIntoPlace(out, dest);
|
|
28796
29141
|
} finally {
|
|
28797
|
-
safeRemove(work,
|
|
29142
|
+
safeRemove(work, path33.dirname(work));
|
|
28798
29143
|
}
|
|
28799
29144
|
}
|
|
28800
29145
|
};
|
|
29146
|
+
var LOCKED_PYTHON = "3.13";
|
|
29147
|
+
async function installLocked(id, kind, out) {
|
|
29148
|
+
const lock = path33.join(launchDir, "sandbox", "addons", id);
|
|
29149
|
+
if (kind === "npm") {
|
|
29150
|
+
for (const f of ["package.json", "package-lock.json"]) fs24.copyFileSync(path33.join(lock, f), path33.join(out, f));
|
|
29151
|
+
const npmCli = path33.join(path33.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
29152
|
+
await execAsync(
|
|
29153
|
+
process.execPath,
|
|
29154
|
+
[npmCli, "ci", "--ignore-scripts", "--no-audit", "--no-fund", "--loglevel=error"],
|
|
29155
|
+
{ cwd: out }
|
|
29156
|
+
);
|
|
29157
|
+
return;
|
|
29158
|
+
}
|
|
29159
|
+
const uv = findExe(tool("uv"), "uv.exe");
|
|
29160
|
+
if (!uv) throw new Error("uv is not installed (the uv step failed)");
|
|
29161
|
+
const env = { ...process.env, ...uvVars() };
|
|
29162
|
+
const venv = path33.join(out, "venv");
|
|
29163
|
+
await execAsync(
|
|
29164
|
+
uv,
|
|
29165
|
+
["venv", "--relocatable", "--python", LOCKED_PYTHON, "--python-preference", "only-managed", venv],
|
|
29166
|
+
{
|
|
29167
|
+
env
|
|
29168
|
+
}
|
|
29169
|
+
);
|
|
29170
|
+
await execAsync(
|
|
29171
|
+
uv,
|
|
29172
|
+
[
|
|
29173
|
+
"pip",
|
|
29174
|
+
"install",
|
|
29175
|
+
"--python",
|
|
29176
|
+
path33.join(venv, "Scripts", "python.exe"),
|
|
29177
|
+
"--require-hashes",
|
|
29178
|
+
"--no-deps",
|
|
29179
|
+
"--only-binary",
|
|
29180
|
+
":all:",
|
|
29181
|
+
"--link-mode",
|
|
29182
|
+
"copy",
|
|
29183
|
+
"-r",
|
|
29184
|
+
path33.join(lock, "requirements.txt")
|
|
29185
|
+
],
|
|
29186
|
+
{ env }
|
|
29187
|
+
);
|
|
29188
|
+
}
|
|
28801
29189
|
async function setupApps(env, apps, o) {
|
|
28802
29190
|
const { entries: entries2, skipped } = appsToInstall(apps, o.gitAccess);
|
|
28803
29191
|
for (const s of skipped) env.summary.push("app skipped: " + s);
|
|
@@ -28809,8 +29197,8 @@ async function setupApps(env, apps, o) {
|
|
|
28809
29197
|
}
|
|
28810
29198
|
|
|
28811
29199
|
// src/guest/toolchains/detect.ts
|
|
28812
|
-
import
|
|
28813
|
-
import
|
|
29200
|
+
import fs25 from "node:fs";
|
|
29201
|
+
import path34 from "node:path";
|
|
28814
29202
|
|
|
28815
29203
|
// src/core/detect/versions.ts
|
|
28816
29204
|
function pickNodeVersion(releases, spec) {
|
|
@@ -28942,14 +29330,14 @@ function workspaceEntries() {
|
|
|
28942
29330
|
if (known) return known;
|
|
28943
29331
|
const list = (dir) => {
|
|
28944
29332
|
try {
|
|
28945
|
-
return
|
|
29333
|
+
return fs25.readdirSync(dir, { withFileTypes: true });
|
|
28946
29334
|
} catch {
|
|
28947
29335
|
return [];
|
|
28948
29336
|
}
|
|
28949
29337
|
};
|
|
28950
29338
|
const top = list(workspace2);
|
|
28951
29339
|
const below = top.filter((d) => d.isDirectory() && !d.name.startsWith(".") && !SKIP_DIRS.has(d.name.toLowerCase())).flatMap(
|
|
28952
|
-
(d) => list(
|
|
29340
|
+
(d) => list(path34.join(workspace2, d.name)).filter((f) => f.isFile()).map((f) => d.name + "/" + f.name)
|
|
28953
29341
|
);
|
|
28954
29342
|
const found = [...top.filter((d) => d.isFile()).map((d) => d.name), ...below];
|
|
28955
29343
|
entries.set(workspace2.toLowerCase(), found);
|
|
@@ -28960,9 +29348,9 @@ function wanted(setting, toolchain) {
|
|
|
28960
29348
|
}
|
|
28961
29349
|
function versionFromFiles(files, parse5 = (t) => specFromVersionFile(t)) {
|
|
28962
29350
|
for (const name of files) {
|
|
28963
|
-
const file3 =
|
|
29351
|
+
const file3 = path34.join(projectWorkspace(), name);
|
|
28964
29352
|
if (!exists(file3)) continue;
|
|
28965
|
-
const spec = parse5(
|
|
29353
|
+
const spec = parse5(fs25.readFileSync(file3, "utf8"), name);
|
|
28966
29354
|
if (spec) return { spec, source: name };
|
|
28967
29355
|
}
|
|
28968
29356
|
return null;
|
|
@@ -29035,22 +29423,22 @@ var DatabaseServer = class {
|
|
|
29035
29423
|
};
|
|
29036
29424
|
|
|
29037
29425
|
// src/guest/databases/dynamodb.ts
|
|
29038
|
-
import
|
|
29039
|
-
import
|
|
29426
|
+
import fs30 from "node:fs";
|
|
29427
|
+
import path37 from "node:path";
|
|
29040
29428
|
import { spawn as spawn3 } from "node:child_process";
|
|
29041
29429
|
|
|
29042
29430
|
// src/guest/toolchains/languages/java.ts
|
|
29043
|
-
import
|
|
29044
|
-
import
|
|
29431
|
+
import fs28 from "node:fs";
|
|
29432
|
+
import path35 from "node:path";
|
|
29045
29433
|
|
|
29046
29434
|
// src/guest/toolchains/version-cache.ts
|
|
29047
|
-
import
|
|
29435
|
+
import fs27 from "node:fs";
|
|
29048
29436
|
|
|
29049
29437
|
// src/guest/toolchains/state-file.ts
|
|
29050
|
-
import
|
|
29438
|
+
import fs26 from "node:fs";
|
|
29051
29439
|
function readState(file3, schema, empty) {
|
|
29052
29440
|
try {
|
|
29053
|
-
return schema.safeParse(JSON.parse(
|
|
29441
|
+
return schema.safeParse(JSON.parse(fs26.readFileSync(file3, "utf8").replace(/^\uFEFF/, ""))).data ?? empty;
|
|
29054
29442
|
} catch {
|
|
29055
29443
|
return empty;
|
|
29056
29444
|
}
|
|
@@ -29085,7 +29473,7 @@ var VersionCache = class {
|
|
|
29085
29473
|
return cached2.value;
|
|
29086
29474
|
try {
|
|
29087
29475
|
const value = await resolve2();
|
|
29088
|
-
|
|
29476
|
+
fs27.mkdirSync(toolsDir, { recursive: true });
|
|
29089
29477
|
writeJsonAtomic(this.file(), { ...this.remembered(), [key2]: { value, at: Date.now() } });
|
|
29090
29478
|
return value;
|
|
29091
29479
|
} catch (e) {
|
|
@@ -29138,7 +29526,7 @@ var setupJdk = async (env, config2) => {
|
|
|
29138
29526
|
const { major, source } = await javaMajor(config2);
|
|
29139
29527
|
const release = await resolveCached("java:" + major, async () => (await temurin(major)).release_name);
|
|
29140
29528
|
const home = tool("java", release.replace(/[^A-Za-z0-9.-]/g, "_"));
|
|
29141
|
-
if (!exists(
|
|
29529
|
+
if (!exists(path35.join(home, "bin", "java.exe"))) {
|
|
29142
29530
|
const asset = await temurin(major);
|
|
29143
29531
|
log("Downloading Java " + release + " (JDK, ~200 MB once) ...");
|
|
29144
29532
|
await downloader.archive(asset.binary.package.link, home, {
|
|
@@ -29148,13 +29536,13 @@ var setupJdk = async (env, config2) => {
|
|
|
29148
29536
|
});
|
|
29149
29537
|
}
|
|
29150
29538
|
env.vars.JAVA_HOME = home;
|
|
29151
|
-
env.prepend.push(
|
|
29539
|
+
env.prepend.push(path35.join(home, "bin"));
|
|
29152
29540
|
env.summary.push("java: " + release + " (Temurin, from " + source + ")");
|
|
29153
29541
|
};
|
|
29154
29542
|
async function ensureJdk() {
|
|
29155
29543
|
const root = tool("java");
|
|
29156
|
-
const installed = exists(root) ?
|
|
29157
|
-
if (installed.length) return
|
|
29544
|
+
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 })) : [];
|
|
29545
|
+
if (installed.length) return path35.join(root, installed[0]);
|
|
29158
29546
|
const scratch = emptyEnv();
|
|
29159
29547
|
await setupJdk(scratch, { enabled: true, version: "lts", maven: false, gradle: false });
|
|
29160
29548
|
return scratch.vars.JAVA_HOME;
|
|
@@ -29167,7 +29555,7 @@ var setupMaven = async (env) => {
|
|
|
29167
29555
|
return pickPackageVersion(versions, "3") ?? Promise.reject(new Error("No Maven 3 release found"));
|
|
29168
29556
|
});
|
|
29169
29557
|
const home = tool("maven", version2);
|
|
29170
|
-
if (!exists(
|
|
29558
|
+
if (!exists(path35.join(home, "bin", "mvn.cmd"))) {
|
|
29171
29559
|
const url2 = MAVEN + version2 + "/apache-maven-" + version2 + "-bin.zip";
|
|
29172
29560
|
log("Downloading Maven " + version2 + " (~10 MB once) ...");
|
|
29173
29561
|
await downloader.archive(url2, home, {
|
|
@@ -29177,7 +29565,7 @@ var setupMaven = async (env) => {
|
|
|
29177
29565
|
}
|
|
29178
29566
|
const repo = tool("maven-repository");
|
|
29179
29567
|
Object.assign(env.vars, { MAVEN_HOME: home, M2_HOME: home, MAVEN_OPTS: "-Dmaven.repo.local=" + repo });
|
|
29180
|
-
env.prepend.push(
|
|
29568
|
+
env.prepend.push(path35.join(home, "bin"));
|
|
29181
29569
|
env.summary.push("maven: " + version2);
|
|
29182
29570
|
};
|
|
29183
29571
|
var setupGradle = async (env) => {
|
|
@@ -29189,7 +29577,7 @@ var setupGradle = async (env) => {
|
|
|
29189
29577
|
async () => current?.version ?? Promise.reject(new Error("Gradle version lookup failed"))
|
|
29190
29578
|
);
|
|
29191
29579
|
const home = tool("gradle", version2);
|
|
29192
|
-
if (!exists(
|
|
29580
|
+
if (!exists(path35.join(home, "bin", "gradle.bat"))) {
|
|
29193
29581
|
if (!current || current.version !== version2)
|
|
29194
29582
|
throw new Error("Gradle " + version2 + " is not installed and cannot be downloaded right now");
|
|
29195
29583
|
log("Downloading Gradle " + version2 + " (~130 MB once) ...");
|
|
@@ -29200,13 +29588,13 @@ var setupGradle = async (env) => {
|
|
|
29200
29588
|
});
|
|
29201
29589
|
}
|
|
29202
29590
|
const userHome = tool("gradle-home");
|
|
29203
|
-
|
|
29591
|
+
fs28.mkdirSync(userHome, { recursive: true });
|
|
29204
29592
|
Object.assign(env.vars, {
|
|
29205
29593
|
GRADLE_HOME: home,
|
|
29206
29594
|
GRADLE_USER_HOME: userHome,
|
|
29207
29595
|
GRADLE_OPTS: "-Dorg.gradle.vfs.watch=false"
|
|
29208
29596
|
});
|
|
29209
|
-
env.prepend.push(
|
|
29597
|
+
env.prepend.push(path35.join(home, "bin"));
|
|
29210
29598
|
env.summary.push("gradle: " + version2);
|
|
29211
29599
|
};
|
|
29212
29600
|
async function setupJava(env, config2) {
|
|
@@ -29230,29 +29618,29 @@ async function setupJava(env, config2) {
|
|
|
29230
29618
|
}
|
|
29231
29619
|
|
|
29232
29620
|
// src/guest/databases/server.ts
|
|
29233
|
-
import
|
|
29234
|
-
import
|
|
29621
|
+
import fs29 from "node:fs";
|
|
29622
|
+
import path36 from "node:path";
|
|
29235
29623
|
import { spawn as spawn2 } from "node:child_process";
|
|
29236
29624
|
function dataFor(name) {
|
|
29237
|
-
return
|
|
29625
|
+
return path36.join(dataDir, "databases", name);
|
|
29238
29626
|
}
|
|
29239
29627
|
async function startServer(name, exe, args, port) {
|
|
29240
29628
|
if (await portOpen(port)) throw new Error("port " + port + " is already in use (change databases." + name + ".port)");
|
|
29241
|
-
const logFile2 =
|
|
29242
|
-
const out =
|
|
29629
|
+
const logFile2 = path36.join(logsDir, name + ".log");
|
|
29630
|
+
const out = fs29.openSync(logFile2, "a");
|
|
29243
29631
|
spawn2(exe, args, { detached: true, stdio: ["ignore", out, out], windowsHide: true }).unref();
|
|
29244
|
-
|
|
29632
|
+
fs29.closeSync(out);
|
|
29245
29633
|
if (!await waitForPort(port, 60))
|
|
29246
29634
|
throw new Error(name + " did not start listening on port " + port + "; see " + logFile2);
|
|
29247
29635
|
}
|
|
29248
29636
|
async function clearStaleLocks(dir, files, port) {
|
|
29249
29637
|
if (await portOpen(port)) return;
|
|
29250
|
-
for (const f of files)
|
|
29638
|
+
for (const f of files) fs29.rmSync(path36.join(dir, f), { force: true });
|
|
29251
29639
|
}
|
|
29252
29640
|
async function createOnce(data, marker, create) {
|
|
29253
|
-
if (exists(
|
|
29641
|
+
if (exists(path36.join(data, marker))) return;
|
|
29254
29642
|
const existed = exists(data);
|
|
29255
|
-
mkdirp(
|
|
29643
|
+
mkdirp(path36.dirname(data));
|
|
29256
29644
|
try {
|
|
29257
29645
|
await create();
|
|
29258
29646
|
} catch (e) {
|
|
@@ -29276,9 +29664,9 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29276
29664
|
* local endpoint up from AWS_ENDPOINT_URL_DYNAMODB, with dummy credentials (real ones never reach the sandbox).
|
|
29277
29665
|
*/
|
|
29278
29666
|
async start(env, plan2) {
|
|
29279
|
-
const java =
|
|
29667
|
+
const java = path37.join(await ensureJdk(), "bin", "java.exe");
|
|
29280
29668
|
const home = tool("dynamodb-local");
|
|
29281
|
-
if (!exists(
|
|
29669
|
+
if (!exists(path37.join(home, "DynamoDBLocal.jar"))) {
|
|
29282
29670
|
log("Downloading DynamoDB Local (~60 MB once) ...");
|
|
29283
29671
|
const sha256 = (await fetchText(DYNAMO_ZIP + ".sha256")).trim().split(/\s+/)[0];
|
|
29284
29672
|
await downloader.archive(DYNAMO_ZIP, home, {
|
|
@@ -29292,9 +29680,9 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29292
29680
|
"dynamodb",
|
|
29293
29681
|
java,
|
|
29294
29682
|
[
|
|
29295
|
-
"-Djava.library.path=" +
|
|
29683
|
+
"-Djava.library.path=" + path37.join(home, "DynamoDBLocal_lib"),
|
|
29296
29684
|
"-jar",
|
|
29297
|
-
|
|
29685
|
+
path37.join(home, "DynamoDBLocal.jar"),
|
|
29298
29686
|
"-sharedDb",
|
|
29299
29687
|
"-dbPath",
|
|
29300
29688
|
data,
|
|
@@ -29318,10 +29706,10 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29318
29706
|
);
|
|
29319
29707
|
if (!plan2.adminPort) return;
|
|
29320
29708
|
const prefix = tool("dynamodb-admin");
|
|
29321
|
-
const script =
|
|
29709
|
+
const script = path37.join(prefix, "node_modules", "dynamodb-admin", "dist", "dynamodb-admin.js");
|
|
29322
29710
|
if (!exists(script)) {
|
|
29323
29711
|
log("Installing dynamodb-admin, the DynamoDB web UI (~20 MB once) ...");
|
|
29324
|
-
const npmCli =
|
|
29712
|
+
const npmCli = path37.join(path37.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
29325
29713
|
await execAsync(
|
|
29326
29714
|
process.execPath,
|
|
29327
29715
|
[npmCli, "install", "--global", "--prefix", prefix, "dynamodb-admin", "--no-fund", "--no-audit"],
|
|
@@ -29334,15 +29722,15 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29334
29722
|
);
|
|
29335
29723
|
return;
|
|
29336
29724
|
}
|
|
29337
|
-
const out =
|
|
29725
|
+
const out = fs30.openSync(path37.join(logsDir, "dynamodb-admin.log"), "a");
|
|
29338
29726
|
spawn3(
|
|
29339
29727
|
process.execPath,
|
|
29340
29728
|
[script, "--port", String(plan2.adminPort), "--dynamo-endpoint", endpoint, "--skip-default-credentials"],
|
|
29341
29729
|
{ detached: true, stdio: ["ignore", out, out], windowsHide: true, env: { ...process.env, ...aws } }
|
|
29342
29730
|
).unref();
|
|
29343
|
-
|
|
29731
|
+
fs30.closeSync(out);
|
|
29344
29732
|
if (!await waitForPort(plan2.adminPort, 30))
|
|
29345
|
-
throw new Error("dynamodb-admin did not start; see " +
|
|
29733
|
+
throw new Error("dynamodb-admin did not start; see " + path37.join(logsDir, "dynamodb-admin.log"));
|
|
29346
29734
|
env.summary.push(
|
|
29347
29735
|
"dynamodb-admin: http://localhost:" + plan2.adminPort + " (browse and edit tables in the sandbox's browser)"
|
|
29348
29736
|
);
|
|
@@ -29350,32 +29738,7 @@ var DynamoServer = class extends DatabaseServer {
|
|
|
29350
29738
|
};
|
|
29351
29739
|
|
|
29352
29740
|
// 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
|
|
29741
|
+
import path38 from "node:path";
|
|
29379
29742
|
var MongoServer = class extends DatabaseServer {
|
|
29380
29743
|
id = "mongodb";
|
|
29381
29744
|
async start(env, plan2) {
|
|
@@ -29390,13 +29753,13 @@ var MongoServer = class extends DatabaseServer {
|
|
|
29390
29753
|
};
|
|
29391
29754
|
const version2 = await resolveCached("mongodb:" + plan2.version, async () => (await find()).version);
|
|
29392
29755
|
const home = tool("mongodb", version2);
|
|
29393
|
-
if (!exists(
|
|
29756
|
+
if (!exists(path38.join(home, "bin", "mongod.exe"))) {
|
|
29394
29757
|
const { archive } = await find();
|
|
29395
29758
|
log("Downloading MongoDB " + version2 + " (~400 MB once) ...");
|
|
29396
29759
|
await downloader.archive(archive.url, home, { sha256: archive.sha256, locate: "mongod.exe", up: 1 });
|
|
29397
29760
|
}
|
|
29398
29761
|
const shell = tool("mongosh");
|
|
29399
|
-
if (!exists(
|
|
29762
|
+
if (!exists(path38.join(shell, "mongosh.exe"))) {
|
|
29400
29763
|
await installFromGithub("mongodb-js/mongosh", /^mongosh-[\d.]+-win32-x64\.zip$/, {
|
|
29401
29764
|
dest: shell,
|
|
29402
29765
|
what: "mongosh, the MongoDB shell (~50 MB once)",
|
|
@@ -29407,17 +29770,17 @@ var MongoServer = class extends DatabaseServer {
|
|
|
29407
29770
|
await clearStaleLocks(data, ["mongod.lock"], plan2.port);
|
|
29408
29771
|
await startServer(
|
|
29409
29772
|
"mongodb",
|
|
29410
|
-
|
|
29773
|
+
path38.join(home, "bin", "mongod.exe"),
|
|
29411
29774
|
["--dbpath", data, "--bind_ip", "127.0.0.1", "--port", String(plan2.port)],
|
|
29412
29775
|
plan2.port
|
|
29413
29776
|
);
|
|
29414
|
-
env.prepend.push(
|
|
29777
|
+
env.prepend.push(path38.join(home, "bin"), shell);
|
|
29415
29778
|
env.summary.push("mongodb " + version2 + ": mongodb://127.0.0.1:" + plan2.port + " (mongosh on PATH)");
|
|
29416
29779
|
}
|
|
29417
29780
|
};
|
|
29418
29781
|
|
|
29419
29782
|
// src/guest/databases/mysql.ts
|
|
29420
|
-
import
|
|
29783
|
+
import path39 from "node:path";
|
|
29421
29784
|
var MARIA = "https://downloads.mariadb.org/rest-api/mariadb/";
|
|
29422
29785
|
var MysqlServer = class extends DatabaseServer {
|
|
29423
29786
|
id = "mysql";
|
|
@@ -29435,8 +29798,8 @@ var MysqlServer = class extends DatabaseServer {
|
|
|
29435
29798
|
};
|
|
29436
29799
|
const version2 = await resolveCached("mariadb-version:" + series, async () => (await latest()).version);
|
|
29437
29800
|
const home = tool("mariadb", version2);
|
|
29438
|
-
const bin =
|
|
29439
|
-
if (!exists(
|
|
29801
|
+
const bin = path39.join(home, "bin");
|
|
29802
|
+
if (!exists(path39.join(bin, "mariadbd.exe"))) {
|
|
29440
29803
|
const { zip } = await latest();
|
|
29441
29804
|
log("Downloading MariaDB " + version2 + " (~90 MB once) ...");
|
|
29442
29805
|
await downloader.archive(zip.file_download_url.replace(/^http:/, "https:"), home, {
|
|
@@ -29449,13 +29812,13 @@ var MysqlServer = class extends DatabaseServer {
|
|
|
29449
29812
|
const data = dataFor("mariadb");
|
|
29450
29813
|
await createOnce(data, "mysql", async () => {
|
|
29451
29814
|
log("Creating the MariaDB database (first start) ...");
|
|
29452
|
-
await execAsync(
|
|
29815
|
+
await execAsync(path39.join(bin, "mariadb-install-db.exe"), ["--datadir=" + data, "--port=" + plan2.port], {
|
|
29453
29816
|
stdio: "ignore"
|
|
29454
29817
|
});
|
|
29455
29818
|
});
|
|
29456
29819
|
await startServer(
|
|
29457
29820
|
"mysql",
|
|
29458
|
-
|
|
29821
|
+
path39.join(bin, "mariadbd.exe"),
|
|
29459
29822
|
["--datadir=" + data, "--port=" + plan2.port, "--bind-address=127.0.0.1", "--console"],
|
|
29460
29823
|
plan2.port
|
|
29461
29824
|
);
|
|
@@ -29469,7 +29832,7 @@ var MysqlServer = class extends DatabaseServer {
|
|
|
29469
29832
|
|
|
29470
29833
|
// src/guest/databases/postgres.ts
|
|
29471
29834
|
import fs31 from "node:fs";
|
|
29472
|
-
import
|
|
29835
|
+
import path40 from "node:path";
|
|
29473
29836
|
function postgresData(version2) {
|
|
29474
29837
|
return dataFor("postgres-" + version2.split(".")[0]);
|
|
29475
29838
|
}
|
|
@@ -29484,8 +29847,8 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29484
29847
|
return hit ? hit.major + "." + hit.latestMinor : Promise.reject(new Error("No supported PostgreSQL " + plan2.version));
|
|
29485
29848
|
});
|
|
29486
29849
|
const home = tool("postgres", exact);
|
|
29487
|
-
const bin =
|
|
29488
|
-
if (!exists(
|
|
29850
|
+
const bin = path40.join(home, "bin");
|
|
29851
|
+
if (!exists(path40.join(bin, "pg_ctl.exe"))) {
|
|
29489
29852
|
log("Downloading PostgreSQL " + exact + " (~330 MB once) ...");
|
|
29490
29853
|
await downloader.archive(
|
|
29491
29854
|
"https://get.enterprisedb.com/postgresql/postgresql-" + exact + "-1-windows-x64-binaries.zip",
|
|
@@ -29502,7 +29865,7 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29502
29865
|
await createOnce(data, "PG_VERSION", async () => {
|
|
29503
29866
|
log("Creating the PostgreSQL database (first start) ...");
|
|
29504
29867
|
await execAsync(
|
|
29505
|
-
|
|
29868
|
+
path40.join(bin, "initdb.exe"),
|
|
29506
29869
|
["-D", data, "-U", "postgres", "-A", "trust", "-E", "UTF8", "--locale=C"],
|
|
29507
29870
|
{ stdio: "ignore" }
|
|
29508
29871
|
);
|
|
@@ -29511,7 +29874,7 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29511
29874
|
throw new Error("port " + plan2.port + " is already in use (change databases.postgres.port)");
|
|
29512
29875
|
await clearStaleLocks(data, ["postmaster.pid"], plan2.port);
|
|
29513
29876
|
await execAsync(
|
|
29514
|
-
|
|
29877
|
+
path40.join(bin, "pg_ctl.exe"),
|
|
29515
29878
|
[
|
|
29516
29879
|
"start",
|
|
29517
29880
|
"-D",
|
|
@@ -29520,7 +29883,7 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29520
29883
|
"-t",
|
|
29521
29884
|
"60",
|
|
29522
29885
|
"-l",
|
|
29523
|
-
|
|
29886
|
+
path40.join(logsDir, "postgres.log"),
|
|
29524
29887
|
"-o",
|
|
29525
29888
|
"-p " + plan2.port + " -c listen_addresses=localhost"
|
|
29526
29889
|
],
|
|
@@ -29537,8 +29900,8 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29537
29900
|
if (exists(tool("postgres"))) {
|
|
29538
29901
|
for (const version2 of fs31.readdirSync(tool("postgres"))) {
|
|
29539
29902
|
const data = postgresData(version2);
|
|
29540
|
-
const pgCtl =
|
|
29541
|
-
if (exists(
|
|
29903
|
+
const pgCtl = path40.join(tool("postgres", version2), "bin", "pg_ctl.exe");
|
|
29904
|
+
if (exists(path40.join(data, "postmaster.pid")) && exists(pgCtl))
|
|
29542
29905
|
await execAsync(pgCtl, ["stop", "-D", data, "-m", "fast", "-w"], { stdio: "ignore" });
|
|
29543
29906
|
}
|
|
29544
29907
|
}
|
|
@@ -29547,12 +29910,12 @@ var PostgresServer = class extends DatabaseServer {
|
|
|
29547
29910
|
};
|
|
29548
29911
|
|
|
29549
29912
|
// src/guest/databases/redis.ts
|
|
29550
|
-
import
|
|
29913
|
+
import path41 from "node:path";
|
|
29551
29914
|
var RedisServer = class extends DatabaseServer {
|
|
29552
29915
|
id = "redis";
|
|
29553
29916
|
async start(env, plan2) {
|
|
29554
29917
|
const home = tool("redis");
|
|
29555
|
-
if (!exists(
|
|
29918
|
+
if (!exists(path41.join(home, "redis-server.exe"))) {
|
|
29556
29919
|
await installFromGithub("redis-windows/redis-windows", /^Redis-[\d.]+-Windows-x64-msys2\.zip$/, {
|
|
29557
29920
|
dest: home,
|
|
29558
29921
|
what: (a) => "Redis (" + a.name + ", ~10 MB once)",
|
|
@@ -29562,7 +29925,7 @@ var RedisServer = class extends DatabaseServer {
|
|
|
29562
29925
|
const data = mkdirp(dataFor("redis"));
|
|
29563
29926
|
await startServer(
|
|
29564
29927
|
"redis",
|
|
29565
|
-
|
|
29928
|
+
path41.join(home, "redis-server.exe"),
|
|
29566
29929
|
["--port", String(plan2.port), "--bind", "127.0.0.1", "--dir", data.replace(/\\/g, "/"), "--appendonly", "yes"],
|
|
29567
29930
|
plan2.port
|
|
29568
29931
|
);
|
|
@@ -29601,15 +29964,15 @@ async function setupDatabase(env, plan2) {
|
|
|
29601
29964
|
|
|
29602
29965
|
// src/guest/toolchains/tools/git.ts
|
|
29603
29966
|
import fs33 from "node:fs";
|
|
29604
|
-
import
|
|
29967
|
+
import path43 from "node:path";
|
|
29605
29968
|
|
|
29606
29969
|
// src/guest/runtime/csc.ts
|
|
29607
29970
|
import fs32 from "node:fs";
|
|
29608
29971
|
import os6 from "node:os";
|
|
29609
|
-
import
|
|
29972
|
+
import path42 from "node:path";
|
|
29610
29973
|
import crypto3 from "node:crypto";
|
|
29611
29974
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
29612
|
-
var CSC =
|
|
29975
|
+
var CSC = path42.join(process.env.WINDIR ?? "C:\\Windows", "Microsoft.NET", "Framework64", "v4.0.30319", "csc.exe");
|
|
29613
29976
|
var SOURCES = {
|
|
29614
29977
|
ptyhost: "PtyHost.cs",
|
|
29615
29978
|
gitshim: "GitShim.cs",
|
|
@@ -29621,17 +29984,17 @@ var SOURCES = {
|
|
|
29621
29984
|
memgov: "MemGov.cs"
|
|
29622
29985
|
};
|
|
29623
29986
|
function sourceOf(name) {
|
|
29624
|
-
return
|
|
29987
|
+
return path42.join(launchDir, "sandbox", "csharp", SOURCES[name]);
|
|
29625
29988
|
}
|
|
29626
29989
|
function sourceHash(name) {
|
|
29627
29990
|
return crypto3.createHash("sha256").update(fs32.readFileSync(sourceOf(name))).digest("hex").slice(0, 12);
|
|
29628
29991
|
}
|
|
29629
29992
|
function ensureCompiled(name) {
|
|
29630
|
-
const exe =
|
|
29993
|
+
const exe = path42.join(os6.tmpdir(), "agent-sandbox", name + "-" + sourceHash(name) + ".exe");
|
|
29631
29994
|
if (exists(exe)) return exe;
|
|
29632
29995
|
if (!exists(CSC))
|
|
29633
29996
|
throw new Error("The .NET Framework C# compiler was not found at " + CSC + " (it ships with Windows 10/11).");
|
|
29634
|
-
mkdirp(
|
|
29997
|
+
mkdirp(path42.dirname(exe));
|
|
29635
29998
|
const result = spawnSync5(CSC, ["/nologo", "/optimize", "/target:exe", "/out:" + exe, sourceOf(name)], {
|
|
29636
29999
|
encoding: "utf8",
|
|
29637
30000
|
windowsHide: true
|
|
@@ -29670,18 +30033,18 @@ var installPortableGit = async (root) => {
|
|
|
29670
30033
|
};
|
|
29671
30034
|
var installGuard = (env, access, realGit) => {
|
|
29672
30035
|
const dir = mkdirp(tool("gitguard"));
|
|
29673
|
-
const guard =
|
|
29674
|
-
if (duringSession() && (exists(
|
|
30036
|
+
const guard = path43.join(launchDir, "runtime", "gitguard.js");
|
|
30037
|
+
if (duringSession() && (exists(path43.join(dir, "git.exe")) || exists(path43.join(dir, "git.cmd")))) {
|
|
29675
30038
|
} else
|
|
29676
30039
|
try {
|
|
29677
|
-
fs33.copyFileSync(ensureCompiled("gitshim"),
|
|
29678
|
-
fs33.rmSync(
|
|
30040
|
+
fs33.copyFileSync(ensureCompiled("gitshim"), path43.join(dir, "git.exe"));
|
|
30041
|
+
fs33.rmSync(path43.join(dir, "git.cmd"), { force: true });
|
|
29679
30042
|
} catch (e) {
|
|
29680
30043
|
warn("git guard: falling back to git.cmd (" + errMsg(e) + ")");
|
|
29681
|
-
fs33.writeFileSync(
|
|
30044
|
+
fs33.writeFileSync(path43.join(dir, "git.cmd"), '@"' + process.execPath + '" "' + guard + '" %*\r\n');
|
|
29682
30045
|
}
|
|
29683
30046
|
fs33.writeFileSync(
|
|
29684
|
-
|
|
30047
|
+
path43.join(dir, "bashenv.sh"),
|
|
29685
30048
|
'git() { "' + posix(process.execPath) + '" "' + posix(guard) + '" "$@"; }\nexport -f git\n'
|
|
29686
30049
|
);
|
|
29687
30050
|
env.prepend.unshift(dir);
|
|
@@ -29690,13 +30053,13 @@ var installGuard = (env, access, realGit) => {
|
|
|
29690
30053
|
AGENT_REAL_GIT: access === "readonly" ? realGit : "",
|
|
29691
30054
|
AGENT_GUARD_NODE: process.execPath,
|
|
29692
30055
|
AGENT_GUARD_SCRIPT: guard,
|
|
29693
|
-
BASH_ENV: posix(
|
|
30056
|
+
BASH_ENV: posix(path43.join(dir, "bashenv.sh"))
|
|
29694
30057
|
});
|
|
29695
30058
|
if (access === "readonly") {
|
|
29696
|
-
const hooks = mkdirp(
|
|
30059
|
+
const hooks = mkdirp(path43.join(dir, "hooks"));
|
|
29697
30060
|
for (const hook of BLOCKED_HOOKS)
|
|
29698
30061
|
fs33.writeFileSync(
|
|
29699
|
-
|
|
30062
|
+
path43.join(hooks, hook),
|
|
29700
30063
|
'#!/bin/sh\necho "git is read-only in this sandbox: ' + hook + ' refused." >&2\nexit 1\n'
|
|
29701
30064
|
);
|
|
29702
30065
|
Object.assign(env.vars, {
|
|
@@ -29705,12 +30068,12 @@ var installGuard = (env, access, realGit) => {
|
|
|
29705
30068
|
GIT_CONFIG_VALUE_0: posix(hooks)
|
|
29706
30069
|
});
|
|
29707
30070
|
} else {
|
|
29708
|
-
env.vars.GIT_DIR =
|
|
30071
|
+
env.vars.GIT_DIR = path43.join(dataDir, "git-disabled");
|
|
29709
30072
|
}
|
|
29710
30073
|
};
|
|
29711
30074
|
var pointAtOwnCertificates = (root) => {
|
|
29712
|
-
const config2 =
|
|
29713
|
-
const bundle =
|
|
30075
|
+
const config2 = path43.join(root, "etc", "gitconfig");
|
|
30076
|
+
const bundle = path43.join(root, "mingw64", "etc", "ssl", "certs", "ca-bundle.crt");
|
|
29714
30077
|
if (!exists(config2) || !exists(bundle)) return;
|
|
29715
30078
|
const text = fs33.readFileSync(config2, "utf8");
|
|
29716
30079
|
const fixed = text.replace(/^(\s*sslCAInfo\s*=\s*).*$/gim, (_m, key2) => key2 + posix(bundle));
|
|
@@ -29718,9 +30081,9 @@ var pointAtOwnCertificates = (root) => {
|
|
|
29718
30081
|
};
|
|
29719
30082
|
async function setupGit(env, hostCopy, refresh, access) {
|
|
29720
30083
|
const root = tool("git");
|
|
29721
|
-
const bash =
|
|
29722
|
-
const gitExe =
|
|
29723
|
-
const hostGit =
|
|
30084
|
+
const bash = path43.join(root, "bin", "bash.exe");
|
|
30085
|
+
const gitExe = path43.join(root, "cmd", "git.exe");
|
|
30086
|
+
const hostGit = path43.join(hostToolsDir, "git");
|
|
29724
30087
|
if (exists(root) && !exists(bash)) {
|
|
29725
30088
|
log("Replacing the old MinGit (no bash) with full Git for Windows.");
|
|
29726
30089
|
safeRemove(root, toolsDir);
|
|
@@ -29734,11 +30097,11 @@ async function setupGit(env, hostCopy, refresh, access) {
|
|
|
29734
30097
|
}
|
|
29735
30098
|
const work = stagingFolder(root);
|
|
29736
30099
|
try {
|
|
29737
|
-
if (hostCopy && exists(
|
|
30100
|
+
if (hostCopy && exists(path43.join(hostGit, "bin", "bash.exe"))) {
|
|
29738
30101
|
log("Copying Git for Windows from this PC ...");
|
|
29739
30102
|
robocopy(hostGit, work);
|
|
29740
30103
|
} else await installPortableGit(work);
|
|
29741
|
-
if (!exists(
|
|
30104
|
+
if (!exists(path43.join(work, "bin", "bash.exe"))) throw new Error("bash.exe missing after installing Git");
|
|
29742
30105
|
moveIntoPlace(work, root);
|
|
29743
30106
|
} finally {
|
|
29744
30107
|
safeRemove(work, toolsDir);
|
|
@@ -29747,10 +30110,10 @@ async function setupGit(env, hostCopy, refresh, access) {
|
|
|
29747
30110
|
if (!exists(bash)) throw new Error("bash.exe missing after installing Git");
|
|
29748
30111
|
pointAtOwnCertificates(root);
|
|
29749
30112
|
env.vars.CLAUDE_CODE_GIT_BASH_PATH = bash;
|
|
29750
|
-
env.append.push(
|
|
30113
|
+
env.append.push(path43.join(root, "usr", "bin"));
|
|
29751
30114
|
const version2 = execOutput(gitExe, ["--version"]).replace(/^git version /, "");
|
|
29752
30115
|
if (access === "full") {
|
|
29753
|
-
env.prepend.push(
|
|
30116
|
+
env.prepend.push(path43.join(root, "cmd"));
|
|
29754
30117
|
env.summary.push("git: " + version2);
|
|
29755
30118
|
return;
|
|
29756
30119
|
}
|
|
@@ -29762,7 +30125,7 @@ async function setupGit(env, hostCopy, refresh, access) {
|
|
|
29762
30125
|
|
|
29763
30126
|
// src/guest/toolchains/languages/go.ts
|
|
29764
30127
|
import fs34 from "node:fs";
|
|
29765
|
-
import
|
|
30128
|
+
import path44 from "node:path";
|
|
29766
30129
|
|
|
29767
30130
|
// src/guest/toolchains/package-ledger.ts
|
|
29768
30131
|
var LedgerSchema = external_exports.record(external_exports.string(), external_exports.string());
|
|
@@ -29816,7 +30179,7 @@ async function setupGo(env, config2) {
|
|
|
29816
30179
|
}
|
|
29817
30180
|
const version2 = await resolveCached("go:" + config2.version, async () => (await findRelease(config2.version)).version);
|
|
29818
30181
|
const root = tool("go", version2);
|
|
29819
|
-
if (!exists(
|
|
30182
|
+
if (!exists(path44.join(root, "bin", "go.exe"))) {
|
|
29820
30183
|
const goArch = arch === "arm64" ? "arm64" : "amd64";
|
|
29821
30184
|
const file3 = (await findRelease(version2)).files.find(
|
|
29822
30185
|
(f) => f.os === "windows" && f.arch === goArch && f.kind === "archive"
|
|
@@ -29833,16 +30196,16 @@ async function setupGo(env, config2) {
|
|
|
29833
30196
|
const vars = {
|
|
29834
30197
|
GOROOT: root,
|
|
29835
30198
|
GOPATH,
|
|
29836
|
-
GOBIN:
|
|
29837
|
-
GOMODCACHE:
|
|
30199
|
+
GOBIN: path44.join(GOPATH, "bin"),
|
|
30200
|
+
GOMODCACHE: path44.join(GOPATH, "pkg", "mod"),
|
|
29838
30201
|
GOCACHE: tool("go-cache"),
|
|
29839
30202
|
GOTOOLCHAIN: "auto",
|
|
29840
30203
|
GOTELEMETRY: "off"
|
|
29841
30204
|
};
|
|
29842
30205
|
fs34.mkdirSync(vars.GOBIN, { recursive: true });
|
|
29843
30206
|
Object.assign(env.vars, vars);
|
|
29844
|
-
env.prepend.push(
|
|
29845
|
-
const go =
|
|
30207
|
+
env.prepend.push(path44.join(root, "bin"), vars.GOBIN);
|
|
30208
|
+
const go = path44.join(root, "bin", "go.exe");
|
|
29846
30209
|
env.summary.push("go: " + versionOf(go, ["version"]));
|
|
29847
30210
|
await installOnce(
|
|
29848
30211
|
env,
|
|
@@ -29900,77 +30263,6 @@ function decideCli(settings, ctx) {
|
|
|
29900
30263
|
return Object.fromEntries(CLI_NAMES.map((name) => [name, decide2(name)]));
|
|
29901
30264
|
}
|
|
29902
30265
|
|
|
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
30266
|
// src/guest/toolchains/tools/cli.ts
|
|
29975
30267
|
function ghConfigDir() {
|
|
29976
30268
|
return path45.join(stateDir, "gh");
|
|
@@ -31610,7 +31902,12 @@ function plan(config2, versions, o) {
|
|
|
31610
31902
|
},
|
|
31611
31903
|
{ name: "Deno", enabled: wanted(config2.deno.enabled, "deno"), install: (env) => setupDeno(env) },
|
|
31612
31904
|
{ name: "Bun", enabled: wanted(config2.bun.enabled, "bun"), install: (env) => setupBun(env) },
|
|
31613
|
-
|
|
31905
|
+
// Headroom (an agent add-on) installs with uv: the uv step runs for it too, before the apps.
|
|
31906
|
+
{
|
|
31907
|
+
name: "uv",
|
|
31908
|
+
enabled: wanted(config2.uv.enabled, "uv") || appsNeedUv(o.apps),
|
|
31909
|
+
install: (env) => setupUv(env)
|
|
31910
|
+
},
|
|
31614
31911
|
{ name: "PowerShell 7", enabled: wanted(config2.pwsh.enabled, "pwsh"), install: (env) => setupPwsh(env, o.refresh) },
|
|
31615
31912
|
// The openssl tool comes from Git's install: after Git.
|
|
31616
31913
|
{
|
|
@@ -31636,7 +31933,7 @@ function plan(config2, versions, o) {
|
|
|
31636
31933
|
name: "Apps",
|
|
31637
31934
|
enabled: apps,
|
|
31638
31935
|
shared: true,
|
|
31639
|
-
after: ["Mesa 3D", "Visual C++ runtime"],
|
|
31936
|
+
after: ["Mesa 3D", "Visual C++ runtime", "uv"],
|
|
31640
31937
|
install: (env) => setupApps(env, o.apps, { gitAccess: o.gitAccess, refresh: o.refresh })
|
|
31641
31938
|
},
|
|
31642
31939
|
{
|
|
@@ -31820,6 +32117,7 @@ async function setupToolchains(config2, versions, options, run2 = {}) {
|
|
|
31820
32117
|
env.summary.push(...part.summary);
|
|
31821
32118
|
}
|
|
31822
32119
|
Object.assign(env.vars, config2.environment);
|
|
32120
|
+
Object.assign(env.vars, envs.get("Git")?.vars);
|
|
31823
32121
|
log("Set up " + steps.length + " toolchains and databases.");
|
|
31824
32122
|
return env;
|
|
31825
32123
|
}
|
|
@@ -32016,6 +32314,7 @@ function execCommand(req) {
|
|
|
32016
32314
|
}
|
|
32017
32315
|
|
|
32018
32316
|
// src/guest/daemon/sessions.ts
|
|
32317
|
+
import fs53 from "node:fs";
|
|
32019
32318
|
import path68 from "node:path";
|
|
32020
32319
|
import crypto4 from "node:crypto";
|
|
32021
32320
|
import os11 from "node:os";
|
|
@@ -32028,6 +32327,8 @@ var FrameType = {
|
|
|
32028
32327
|
Resize: 3,
|
|
32029
32328
|
Restart: 4,
|
|
32030
32329
|
Ping: 5,
|
|
32330
|
+
/** Ends the program and everything it started, and with it the session. */
|
|
32331
|
+
Close: 6,
|
|
32031
32332
|
Output: 16,
|
|
32032
32333
|
Exit: 17,
|
|
32033
32334
|
Error: 18,
|
|
@@ -32111,6 +32412,16 @@ function cmdArgs(args) {
|
|
|
32111
32412
|
function commandLine(file3, args) {
|
|
32112
32413
|
return path64.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
|
|
32113
32414
|
}
|
|
32415
|
+
function shellLaunch(asked, paths) {
|
|
32416
|
+
if (asked === "cmd") return { name: "cmd", file: paths.cmd, args: [] };
|
|
32417
|
+
if (asked === "powershell" || asked === "auto" && !paths.pwsh)
|
|
32418
|
+
return { name: "powershell", file: paths.powershell, args: ["-NoLogo"] };
|
|
32419
|
+
if (!paths.pwsh)
|
|
32420
|
+
throw new Error(
|
|
32421
|
+
"PowerShell 7 is not installed in this sandbox (toolchains.pwsh). Open powershell or cmd instead, or turn pwsh on."
|
|
32422
|
+
);
|
|
32423
|
+
return { name: "pwsh", file: paths.pwsh, args: ["-NoLogo"] };
|
|
32424
|
+
}
|
|
32114
32425
|
|
|
32115
32426
|
// src/guest/sessions/pty-host.ts
|
|
32116
32427
|
import fs50 from "node:fs";
|
|
@@ -32330,6 +32641,8 @@ var IdleShutdown = class {
|
|
|
32330
32641
|
};
|
|
32331
32642
|
|
|
32332
32643
|
// src/guest/daemon/sessions.ts
|
|
32644
|
+
var CLOSE_WAIT_MS = 8e3;
|
|
32645
|
+
var ROOTS_KEPT_MS = 10 * 60 * 1e3;
|
|
32333
32646
|
function terminalTab(id, title, cwd) {
|
|
32334
32647
|
const view = [process.execPath, path68.join(path68.dirname(process.argv[1]), "view.js"), id];
|
|
32335
32648
|
const wt = path68.join(toolsDir, "terminal", "wt.exe");
|
|
@@ -32374,14 +32687,38 @@ function writeBudget(cpus, memoryGb, jobs, env) {
|
|
|
32374
32687
|
warn("budget.json could not be written: " + errMsg(e));
|
|
32375
32688
|
}
|
|
32376
32689
|
}
|
|
32377
|
-
var
|
|
32690
|
+
var agentProgram = async (req, env, say) => {
|
|
32378
32691
|
const harness = harnessFor(req);
|
|
32379
32692
|
say("Preparing " + req.harness);
|
|
32380
32693
|
await agents.provision(req.harness, harness, env, false);
|
|
32381
32694
|
const launch = agents.resolveLaunch(req.harness, harness);
|
|
32382
32695
|
const base = [...launch.args, ...harness.arguments];
|
|
32696
|
+
return {
|
|
32697
|
+
command: commandLine(launch.file, [...base, ...req.args]),
|
|
32698
|
+
restartCommand: commandLine(launch.file, [...base, ...harness.resumeArguments ?? []]),
|
|
32699
|
+
environment: harness.environment
|
|
32700
|
+
};
|
|
32701
|
+
};
|
|
32702
|
+
function shellPaths() {
|
|
32703
|
+
const candidates = [
|
|
32704
|
+
path68.join(pwshDir(), "pwsh.exe"),
|
|
32705
|
+
path68.join(process.env.ProgramFiles ?? "C:\\Program Files", "PowerShell", "7", "pwsh.exe")
|
|
32706
|
+
];
|
|
32707
|
+
return { pwsh: candidates.find((f) => fs53.existsSync(f)) ?? null, powershell: SYSTEM.powershell(), cmd: SYSTEM.cmd() };
|
|
32708
|
+
}
|
|
32709
|
+
var shellProgram = (shell) => {
|
|
32710
|
+
const line = commandLine(shell.file, shell.args);
|
|
32711
|
+
return { command: line, restartCommand: line, environment: {} };
|
|
32712
|
+
};
|
|
32713
|
+
var launchPtyHost = async (req, program, remote, env, sessions2, onSpawn) => {
|
|
32383
32714
|
const port = await freePort();
|
|
32384
32715
|
const token = crypto4.randomBytes(24).toString("base64url");
|
|
32716
|
+
const sessionEnv = {
|
|
32717
|
+
...withRegistryPath(env),
|
|
32718
|
+
...program.environment,
|
|
32719
|
+
...memoryEnv(env, sessions2)
|
|
32720
|
+
};
|
|
32721
|
+
if (req.shell) delete sessionEnv.PSModulePath;
|
|
32385
32722
|
const child = startPtyHost({
|
|
32386
32723
|
exe: ensurePtyHost(),
|
|
32387
32724
|
port,
|
|
@@ -32390,11 +32727,12 @@ var launchPtyHost = async (req, remote, env, say, sessions2) => {
|
|
|
32390
32727
|
rows: 32,
|
|
32391
32728
|
id: req.id,
|
|
32392
32729
|
cwd: req.cwd,
|
|
32393
|
-
env:
|
|
32730
|
+
env: sessionEnv,
|
|
32394
32731
|
remote,
|
|
32395
|
-
command:
|
|
32396
|
-
restartCommand:
|
|
32732
|
+
command: program.command,
|
|
32733
|
+
restartCommand: program.restartCommand
|
|
32397
32734
|
});
|
|
32735
|
+
onSpawn(child);
|
|
32398
32736
|
try {
|
|
32399
32737
|
await waitForPtyHost(child, port, 15e3);
|
|
32400
32738
|
} catch (e) {
|
|
@@ -32407,6 +32745,17 @@ var launchPtyHost = async (req, remote, env, say, sessions2) => {
|
|
|
32407
32745
|
};
|
|
32408
32746
|
var placeFor = async (req, say) => {
|
|
32409
32747
|
if (!req.project) {
|
|
32748
|
+
const known = insidePrimary(req.cwd) ? null : provisioner.provisionedFor(req.cwd);
|
|
32749
|
+
if (known && exists(req.cwd))
|
|
32750
|
+
return {
|
|
32751
|
+
env: known.env,
|
|
32752
|
+
hooks: known.spec.hooks ? projectHooks(known.spec.name, known.spec.workspace) : null,
|
|
32753
|
+
project: known.spec.name
|
|
32754
|
+
};
|
|
32755
|
+
if (!insidePrimary(req.cwd) && insideWorkspace(req.cwd))
|
|
32756
|
+
throw new Error(
|
|
32757
|
+
"The project in " + req.cwd + " is not set up in the sandbox yet: run sandbox start in its folder first."
|
|
32758
|
+
);
|
|
32410
32759
|
if (!insidePrimary(req.cwd) || !exists(req.cwd))
|
|
32411
32760
|
throw new Error("Folder is not inside the sandbox workspace " + workspace + ": " + req.cwd);
|
|
32412
32761
|
return { env: process.env, hooks: null, project: primaryProject() };
|
|
@@ -32434,20 +32783,49 @@ var SessionManager = class {
|
|
|
32434
32783
|
/** Sessions and projects being set up right now (a headless sandbox must not shut down under them). */
|
|
32435
32784
|
starting = 0;
|
|
32436
32785
|
idle = new IdleShutdown(() => this.live.size > 0 || this.starting > 0);
|
|
32786
|
+
/** Each session's ptyhost (process id and when it ran), for linking the programs it starts to it (audit). */
|
|
32787
|
+
ptyHosts = /* @__PURE__ */ new Map();
|
|
32437
32788
|
/** How many sessions are running. */
|
|
32438
32789
|
get count() {
|
|
32439
32790
|
return this.live.size;
|
|
32440
32791
|
}
|
|
32441
|
-
/**
|
|
32792
|
+
/** The sessions' ptyhosts, running or ended within ROOTS_KEPT_MS (audit events arrive after they happen). */
|
|
32793
|
+
roots() {
|
|
32794
|
+
const cutoff = Date.now() - ROOTS_KEPT_MS;
|
|
32795
|
+
for (const [id, r] of this.ptyHosts) if (r.to !== void 0 && r.to < cutoff) this.ptyHosts.delete(id);
|
|
32796
|
+
return [...this.ptyHosts.values()];
|
|
32797
|
+
}
|
|
32798
|
+
rootStarted(id, child, from) {
|
|
32799
|
+
if (child.pid) this.ptyHosts.set(id, { session: id, pid: child.pid, from });
|
|
32800
|
+
child.once("exit", () => this.rootEnded(id));
|
|
32801
|
+
}
|
|
32802
|
+
rootEnded(id) {
|
|
32803
|
+
const r = this.ptyHosts.get(id);
|
|
32804
|
+
if (r && r.to === void 0) this.ptyHosts.set(id, { ...r, to: Date.now() });
|
|
32805
|
+
}
|
|
32806
|
+
/**
|
|
32807
|
+
* `session` requests: an agent (or a plain shell) in its own ptyhost, in the launch folder's project or a registered
|
|
32808
|
+
* one.
|
|
32809
|
+
*/
|
|
32442
32810
|
async start(req) {
|
|
32811
|
+
let shell = null;
|
|
32812
|
+
let problem = null;
|
|
32813
|
+
if (req.shell)
|
|
32814
|
+
try {
|
|
32815
|
+
shell = shellLaunch(req.shell, shellPaths());
|
|
32816
|
+
} catch (e) {
|
|
32817
|
+
problem = errMsg(e);
|
|
32818
|
+
}
|
|
32819
|
+
const name = shell?.name ?? (req.shell ? "shell" : req.harness);
|
|
32443
32820
|
let status = {
|
|
32444
32821
|
id: req.id,
|
|
32445
32822
|
launchId: session.launchId,
|
|
32446
|
-
harness:
|
|
32823
|
+
harness: name,
|
|
32824
|
+
...req.shell ? { kind: "shell" } : {},
|
|
32447
32825
|
cwd: req.cwd,
|
|
32448
32826
|
...req.project ? { project: req.project.name } : {},
|
|
32449
32827
|
phase: "starting",
|
|
32450
|
-
message: "Starting " +
|
|
32828
|
+
message: "Starting " + name,
|
|
32451
32829
|
updatedAt: now(),
|
|
32452
32830
|
startedAt: now()
|
|
32453
32831
|
};
|
|
@@ -32458,28 +32836,40 @@ var SessionManager = class {
|
|
|
32458
32836
|
};
|
|
32459
32837
|
this.starting++;
|
|
32460
32838
|
if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1")
|
|
32461
|
-
safely("terminal tab", () => terminalTab(req.id,
|
|
32839
|
+
safely("terminal tab", () => terminalTab(req.id, name + " " + path68.basename(req.cwd), req.cwd));
|
|
32462
32840
|
try {
|
|
32841
|
+
if (problem) throw new Error(problem);
|
|
32463
32842
|
const place = await placeFor(req, say);
|
|
32843
|
+
const program = shell ? shellProgram(shell) : await agentProgram(req, place.env, say);
|
|
32464
32844
|
const remote = session.networking && session.attach.enabled;
|
|
32465
|
-
const
|
|
32466
|
-
const
|
|
32845
|
+
const from = Date.now();
|
|
32846
|
+
const { child, port, token } = await launchPtyHost(
|
|
32847
|
+
req,
|
|
32848
|
+
program,
|
|
32849
|
+
remote,
|
|
32850
|
+
place.env,
|
|
32851
|
+
this.live.size + 1,
|
|
32852
|
+
(c) => this.rootStarted(req.id, c, from)
|
|
32853
|
+
);
|
|
32854
|
+
const agent = shell === null;
|
|
32855
|
+
const resumed = agent && req.harness === "claude" ? resumedConversation(req.args) : void 0;
|
|
32467
32856
|
const running = {
|
|
32468
32857
|
...status,
|
|
32469
32858
|
...resumed ? { conversation: resumed } : {},
|
|
32470
32859
|
project: place.project,
|
|
32471
32860
|
phase: "running",
|
|
32472
|
-
message:
|
|
32861
|
+
message: name + " is running",
|
|
32473
32862
|
attach: { addresses: remote ? guestAddresses() : [], port, token }
|
|
32474
32863
|
};
|
|
32475
32864
|
this.live.set(req.id, { status: running, child });
|
|
32476
32865
|
child.once("exit", (code) => this.onExit(running, place, code));
|
|
32477
32866
|
saveStatus(running);
|
|
32478
|
-
if (req.harness === "claude") this.trackConversation(running.id, resumed);
|
|
32867
|
+
if (agent && req.harness === "claude") this.trackConversation(running.id, resumed);
|
|
32479
32868
|
log(
|
|
32480
|
-
"Session " + req.id + " started (" +
|
|
32869
|
+
"Session " + req.id + " started (" + name + " in " + req.cwd + ", project " + place.project + ", port " + port + ")"
|
|
32481
32870
|
);
|
|
32482
32871
|
} catch (e) {
|
|
32872
|
+
this.rootEnded(req.id);
|
|
32483
32873
|
saveStatus({ ...status, phase: "failed", message: errMsg(e) });
|
|
32484
32874
|
warn("Session " + req.id + " failed: " + errMsg(e));
|
|
32485
32875
|
this.idle.check();
|
|
@@ -32505,10 +32895,13 @@ var SessionManager = class {
|
|
|
32505
32895
|
this.idle.check();
|
|
32506
32896
|
}
|
|
32507
32897
|
}
|
|
32508
|
-
/**
|
|
32898
|
+
/**
|
|
32899
|
+
* `restart` requests: the matching sessions restart their agent (continuing the conversation where it can). Shells
|
|
32900
|
+
* are left alone: restarting one would only throw away what it was doing.
|
|
32901
|
+
*/
|
|
32509
32902
|
async restart(req) {
|
|
32510
32903
|
const targets = [...this.live.values()].filter(
|
|
32511
|
-
(s) => s.status.attach && (req.harness === null || s.status.harness === req.harness) && (!req.cwd || isWithin(req.cwd, s.status.cwd))
|
|
32904
|
+
(s) => s.status.attach && s.status.kind !== "shell" && (req.harness === null || s.status.harness === req.harness) && (!req.cwd || isWithin(req.cwd, s.status.cwd))
|
|
32512
32905
|
);
|
|
32513
32906
|
for (const s of targets)
|
|
32514
32907
|
await sendControl(
|
|
@@ -32517,6 +32910,41 @@ var SessionManager = class {
|
|
|
32517
32910
|
);
|
|
32518
32911
|
respond(req.id, { ok: true, message: "restarted " + targets.length + " session(s)" });
|
|
32519
32912
|
}
|
|
32913
|
+
/**
|
|
32914
|
+
* `close` requests: the session's ptyhost ends its program and everything it started (ProcessTree), then exits as
|
|
32915
|
+
* if the program had. One that does not end in time has its ptyhost ended instead (closing the pseudo console ends
|
|
32916
|
+
* what is attached to it).
|
|
32917
|
+
*/
|
|
32918
|
+
async close(req) {
|
|
32919
|
+
const entry = this.live.get(req.session);
|
|
32920
|
+
if (!entry?.status.attach) {
|
|
32921
|
+
respond(req.id, { ok: false, message: "Session " + req.session + " is not running." });
|
|
32922
|
+
return;
|
|
32923
|
+
}
|
|
32924
|
+
const { child, status } = entry;
|
|
32925
|
+
const ended = new Promise((resolve2) => {
|
|
32926
|
+
if (child.exitCode !== null || child.signalCode !== null) return resolve2(true);
|
|
32927
|
+
const timer = setTimeout(() => resolve2(false), CLOSE_WAIT_MS);
|
|
32928
|
+
child.once("exit", () => {
|
|
32929
|
+
clearTimeout(timer);
|
|
32930
|
+
resolve2(true);
|
|
32931
|
+
});
|
|
32932
|
+
});
|
|
32933
|
+
try {
|
|
32934
|
+
await sendControl(
|
|
32935
|
+
{ addresses: ["127.0.0.1"], port: status.attach.port, token: status.attach.token },
|
|
32936
|
+
FrameType.Close
|
|
32937
|
+
);
|
|
32938
|
+
} catch (e) {
|
|
32939
|
+
warn("Session " + req.session + " did not take the close request: " + errMsg(e));
|
|
32940
|
+
}
|
|
32941
|
+
if (!await ended) {
|
|
32942
|
+
warn("Session " + req.session + " did not end in time; ending its session host.");
|
|
32943
|
+
safely("ending a session host", () => child.kill());
|
|
32944
|
+
}
|
|
32945
|
+
log("Session " + req.session + " closed on request");
|
|
32946
|
+
respond(req.id, { ok: true, message: "Closed " + status.harness + " session " + req.session + "." });
|
|
32947
|
+
}
|
|
32520
32948
|
/**
|
|
32521
32949
|
* Finds out which of Claude's conversation files this session writes (it appears with the first message) and puts
|
|
32522
32950
|
* it in the status, so the host can reopen this very conversation. A reopened session starts with the one it was
|
|
@@ -32559,6 +32987,10 @@ var SessionManager = class {
|
|
|
32559
32987
|
attach: void 0
|
|
32560
32988
|
});
|
|
32561
32989
|
log("Session " + running.id + " ended (exit " + code + ")");
|
|
32990
|
+
if (running.kind === "shell") {
|
|
32991
|
+
this.idle.check();
|
|
32992
|
+
return;
|
|
32993
|
+
}
|
|
32562
32994
|
if (place.hooks)
|
|
32563
32995
|
void runHooksAsync("post-agent", place.env, place.hooks).catch(
|
|
32564
32996
|
(e) => warn("post-agent hooks failed: " + errMsg(e))
|
|
@@ -32898,7 +33330,7 @@ var GovernorCore = class {
|
|
|
32898
33330
|
};
|
|
32899
33331
|
|
|
32900
33332
|
// src/guest/governor/governor.ts
|
|
32901
|
-
import
|
|
33333
|
+
import fs54 from "node:fs";
|
|
32902
33334
|
import os12 from "node:os";
|
|
32903
33335
|
import path69 from "node:path";
|
|
32904
33336
|
import { spawn as spawn8 } from "node:child_process";
|
|
@@ -32971,11 +33403,11 @@ var MemGovProcess = class {
|
|
|
32971
33403
|
function appendToMemoryLog(line) {
|
|
32972
33404
|
try {
|
|
32973
33405
|
const logs = path69.join(dataDir, "logs");
|
|
32974
|
-
const newest =
|
|
33406
|
+
const newest = fs54.readdirSync(logs).filter((f) => /^memory-\d{8}-\d{6}\.log$/.test(f)).sort().pop();
|
|
32975
33407
|
if (!newest) return;
|
|
32976
33408
|
const t = /* @__PURE__ */ new Date();
|
|
32977
33409
|
const stamp = [t.getHours(), t.getMinutes(), t.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
|
|
32978
|
-
|
|
33410
|
+
fs54.appendFileSync(path69.join(logs, newest), stamp + " | " + line + "\r\n");
|
|
32979
33411
|
} catch {
|
|
32980
33412
|
}
|
|
32981
33413
|
}
|
|
@@ -33032,9 +33464,9 @@ var Daemon = class {
|
|
|
33032
33464
|
tick() {
|
|
33033
33465
|
const { valid, invalid } = run.scanRequests();
|
|
33034
33466
|
for (const file3 of invalid)
|
|
33035
|
-
safely("removing an invalid request", () =>
|
|
33467
|
+
safely("removing an invalid request", () => fs55.rmSync(file3, { recursive: true, force: true }));
|
|
33036
33468
|
for (const req of valid) {
|
|
33037
|
-
safely("claiming a request", () =>
|
|
33469
|
+
safely("claiming a request", () => fs55.rmSync(run.requestFile(req.id), { force: true }));
|
|
33038
33470
|
if (run.readSession(req.id)) continue;
|
|
33039
33471
|
void Promise.resolve(this.handle(withRequestSecrets(req))).catch(
|
|
33040
33472
|
(e) => respond(req.id, { ok: false, message: errMsg(e) })
|
|
@@ -33056,6 +33488,8 @@ var Daemon = class {
|
|
|
33056
33488
|
return execCommand(req);
|
|
33057
33489
|
case "restart":
|
|
33058
33490
|
return sessions.restart(req);
|
|
33491
|
+
case "close":
|
|
33492
|
+
return sessions.close(req);
|
|
33059
33493
|
case "pressure":
|
|
33060
33494
|
return governor.hostPressure(req.seconds, req.reason, req.level ?? "slow");
|
|
33061
33495
|
case "ping":
|
|
@@ -33070,7 +33504,7 @@ process.on("unhandledRejection", (e) => warn("daemon: unexpected error (continui
|
|
|
33070
33504
|
adoptBootSecrets();
|
|
33071
33505
|
log("Session daemon started (pid " + process.pid + ").");
|
|
33072
33506
|
safely("port forwards", startRelays);
|
|
33073
|
-
safely("audit", startProcessCollector);
|
|
33507
|
+
safely("audit", () => startProcessCollector(() => sessions.roots()));
|
|
33074
33508
|
safely("memory governor", () => governor.start());
|
|
33075
33509
|
log("Memory governor: " + governor.describe());
|
|
33076
33510
|
new Daemon().start();
|