@zenera/cli 1.1.24 → 1.1.26
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 +65 -0
- package/dist/ask.js +28 -5
- package/dist/banner.js +2 -2
- package/dist/batch.d.ts +6 -0
- package/dist/batch.js +76 -1
- package/dist/catalog.d.ts +31 -1
- package/dist/catalog.js +140 -7
- package/dist/commands/index.js +2 -0
- package/dist/commands/inspect.d.ts +52 -2
- package/dist/commands/inspect.js +220 -31
- package/dist/commands/memory.js +156 -32
- package/dist/commands/meta.js +333 -24
- package/dist/commands/models.js +97 -12
- package/dist/commands/open.js +4 -4
- package/dist/commands/run.js +38 -4
- package/dist/commands/sandbox.js +148 -16
- package/dist/commands/view.d.ts +8 -0
- package/dist/commands/view.js +114 -0
- package/dist/engine.d.ts +8 -1
- package/dist/engine.js +7 -0
- package/dist/eventlog.d.ts +64 -0
- package/dist/eventlog.js +170 -0
- package/dist/liveness.d.ts +7 -0
- package/dist/liveness.js +35 -3
- package/dist/main.js +0 -0
- package/dist/meta/editor.d.ts +9 -0
- package/dist/meta/editor.js +43 -0
- package/dist/meta/finetune/analyze-brief.d.ts +26 -0
- package/dist/meta/finetune/analyze-brief.js +131 -0
- package/dist/meta/finetune/apply-brief.d.ts +23 -0
- package/dist/meta/finetune/apply-brief.js +247 -0
- package/dist/meta/finetune/brief.d.ts +45 -0
- package/dist/meta/finetune/brief.js +158 -0
- package/dist/meta/finetune/children.d.ts +8 -0
- package/dist/meta/finetune/children.js +76 -0
- package/dist/meta/finetune/command.d.ts +30 -0
- package/dist/meta/finetune/command.js +516 -0
- package/dist/meta/finetune/cost.d.ts +46 -0
- package/dist/meta/finetune/cost.js +105 -0
- package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
- package/dist/meta/finetune/dataset/anchors.js +239 -0
- package/dist/meta/finetune/dataset/changes.d.ts +36 -0
- package/dist/meta/finetune/dataset/changes.js +319 -0
- package/dist/meta/finetune/dataset/command.d.ts +17 -0
- package/dist/meta/finetune/dataset/command.js +1011 -0
- package/dist/meta/finetune/dataset/drift.d.ts +33 -0
- package/dist/meta/finetune/dataset/drift.js +71 -0
- package/dist/meta/finetune/dataset/export.d.ts +26 -0
- package/dist/meta/finetune/dataset/export.js +51 -0
- package/dist/meta/finetune/dataset/index.d.ts +2 -0
- package/dist/meta/finetune/dataset/index.js +2 -0
- package/dist/meta/finetune/dataset/sample.d.ts +50 -0
- package/dist/meta/finetune/dataset/sample.js +197 -0
- package/dist/meta/finetune/dataset/schema.d.ts +33 -0
- package/dist/meta/finetune/dataset/schema.js +216 -0
- package/dist/meta/finetune/dataset/store.d.ts +35 -0
- package/dist/meta/finetune/dataset/store.js +177 -0
- package/dist/meta/finetune/dataset/types.d.ts +127 -0
- package/dist/meta/finetune/dataset/types.js +39 -0
- package/dist/meta/finetune/failure.d.ts +15 -0
- package/dist/meta/finetune/failure.js +26 -0
- package/dist/meta/finetune/feedback.d.ts +57 -0
- package/dist/meta/finetune/feedback.js +104 -0
- package/dist/meta/finetune/guard.d.ts +29 -0
- package/dist/meta/finetune/guard.js +104 -0
- package/dist/meta/finetune/improvements.d.ts +98 -0
- package/dist/meta/finetune/improvements.js +501 -0
- package/dist/meta/finetune/index.d.ts +2 -0
- package/dist/meta/finetune/index.js +2 -0
- package/dist/meta/finetune/journal.d.ts +35 -0
- package/dist/meta/finetune/journal.js +135 -0
- package/dist/meta/finetune/live.d.ts +84 -0
- package/dist/meta/finetune/live.js +272 -0
- package/dist/meta/finetune/loop.d.ts +3 -0
- package/dist/meta/finetune/loop.js +163 -0
- package/dist/meta/finetune/memories.d.ts +47 -0
- package/dist/meta/finetune/memories.js +154 -0
- package/dist/meta/finetune/recheck.d.ts +58 -0
- package/dist/meta/finetune/recheck.js +311 -0
- package/dist/meta/finetune/report.d.ts +40 -0
- package/dist/meta/finetune/report.js +1397 -0
- package/dist/meta/finetune/retry.d.ts +24 -0
- package/dist/meta/finetune/retry.js +96 -0
- package/dist/meta/finetune/sampler.d.ts +18 -0
- package/dist/meta/finetune/sampler.js +47 -0
- package/dist/meta/finetune/system.d.ts +27 -0
- package/dist/meta/finetune/system.js +132 -0
- package/dist/meta/finetune/train.d.ts +43 -0
- package/dist/meta/finetune/train.js +425 -0
- package/dist/meta/finetune/tui.d.ts +16 -0
- package/dist/meta/finetune/tui.js +316 -0
- package/dist/meta/finetune/tuning.d.ts +193 -0
- package/dist/meta/finetune/tuning.js +308 -0
- package/dist/meta/finetune/usage.d.ts +66 -0
- package/dist/meta/finetune/usage.js +260 -0
- package/dist/meta/finetune/view.d.ts +9 -0
- package/dist/meta/finetune/view.js +27 -0
- package/dist/meta/host.d.ts +15 -0
- package/dist/meta/host.js +21 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/launch.d.ts +81 -0
- package/dist/meta/launch.js +286 -0
- package/dist/meta/model.d.ts +44 -0
- package/dist/meta/model.js +119 -0
- package/dist/meta/prompts.d.ts +18 -0
- package/dist/meta/prompts.js +61 -0
- package/dist/meta/relay.d.ts +20 -0
- package/dist/meta/relay.js +123 -0
- package/dist/meta/tokens.d.ts +52 -0
- package/dist/meta/tokens.js +226 -0
- package/dist/meta/window.d.ts +61 -0
- package/dist/meta/window.js +198 -0
- package/dist/meta/wire.d.ts +42 -0
- package/dist/meta/wire.js +129 -0
- package/dist/meta.d.ts +71 -1
- package/dist/meta.js +303 -6
- package/dist/modelref.d.ts +16 -0
- package/dist/modelref.js +41 -0
- package/dist/narrate.js +5 -2
- package/dist/podman.d.ts +26 -0
- package/dist/podman.js +83 -3
- package/dist/projects.d.ts +0 -5
- package/dist/projects.js +2 -15
- package/dist/resources.d.ts +215 -0
- package/dist/resources.js +856 -0
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.js +10 -3
- package/dist/scaffold.d.ts +15 -7
- package/dist/scaffold.js +24 -67
- package/dist/session.js +4 -29
- package/dist/term.d.ts +2 -0
- package/dist/term.js +11 -2
- package/dist/trace.d.ts +5 -0
- package/dist/trace.js +107 -7
- package/dist/tui/app.js +19 -5
- package/dist/tui/links.d.ts +27 -0
- package/dist/tui/links.js +142 -0
- package/dist/tui/models.d.ts +35 -0
- package/dist/tui/models.js +447 -0
- package/dist/tui/sandbox.d.ts +10 -0
- package/dist/tui/sandbox.js +131 -0
- package/dist/tui/wrap.d.ts +5 -0
- package/dist/tui/wrap.js +12 -0
- package/dist/usage.d.ts +78 -0
- package/dist/usage.js +51 -0
- package/package.json +4 -2
- package/templates/editor/.github/copilot-instructions.md +60 -145
- package/templates/editor/.github/prompts/analyze.prompt.md +33 -0
- package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
- package/templates/editor/.github/prompts/finetune-apply.prompt.md +270 -0
- package/templates/editor/.github/prompts/finetune.prompt.md +691 -198
- package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
- package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
- package/templates/editor/.github/prompts/project-review.prompt.md +5 -4
- package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +588 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +9 -1
- package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
- package/templates/editor/.github/skills/zen-cli/references/finetune.md +137 -0
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +63 -11
- package/templates/editor/.github/skills/zen-cli/references/memory.md +33 -10
- package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
- package/templates/editor/.github/skills/zen-cli/references/models.md +5 -1
- package/templates/editor/.github/skills/zen-cli/references/projects.md +4 -6
- package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +35 -14
- package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
- package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
- package/templates/editor/.github/skills/zen-finetune/SKILL.md +1492 -660
- package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
- package/templates/editor/.github/skills/zen-inspect/SKILL.md +74 -26
- package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +271 -0
- package/templates/editor/.github/skills/zen-instructions/SKILL.md +4 -12
- package/templates/editor/.github/skills/zen-memory/SKILL.md +82 -53
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
- package/templates/editor/.github/skills/zen-review/SKILL.md +8 -31
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -5
- package/templates/editor/.github/skills/zen-review/scripts/review.sh +3 -12
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +9 -4
- package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +2 -2
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +2 -4
- package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
- package/templates/editor/.vscode/settings.json +1 -0
- package/templates/project/agents/files-instructions.md +29 -20
- package/templates/project/agents/fork-instructions.md +78 -28
- package/templates/project/agents/memory-instructions.md +222 -494
- package/templates/project/agents/tools-instructions.md +14 -4
- package/templates/project/gitignore +2 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/collect.sh +0 -432
- package/templates/editor/.github/skills/zen-finetune/scripts/sample.sh +0 -199
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +0 -116
package/dist/narrate.js
CHANGED
|
@@ -117,8 +117,11 @@ export function duration(ms) {
|
|
|
117
117
|
if (ms < 60_000) {
|
|
118
118
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
119
119
|
}
|
|
120
|
-
const
|
|
121
|
-
|
|
120
|
+
const totalSeconds = Math.round(ms / 1000);
|
|
121
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
122
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
123
|
+
const seconds = totalSeconds % 60;
|
|
124
|
+
return hours > 0 ? `${hours}h ${minutes}m ${seconds}s` : `${minutes}m ${seconds}s`;
|
|
122
125
|
}
|
|
123
126
|
export const stopMark = (reason) => reason === 'final' ? green('done') : reason === 'aborted' ? yellow('aborted') : red('failed');
|
|
124
127
|
//# sourceMappingURL=narrate.js.map
|
package/dist/podman.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface PodmanStatus {
|
|
|
41
41
|
swap: number;
|
|
42
42
|
cpus: number;
|
|
43
43
|
};
|
|
44
|
+
/** containers the engine can still create; a stopped one holds a lock too */
|
|
45
|
+
freeLocks?: number;
|
|
44
46
|
image?: string;
|
|
45
47
|
imagePresent?: boolean;
|
|
46
48
|
}
|
|
@@ -62,6 +64,30 @@ export declare class BuildError extends CliError {
|
|
|
62
64
|
}
|
|
63
65
|
/** What `zn sandbox status` prints. Changes nothing, and never throws. */
|
|
64
66
|
export declare function podmanStatus(opts?: PodmanOptions): Promise<PodmanStatus>;
|
|
67
|
+
/** Containers the engine can still create; undefined when it will not say. */
|
|
68
|
+
export declare function freeLocks(engine?: string, exec?: import("@zenera/neo").Runner): Promise<number | undefined>;
|
|
69
|
+
export interface LockOptions {
|
|
70
|
+
engine?: string;
|
|
71
|
+
exec?: typeof runProcess;
|
|
72
|
+
/** a container that may already exist, and so needs no new lock */
|
|
73
|
+
reuses?: string;
|
|
74
|
+
/** session id -> its directory; read from the registry when absent */
|
|
75
|
+
owners?: ReadonlyMap<string, string>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Refuses a run the engine cannot hold before anything is spent on it. Every
|
|
79
|
+
* container takes a lock, stopped ones included, and at zero the failure would
|
|
80
|
+
* otherwise land on the first shell command — mid-turn, or once per item.
|
|
81
|
+
*/
|
|
82
|
+
export declare function assertLocks(need: number, opts?: LockOptions): Promise<void>;
|
|
83
|
+
/** Every session on this machine, by id, from the projects the registry knows. */
|
|
84
|
+
export declare function sessionOwners(): Promise<Map<string, string>>;
|
|
85
|
+
/**
|
|
86
|
+
* Containers no live process is using: every stopped one, and a running one
|
|
87
|
+
* whose run exited without tearing it down (a kill, a crash, a closed lid).
|
|
88
|
+
* A running container that cannot be traced to its owner is left alone.
|
|
89
|
+
*/
|
|
90
|
+
export declare function idleContainers(containers: readonly OwnedContainer[], owners: ReadonlyMap<string, string>): OwnedContainer[];
|
|
65
91
|
export interface OwnedContainer {
|
|
66
92
|
name: string;
|
|
67
93
|
/** podman's own word: `running`, `exited`, `created`, `paused` */
|
package/dist/podman.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { runProcess, SandboxError } from '@zenera/neo';
|
|
1
|
+
import { pidAlive, runProcess, SandboxError } from '@zenera/neo';
|
|
2
2
|
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
3
3
|
import { homedir, platform } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
+
import { isBusy, isProjectDir, Registry, sessionIds, sessionsDir } from "./projects.js";
|
|
5
6
|
import { CliError, confirm, dim, EXIT, isInteractive, note, progress } from "./term.js";
|
|
6
7
|
const DEFAULT_MACHINE_CPUS = 2;
|
|
7
8
|
const DEFAULT_MACHINE_MEMORY = 2048;
|
|
@@ -409,6 +410,9 @@ export async function podmanStatus(opts = {}) {
|
|
|
409
410
|
cpus: Number.isFinite(cpus) ? cpus : 0,
|
|
410
411
|
};
|
|
411
412
|
}
|
|
413
|
+
// Asked apart from the line above: an engine without the field fails
|
|
414
|
+
// the whole template, and that must not cost the report its memory.
|
|
415
|
+
status.freeLocks = await freeLocks(engine, run);
|
|
412
416
|
}
|
|
413
417
|
if (opts.image) {
|
|
414
418
|
status.image = opts.image;
|
|
@@ -425,6 +429,76 @@ function safeMachines(stdout) {
|
|
|
425
429
|
return [];
|
|
426
430
|
}
|
|
427
431
|
}
|
|
432
|
+
/** Containers the engine can still create; undefined when it will not say. */
|
|
433
|
+
export async function freeLocks(engine = 'podman', exec = runProcess) {
|
|
434
|
+
const res = await exec(engine, ['info', '--format', '{{.Host.FreeLocks}}'], {
|
|
435
|
+
timeoutMs: 30_000,
|
|
436
|
+
}).catch(() => undefined);
|
|
437
|
+
const free = res?.code === 0 ? res.stdout.trim() : '';
|
|
438
|
+
return /^\d+$/.test(free) ? Number(free) : undefined;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Refuses a run the engine cannot hold before anything is spent on it. Every
|
|
442
|
+
* container takes a lock, stopped ones included, and at zero the failure would
|
|
443
|
+
* otherwise land on the first shell command — mid-turn, or once per item.
|
|
444
|
+
*/
|
|
445
|
+
export async function assertLocks(need, opts = {}) {
|
|
446
|
+
const engine = opts.engine ?? 'podman';
|
|
447
|
+
const exec = opts.exec ?? runProcess;
|
|
448
|
+
const free = await freeLocks(engine, exec);
|
|
449
|
+
if (free === undefined || free >= need) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (opts.reuses) {
|
|
453
|
+
const there = await exec(engine, ['container', 'exists', opts.reuses], {
|
|
454
|
+
timeoutMs: 30_000,
|
|
455
|
+
}).catch(() => undefined);
|
|
456
|
+
if (there?.code === 0) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
const idle = idleContainers(await ownedContainers(engine, exec), opts.owners ?? (await sessionOwners())).length;
|
|
461
|
+
throw new CliError(`the container engine has ${free} locks free and this run needs ${need} — ` +
|
|
462
|
+
'every container holds one, stopped ones included', EXIT.sandbox, idle > 0
|
|
463
|
+
? `zen sandbox clean --idle frees ${idle}`
|
|
464
|
+
: `every container zen made is in use — \`${engine} ps --all\` shows what holds them`);
|
|
465
|
+
}
|
|
466
|
+
/** Every session on this machine, by id, from the projects the registry knows. */
|
|
467
|
+
export async function sessionOwners() {
|
|
468
|
+
const owners = new Map();
|
|
469
|
+
for (const entry of (await Registry.open()).entries) {
|
|
470
|
+
if (isProjectDir(entry.path)) {
|
|
471
|
+
for (const id of sessionIds(entry.path)) {
|
|
472
|
+
owners.set(id, join(sessionsDir(entry.path), id));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return owners;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Containers no live process is using: every stopped one, and a running one
|
|
480
|
+
* whose run exited without tearing it down (a kill, a crash, a closed lid).
|
|
481
|
+
* A running container that cannot be traced to its owner is left alone.
|
|
482
|
+
*/
|
|
483
|
+
export function idleContainers(containers, owners) {
|
|
484
|
+
return containers.filter((c) => {
|
|
485
|
+
if (c.state !== 'running') {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
const faker = /^faker-(\d+)$/.exec(c.key ?? '');
|
|
489
|
+
if (faker) {
|
|
490
|
+
return !pidAlive(Number(faker[1]));
|
|
491
|
+
}
|
|
492
|
+
const dir = c.key === undefined ? undefined : owners.get(c.key);
|
|
493
|
+
return dir !== undefined && !isBusy(dir);
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* `ps --format json` is ~1 kB a container, so the runner's default 64 kB cap cut
|
|
498
|
+
* the listing at about sixty, the JSON stopped parsing, and every report said
|
|
499
|
+
* "none" while two thousand sat on the machine.
|
|
500
|
+
*/
|
|
501
|
+
const LISTING_BYTES = 64 * 1024 * 1024;
|
|
428
502
|
/**
|
|
429
503
|
* Containers this CLI created, whatever session they belong to, and whether
|
|
430
504
|
* each is up. `--all` is the point: with `persist: true` a session leaves a
|
|
@@ -438,7 +512,7 @@ export async function ownedContainers(engine = 'podman', exec = runProcess, opts
|
|
|
438
512
|
if (opts.sizes) {
|
|
439
513
|
args.push('--size');
|
|
440
514
|
}
|
|
441
|
-
const res = await exec(engine, args, { timeoutMs: 120_000 }).catch(() => undefined);
|
|
515
|
+
const res = await exec(engine, args, { timeoutMs: 120_000, maxBytes: LISTING_BYTES }).catch(() => undefined);
|
|
442
516
|
if (!res || res.code !== 0) {
|
|
443
517
|
return [];
|
|
444
518
|
}
|
|
@@ -471,8 +545,14 @@ export async function removeContainers(names, engine = 'podman', exec = runProce
|
|
|
471
545
|
if (names.length === 0) {
|
|
472
546
|
return;
|
|
473
547
|
}
|
|
474
|
-
|
|
548
|
+
// In slices, so two thousand of them get a timeout each slice can meet.
|
|
549
|
+
for (let i = 0; i < names.length; i += REMOVE_SLICE) {
|
|
550
|
+
await exec(engine, ['rm', '--force', '--volumes', ...names.slice(i, i + REMOVE_SLICE)], {
|
|
551
|
+
timeoutMs: 120_000,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
475
554
|
}
|
|
555
|
+
const REMOVE_SLICE = 100;
|
|
476
556
|
/** What the engine is using. Never throws: a disk report is not worth a crash. */
|
|
477
557
|
export async function engineDisk(engine = 'podman', exec = runProcess) {
|
|
478
558
|
const call = (args) => exec(engine, args, { timeoutMs: 120_000 }).catch(() => undefined);
|
package/dist/projects.d.ts
CHANGED
|
@@ -87,10 +87,5 @@ export declare function lastUsedAt(projectDir: string): string | undefined;
|
|
|
87
87
|
export declare function dirSize(dir: string): number;
|
|
88
88
|
/** True when a session's lock names a process that is still alive. */
|
|
89
89
|
export declare function isBusy(sessionDir: string): boolean;
|
|
90
|
-
/**
|
|
91
|
-
* `kill(pid, 0)` sends no signal and only asks whether the process exists.
|
|
92
|
-
* EPERM means it exists and belongs to someone else, which still counts.
|
|
93
|
-
*/
|
|
94
|
-
export declare function alive(pid: number): boolean;
|
|
95
90
|
export declare function projectName(dir: string): string;
|
|
96
91
|
//# sourceMappingURL=projects.d.ts.map
|
package/dist/projects.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ASSETS_MOUNT, assetsDir, FILES_DIR, MEMORY_MOUNT, memoryDir, skillDirs, skillMounts, SKILLS_MOUNT, } from '@zenera/neo';
|
|
1
|
+
import { ASSETS_MOUNT, assetsDir, FILES_DIR, MEMORY_MOUNT, memoryDir, pidAlive, skillDirs, skillMounts, SKILLS_MOUNT, } from '@zenera/neo';
|
|
2
2
|
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
|
|
4
4
|
import { paths, readJson, writeJson } from "./home.js";
|
|
@@ -290,26 +290,13 @@ export function isBusy(sessionDir) {
|
|
|
290
290
|
const path = join(sessionDir, '.lock');
|
|
291
291
|
try {
|
|
292
292
|
const { pid } = JSON.parse(readFileSync(path, 'utf8'));
|
|
293
|
-
return typeof pid === 'number' &&
|
|
293
|
+
return typeof pid === 'number' && pidAlive(pid);
|
|
294
294
|
}
|
|
295
295
|
catch {
|
|
296
296
|
// Absent, unreadable or malformed: nothing is holding it.
|
|
297
297
|
return false;
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
|
-
/**
|
|
301
|
-
* `kill(pid, 0)` sends no signal and only asks whether the process exists.
|
|
302
|
-
* EPERM means it exists and belongs to someone else, which still counts.
|
|
303
|
-
*/
|
|
304
|
-
export function alive(pid) {
|
|
305
|
-
try {
|
|
306
|
-
process.kill(pid, 0);
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
catch (err) {
|
|
310
|
-
return err.code === 'EPERM';
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
300
|
export function projectName(dir) {
|
|
314
301
|
return basename(resolve(dir));
|
|
315
302
|
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { runProcess } from '@zenera/neo';
|
|
2
|
+
import { type OwnedContainer } from './podman.ts';
|
|
3
|
+
type Exec = typeof runProcess;
|
|
4
|
+
export interface HostProcess {
|
|
5
|
+
pid: number;
|
|
6
|
+
/** `vm` holds the machine's memory; the others run beside it */
|
|
7
|
+
role: 'vm' | 'hypervisor' | 'network';
|
|
8
|
+
name: string;
|
|
9
|
+
/** in RAM this moment */
|
|
10
|
+
rss: number;
|
|
11
|
+
/** macOS: what Activity Monitor's Memory column shows — RAM, compressed and swapped */
|
|
12
|
+
footprint?: number;
|
|
13
|
+
peak?: number;
|
|
14
|
+
/** cumulative, since it started */
|
|
15
|
+
cpuSeconds: number;
|
|
16
|
+
}
|
|
17
|
+
export interface GuestMemory {
|
|
18
|
+
total: number;
|
|
19
|
+
free: number;
|
|
20
|
+
available: number;
|
|
21
|
+
swapTotal: number;
|
|
22
|
+
swapFree: number;
|
|
23
|
+
cpus: number;
|
|
24
|
+
}
|
|
25
|
+
export interface ContainerStat {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
cpuNano: number;
|
|
29
|
+
/** wall clock of the reading, in nanoseconds */
|
|
30
|
+
systemNano: number;
|
|
31
|
+
/** percent of one core, averaged over the container's whole life */
|
|
32
|
+
avgCpu: number;
|
|
33
|
+
memory: number;
|
|
34
|
+
limit: number;
|
|
35
|
+
pids: number;
|
|
36
|
+
netIn: number;
|
|
37
|
+
netOut: number;
|
|
38
|
+
blockIn: number;
|
|
39
|
+
blockOut: number;
|
|
40
|
+
}
|
|
41
|
+
export interface Sample {
|
|
42
|
+
at: number;
|
|
43
|
+
platform: NodeJS.Platform;
|
|
44
|
+
engine: string;
|
|
45
|
+
ready: boolean;
|
|
46
|
+
machine?: string;
|
|
47
|
+
host: {
|
|
48
|
+
memory: number;
|
|
49
|
+
cpus: number;
|
|
50
|
+
processes: HostProcess[];
|
|
51
|
+
};
|
|
52
|
+
guest?: GuestMemory;
|
|
53
|
+
stats: ContainerStat[];
|
|
54
|
+
owned: OwnedContainer[];
|
|
55
|
+
/** running containers whose zen run is gone */
|
|
56
|
+
orphans: string[];
|
|
57
|
+
/** session id -> project name */
|
|
58
|
+
projects: ReadonlyMap<string, string>;
|
|
59
|
+
problems: string[];
|
|
60
|
+
}
|
|
61
|
+
export interface ProcessView {
|
|
62
|
+
pid: number;
|
|
63
|
+
role: HostProcess['role'];
|
|
64
|
+
name: string;
|
|
65
|
+
/** the footprint where there is one, else what is in RAM */
|
|
66
|
+
memory: number;
|
|
67
|
+
rss: number;
|
|
68
|
+
footprint?: number;
|
|
69
|
+
peak?: number;
|
|
70
|
+
/** percent of one core over the interval; absent on the first sample */
|
|
71
|
+
cpu?: number;
|
|
72
|
+
}
|
|
73
|
+
export interface MachineView {
|
|
74
|
+
name?: string;
|
|
75
|
+
total: number;
|
|
76
|
+
/** held by programs: total minus available */
|
|
77
|
+
used: number;
|
|
78
|
+
/** page cache and other memory Linux gives back on demand */
|
|
79
|
+
cache: number;
|
|
80
|
+
free: number;
|
|
81
|
+
available: number;
|
|
82
|
+
swapTotal: number;
|
|
83
|
+
swapUsed: number;
|
|
84
|
+
cpus: number;
|
|
85
|
+
/**
|
|
86
|
+
* macOS counts this much for the machine beyond what anything inside uses,
|
|
87
|
+
* cache included: memory used once, freed inside, and never handed back.
|
|
88
|
+
*/
|
|
89
|
+
held?: number;
|
|
90
|
+
}
|
|
91
|
+
export interface ContainerView {
|
|
92
|
+
name: string;
|
|
93
|
+
id: string;
|
|
94
|
+
kind: 'zen' | 'faker' | 'other';
|
|
95
|
+
project?: string;
|
|
96
|
+
orphaned: boolean;
|
|
97
|
+
/** percent of one core */
|
|
98
|
+
cpu: number;
|
|
99
|
+
/** whether `cpu` is over the last interval or the container's whole life */
|
|
100
|
+
cpuOver: 'interval' | 'lifetime';
|
|
101
|
+
memory: number;
|
|
102
|
+
/** absent when the container may use the whole machine */
|
|
103
|
+
limit?: number;
|
|
104
|
+
pids: number;
|
|
105
|
+
netIn: number;
|
|
106
|
+
netOut: number;
|
|
107
|
+
blockIn: number;
|
|
108
|
+
blockOut: number;
|
|
109
|
+
createdAt?: string;
|
|
110
|
+
}
|
|
111
|
+
export interface ResourceView {
|
|
112
|
+
at: string;
|
|
113
|
+
/** seconds between the two samples the cpu figures are taken over */
|
|
114
|
+
interval?: number;
|
|
115
|
+
platform: NodeJS.Platform;
|
|
116
|
+
engine: string;
|
|
117
|
+
ready: boolean;
|
|
118
|
+
host: {
|
|
119
|
+
memory: number;
|
|
120
|
+
cpus: number;
|
|
121
|
+
vm?: ProcessView;
|
|
122
|
+
helpers: ProcessView[];
|
|
123
|
+
};
|
|
124
|
+
machine?: MachineView;
|
|
125
|
+
containers: ContainerView[];
|
|
126
|
+
/** containers that exist but are not running, which cost disk and no memory */
|
|
127
|
+
stopped: number;
|
|
128
|
+
totals: {
|
|
129
|
+
running: number;
|
|
130
|
+
zen: number;
|
|
131
|
+
faker: number;
|
|
132
|
+
other: number;
|
|
133
|
+
orphaned: number;
|
|
134
|
+
memory: number;
|
|
135
|
+
cpu: number;
|
|
136
|
+
};
|
|
137
|
+
hints: string[];
|
|
138
|
+
problems: string[];
|
|
139
|
+
}
|
|
140
|
+
export interface SamplerOptions {
|
|
141
|
+
engine?: string;
|
|
142
|
+
exec?: Exec;
|
|
143
|
+
/** so the tests can be macOS on Linux and the other way round */
|
|
144
|
+
platform?: NodeJS.Platform;
|
|
145
|
+
/** session id -> {dir, project}; read from the registry when absent */
|
|
146
|
+
owners?: () => Promise<Owners>;
|
|
147
|
+
now?: () => number;
|
|
148
|
+
}
|
|
149
|
+
export interface Owners {
|
|
150
|
+
dirs: ReadonlyMap<string, string>;
|
|
151
|
+
names: ReadonlyMap<string, string>;
|
|
152
|
+
}
|
|
153
|
+
/** Reads one sample at a time and remembers the last, so each view has an interval. */
|
|
154
|
+
export declare class ResourceSampler {
|
|
155
|
+
#private;
|
|
156
|
+
readonly engine: string;
|
|
157
|
+
constructor(opts?: SamplerOptions);
|
|
158
|
+
next(): Promise<ResourceView>;
|
|
159
|
+
sample(): Promise<Sample>;
|
|
160
|
+
}
|
|
161
|
+
/** Every session on this machine, by id: where it lives and which project it is in. */
|
|
162
|
+
export declare function registryOwners(): Promise<Owners>;
|
|
163
|
+
export declare function parseInfo(stdout: string): GuestMemory | undefined;
|
|
164
|
+
export declare function parseStats(stdout: string): ContainerStat[];
|
|
165
|
+
interface PsRow {
|
|
166
|
+
pid: number;
|
|
167
|
+
rss: number;
|
|
168
|
+
cpuSeconds: number;
|
|
169
|
+
ageSeconds: number;
|
|
170
|
+
command: string;
|
|
171
|
+
}
|
|
172
|
+
export declare function parsePs(stdout: string): PsRow[];
|
|
173
|
+
/** `[[dd-]hh:]mm:ss[.cc]` — how `ps` prints both cpu time and elapsed time. */
|
|
174
|
+
export declare function clock(text: string): number;
|
|
175
|
+
/**
|
|
176
|
+
* Picks the machine out of every process on the host. A Mac can run more than
|
|
177
|
+
* one virtual machine through the same framework, so the Apple service and
|
|
178
|
+
* the network helper are matched to the hypervisor by when they started.
|
|
179
|
+
*/
|
|
180
|
+
export declare function machineProcesses(rows: readonly PsRow[]): HostProcess[];
|
|
181
|
+
/** `footprint -f bytes` output: one block per process. */
|
|
182
|
+
export declare function parseFootprint(stdout: string): Map<number, {
|
|
183
|
+
footprint: number;
|
|
184
|
+
peak?: number;
|
|
185
|
+
}>;
|
|
186
|
+
export declare function viewOf(now: Sample, before?: Sample): ResourceView;
|
|
187
|
+
export type Tone = 'plain' | 'strong' | 'dim' | 'good' | 'warn' | 'bad' | 'accent' | 'heading';
|
|
188
|
+
export interface Span {
|
|
189
|
+
readonly text: string;
|
|
190
|
+
readonly tone?: Tone;
|
|
191
|
+
}
|
|
192
|
+
export type Line = readonly Span[];
|
|
193
|
+
export type Sort = 'memory' | 'cpu' | 'name';
|
|
194
|
+
export declare const SORTS: readonly Sort[];
|
|
195
|
+
export interface LayoutOptions {
|
|
196
|
+
width: number;
|
|
197
|
+
/** the most lines to return; containers are cut first, with a count of the rest */
|
|
198
|
+
rows?: number;
|
|
199
|
+
/** a note beside every figure saying what it means, and a sentence under each heading */
|
|
200
|
+
explain: boolean;
|
|
201
|
+
sort?: Sort;
|
|
202
|
+
/** seconds between refreshes, for the live screen's header */
|
|
203
|
+
live?: number;
|
|
204
|
+
/** wrap a long note onto the next line instead of letting the edge cut it */
|
|
205
|
+
wrapNotes?: boolean;
|
|
206
|
+
/**
|
|
207
|
+
* The sentence under each heading and the column legend. On by default
|
|
208
|
+
* with `explain`; the live screen turns it off before it cuts any figure.
|
|
209
|
+
*/
|
|
210
|
+
intros?: boolean;
|
|
211
|
+
}
|
|
212
|
+
export declare function pct(n: number): string;
|
|
213
|
+
export declare function layout(view: ResourceView, o: LayoutOptions): Line[];
|
|
214
|
+
export {};
|
|
215
|
+
//# sourceMappingURL=resources.d.ts.map
|