moshcode 0.90.0 → 0.92.0
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/README.md +124 -0
- package/bin/moshcode.mjs +7 -0
- package/package.json +1 -1
- package/prd/0013-persistent-ssh-workspaces.md +1181 -0
- package/prd/README.md +2 -0
- package/src/cli-schema.mjs +123 -0
- package/src/commands.mjs +164 -0
- package/src/engines.mjs +16 -0
- package/src/nice.mjs +199 -0
- package/src/ssh.mjs +1228 -0
- package/src/tui.mjs +73 -0
package/src/tui.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import { activeChildInput, createMirror, pressKey, setActiveSink, teeOutput } fr
|
|
|
22
22
|
import { fetchMotdAd } from "./ads.mjs";
|
|
23
23
|
import { runScript } from "./runtime.mjs";
|
|
24
24
|
import { moshVocabulary } from "./commands.mjs";
|
|
25
|
+
import { loadNice, saveNice, describeNice, canCapMemory, parseMemory } from "./nice.mjs";
|
|
25
26
|
import { mcpCommand, pluginCommand, skillCommand } from "./integrations.mjs";
|
|
26
27
|
import { stocksCommand } from "./advisor.mjs";
|
|
27
28
|
import { cryptoCommand } from "./crypto.mjs";
|
|
@@ -388,6 +389,63 @@ function isInstalledTool(key) {
|
|
|
388
389
|
* line, not an argument list: re-joining tokens would drop the quoting that the
|
|
389
390
|
* shell still has to read.
|
|
390
391
|
*/
|
|
392
|
+
/**
|
|
393
|
+
* `/nice` — run the CLIs the pit starts at a lower priority than your terminal.
|
|
394
|
+
*
|
|
395
|
+
* A toggle rather than a per-launch flag because the thing being tuned is the
|
|
396
|
+
* box, not the command: you decide once that this machine is shared, and every
|
|
397
|
+
* engine started afterwards honours it. Off by default — a throttle nobody
|
|
398
|
+
* asked for is a slow engine nobody can explain.
|
|
399
|
+
*/
|
|
400
|
+
function niceCommand(rest) {
|
|
401
|
+
const [verb, ...args] = rest.filter((a) => a !== "--json");
|
|
402
|
+
const sub = String(verb ?? "").toLowerCase();
|
|
403
|
+
const json = rest.includes("--json");
|
|
404
|
+
const settings = loadNice();
|
|
405
|
+
|
|
406
|
+
if (json) { console.log(JSON.stringify(settings, null, 2)); return; }
|
|
407
|
+
|
|
408
|
+
if (!verb || sub === "status") {
|
|
409
|
+
console.log(info(describeNice(settings)));
|
|
410
|
+
if (!settings.on) console.log(ash(` ${acid("/nice on")} throttles CPU and I/O for every engine the pit starts`));
|
|
411
|
+
else if (!settings.memoryMax) console.log(ash(` ${acid("/nice mem 2G")} adds a memory ceiling — the part nice(1) can't do`));
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (sub === "on" || sub === "off") {
|
|
416
|
+
const saved = saveNice({ ...settings, on: sub === "on" });
|
|
417
|
+
console.log(ok(describeNice(saved)));
|
|
418
|
+
if (saved.on) console.log(ash(" applies to engines started from here on; anything already running keeps its priority"));
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (sub === "cpu" || sub === "io") {
|
|
423
|
+
const n = Number(args[0]);
|
|
424
|
+
if (!Number.isInteger(n)) {
|
|
425
|
+
console.log(err(`usage: /nice ${sub} <number>${sub === "cpu" ? " (-20..19, higher = yields more)" : " (0..7, higher = yields more)"}`));
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const saved = saveNice({ ...settings, [sub]: n });
|
|
429
|
+
console.log(ok(describeNice(saved)));
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (sub === "mem" || sub === "memory") {
|
|
434
|
+
const parsed = parseMemory(args[0]);
|
|
435
|
+
if (!parsed.ok) { console.log(err(parsed.error)); return; }
|
|
436
|
+
const saved = saveNice({ ...settings, memoryMax: parsed.value });
|
|
437
|
+
console.log(ok(describeNice(saved)));
|
|
438
|
+
// Worth saying plainly: this is the one setting that can silently not apply.
|
|
439
|
+
if (parsed.value && !canCapMemory()) {
|
|
440
|
+
console.log(ash(" no systemd user session on this box, so the ceiling is recorded but not enforced"));
|
|
441
|
+
console.log(ash(` ${acid("loginctl enable-linger $USER")} gives this login one`));
|
|
442
|
+
}
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
console.log(err(`/nice ${sub} isn't a thing — try on, off, cpu <n>, io <n>, or mem <size>`));
|
|
447
|
+
}
|
|
448
|
+
|
|
391
449
|
function aliasCommand(rest, line) {
|
|
392
450
|
const json = rest.includes("--json");
|
|
393
451
|
// `--json` is the listing's flag wherever it appears, so `/alias --json` is a
|
|
@@ -936,6 +994,7 @@ export async function tui() {
|
|
|
936
994
|
continue;
|
|
937
995
|
}
|
|
938
996
|
if (cmd === "alias" || cmd === "aliases") { aliasCommand(rest, line); continue; }
|
|
997
|
+
if (cmd === "nice" || cmd === "throttle") { niceCommand(rest); continue; }
|
|
939
998
|
if (cmd === "pwd" || cmd === "where") { printPwd(); continue; }
|
|
940
999
|
if (cmd === "login") {
|
|
941
1000
|
const device = rest.includes("--device") || rest.includes("device") || rest.includes("-d");
|
|
@@ -1024,6 +1083,20 @@ export async function tui() {
|
|
|
1024
1083
|
rl = mkrl();
|
|
1025
1084
|
continue;
|
|
1026
1085
|
}
|
|
1086
|
+
// SSH workspaces (PRD 0013). `/ssh dev`, `/ssh exec --tty` and `/ssh
|
|
1087
|
+
// shell` hand the terminal to ssh the way /attach does; every other verb
|
|
1088
|
+
// answers in place and the prompt stays.
|
|
1089
|
+
if (cmd === "ssh") {
|
|
1090
|
+
const { sshCommand, takesTerminal } = await import("./ssh.mjs");
|
|
1091
|
+
if (takesTerminal(rest)) {
|
|
1092
|
+
rl.close();
|
|
1093
|
+
await sshCommand(rest);
|
|
1094
|
+
rl = mkrl();
|
|
1095
|
+
} else {
|
|
1096
|
+
await sshCommand(rest);
|
|
1097
|
+
}
|
|
1098
|
+
continue;
|
|
1099
|
+
}
|
|
1027
1100
|
if (cmd === "agents" || cmd === "agent" || cmd === "engines") {
|
|
1028
1101
|
if (!rest[0] || (rest.length === 1 && rest[0] === "--json")) {
|
|
1029
1102
|
printEngines(rest[0] === "--json");
|