windows-development-sandbox 1.18.2 → 1.18.4
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 +1 -1
- package/dist/app/features/defs.d.ts +26 -0
- package/dist/app/features/defs.js +2 -1
- package/dist/app/features/sandbox/sandbox.def.d.ts +34 -0
- package/dist/app/features/sandbox/sandbox.def.js +52 -10
- package/dist/app/features/sandbox/sandbox.run.d.ts +24 -0
- package/dist/app/features/sandbox/sandbox.run.js +45 -1
- package/dist/app/registry.js +2 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-MQIA7GNB.js → chunk-FRPLQLSY.js} +3188 -2765
- package/dist/bin/{chunk-M4OM632I.js → chunk-MY7NLQQY.js} +1 -1
- package/dist/bin/{chunk-IIHL7W6B.js → chunk-N4GXYTLV.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 +4 -1
- package/dist/cli/commands/launch/leftover-offer.d.ts +3 -0
- package/dist/cli/commands/launch/leftover-offer.js +26 -0
- package/dist/cli/commands/repair/checks/sandbox.d.ts +3 -1
- package/dist/cli/commands/repair/checks/sandbox.js +53 -2
- package/dist/core/config/defaults.js +1 -1
- package/dist/core/schema/sandbox.js +1 -1
- package/dist/core/schema/toolchains.js +2 -2
- package/dist/guest/daemon/daemon.js +1 -1
- package/dist/guest/daemon/heartbeat.d.ts +11 -0
- package/dist/guest/daemon/heartbeat.js +59 -0
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/entries/daemon.js +2 -0
- package/dist/guest/governor/core.d.ts +19 -1
- package/dist/guest/governor/core.js +23 -1
- package/dist/guest/governor/decide.d.ts +14 -0
- package/dist/guest/governor/decide.js +52 -7
- package/dist/guest/governor/governor.d.ts +4 -1
- package/dist/guest/governor/governor.js +9 -2
- package/dist/guest/toolchains/native/rust-extras.d.ts +7 -0
- package/dist/guest/toolchains/native/rust-extras.js +26 -3
- package/dist/guest/toolchains/plan.js +6 -4
- package/dist/host/channel/channel.d.ts +1 -1
- package/dist/host/channel/channel.js +10 -2
- package/dist/host/health/index.d.ts +1 -0
- package/dist/host/health/index.js +1 -0
- package/dist/host/health/leftovers.d.ts +3 -0
- package/dist/host/health/leftovers.js +40 -0
- package/dist/host/health/stale.d.ts +48 -0
- package/dist/host/health/stale.js +40 -0
- package/dist/host/launch/wsb-file.d.ts +6 -1
- package/dist/host/launch/wsb-file.js +9 -5
- package/dist/host/life/crash-report.d.ts +3 -1
- package/dist/host/life/crash-report.js +9 -3
- package/dist/host/life/index.d.ts +1 -0
- package/dist/host/life/index.js +1 -0
- package/dist/host/life/last-end.d.ts +28 -0
- package/dist/host/life/last-end.js +91 -0
- package/dist/host/life/life-record.d.ts +3 -0
- package/dist/host/life/life-record.js +2 -2
- package/dist/host/life/stop-events.d.ts +3 -1
- package/dist/host/life/stop-events.js +59 -0
- package/dist/host/life/stop-warning.js +3 -0
- package/dist/host/life/watchdog.d.ts +2 -0
- package/dist/host/life/watchdog.js +8 -2
- package/dist/host/sandbox/cleanup.d.ts +37 -0
- package/dist/host/sandbox/cleanup.js +82 -0
- package/dist/host/sandbox/index.d.ts +1 -0
- package/dist/host/sandbox/index.js +1 -0
- package/dist/host/sandbox/platform.js +1 -1
- package/dist/runtime/agent.js +28 -3
- package/dist/runtime/daemon.js +629 -479
- package/dist/runtime/db.js +28 -3
- package/dist/runtime/main.js +59 -11
- package/dist/runtime/netproxy.js +28 -3
- package/dist/runtime/tool.js +28 -3
- package/dist/runtime/view.js +28 -3
- package/dist/selftest/heavy-load.test.js +212 -14
- package/dist/selftest/live-terminal.test.js +4 -0
- package/dist/shared/channel/run-dir.d.ts +4 -1
- package/dist/shared/channel/run-dir.js +7 -1
- package/dist/shared/channel/schema.d.ts +24 -0
- package/dist/shared/channel/schema.js +22 -0
- package/dist/shared/memory/policy.d.ts +10 -0
- package/dist/shared/memory/policy.js +17 -1
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/sync/watcher.js +10 -5
- package/dist/web/index.html +1 -1
- package/dist/web/{main-CWIF4VQI.js → main-GVZWWP4I.js} +63 -63
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/Program.cs +5 -1
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/native/scripts/stop-events.ps1 +7 -3
- package/package.json +1 -1
- package/sandbox/csharp/MemGov.cs +58 -0
- package/schemas/config.schema.json +3 -3
- package/schemas/sandbox-config.schema.json +3 -3
|
@@ -8,9 +8,9 @@ using System.Runtime.InteropServices;
|
|
|
8
8
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
9
9
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
10
10
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
11
|
-
[assembly: AssemblyVersion("1.18.
|
|
12
|
-
[assembly: AssemblyFileVersion("1.18.
|
|
13
|
-
[assembly: AssemblyInformationalVersion("1.18.
|
|
11
|
+
[assembly: AssemblyVersion("1.18.4.0")]
|
|
12
|
+
[assembly: AssemblyFileVersion("1.18.4.0")]
|
|
13
|
+
[assembly: AssemblyInformationalVersion("1.18.4")]
|
|
14
14
|
[assembly: ComVisible(false)]
|
|
15
15
|
// computecore.dll and computestorage.dll are not KnownDLLs: load them from System32 only, never from the exe's folder.
|
|
16
16
|
[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
|
@@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|
|
8
8
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
9
9
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
10
10
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
11
|
-
[assembly: AssemblyVersion("1.18.
|
|
12
|
-
[assembly: AssemblyFileVersion("1.18.
|
|
13
|
-
[assembly: AssemblyInformationalVersion("1.18.
|
|
11
|
+
[assembly: AssemblyVersion("1.18.4.0")]
|
|
12
|
+
[assembly: AssemblyFileVersion("1.18.4.0")]
|
|
13
|
+
[assembly: AssemblyInformationalVersion("1.18.4")]
|
|
14
14
|
[assembly: ComVisible(false)]
|
|
@@ -174,6 +174,10 @@ static class Program
|
|
|
174
174
|
new[] { "Microsoft-Windows-Hyper-V-Compute-Admin", "*[System[(Level=1 or Level=2) and " + time + "]]" },
|
|
175
175
|
// A crash report of the programs that hold the VM (kept only when it names one of them, see Detail).
|
|
176
176
|
new[] { "Application", "*[System[(EventID=1000 or EventID=1001) and " + time + "]]" },
|
|
177
|
+
// The graphics driver stopped responding and was reset (with vGPU the sandbox shares the GPU).
|
|
178
|
+
new[] { "System", "*[System[Provider[@Name='Display'] and EventID=4101 and " + time + "]]" },
|
|
179
|
+
// Errors of the Hyper-V services that run the VM.
|
|
180
|
+
new[] { "System", "*[System[(Provider[@Name='Microsoft-Windows-Hyper-V-Worker'] or Provider[@Name='Microsoft-Windows-Hyper-V-VmSwitch'] or Provider[@Name='Microsoft-Windows-Hyper-V-Compute']) and (Level=1 or Level=2) and " + time + "]]" },
|
|
177
181
|
};
|
|
178
182
|
List<string> items = new List<string>();
|
|
179
183
|
foreach (string[] query in queries)
|
|
@@ -261,7 +265,7 @@ static class Program
|
|
|
261
265
|
static bool MentionsVmProgram(string detail)
|
|
262
266
|
{
|
|
263
267
|
string lower = detail.ToLowerInvariant();
|
|
264
|
-
return lower.Contains("vmwp.exe") || lower.Contains("vmmem") || lower.Contains("vmcompute") || lower.Contains("windowssandbox");
|
|
268
|
+
return lower.Contains("vmwp.exe") || lower.Contains("vmmem") || lower.Contains("vmcompute") || lower.Contains("windowssandbox") || lower.Contains("livekernelevent");
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
/// <summary>A JSON string literal.</summary>
|
|
@@ -9,7 +9,7 @@ using System.Runtime.InteropServices;
|
|
|
9
9
|
[assembly: AssemblyCompany("windows-development-sandbox (open source)")]
|
|
10
10
|
[assembly: AssemblyProduct("Windows Development Sandbox")]
|
|
11
11
|
[assembly: AssemblyCopyright("MIT License, windows-development-sandbox contributors")]
|
|
12
|
-
[assembly: AssemblyVersion("1.18.
|
|
13
|
-
[assembly: AssemblyFileVersion("1.18.
|
|
14
|
-
[assembly: AssemblyInformationalVersion("1.18.
|
|
12
|
+
[assembly: AssemblyVersion("1.18.4.0")]
|
|
13
|
+
[assembly: AssemblyFileVersion("1.18.4.0")]
|
|
14
|
+
[assembly: AssemblyInformationalVersion("1.18.4")]
|
|
15
15
|
[assembly: ComVisible(false)]
|
|
@@ -13,8 +13,12 @@ $filters = @(
|
|
|
13
13
|
# Any error or critical event of the Hyper-V worker and compute services (the VM's memory, start and stop).
|
|
14
14
|
@{ LogName = 'Microsoft-Windows-Hyper-V-Worker-Admin'; Level = 1, 2; StartTime = $Since },
|
|
15
15
|
@{ LogName = 'Microsoft-Windows-Hyper-V-Compute-Admin'; Level = 1, 2; StartTime = $Since },
|
|
16
|
-
# A crash report of the programs that hold the VM (kept only when it names one
|
|
17
|
-
@{ LogName = 'Application'; Id = 1000, 1001; StartTime = $Since; OnlyVmPrograms = $true }
|
|
16
|
+
# A crash report of the programs that hold the VM, or a graphics driver (GPU) reset: kept only when it names one.
|
|
17
|
+
@{ LogName = 'Application'; Id = 1000, 1001; StartTime = $Since; OnlyVmPrograms = $true },
|
|
18
|
+
# The graphics driver stopped responding and was reset (with vGPU the sandbox shares the GPU).
|
|
19
|
+
@{ LogName = 'System'; ProviderName = 'Display'; Id = 4101; StartTime = $Since },
|
|
20
|
+
# Errors of the Hyper-V services that run the VM.
|
|
21
|
+
@{ LogName = 'System'; ProviderName = 'Microsoft-Windows-Hyper-V-Worker', 'Microsoft-Windows-Hyper-V-VmSwitch', 'Microsoft-Windows-Hyper-V-Compute'; Level = 1, 2; StartTime = $Since }
|
|
18
22
|
)
|
|
19
23
|
$maxMessage = 390
|
|
20
24
|
$maxResourceMessage = 1500
|
|
@@ -38,7 +42,7 @@ $events = foreach ($filter in $filters) {
|
|
|
38
42
|
$query.Remove('OnlyVmPrograms')
|
|
39
43
|
Get-WinEvent -FilterHashtable $query -MaxEvents 100 | ForEach-Object {
|
|
40
44
|
$detail = Get-EventDetail $_
|
|
41
|
-
if ($onlyVm -and $detail -notmatch 'vmwp\.exe|vmmem|vmcompute|windowssandbox') { return }
|
|
45
|
+
if ($onlyVm -and $detail -notmatch 'vmwp\.exe|vmmem|vmcompute|windowssandbox|LiveKernelEvent') { return }
|
|
42
46
|
[pscustomobject]@{
|
|
43
47
|
at = $_.TimeCreated.ToUniversalTime().ToString('o')
|
|
44
48
|
id = $_.Id
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "windows-development-sandbox",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.4",
|
|
4
4
|
"description": "A disposable Windows Sandbox for development, with or without an AI agent (Claude Code, Codex, Gemini, opencode, ...): the folder you run it from is the workspace, toolchains and databases for your project install themselves, and nothing else on your PC is reachable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/sandbox/csharp/MemGov.cs
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// procs = the processes in the agents' job (the job ptyhost makes for everything the agents start), nothing else.
|
|
7
7
|
// stdin, one command per line:
|
|
8
8
|
// priority <pid> <idle|below|normal> lowers (or restores) the priority of a process in that job
|
|
9
|
+
// iopriority <pid> <verylow|low|normal> the disk queue priority of a process in that job
|
|
9
10
|
// suspend <pid> <ms> pauses a process in that job, resumes it after ms (at most 30000)
|
|
10
11
|
// exit
|
|
11
12
|
//
|
|
@@ -45,6 +46,11 @@ static class MemGov
|
|
|
45
46
|
private const int ProcessMemoryPriorityClass = 0;
|
|
46
47
|
private const uint MemoryPriorityLow = 2;
|
|
47
48
|
private const uint MemoryPriorityNormal = 5;
|
|
49
|
+
// NtSetInformationProcess(ProcessIoPriority): IO_PRIORITY_HINT VeryLow = 0, Low = 1, Normal = 2.
|
|
50
|
+
private const int ProcessIoPriority = 33;
|
|
51
|
+
private const int IoPriorityVeryLow = 0;
|
|
52
|
+
private const int IoPriorityLow = 1;
|
|
53
|
+
private const int IoPriorityNormal = 2;
|
|
48
54
|
|
|
49
55
|
// JOBOBJECT_CPU_RATE_CONTROL_INFORMATION (CpuRate in hundredths of a percent).
|
|
50
56
|
[StructLayout(LayoutKind.Sequential)]
|
|
@@ -133,6 +139,13 @@ static class MemGov
|
|
|
133
139
|
[DllImport("kernel32.dll", EntryPoint = "K32GetProcessMemoryInfo", SetLastError = true)]
|
|
134
140
|
public static extern bool GetProcessMemoryInfo(IntPtr process, ref MemoryCounters counters, uint size);
|
|
135
141
|
|
|
142
|
+
// NTSTATUS, not Win32: SetLastError does not apply, the status is the result (0 = success).
|
|
143
|
+
[DllImport("ntdll.dll")]
|
|
144
|
+
public static extern int NtSetInformationProcess(IntPtr process, int infoClass, ref int info, int length);
|
|
145
|
+
|
|
146
|
+
[DllImport("ntdll.dll")]
|
|
147
|
+
public static extern uint RtlNtStatusToDosError(int status);
|
|
148
|
+
|
|
136
149
|
[DllImport("ntdll.dll")]
|
|
137
150
|
public static extern int NtSuspendProcess(IntPtr process);
|
|
138
151
|
|
|
@@ -397,6 +410,14 @@ static class MemGov
|
|
|
397
410
|
{
|
|
398
411
|
SetMemoryPriority(pid, parts[2] == "low" ? MemoryPriorityLow : MemoryPriorityNormal);
|
|
399
412
|
}
|
|
413
|
+
else if (parts[0] == "iopriority")
|
|
414
|
+
{
|
|
415
|
+
int level = ParseIoPriority(parts[2]);
|
|
416
|
+
if (level >= 0)
|
|
417
|
+
{
|
|
418
|
+
SetIoPriority(pid, level);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
400
421
|
else if (parts[0] == "priority")
|
|
401
422
|
{
|
|
402
423
|
uint cls = parts[2] == "idle" ? IdleClass : parts[2] == "below" ? BelowNormalClass : NormalClass;
|
|
@@ -487,6 +508,43 @@ static class MemGov
|
|
|
487
508
|
}
|
|
488
509
|
}
|
|
489
510
|
|
|
511
|
+
/// <summary>verylow, low or normal to the IO priority value; -1 when it is none of them.</summary>
|
|
512
|
+
private static int ParseIoPriority(string word)
|
|
513
|
+
{
|
|
514
|
+
if (word == "verylow")
|
|
515
|
+
{
|
|
516
|
+
return IoPriorityVeryLow;
|
|
517
|
+
}
|
|
518
|
+
if (word == "low")
|
|
519
|
+
{
|
|
520
|
+
return IoPriorityLow;
|
|
521
|
+
}
|
|
522
|
+
return word == "normal" ? IoPriorityNormal : -1;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/// <summary>The process's disk requests queue behind the others' (needs no privilege for very low and low).</summary>
|
|
526
|
+
private static void SetIoPriority(int pid, int level)
|
|
527
|
+
{
|
|
528
|
+
IntPtr process = NativeMethods.OpenProcess(ProcessSetInformation, false, pid);
|
|
529
|
+
if (process == IntPtr.Zero)
|
|
530
|
+
{
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
try
|
|
534
|
+
{
|
|
535
|
+
int value = level;
|
|
536
|
+
int status = NativeMethods.NtSetInformationProcess(process, ProcessIoPriority, ref value, sizeof(int));
|
|
537
|
+
if (status != 0)
|
|
538
|
+
{
|
|
539
|
+
throw new Win32Exception((int)NativeMethods.RtlNtStatusToDosError(status));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
finally
|
|
543
|
+
{
|
|
544
|
+
NativeMethods.CloseHandle(process);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
490
548
|
/// <summary>A waiting compiler's pages go to the paging file now, so the ones that run have the RAM.</summary>
|
|
491
549
|
private static void Trim(int pid)
|
|
492
550
|
{
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"maximum": 9007199254740991
|
|
145
145
|
}
|
|
146
146
|
],
|
|
147
|
-
"description": "Sandbox RAM in MB (>= 2048), or \"auto\": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %,
|
|
147
|
+
"description": "Sandbox RAM in MB (>= 2048), or \"auto\": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %, 4 GB more with vGPU): a bigger value is lowered."
|
|
148
148
|
},
|
|
149
149
|
"maxMemoryMb": {
|
|
150
150
|
"type": "integer",
|
|
@@ -772,7 +772,7 @@
|
|
|
772
772
|
"targetDir": {
|
|
773
773
|
"type": "string",
|
|
774
774
|
"minLength": 1,
|
|
775
|
-
"description": "\"shared\": cargo's default target\\ (shared with builds on this PC, so builds on either side invalidate the other), \"separate\": <workspace>\\target\\sandbox (kept, no cross-talk), \"local\": on the sandbox's own disk (fastest, lost every boot), or a guest path."
|
|
775
|
+
"description": "\"auto\" (default): on the sandbox's own disk when C: has 25 GB free at boot, else \"separate\" (builds then write through the mapped workspace, which can overload this PC's disk). \"shared\": cargo's default target\\ (shared with builds on this PC, so builds on either side invalidate the other), \"separate\": <workspace>\\target\\sandbox (kept, no cross-talk), \"local\": on the sandbox's own disk (fastest, lost every boot), or a guest path."
|
|
776
776
|
},
|
|
777
777
|
"linker": {
|
|
778
778
|
"type": "string",
|
|
@@ -794,7 +794,7 @@
|
|
|
794
794
|
"maximum": 32
|
|
795
795
|
}
|
|
796
796
|
],
|
|
797
|
-
"description": "GNU host: how many programs may link at the same time in the whole sandbox (other links wait). \"auto\" = one per
|
|
797
|
+
"description": "GNU host: how many programs may link at the same time in the whole sandbox (other links wait). \"auto\" = one per 6 GB of sandbox memory, 1 to 4 (the memory governor slows links down too when memory runs short)."
|
|
798
798
|
}
|
|
799
799
|
},
|
|
800
800
|
"additionalProperties": false
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"maximum": 9007199254740991
|
|
106
106
|
}
|
|
107
107
|
],
|
|
108
|
-
"description": "Sandbox RAM in MB (>= 2048), or \"auto\": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %,
|
|
108
|
+
"description": "Sandbox RAM in MB (>= 2048), or \"auto\": free RAM minus reserveHostMb, capped at maxMemoryMb. Never more than this PC can keep in RAM for it (its RAM minus the larger of reserveHostMb and 25 %, 4 GB more with vGPU): a bigger value is lowered."
|
|
109
109
|
},
|
|
110
110
|
"vGpu": {
|
|
111
111
|
"type": "boolean",
|
|
@@ -457,7 +457,7 @@
|
|
|
457
457
|
"targetDir": {
|
|
458
458
|
"type": "string",
|
|
459
459
|
"minLength": 1,
|
|
460
|
-
"description": "\"shared\": cargo's default target\\ (shared with builds on this PC, so builds on either side invalidate the other), \"separate\": <workspace>\\target\\sandbox (kept, no cross-talk), \"local\": on the sandbox's own disk (fastest, lost every boot), or a guest path."
|
|
460
|
+
"description": "\"auto\" (default): on the sandbox's own disk when C: has 25 GB free at boot, else \"separate\" (builds then write through the mapped workspace, which can overload this PC's disk). \"shared\": cargo's default target\\ (shared with builds on this PC, so builds on either side invalidate the other), \"separate\": <workspace>\\target\\sandbox (kept, no cross-talk), \"local\": on the sandbox's own disk (fastest, lost every boot), or a guest path."
|
|
461
461
|
},
|
|
462
462
|
"linker": {
|
|
463
463
|
"type": "string",
|
|
@@ -479,7 +479,7 @@
|
|
|
479
479
|
"maximum": 32
|
|
480
480
|
}
|
|
481
481
|
],
|
|
482
|
-
"description": "GNU host: how many programs may link at the same time in the whole sandbox (other links wait). \"auto\" = one per
|
|
482
|
+
"description": "GNU host: how many programs may link at the same time in the whole sandbox (other links wait). \"auto\" = one per 6 GB of sandbox memory, 1 to 4 (the memory governor slows links down too when memory runs short)."
|
|
483
483
|
}
|
|
484
484
|
},
|
|
485
485
|
"additionalProperties": false
|