windows-development-sandbox 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.sandbox-config.example.json +2 -1
- package/config.example.json +1 -0
- package/dist/cli/boot-progress.d.ts +22 -0
- package/dist/cli/boot-progress.js +59 -0
- package/dist/cli/commands/launch.d.ts +5 -2
- package/dist/cli/commands/launch.js +77 -22
- package/dist/cli/commands/maintenance.js +36 -3
- package/dist/cli/commands/project.d.ts +10 -6
- package/dist/cli/commands/project.js +42 -3
- package/dist/cli/commands/restart.js +17 -7
- package/dist/cli/commands/sessions.js +2 -1
- package/dist/cli/manifest.js +1 -1
- package/dist/cli/progress.d.ts +15 -0
- package/dist/cli/progress.js +52 -0
- package/dist/core/config.js +1 -1
- package/dist/core/local-config.d.ts +16 -1
- package/dist/core/local-config.js +15 -9
- package/dist/core/project-policy.d.ts +50 -3
- package/dist/core/project-policy.js +90 -4
- package/dist/core/schema/config.d.ts +3 -2
- package/dist/core/schema/config.js +1 -1
- package/dist/core/schema/projects.d.ts +1 -0
- package/dist/core/schema/projects.js +1 -0
- package/dist/core/schema/sandbox.d.ts +1 -1
- package/dist/core/schema/sandbox.js +1 -1
- package/dist/core/types.d.ts +18 -1
- package/dist/core/workspace.d.ts +21 -4
- package/dist/core/workspace.js +87 -26
- package/dist/guest/env.d.ts +6 -2
- package/dist/guest/env.js +15 -3
- package/dist/guest/main.js +5 -1
- package/dist/guest/toolchains/index.js +29 -3
- package/dist/host/channel.d.ts +2 -2
- package/dist/host/channel.js +3 -2
- package/dist/host/generate.d.ts +1 -1
- package/dist/host/generate.js +13 -6
- package/dist/host/join.d.ts +7 -0
- package/dist/host/join.js +23 -9
- package/dist/host/launch/mappings.d.ts +7 -2
- package/dist/host/launch/mappings.js +64 -18
- package/dist/host/launch/projects.d.ts +2 -0
- package/dist/host/launch/projects.js +11 -5
- package/dist/host/projects.d.ts +25 -2
- package/dist/host/projects.js +54 -5
- package/dist/runtime/daemon.js +71 -9
- package/dist/runtime/db.js +33 -3
- package/dist/runtime/main.js +191 -30
- package/dist/runtime/netproxy.js +15 -3
- package/dist/runtime/view.js +262 -128
- package/dist/selftest/channel.test.js +38 -2
- package/dist/selftest/fixtures.d.ts +2 -1
- package/dist/selftest/index.js +2 -1
- package/dist/selftest/live-terminal.test.d.ts +2 -0
- package/dist/selftest/live-terminal.test.js +169 -0
- package/dist/selftest/local-config.test.js +28 -3
- package/dist/selftest/mirror.test.js +36 -7
- package/dist/selftest/projects.test.js +76 -7
- package/dist/shared/console-input.d.ts +11 -0
- package/dist/shared/console-input.js +61 -0
- package/dist/shared/download.d.ts +3 -0
- package/dist/shared/download.js +25 -2
- package/dist/shared/guest-paths.d.ts +27 -0
- package/dist/shared/guest-paths.js +68 -0
- package/dist/shared/projects.d.ts +27 -4
- package/dist/shared/projects.js +72 -13
- package/dist/shared/pty-client.d.ts +17 -0
- package/dist/shared/pty-client.js +65 -8
- package/dist/shared/schema.d.ts +24 -0
- package/dist/shared/schema.js +12 -0
- package/package.json +1 -1
- package/sandbox/ptyhost.cs +60 -3
- package/schemas/config.schema.json +15 -1
- package/schemas/sandbox-config.schema.json +4 -3
package/sandbox/ptyhost.cs
CHANGED
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
// 20 STATUS [viewers:2][remoteViewers:2] viewers heard from recently (remote = not loopback, i.e. the PC)
|
|
19
19
|
// 21 CONSOLE utf8 "conpty.dll" or "windows", sent after HELLO. With conpty.dll the output is passed
|
|
20
20
|
// through (real scrollback, no repaint on resize): a viewer that joins later is sent the
|
|
21
|
-
//
|
|
21
|
+
// terminal modes in force (mouse tracking ...) and the output since the last screen clear
|
|
22
|
+
// instead, and must not clear its screen on a resize.
|
|
22
23
|
using System;
|
|
23
24
|
using System.Collections.Concurrent;
|
|
24
25
|
using System.Collections.Generic;
|
|
@@ -265,7 +266,12 @@ sealed class ClientHub
|
|
|
265
266
|
// Taken and queued under the replay lock, so no output falls between the replay and the live stream.
|
|
266
267
|
lock (replayGate)
|
|
267
268
|
{
|
|
268
|
-
if (Native.ConsoleKind.StartsWith("conpty")
|
|
269
|
+
if (Native.ConsoleKind.StartsWith("conpty"))
|
|
270
|
+
{
|
|
271
|
+
byte[] prefix = ModePrefix();
|
|
272
|
+
if (prefix.Length > 0) Send(client, Frame.Output, prefix);
|
|
273
|
+
if (replay.Length > 0) Send(client, Frame.Output, replay.ToArray());
|
|
274
|
+
}
|
|
269
275
|
lock (gate) clients.Add(client);
|
|
270
276
|
}
|
|
271
277
|
TakeOwnership(client);
|
|
@@ -319,6 +325,7 @@ sealed class ClientHub
|
|
|
319
325
|
void Record(byte[] output)
|
|
320
326
|
{
|
|
321
327
|
if (!Native.ConsoleKind.StartsWith("conpty")) return;
|
|
328
|
+
TrackModes(output);
|
|
322
329
|
int clear = LastClear(output);
|
|
323
330
|
if (clear >= 0) { replay.SetLength(0); replay.Write(output, clear, output.Length - clear); }
|
|
324
331
|
else replay.Write(output, 0, output.Length);
|
|
@@ -330,6 +337,56 @@ sealed class ClientHub
|
|
|
330
337
|
if (from + 1 < all.Length) replay.Write(all, from + 1, all.Length - from - 1);
|
|
331
338
|
}
|
|
332
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Terminal modes the program (or conpty.dll) turned on that a late viewer's terminal must have too, or its clicks and
|
|
342
|
+
* wheel never reach the program: mouse tracking (1000, 1002, 1003, 1005, 1006, 1015), focus events (1004), bracketed
|
|
343
|
+
* paste (2004), win32 input (9001), application cursor keys (1), cursor visibility (25), the alternate screen (1049).
|
|
344
|
+
* The replay is cut at the last screen clear, which may come after the program turned them on.
|
|
345
|
+
*/
|
|
346
|
+
static readonly int[] ReplayedModes = { 1, 25, 1000, 1002, 1003, 1004, 1005, 1006, 1015, 1049, 2004, 9001 };
|
|
347
|
+
readonly Dictionary<int, bool> modes = new Dictionary<int, bool>();
|
|
348
|
+
/** DECSET / DECRST parser, kept across chunks: 0 text, 1 after ESC, 2 after ESC[, 3 in ESC[? parameters. */
|
|
349
|
+
int modeState;
|
|
350
|
+
readonly StringBuilder modeParams = new StringBuilder();
|
|
351
|
+
|
|
352
|
+
void TrackModes(byte[] output)
|
|
353
|
+
{
|
|
354
|
+
foreach (byte b in output)
|
|
355
|
+
{
|
|
356
|
+
if (b == 0x1b) { modeState = 1; continue; }
|
|
357
|
+
switch (modeState)
|
|
358
|
+
{
|
|
359
|
+
case 1: modeState = b == (byte)'[' ? 2 : 0; break;
|
|
360
|
+
case 2: modeState = b == (byte)'?' ? 3 : 0; modeParams.Length = 0; break;
|
|
361
|
+
case 3:
|
|
362
|
+
if ((b >= (byte)'0' && b <= (byte)'9') || b == (byte)';') { if (modeParams.Length < 64) modeParams.Append((char)b); }
|
|
363
|
+
else
|
|
364
|
+
{
|
|
365
|
+
if (b == (byte)'h' || b == (byte)'l')
|
|
366
|
+
foreach (string p in modeParams.ToString().Split(';'))
|
|
367
|
+
{
|
|
368
|
+
int mode;
|
|
369
|
+
if (int.TryParse(p, out mode) && Array.IndexOf(ReplayedModes, mode) >= 0) modes[mode] = b == (byte)'h';
|
|
370
|
+
}
|
|
371
|
+
modeState = 0;
|
|
372
|
+
}
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** The modes to set before the replay, e.g. ESC[?1000h ESC[?1006h. */
|
|
379
|
+
byte[] ModePrefix()
|
|
380
|
+
{
|
|
381
|
+
var text = new StringBuilder();
|
|
382
|
+
foreach (int mode in ReplayedModes)
|
|
383
|
+
{
|
|
384
|
+
bool on;
|
|
385
|
+
if (modes.TryGetValue(mode, out on)) text.Append("\x1b[?" + mode + (on ? "h" : "l"));
|
|
386
|
+
}
|
|
387
|
+
return Encoding.ASCII.GetBytes(text.ToString());
|
|
388
|
+
}
|
|
389
|
+
|
|
333
390
|
/** Where the last ESC[2J (clear screen) or ESC c (reset) starts in `data`, or -1. */
|
|
334
391
|
static int LastClear(byte[] data)
|
|
335
392
|
{
|
|
@@ -364,7 +421,7 @@ sealed class ClientHub
|
|
|
364
421
|
}
|
|
365
422
|
|
|
366
423
|
/** A restarted program starts on a clean screen (viewers clear theirs on RESTARTING). */
|
|
367
|
-
public void ResetReplay() { lock (replayGate) replay.SetLength(0); }
|
|
424
|
+
public void ResetReplay() { lock (replayGate) { replay.SetLength(0); modes.Clear(); modeState = 0; } }
|
|
368
425
|
|
|
369
426
|
public void Notify(byte type)
|
|
370
427
|
{
|
|
@@ -99,8 +99,10 @@
|
|
|
99
99
|
"description": "Folder on this PC (relative paths are relative to the config file)."
|
|
100
100
|
},
|
|
101
101
|
"guest": {
|
|
102
|
+
"description": "Where it appears inside the sandbox, e.g. C:\\Assets, or on another drive letter (D: to Z:) such as F:\\SteamLibrary\\steamapps\\common\\Game (shown as F: at boot). Leave it out to use the same path as on this PC (a folder inside the project stays where it is in the project). A path the sandbox cannot use (C:\\Windows\\..., C:\\Users\\..., one already in use) goes to C:\\Mapped\\<drive>\\<path> instead, and the launch says so.",
|
|
102
103
|
"type": "string",
|
|
103
|
-
"
|
|
104
|
+
"minLength": 1,
|
|
105
|
+
"maxLength": 1024
|
|
104
106
|
},
|
|
105
107
|
"readOnly": {
|
|
106
108
|
"type": "boolean",
|
|
@@ -1449,6 +1451,18 @@
|
|
|
1449
1451
|
},
|
|
1450
1452
|
"description": "Parent folders you said no to (not asked again)."
|
|
1451
1453
|
},
|
|
1454
|
+
"allowOutsideMappings": {
|
|
1455
|
+
"anyOf": [
|
|
1456
|
+
{
|
|
1457
|
+
"type": "string",
|
|
1458
|
+
"const": "ask"
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
"type": "boolean"
|
|
1462
|
+
}
|
|
1463
|
+
],
|
|
1464
|
+
"description": "A project's .sandbox-config.json may map folders from outside the project (e.g. a game folder on another drive). \"ask\" = an interactive launch asks once per project and set of folders, and remembers your answer; true = always allowed (still listed when you approve the file); false = never (the launch stops and says which folders). Only your own settings decide this, never a project file."
|
|
1465
|
+
},
|
|
1452
1466
|
"wsbShare": {
|
|
1453
1467
|
"type": "boolean",
|
|
1454
1468
|
"description": "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."
|
|
@@ -61,8 +61,10 @@
|
|
|
61
61
|
"description": "Folder on this PC (relative paths are relative to the config file)."
|
|
62
62
|
},
|
|
63
63
|
"guest": {
|
|
64
|
+
"description": "Where it appears inside the sandbox, e.g. C:\\Assets, or on another drive letter (D: to Z:) such as F:\\SteamLibrary\\steamapps\\common\\Game (shown as F: at boot). Leave it out to use the same path as on this PC (a folder inside the project stays where it is in the project). A path the sandbox cannot use (C:\\Windows\\..., C:\\Users\\..., one already in use) goes to C:\\Mapped\\<drive>\\<path> instead, and the launch says so.",
|
|
64
65
|
"type": "string",
|
|
65
|
-
"
|
|
66
|
+
"minLength": 1,
|
|
67
|
+
"maxLength": 1024
|
|
66
68
|
},
|
|
67
69
|
"readOnly": {
|
|
68
70
|
"type": "boolean",
|
|
@@ -75,12 +77,11 @@
|
|
|
75
77
|
},
|
|
76
78
|
"required": [
|
|
77
79
|
"host",
|
|
78
|
-
"guest",
|
|
79
80
|
"readOnly"
|
|
80
81
|
],
|
|
81
82
|
"additionalProperties": false
|
|
82
83
|
},
|
|
83
|
-
"description": "Extra folders
|
|
84
|
+
"description": "Extra folders (relative paths are relative to this file), e.g. a read-only data folder at another place in the sandbox. Folders outside the project are used only as your projects.allowOutsideMappings setting allows (by default you are asked once)."
|
|
84
85
|
},
|
|
85
86
|
"scripts": {
|
|
86
87
|
"type": "array",
|