windows-development-sandbox 1.18.3 → 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/dist/app/features/defs.d.ts +18 -0
- package/dist/app/features/defs.js +2 -1
- package/dist/app/features/sandbox/sandbox.def.d.ts +22 -0
- package/dist/app/features/sandbox/sandbox.def.js +41 -14
- package/dist/app/features/sandbox/sandbox.run.d.ts +20 -0
- package/dist/app/features/sandbox/sandbox.run.js +41 -1
- package/dist/app/registry.js +2 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-FQWYCF6L.js → chunk-FRPLQLSY.js} +3453 -3145
- package/dist/bin/{chunk-M6XUQK53.js → chunk-MY7NLQQY.js} +1 -1
- package/dist/bin/{chunk-3G53NNZP.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.js +29 -2
- package/dist/guest/daemon/heartbeat.d.ts +7 -2
- package/dist/guest/daemon/heartbeat.js +34 -15
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/entries/daemon.js +1 -1
- 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/life/crash-report.d.ts +1 -1
- package/dist/host/life/crash-report.js +5 -3
- package/dist/host/life/last-end.d.ts +7 -0
- package/dist/host/life/last-end.js +21 -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/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 +3 -1
- package/dist/runtime/daemon.js +368 -351
- package/dist/runtime/db.js +3 -1
- package/dist/runtime/main.js +3 -1
- package/dist/runtime/netproxy.js +3 -1
- package/dist/runtime/tool.js +3 -1
- package/dist/runtime/view.js +3 -1
- package/dist/selftest/heavy-load.test.js +119 -2
- package/dist/shared/channel/schema.d.ts +1 -0
- package/dist/shared/channel/schema.js +2 -1
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/sync/watcher.js +9 -4
- package/dist/web/index.html +1 -1
- package/dist/web/{main-6XYO5FZC.js → main-GVZWWP4I.js} +62 -62
- 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/dist/runtime/daemon.js
CHANGED
|
@@ -27404,7 +27404,8 @@ var HeartbeatSchema = external_exports.object({
|
|
|
27404
27404
|
topProcesses: external_exports.array(external_exports.object({ name: Text(64), privateMb: external_exports.number().int().min(0).max(1e7) })).max(5),
|
|
27405
27405
|
/** The disk queue this PC last reported while asking the sandbox to slow down. */
|
|
27406
27406
|
diskQueueReported: external_exports.number().min(0).max(1e5).optional(),
|
|
27407
|
-
|
|
27407
|
+
/** "ending": the sandbox is shutting down in order (idle shutdown, sandbox stop, Windows shutting down). */
|
|
27408
|
+
phase: external_exports.enum(["ready", "working", "ending"])
|
|
27408
27409
|
});
|
|
27409
27410
|
var GuestResponseSchema = external_exports.object({
|
|
27410
27411
|
id: IdSchema,
|
|
@@ -27889,6 +27890,7 @@ var SYSTEM = {
|
|
|
27889
27890
|
cmd: () => system32("cmd.exe"),
|
|
27890
27891
|
powershell: () => system32("WindowsPowerShell\\v1.0\\powershell.exe"),
|
|
27891
27892
|
tasklist: () => system32("tasklist.exe"),
|
|
27893
|
+
taskkill: () => system32("taskkill.exe"),
|
|
27892
27894
|
whoami: () => system32("whoami.exe"),
|
|
27893
27895
|
icacls: () => system32("icacls.exe"),
|
|
27894
27896
|
tar: () => system32("tar.exe"),
|
|
@@ -33956,11 +33958,11 @@ function execCommand(req) {
|
|
|
33956
33958
|
}
|
|
33957
33959
|
|
|
33958
33960
|
// src/guest/daemon/sessions.ts
|
|
33959
|
-
import
|
|
33960
|
-
import
|
|
33961
|
+
import fs64 from "node:fs";
|
|
33962
|
+
import path81 from "node:path";
|
|
33961
33963
|
import crypto5 from "node:crypto";
|
|
33962
|
-
import
|
|
33963
|
-
import { spawn as
|
|
33964
|
+
import os15 from "node:os";
|
|
33965
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
33964
33966
|
|
|
33965
33967
|
// src/shared/pty/protocol.ts
|
|
33966
33968
|
var FrameType = {
|
|
@@ -34542,71 +34544,368 @@ async function flushAccounts(final = false) {
|
|
|
34542
34544
|
}
|
|
34543
34545
|
}
|
|
34544
34546
|
|
|
34545
|
-
// src/guest/daemon/
|
|
34546
|
-
|
|
34547
|
-
|
|
34548
|
-
|
|
34549
|
-
|
|
34550
|
-
|
|
34547
|
+
// src/guest/daemon/heartbeat.ts
|
|
34548
|
+
import os14 from "node:os";
|
|
34549
|
+
|
|
34550
|
+
// src/guest/governor/core.ts
|
|
34551
|
+
var STEP_TEXT = [
|
|
34552
|
+
"builds back to normal",
|
|
34553
|
+
"build programs at lower priority",
|
|
34554
|
+
"builds get less CPU and take turns",
|
|
34555
|
+
"builds take turns, waiting ones go to the paging file",
|
|
34556
|
+
"one compiler at a time"
|
|
34557
|
+
];
|
|
34558
|
+
var GovernorCore = class {
|
|
34559
|
+
constructor(deps) {
|
|
34560
|
+
this.deps = deps;
|
|
34551
34561
|
}
|
|
34552
|
-
|
|
34553
|
-
|
|
34554
|
-
|
|
34555
|
-
|
|
34556
|
-
|
|
34557
|
-
|
|
34558
|
-
|
|
34559
|
-
|
|
34560
|
-
|
|
34561
|
-
|
|
34562
|
-
|
|
34563
|
-
|
|
34562
|
+
deps;
|
|
34563
|
+
state = INITIAL_STATE;
|
|
34564
|
+
lastAction = "";
|
|
34565
|
+
lastWrite = "";
|
|
34566
|
+
lastWriteAt = 0;
|
|
34567
|
+
/** Compilers waiting their turn now, by pid (name), to log a hold once. */
|
|
34568
|
+
held = /* @__PURE__ */ new Map();
|
|
34569
|
+
latest = null;
|
|
34570
|
+
diskQueue = null;
|
|
34571
|
+
hostPressure(seconds, reason, level = "slow", diskQueue) {
|
|
34572
|
+
if (diskQueue !== void 0) this.diskQueue = diskQueue;
|
|
34573
|
+
const nowMs = this.deps.now();
|
|
34574
|
+
const until = nowMs + seconds * 1e3;
|
|
34575
|
+
const active = this.state.hostUntil > nowMs;
|
|
34576
|
+
const step = Math.max(level === "severe" ? 4 : 2, active ? this.state.hostStep : 0);
|
|
34577
|
+
if (!active || step > this.state.hostStep)
|
|
34578
|
+
this.deps.logLine(
|
|
34579
|
+
"governor: this PC is " + (level === "severe" ? "nearly out of memory" : "low") + " (" + reason + "); builds to step " + step
|
|
34580
|
+
);
|
|
34581
|
+
this.state = { ...this.state, hostUntil: Math.max(until, this.state.hostUntil), hostStep: step };
|
|
34564
34582
|
}
|
|
34565
|
-
|
|
34566
|
-
|
|
34583
|
+
/** The newest numbers, null before the first sample. */
|
|
34584
|
+
get snapshot() {
|
|
34585
|
+
return this.latest ? { ...this.latest, diskQueue: this.diskQueue } : null;
|
|
34586
|
+
}
|
|
34587
|
+
get current() {
|
|
34588
|
+
return this.state;
|
|
34589
|
+
}
|
|
34590
|
+
onSample(sample) {
|
|
34591
|
+
const nowMs = this.deps.now();
|
|
34592
|
+
const before = this.state.step;
|
|
34593
|
+
const d = decide(this.state, sample, nowMs, this.deps.profile, this.deps.maxCompilers ?? null);
|
|
34594
|
+
this.state = d.state;
|
|
34595
|
+
this.latest = {
|
|
34596
|
+
ramFreePercent: d.ramFreePercent,
|
|
34597
|
+
commitPercent: d.commitPercent,
|
|
34598
|
+
step: d.state.step,
|
|
34599
|
+
hostStep: nowMs < d.state.hostUntil ? d.state.hostStep : 0,
|
|
34600
|
+
diskQueue: null,
|
|
34601
|
+
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) }))
|
|
34602
|
+
};
|
|
34603
|
+
const holding = /* @__PURE__ */ new Set();
|
|
34604
|
+
for (const action of d.actions) {
|
|
34605
|
+
if (action.kind === "hold") holding.add(action.pid);
|
|
34606
|
+
this.apply(action);
|
|
34607
|
+
}
|
|
34608
|
+
for (const pid of [...this.held.keys()]) if (!holding.has(pid)) this.held.delete(pid);
|
|
34609
|
+
if (d.state.step !== before)
|
|
34610
|
+
this.deps.logLine(
|
|
34611
|
+
"governor: step " + d.state.step + " (" + d.ramFreePercent + "% RAM free, commit " + d.commitPercent + "% used): " + STEP_TEXT[d.state.step]
|
|
34612
|
+
);
|
|
34613
|
+
const status = {
|
|
34614
|
+
level: d.level,
|
|
34615
|
+
step: d.state.step,
|
|
34616
|
+
profile: this.deps.profile,
|
|
34617
|
+
ramFreePercent: Math.max(0, Math.min(100, d.ramFreePercent)),
|
|
34618
|
+
commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
|
|
34619
|
+
lowered: Object.keys(d.state.lowered).length,
|
|
34620
|
+
paused: [...this.held].slice(0, 8).map(([pid, name]) => ({ name: name.slice(0, 64), pid, seconds: HOLD_MS / 1e3 })),
|
|
34621
|
+
cpuPercent: d.state.cpuRate,
|
|
34622
|
+
pcLow: nowMs < d.state.hostUntil,
|
|
34623
|
+
lastAction: this.lastAction.slice(0, 300),
|
|
34624
|
+
updatedAt: now()
|
|
34625
|
+
};
|
|
34626
|
+
const shape = JSON.stringify({ ...status, updatedAt: "", paused: status.paused.map((p) => p.pid) });
|
|
34627
|
+
if (shape !== this.lastWrite || nowMs - this.lastWriteAt > 6e4) {
|
|
34628
|
+
this.lastWrite = shape;
|
|
34629
|
+
this.lastWriteAt = nowMs;
|
|
34630
|
+
this.deps.saveStatus(status);
|
|
34631
|
+
}
|
|
34632
|
+
}
|
|
34633
|
+
apply(action) {
|
|
34634
|
+
const port = this.deps.port;
|
|
34635
|
+
try {
|
|
34636
|
+
switch (action.kind) {
|
|
34637
|
+
case "hold":
|
|
34638
|
+
port.hold(action.pid, action.ms);
|
|
34639
|
+
if (!this.held.has(action.pid)) {
|
|
34640
|
+
this.held.set(action.pid, action.name);
|
|
34641
|
+
this.note(action.name + " (" + action.pid + ") waits its turn");
|
|
34642
|
+
}
|
|
34643
|
+
return;
|
|
34644
|
+
case "priority":
|
|
34645
|
+
port.setPriority(action.pid, action.to);
|
|
34646
|
+
this.note(action.name + " (" + action.pid + ") priority " + action.to);
|
|
34647
|
+
return;
|
|
34648
|
+
case "io":
|
|
34649
|
+
port.setIoPriority(action.pid, action.to);
|
|
34650
|
+
return;
|
|
34651
|
+
case "memory":
|
|
34652
|
+
port.setMemoryPriority(action.pid, action.low);
|
|
34653
|
+
return;
|
|
34654
|
+
case "throttle":
|
|
34655
|
+
port.throttle(action.pid);
|
|
34656
|
+
return;
|
|
34657
|
+
case "cpu":
|
|
34658
|
+
port.setCpuRate(action.percent);
|
|
34659
|
+
this.note(action.percent >= 100 ? "compilers: no CPU cap" : "compilers: at most " + action.percent + "% CPU");
|
|
34660
|
+
return;
|
|
34661
|
+
case "trim":
|
|
34662
|
+
port.trim(action.pid);
|
|
34663
|
+
return;
|
|
34664
|
+
}
|
|
34665
|
+
} catch (e) {
|
|
34666
|
+
this.deps.warn("governor: " + errMsg(e));
|
|
34667
|
+
}
|
|
34668
|
+
}
|
|
34669
|
+
note(text) {
|
|
34670
|
+
this.lastAction = text;
|
|
34671
|
+
this.deps.logLine("governor: " + text);
|
|
34567
34672
|
}
|
|
34568
34673
|
};
|
|
34569
34674
|
|
|
34570
|
-
// src/guest/
|
|
34571
|
-
|
|
34572
|
-
|
|
34573
|
-
|
|
34574
|
-
|
|
34575
|
-
|
|
34576
|
-
|
|
34577
|
-
|
|
34578
|
-
|
|
34579
|
-
|
|
34580
|
-
|
|
34581
|
-
|
|
34582
|
-
|
|
34583
|
-
|
|
34584
|
-
|
|
34585
|
-
|
|
34586
|
-
|
|
34675
|
+
// src/guest/governor/governor.ts
|
|
34676
|
+
import fs63 from "node:fs";
|
|
34677
|
+
import os13 from "node:os";
|
|
34678
|
+
import path80 from "node:path";
|
|
34679
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
34680
|
+
import { createInterface } from "node:readline";
|
|
34681
|
+
var SampleSchema = external_exports.object({
|
|
34682
|
+
ramTotalMb: external_exports.number(),
|
|
34683
|
+
ramAvailMb: external_exports.number(),
|
|
34684
|
+
commitLimitMb: external_exports.number(),
|
|
34685
|
+
commitAvailMb: external_exports.number(),
|
|
34686
|
+
procs: external_exports.array(
|
|
34687
|
+
external_exports.object({
|
|
34688
|
+
pid: external_exports.number().int(),
|
|
34689
|
+
name: external_exports.string().max(128),
|
|
34690
|
+
mb: external_exports.number(),
|
|
34691
|
+
prio: external_exports.enum(["idle", "below", "normal"]).catch("normal")
|
|
34692
|
+
})
|
|
34693
|
+
).max(1024)
|
|
34694
|
+
});
|
|
34695
|
+
var MemGovProcess = class {
|
|
34696
|
+
constructor(onSample) {
|
|
34697
|
+
this.onSample = onSample;
|
|
34698
|
+
}
|
|
34699
|
+
onSample;
|
|
34700
|
+
child = null;
|
|
34701
|
+
start() {
|
|
34702
|
+
try {
|
|
34703
|
+
const child = spawn8(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
|
|
34704
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
34705
|
+
windowsHide: true
|
|
34706
|
+
});
|
|
34707
|
+
this.child = child;
|
|
34708
|
+
createInterface({ input: child.stdout }).on("line", (line) => {
|
|
34709
|
+
try {
|
|
34710
|
+
this.onSample(SampleSchema.parse(JSON.parse(line)));
|
|
34711
|
+
} catch (e) {
|
|
34712
|
+
warn("governor: bad sample: " + errMsg(e));
|
|
34713
|
+
}
|
|
34714
|
+
});
|
|
34715
|
+
child.stdin.on("error", () => void 0);
|
|
34716
|
+
child.once("exit", () => {
|
|
34717
|
+
this.child = null;
|
|
34718
|
+
setTimeout(() => this.start(), 3e4).unref();
|
|
34719
|
+
});
|
|
34720
|
+
} catch (e) {
|
|
34721
|
+
warn("governor: could not start memgov.exe (no memory governor): " + errMsg(e));
|
|
34722
|
+
}
|
|
34723
|
+
}
|
|
34724
|
+
setPriority(pid, to) {
|
|
34725
|
+
this.send("priority " + pid + " " + to);
|
|
34726
|
+
}
|
|
34727
|
+
hold(pid, ms) {
|
|
34728
|
+
this.send("suspend " + pid + " " + ms);
|
|
34729
|
+
}
|
|
34730
|
+
setMemoryPriority(pid, low) {
|
|
34731
|
+
this.send("memprio " + pid + " " + (low ? "low" : "normal"));
|
|
34732
|
+
}
|
|
34733
|
+
setIoPriority(pid, to) {
|
|
34734
|
+
this.send("iopriority " + pid + " " + to);
|
|
34735
|
+
}
|
|
34736
|
+
throttle(pid) {
|
|
34737
|
+
this.send("throttle " + pid);
|
|
34738
|
+
}
|
|
34739
|
+
setCpuRate(percent) {
|
|
34740
|
+
this.send("cpurate " + Math.round(percent));
|
|
34741
|
+
}
|
|
34742
|
+
trim(pid) {
|
|
34743
|
+
this.send("trim " + pid);
|
|
34744
|
+
}
|
|
34745
|
+
send(line) {
|
|
34746
|
+
this.child?.stdin?.write(line + "\n");
|
|
34747
|
+
}
|
|
34587
34748
|
};
|
|
34588
|
-
function
|
|
34589
|
-
const out = {};
|
|
34590
|
-
out.PTYHOST_BACKSTOP_MB = String(session.agentBackstop ?? "auto");
|
|
34591
|
-
const cpus = usableCpus(os13.cpus().length, session.cpuLimitPercent ?? null);
|
|
34592
|
-
const memoryGb = os13.totalmem() / 1024 ** 3;
|
|
34593
|
-
const jobs = cargoJobs(cpus, memoryGb, sessions2);
|
|
34594
|
-
out.NUMBER_OF_PROCESSORS = String(cpus);
|
|
34595
|
-
if (!env.CARGO_BUILD_JOBS) out.CARGO_BUILD_JOBS = String(jobs);
|
|
34596
|
-
if (!env.CMAKE_BUILD_PARALLEL_LEVEL) out.CMAKE_BUILD_PARALLEL_LEVEL = String(jobs);
|
|
34597
|
-
out.SANDBOX_BUDGET_FILE = run.budgetFile;
|
|
34598
|
-
writeBudget(cpus, memoryGb, jobs, env);
|
|
34599
|
-
return out;
|
|
34600
|
-
}
|
|
34601
|
-
function writeBudget(cpus, memoryGb, jobs, env) {
|
|
34749
|
+
function appendToMemoryLog(line) {
|
|
34602
34750
|
try {
|
|
34603
|
-
|
|
34604
|
-
|
|
34605
|
-
|
|
34606
|
-
|
|
34607
|
-
|
|
34608
|
-
|
|
34609
|
-
|
|
34751
|
+
const logs = path80.join(dataDir, "logs");
|
|
34752
|
+
const newest = fs63.readdirSync(logs).filter((f) => /^memory-\d{8}-\d{6}\.log$/.test(f)).sort().pop();
|
|
34753
|
+
if (!newest) return;
|
|
34754
|
+
const t = /* @__PURE__ */ new Date();
|
|
34755
|
+
const stamp = [t.getHours(), t.getMinutes(), t.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
|
|
34756
|
+
fs63.appendFileSync(path80.join(logs, newest), stamp + " | " + line + "\r\n");
|
|
34757
|
+
} catch {
|
|
34758
|
+
}
|
|
34759
|
+
}
|
|
34760
|
+
var Governor = class {
|
|
34761
|
+
core = null;
|
|
34762
|
+
describe() {
|
|
34763
|
+
const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
|
|
34764
|
+
const first = DIAL_STEPS[profile][0];
|
|
34765
|
+
return session.pressureResponse === false ? "off (sandbox.pressureResponse)" : profile + " profile: slows builds down from " + first.availablePercent + "% free RAM or " + first.commitPercent + "% commit, in steps";
|
|
34766
|
+
}
|
|
34767
|
+
start() {
|
|
34768
|
+
if (session.pressureResponse === false) return;
|
|
34769
|
+
const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
|
|
34770
|
+
const proc = new MemGovProcess((s) => this.core?.onSample(s));
|
|
34771
|
+
this.core = new GovernorCore({
|
|
34772
|
+
port: proc,
|
|
34773
|
+
profile,
|
|
34774
|
+
maxCompilers: maxCompilers(os13.cpus().length, profile),
|
|
34775
|
+
now: () => Date.now(),
|
|
34776
|
+
logLine: appendToMemoryLog,
|
|
34777
|
+
warn,
|
|
34778
|
+
saveStatus: (status) => {
|
|
34779
|
+
try {
|
|
34780
|
+
writeJsonAtomic(run.pressureFile, status);
|
|
34781
|
+
} catch (e) {
|
|
34782
|
+
warn("governor: could not write its status: " + errMsg(e));
|
|
34783
|
+
}
|
|
34784
|
+
}
|
|
34785
|
+
});
|
|
34786
|
+
proc.start();
|
|
34787
|
+
}
|
|
34788
|
+
/** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
|
|
34789
|
+
hostPressure(seconds, reason, level = "slow", diskQueue) {
|
|
34790
|
+
this.core?.hostPressure(seconds, reason, level, diskQueue);
|
|
34791
|
+
}
|
|
34792
|
+
/** The newest numbers, for the heartbeat (null when the governor is off or has not sampled yet). */
|
|
34793
|
+
snapshot() {
|
|
34794
|
+
return this.core?.snapshot ?? null;
|
|
34795
|
+
}
|
|
34796
|
+
};
|
|
34797
|
+
var governor = new Governor();
|
|
34798
|
+
|
|
34799
|
+
// src/guest/daemon/heartbeat.ts
|
|
34800
|
+
var BEAT_MS = 1e4;
|
|
34801
|
+
var clamp = (n, low, high) => Math.max(low, Math.min(high, n));
|
|
34802
|
+
function buildHeartbeat(snapshot2, sessionCount, uptimeSeconds, freeBytes2, totalBytes, at, ending = false) {
|
|
34803
|
+
const ramFree = snapshot2?.ramFreePercent ?? Math.round(freeBytes2 / Math.max(1, totalBytes) * 100);
|
|
34804
|
+
return {
|
|
34805
|
+
at,
|
|
34806
|
+
uptimeS: Math.max(0, Math.round(uptimeSeconds)),
|
|
34807
|
+
ramFreePct: clamp(ramFree, 0, 100),
|
|
34808
|
+
commitPct: clamp(snapshot2?.commitPercent ?? 0, 0, 100),
|
|
34809
|
+
step: clamp(snapshot2?.step ?? 0, 0, 4),
|
|
34810
|
+
hostStep: clamp(snapshot2?.hostStep ?? 0, 0, 4),
|
|
34811
|
+
topProcesses: (snapshot2?.top ?? []).slice(0, 5).map((p) => ({ name: p.name.slice(0, 64), privateMb: p.mb })),
|
|
34812
|
+
...snapshot2?.diskQueue !== null && snapshot2?.diskQueue !== void 0 ? { diskQueueReported: snapshot2.diskQueue } : {},
|
|
34813
|
+
phase: ending ? "ending" : sessionCount > 0 ? "working" : "ready"
|
|
34814
|
+
};
|
|
34815
|
+
}
|
|
34816
|
+
var countSessions = () => 0;
|
|
34817
|
+
function writeBeat(ending) {
|
|
34818
|
+
try {
|
|
34819
|
+
writeJsonAtomic(
|
|
34820
|
+
run.heartbeatFile,
|
|
34821
|
+
buildHeartbeat(governor.snapshot(), countSessions(), os14.uptime(), os14.freemem(), os14.totalmem(), now(), ending)
|
|
34822
|
+
);
|
|
34823
|
+
} catch (e) {
|
|
34824
|
+
warn("heartbeat: " + errMsg(e));
|
|
34825
|
+
}
|
|
34826
|
+
}
|
|
34827
|
+
function markEnding() {
|
|
34828
|
+
writeBeat(true);
|
|
34829
|
+
}
|
|
34830
|
+
function startHeartbeat(sessionCount) {
|
|
34831
|
+
countSessions = sessionCount;
|
|
34832
|
+
writeBeat(false);
|
|
34833
|
+
const timer = setInterval(() => writeBeat(false), BEAT_MS);
|
|
34834
|
+
timer.unref();
|
|
34835
|
+
for (const signal of ["SIGHUP", "SIGBREAK", "SIGTERM"])
|
|
34836
|
+
process.on(signal, () => {
|
|
34837
|
+
clearInterval(timer);
|
|
34838
|
+
markEnding();
|
|
34839
|
+
process.exit(0);
|
|
34840
|
+
});
|
|
34841
|
+
}
|
|
34842
|
+
|
|
34843
|
+
// src/guest/daemon/idle-shutdown.ts
|
|
34844
|
+
var GRACE_MS = 15e3;
|
|
34845
|
+
var IdleShutdown = class {
|
|
34846
|
+
/** `busy`: a session runs or is starting. */
|
|
34847
|
+
constructor(busy) {
|
|
34848
|
+
this.busy = busy;
|
|
34849
|
+
}
|
|
34850
|
+
busy;
|
|
34851
|
+
/** After a session ended or failed: shuts a headless sandbox down if it stays idle for a moment. */
|
|
34852
|
+
check() {
|
|
34853
|
+
if (!session.headless || !isWin) return;
|
|
34854
|
+
if (!this.idle()) return;
|
|
34855
|
+
setTimeout(() => {
|
|
34856
|
+
if (!this.idle()) return;
|
|
34857
|
+
log("Headless sandbox has no sessions left; shutting down.");
|
|
34858
|
+
safely("heartbeat", markEnding);
|
|
34859
|
+
safely("claude-mem save", saveClaudeMem);
|
|
34860
|
+
safely("agent databases save", saveLocalState);
|
|
34861
|
+
void flushAccounts(true).finally(() => spawnSync6(SYSTEM.shutdown(), ["/s", "/t", "5"], { windowsHide: true }));
|
|
34862
|
+
}, GRACE_MS);
|
|
34863
|
+
}
|
|
34864
|
+
idle() {
|
|
34865
|
+
return !this.busy() && run.scanRequests().valid.length === 0;
|
|
34866
|
+
}
|
|
34867
|
+
};
|
|
34868
|
+
|
|
34869
|
+
// src/guest/daemon/sessions.ts
|
|
34870
|
+
var CLOSE_WAIT_MS = 8e3;
|
|
34871
|
+
var ROOTS_KEPT_MS = 10 * 60 * 1e3;
|
|
34872
|
+
function terminalTab(id, title, cwd) {
|
|
34873
|
+
const view = [process.execPath, path81.join(path81.dirname(process.argv[1]), "view.js"), id];
|
|
34874
|
+
const wt = path81.join(toolsDir, "terminal", "wt.exe");
|
|
34875
|
+
if (exists(wt))
|
|
34876
|
+
spawn9(wt, ["-w", "0", "nt", "--title", title, "-d", cwd, ...view], { detached: true, stdio: "ignore" }).unref();
|
|
34877
|
+
else spawn9(SYSTEM.cmd(), ["/d", "/c", "start", title, ...view], { detached: true, stdio: "ignore", cwd }).unref();
|
|
34878
|
+
}
|
|
34879
|
+
var harnessFor = (req) => {
|
|
34880
|
+
if (req.harness === session.harnessName && session.harness) return session.harness;
|
|
34881
|
+
const sent = req.harnessSpec ?? req.project?.harnesses[req.harness];
|
|
34882
|
+
if (sent) return sent;
|
|
34883
|
+
throw new Error(
|
|
34884
|
+
'Agent "' + req.harness + '" is not configured for this sandbox (it runs ' + session.harnessName + ")."
|
|
34885
|
+
);
|
|
34886
|
+
};
|
|
34887
|
+
function memoryEnv(env, sessions2) {
|
|
34888
|
+
const out = {};
|
|
34889
|
+
out.PTYHOST_BACKSTOP_MB = String(session.agentBackstop ?? "auto");
|
|
34890
|
+
const cpus = usableCpus(os15.cpus().length, session.cpuLimitPercent ?? null);
|
|
34891
|
+
const memoryGb = os15.totalmem() / 1024 ** 3;
|
|
34892
|
+
const jobs = cargoJobs(cpus, memoryGb, sessions2);
|
|
34893
|
+
out.NUMBER_OF_PROCESSORS = String(cpus);
|
|
34894
|
+
if (!env.CARGO_BUILD_JOBS) out.CARGO_BUILD_JOBS = String(jobs);
|
|
34895
|
+
if (!env.CMAKE_BUILD_PARALLEL_LEVEL) out.CMAKE_BUILD_PARALLEL_LEVEL = String(jobs);
|
|
34896
|
+
out.SANDBOX_BUDGET_FILE = run.budgetFile;
|
|
34897
|
+
writeBudget(cpus, memoryGb, jobs, env);
|
|
34898
|
+
return out;
|
|
34899
|
+
}
|
|
34900
|
+
function writeBudget(cpus, memoryGb, jobs, env) {
|
|
34901
|
+
try {
|
|
34902
|
+
writeJsonAtomic(run.budgetFile, {
|
|
34903
|
+
processors: cpus,
|
|
34904
|
+
memoryMb: Math.round(memoryGb * 1024),
|
|
34905
|
+
buildJobs: buildJobs(cpus, memoryGb),
|
|
34906
|
+
cargoJobsPerSession: jobs,
|
|
34907
|
+
linkSlots: Number(env.AGENT_LINK_SLOTS) || linkSlotsFor(memoryGb),
|
|
34908
|
+
cpuLimitPercent: session.cpuLimitPercent ?? null,
|
|
34610
34909
|
governor: run.pressureFile,
|
|
34611
34910
|
note: "Plan builds with these numbers. When memory runs short the sandbox slows builds down in steps (governor); nothing fails."
|
|
34612
34911
|
});
|
|
@@ -34628,10 +34927,10 @@ var agentProgram = async (req, env, say) => {
|
|
|
34628
34927
|
};
|
|
34629
34928
|
function shellPaths() {
|
|
34630
34929
|
const candidates = [
|
|
34631
|
-
|
|
34632
|
-
|
|
34930
|
+
path81.join(pwshDir(), "pwsh.exe"),
|
|
34931
|
+
path81.join(process.env.ProgramFiles ?? "C:\\Program Files", "PowerShell", "7", "pwsh.exe")
|
|
34633
34932
|
];
|
|
34634
|
-
return { pwsh: candidates.find((f) =>
|
|
34933
|
+
return { pwsh: candidates.find((f) => fs64.existsSync(f)) ?? null, powershell: SYSTEM.powershell(), cmd: SYSTEM.cmd() };
|
|
34635
34934
|
}
|
|
34636
34935
|
var shellProgram = (shell) => {
|
|
34637
34936
|
const line = commandLine(shell.file, shell.args);
|
|
@@ -34665,7 +34964,7 @@ var launchPtyHost = async (req, program, remote, env, sessions2, onSpawn) => {
|
|
|
34665
34964
|
} catch (e) {
|
|
34666
34965
|
const tail = ptyHostLogTail(req.id);
|
|
34667
34966
|
throw new Error(
|
|
34668
|
-
errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " +
|
|
34967
|
+
errMsg(e) + (tail ? ". From its log:\n" + tail : "") + "\nLog: " + path81.join(dataDir, "logs", "ptyhost-" + req.id + ".log")
|
|
34669
34968
|
);
|
|
34670
34969
|
}
|
|
34671
34970
|
return { child, port, token };
|
|
@@ -34779,7 +35078,7 @@ var SessionManager = class {
|
|
|
34779
35078
|
};
|
|
34780
35079
|
this.starting++;
|
|
34781
35080
|
if (req.id !== session.launchId && process.env.AGENT_NO_TABS !== "1")
|
|
34782
|
-
safely("terminal tab", () => terminalTab(req.id, name + " " +
|
|
35081
|
+
safely("terminal tab", () => terminalTab(req.id, name + " " + path81.basename(req.cwd), req.cwd));
|
|
34783
35082
|
try {
|
|
34784
35083
|
if (problem) throw new Error(problem);
|
|
34785
35084
|
const place = await placeFor(req, say);
|
|
@@ -34947,255 +35246,6 @@ var SessionManager = class {
|
|
|
34947
35246
|
};
|
|
34948
35247
|
var sessions = new SessionManager();
|
|
34949
35248
|
|
|
34950
|
-
// src/guest/governor/core.ts
|
|
34951
|
-
var STEP_TEXT = [
|
|
34952
|
-
"builds back to normal",
|
|
34953
|
-
"build programs at lower priority",
|
|
34954
|
-
"builds get less CPU and take turns",
|
|
34955
|
-
"builds take turns, waiting ones go to the paging file",
|
|
34956
|
-
"one compiler at a time"
|
|
34957
|
-
];
|
|
34958
|
-
var GovernorCore = class {
|
|
34959
|
-
constructor(deps) {
|
|
34960
|
-
this.deps = deps;
|
|
34961
|
-
}
|
|
34962
|
-
deps;
|
|
34963
|
-
state = INITIAL_STATE;
|
|
34964
|
-
lastAction = "";
|
|
34965
|
-
lastWrite = "";
|
|
34966
|
-
lastWriteAt = 0;
|
|
34967
|
-
/** Compilers waiting their turn now, by pid (name), to log a hold once. */
|
|
34968
|
-
held = /* @__PURE__ */ new Map();
|
|
34969
|
-
latest = null;
|
|
34970
|
-
diskQueue = null;
|
|
34971
|
-
hostPressure(seconds, reason, level = "slow", diskQueue) {
|
|
34972
|
-
if (diskQueue !== void 0) this.diskQueue = diskQueue;
|
|
34973
|
-
const nowMs = this.deps.now();
|
|
34974
|
-
const until = nowMs + seconds * 1e3;
|
|
34975
|
-
const active = this.state.hostUntil > nowMs;
|
|
34976
|
-
const step = Math.max(level === "severe" ? 4 : 2, active ? this.state.hostStep : 0);
|
|
34977
|
-
if (!active || step > this.state.hostStep)
|
|
34978
|
-
this.deps.logLine(
|
|
34979
|
-
"governor: this PC is " + (level === "severe" ? "nearly out of memory" : "low") + " (" + reason + "); builds to step " + step
|
|
34980
|
-
);
|
|
34981
|
-
this.state = { ...this.state, hostUntil: Math.max(until, this.state.hostUntil), hostStep: step };
|
|
34982
|
-
}
|
|
34983
|
-
/** The newest numbers, null before the first sample. */
|
|
34984
|
-
get snapshot() {
|
|
34985
|
-
return this.latest ? { ...this.latest, diskQueue: this.diskQueue } : null;
|
|
34986
|
-
}
|
|
34987
|
-
get current() {
|
|
34988
|
-
return this.state;
|
|
34989
|
-
}
|
|
34990
|
-
onSample(sample) {
|
|
34991
|
-
const nowMs = this.deps.now();
|
|
34992
|
-
const before = this.state.step;
|
|
34993
|
-
const d = decide(this.state, sample, nowMs, this.deps.profile, this.deps.maxCompilers ?? null);
|
|
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
|
-
};
|
|
35003
|
-
const holding = /* @__PURE__ */ new Set();
|
|
35004
|
-
for (const action of d.actions) {
|
|
35005
|
-
if (action.kind === "hold") holding.add(action.pid);
|
|
35006
|
-
this.apply(action);
|
|
35007
|
-
}
|
|
35008
|
-
for (const pid of [...this.held.keys()]) if (!holding.has(pid)) this.held.delete(pid);
|
|
35009
|
-
if (d.state.step !== before)
|
|
35010
|
-
this.deps.logLine(
|
|
35011
|
-
"governor: step " + d.state.step + " (" + d.ramFreePercent + "% RAM free, commit " + d.commitPercent + "% used): " + STEP_TEXT[d.state.step]
|
|
35012
|
-
);
|
|
35013
|
-
const status = {
|
|
35014
|
-
level: d.level,
|
|
35015
|
-
step: d.state.step,
|
|
35016
|
-
profile: this.deps.profile,
|
|
35017
|
-
ramFreePercent: Math.max(0, Math.min(100, d.ramFreePercent)),
|
|
35018
|
-
commitPercent: Math.max(0, Math.min(100, d.commitPercent)),
|
|
35019
|
-
lowered: Object.keys(d.state.lowered).length,
|
|
35020
|
-
paused: [...this.held].slice(0, 8).map(([pid, name]) => ({ name: name.slice(0, 64), pid, seconds: HOLD_MS / 1e3 })),
|
|
35021
|
-
cpuPercent: d.state.cpuRate,
|
|
35022
|
-
pcLow: nowMs < d.state.hostUntil,
|
|
35023
|
-
lastAction: this.lastAction.slice(0, 300),
|
|
35024
|
-
updatedAt: now()
|
|
35025
|
-
};
|
|
35026
|
-
const shape = JSON.stringify({ ...status, updatedAt: "", paused: status.paused.map((p) => p.pid) });
|
|
35027
|
-
if (shape !== this.lastWrite || nowMs - this.lastWriteAt > 6e4) {
|
|
35028
|
-
this.lastWrite = shape;
|
|
35029
|
-
this.lastWriteAt = nowMs;
|
|
35030
|
-
this.deps.saveStatus(status);
|
|
35031
|
-
}
|
|
35032
|
-
}
|
|
35033
|
-
apply(action) {
|
|
35034
|
-
const port = this.deps.port;
|
|
35035
|
-
try {
|
|
35036
|
-
switch (action.kind) {
|
|
35037
|
-
case "hold":
|
|
35038
|
-
port.hold(action.pid, action.ms);
|
|
35039
|
-
if (!this.held.has(action.pid)) {
|
|
35040
|
-
this.held.set(action.pid, action.name);
|
|
35041
|
-
this.note(action.name + " (" + action.pid + ") waits its turn");
|
|
35042
|
-
}
|
|
35043
|
-
return;
|
|
35044
|
-
case "priority":
|
|
35045
|
-
port.setPriority(action.pid, action.to);
|
|
35046
|
-
this.note(action.name + " (" + action.pid + ") priority " + action.to);
|
|
35047
|
-
return;
|
|
35048
|
-
case "io":
|
|
35049
|
-
port.setIoPriority(action.pid, action.to);
|
|
35050
|
-
return;
|
|
35051
|
-
case "memory":
|
|
35052
|
-
port.setMemoryPriority(action.pid, action.low);
|
|
35053
|
-
return;
|
|
35054
|
-
case "throttle":
|
|
35055
|
-
port.throttle(action.pid);
|
|
35056
|
-
return;
|
|
35057
|
-
case "cpu":
|
|
35058
|
-
port.setCpuRate(action.percent);
|
|
35059
|
-
this.note(action.percent >= 100 ? "compilers: no CPU cap" : "compilers: at most " + action.percent + "% CPU");
|
|
35060
|
-
return;
|
|
35061
|
-
case "trim":
|
|
35062
|
-
port.trim(action.pid);
|
|
35063
|
-
return;
|
|
35064
|
-
}
|
|
35065
|
-
} catch (e) {
|
|
35066
|
-
this.deps.warn("governor: " + errMsg(e));
|
|
35067
|
-
}
|
|
35068
|
-
}
|
|
35069
|
-
note(text) {
|
|
35070
|
-
this.lastAction = text;
|
|
35071
|
-
this.deps.logLine("governor: " + text);
|
|
35072
|
-
}
|
|
35073
|
-
};
|
|
35074
|
-
|
|
35075
|
-
// src/guest/governor/governor.ts
|
|
35076
|
-
import fs64 from "node:fs";
|
|
35077
|
-
import os14 from "node:os";
|
|
35078
|
-
import path81 from "node:path";
|
|
35079
|
-
import { spawn as spawn9 } from "node:child_process";
|
|
35080
|
-
import { createInterface } from "node:readline";
|
|
35081
|
-
var SampleSchema = external_exports.object({
|
|
35082
|
-
ramTotalMb: external_exports.number(),
|
|
35083
|
-
ramAvailMb: external_exports.number(),
|
|
35084
|
-
commitLimitMb: external_exports.number(),
|
|
35085
|
-
commitAvailMb: external_exports.number(),
|
|
35086
|
-
procs: external_exports.array(
|
|
35087
|
-
external_exports.object({
|
|
35088
|
-
pid: external_exports.number().int(),
|
|
35089
|
-
name: external_exports.string().max(128),
|
|
35090
|
-
mb: external_exports.number(),
|
|
35091
|
-
prio: external_exports.enum(["idle", "below", "normal"]).catch("normal")
|
|
35092
|
-
})
|
|
35093
|
-
).max(1024)
|
|
35094
|
-
});
|
|
35095
|
-
var MemGovProcess = class {
|
|
35096
|
-
constructor(onSample) {
|
|
35097
|
-
this.onSample = onSample;
|
|
35098
|
-
}
|
|
35099
|
-
onSample;
|
|
35100
|
-
child = null;
|
|
35101
|
-
start() {
|
|
35102
|
-
try {
|
|
35103
|
-
const child = spawn9(ensureCompiled("memgov"), ["serve", "--interval", "2"], {
|
|
35104
|
-
stdio: ["pipe", "pipe", "ignore"],
|
|
35105
|
-
windowsHide: true
|
|
35106
|
-
});
|
|
35107
|
-
this.child = child;
|
|
35108
|
-
createInterface({ input: child.stdout }).on("line", (line) => {
|
|
35109
|
-
try {
|
|
35110
|
-
this.onSample(SampleSchema.parse(JSON.parse(line)));
|
|
35111
|
-
} catch (e) {
|
|
35112
|
-
warn("governor: bad sample: " + errMsg(e));
|
|
35113
|
-
}
|
|
35114
|
-
});
|
|
35115
|
-
child.stdin.on("error", () => void 0);
|
|
35116
|
-
child.once("exit", () => {
|
|
35117
|
-
this.child = null;
|
|
35118
|
-
setTimeout(() => this.start(), 3e4).unref();
|
|
35119
|
-
});
|
|
35120
|
-
} catch (e) {
|
|
35121
|
-
warn("governor: could not start memgov.exe (no memory governor): " + errMsg(e));
|
|
35122
|
-
}
|
|
35123
|
-
}
|
|
35124
|
-
setPriority(pid, to) {
|
|
35125
|
-
this.send("priority " + pid + " " + to);
|
|
35126
|
-
}
|
|
35127
|
-
hold(pid, ms) {
|
|
35128
|
-
this.send("suspend " + pid + " " + ms);
|
|
35129
|
-
}
|
|
35130
|
-
setMemoryPriority(pid, low) {
|
|
35131
|
-
this.send("memprio " + pid + " " + (low ? "low" : "normal"));
|
|
35132
|
-
}
|
|
35133
|
-
setIoPriority(pid, to) {
|
|
35134
|
-
this.send("iopriority " + pid + " " + to);
|
|
35135
|
-
}
|
|
35136
|
-
throttle(pid) {
|
|
35137
|
-
this.send("throttle " + pid);
|
|
35138
|
-
}
|
|
35139
|
-
setCpuRate(percent) {
|
|
35140
|
-
this.send("cpurate " + Math.round(percent));
|
|
35141
|
-
}
|
|
35142
|
-
trim(pid) {
|
|
35143
|
-
this.send("trim " + pid);
|
|
35144
|
-
}
|
|
35145
|
-
send(line) {
|
|
35146
|
-
this.child?.stdin?.write(line + "\n");
|
|
35147
|
-
}
|
|
35148
|
-
};
|
|
35149
|
-
function appendToMemoryLog(line) {
|
|
35150
|
-
try {
|
|
35151
|
-
const logs = path81.join(dataDir, "logs");
|
|
35152
|
-
const newest = fs64.readdirSync(logs).filter((f) => /^memory-\d{8}-\d{6}\.log$/.test(f)).sort().pop();
|
|
35153
|
-
if (!newest) return;
|
|
35154
|
-
const t = /* @__PURE__ */ new Date();
|
|
35155
|
-
const stamp = [t.getHours(), t.getMinutes(), t.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
|
|
35156
|
-
fs64.appendFileSync(path81.join(logs, newest), stamp + " | " + line + "\r\n");
|
|
35157
|
-
} catch {
|
|
35158
|
-
}
|
|
35159
|
-
}
|
|
35160
|
-
var Governor = class {
|
|
35161
|
-
core = null;
|
|
35162
|
-
describe() {
|
|
35163
|
-
const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
|
|
35164
|
-
const first = DIAL_STEPS[profile][0];
|
|
35165
|
-
return session.pressureResponse === false ? "off (sandbox.pressureResponse)" : profile + " profile: slows builds down from " + first.availablePercent + "% free RAM or " + first.commitPercent + "% commit, in steps";
|
|
35166
|
-
}
|
|
35167
|
-
start() {
|
|
35168
|
-
if (session.pressureResponse === false) return;
|
|
35169
|
-
const profile = session.loadProfile === "gentle" ? "gentle" : "normal";
|
|
35170
|
-
const proc = new MemGovProcess((s) => this.core?.onSample(s));
|
|
35171
|
-
this.core = new GovernorCore({
|
|
35172
|
-
port: proc,
|
|
35173
|
-
profile,
|
|
35174
|
-
maxCompilers: maxCompilers(os14.cpus().length, profile),
|
|
35175
|
-
now: () => Date.now(),
|
|
35176
|
-
logLine: appendToMemoryLog,
|
|
35177
|
-
warn,
|
|
35178
|
-
saveStatus: (status) => {
|
|
35179
|
-
try {
|
|
35180
|
-
writeJsonAtomic(run.pressureFile, status);
|
|
35181
|
-
} catch (e) {
|
|
35182
|
-
warn("governor: could not write its status: " + errMsg(e));
|
|
35183
|
-
}
|
|
35184
|
-
}
|
|
35185
|
-
});
|
|
35186
|
-
proc.start();
|
|
35187
|
-
}
|
|
35188
|
-
/** The host's watchdog: this PC is low (or nearly out of memory) for a while. */
|
|
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;
|
|
35195
|
-
}
|
|
35196
|
-
};
|
|
35197
|
-
var governor = new Governor();
|
|
35198
|
-
|
|
35199
35249
|
// src/guest/daemon/live.ts
|
|
35200
35250
|
import fs66 from "node:fs";
|
|
35201
35251
|
import path83 from "node:path";
|
|
@@ -35559,39 +35609,6 @@ var Daemon = class {
|
|
|
35559
35609
|
}
|
|
35560
35610
|
};
|
|
35561
35611
|
|
|
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
|
-
|
|
35595
35612
|
// src/guest/entries/daemon.ts
|
|
35596
35613
|
process.on("uncaughtException", (e) => warn("daemon: unexpected error (continuing): " + (e.stack ?? errMsg(e))));
|
|
35597
35614
|
process.on("unhandledRejection", (e) => warn("daemon: unexpected error (continuing): " + errMsg(e)));
|
|
@@ -35604,5 +35621,5 @@ safely("leftover processes", () => sessions.sweepLeftovers());
|
|
|
35604
35621
|
safely("memory governor", () => governor.start());
|
|
35605
35622
|
log("Memory governor: " + governor.describe());
|
|
35606
35623
|
safely("service sign-ins", startAccountWatch);
|
|
35607
|
-
safely("heartbeat", startHeartbeat);
|
|
35624
|
+
safely("heartbeat", () => startHeartbeat(() => sessions.count));
|
|
35608
35625
|
new Daemon().start();
|