windows-development-sandbox 1.18.2 → 1.18.3
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 +8 -0
- package/dist/app/features/sandbox/sandbox.def.d.ts +12 -0
- package/dist/app/features/sandbox/sandbox.def.js +17 -2
- package/dist/app/features/sandbox/sandbox.run.d.ts +4 -0
- package/dist/app/features/sandbox/sandbox.run.js +4 -0
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-IIHL7W6B.js → chunk-3G53NNZP.js} +1 -1
- package/dist/bin/{chunk-MQIA7GNB.js → chunk-FQWYCF6L.js} +981 -866
- package/dist/bin/{chunk-M4OM632I.js → chunk-M6XUQK53.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/repair/checks/sandbox.d.ts +3 -1
- package/dist/cli/commands/repair/checks/sandbox.js +24 -0
- 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 +6 -0
- package/dist/guest/daemon/heartbeat.js +40 -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/launch/wsb-file.d.ts +6 -1
- package/dist/host/launch/wsb-file.js +9 -5
- package/dist/host/life/crash-report.d.ts +2 -0
- package/dist/host/life/crash-report.js +4 -0
- 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 +21 -0
- package/dist/host/life/last-end.js +70 -0
- package/dist/host/life/watchdog.d.ts +2 -0
- package/dist/host/life/watchdog.js +8 -2
- package/dist/runtime/agent.js +26 -3
- package/dist/runtime/daemon.js +367 -234
- package/dist/runtime/db.js +26 -3
- package/dist/runtime/main.js +57 -11
- package/dist/runtime/netproxy.js +26 -3
- package/dist/runtime/tool.js +26 -3
- package/dist/runtime/view.js +26 -3
- package/dist/selftest/heavy-load.test.js +95 -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 +23 -0
- package/dist/shared/channel/schema.js +21 -0
- package/dist/shared/memory/policy.d.ts +10 -0
- package/dist/shared/memory/policy.js +17 -1
- package/dist/sync/watcher.js +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/{main-CWIF4VQI.js → main-6XYO5FZC.js} +43 -43
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -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
|
@@ -192,8 +192,16 @@ export class SandboxChannel {
|
|
|
192
192
|
return this.waitForResponse(requestId, 30000);
|
|
193
193
|
}
|
|
194
194
|
/** The PC is low on memory or CPU: the sandbox slows its builds down for `seconds`. Never waits for an answer. */
|
|
195
|
-
pressure(reason, seconds, level = 'slow') {
|
|
196
|
-
this.send({
|
|
195
|
+
pressure(reason, seconds, level = 'slow', diskQueue) {
|
|
196
|
+
this.send({
|
|
197
|
+
kind: 'pressure',
|
|
198
|
+
id: newId(),
|
|
199
|
+
reason,
|
|
200
|
+
seconds,
|
|
201
|
+
level,
|
|
202
|
+
...(diskQueue === undefined ? {} : { diskQueue }),
|
|
203
|
+
createdAt: now(),
|
|
204
|
+
});
|
|
197
205
|
}
|
|
198
206
|
async ping() {
|
|
199
207
|
const requestId = newId();
|
|
@@ -18,7 +18,12 @@ export interface MemoryDecision {
|
|
|
18
18
|
readonly commitAvailableMb: number | null;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* GPU-PV (vGPU) needs room of its own on this PC: the GPU's shared memory for the sandbox comes out of this PC's RAM,
|
|
22
|
+
* and a GPU game plus heavy builds with vGPU on has killed the VM when the PC had no RAM left for it.
|
|
23
|
+
*/
|
|
24
|
+
export declare const VGPU_RESERVE_MB = 4096;
|
|
25
|
+
/**
|
|
26
|
+
* The most memory this PC can keep in RAM for the sandbox (pure): its RAM minus max(reserveHostMb, 25 %), and 4 GB
|
|
22
27
|
* more with vGPU. Windows Sandbox's memory is this PC's memory taken as needed; beyond what the PC can keep resident it
|
|
23
28
|
* is paged to this PC's disk while the sandbox pages to its own, and that is what can freeze the whole PC.
|
|
24
29
|
*/
|
|
@@ -11,10 +11,13 @@ export const GUEST = {
|
|
|
11
11
|
const MB = 1048576;
|
|
12
12
|
const MIN_AUTO_MEMORY_MB = 4096;
|
|
13
13
|
const roundDown = (mb) => Math.floor(mb / 1024) * 1024;
|
|
14
|
-
/** GPU-PV (vGPU) needs room of its own on this PC: memory the graphics driver pins for the sandbox. */
|
|
15
|
-
const VGPU_RESERVE_MB = 2048;
|
|
16
14
|
/**
|
|
17
|
-
*
|
|
15
|
+
* GPU-PV (vGPU) needs room of its own on this PC: the GPU's shared memory for the sandbox comes out of this PC's RAM,
|
|
16
|
+
* and a GPU game plus heavy builds with vGPU on has killed the VM when the PC had no RAM left for it.
|
|
17
|
+
*/
|
|
18
|
+
export const VGPU_RESERVE_MB = 4096;
|
|
19
|
+
/**
|
|
20
|
+
* The most memory this PC can keep in RAM for the sandbox (pure): its RAM minus max(reserveHostMb, 25 %), and 4 GB
|
|
18
21
|
* more with vGPU. Windows Sandbox's memory is this PC's memory taken as needed; beyond what the PC can keep resident it
|
|
19
22
|
* is paged to this PC's disk while the sandbox pages to its own, and that is what can freeze the whole PC.
|
|
20
23
|
*/
|
|
@@ -46,8 +49,9 @@ export function residentNote(asked, given) {
|
|
|
46
49
|
*/
|
|
47
50
|
export function decideMemory(sandbox, freeMb, totalMb, commitAvailableMb) {
|
|
48
51
|
const shareMb = Math.floor((totalMb * sandbox.maxMemoryPercent) / 100);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
52
|
+
const reserveMb = sandbox.reserveHostMb + (sandbox.vGpu ? VGPU_RESERVE_MB : 0);
|
|
53
|
+
const byFree = freeMb - reserveMb;
|
|
54
|
+
const byCommit = commitAvailableMb === null ? Infinity : commitAvailableMb - reserveMb;
|
|
51
55
|
const candidates = [
|
|
52
56
|
['max', sandbox.maxMemoryMb],
|
|
53
57
|
['share', shareMb],
|
|
@@ -11,6 +11,8 @@ export interface CrashExtra {
|
|
|
11
11
|
readonly hostMemoryNow?: string;
|
|
12
12
|
/** The frozen sandbox's launch had vGPU on (read from its .wsb). */
|
|
13
13
|
readonly vgpu?: boolean;
|
|
14
|
+
/** The sandbox's last heartbeat as a line (see heartbeatLine): what it was doing inside. */
|
|
15
|
+
readonly lastInside?: string;
|
|
14
16
|
}
|
|
15
17
|
/** "This PC stopped responding at X and was restarted at Y (n minutes later)", or null when there was no long gap. */
|
|
16
18
|
export declare function freezeLine(cause: StopCause, lastSeen: string): string | null;
|
|
@@ -6,6 +6,7 @@ import { assertNoLinks, safeText } from '../../core/util/index.js';
|
|
|
6
6
|
import { vgpuWarning } from '../launch/risk-notes.js';
|
|
7
7
|
import { hostMemoryLine, readHostMemory } from './host-memory.js';
|
|
8
8
|
import { hostDataFolder, hostDataRoot } from '../storage/index.js';
|
|
9
|
+
import { heartbeatLine, readHeartbeat } from './last-end.js';
|
|
9
10
|
import { bugcheckCode, explainStop, readStopEvents } from './stop-events.js';
|
|
10
11
|
const KEEP_REPORTS = 20;
|
|
11
12
|
const MEMORY_TAIL_BYTES = 16 * 1024;
|
|
@@ -170,6 +171,7 @@ export function crashReportText(cause, events, memoryLog, lastSeen, extra = {})
|
|
|
170
171
|
...(hostLines.length ? hostLines : [' (none: the background sync was not running)']),
|
|
171
172
|
...(extra.hostMemoryNow ? [' after the restart: ' + extra.hostMemoryNow] : []),
|
|
172
173
|
'',
|
|
174
|
+
...(extra.lastInside ? [safeText(extra.lastInside), ''] : []),
|
|
173
175
|
"The sandbox's memory log, last lines (C:\\AgentData\\logs\\memory-*.log inside it):",
|
|
174
176
|
...memoryLines,
|
|
175
177
|
'',
|
|
@@ -239,9 +241,11 @@ export function saveCrashReport(storageRoot, dataPath, lastSeen) {
|
|
|
239
241
|
const since = new Date(Date.parse(lastSeen) - 10 * 60 * 1000);
|
|
240
242
|
const windir = process.env.SystemRoot ?? 'C:\\Windows';
|
|
241
243
|
const memoryNow = readHostMemory(storageRoot);
|
|
244
|
+
const heartbeat = readHeartbeat(dataPath);
|
|
242
245
|
fs.writeFileSync(file, crashReportText(cause, events, memoryLogTail(dataPath), lastSeen, {
|
|
243
246
|
hostMemoryLog: hostMemoryTail(storageRoot, dataPath),
|
|
244
247
|
vgpu: launchHadVgpu(storageRoot, lastSeen),
|
|
248
|
+
...(heartbeat ? { lastInside: heartbeatLine(heartbeat) } : {}),
|
|
245
249
|
dumps: findDumps([path.join(windir, 'Minidump'), windir], since),
|
|
246
250
|
...(memoryNow ? { hostMemoryNow: hostMemoryLine(memoryNow) } : {}),
|
|
247
251
|
}));
|
|
@@ -4,6 +4,7 @@ export * from './stop-warning.js';
|
|
|
4
4
|
export * from './keep-awake.js';
|
|
5
5
|
export * from './windows-update.js';
|
|
6
6
|
export * from './crash-report.js';
|
|
7
|
+
export * from './last-end.js';
|
|
7
8
|
export * from './session-ledger.js';
|
|
8
9
|
export * from './host-memory.js';
|
|
9
10
|
export * from './watchdog.js';
|
package/dist/host/life/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './stop-warning.js';
|
|
|
4
4
|
export * from './keep-awake.js';
|
|
5
5
|
export * from './windows-update.js';
|
|
6
6
|
export * from './crash-report.js';
|
|
7
|
+
export * from './last-end.js';
|
|
7
8
|
export * from './session-ledger.js';
|
|
8
9
|
export * from './host-memory.js';
|
|
9
10
|
export * from './watchdog.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Heartbeat } from '../../shared/channel/index.js';
|
|
2
|
+
import type { Life } from './life-record.js';
|
|
3
|
+
/** How the last sandbox ended, when nobody closed it. */
|
|
4
|
+
export interface LastEnd {
|
|
5
|
+
/** "ended unexpectedly 21:31: this PC's disks were overloaded (queue 40)". */
|
|
6
|
+
readonly text: string;
|
|
7
|
+
readonly at: string;
|
|
8
|
+
}
|
|
9
|
+
/** The sandbox's last heartbeat, or null (none written, damaged, or reached through a link). */
|
|
10
|
+
export declare function readHeartbeat(dataPath: string): Heartbeat | null;
|
|
11
|
+
/** One line of what the sandbox was doing at its last heartbeat (pure; guest text goes through safeText). */
|
|
12
|
+
export declare function heartbeatLine(hb: Heartbeat): string;
|
|
13
|
+
/** The likeliest reason, from the last heartbeat (pure). */
|
|
14
|
+
export declare function guessReason(hb: Heartbeat | null): string;
|
|
15
|
+
/**
|
|
16
|
+
* How the last sandbox ended (pure): null when it was closed normally, or is still running. `heartbeat` only counts
|
|
17
|
+
* when it was written during that run.
|
|
18
|
+
*/
|
|
19
|
+
export declare function lastEndOf(life: Life | null, heartbeat: Heartbeat | null, running: boolean): LastEnd | null;
|
|
20
|
+
/** The status page's "Last sandbox" fact for this data folder. */
|
|
21
|
+
export declare function readLastEnd(lifeRead: () => Life | null, dataPath: string, running: boolean): LastEnd | null;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// What the sandbox did in its last seconds and how it ended, for the status page and the crash report. The sandbox's
|
|
2
|
+
// daemon writes run\heartbeat.json every 10 seconds; when the sandbox vanishes, the last one is the best evidence.
|
|
3
|
+
// The guest wrote it, so it is read through the schema, never through a link, and printed through safeText.
|
|
4
|
+
import { assertNoLinks, safeText } from '../../core/util/index.js';
|
|
5
|
+
import { RunDir, HeartbeatSchema } from '../../shared/channel/index.js';
|
|
6
|
+
import { readValid } from '../../shared/io/index.js';
|
|
7
|
+
import { hostDataRoot } from '../storage/index.js';
|
|
8
|
+
/** The sandbox's last heartbeat, or null (none written, damaged, or reached through a link). */
|
|
9
|
+
export function readHeartbeat(dataPath) {
|
|
10
|
+
try {
|
|
11
|
+
const root = hostDataRoot(dataPath);
|
|
12
|
+
const file = new RunDir(root).heartbeatFile;
|
|
13
|
+
assertNoLinks(root, file);
|
|
14
|
+
return readValid(HeartbeatSchema, file);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// A link or an unreadable folder: no evidence, never an error.
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const clock = (iso) => {
|
|
22
|
+
const at = new Date(iso);
|
|
23
|
+
return Number.isNaN(at.getTime())
|
|
24
|
+
? iso
|
|
25
|
+
: at.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', hour12: false });
|
|
26
|
+
};
|
|
27
|
+
/** One line of what the sandbox was doing at its last heartbeat (pure; guest text goes through safeText). */
|
|
28
|
+
export function heartbeatLine(hb) {
|
|
29
|
+
const top = hb.topProcesses.map((p) => safeText(p.name) + ' ' + p.privateMb + ' MB').join(', ');
|
|
30
|
+
return ('last seen inside at ' +
|
|
31
|
+
clock(hb.at) +
|
|
32
|
+
': up ' +
|
|
33
|
+
Math.round(hb.uptimeS / 60) +
|
|
34
|
+
' min, ' +
|
|
35
|
+
hb.ramFreePct +
|
|
36
|
+
'% RAM free, ' +
|
|
37
|
+
hb.commitPct +
|
|
38
|
+
'% commit used, builds at step ' +
|
|
39
|
+
hb.step +
|
|
40
|
+
(hb.hostStep > 0 ? ' (this PC asked for step ' + hb.hostStep + ')' : '') +
|
|
41
|
+
(hb.diskQueueReported !== undefined ? ', this PC disk queue ' + hb.diskQueueReported : '') +
|
|
42
|
+
(top ? '; biggest: ' + top : ''));
|
|
43
|
+
}
|
|
44
|
+
/** The likeliest reason, from the last heartbeat (pure). */
|
|
45
|
+
export function guessReason(hb) {
|
|
46
|
+
if (hb && hb.diskQueueReported !== undefined && hb.hostStep > 0)
|
|
47
|
+
return "this PC's disks were overloaded (queue " + hb.diskQueueReported + ')';
|
|
48
|
+
if (hb && (hb.ramFreePct < 8 || hb.commitPct > 92))
|
|
49
|
+
return 'the sandbox was running out of memory';
|
|
50
|
+
return 'Windows stopped it (no reason was logged)';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* How the last sandbox ended (pure): null when it was closed normally, or is still running. `heartbeat` only counts
|
|
54
|
+
* when it was written during that run.
|
|
55
|
+
*/
|
|
56
|
+
export function lastEndOf(life, heartbeat, running) {
|
|
57
|
+
if (!life || running)
|
|
58
|
+
return null;
|
|
59
|
+
if (life.ended && !life.ended.cause)
|
|
60
|
+
return null;
|
|
61
|
+
const hb = heartbeat && Date.parse(heartbeat.at) >= Date.parse(life.started) - 60000 ? heartbeat : null;
|
|
62
|
+
const at = life.ended?.at ?? life.lastSeen;
|
|
63
|
+
const why = life.ended?.cause ? safeText(life.ended.cause.text) : guessReason(hb);
|
|
64
|
+
return { at, text: 'ended unexpectedly ' + clock(at) + ': ' + why };
|
|
65
|
+
}
|
|
66
|
+
/** The status page's "Last sandbox" fact for this data folder. */
|
|
67
|
+
export function readLastEnd(lifeRead, dataPath, running) {
|
|
68
|
+
const life = lifeRead();
|
|
69
|
+
return lastEndOf(life, life && !running ? readHeartbeat(dataPath) : null, running);
|
|
70
|
+
}
|
|
@@ -10,6 +10,8 @@ export interface WatchdogState {
|
|
|
10
10
|
readonly cpuHighSeconds: number;
|
|
11
11
|
/** Seconds the disk queue has been above the limit. */
|
|
12
12
|
readonly diskHighSeconds: number;
|
|
13
|
+
/** Seconds the disk queue has been at or above twice the limit (for the severe step). */
|
|
14
|
+
readonly diskSevereSeconds: number;
|
|
13
15
|
/** Time (ms) the last request went out. */
|
|
14
16
|
readonly lastSentAt: number;
|
|
15
17
|
}
|
|
@@ -9,6 +9,7 @@ export const WATCHDOG_START = {
|
|
|
9
9
|
calm: 0,
|
|
10
10
|
cpuHighSeconds: 0,
|
|
11
11
|
diskHighSeconds: 0,
|
|
12
|
+
diskSevereSeconds: 0,
|
|
12
13
|
lastSentAt: 0,
|
|
13
14
|
};
|
|
14
15
|
/** The request is repeated this often while the PC stays low, and each one lasts a bit longer than that. */
|
|
@@ -50,8 +51,12 @@ export function watchdogStep(prev, input) {
|
|
|
50
51
|
reason = "this PC's CPU has been above " + t.cpuPercent + '% for ' + cpuHigh + ' seconds';
|
|
51
52
|
const diskQueue = input.memory?.diskQueue;
|
|
52
53
|
const diskHigh = diskQueue !== undefined && diskQueue >= t.diskQueue ? prev.diskHighSeconds + input.intervalSeconds : 0;
|
|
54
|
+
const diskDouble = diskQueue !== undefined && diskQueue >= 2 * t.diskQueue ? prev.diskSevereSeconds + input.intervalSeconds : 0;
|
|
55
|
+
const diskSevere = diskDouble >= t.diskSeconds || diskHigh >= 3 * t.diskSeconds;
|
|
53
56
|
if (!reason && diskHigh >= t.diskSeconds)
|
|
54
|
-
reason =
|
|
57
|
+
reason = diskSevere
|
|
58
|
+
? "this PC's disks are overloaded (queue " + diskQueue + ' for ' + diskHigh + ' seconds)'
|
|
59
|
+
: "this PC's disks have had a queue of " + diskQueue + ' for ' + diskHigh + ' seconds';
|
|
55
60
|
const calmNow = input.memory ? lowReason(input.memory, input.reserveHostMb, t, 1.25) === '' : true;
|
|
56
61
|
let low = prev.low;
|
|
57
62
|
let calm = prev.calm;
|
|
@@ -66,7 +71,7 @@ export function watchdogStep(prev, input) {
|
|
|
66
71
|
calm = 0;
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
|
-
const severe = low && input.memory !== null && severeHost(input.memory);
|
|
74
|
+
const severe = low && ((input.memory !== null && severeHost(input.memory)) || diskSevere);
|
|
70
75
|
// Getting severe is sent at once; otherwise the request is repeated every RESEND_MS while the PC stays low.
|
|
71
76
|
const send = low && (input.nowMs - prev.lastSentAt >= RESEND_MS || (severe && !prev.severe));
|
|
72
77
|
return {
|
|
@@ -76,6 +81,7 @@ export function watchdogStep(prev, input) {
|
|
|
76
81
|
calm,
|
|
77
82
|
cpuHighSeconds: cpuHigh,
|
|
78
83
|
diskHighSeconds: diskHigh,
|
|
84
|
+
diskSevereSeconds: diskDouble,
|
|
79
85
|
lastSentAt: send ? input.nowMs : prev.lastSentAt,
|
|
80
86
|
},
|
|
81
87
|
send,
|
package/dist/runtime/agent.js
CHANGED
|
@@ -25466,7 +25466,7 @@ var SandboxSchema = external_exports.strictObject({
|
|
|
25466
25466
|
'(alpha) What runs the sandbox. "windows-sandbox" = Windows Sandbox (the default: desktop, Windows Terminal, GPU, clipboard, audio, printers). "hcs" = a headless Hyper-V isolated Server Core container for agents (no desktop, GPU or clipboard); it needs Windows features and an image on this PC (sandbox engine check hcs lists what is missing), and starting it is not enabled yet in this alpha. sandbox engine shows what each engine can do. Yours only: a project file (.sandbox-config.json) cannot set it.'
|
|
25467
25467
|
),
|
|
25468
25468
|
memoryMb: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(2048)]).describe(
|
|
25469
|
-
'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 %,
|
|
25469
|
+
'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.'
|
|
25470
25470
|
),
|
|
25471
25471
|
maxMemoryMb: external_exports.number().int().positive().describe('Upper limit for memoryMb "auto".'),
|
|
25472
25472
|
maxMemoryPercent: external_exports.number().int().min(10).max(100).describe(`memoryMb "auto" never takes more than this share of this PC's total RAM (percent).`),
|
|
@@ -25628,13 +25628,13 @@ var ToolchainsSchema = external_exports.strictObject({
|
|
|
25628
25628
|
'["sccache", "cargo-nextest", "cargo-deny"]'
|
|
25629
25629
|
),
|
|
25630
25630
|
targetDir: external_exports.string().min(1).describe(
|
|
25631
|
-
`"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.`
|
|
25631
|
+
`"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.`
|
|
25632
25632
|
),
|
|
25633
25633
|
linker: external_exports.enum(["lld", "gnu"]).describe(
|
|
25634
25634
|
`GNU host: "lld" links with Rust's own lld through MinGW's gcc (much less memory than GNU ld), "gnu" with GNU ld.`
|
|
25635
25635
|
),
|
|
25636
25636
|
linkSlots: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(1).max(32)]).describe(
|
|
25637
|
-
'GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per
|
|
25637
|
+
'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).'
|
|
25638
25638
|
)
|
|
25639
25639
|
}),
|
|
25640
25640
|
msvc: external_exports.strictObject({
|
|
@@ -27282,6 +27282,8 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
27282
27282
|
seconds: external_exports.number().int().min(10).max(300),
|
|
27283
27283
|
/** "severe": the PC is nearly out of memory; builds go to the governor's last step at once. */
|
|
27284
27284
|
level: external_exports.enum(["slow", "severe"]).optional(),
|
|
27285
|
+
/** The disk queue the PC reported (shown in the heartbeat). */
|
|
27286
|
+
diskQueue: external_exports.number().min(0).max(1e5).optional(),
|
|
27285
27287
|
createdAt: TimeSchema
|
|
27286
27288
|
})
|
|
27287
27289
|
]);
|
|
@@ -27304,6 +27306,21 @@ var PressureStatusSchema = external_exports.object({
|
|
|
27304
27306
|
lastAction: Text(300),
|
|
27305
27307
|
updatedAt: TimeSchema
|
|
27306
27308
|
});
|
|
27309
|
+
var HeartbeatSchema = external_exports.object({
|
|
27310
|
+
at: TimeSchema,
|
|
27311
|
+
/** Seconds since the sandbox booted. */
|
|
27312
|
+
uptimeS: external_exports.number().int().min(0).max(1e9),
|
|
27313
|
+
ramFreePct: external_exports.number().min(0).max(100),
|
|
27314
|
+
commitPct: external_exports.number().min(0).max(100),
|
|
27315
|
+
/** The governor's dial now, and the step this PC asked for. */
|
|
27316
|
+
step: external_exports.number().int().min(0).max(4),
|
|
27317
|
+
hostStep: external_exports.number().int().min(0).max(4),
|
|
27318
|
+
/** The biggest programs in the agents' job. */
|
|
27319
|
+
topProcesses: external_exports.array(external_exports.object({ name: Text(64), privateMb: external_exports.number().int().min(0).max(1e7) })).max(5),
|
|
27320
|
+
/** The disk queue this PC last reported while asking the sandbox to slow down. */
|
|
27321
|
+
diskQueueReported: external_exports.number().min(0).max(1e5).optional(),
|
|
27322
|
+
phase: external_exports.enum(["ready", "working"])
|
|
27323
|
+
});
|
|
27307
27324
|
var GuestResponseSchema = external_exports.object({
|
|
27308
27325
|
id: IdSchema,
|
|
27309
27326
|
ok: external_exports.boolean(),
|
|
@@ -27489,6 +27506,8 @@ var RunDir = class {
|
|
|
27489
27506
|
vpnFile;
|
|
27490
27507
|
/** What the memory governor in the sandbox is doing (pressure.json). */
|
|
27491
27508
|
pressureFile;
|
|
27509
|
+
/** The daemon's heartbeat every 10 seconds (heartbeat.json): what the sandbox did last. */
|
|
27510
|
+
heartbeatFile;
|
|
27492
27511
|
/** What the sandbox's programs may really use (budget.json): processors, memory, build jobs, link slots. */
|
|
27493
27512
|
budgetFile;
|
|
27494
27513
|
requestsDir;
|
|
@@ -27512,6 +27531,7 @@ var RunDir = class {
|
|
|
27512
27531
|
this.sandboxFile = path5.join(this.root, "sandbox.json");
|
|
27513
27532
|
this.vpnFile = path5.join(this.root, "vpn.json");
|
|
27514
27533
|
this.pressureFile = path5.join(this.root, "pressure.json");
|
|
27534
|
+
this.heartbeatFile = path5.join(this.root, "heartbeat.json");
|
|
27515
27535
|
this.budgetFile = path5.join(this.root, "budget.json");
|
|
27516
27536
|
this.requestsDir = path5.join(this.root, "requests");
|
|
27517
27537
|
this.responsesDir = path5.join(this.root, "responses");
|
|
@@ -27556,6 +27576,9 @@ var RunDir = class {
|
|
|
27556
27576
|
readPressure() {
|
|
27557
27577
|
return readValid(PressureStatusSchema, this.pressureFile);
|
|
27558
27578
|
}
|
|
27579
|
+
readHeartbeat() {
|
|
27580
|
+
return readValid(HeartbeatSchema, this.heartbeatFile);
|
|
27581
|
+
}
|
|
27559
27582
|
readSession(id) {
|
|
27560
27583
|
return readValid(SessionStatusSchema, this.sessionFile(id));
|
|
27561
27584
|
}
|