windows-development-sandbox 1.12.0 → 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 +1 -0
- package/config.example.json +11 -1
- 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.def.js +1 -0
- package/dist/app/features/audit/audit.def.d.ts +11 -2
- package/dist/app/features/audit/audit.def.js +7 -4
- package/dist/app/features/audit/audit.run.d.ts +3 -0
- package/dist/app/features/defs.d.ts +155 -3
- package/dist/app/features/defs.js +12 -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/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 +14 -1
- 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 +24 -4
- package/dist/cli/commands/registry.js +2 -0
- 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 -4
- package/dist/cli/manifest.js +33 -4
- package/dist/cli/menu/io-menu.d.ts +5 -3
- package/dist/cli/menu/io-menu.js +12 -5
- 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 +2 -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 +11 -1
- 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/config.d.ts +22 -3
- package/dist/core/schema/config.js +39 -2
- 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/daemon/daemon.js +2 -0
- package/dist/guest/daemon/idle-shutdown.js +2 -1
- package/dist/guest/daemon/sessions.d.ts +16 -2
- package/dist/guest/daemon/sessions.js +126 -20
- 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/toolchains/setup.js +3 -0
- package/dist/host/audit/log.d.ts +3 -2
- package/dist/host/audit/log.js +3 -3
- 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 +74 -3
- package/dist/runtime/daemon.js +205 -24
- package/dist/runtime/db.js +74 -3
- package/dist/runtime/gitguard.js +6 -0
- package/dist/runtime/main.js +77 -3
- package/dist/runtime/netproxy.js +74 -3
- package/dist/runtime/view.js +76 -3
- package/dist/selftest/app.test.js +41 -6
- 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/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/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/fixtures.d.ts +13 -0
- package/dist/selftest/support/web-preview.js +63 -0
- package/dist/selftest/web.test.js +2 -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/web/index.html +1 -1
- package/dist/web/main-Z2WYAE2Z.js +221 -0
- 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/csharp/PtyHost.cs +20 -0
- package/schemas/config.schema.json +65 -0
- package/schemas/sandbox-config.schema.json +0 -18
- package/dist/web/main-UD4QCXZR.js +0 -219
package/dist/runtime/daemon.js
CHANGED
|
@@ -26743,12 +26743,39 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26743
26743
|
});
|
|
26744
26744
|
|
|
26745
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
|
+
});
|
|
26746
26772
|
var WebSchema = external_exports.strictObject({
|
|
26747
26773
|
enabled: external_exports.boolean().describe(
|
|
26748
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."
|
|
26749
26775
|
),
|
|
26750
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."),
|
|
26751
|
-
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.")
|
|
26752
26779
|
});
|
|
26753
26780
|
|
|
26754
26781
|
// src/core/schema/vpn.ts
|
|
@@ -26778,6 +26805,36 @@ var GithubSchema = external_exports.strictObject({
|
|
|
26778
26805
|
});
|
|
26779
26806
|
|
|
26780
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
|
+
}
|
|
26781
26838
|
var ConfigSchema = external_exports.strictObject({
|
|
26782
26839
|
$schema: SchemaRefSchema.optional(),
|
|
26783
26840
|
defaultHarness: NameSchema.describe("Agent started by `sandbox launch` (sandbox claude always runs claude)."),
|
|
@@ -26844,10 +26901,14 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26844
26901
|
scripts: StringsSchema.describe(
|
|
26845
26902
|
"Scripts (.ps1 / .mjs / .cmd, relative to this file) run inside the sandbox before the agent."
|
|
26846
26903
|
),
|
|
26847
|
-
// 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.
|
|
26848
26906
|
sandbox: SandboxSchema.omit({
|
|
26849
26907
|
cpuLimit: true,
|
|
26850
26908
|
pageFileMb: true,
|
|
26909
|
+
reserveHostMb: true,
|
|
26910
|
+
maxMemoryPercent: true,
|
|
26911
|
+
maxMemoryMb: true,
|
|
26851
26912
|
engine: true,
|
|
26852
26913
|
agentMemoryHeadroomMb: true,
|
|
26853
26914
|
pressureResponse: true
|
|
@@ -26861,7 +26922,10 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26861
26922
|
// Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
|
|
26862
26923
|
toolchains: external_exports.strictObject({
|
|
26863
26924
|
...import_lodash.default.mapValues(import_lodash.default.omit(ToolchainsSchema.shape, "environment"), (shape) => shape.partial()),
|
|
26864
|
-
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
|
+
)
|
|
26865
26929
|
}).partial(),
|
|
26866
26930
|
databases: external_exports.strictObject(import_lodash.default.mapValues(DatabasesSchema.shape, (shape) => shape.partial())).partial(),
|
|
26867
26931
|
attach: AttachSchema.partial(),
|
|
@@ -26931,6 +26995,7 @@ var ProjectSpecSchema = external_exports.strictObject({
|
|
|
26931
26995
|
/** Its hooks were staged in C:\AgentLaunch\projects\<name>\hooks. */
|
|
26932
26996
|
hooks: external_exports.boolean()
|
|
26933
26997
|
});
|
|
26998
|
+
var ShellChoiceSchema = external_exports.enum(["auto", "pwsh", "powershell", "cmd"]);
|
|
26934
26999
|
var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
26935
27000
|
external_exports.strictObject({
|
|
26936
27001
|
kind: external_exports.literal("session"),
|
|
@@ -26940,8 +27005,12 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
26940
27005
|
cwd: Text(),
|
|
26941
27006
|
project: ProjectSpecSchema.optional(),
|
|
26942
27007
|
harnessSpec: HarnessSchema.optional(),
|
|
27008
|
+
/** A plain shell instead of an agent (harness is then "shell" and args are ignored). */
|
|
27009
|
+
shell: ShellChoiceSchema.optional(),
|
|
26943
27010
|
createdAt: TimeSchema
|
|
26944
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 }),
|
|
26945
27014
|
/** Provision a registered project without starting an agent (sandbox start / exec / db from its folder). */
|
|
26946
27015
|
external_exports.strictObject({ kind: external_exports.literal("project"), id: IdSchema, project: ProjectSpecSchema, createdAt: TimeSchema }),
|
|
26947
27016
|
external_exports.strictObject({
|
|
@@ -27007,6 +27076,8 @@ var SessionStatusSchema = external_exports.object({
|
|
|
27007
27076
|
id: IdSchema,
|
|
27008
27077
|
launchId: Text(64),
|
|
27009
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(),
|
|
27010
27081
|
cwd: Text(),
|
|
27011
27082
|
/** The project it runs in: its hub name, or the launch folder's for the first project. */
|
|
27012
27083
|
project: Text(64).optional(),
|
|
@@ -27939,7 +28010,7 @@ function withRequestSecrets(req) {
|
|
|
27939
28010
|
}
|
|
27940
28011
|
|
|
27941
28012
|
// src/guest/daemon/daemon.ts
|
|
27942
|
-
import
|
|
28013
|
+
import fs55 from "node:fs";
|
|
27943
28014
|
|
|
27944
28015
|
// src/guest/setup/claude-mem.ts
|
|
27945
28016
|
import fs15 from "node:fs";
|
|
@@ -32046,6 +32117,7 @@ async function setupToolchains(config2, versions, options, run2 = {}) {
|
|
|
32046
32117
|
env.summary.push(...part.summary);
|
|
32047
32118
|
}
|
|
32048
32119
|
Object.assign(env.vars, config2.environment);
|
|
32120
|
+
Object.assign(env.vars, envs.get("Git")?.vars);
|
|
32049
32121
|
log("Set up " + steps.length + " toolchains and databases.");
|
|
32050
32122
|
return env;
|
|
32051
32123
|
}
|
|
@@ -32242,6 +32314,7 @@ function execCommand(req) {
|
|
|
32242
32314
|
}
|
|
32243
32315
|
|
|
32244
32316
|
// src/guest/daemon/sessions.ts
|
|
32317
|
+
import fs53 from "node:fs";
|
|
32245
32318
|
import path68 from "node:path";
|
|
32246
32319
|
import crypto4 from "node:crypto";
|
|
32247
32320
|
import os11 from "node:os";
|
|
@@ -32254,6 +32327,8 @@ var FrameType = {
|
|
|
32254
32327
|
Resize: 3,
|
|
32255
32328
|
Restart: 4,
|
|
32256
32329
|
Ping: 5,
|
|
32330
|
+
/** Ends the program and everything it started, and with it the session. */
|
|
32331
|
+
Close: 6,
|
|
32257
32332
|
Output: 16,
|
|
32258
32333
|
Exit: 17,
|
|
32259
32334
|
Error: 18,
|
|
@@ -32337,6 +32412,16 @@ function cmdArgs(args) {
|
|
|
32337
32412
|
function commandLine(file3, args) {
|
|
32338
32413
|
return path64.win32.basename(file3).toLowerCase() === "cmd.exe" ? [quoteArg(file3), cmdArgs(args)].filter(Boolean).join(" ") : [file3, ...args].map(quoteArg).join(" ");
|
|
32339
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
|
+
}
|
|
32340
32425
|
|
|
32341
32426
|
// src/guest/sessions/pty-host.ts
|
|
32342
32427
|
import fs50 from "node:fs";
|
|
@@ -32556,6 +32641,7 @@ var IdleShutdown = class {
|
|
|
32556
32641
|
};
|
|
32557
32642
|
|
|
32558
32643
|
// src/guest/daemon/sessions.ts
|
|
32644
|
+
var CLOSE_WAIT_MS = 8e3;
|
|
32559
32645
|
var ROOTS_KEPT_MS = 10 * 60 * 1e3;
|
|
32560
32646
|
function terminalTab(id, title, cwd) {
|
|
32561
32647
|
const view = [process.execPath, path68.join(path68.dirname(process.argv[1]), "view.js"), id];
|
|
@@ -32601,14 +32687,38 @@ function writeBudget(cpus, memoryGb, jobs, env) {
|
|
|
32601
32687
|
warn("budget.json could not be written: " + errMsg(e));
|
|
32602
32688
|
}
|
|
32603
32689
|
}
|
|
32604
|
-
var
|
|
32690
|
+
var agentProgram = async (req, env, say) => {
|
|
32605
32691
|
const harness = harnessFor(req);
|
|
32606
32692
|
say("Preparing " + req.harness);
|
|
32607
32693
|
await agents.provision(req.harness, harness, env, false);
|
|
32608
32694
|
const launch = agents.resolveLaunch(req.harness, harness);
|
|
32609
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) => {
|
|
32610
32714
|
const port = await freePort();
|
|
32611
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;
|
|
32612
32722
|
const child = startPtyHost({
|
|
32613
32723
|
exe: ensurePtyHost(),
|
|
32614
32724
|
port,
|
|
@@ -32617,10 +32727,10 @@ var launchPtyHost = async (req, remote, env, say, sessions2, onSpawn) => {
|
|
|
32617
32727
|
rows: 32,
|
|
32618
32728
|
id: req.id,
|
|
32619
32729
|
cwd: req.cwd,
|
|
32620
|
-
env:
|
|
32730
|
+
env: sessionEnv,
|
|
32621
32731
|
remote,
|
|
32622
|
-
command:
|
|
32623
|
-
restartCommand:
|
|
32732
|
+
command: program.command,
|
|
32733
|
+
restartCommand: program.restartCommand
|
|
32624
32734
|
});
|
|
32625
32735
|
onSpawn(child);
|
|
32626
32736
|
try {
|
|
@@ -32635,6 +32745,17 @@ var launchPtyHost = async (req, remote, env, say, sessions2, onSpawn) => {
|
|
|
32635
32745
|
};
|
|
32636
32746
|
var placeFor = async (req, say) => {
|
|
32637
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
|
+
);
|
|
32638
32759
|
if (!insidePrimary(req.cwd) || !exists(req.cwd))
|
|
32639
32760
|
throw new Error("Folder is not inside the sandbox workspace " + workspace + ": " + req.cwd);
|
|
32640
32761
|
return { env: process.env, hooks: null, project: primaryProject() };
|
|
@@ -32682,16 +32803,29 @@ var SessionManager = class {
|
|
|
32682
32803
|
const r = this.ptyHosts.get(id);
|
|
32683
32804
|
if (r && r.to === void 0) this.ptyHosts.set(id, { ...r, to: Date.now() });
|
|
32684
32805
|
}
|
|
32685
|
-
/**
|
|
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
|
+
*/
|
|
32686
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);
|
|
32687
32820
|
let status = {
|
|
32688
32821
|
id: req.id,
|
|
32689
32822
|
launchId: session.launchId,
|
|
32690
|
-
harness:
|
|
32823
|
+
harness: name,
|
|
32824
|
+
...req.shell ? { kind: "shell" } : {},
|
|
32691
32825
|
cwd: req.cwd,
|
|
32692
32826
|
...req.project ? { project: req.project.name } : {},
|
|
32693
32827
|
phase: "starting",
|
|
32694
|
-
message: "Starting " +
|
|
32828
|
+
message: "Starting " + name,
|
|
32695
32829
|
updatedAt: now(),
|
|
32696
32830
|
startedAt: now()
|
|
32697
32831
|
};
|
|
@@ -32702,34 +32836,37 @@ var SessionManager = class {
|
|
|
32702
32836
|
};
|
|
32703
32837
|
this.starting++;
|
|
32704
32838
|
if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1")
|
|
32705
|
-
safely("terminal tab", () => terminalTab(req.id,
|
|
32839
|
+
safely("terminal tab", () => terminalTab(req.id, name + " " + path68.basename(req.cwd), req.cwd));
|
|
32706
32840
|
try {
|
|
32841
|
+
if (problem) throw new Error(problem);
|
|
32707
32842
|
const place = await placeFor(req, say);
|
|
32843
|
+
const program = shell ? shellProgram(shell) : await agentProgram(req, place.env, say);
|
|
32708
32844
|
const remote = session.networking && session.attach.enabled;
|
|
32709
32845
|
const from = Date.now();
|
|
32710
32846
|
const { child, port, token } = await launchPtyHost(
|
|
32711
32847
|
req,
|
|
32848
|
+
program,
|
|
32712
32849
|
remote,
|
|
32713
32850
|
place.env,
|
|
32714
|
-
say,
|
|
32715
32851
|
this.live.size + 1,
|
|
32716
32852
|
(c) => this.rootStarted(req.id, c, from)
|
|
32717
32853
|
);
|
|
32718
|
-
const
|
|
32854
|
+
const agent = shell === null;
|
|
32855
|
+
const resumed = agent && req.harness === "claude" ? resumedConversation(req.args) : void 0;
|
|
32719
32856
|
const running = {
|
|
32720
32857
|
...status,
|
|
32721
32858
|
...resumed ? { conversation: resumed } : {},
|
|
32722
32859
|
project: place.project,
|
|
32723
32860
|
phase: "running",
|
|
32724
|
-
message:
|
|
32861
|
+
message: name + " is running",
|
|
32725
32862
|
attach: { addresses: remote ? guestAddresses() : [], port, token }
|
|
32726
32863
|
};
|
|
32727
32864
|
this.live.set(req.id, { status: running, child });
|
|
32728
32865
|
child.once("exit", (code) => this.onExit(running, place, code));
|
|
32729
32866
|
saveStatus(running);
|
|
32730
|
-
if (req.harness === "claude") this.trackConversation(running.id, resumed);
|
|
32867
|
+
if (agent && req.harness === "claude") this.trackConversation(running.id, resumed);
|
|
32731
32868
|
log(
|
|
32732
|
-
"Session " + req.id + " started (" +
|
|
32869
|
+
"Session " + req.id + " started (" + name + " in " + req.cwd + ", project " + place.project + ", port " + port + ")"
|
|
32733
32870
|
);
|
|
32734
32871
|
} catch (e) {
|
|
32735
32872
|
this.rootEnded(req.id);
|
|
@@ -32758,10 +32895,13 @@ var SessionManager = class {
|
|
|
32758
32895
|
this.idle.check();
|
|
32759
32896
|
}
|
|
32760
32897
|
}
|
|
32761
|
-
/**
|
|
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
|
+
*/
|
|
32762
32902
|
async restart(req) {
|
|
32763
32903
|
const targets = [...this.live.values()].filter(
|
|
32764
|
-
(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))
|
|
32765
32905
|
);
|
|
32766
32906
|
for (const s of targets)
|
|
32767
32907
|
await sendControl(
|
|
@@ -32770,6 +32910,41 @@ var SessionManager = class {
|
|
|
32770
32910
|
);
|
|
32771
32911
|
respond(req.id, { ok: true, message: "restarted " + targets.length + " session(s)" });
|
|
32772
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
|
+
}
|
|
32773
32948
|
/**
|
|
32774
32949
|
* Finds out which of Claude's conversation files this session writes (it appears with the first message) and puts
|
|
32775
32950
|
* it in the status, so the host can reopen this very conversation. A reopened session starts with the one it was
|
|
@@ -32812,6 +32987,10 @@ var SessionManager = class {
|
|
|
32812
32987
|
attach: void 0
|
|
32813
32988
|
});
|
|
32814
32989
|
log("Session " + running.id + " ended (exit " + code + ")");
|
|
32990
|
+
if (running.kind === "shell") {
|
|
32991
|
+
this.idle.check();
|
|
32992
|
+
return;
|
|
32993
|
+
}
|
|
32815
32994
|
if (place.hooks)
|
|
32816
32995
|
void runHooksAsync("post-agent", place.env, place.hooks).catch(
|
|
32817
32996
|
(e) => warn("post-agent hooks failed: " + errMsg(e))
|
|
@@ -33151,7 +33330,7 @@ var GovernorCore = class {
|
|
|
33151
33330
|
};
|
|
33152
33331
|
|
|
33153
33332
|
// src/guest/governor/governor.ts
|
|
33154
|
-
import
|
|
33333
|
+
import fs54 from "node:fs";
|
|
33155
33334
|
import os12 from "node:os";
|
|
33156
33335
|
import path69 from "node:path";
|
|
33157
33336
|
import { spawn as spawn8 } from "node:child_process";
|
|
@@ -33224,11 +33403,11 @@ var MemGovProcess = class {
|
|
|
33224
33403
|
function appendToMemoryLog(line) {
|
|
33225
33404
|
try {
|
|
33226
33405
|
const logs = path69.join(dataDir, "logs");
|
|
33227
|
-
const newest =
|
|
33406
|
+
const newest = fs54.readdirSync(logs).filter((f) => /^memory-\d{8}-\d{6}\.log$/.test(f)).sort().pop();
|
|
33228
33407
|
if (!newest) return;
|
|
33229
33408
|
const t = /* @__PURE__ */ new Date();
|
|
33230
33409
|
const stamp = [t.getHours(), t.getMinutes(), t.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
|
|
33231
|
-
|
|
33410
|
+
fs54.appendFileSync(path69.join(logs, newest), stamp + " | " + line + "\r\n");
|
|
33232
33411
|
} catch {
|
|
33233
33412
|
}
|
|
33234
33413
|
}
|
|
@@ -33285,9 +33464,9 @@ var Daemon = class {
|
|
|
33285
33464
|
tick() {
|
|
33286
33465
|
const { valid, invalid } = run.scanRequests();
|
|
33287
33466
|
for (const file3 of invalid)
|
|
33288
|
-
safely("removing an invalid request", () =>
|
|
33467
|
+
safely("removing an invalid request", () => fs55.rmSync(file3, { recursive: true, force: true }));
|
|
33289
33468
|
for (const req of valid) {
|
|
33290
|
-
safely("claiming a request", () =>
|
|
33469
|
+
safely("claiming a request", () => fs55.rmSync(run.requestFile(req.id), { force: true }));
|
|
33291
33470
|
if (run.readSession(req.id)) continue;
|
|
33292
33471
|
void Promise.resolve(this.handle(withRequestSecrets(req))).catch(
|
|
33293
33472
|
(e) => respond(req.id, { ok: false, message: errMsg(e) })
|
|
@@ -33309,6 +33488,8 @@ var Daemon = class {
|
|
|
33309
33488
|
return execCommand(req);
|
|
33310
33489
|
case "restart":
|
|
33311
33490
|
return sessions.restart(req);
|
|
33491
|
+
case "close":
|
|
33492
|
+
return sessions.close(req);
|
|
33312
33493
|
case "pressure":
|
|
33313
33494
|
return governor.hostPressure(req.seconds, req.reason, req.level ?? "slow");
|
|
33314
33495
|
case "ping":
|
package/dist/runtime/db.js
CHANGED
|
@@ -26636,12 +26636,39 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26636
26636
|
});
|
|
26637
26637
|
|
|
26638
26638
|
// src/core/schema/web.ts
|
|
26639
|
+
var REMOTE_ROLES = ["view", "control"];
|
|
26640
|
+
var WindowsUserNameSchema = external_exports.string().trim().min(1).max(120).regex(
|
|
26641
|
+
/^(?:[A-Za-z0-9][A-Za-z0-9._ -]{0,62}\\)?[^\\/"[\]:;|=,+*?<>@]{1,64}$/,
|
|
26642
|
+
"a Windows user name (name or DOMAIN\\name)"
|
|
26643
|
+
);
|
|
26644
|
+
var RemoteUserSchema = external_exports.strictObject({
|
|
26645
|
+
name: WindowsUserNameSchema.describe("The Windows user (name, or DOMAIN\\name)"),
|
|
26646
|
+
role: external_exports.enum(REMOTE_ROLES).describe("view: sees everything, terminals read-only. control: everything but remote access, logins and tokens.")
|
|
26647
|
+
});
|
|
26648
|
+
var WebLanSchema = external_exports.strictObject({
|
|
26649
|
+
enabled: external_exports.boolean().describe(
|
|
26650
|
+
"(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."
|
|
26651
|
+
),
|
|
26652
|
+
port: external_exports.number().int().min(1024).max(65535).describe("HTTPS port for paired devices on your network."),
|
|
26653
|
+
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).")
|
|
26654
|
+
});
|
|
26655
|
+
var WebRemoteSchema = external_exports.strictObject({
|
|
26656
|
+
windowsSignIn: external_exports.boolean().describe(
|
|
26657
|
+
"(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."
|
|
26658
|
+
),
|
|
26659
|
+
users: external_exports.array(RemoteUserSchema).max(32).describe("Who else may sign in with Windows, and their role (view or control)."),
|
|
26660
|
+
rememberDays: external_exports.number().int().min(1).max(90).describe(
|
|
26661
|
+
"How many days a paired device or a Windows sign-in stays signed in (from when it signed in, not renewed)."
|
|
26662
|
+
),
|
|
26663
|
+
lan: WebLanSchema
|
|
26664
|
+
});
|
|
26639
26665
|
var WebSchema = external_exports.strictObject({
|
|
26640
26666
|
enabled: external_exports.boolean().describe(
|
|
26641
26667
|
"(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."
|
|
26642
26668
|
),
|
|
26643
26669
|
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."),
|
|
26644
|
-
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts.")
|
|
26670
|
+
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts."),
|
|
26671
|
+
remote: WebRemoteSchema.describe("(Beta) Access for other Windows users of this PC and for paired devices.")
|
|
26645
26672
|
});
|
|
26646
26673
|
|
|
26647
26674
|
// src/core/schema/vpn.ts
|
|
@@ -26671,6 +26698,36 @@ var GithubSchema = external_exports.strictObject({
|
|
|
26671
26698
|
});
|
|
26672
26699
|
|
|
26673
26700
|
// src/core/schema/config.ts
|
|
26701
|
+
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;
|
|
26702
|
+
var RESERVED_ENV_SUFFIX = /(_PROXY|_BASE_URL|_ENDPOINT|_CA_BUNDLE|_CA_CERTS)$/i;
|
|
26703
|
+
var RESERVED_ENV_NAMES = new Set(
|
|
26704
|
+
[
|
|
26705
|
+
"PATH",
|
|
26706
|
+
"PATHEXT",
|
|
26707
|
+
"BASH_ENV",
|
|
26708
|
+
"ENV",
|
|
26709
|
+
"COMSPEC",
|
|
26710
|
+
"PSMODULEPATH",
|
|
26711
|
+
"PYTHONPATH",
|
|
26712
|
+
"PYTHONSTARTUP",
|
|
26713
|
+
"PERL5OPT",
|
|
26714
|
+
"RUBYOPT",
|
|
26715
|
+
"JAVA_TOOL_OPTIONS",
|
|
26716
|
+
"LD_PRELOAD",
|
|
26717
|
+
"SYSTEMROOT",
|
|
26718
|
+
"WINDIR",
|
|
26719
|
+
"HOME",
|
|
26720
|
+
"USERPROFILE",
|
|
26721
|
+
"APPDATA",
|
|
26722
|
+
"LOCALAPPDATA",
|
|
26723
|
+
"PROGRAMDATA",
|
|
26724
|
+
"TEMP",
|
|
26725
|
+
"TMP"
|
|
26726
|
+
].map((n) => n.toUpperCase())
|
|
26727
|
+
);
|
|
26728
|
+
function reservedEnvName(name) {
|
|
26729
|
+
return RESERVED_ENV_PREFIX.test(name) || RESERVED_ENV_SUFFIX.test(name) || RESERVED_ENV_NAMES.has(name.toUpperCase());
|
|
26730
|
+
}
|
|
26674
26731
|
var ConfigSchema = external_exports.strictObject({
|
|
26675
26732
|
$schema: SchemaRefSchema.optional(),
|
|
26676
26733
|
defaultHarness: NameSchema.describe("Agent started by `sandbox launch` (sandbox claude always runs claude)."),
|
|
@@ -26737,10 +26794,14 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26737
26794
|
scripts: StringsSchema.describe(
|
|
26738
26795
|
"Scripts (.ps1 / .mjs / .cmd, relative to this file) run inside the sandbox before the agent."
|
|
26739
26796
|
),
|
|
26740
|
-
// This PC's resources are yours to share: CPU
|
|
26797
|
+
// 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
|
|
26798
|
+
// project's to set.
|
|
26741
26799
|
sandbox: SandboxSchema.omit({
|
|
26742
26800
|
cpuLimit: true,
|
|
26743
26801
|
pageFileMb: true,
|
|
26802
|
+
reserveHostMb: true,
|
|
26803
|
+
maxMemoryPercent: true,
|
|
26804
|
+
maxMemoryMb: true,
|
|
26744
26805
|
engine: true,
|
|
26745
26806
|
agentMemoryHeadroomMb: true,
|
|
26746
26807
|
pressureResponse: true
|
|
@@ -26754,7 +26815,10 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26754
26815
|
// Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
|
|
26755
26816
|
toolchains: external_exports.strictObject({
|
|
26756
26817
|
...import_lodash.default.mapValues(import_lodash.default.omit(ToolchainsSchema.shape, "environment"), (shape) => shape.partial()),
|
|
26757
|
-
environment: ToolchainsSchema.shape.environment
|
|
26818
|
+
environment: ToolchainsSchema.shape.environment.refine(
|
|
26819
|
+
(env) => !Object.keys(env).some(reservedEnvName),
|
|
26820
|
+
"names the sandbox sets or that carry logins (AGENT_*, GIT_*, PATH, BASH_ENV, NODE_*, proxies, ANTHROPIC_*, CLAUDE_* ...) cannot be set by a project"
|
|
26821
|
+
)
|
|
26758
26822
|
}).partial(),
|
|
26759
26823
|
databases: external_exports.strictObject(import_lodash.default.mapValues(DatabasesSchema.shape, (shape) => shape.partial())).partial(),
|
|
26760
26824
|
attach: AttachSchema.partial(),
|
|
@@ -26824,6 +26888,7 @@ var ProjectSpecSchema = external_exports.strictObject({
|
|
|
26824
26888
|
/** Its hooks were staged in C:\AgentLaunch\projects\<name>\hooks. */
|
|
26825
26889
|
hooks: external_exports.boolean()
|
|
26826
26890
|
});
|
|
26891
|
+
var ShellChoiceSchema = external_exports.enum(["auto", "pwsh", "powershell", "cmd"]);
|
|
26827
26892
|
var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
26828
26893
|
external_exports.strictObject({
|
|
26829
26894
|
kind: external_exports.literal("session"),
|
|
@@ -26833,8 +26898,12 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
26833
26898
|
cwd: Text(),
|
|
26834
26899
|
project: ProjectSpecSchema.optional(),
|
|
26835
26900
|
harnessSpec: HarnessSchema.optional(),
|
|
26901
|
+
/** A plain shell instead of an agent (harness is then "shell" and args are ignored). */
|
|
26902
|
+
shell: ShellChoiceSchema.optional(),
|
|
26836
26903
|
createdAt: TimeSchema
|
|
26837
26904
|
}),
|
|
26905
|
+
/** End a running session (an agent or a shell) and everything it started. */
|
|
26906
|
+
external_exports.strictObject({ kind: external_exports.literal("close"), id: IdSchema, session: IdSchema, createdAt: TimeSchema }),
|
|
26838
26907
|
/** Provision a registered project without starting an agent (sandbox start / exec / db from its folder). */
|
|
26839
26908
|
external_exports.strictObject({ kind: external_exports.literal("project"), id: IdSchema, project: ProjectSpecSchema, createdAt: TimeSchema }),
|
|
26840
26909
|
external_exports.strictObject({
|
|
@@ -26900,6 +26969,8 @@ var SessionStatusSchema = external_exports.object({
|
|
|
26900
26969
|
id: IdSchema,
|
|
26901
26970
|
launchId: Text(64),
|
|
26902
26971
|
harness: Text(64),
|
|
26972
|
+
/** A plain shell (harness is then the shell: pwsh, powershell or cmd); absent: an agent. */
|
|
26973
|
+
kind: external_exports.enum(["agent", "shell"]).optional(),
|
|
26903
26974
|
cwd: Text(),
|
|
26904
26975
|
/** The project it runs in: its hub name, or the launch folder's for the first project. */
|
|
26905
26976
|
project: Text(64).optional(),
|
package/dist/runtime/gitguard.js
CHANGED
|
@@ -62,6 +62,7 @@ var LISTING = {
|
|
|
62
62
|
};
|
|
63
63
|
var WITH_VALUE = /* @__PURE__ */ new Set(["-C", "--namespace"]);
|
|
64
64
|
var FORBIDDEN_GLOBAL = /^(-c|--config-env|--exec-path|--git-dir|--work-tree|--super-prefix)(=|$)/;
|
|
65
|
+
var RUNS_OR_WRITES = /^(--open-files-in-pager|--upload-pack|--output|--ext-diff)(=|$)/;
|
|
65
66
|
function gitDecision(args, access) {
|
|
66
67
|
if (access === "full") return { allow: true };
|
|
67
68
|
if (access !== "readonly")
|
|
@@ -76,6 +77,11 @@ function gitDecision(args, access) {
|
|
|
76
77
|
i += WITH_VALUE.has(args[i]) ? 2 : 1;
|
|
77
78
|
}
|
|
78
79
|
const [command, ...rest] = args.slice(i);
|
|
80
|
+
const runsOrWrites = rest.find(
|
|
81
|
+
(a) => RUNS_OR_WRITES.test(a) || command === "ls-remote" && /^-u(.|$)/.test(a) || command === "grep" && /^-O/.test(a)
|
|
82
|
+
);
|
|
83
|
+
if (runsOrWrites)
|
|
84
|
+
return { allow: false, reason: "git " + runsOrWrites + " is not allowed: git is read-only in this sandbox." };
|
|
79
85
|
if (command === void 0 || command === "--version" || READ_ONLY.has(command) || (LISTING[command]?.(rest) ?? false))
|
|
80
86
|
return { allow: true };
|
|
81
87
|
return {
|