omnius 1.0.152 → 1.0.154
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/index.js +164 -19
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -529083,14 +529083,16 @@ async function scanOllamaProcesses(options2 = {}) {
|
|
|
529083
529083
|
]);
|
|
529084
529084
|
const snapshots = [];
|
|
529085
529085
|
for (const row of psRows) {
|
|
529086
|
-
|
|
529086
|
+
const serve = isOllamaServeCommand(row.command);
|
|
529087
|
+
const runner = !serve && isOllamaRunnerCommand(row.command);
|
|
529088
|
+
if (!serve && !runner)
|
|
529087
529089
|
continue;
|
|
529088
|
-
const env2 = await readProcEnv(system, row.pid);
|
|
529090
|
+
const env2 = serve ? await readProcEnv(system, row.pid) : { readable: false, values: {} };
|
|
529089
529091
|
const ports = uniqueNumbers([
|
|
529090
529092
|
...portMap.get(row.pid) ?? [],
|
|
529091
|
-
...portsFromEnv(env2.values)
|
|
529093
|
+
...serve ? portsFromEnv(env2.values) : []
|
|
529092
529094
|
]);
|
|
529093
|
-
const ollamaApiPorts = await probeOllamaPorts(system, ports);
|
|
529095
|
+
const ollamaApiPorts = serve ? await probeOllamaPorts(system, ports) : [];
|
|
529094
529096
|
snapshots.push({
|
|
529095
529097
|
pid: row.pid,
|
|
529096
529098
|
ppid: row.ppid,
|
|
@@ -529103,7 +529105,9 @@ async function scanOllamaProcesses(options2 = {}) {
|
|
|
529103
529105
|
envReadable: env2.readable,
|
|
529104
529106
|
env: env2.values,
|
|
529105
529107
|
gpuMemoryMb: gpuMemoryByPid.get(row.pid) ?? null,
|
|
529106
|
-
isOllamaServe:
|
|
529108
|
+
isOllamaServe: serve,
|
|
529109
|
+
isOllamaRunner: runner,
|
|
529110
|
+
runnerModelBlob: runner ? parseRunnerModelBlob(row.command) : null
|
|
529107
529111
|
});
|
|
529108
529112
|
}
|
|
529109
529113
|
const decisions = classifyOllamaProcesses(snapshots, {
|
|
@@ -529181,11 +529185,11 @@ async function cleanupStaleOllamaProcesses(options2 = {}) {
|
|
|
529181
529185
|
continue;
|
|
529182
529186
|
}
|
|
529183
529187
|
try {
|
|
529184
|
-
system
|
|
529188
|
+
signalOllamaProcess(system, proc, "SIGTERM");
|
|
529185
529189
|
await system.sleep(options2.graceMs ?? DEFAULT_GRACE_MS);
|
|
529186
529190
|
let signal = "SIGTERM";
|
|
529187
529191
|
if (system.isPidAlive(proc.pid)) {
|
|
529188
|
-
system
|
|
529192
|
+
signalOllamaProcess(system, proc, "SIGKILL");
|
|
529189
529193
|
signal = "SIGKILL";
|
|
529190
529194
|
await system.sleep(250);
|
|
529191
529195
|
}
|
|
@@ -529223,6 +529227,20 @@ function classifyOllamaProcesses(processes, options2 = {}) {
|
|
|
529223
529227
|
const hasPortEvidence = proc.ports.length > 0 && proc.ollamaApiPorts.length > 0;
|
|
529224
529228
|
const lowCpu = proc.cpuPct === null || proc.cpuPct <= cpuThresholdPct;
|
|
529225
529229
|
const oldEnough = proc.elapsedMs === null || proc.elapsedMs >= minAgeMs;
|
|
529230
|
+
if (proc.isOllamaRunner) {
|
|
529231
|
+
const liveServePids = new Set(processes.filter((p2) => p2.isOllamaServe).map((p2) => p2.pid));
|
|
529232
|
+
const parentIsLiveServe = proc.ppid !== null && liveServePids.has(proc.ppid);
|
|
529233
|
+
if (parentIsLiveServe) {
|
|
529234
|
+
return decision(proc, "keep", "active-pool-owned", true, false, "deterministic", [`runner managed by live ollama serve pid=${proc.ppid}`]);
|
|
529235
|
+
}
|
|
529236
|
+
reasons.push(`orphan ollama runner (ppid=${proc.ppid ?? "?"} is not a live ollama serve)`);
|
|
529237
|
+
if (proc.runnerModelBlob)
|
|
529238
|
+
reasons.push(`holds model blob ${basename18(proc.runnerModelBlob)}`);
|
|
529239
|
+
if (proc.gpuMemoryMb !== null && proc.gpuMemoryMb > 0) {
|
|
529240
|
+
reasons.push(`holding ${proc.gpuMemoryMb} MB GPU memory`);
|
|
529241
|
+
}
|
|
529242
|
+
return decision(proc, "terminate", "orphan-runner", false, true, "deterministic", reasons);
|
|
529243
|
+
}
|
|
529226
529244
|
if (!proc.isOllamaServe) {
|
|
529227
529245
|
return decision(proc, "keep", "unknown-ollama", false, false, "deterministic", ["not an ollama serve process"]);
|
|
529228
529246
|
}
|
|
@@ -529264,6 +529282,23 @@ function decision(proc, action, classification, protectedProc, eligible, source,
|
|
|
529264
529282
|
reasons
|
|
529265
529283
|
};
|
|
529266
529284
|
}
|
|
529285
|
+
function signalOllamaProcess(system, proc, signal) {
|
|
529286
|
+
let delivered = false;
|
|
529287
|
+
if (proc.isOllamaServe) {
|
|
529288
|
+
try {
|
|
529289
|
+
system.kill(-proc.pid, signal);
|
|
529290
|
+
delivered = true;
|
|
529291
|
+
} catch {
|
|
529292
|
+
}
|
|
529293
|
+
}
|
|
529294
|
+
try {
|
|
529295
|
+
system.kill(proc.pid, signal);
|
|
529296
|
+
delivered = true;
|
|
529297
|
+
} catch (err) {
|
|
529298
|
+
if (!delivered)
|
|
529299
|
+
throw err;
|
|
529300
|
+
}
|
|
529301
|
+
}
|
|
529267
529302
|
async function maybeApplyInference(scan, options2, system) {
|
|
529268
529303
|
const mode = options2.useInference ?? "auto";
|
|
529269
529304
|
if (mode === false || process.env["OMNIUS_OLLAMA_CLEANUP_INFERENCE"] === "0") {
|
|
@@ -529577,6 +529612,14 @@ function isOllamaServeCommand(command) {
|
|
|
529577
529612
|
const [exe, subcommand] = command.trim().split(/\s+/);
|
|
529578
529613
|
return basename18(exe ?? "") === "ollama" && subcommand === "serve";
|
|
529579
529614
|
}
|
|
529615
|
+
function isOllamaRunnerCommand(command) {
|
|
529616
|
+
const [exe, subcommand] = command.trim().split(/\s+/);
|
|
529617
|
+
return basename18(exe ?? "") === "ollama" && subcommand === "runner";
|
|
529618
|
+
}
|
|
529619
|
+
function parseRunnerModelBlob(command) {
|
|
529620
|
+
const m2 = command.match(/--model\s+(\S+)/);
|
|
529621
|
+
return m2?.[1] ?? null;
|
|
529622
|
+
}
|
|
529580
529623
|
function portsFromEnv(env2) {
|
|
529581
529624
|
const host = env2["OLLAMA_HOST"];
|
|
529582
529625
|
if (!host)
|
|
@@ -530144,15 +530187,31 @@ var init_ollama_pool = __esm({
|
|
|
530144
530187
|
const child = spawn23(config.ollamaBinary, ["serve"], {
|
|
530145
530188
|
env: env2,
|
|
530146
530189
|
stdio: ["ignore", "pipe", "pipe"],
|
|
530147
|
-
detached:
|
|
530190
|
+
detached: true
|
|
530148
530191
|
});
|
|
530192
|
+
child.unref();
|
|
530149
530193
|
const proc = {
|
|
530150
530194
|
pid: child.pid ?? -1,
|
|
530151
530195
|
kill: () => {
|
|
530152
|
-
|
|
530153
|
-
|
|
530154
|
-
|
|
530155
|
-
|
|
530196
|
+
const pid = child.pid;
|
|
530197
|
+
if (!pid || pid <= 0)
|
|
530198
|
+
return;
|
|
530199
|
+
const tryKill = (target, sig) => {
|
|
530200
|
+
try {
|
|
530201
|
+
process.kill(target, sig);
|
|
530202
|
+
return true;
|
|
530203
|
+
} catch {
|
|
530204
|
+
return false;
|
|
530205
|
+
}
|
|
530206
|
+
};
|
|
530207
|
+
const groupKilled = tryKill(-pid, "SIGTERM");
|
|
530208
|
+
if (!groupKilled)
|
|
530209
|
+
tryKill(pid, "SIGTERM");
|
|
530210
|
+
setTimeout(() => {
|
|
530211
|
+
if (tryKill(-pid, "SIGKILL"))
|
|
530212
|
+
return;
|
|
530213
|
+
tryKill(pid, "SIGKILL");
|
|
530214
|
+
}, 8e3).unref();
|
|
530156
530215
|
}
|
|
530157
530216
|
};
|
|
530158
530217
|
child.stdout?.on("data", () => {
|
|
@@ -530242,6 +530301,65 @@ var init_ollama_pool = __esm({
|
|
|
530242
530301
|
}, null));
|
|
530243
530302
|
this.startReaper();
|
|
530244
530303
|
this.scheduleStartupCleanupScan();
|
|
530304
|
+
this.installProcessExitHooks();
|
|
530305
|
+
}
|
|
530306
|
+
/**
|
|
530307
|
+
* Process-exit hooks that kill every spawned `ollama serve` subprocess
|
|
530308
|
+
* group on Omnius shutdown. Catches all the ways the previous orphan
|
|
530309
|
+
* runners were created:
|
|
530310
|
+
*
|
|
530311
|
+
* - SIGTERM / SIGINT (systemd stop, Ctrl-C, kill PID)
|
|
530312
|
+
* - process.exit() from a fatal error path
|
|
530313
|
+
* - 'beforeExit' (graceful natural shutdown)
|
|
530314
|
+
*
|
|
530315
|
+
* The 'exit' listener is intentionally synchronous-only because Node has
|
|
530316
|
+
* already started tearing down by then — it just fires `process.kill` on
|
|
530317
|
+
* the recorded PGIDs and returns. Async work is impossible at that stage.
|
|
530318
|
+
*
|
|
530319
|
+
* Signal handlers also forward the signal after teardown so any other
|
|
530320
|
+
* shutdown plumbing (web framework graceful close, etc.) still observes
|
|
530321
|
+
* the original signal — we don't swallow it.
|
|
530322
|
+
*
|
|
530323
|
+
* Idempotent across multiple pool instances in the same process: every
|
|
530324
|
+
* pool only kills its OWN pids.
|
|
530325
|
+
*/
|
|
530326
|
+
installProcessExitHooks() {
|
|
530327
|
+
if (process.env["NODE_ENV"] === "test" || process.env["VITEST"])
|
|
530328
|
+
return;
|
|
530329
|
+
if (process.env["OMNIUS_OLLAMA_PROCESS_EXIT_HOOK"] === "0")
|
|
530330
|
+
return;
|
|
530331
|
+
const killAllPoolOwnedSync = (sig) => {
|
|
530332
|
+
for (const inst of this.instances) {
|
|
530333
|
+
if (!inst.state.poolOwned)
|
|
530334
|
+
continue;
|
|
530335
|
+
const pid = inst.state.pid;
|
|
530336
|
+
if (!pid || pid <= 0)
|
|
530337
|
+
continue;
|
|
530338
|
+
try {
|
|
530339
|
+
process.kill(-pid, sig);
|
|
530340
|
+
} catch {
|
|
530341
|
+
try {
|
|
530342
|
+
process.kill(pid, sig);
|
|
530343
|
+
} catch {
|
|
530344
|
+
}
|
|
530345
|
+
}
|
|
530346
|
+
}
|
|
530347
|
+
};
|
|
530348
|
+
const onSignal = (sig) => {
|
|
530349
|
+
killAllPoolOwnedSync(sig);
|
|
530350
|
+
process.removeListener("SIGTERM", onSigterm);
|
|
530351
|
+
process.removeListener("SIGINT", onSigint);
|
|
530352
|
+
try {
|
|
530353
|
+
process.kill(process.pid, sig);
|
|
530354
|
+
} catch {
|
|
530355
|
+
}
|
|
530356
|
+
};
|
|
530357
|
+
const onSigterm = () => onSignal("SIGTERM");
|
|
530358
|
+
const onSigint = () => onSignal("SIGINT");
|
|
530359
|
+
process.on("SIGTERM", onSigterm);
|
|
530360
|
+
process.on("SIGINT", onSigint);
|
|
530361
|
+
process.on("exit", () => killAllPoolOwnedSync("SIGTERM"));
|
|
530362
|
+
process.on("beforeExit", () => killAllPoolOwnedSync("SIGTERM"));
|
|
530245
530363
|
}
|
|
530246
530364
|
/**
|
|
530247
530365
|
* Resolve the effective agent id for an acquire request. Explicit option
|
|
@@ -530834,7 +530952,7 @@ var init_ollama_pool = __esm({
|
|
|
530834
530952
|
return;
|
|
530835
530953
|
const handle2 = setTimeout(async () => {
|
|
530836
530954
|
try {
|
|
530837
|
-
const cleanupOnStart = process.env["OMNIUS_OLLAMA_CLEANUP_ON_START"]
|
|
530955
|
+
const cleanupOnStart = process.env["OMNIUS_OLLAMA_CLEANUP_ON_START"] !== "0";
|
|
530838
530956
|
const { cleanupStaleOllamaProcesses: cleanupStaleOllamaProcesses2 } = await Promise.resolve().then(() => (init_ollama_pool_cleanup(), ollama_pool_cleanup_exports));
|
|
530839
530957
|
const report2 = await cleanupStaleOllamaProcesses2({
|
|
530840
530958
|
dryRun: !cleanupOnStart,
|
|
@@ -530847,6 +530965,9 @@ var init_ollama_pool = __esm({
|
|
|
530847
530965
|
if (stale.length > 0) {
|
|
530848
530966
|
this.emit(cleanupOnStart ? "stale-process-cleanup" : "stale-processes-found", {
|
|
530849
530967
|
staleCount: stale.length,
|
|
530968
|
+
// Surface orphan-runner counts separately so observability can
|
|
530969
|
+
// alert on the VRAM-hostage failure mode specifically.
|
|
530970
|
+
orphanRunnerCount: report2.decisions.filter((d2) => d2.classification === "orphan-runner" && d2.action === "terminate").length,
|
|
530850
530971
|
dryRun: report2.dryRun,
|
|
530851
530972
|
terminated: report2.terminated,
|
|
530852
530973
|
skipped: report2.skipped,
|
|
@@ -582430,6 +582551,15 @@ ${CONTENT_BG_SEQ}`);
|
|
|
582430
582551
|
return;
|
|
582431
582552
|
}
|
|
582432
582553
|
if (key?.name === "return" || key?.name === "enter") {
|
|
582554
|
+
if (key?.shift) {
|
|
582555
|
+
const currentLine2 = rl.line ?? "";
|
|
582556
|
+
const cursor = typeof rl.cursor === "number" ? rl.cursor : currentLine2.length;
|
|
582557
|
+
rl.line = currentLine2.slice(0, cursor) + "\n" + currentLine2.slice(cursor);
|
|
582558
|
+
rl.cursor = cursor + 1;
|
|
582559
|
+
self2.updateFooterHeight();
|
|
582560
|
+
self2.renderFooterAndPositionInput();
|
|
582561
|
+
return;
|
|
582562
|
+
}
|
|
582433
582563
|
const currentLine = rl.line ?? "";
|
|
582434
582564
|
rl.line = "";
|
|
582435
582565
|
rl.cursor = 0;
|
|
@@ -633985,6 +634115,12 @@ var init_direct_input = __esm({
|
|
|
633985
634115
|
}
|
|
633986
634116
|
break;
|
|
633987
634117
|
}
|
|
634118
|
+
if (remaining.length >= 2 && (remaining[1] === "\r" || remaining[1] === "\n")) {
|
|
634119
|
+
this._insertText("\n");
|
|
634120
|
+
i2 += 2;
|
|
634121
|
+
if (remaining[1] === "\r" && remaining[2] === "\n") i2++;
|
|
634122
|
+
continue;
|
|
634123
|
+
}
|
|
633988
634124
|
if (remaining.length === 1) {
|
|
633989
634125
|
break;
|
|
633990
634126
|
}
|
|
@@ -633992,6 +634128,21 @@ var init_direct_input = __esm({
|
|
|
633992
634128
|
continue;
|
|
633993
634129
|
}
|
|
633994
634130
|
if (code8 < 32 || code8 === 127) {
|
|
634131
|
+
if (code8 === 13) {
|
|
634132
|
+
if (this._preSubmit?.()) {
|
|
634133
|
+
i2++;
|
|
634134
|
+
continue;
|
|
634135
|
+
}
|
|
634136
|
+
this._submit();
|
|
634137
|
+
i2++;
|
|
634138
|
+
if (this._buffer[i2] === "\n") i2++;
|
|
634139
|
+
continue;
|
|
634140
|
+
}
|
|
634141
|
+
if (code8 === 10) {
|
|
634142
|
+
this._insertText("\n");
|
|
634143
|
+
i2++;
|
|
634144
|
+
continue;
|
|
634145
|
+
}
|
|
633995
634146
|
this._handleControl(code8);
|
|
633996
634147
|
i2++;
|
|
633997
634148
|
continue;
|
|
@@ -634194,12 +634345,6 @@ var init_direct_input = __esm({
|
|
|
634194
634345
|
/** Handle control characters (ASCII < 32 and DEL) */
|
|
634195
634346
|
_handleControl(code8) {
|
|
634196
634347
|
switch (code8) {
|
|
634197
|
-
case 13:
|
|
634198
|
-
// Enter (CR)
|
|
634199
|
-
case 10:
|
|
634200
|
-
if (this._preSubmit?.()) return;
|
|
634201
|
-
this._submit();
|
|
634202
|
-
return;
|
|
634203
634348
|
case 127:
|
|
634204
634349
|
// Backspace (DEL)
|
|
634205
634350
|
case 8:
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnius",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.154",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "omnius",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.154",
|
|
10
10
|
"bundleDependencies": [
|
|
11
11
|
"image-to-ascii"
|
|
12
12
|
],
|
package/package.json
CHANGED