windows-development-sandbox 1.18.0 → 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-BKF43GJ3.js → chunk-3G53NNZP.js} +1 -1
- package/dist/bin/{chunk-YD3A67RS.js → chunk-FQWYCF6L.js} +984 -868
- package/dist/bin/{chunk-Z5D32FN3.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/host/profile/claude-login.js +3 -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
package/dist/runtime/daemon.js
CHANGED
|
@@ -4517,7 +4517,7 @@ var require_lodash = __commonJS({
|
|
|
4517
4517
|
function valuesIn(object2) {
|
|
4518
4518
|
return object2 == null ? [] : baseValues(object2, keysIn(object2));
|
|
4519
4519
|
}
|
|
4520
|
-
function
|
|
4520
|
+
function clamp2(number4, lower, upper) {
|
|
4521
4521
|
if (upper === undefined2) {
|
|
4522
4522
|
upper = lower;
|
|
4523
4523
|
lower = undefined2;
|
|
@@ -5199,7 +5199,7 @@ var require_lodash = __commonJS({
|
|
|
5199
5199
|
lodash.camelCase = camelCase;
|
|
5200
5200
|
lodash.capitalize = capitalize;
|
|
5201
5201
|
lodash.ceil = ceil;
|
|
5202
|
-
lodash.clamp =
|
|
5202
|
+
lodash.clamp = clamp2;
|
|
5203
5203
|
lodash.clone = clone2;
|
|
5204
5204
|
lodash.cloneDeep = cloneDeep;
|
|
5205
5205
|
lodash.cloneDeepWith = cloneDeepWith;
|
|
@@ -25485,7 +25485,7 @@ var SandboxSchema = external_exports.strictObject({
|
|
|
25485
25485
|
'(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.'
|
|
25486
25486
|
),
|
|
25487
25487
|
memoryMb: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(2048)]).describe(
|
|
25488
|
-
'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 %,
|
|
25488
|
+
'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.'
|
|
25489
25489
|
),
|
|
25490
25490
|
maxMemoryMb: external_exports.number().int().positive().describe('Upper limit for memoryMb "auto".'),
|
|
25491
25491
|
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).`),
|
|
@@ -25647,13 +25647,13 @@ var ToolchainsSchema = external_exports.strictObject({
|
|
|
25647
25647
|
'["sccache", "cargo-nextest", "cargo-deny"]'
|
|
25648
25648
|
),
|
|
25649
25649
|
targetDir: external_exports.string().min(1).describe(
|
|
25650
|
-
`"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.`
|
|
25650
|
+
`"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.`
|
|
25651
25651
|
),
|
|
25652
25652
|
linker: external_exports.enum(["lld", "gnu"]).describe(
|
|
25653
25653
|
`GNU host: "lld" links with Rust's own lld through MinGW's gcc (much less memory than GNU ld), "gnu" with GNU ld.`
|
|
25654
25654
|
),
|
|
25655
25655
|
linkSlots: external_exports.union([external_exports.literal("auto"), external_exports.number().int().min(1).max(32)]).describe(
|
|
25656
|
-
'GNU host: how many programs may link at the same time in the whole sandbox (other links wait). "auto" = one per
|
|
25656
|
+
'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).'
|
|
25657
25657
|
)
|
|
25658
25658
|
}),
|
|
25659
25659
|
msvc: external_exports.strictObject({
|
|
@@ -27367,6 +27367,8 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
27367
27367
|
seconds: external_exports.number().int().min(10).max(300),
|
|
27368
27368
|
/** "severe": the PC is nearly out of memory; builds go to the governor's last step at once. */
|
|
27369
27369
|
level: external_exports.enum(["slow", "severe"]).optional(),
|
|
27370
|
+
/** The disk queue the PC reported (shown in the heartbeat). */
|
|
27371
|
+
diskQueue: external_exports.number().min(0).max(1e5).optional(),
|
|
27370
27372
|
createdAt: TimeSchema
|
|
27371
27373
|
})
|
|
27372
27374
|
]);
|
|
@@ -27389,6 +27391,21 @@ var PressureStatusSchema = external_exports.object({
|
|
|
27389
27391
|
lastAction: Text(300),
|
|
27390
27392
|
updatedAt: TimeSchema
|
|
27391
27393
|
});
|
|
27394
|
+
var HeartbeatSchema = external_exports.object({
|
|
27395
|
+
at: TimeSchema,
|
|
27396
|
+
/** Seconds since the sandbox booted. */
|
|
27397
|
+
uptimeS: external_exports.number().int().min(0).max(1e9),
|
|
27398
|
+
ramFreePct: external_exports.number().min(0).max(100),
|
|
27399
|
+
commitPct: external_exports.number().min(0).max(100),
|
|
27400
|
+
/** The governor's dial now, and the step this PC asked for. */
|
|
27401
|
+
step: external_exports.number().int().min(0).max(4),
|
|
27402
|
+
hostStep: external_exports.number().int().min(0).max(4),
|
|
27403
|
+
/** The biggest programs in the agents' job. */
|
|
27404
|
+
topProcesses: external_exports.array(external_exports.object({ name: Text(64), privateMb: external_exports.number().int().min(0).max(1e7) })).max(5),
|
|
27405
|
+
/** The disk queue this PC last reported while asking the sandbox to slow down. */
|
|
27406
|
+
diskQueueReported: external_exports.number().min(0).max(1e5).optional(),
|
|
27407
|
+
phase: external_exports.enum(["ready", "working"])
|
|
27408
|
+
});
|
|
27392
27409
|
var GuestResponseSchema = external_exports.object({
|
|
27393
27410
|
id: IdSchema,
|
|
27394
27411
|
ok: external_exports.boolean(),
|
|
@@ -27699,6 +27716,8 @@ var RunDir = class {
|
|
|
27699
27716
|
vpnFile;
|
|
27700
27717
|
/** What the memory governor in the sandbox is doing (pressure.json). */
|
|
27701
27718
|
pressureFile;
|
|
27719
|
+
/** The daemon's heartbeat every 10 seconds (heartbeat.json): what the sandbox did last. */
|
|
27720
|
+
heartbeatFile;
|
|
27702
27721
|
/** What the sandbox's programs may really use (budget.json): processors, memory, build jobs, link slots. */
|
|
27703
27722
|
budgetFile;
|
|
27704
27723
|
requestsDir;
|
|
@@ -27722,6 +27741,7 @@ var RunDir = class {
|
|
|
27722
27741
|
this.sandboxFile = path7.join(this.root, "sandbox.json");
|
|
27723
27742
|
this.vpnFile = path7.join(this.root, "vpn.json");
|
|
27724
27743
|
this.pressureFile = path7.join(this.root, "pressure.json");
|
|
27744
|
+
this.heartbeatFile = path7.join(this.root, "heartbeat.json");
|
|
27725
27745
|
this.budgetFile = path7.join(this.root, "budget.json");
|
|
27726
27746
|
this.requestsDir = path7.join(this.root, "requests");
|
|
27727
27747
|
this.responsesDir = path7.join(this.root, "responses");
|
|
@@ -27766,6 +27786,9 @@ var RunDir = class {
|
|
|
27766
27786
|
readPressure() {
|
|
27767
27787
|
return readValid(PressureStatusSchema, this.pressureFile);
|
|
27768
27788
|
}
|
|
27789
|
+
readHeartbeat() {
|
|
27790
|
+
return readValid(HeartbeatSchema, this.heartbeatFile);
|
|
27791
|
+
}
|
|
27769
27792
|
readSession(id) {
|
|
27770
27793
|
return readValid(SessionStatusSchema, this.sessionFile(id));
|
|
27771
27794
|
}
|
|
@@ -33038,11 +33061,280 @@ function cargoJobs(cpus, memoryGb, sessions2) {
|
|
|
33038
33061
|
const jobs = Math.min(byCpu, byMemory);
|
|
33039
33062
|
return Math.max(1, Math.min(jobs, Math.floor(buildJobs(cpus, memoryGb) / Math.max(1, sessions2))));
|
|
33040
33063
|
}
|
|
33064
|
+
var LOCAL_TARGET_MIN_BYTES = 25 * 1024 ** 3;
|
|
33065
|
+
function chooseTargetDir(targetDir, freeBytes2) {
|
|
33066
|
+
if (targetDir !== "auto") return { targetDir };
|
|
33067
|
+
if (freeBytes2 >= LOCAL_TARGET_MIN_BYTES) return { targetDir: "local" };
|
|
33068
|
+
return {
|
|
33069
|
+
targetDir: "separate",
|
|
33070
|
+
warning: "Rust builds write through the mapped workspace; this can overload your PC's disk (C: has less than 25 GB free for a local build folder)"
|
|
33071
|
+
};
|
|
33072
|
+
}
|
|
33041
33073
|
function maxCompilers(cpus, profile) {
|
|
33042
|
-
return profile === "gentle" ? Math.max(2, Math.floor(cpus / 4)) : null;
|
|
33074
|
+
return profile === "gentle" ? Math.min(4, Math.max(2, Math.floor(cpus / 4))) : null;
|
|
33075
|
+
}
|
|
33076
|
+
|
|
33077
|
+
// src/guest/governor/decide.ts
|
|
33078
|
+
var COMPILERS = /* @__PURE__ */ new Set([
|
|
33079
|
+
"rustc",
|
|
33080
|
+
"clippy-driver",
|
|
33081
|
+
"rustdoc",
|
|
33082
|
+
"cc1",
|
|
33083
|
+
"cc1plus",
|
|
33084
|
+
"cc1obj",
|
|
33085
|
+
"collect2",
|
|
33086
|
+
"gcc",
|
|
33087
|
+
"g++",
|
|
33088
|
+
"c++",
|
|
33089
|
+
"cc",
|
|
33090
|
+
"clang",
|
|
33091
|
+
"clang++",
|
|
33092
|
+
"clang-cl",
|
|
33093
|
+
"cl",
|
|
33094
|
+
"link",
|
|
33095
|
+
"lld",
|
|
33096
|
+
"lld-link",
|
|
33097
|
+
"ld",
|
|
33098
|
+
"ld.lld",
|
|
33099
|
+
"as",
|
|
33100
|
+
"tsc",
|
|
33101
|
+
"javac"
|
|
33102
|
+
]);
|
|
33103
|
+
var BUILD_TOOLS = /* @__PURE__ */ new Set([
|
|
33104
|
+
"dotnet",
|
|
33105
|
+
"msbuild",
|
|
33106
|
+
"vbcscompiler",
|
|
33107
|
+
"ninja",
|
|
33108
|
+
"make",
|
|
33109
|
+
"mingw32-make",
|
|
33110
|
+
"cmake",
|
|
33111
|
+
"cargo",
|
|
33112
|
+
"go",
|
|
33113
|
+
"java",
|
|
33114
|
+
"gradle",
|
|
33115
|
+
"python"
|
|
33116
|
+
]);
|
|
33117
|
+
var NEVER2 = /* @__PURE__ */ new Set([
|
|
33118
|
+
"claude",
|
|
33119
|
+
"codex",
|
|
33120
|
+
"gemini",
|
|
33121
|
+
"opencode",
|
|
33122
|
+
"aider",
|
|
33123
|
+
"cursor-agent",
|
|
33124
|
+
"cmd",
|
|
33125
|
+
"powershell",
|
|
33126
|
+
"pwsh",
|
|
33127
|
+
"bash",
|
|
33128
|
+
"sh",
|
|
33129
|
+
"zsh",
|
|
33130
|
+
"git",
|
|
33131
|
+
"conhost",
|
|
33132
|
+
"openconsole",
|
|
33133
|
+
"windowsterminal",
|
|
33134
|
+
"wt",
|
|
33135
|
+
"ptyhost",
|
|
33136
|
+
"memgov",
|
|
33137
|
+
"sandboxtools",
|
|
33138
|
+
"sbx-db",
|
|
33139
|
+
"explorer",
|
|
33140
|
+
"csrss",
|
|
33141
|
+
"wininit",
|
|
33142
|
+
"winlogon",
|
|
33143
|
+
"services",
|
|
33144
|
+
"svchost",
|
|
33145
|
+
"lsass",
|
|
33146
|
+
"system",
|
|
33147
|
+
"smss",
|
|
33148
|
+
"dwm"
|
|
33149
|
+
]);
|
|
33150
|
+
var key = (name) => name.toLowerCase().replace(/\.exe$/, "");
|
|
33151
|
+
var isNeverTouched = (name) => NEVER2.has(key(name));
|
|
33152
|
+
var canLower = (name) => !isNeverTouched(name) && (COMPILERS.has(key(name)) || BUILD_TOOLS.has(key(name)));
|
|
33153
|
+
var HEAVY = /* @__PURE__ */ new Set([
|
|
33154
|
+
"rustc",
|
|
33155
|
+
"clippy-driver",
|
|
33156
|
+
"rustdoc",
|
|
33157
|
+
"cc1",
|
|
33158
|
+
"cc1plus",
|
|
33159
|
+
"clang",
|
|
33160
|
+
"clang++",
|
|
33161
|
+
"clang-cl",
|
|
33162
|
+
"cl",
|
|
33163
|
+
"link",
|
|
33164
|
+
"lld",
|
|
33165
|
+
"lld-link",
|
|
33166
|
+
"ld",
|
|
33167
|
+
"ld.lld"
|
|
33168
|
+
]);
|
|
33169
|
+
var LINKERS = /* @__PURE__ */ new Set(["link", "lld", "lld-link", "ld", "ld.lld"]);
|
|
33170
|
+
var isLinker = (name) => !isNeverTouched(name) && LINKERS.has(key(name));
|
|
33171
|
+
function linkerSlots(totalMb, cpus) {
|
|
33172
|
+
return Math.max(1, Math.min(4, Math.max(1, Math.floor(cpus)), Math.floor(totalMb / 6144)));
|
|
33173
|
+
}
|
|
33174
|
+
var isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
|
|
33175
|
+
var canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
|
|
33176
|
+
var INITIAL_STATE = {
|
|
33177
|
+
step: 0,
|
|
33178
|
+
calm: 0,
|
|
33179
|
+
lowered: {},
|
|
33180
|
+
memLow: [],
|
|
33181
|
+
throttled: [],
|
|
33182
|
+
trimmed: [],
|
|
33183
|
+
ioLowered: {},
|
|
33184
|
+
cpuRate: 100,
|
|
33185
|
+
lastCommitMb: 0,
|
|
33186
|
+
lastAt: 0,
|
|
33187
|
+
growth: 0,
|
|
33188
|
+
hostUntil: 0,
|
|
33189
|
+
hostStep: 0
|
|
33190
|
+
};
|
|
33191
|
+
var GROWTH_WEIGHT = 0.3;
|
|
33192
|
+
var HOLD_MS = 3e3;
|
|
33193
|
+
var ROTATE_MS = 2e4;
|
|
33194
|
+
var SOON_WITHIN_PERCENT = 12;
|
|
33195
|
+
function stepFor(ramFree, commit, secondsToLimit, profile) {
|
|
33196
|
+
let step = 0;
|
|
33197
|
+
DIAL_STEPS[profile].forEach((t, i) => {
|
|
33198
|
+
const near = commit > t.commitPercent - SOON_WITHIN_PERCENT;
|
|
33199
|
+
const soon = near && t.secondsToLimit !== void 0 && secondsToLimit < t.secondsToLimit;
|
|
33200
|
+
if (ramFree < t.availablePercent || commit > t.commitPercent || soon) step = i + 1;
|
|
33201
|
+
});
|
|
33202
|
+
return step;
|
|
33203
|
+
}
|
|
33204
|
+
function clearOf(step, ramFree, commit, profile) {
|
|
33205
|
+
if (step === 0) return true;
|
|
33206
|
+
const t = DIAL_STEPS[profile][step - 1];
|
|
33207
|
+
return ramFree > t.availablePercent + DIAL_EXIT_MARGIN.availablePercent && commit < t.commitPercent - DIAL_EXIT_MARGIN.commitPercent;
|
|
33208
|
+
}
|
|
33209
|
+
function decide(prev, sample, nowMs, profile, maxCompilers2 = null) {
|
|
33210
|
+
const ramFree = sample.ramAvailMb / Math.max(1, sample.ramTotalMb) * 100;
|
|
33211
|
+
const usedMb = sample.commitLimitMb - sample.commitAvailMb;
|
|
33212
|
+
const commit = usedMb / Math.max(1, sample.commitLimitMb) * 100;
|
|
33213
|
+
const seconds = (nowMs - prev.lastAt) / 1e3;
|
|
33214
|
+
const instant = prev.lastAt > 0 && seconds > 0 ? (usedMb - prev.lastCommitMb) / seconds : 0;
|
|
33215
|
+
const growth = prev.lastAt > 0 ? prev.growth * (1 - GROWTH_WEIGHT) + instant * GROWTH_WEIGHT : 0;
|
|
33216
|
+
const secondsToLimit = growth > 0 ? sample.commitAvailMb / growth : Number.POSITIVE_INFINITY;
|
|
33217
|
+
const pcLow = nowMs < prev.hostUntil;
|
|
33218
|
+
const wanted2 = Math.max(stepFor(ramFree, commit, secondsToLimit, profile), pcLow ? prev.hostStep : 0);
|
|
33219
|
+
let step = prev.step;
|
|
33220
|
+
let calm = 0;
|
|
33221
|
+
if (wanted2 > prev.step) step = wanted2;
|
|
33222
|
+
else if (prev.step > 0 && wanted2 < prev.step && clearOf(prev.step, ramFree, commit, profile)) {
|
|
33223
|
+
calm = prev.calm + 1;
|
|
33224
|
+
if (calm >= DIAL_CALM_SAMPLES) {
|
|
33225
|
+
step = prev.step - 1;
|
|
33226
|
+
calm = 0;
|
|
33227
|
+
}
|
|
33228
|
+
}
|
|
33229
|
+
if (profile === "gentle" && step < 2 && sample.procs.some((p) => isHeavyCompiler(p.name))) step = 2;
|
|
33230
|
+
const actions = [];
|
|
33231
|
+
const present2 = new Set(sample.procs.map((p) => p.pid));
|
|
33232
|
+
const keep = (pids) => pids.filter((pid) => present2.has(pid));
|
|
33233
|
+
const lowered = {};
|
|
33234
|
+
for (const [pid, to] of Object.entries(prev.lowered)) if (present2.has(Number(pid))) lowered[Number(pid)] = to;
|
|
33235
|
+
const memLow = new Set(keep(prev.memLow));
|
|
33236
|
+
const throttled = new Set(keep(prev.throttled));
|
|
33237
|
+
const trimmed = new Set(keep(prev.trimmed));
|
|
33238
|
+
for (const p of sample.procs) {
|
|
33239
|
+
if (!canLower(p.name)) continue;
|
|
33240
|
+
const rest = profile === "gentle" && canPause(p.name) ? "below" : "normal";
|
|
33241
|
+
const target = step >= 2 ? "idle" : step === 1 ? "below" : rest;
|
|
33242
|
+
const was = lowered[p.pid];
|
|
33243
|
+
const touched = was !== void 0 || target !== "normal";
|
|
33244
|
+
if (touched && was !== target && p.prio !== target)
|
|
33245
|
+
actions.push({ kind: "priority", pid: p.pid, name: p.name, to: target });
|
|
33246
|
+
if (target === "normal") delete lowered[p.pid];
|
|
33247
|
+
else lowered[p.pid] = target;
|
|
33248
|
+
}
|
|
33249
|
+
const ioLowered = {};
|
|
33250
|
+
for (const [pid, to] of Object.entries(prev.ioLowered)) if (present2.has(Number(pid))) ioLowered[Number(pid)] = to;
|
|
33251
|
+
for (const p of sample.procs) {
|
|
33252
|
+
if (!canPause(p.name)) continue;
|
|
33253
|
+
const cpu = lowered[p.pid] ?? "normal";
|
|
33254
|
+
const target = step >= 3 ? "verylow" : cpu !== "normal" ? "low" : "normal";
|
|
33255
|
+
const was = ioLowered[p.pid] ?? "normal";
|
|
33256
|
+
if (was !== target) actions.push({ kind: "io", pid: p.pid, name: p.name, to: target });
|
|
33257
|
+
if (target === "normal") delete ioLowered[p.pid];
|
|
33258
|
+
else ioLowered[p.pid] = target;
|
|
33259
|
+
}
|
|
33260
|
+
const lowMemory = step >= 1;
|
|
33261
|
+
for (const p of sample.procs) {
|
|
33262
|
+
if (!canLower(p.name) || lowMemory === memLow.has(p.pid)) continue;
|
|
33263
|
+
actions.push({ kind: "memory", pid: p.pid, name: p.name, low: lowMemory });
|
|
33264
|
+
if (lowMemory) memLow.add(p.pid);
|
|
33265
|
+
else memLow.delete(p.pid);
|
|
33266
|
+
}
|
|
33267
|
+
if (step >= 2) {
|
|
33268
|
+
for (const p of sample.procs)
|
|
33269
|
+
if (canPause(p.name) && !throttled.has(p.pid)) {
|
|
33270
|
+
actions.push({ kind: "throttle", pid: p.pid, name: p.name });
|
|
33271
|
+
throttled.add(p.pid);
|
|
33272
|
+
}
|
|
33273
|
+
}
|
|
33274
|
+
const cpuRate = DIAL_CPU_RATE[step] ?? 100;
|
|
33275
|
+
if (cpuRate !== prev.cpuRate) actions.push({ kind: "cpu", percent: cpuRate });
|
|
33276
|
+
const heavy = sample.procs.filter((p) => isHeavyCompiler(p.name)).sort((a, b) => a.pid - b.pid);
|
|
33277
|
+
let allowed = compilersAllowed(step, heavy.length);
|
|
33278
|
+
if (maxCompilers2 !== null && step >= 1) allowed = Math.min(allowed, Math.max(1, maxCompilers2));
|
|
33279
|
+
const turn = heavy.length > 0 ? Math.floor(nowMs / ROTATE_MS) % heavy.length : 0;
|
|
33280
|
+
const order = [...heavy.slice(turn), ...heavy.slice(0, turn)];
|
|
33281
|
+
let waiting = order.slice(Math.min(allowed, order.length));
|
|
33282
|
+
if (step >= 2) {
|
|
33283
|
+
const waitingPids = new Set(waiting.map((p) => p.pid));
|
|
33284
|
+
let linking = 0;
|
|
33285
|
+
for (const p of order)
|
|
33286
|
+
if (isLinker(p.name) && !waitingPids.has(p.pid) && ++linking > 1) {
|
|
33287
|
+
waiting = [...waiting, p];
|
|
33288
|
+
waitingPids.add(p.pid);
|
|
33289
|
+
}
|
|
33290
|
+
}
|
|
33291
|
+
if (waiting.length > 0) {
|
|
33292
|
+
const waitingPids = new Set(waiting.map((p) => p.pid));
|
|
33293
|
+
for (const p of waiting) {
|
|
33294
|
+
actions.push({ kind: "hold", pid: p.pid, name: p.name, ms: HOLD_MS });
|
|
33295
|
+
if (step >= 3 && !trimmed.has(p.pid)) {
|
|
33296
|
+
actions.push({ kind: "trim", pid: p.pid, name: p.name });
|
|
33297
|
+
trimmed.add(p.pid);
|
|
33298
|
+
}
|
|
33299
|
+
}
|
|
33300
|
+
for (const p of order) if (!waitingPids.has(p.pid)) trimmed.delete(p.pid);
|
|
33301
|
+
} else trimmed.clear();
|
|
33302
|
+
const level = step >= 3 ? "suspending" : step >= 1 ? "throttled" : "ok";
|
|
33303
|
+
return {
|
|
33304
|
+
state: {
|
|
33305
|
+
step,
|
|
33306
|
+
calm,
|
|
33307
|
+
lowered,
|
|
33308
|
+
memLow: [...memLow],
|
|
33309
|
+
throttled: [...throttled],
|
|
33310
|
+
trimmed: [...trimmed],
|
|
33311
|
+
ioLowered,
|
|
33312
|
+
cpuRate,
|
|
33313
|
+
lastCommitMb: usedMb,
|
|
33314
|
+
lastAt: nowMs,
|
|
33315
|
+
growth,
|
|
33316
|
+
hostUntil: prev.hostUntil,
|
|
33317
|
+
hostStep: prev.hostStep
|
|
33318
|
+
},
|
|
33319
|
+
actions,
|
|
33320
|
+
level,
|
|
33321
|
+
ramFreePercent: Math.round(ramFree),
|
|
33322
|
+
commitPercent: Math.round(commit)
|
|
33323
|
+
};
|
|
33043
33324
|
}
|
|
33044
33325
|
|
|
33045
33326
|
// src/guest/toolchains/native/rust-extras.ts
|
|
33327
|
+
function resolveTargetDir(rust, free = freeBytes((process.env.SystemDrive ?? "C:") + "\\"), note = warn) {
|
|
33328
|
+
if (rust.targetDir !== "auto") return rust;
|
|
33329
|
+
const chosen = chooseTargetDir(rust.targetDir, free);
|
|
33330
|
+
if (chosen.warning) note(chosen.warning);
|
|
33331
|
+
return { ...rust, targetDir: chosen.targetDir };
|
|
33332
|
+
}
|
|
33333
|
+
function targetSummary(rust) {
|
|
33334
|
+
const target = cargoTarget(rust.targetDir);
|
|
33335
|
+
if (target) return "rust builds: " + target + " (CARGO_TARGET_DIR)";
|
|
33336
|
+
return rust.targetDir === "shared" ? "rust builds: target\\ in each project (shared with this PC)" : "rust builds: target\\sandbox in each project (on the mapped workspace)";
|
|
33337
|
+
}
|
|
33046
33338
|
var cargoTarget = (targetDir) => {
|
|
33047
33339
|
if (targetDir === "shared" || targetDir === "separate") return null;
|
|
33048
33340
|
if (targetDir === "local") return path70.join(localDir, "cargo-target");
|
|
@@ -33061,8 +33353,7 @@ function linkGate(env, rust, host) {
|
|
|
33061
33353
|
if (!host.endsWith("-pc-windows-gnu") || !exists(gcc)) return;
|
|
33062
33354
|
const gate = path70.join(mkdirp(tool("shims")), "linkgate.exe");
|
|
33063
33355
|
fs56.copyFileSync(ensureCompiled("linkgate"), gate);
|
|
33064
|
-
const
|
|
33065
|
-
const slots = rust.linkSlots === "auto" ? linkSlotsFor(memoryGb) : rust.linkSlots;
|
|
33356
|
+
const slots = rust.linkSlots === "auto" ? linkerSlots(os10.totalmem() / 1024 ** 2, os10.cpus().length) : rust.linkSlots;
|
|
33066
33357
|
env.vars.AGENT_LINK_SLOTS = String(slots);
|
|
33067
33358
|
env.vars.AGENT_REAL_LINKER = gcc;
|
|
33068
33359
|
env.vars.CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = gate;
|
|
@@ -33174,11 +33465,13 @@ function plan(config2, versions, o) {
|
|
|
33174
33465
|
after: ["C/C++", "MSVC", "Visual Studio", "Unreal"],
|
|
33175
33466
|
install: async (env) => {
|
|
33176
33467
|
await setupRust(env, { ...config2.rust, host: rustHost(config2) }, o.refresh);
|
|
33177
|
-
|
|
33468
|
+
const rust = resolveTargetDir(config2.rust);
|
|
33469
|
+
Object.assign(env.vars, rustCaches(rust));
|
|
33470
|
+
env.summary.push(targetSummary(rust));
|
|
33178
33471
|
if (!dryRun) {
|
|
33179
33472
|
cargoDefaults(rustHost(config2));
|
|
33180
|
-
cargoShim(env,
|
|
33181
|
-
linkGate(env,
|
|
33473
|
+
cargoShim(env, rust);
|
|
33474
|
+
linkGate(env, rust, rustHost(config2));
|
|
33182
33475
|
}
|
|
33183
33476
|
}
|
|
33184
33477
|
},
|
|
@@ -34654,225 +34947,6 @@ var SessionManager = class {
|
|
|
34654
34947
|
};
|
|
34655
34948
|
var sessions = new SessionManager();
|
|
34656
34949
|
|
|
34657
|
-
// src/guest/governor/decide.ts
|
|
34658
|
-
var COMPILERS = /* @__PURE__ */ new Set([
|
|
34659
|
-
"rustc",
|
|
34660
|
-
"clippy-driver",
|
|
34661
|
-
"rustdoc",
|
|
34662
|
-
"cc1",
|
|
34663
|
-
"cc1plus",
|
|
34664
|
-
"cc1obj",
|
|
34665
|
-
"collect2",
|
|
34666
|
-
"gcc",
|
|
34667
|
-
"g++",
|
|
34668
|
-
"c++",
|
|
34669
|
-
"cc",
|
|
34670
|
-
"clang",
|
|
34671
|
-
"clang++",
|
|
34672
|
-
"clang-cl",
|
|
34673
|
-
"cl",
|
|
34674
|
-
"link",
|
|
34675
|
-
"lld",
|
|
34676
|
-
"lld-link",
|
|
34677
|
-
"ld",
|
|
34678
|
-
"ld.lld",
|
|
34679
|
-
"as",
|
|
34680
|
-
"tsc",
|
|
34681
|
-
"javac"
|
|
34682
|
-
]);
|
|
34683
|
-
var BUILD_TOOLS = /* @__PURE__ */ new Set([
|
|
34684
|
-
"dotnet",
|
|
34685
|
-
"msbuild",
|
|
34686
|
-
"vbcscompiler",
|
|
34687
|
-
"ninja",
|
|
34688
|
-
"make",
|
|
34689
|
-
"mingw32-make",
|
|
34690
|
-
"cmake",
|
|
34691
|
-
"cargo",
|
|
34692
|
-
"go",
|
|
34693
|
-
"java",
|
|
34694
|
-
"gradle",
|
|
34695
|
-
"python"
|
|
34696
|
-
]);
|
|
34697
|
-
var NEVER2 = /* @__PURE__ */ new Set([
|
|
34698
|
-
"claude",
|
|
34699
|
-
"codex",
|
|
34700
|
-
"gemini",
|
|
34701
|
-
"opencode",
|
|
34702
|
-
"aider",
|
|
34703
|
-
"cursor-agent",
|
|
34704
|
-
"cmd",
|
|
34705
|
-
"powershell",
|
|
34706
|
-
"pwsh",
|
|
34707
|
-
"bash",
|
|
34708
|
-
"sh",
|
|
34709
|
-
"zsh",
|
|
34710
|
-
"git",
|
|
34711
|
-
"conhost",
|
|
34712
|
-
"openconsole",
|
|
34713
|
-
"windowsterminal",
|
|
34714
|
-
"wt",
|
|
34715
|
-
"ptyhost",
|
|
34716
|
-
"memgov",
|
|
34717
|
-
"sandboxtools",
|
|
34718
|
-
"sbx-db",
|
|
34719
|
-
"explorer",
|
|
34720
|
-
"csrss",
|
|
34721
|
-
"wininit",
|
|
34722
|
-
"winlogon",
|
|
34723
|
-
"services",
|
|
34724
|
-
"svchost",
|
|
34725
|
-
"lsass",
|
|
34726
|
-
"system",
|
|
34727
|
-
"smss",
|
|
34728
|
-
"dwm"
|
|
34729
|
-
]);
|
|
34730
|
-
var key = (name) => name.toLowerCase().replace(/\.exe$/, "");
|
|
34731
|
-
var isNeverTouched = (name) => NEVER2.has(key(name));
|
|
34732
|
-
var canLower = (name) => !isNeverTouched(name) && (COMPILERS.has(key(name)) || BUILD_TOOLS.has(key(name)));
|
|
34733
|
-
var HEAVY = /* @__PURE__ */ new Set([
|
|
34734
|
-
"rustc",
|
|
34735
|
-
"clippy-driver",
|
|
34736
|
-
"rustdoc",
|
|
34737
|
-
"cc1",
|
|
34738
|
-
"cc1plus",
|
|
34739
|
-
"clang",
|
|
34740
|
-
"clang++",
|
|
34741
|
-
"clang-cl",
|
|
34742
|
-
"cl",
|
|
34743
|
-
"link",
|
|
34744
|
-
"lld",
|
|
34745
|
-
"lld-link",
|
|
34746
|
-
"ld",
|
|
34747
|
-
"ld.lld"
|
|
34748
|
-
]);
|
|
34749
|
-
var isHeavyCompiler = (name) => !isNeverTouched(name) && HEAVY.has(key(name));
|
|
34750
|
-
var canPause = (name) => !isNeverTouched(name) && COMPILERS.has(key(name));
|
|
34751
|
-
var INITIAL_STATE = {
|
|
34752
|
-
step: 0,
|
|
34753
|
-
calm: 0,
|
|
34754
|
-
lowered: {},
|
|
34755
|
-
memLow: [],
|
|
34756
|
-
throttled: [],
|
|
34757
|
-
trimmed: [],
|
|
34758
|
-
cpuRate: 100,
|
|
34759
|
-
lastCommitMb: 0,
|
|
34760
|
-
lastAt: 0,
|
|
34761
|
-
growth: 0,
|
|
34762
|
-
hostUntil: 0,
|
|
34763
|
-
hostStep: 0
|
|
34764
|
-
};
|
|
34765
|
-
var GROWTH_WEIGHT = 0.3;
|
|
34766
|
-
var HOLD_MS = 3e3;
|
|
34767
|
-
var ROTATE_MS = 2e4;
|
|
34768
|
-
var SOON_WITHIN_PERCENT = 12;
|
|
34769
|
-
function stepFor(ramFree, commit, secondsToLimit, profile) {
|
|
34770
|
-
let step = 0;
|
|
34771
|
-
DIAL_STEPS[profile].forEach((t, i) => {
|
|
34772
|
-
const near = commit > t.commitPercent - SOON_WITHIN_PERCENT;
|
|
34773
|
-
const soon = near && t.secondsToLimit !== void 0 && secondsToLimit < t.secondsToLimit;
|
|
34774
|
-
if (ramFree < t.availablePercent || commit > t.commitPercent || soon) step = i + 1;
|
|
34775
|
-
});
|
|
34776
|
-
return step;
|
|
34777
|
-
}
|
|
34778
|
-
function clearOf(step, ramFree, commit, profile) {
|
|
34779
|
-
if (step === 0) return true;
|
|
34780
|
-
const t = DIAL_STEPS[profile][step - 1];
|
|
34781
|
-
return ramFree > t.availablePercent + DIAL_EXIT_MARGIN.availablePercent && commit < t.commitPercent - DIAL_EXIT_MARGIN.commitPercent;
|
|
34782
|
-
}
|
|
34783
|
-
function decide(prev, sample, nowMs, profile, maxCompilers2 = null) {
|
|
34784
|
-
const ramFree = sample.ramAvailMb / Math.max(1, sample.ramTotalMb) * 100;
|
|
34785
|
-
const usedMb = sample.commitLimitMb - sample.commitAvailMb;
|
|
34786
|
-
const commit = usedMb / Math.max(1, sample.commitLimitMb) * 100;
|
|
34787
|
-
const seconds = (nowMs - prev.lastAt) / 1e3;
|
|
34788
|
-
const instant = prev.lastAt > 0 && seconds > 0 ? (usedMb - prev.lastCommitMb) / seconds : 0;
|
|
34789
|
-
const growth = prev.lastAt > 0 ? prev.growth * (1 - GROWTH_WEIGHT) + instant * GROWTH_WEIGHT : 0;
|
|
34790
|
-
const secondsToLimit = growth > 0 ? sample.commitAvailMb / growth : Number.POSITIVE_INFINITY;
|
|
34791
|
-
const pcLow = nowMs < prev.hostUntil;
|
|
34792
|
-
const wanted2 = Math.max(stepFor(ramFree, commit, secondsToLimit, profile), pcLow ? prev.hostStep : 0);
|
|
34793
|
-
let step = prev.step;
|
|
34794
|
-
let calm = 0;
|
|
34795
|
-
if (wanted2 > prev.step) step = wanted2;
|
|
34796
|
-
else if (prev.step > 0 && wanted2 < prev.step && clearOf(prev.step, ramFree, commit, profile)) {
|
|
34797
|
-
calm = prev.calm + 1;
|
|
34798
|
-
if (calm >= DIAL_CALM_SAMPLES) {
|
|
34799
|
-
step = prev.step - 1;
|
|
34800
|
-
calm = 0;
|
|
34801
|
-
}
|
|
34802
|
-
}
|
|
34803
|
-
const actions = [];
|
|
34804
|
-
const present2 = new Set(sample.procs.map((p) => p.pid));
|
|
34805
|
-
const keep = (pids) => pids.filter((pid) => present2.has(pid));
|
|
34806
|
-
const lowered = {};
|
|
34807
|
-
for (const [pid, to] of Object.entries(prev.lowered)) if (present2.has(Number(pid))) lowered[Number(pid)] = to;
|
|
34808
|
-
const memLow = new Set(keep(prev.memLow));
|
|
34809
|
-
const throttled = new Set(keep(prev.throttled));
|
|
34810
|
-
const trimmed = new Set(keep(prev.trimmed));
|
|
34811
|
-
for (const p of sample.procs) {
|
|
34812
|
-
if (!canLower(p.name)) continue;
|
|
34813
|
-
const rest = profile === "gentle" && canPause(p.name) ? "below" : "normal";
|
|
34814
|
-
const target = step >= 2 ? "idle" : step === 1 ? "below" : rest;
|
|
34815
|
-
const was = lowered[p.pid];
|
|
34816
|
-
const touched = was !== void 0 || target !== "normal";
|
|
34817
|
-
if (touched && was !== target && p.prio !== target)
|
|
34818
|
-
actions.push({ kind: "priority", pid: p.pid, name: p.name, to: target });
|
|
34819
|
-
if (target === "normal") delete lowered[p.pid];
|
|
34820
|
-
else lowered[p.pid] = target;
|
|
34821
|
-
}
|
|
34822
|
-
const lowMemory = step >= 1;
|
|
34823
|
-
for (const p of sample.procs) {
|
|
34824
|
-
if (!canLower(p.name) || lowMemory === memLow.has(p.pid)) continue;
|
|
34825
|
-
actions.push({ kind: "memory", pid: p.pid, name: p.name, low: lowMemory });
|
|
34826
|
-
if (lowMemory) memLow.add(p.pid);
|
|
34827
|
-
else memLow.delete(p.pid);
|
|
34828
|
-
}
|
|
34829
|
-
if (step >= 2) {
|
|
34830
|
-
for (const p of sample.procs)
|
|
34831
|
-
if (canPause(p.name) && !throttled.has(p.pid)) {
|
|
34832
|
-
actions.push({ kind: "throttle", pid: p.pid, name: p.name });
|
|
34833
|
-
throttled.add(p.pid);
|
|
34834
|
-
}
|
|
34835
|
-
}
|
|
34836
|
-
const cpuRate = DIAL_CPU_RATE[step] ?? 100;
|
|
34837
|
-
if (cpuRate !== prev.cpuRate) actions.push({ kind: "cpu", percent: cpuRate });
|
|
34838
|
-
const heavy = sample.procs.filter((p) => isHeavyCompiler(p.name)).sort((a, b) => a.pid - b.pid);
|
|
34839
|
-
let allowed = compilersAllowed(step, heavy.length);
|
|
34840
|
-
if (maxCompilers2 !== null && step >= 2) allowed = Math.min(allowed, Math.max(1, maxCompilers2));
|
|
34841
|
-
if (allowed < heavy.length) {
|
|
34842
|
-
const turn = Math.floor(nowMs / ROTATE_MS) % heavy.length;
|
|
34843
|
-
const order = [...heavy.slice(turn), ...heavy.slice(0, turn)];
|
|
34844
|
-
for (const p of order.slice(allowed)) {
|
|
34845
|
-
actions.push({ kind: "hold", pid: p.pid, name: p.name, ms: HOLD_MS });
|
|
34846
|
-
if (step >= 3 && !trimmed.has(p.pid)) {
|
|
34847
|
-
actions.push({ kind: "trim", pid: p.pid, name: p.name });
|
|
34848
|
-
trimmed.add(p.pid);
|
|
34849
|
-
}
|
|
34850
|
-
}
|
|
34851
|
-
for (const p of order.slice(0, allowed)) trimmed.delete(p.pid);
|
|
34852
|
-
} else trimmed.clear();
|
|
34853
|
-
const level = step >= 3 ? "suspending" : step >= 1 ? "throttled" : "ok";
|
|
34854
|
-
return {
|
|
34855
|
-
state: {
|
|
34856
|
-
step,
|
|
34857
|
-
calm,
|
|
34858
|
-
lowered,
|
|
34859
|
-
memLow: [...memLow],
|
|
34860
|
-
throttled: [...throttled],
|
|
34861
|
-
trimmed: [...trimmed],
|
|
34862
|
-
cpuRate,
|
|
34863
|
-
lastCommitMb: usedMb,
|
|
34864
|
-
lastAt: nowMs,
|
|
34865
|
-
growth,
|
|
34866
|
-
hostUntil: prev.hostUntil,
|
|
34867
|
-
hostStep: prev.hostStep
|
|
34868
|
-
},
|
|
34869
|
-
actions,
|
|
34870
|
-
level,
|
|
34871
|
-
ramFreePercent: Math.round(ramFree),
|
|
34872
|
-
commitPercent: Math.round(commit)
|
|
34873
|
-
};
|
|
34874
|
-
}
|
|
34875
|
-
|
|
34876
34950
|
// src/guest/governor/core.ts
|
|
34877
34951
|
var STEP_TEXT = [
|
|
34878
34952
|
"builds back to normal",
|
|
@@ -34892,7 +34966,10 @@ var GovernorCore = class {
|
|
|
34892
34966
|
lastWriteAt = 0;
|
|
34893
34967
|
/** Compilers waiting their turn now, by pid (name), to log a hold once. */
|
|
34894
34968
|
held = /* @__PURE__ */ new Map();
|
|
34895
|
-
|
|
34969
|
+
latest = null;
|
|
34970
|
+
diskQueue = null;
|
|
34971
|
+
hostPressure(seconds, reason, level = "slow", diskQueue) {
|
|
34972
|
+
if (diskQueue !== void 0) this.diskQueue = diskQueue;
|
|
34896
34973
|
const nowMs = this.deps.now();
|
|
34897
34974
|
const until = nowMs + seconds * 1e3;
|
|
34898
34975
|
const active = this.state.hostUntil > nowMs;
|
|
@@ -34903,6 +34980,10 @@ var GovernorCore = class {
|
|
|
34903
34980
|
);
|
|
34904
34981
|
this.state = { ...this.state, hostUntil: Math.max(until, this.state.hostUntil), hostStep: step };
|
|
34905
34982
|
}
|
|
34983
|
+
/** The newest numbers, null before the first sample. */
|
|
34984
|
+
get snapshot() {
|
|
34985
|
+
return this.latest ? { ...this.latest, diskQueue: this.diskQueue } : null;
|
|
34986
|
+
}
|
|
34906
34987
|
get current() {
|
|
34907
34988
|
return this.state;
|
|
34908
34989
|
}
|
|
@@ -34911,6 +34992,14 @@ var GovernorCore = class {
|
|
|
34911
34992
|
const before = this.state.step;
|
|
34912
34993
|
const d = decide(this.state, sample, nowMs, this.deps.profile, this.deps.maxCompilers ?? null);
|
|
34913
34994
|
this.state = d.state;
|
|
34995
|
+
this.latest = {
|
|
34996
|
+
ramFreePercent: d.ramFreePercent,
|
|
34997
|
+
commitPercent: d.commitPercent,
|
|
34998
|
+
step: d.state.step,
|
|
34999
|
+
hostStep: nowMs < d.state.hostUntil ? d.state.hostStep : 0,
|
|
35000
|
+
diskQueue: null,
|
|
35001
|
+
top: [...sample.procs].sort((a, b) => b.mb - a.mb).slice(0, 5).map((p) => ({ name: p.name.slice(0, 64), mb: Math.round(p.mb) }))
|
|
35002
|
+
};
|
|
34914
35003
|
const holding = /* @__PURE__ */ new Set();
|
|
34915
35004
|
for (const action of d.actions) {
|
|
34916
35005
|
if (action.kind === "hold") holding.add(action.pid);
|
|
@@ -34956,6 +35045,9 @@ var GovernorCore = class {
|
|
|
34956
35045
|
port.setPriority(action.pid, action.to);
|
|
34957
35046
|
this.note(action.name + " (" + action.pid + ") priority " + action.to);
|
|
34958
35047
|
return;
|
|
35048
|
+
case "io":
|
|
35049
|
+
port.setIoPriority(action.pid, action.to);
|
|
35050
|
+
return;
|
|
34959
35051
|
case "memory":
|
|
34960
35052
|
port.setMemoryPriority(action.pid, action.low);
|
|
34961
35053
|
return;
|
|
@@ -35038,6 +35130,9 @@ var MemGovProcess = class {
|
|
|
35038
35130
|
setMemoryPriority(pid, low) {
|
|
35039
35131
|
this.send("memprio " + pid + " " + (low ? "low" : "normal"));
|
|
35040
35132
|
}
|
|
35133
|
+
setIoPriority(pid, to) {
|
|
35134
|
+
this.send("iopriority " + pid + " " + to);
|
|
35135
|
+
}
|
|
35041
35136
|
throttle(pid) {
|
|
35042
35137
|
this.send("throttle " + pid);
|
|
35043
35138
|
}
|
|
@@ -35091,8 +35186,12 @@ var Governor = class {
|
|
|
35091
35186
|
proc.start();
|
|
35092
35187
|
}
|
|
35093
35188
|
/** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
|
|
35094
|
-
hostPressure(seconds, reason, level = "slow") {
|
|
35095
|
-
this.core?.hostPressure(seconds, reason, level);
|
|
35189
|
+
hostPressure(seconds, reason, level = "slow", diskQueue) {
|
|
35190
|
+
this.core?.hostPressure(seconds, reason, level, diskQueue);
|
|
35191
|
+
}
|
|
35192
|
+
/** The newest numbers, for the heartbeat (null when the governor is off or has not sampled yet). */
|
|
35193
|
+
snapshot() {
|
|
35194
|
+
return this.core?.snapshot ?? null;
|
|
35096
35195
|
}
|
|
35097
35196
|
};
|
|
35098
35197
|
var governor = new Governor();
|
|
@@ -35453,13 +35552,46 @@ var Daemon = class {
|
|
|
35453
35552
|
case "close":
|
|
35454
35553
|
return sessions.close(req);
|
|
35455
35554
|
case "pressure":
|
|
35456
|
-
return governor.hostPressure(req.seconds, req.reason, req.level ?? "slow");
|
|
35555
|
+
return governor.hostPressure(req.seconds, req.reason, req.level ?? "slow", req.diskQueue);
|
|
35457
35556
|
case "ping":
|
|
35458
35557
|
return respond(req.id, { ok: true, message: "pong (" + sessions.count + " session(s) running)" });
|
|
35459
35558
|
}
|
|
35460
35559
|
}
|
|
35461
35560
|
};
|
|
35462
35561
|
|
|
35562
|
+
// src/guest/daemon/heartbeat.ts
|
|
35563
|
+
import os15 from "node:os";
|
|
35564
|
+
var BEAT_MS = 1e4;
|
|
35565
|
+
var clamp = (n, low, high) => Math.max(low, Math.min(high, n));
|
|
35566
|
+
function buildHeartbeat(snapshot2, sessionCount, uptimeSeconds, freeBytes2, totalBytes, at) {
|
|
35567
|
+
const ramFree = snapshot2?.ramFreePercent ?? Math.round(freeBytes2 / Math.max(1, totalBytes) * 100);
|
|
35568
|
+
return {
|
|
35569
|
+
at,
|
|
35570
|
+
uptimeS: Math.max(0, Math.round(uptimeSeconds)),
|
|
35571
|
+
ramFreePct: clamp(ramFree, 0, 100),
|
|
35572
|
+
commitPct: clamp(snapshot2?.commitPercent ?? 0, 0, 100),
|
|
35573
|
+
step: clamp(snapshot2?.step ?? 0, 0, 4),
|
|
35574
|
+
hostStep: clamp(snapshot2?.hostStep ?? 0, 0, 4),
|
|
35575
|
+
topProcesses: (snapshot2?.top ?? []).slice(0, 5).map((p) => ({ name: p.name.slice(0, 64), privateMb: p.mb })),
|
|
35576
|
+
...snapshot2?.diskQueue != null ? { diskQueueReported: snapshot2.diskQueue } : {},
|
|
35577
|
+
phase: sessionCount > 0 ? "working" : "ready"
|
|
35578
|
+
};
|
|
35579
|
+
}
|
|
35580
|
+
function startHeartbeat() {
|
|
35581
|
+
const beat = () => {
|
|
35582
|
+
try {
|
|
35583
|
+
writeJsonAtomic(
|
|
35584
|
+
run.heartbeatFile,
|
|
35585
|
+
buildHeartbeat(governor.snapshot(), sessions.count, os15.uptime(), os15.freemem(), os15.totalmem(), now())
|
|
35586
|
+
);
|
|
35587
|
+
} catch (e) {
|
|
35588
|
+
warn("heartbeat: " + errMsg(e));
|
|
35589
|
+
}
|
|
35590
|
+
};
|
|
35591
|
+
beat();
|
|
35592
|
+
setInterval(beat, BEAT_MS).unref();
|
|
35593
|
+
}
|
|
35594
|
+
|
|
35463
35595
|
// src/guest/entries/daemon.ts
|
|
35464
35596
|
process.on("uncaughtException", (e) => warn("daemon: unexpected error (continuing): " + (e.stack ?? errMsg(e))));
|
|
35465
35597
|
process.on("unhandledRejection", (e) => warn("daemon: unexpected error (continuing): " + errMsg(e)));
|
|
@@ -35472,4 +35604,5 @@ safely("leftover processes", () => sessions.sweepLeftovers());
|
|
|
35472
35604
|
safely("memory governor", () => governor.start());
|
|
35473
35605
|
log("Memory governor: " + governor.describe());
|
|
35474
35606
|
safely("service sign-ins", startAccountWatch);
|
|
35607
|
+
safely("heartbeat", startHeartbeat);
|
|
35475
35608
|
new Daemon().start();
|