windows-development-sandbox 1.13.2 → 1.15.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/config.example.json +2 -1
- package/dist/app/features/defs.d.ts +1 -1
- package/dist/app/features/projects/projects.def.d.ts +1 -1
- package/dist/app/features/projects/projects.run.d.ts +1 -1
- package/dist/app/features/projects/projects.run.js +10 -2
- package/dist/app/features/sandbox/sandbox.def.js +3 -1
- package/dist/app/features/settings/categories.def.js +1 -0
- package/dist/app/features/storage/storage.run.js +1 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-VENWSGX2.js → chunk-D7CM63BS.js} +2303 -1462
- package/dist/bin/{chunk-K4SU3MHJ.js → chunk-HTQT5SBY.js} +1 -1
- package/dist/bin/{chunk-IL7BXJF2.js → chunk-RQ4BWBYX.js} +1 -1
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/commands/launch/launch.js +1 -1
- package/dist/cli/commands/projects/here.js +2 -0
- package/dist/cli/commands/repair/checks/contained.js +1 -1
- package/dist/cli/services/health-service.js +15 -3
- package/dist/cli/services/projects-service.d.ts +8 -3
- package/dist/cli/services/projects-service.js +21 -4
- package/dist/core/config/defaults.js +1 -0
- package/dist/core/schema/config.d.ts +4 -0
- package/dist/core/schema/projects.d.ts +4 -0
- package/dist/core/schema/projects.js +3 -0
- package/dist/guest/boot/boot.js +8 -2
- package/dist/guest/daemon/daemon.js +3 -0
- package/dist/guest/daemon/live-folders.d.ts +48 -0
- package/dist/guest/daemon/live-folders.js +245 -0
- package/dist/guest/daemon/live.d.ts +4 -0
- package/dist/guest/daemon/live.js +57 -0
- package/dist/guest/daemon/sessions.d.ts +7 -0
- package/dist/guest/daemon/sessions.js +23 -2
- package/dist/guest/entries/daemon.js +5 -2
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/runtime/secrets.d.ts +5 -2
- package/dist/guest/runtime/secrets.js +12 -5
- package/dist/guest/sessions/pty-host.d.ts +10 -0
- package/dist/guest/sessions/pty-host.js +48 -3
- package/dist/host/channel/channel.js +1 -1
- package/dist/host/engines/hcs/live-folders.d.ts +117 -0
- package/dist/host/engines/hcs/live-folders.js +347 -0
- package/dist/host/engines/index.d.ts +1 -0
- package/dist/host/engines/index.js +1 -0
- package/dist/host/install/install-record.d.ts +1 -0
- package/dist/host/install/install-record.js +2 -0
- package/dist/host/launch/generate.js +8 -1
- package/dist/host/projects/join.d.ts +4 -0
- package/dist/host/projects/join.js +11 -3
- package/dist/host/projects/mapper.d.ts +34 -5
- package/dist/host/projects/mapper.js +88 -20
- package/dist/host/projects/registry.d.ts +2 -0
- package/dist/host/projects/registry.js +1 -1
- package/dist/host/sandbox/contained-deps.d.ts +2 -1
- package/dist/host/sandbox/contained-deps.js +6 -4
- package/dist/host/secrets/launch-secrets.js +2 -1
- package/dist/host/sharing/lifecycle.js +9 -1
- package/dist/host/storage/contained/contained-storage.js +13 -0
- package/dist/host/storage/contained/disk-port.d.ts +5 -0
- package/dist/host/storage/contained/helper-port.d.ts +72 -0
- package/dist/host/storage/contained/helper-port.js +162 -0
- package/dist/host/storage/contained/index.d.ts +1 -0
- package/dist/host/storage/contained/index.js +1 -0
- package/dist/host/web/bridge.d.ts +5 -0
- package/dist/host/web/bridge.js +11 -1
- package/dist/host/web/server.d.ts +2 -0
- package/dist/host/web/server.js +11 -1
- package/dist/runtime/agent.js +23 -0
- package/dist/runtime/daemon.js +523 -135
- package/dist/runtime/db.js +23 -0
- package/dist/runtime/main.js +221 -15
- package/dist/runtime/netproxy.js +23 -0
- package/dist/runtime/view.js +209 -12
- package/dist/selftest/channel.test.js +72 -1
- package/dist/selftest/contained.test.js +1 -37
- package/dist/selftest/hcs.test.js +5 -2
- package/dist/selftest/index.js +4 -0
- package/dist/selftest/install.test.js +11 -0
- package/dist/selftest/layout.test.js +1 -0
- package/dist/selftest/live-daemon.test.js +51 -1
- package/dist/selftest/live-folders.test.d.ts +2 -0
- package/dist/selftest/live-folders.test.js +588 -0
- package/dist/selftest/live-terminal.test.js +112 -4
- package/dist/selftest/projects.test.js +7 -7
- package/dist/selftest/storage-helper.test.d.ts +2 -0
- package/dist/selftest/storage-helper.test.js +493 -0
- package/dist/selftest/support/engine-golden.js +1 -0
- package/dist/selftest/support/fixtures.d.ts +1 -0
- package/dist/selftest/support/live.js +2 -0
- package/dist/selftest/support/vhdx.d.ts +14 -0
- package/dist/selftest/support/vhdx.js +72 -0
- package/dist/selftest/web.test.js +14 -2
- package/dist/shared/channel/index.d.ts +1 -0
- package/dist/shared/channel/index.js +1 -0
- package/dist/shared/channel/live.d.ts +53 -0
- package/dist/shared/channel/live.js +92 -0
- package/dist/shared/channel/run-dir.d.ts +11 -0
- package/dist/shared/channel/run-dir.js +20 -0
- package/dist/shared/channel/secrets.d.ts +1 -0
- package/dist/shared/channel/secrets.js +5 -0
- package/dist/shared/paths/projects.d.ts +6 -1
- package/dist/shared/paths/projects.js +21 -1
- package/dist/shared/pty/index.d.ts +3 -1
- package/dist/shared/pty/index.js +3 -1
- package/dist/shared/pty/key-gate.d.ts +24 -0
- package/dist/shared/pty/key-gate.js +45 -0
- package/dist/shared/pty/mouse-modes.d.ts +27 -0
- package/dist/shared/pty/mouse-modes.js +155 -0
- package/dist/shared/pty/terminal.d.ts +0 -5
- package/dist/shared/pty/terminal.js +51 -20
- package/dist/sync/watcher.js +10 -1
- package/dist/web/index.html +1 -1
- package/dist/web/{main-NBQ3LF4E.js → main-7DJZ2M27.js} +34 -34
- package/native/csharp/HcsHost/AssemblyInfo.cs +4 -4
- package/native/csharp/HcsHost/FolderAccess.cs +361 -0
- package/native/csharp/HcsHost/Hcs.cs +31 -3
- package/native/csharp/HcsHost/Program.cs +54 -6
- package/native/csharp/HcsHost/Share.cs +64 -11
- package/native/csharp/HcsHost/WsbGuard.cs +130 -0
- package/native/csharp/HcsHost/WsbShare.cs +295 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +15 -0
- package/native/csharp/StorageHelper/Client.cs +297 -0
- package/native/csharp/StorageHelper/Log.cs +177 -0
- package/native/csharp/StorageHelper/MountRecords.cs +160 -0
- package/native/csharp/StorageHelper/Operations.cs +596 -0
- package/native/csharp/StorageHelper/Pins.cs +270 -0
- package/native/csharp/StorageHelper/Privileges.cs +78 -0
- package/native/csharp/StorageHelper/Program.cs +349 -0
- package/native/csharp/StorageHelper/Protocol.cs +107 -0
- package/native/csharp/StorageHelper/RateLimiter.cs +97 -0
- package/native/csharp/StorageHelper/Rules.cs +156 -0
- package/native/csharp/StorageHelper/Server.cs +656 -0
- package/native/csharp/StorageHelper/Settings.cs +297 -0
- package/native/csharp/StorageHelper/StorageService.cs +53 -0
- package/native/csharp/StorageHelper/UserSettings.cs +206 -0
- package/native/csharp/StorageHelper/Vhdx.cs +230 -0
- package/native/csharp/StorageHelper/VirtualDisk.cs +241 -0
- package/native/csharp/StorageHelper/Volumes.cs +379 -0
- package/native/csharp/StorageHelper/Watchdog.cs +128 -0
- package/native/csharp/StorageHelper/Win32.cs +250 -0
- package/native/scripts/contained-common.ps1 +4 -0
- package/native/scripts/hcs-live-share.ps1 +191 -0
- package/native/scripts/set-storage-helper.ps1 +203 -0
- package/package.json +1 -1
- package/sandbox/csharp/BindMount.cs +120 -0
- package/sandbox/csharp/PtyHost.cs +236 -1
- package/schemas/config.schema.json +8 -0
package/dist/runtime/db.js
CHANGED
|
@@ -26621,6 +26621,9 @@ var ProjectsSchema = external_exports.strictObject({
|
|
|
26621
26621
|
),
|
|
26622
26622
|
wsbShare: external_exports.boolean().describe(
|
|
26623
26623
|
"On Windows 11 24H2+ with the Windows Sandbox command line (wsb), add other folders to the running sandbox with `wsb share` (untested). Otherwise starting a project outside every root offers a restart."
|
|
26624
|
+
),
|
|
26625
|
+
liveFolders: external_exports.enum(["off", "hcs"]).describe(
|
|
26626
|
+
'ALPHA, UNTESTED ON A REAL PC: "hcs" adds a project folder to the running sandbox through the Host Compute Service where `wsb share` is missing (one administrator prompt per add or remove; always read-only in this alpha). If it fails, the sandbox may close: save your work first. Turn it on before the sandbox starts. "off" (default) offers a restart instead. The real-PC tests still to pass are in docs/design/hcs-live-folders.md ("Test plan").'
|
|
26624
26627
|
)
|
|
26625
26628
|
});
|
|
26626
26629
|
|
|
@@ -27211,8 +27214,16 @@ var RunDir = class {
|
|
|
27211
27214
|
projectsDir;
|
|
27212
27215
|
/** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
|
|
27213
27216
|
auditDir;
|
|
27217
|
+
/**
|
|
27218
|
+
* Each running session's process tree, recorded by its ptyhost (guest only: the daemon ends what a ptyhost that was
|
|
27219
|
+
* itself ended left running).
|
|
27220
|
+
*/
|
|
27221
|
+
treesDir;
|
|
27214
27222
|
/** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
|
|
27215
27223
|
secretsDir;
|
|
27224
|
+
/** Live folders (live.ts): signed host requests, and the daemon's replies. */
|
|
27225
|
+
liveDir;
|
|
27226
|
+
liveRepliesDir;
|
|
27216
27227
|
constructor(dataDir2) {
|
|
27217
27228
|
this.root = path5.join(dataDir2, "run");
|
|
27218
27229
|
this.sandboxFile = path5.join(this.root, "sandbox.json");
|
|
@@ -27224,7 +27235,16 @@ var RunDir = class {
|
|
|
27224
27235
|
this.sessionsDir = path5.join(this.root, "sessions");
|
|
27225
27236
|
this.projectsDir = path5.join(this.root, "projects");
|
|
27226
27237
|
this.auditDir = path5.join(this.root, "audit");
|
|
27238
|
+
this.treesDir = path5.join(this.root, "trees");
|
|
27227
27239
|
this.secretsDir = path5.join(dataDir2, "secrets");
|
|
27240
|
+
this.liveDir = path5.join(this.root, "live");
|
|
27241
|
+
this.liveRepliesDir = path5.join(this.root, "live-replies");
|
|
27242
|
+
}
|
|
27243
|
+
liveFile(id) {
|
|
27244
|
+
return path5.join(this.liveDir, safeId(id) + ".json");
|
|
27245
|
+
}
|
|
27246
|
+
liveReplyFile(id) {
|
|
27247
|
+
return path5.join(this.liveRepliesDir, safeId(id) + ".json");
|
|
27228
27248
|
}
|
|
27229
27249
|
requestFile(id) {
|
|
27230
27250
|
return path5.join(this.requestsDir, safeId(id) + ".json");
|
|
@@ -27235,6 +27255,9 @@ var RunDir = class {
|
|
|
27235
27255
|
sessionFile(id) {
|
|
27236
27256
|
return path5.join(this.sessionsDir, safeId(id) + ".json");
|
|
27237
27257
|
}
|
|
27258
|
+
treeFile(id) {
|
|
27259
|
+
return path5.join(this.treesDir, safeId(id) + ".json");
|
|
27260
|
+
}
|
|
27238
27261
|
projectFile(name) {
|
|
27239
27262
|
return path5.join(this.projectsDir, safeId(name) + ".json");
|
|
27240
27263
|
}
|
package/dist/runtime/main.js
CHANGED
|
@@ -26750,6 +26750,9 @@ var ProjectsSchema = external_exports.strictObject({
|
|
|
26750
26750
|
),
|
|
26751
26751
|
wsbShare: external_exports.boolean().describe(
|
|
26752
26752
|
"On Windows 11 24H2+ with the Windows Sandbox command line (wsb), add other folders to the running sandbox with `wsb share` (untested). Otherwise starting a project outside every root offers a restart."
|
|
26753
|
+
),
|
|
26754
|
+
liveFolders: external_exports.enum(["off", "hcs"]).describe(
|
|
26755
|
+
'ALPHA, UNTESTED ON A REAL PC: "hcs" adds a project folder to the running sandbox through the Host Compute Service where `wsb share` is missing (one administrator prompt per add or remove; always read-only in this alpha). If it fails, the sandbox may close: save your work first. Turn it on before the sandbox starts. "off" (default) offers a restart instead. The real-PC tests still to pass are in docs/design/hcs-live-folders.md ("Test plan").'
|
|
26753
26756
|
)
|
|
26754
26757
|
});
|
|
26755
26758
|
|
|
@@ -27322,8 +27325,16 @@ var RunDir = class {
|
|
|
27322
27325
|
projectsDir;
|
|
27323
27326
|
/** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
|
|
27324
27327
|
auditDir;
|
|
27328
|
+
/**
|
|
27329
|
+
* Each running session's process tree, recorded by its ptyhost (guest only: the daemon ends what a ptyhost that was
|
|
27330
|
+
* itself ended left running).
|
|
27331
|
+
*/
|
|
27332
|
+
treesDir;
|
|
27325
27333
|
/** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
|
|
27326
27334
|
secretsDir;
|
|
27335
|
+
/** Live folders (live.ts): signed host requests, and the daemon's replies. */
|
|
27336
|
+
liveDir;
|
|
27337
|
+
liveRepliesDir;
|
|
27327
27338
|
constructor(dataDir2) {
|
|
27328
27339
|
this.root = path6.join(dataDir2, "run");
|
|
27329
27340
|
this.sandboxFile = path6.join(this.root, "sandbox.json");
|
|
@@ -27335,7 +27346,16 @@ var RunDir = class {
|
|
|
27335
27346
|
this.sessionsDir = path6.join(this.root, "sessions");
|
|
27336
27347
|
this.projectsDir = path6.join(this.root, "projects");
|
|
27337
27348
|
this.auditDir = path6.join(this.root, "audit");
|
|
27349
|
+
this.treesDir = path6.join(this.root, "trees");
|
|
27338
27350
|
this.secretsDir = path6.join(dataDir2, "secrets");
|
|
27351
|
+
this.liveDir = path6.join(this.root, "live");
|
|
27352
|
+
this.liveRepliesDir = path6.join(this.root, "live-replies");
|
|
27353
|
+
}
|
|
27354
|
+
liveFile(id) {
|
|
27355
|
+
return path6.join(this.liveDir, safeId(id) + ".json");
|
|
27356
|
+
}
|
|
27357
|
+
liveReplyFile(id) {
|
|
27358
|
+
return path6.join(this.liveRepliesDir, safeId(id) + ".json");
|
|
27339
27359
|
}
|
|
27340
27360
|
requestFile(id) {
|
|
27341
27361
|
return path6.join(this.requestsDir, safeId(id) + ".json");
|
|
@@ -27346,6 +27366,9 @@ var RunDir = class {
|
|
|
27346
27366
|
sessionFile(id) {
|
|
27347
27367
|
return path6.join(this.sessionsDir, safeId(id) + ".json");
|
|
27348
27368
|
}
|
|
27369
|
+
treeFile(id) {
|
|
27370
|
+
return path6.join(this.treesDir, safeId(id) + ".json");
|
|
27371
|
+
}
|
|
27349
27372
|
projectFile(name) {
|
|
27350
27373
|
return path6.join(this.projectsDir, safeId(name) + ".json");
|
|
27351
27374
|
}
|
|
@@ -29290,7 +29313,8 @@ var SOURCES = {
|
|
|
29290
29313
|
cargoshim: "CargoShim.cs",
|
|
29291
29314
|
linkgate: "LinkGate.cs",
|
|
29292
29315
|
pathsync: "PathSync.cs",
|
|
29293
|
-
memgov: "MemGov.cs"
|
|
29316
|
+
memgov: "MemGov.cs",
|
|
29317
|
+
bindmount: "BindMount.cs"
|
|
29294
29318
|
};
|
|
29295
29319
|
function sourceOf(name) {
|
|
29296
29320
|
return path31.join(launchDir, "sandbox", "csharp", SOURCES[name]);
|
|
@@ -35339,12 +35363,175 @@ var CtrlCGuard = class {
|
|
|
35339
35363
|
}
|
|
35340
35364
|
};
|
|
35341
35365
|
|
|
35342
|
-
// src/shared/pty/
|
|
35343
|
-
var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
|
|
35366
|
+
// src/shared/pty/key-gate.ts
|
|
35344
35367
|
function fixWindowsKeys(chunk) {
|
|
35345
35368
|
if (!chunk.includes(8) && !chunk.includes(127)) return chunk;
|
|
35346
35369
|
return Buffer.from(chunk.map((b) => b === 8 ? 127 : b === 127 ? 8 : b));
|
|
35347
35370
|
}
|
|
35371
|
+
var KeyGate = class {
|
|
35372
|
+
pending = [];
|
|
35373
|
+
decided;
|
|
35374
|
+
swap = false;
|
|
35375
|
+
/** windowsConsole: input comes from a Windows console in raw mode (its mode is decided later); else it goes as is. */
|
|
35376
|
+
constructor(windowsConsole) {
|
|
35377
|
+
this.decided = !windowsConsole;
|
|
35378
|
+
}
|
|
35379
|
+
/** The bytes to send now (empty while the mode is not known yet). */
|
|
35380
|
+
push(data) {
|
|
35381
|
+
if (!data.length) return data;
|
|
35382
|
+
if (!this.decided) {
|
|
35383
|
+
this.pending.push(data);
|
|
35384
|
+
return Buffer.alloc(0);
|
|
35385
|
+
}
|
|
35386
|
+
return this.swap ? fixWindowsKeys(data) : data;
|
|
35387
|
+
}
|
|
35388
|
+
/** The console's mode is known: what was held, ready to send. Later calls only change how new input is read. */
|
|
35389
|
+
decide(vtInput) {
|
|
35390
|
+
this.swap = !vtInput;
|
|
35391
|
+
this.decided = true;
|
|
35392
|
+
const held = Buffer.concat(this.pending);
|
|
35393
|
+
this.pending = [];
|
|
35394
|
+
return this.swap ? fixWindowsKeys(held) : held;
|
|
35395
|
+
}
|
|
35396
|
+
};
|
|
35397
|
+
|
|
35398
|
+
// src/shared/pty/mouse-modes.ts
|
|
35399
|
+
var TRACKING = [9, 1e3, 1002, 1003];
|
|
35400
|
+
var MAX_PARAMS = 64;
|
|
35401
|
+
var MOTION = 32;
|
|
35402
|
+
var NO_BUTTON = 3;
|
|
35403
|
+
var MouseModes = class {
|
|
35404
|
+
on = /* @__PURE__ */ new Set();
|
|
35405
|
+
/** 0 text, 1 after ESC, 2 after ESC[, 3 in ESC[? parameters, 4 after ESC[! */
|
|
35406
|
+
state = 0;
|
|
35407
|
+
params = "";
|
|
35408
|
+
/** Reads the program's output (after OutputFilter): the mode changes in it. */
|
|
35409
|
+
watch(output3) {
|
|
35410
|
+
for (const b of output3) {
|
|
35411
|
+
if (b === 27) {
|
|
35412
|
+
this.state = 1;
|
|
35413
|
+
continue;
|
|
35414
|
+
}
|
|
35415
|
+
if (this.state === 1) {
|
|
35416
|
+
if (b === 99) this.on.clear();
|
|
35417
|
+
this.state = b === 91 ? 2 : 0;
|
|
35418
|
+
} else if (this.state === 2) {
|
|
35419
|
+
this.state = b === 63 ? 3 : b === 33 ? 4 : 0;
|
|
35420
|
+
this.params = "";
|
|
35421
|
+
} else if (this.state === 4) {
|
|
35422
|
+
if (b === 112) this.on.clear();
|
|
35423
|
+
this.state = 0;
|
|
35424
|
+
} else if (this.state === 3) {
|
|
35425
|
+
if (b >= 48 && b <= 57 || b === 59) {
|
|
35426
|
+
this.params += String.fromCharCode(b);
|
|
35427
|
+
if (this.params.length > MAX_PARAMS) this.state = 0;
|
|
35428
|
+
} else {
|
|
35429
|
+
if (b === 104 || b === 108) this.apply(this.params, b === 104);
|
|
35430
|
+
this.state = 0;
|
|
35431
|
+
}
|
|
35432
|
+
}
|
|
35433
|
+
}
|
|
35434
|
+
}
|
|
35435
|
+
/** The program is gone (exited or restarting): its modes went with it. */
|
|
35436
|
+
reset() {
|
|
35437
|
+
this.on.clear();
|
|
35438
|
+
this.state = 0;
|
|
35439
|
+
this.params = "";
|
|
35440
|
+
}
|
|
35441
|
+
/** True while the program tracks the mouse in any way. */
|
|
35442
|
+
tracking() {
|
|
35443
|
+
return TRACKING.some((m) => this.on.has(m));
|
|
35444
|
+
}
|
|
35445
|
+
/** True while the program has a mode on (2004: bracketed paste). */
|
|
35446
|
+
has(mode) {
|
|
35447
|
+
return this.on.has(mode);
|
|
35448
|
+
}
|
|
35449
|
+
/** The mode numbers on now (for the report and tests). */
|
|
35450
|
+
modes() {
|
|
35451
|
+
return [...this.on].sort((a, b) => a - b);
|
|
35452
|
+
}
|
|
35453
|
+
/** `input` without the mouse reports the program has not asked for. Sequences must be whole (InputJoiner). */
|
|
35454
|
+
filter(input2) {
|
|
35455
|
+
if (!input2.includes(27)) return input2;
|
|
35456
|
+
const parts2 = [];
|
|
35457
|
+
let from = 0;
|
|
35458
|
+
let i = input2.indexOf(27);
|
|
35459
|
+
while (i !== -1) {
|
|
35460
|
+
const report = mouseReport(input2, i, this.on.has(1005), this.on.has(1015));
|
|
35461
|
+
if (report && !this.allows(report.button)) {
|
|
35462
|
+
parts2.push(input2.subarray(from, i));
|
|
35463
|
+
from = i + report.length;
|
|
35464
|
+
i = input2.indexOf(27, from);
|
|
35465
|
+
} else i = input2.indexOf(27, i + 1);
|
|
35466
|
+
}
|
|
35467
|
+
if (from === 0) return input2;
|
|
35468
|
+
parts2.push(input2.subarray(from));
|
|
35469
|
+
return Buffer.concat(parts2);
|
|
35470
|
+
}
|
|
35471
|
+
allows(button) {
|
|
35472
|
+
if (!this.tracking()) return false;
|
|
35473
|
+
if ((button & MOTION) === 0) return true;
|
|
35474
|
+
if (this.on.has(1003)) return true;
|
|
35475
|
+
return this.on.has(1002) && (button & NO_BUTTON) !== NO_BUTTON;
|
|
35476
|
+
}
|
|
35477
|
+
apply(params, set2) {
|
|
35478
|
+
for (const p of params.split(";")) {
|
|
35479
|
+
const mode = Number(p);
|
|
35480
|
+
if (!p || !Number.isSafeInteger(mode)) continue;
|
|
35481
|
+
if (set2) this.on.add(mode);
|
|
35482
|
+
else this.on.delete(mode);
|
|
35483
|
+
}
|
|
35484
|
+
}
|
|
35485
|
+
};
|
|
35486
|
+
function mouseReport(data, at, utf8, urxvt) {
|
|
35487
|
+
if (data[at + 1] !== 91) return null;
|
|
35488
|
+
const sgr = data[at + 2] === 60;
|
|
35489
|
+
if (sgr || urxvt && data[at + 2] >= 48 && data[at + 2] <= 57) {
|
|
35490
|
+
let i = at + (sgr ? 3 : 2);
|
|
35491
|
+
let digits = "";
|
|
35492
|
+
let fields = 1;
|
|
35493
|
+
for (; i < data.length && i - at < 32; i++) {
|
|
35494
|
+
const b = data[i];
|
|
35495
|
+
if (b >= 48 && b <= 57) {
|
|
35496
|
+
if (fields === 1) digits += String.fromCharCode(b);
|
|
35497
|
+
} else if (b === 59) fields++;
|
|
35498
|
+
else break;
|
|
35499
|
+
}
|
|
35500
|
+
if (i >= data.length || fields !== 3 || !digits) return null;
|
|
35501
|
+
if (sgr ? data[i] !== 77 && data[i] !== 109 : data[i] !== 77) return null;
|
|
35502
|
+
const button = Number(digits) - (sgr ? 0 : 32);
|
|
35503
|
+
return button >= 0 ? { button, length: i - at + 1 } : null;
|
|
35504
|
+
}
|
|
35505
|
+
if (data[at + 2] === 77 && !utf8 && data.length - at >= 6) {
|
|
35506
|
+
const button = data[at + 3] - 32;
|
|
35507
|
+
return button >= 0 ? { button, length: 6 } : null;
|
|
35508
|
+
}
|
|
35509
|
+
return null;
|
|
35510
|
+
}
|
|
35511
|
+
|
|
35512
|
+
// src/shared/pty/terminal.ts
|
|
35513
|
+
var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
|
|
35514
|
+
var SETTLE_QUIET_MS = 50;
|
|
35515
|
+
var SETTLE_MAX_MS = 300;
|
|
35516
|
+
function drainInput(stream) {
|
|
35517
|
+
return new Promise((done) => {
|
|
35518
|
+
let quiet;
|
|
35519
|
+
const end = () => {
|
|
35520
|
+
clearTimeout(quiet);
|
|
35521
|
+
clearTimeout(cap);
|
|
35522
|
+
stream.off("data", onData);
|
|
35523
|
+
done();
|
|
35524
|
+
};
|
|
35525
|
+
const onData = () => {
|
|
35526
|
+
clearTimeout(quiet);
|
|
35527
|
+
quiet = setTimeout(end, SETTLE_QUIET_MS);
|
|
35528
|
+
};
|
|
35529
|
+
const cap = setTimeout(end, SETTLE_MAX_MS);
|
|
35530
|
+
stream.on("data", onData);
|
|
35531
|
+
onData();
|
|
35532
|
+
});
|
|
35533
|
+
}
|
|
35534
|
+
var VT_WAIT_MS = 1e4;
|
|
35348
35535
|
function runTerminalClient(socket, token, options = {}) {
|
|
35349
35536
|
const stdin = process.stdin;
|
|
35350
35537
|
const stdout = process.stdout;
|
|
@@ -35352,14 +35539,16 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
35352
35539
|
const [c, r] = stdout.isTTY ? stdout.getWindowSize() : [0, 0];
|
|
35353
35540
|
return [c || 120, r || 30];
|
|
35354
35541
|
};
|
|
35355
|
-
|
|
35542
|
+
const keys = new KeyGate(process.platform === "win32" && Boolean(stdin.isTTY));
|
|
35356
35543
|
return new Promise((resolve2) => {
|
|
35357
35544
|
let done = false;
|
|
35358
35545
|
const reader = new FrameReader();
|
|
35359
35546
|
const filter = new OutputFilter({ clipboardWrites: options.clipboardWrites });
|
|
35360
35547
|
let sent = size();
|
|
35361
35548
|
let resizeTimer;
|
|
35362
|
-
let vtInput;
|
|
35549
|
+
let vtInput, vtTimer;
|
|
35550
|
+
const mouse = new MouseModes();
|
|
35551
|
+
let passthrough = false;
|
|
35363
35552
|
const finish = (result) => {
|
|
35364
35553
|
if (done) return;
|
|
35365
35554
|
done = true;
|
|
@@ -35370,9 +35559,13 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
35370
35559
|
clearInterval(sizeWatch);
|
|
35371
35560
|
clearTimeout(joinTimer);
|
|
35372
35561
|
clearTimeout(hintTimer);
|
|
35562
|
+
clearTimeout(vtTimer);
|
|
35373
35563
|
socket.destroy();
|
|
35374
|
-
|
|
35375
|
-
|
|
35564
|
+
const tracked = mouse.tracking();
|
|
35565
|
+
const reset = "\x1B[0m\x1B[?25h" + MOUSE_OFF + (mouse.has(2004) ? "\x1B[?2004l" : "") + "\r\n";
|
|
35566
|
+
const flushed = new Promise((written) => stdout.write(reset, () => written()));
|
|
35567
|
+
const settled = tracked ? flushed.then(() => drainInput(stdin)) : Promise.resolve();
|
|
35568
|
+
void Promise.all([settled, vtInput?.stop()]).then(() => {
|
|
35376
35569
|
if (stdin.isTTY) stdin.setRawMode(false);
|
|
35377
35570
|
stdin.pause();
|
|
35378
35571
|
resolve2(result);
|
|
@@ -35380,9 +35573,10 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
35380
35573
|
};
|
|
35381
35574
|
const joiner = new InputJoiner();
|
|
35382
35575
|
let joinTimer;
|
|
35383
|
-
const
|
|
35384
|
-
if (data.length && !done) socket.write(encodeFrame(FrameType.Input,
|
|
35576
|
+
const write = (data) => {
|
|
35577
|
+
if (data.length && !done) socket.write(encodeFrame(FrameType.Input, data));
|
|
35385
35578
|
};
|
|
35579
|
+
const sendInput = (data) => write(keys.push(passthrough ? mouse.filter(data) : data));
|
|
35386
35580
|
const guard = options.confirmCtrlC ? new CtrlCGuard() : null;
|
|
35387
35581
|
let hintTimer;
|
|
35388
35582
|
const onInput = (chunk) => {
|
|
@@ -35404,7 +35598,6 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
35404
35598
|
sendInput(joiner.push(chunk));
|
|
35405
35599
|
if (joiner.holding()) joinTimer = setTimeout(() => sendInput(joiner.flush()), JOIN_MS);
|
|
35406
35600
|
};
|
|
35407
|
-
let passthrough = false;
|
|
35408
35601
|
const sendSize = () => {
|
|
35409
35602
|
const [c2, r2] = size();
|
|
35410
35603
|
if (c2 === sent[0] && r2 === sent[1]) return;
|
|
@@ -35434,11 +35627,14 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
35434
35627
|
for (const frame of frames) {
|
|
35435
35628
|
if (frame.type === FrameType.Output) {
|
|
35436
35629
|
const out = filter.push(frame.payload);
|
|
35630
|
+
mouse.watch(out);
|
|
35437
35631
|
guard?.watchOutput(out.toString("latin1"));
|
|
35438
35632
|
stdout.write(out);
|
|
35439
35633
|
} else if (frame.type === FrameType.Console) passthrough = frame.payload.toString("latin1") === "conpty.dll";
|
|
35440
|
-
else if (frame.type === FrameType.Restarting)
|
|
35441
|
-
|
|
35634
|
+
else if (frame.type === FrameType.Restarting) {
|
|
35635
|
+
mouse.reset();
|
|
35636
|
+
stdout.write(MOUSE_OFF + "\x1B[2J\x1B[3J\x1B[H");
|
|
35637
|
+
} else if (frame.type === FrameType.Exit)
|
|
35442
35638
|
finish({ reason: "exit", exitCode: frame.payload.length >= 4 ? frame.payload.readInt32LE(0) : 1 });
|
|
35443
35639
|
else if (frame.type === FrameType.Error)
|
|
35444
35640
|
finish({
|
|
@@ -35454,8 +35650,10 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
35454
35650
|
socket.write(helloFrame(token, c, r));
|
|
35455
35651
|
if (stdin.isTTY) stdin.setRawMode(true);
|
|
35456
35652
|
vtInput = enableVtInput();
|
|
35653
|
+
vtTimer = setTimeout(() => write(keys.decide(false)), VT_WAIT_MS);
|
|
35457
35654
|
void vtInput.ready.then((on) => {
|
|
35458
|
-
|
|
35655
|
+
clearTimeout(vtTimer);
|
|
35656
|
+
write(keys.decide(on));
|
|
35459
35657
|
});
|
|
35460
35658
|
stdin.on("data", onInput);
|
|
35461
35659
|
stdin.resume();
|
|
@@ -35565,7 +35763,9 @@ var SecretsFileSchema = external_exports.strictObject({
|
|
|
35565
35763
|
/** The checked WireGuard config of vpn.provider wireguard-file (holds the private key). */
|
|
35566
35764
|
wireguardConfig: external_exports.string().min(1).max(32 * 1024).optional(),
|
|
35567
35765
|
/** The GitHub token you saved for sandboxes (github.shareToken), only with git access "full". */
|
|
35568
|
-
githubToken: GithubTokenSchema.optional()
|
|
35766
|
+
githubToken: GithubTokenSchema.optional(),
|
|
35767
|
+
/** projects.liveFolders "hcs": this launch's key for signed live-folder requests (live.ts). */
|
|
35768
|
+
liveFoldersKey: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
|
|
35569
35769
|
});
|
|
35570
35770
|
|
|
35571
35771
|
// src/guest/runtime/secrets.ts
|
|
@@ -35626,7 +35826,13 @@ function startDaemon(env, secrets) {
|
|
|
35626
35826
|
...env,
|
|
35627
35827
|
AGENT_LOG_PREFIX: "daemon",
|
|
35628
35828
|
// The agent's environment (it may hold API keys): the daemon moves it into memory and removes this at once.
|
|
35629
|
-
|
|
35829
|
+
// The live-folder key (projects.liveFolders "hcs") goes the same way into the daemon's own state.
|
|
35830
|
+
...secrets.harnessEnvironment || secrets.liveFoldersKey ? {
|
|
35831
|
+
[BOOT_SECRETS_VARIABLE]: JSON.stringify({
|
|
35832
|
+
...secrets.harnessEnvironment ? { harnessEnvironment: secrets.harnessEnvironment } : {},
|
|
35833
|
+
...secrets.liveFoldersKey ? { liveFoldersKey: secrets.liveFoldersKey } : {}
|
|
35834
|
+
})
|
|
35835
|
+
} : {}
|
|
35630
35836
|
}
|
|
35631
35837
|
}).unref();
|
|
35632
35838
|
}
|
package/dist/runtime/netproxy.js
CHANGED
|
@@ -26674,6 +26674,9 @@ var ProjectsSchema = external_exports.strictObject({
|
|
|
26674
26674
|
),
|
|
26675
26675
|
wsbShare: external_exports.boolean().describe(
|
|
26676
26676
|
"On Windows 11 24H2+ with the Windows Sandbox command line (wsb), add other folders to the running sandbox with `wsb share` (untested). Otherwise starting a project outside every root offers a restart."
|
|
26677
|
+
),
|
|
26678
|
+
liveFolders: external_exports.enum(["off", "hcs"]).describe(
|
|
26679
|
+
'ALPHA, UNTESTED ON A REAL PC: "hcs" adds a project folder to the running sandbox through the Host Compute Service where `wsb share` is missing (one administrator prompt per add or remove; always read-only in this alpha). If it fails, the sandbox may close: save your work first. Turn it on before the sandbox starts. "off" (default) offers a restart instead. The real-PC tests still to pass are in docs/design/hcs-live-folders.md ("Test plan").'
|
|
26677
26680
|
)
|
|
26678
26681
|
});
|
|
26679
26682
|
|
|
@@ -27202,8 +27205,16 @@ var RunDir = class {
|
|
|
27202
27205
|
projectsDir;
|
|
27203
27206
|
/** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
|
|
27204
27207
|
auditDir;
|
|
27208
|
+
/**
|
|
27209
|
+
* Each running session's process tree, recorded by its ptyhost (guest only: the daemon ends what a ptyhost that was
|
|
27210
|
+
* itself ended left running).
|
|
27211
|
+
*/
|
|
27212
|
+
treesDir;
|
|
27205
27213
|
/** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
|
|
27206
27214
|
secretsDir;
|
|
27215
|
+
/** Live folders (live.ts): signed host requests, and the daemon's replies. */
|
|
27216
|
+
liveDir;
|
|
27217
|
+
liveRepliesDir;
|
|
27207
27218
|
constructor(dataDir2) {
|
|
27208
27219
|
this.root = path3.join(dataDir2, "run");
|
|
27209
27220
|
this.sandboxFile = path3.join(this.root, "sandbox.json");
|
|
@@ -27215,7 +27226,16 @@ var RunDir = class {
|
|
|
27215
27226
|
this.sessionsDir = path3.join(this.root, "sessions");
|
|
27216
27227
|
this.projectsDir = path3.join(this.root, "projects");
|
|
27217
27228
|
this.auditDir = path3.join(this.root, "audit");
|
|
27229
|
+
this.treesDir = path3.join(this.root, "trees");
|
|
27218
27230
|
this.secretsDir = path3.join(dataDir2, "secrets");
|
|
27231
|
+
this.liveDir = path3.join(this.root, "live");
|
|
27232
|
+
this.liveRepliesDir = path3.join(this.root, "live-replies");
|
|
27233
|
+
}
|
|
27234
|
+
liveFile(id) {
|
|
27235
|
+
return path3.join(this.liveDir, safeId(id) + ".json");
|
|
27236
|
+
}
|
|
27237
|
+
liveReplyFile(id) {
|
|
27238
|
+
return path3.join(this.liveRepliesDir, safeId(id) + ".json");
|
|
27219
27239
|
}
|
|
27220
27240
|
requestFile(id) {
|
|
27221
27241
|
return path3.join(this.requestsDir, safeId(id) + ".json");
|
|
@@ -27226,6 +27246,9 @@ var RunDir = class {
|
|
|
27226
27246
|
sessionFile(id) {
|
|
27227
27247
|
return path3.join(this.sessionsDir, safeId(id) + ".json");
|
|
27228
27248
|
}
|
|
27249
|
+
treeFile(id) {
|
|
27250
|
+
return path3.join(this.treesDir, safeId(id) + ".json");
|
|
27251
|
+
}
|
|
27229
27252
|
projectFile(name) {
|
|
27230
27253
|
return path3.join(this.projectsDir, safeId(name) + ".json");
|
|
27231
27254
|
}
|