instar 1.3.761 → 1.3.763
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +92 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +28 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/FileClassifier.d.ts.map +1 -1
- package/dist/core/FileClassifier.js +5 -0
- package/dist/core/FileClassifier.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +12 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +54 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
- package/dist/core/WriteDomainRegistry.js +16 -0
- package/dist/core/WriteDomainRegistry.js.map +1 -1
- package/dist/core/componentCategories.d.ts.map +1 -1
- package/dist/core/componentCategories.js +1 -0
- package/dist/core/componentCategories.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +50 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/data/llmBenchCoverage.d.ts.map +1 -1
- package/dist/data/llmBenchCoverage.js +18 -0
- package/dist/data/llmBenchCoverage.js.map +1 -1
- package/dist/monitoring/ExternalHogArmMarker.d.ts +65 -0
- package/dist/monitoring/ExternalHogArmMarker.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogArmMarker.js +0 -0
- package/dist/monitoring/ExternalHogArmMarker.js.map +1 -0
- package/dist/monitoring/ExternalHogArmStore.d.ts +46 -0
- package/dist/monitoring/ExternalHogArmStore.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogArmStore.js +124 -0
- package/dist/monitoring/ExternalHogArmStore.js.map +1 -0
- package/dist/monitoring/ExternalHogClassifier.d.ts +62 -0
- package/dist/monitoring/ExternalHogClassifier.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogClassifier.js +0 -0
- package/dist/monitoring/ExternalHogClassifier.js.map +1 -0
- package/dist/monitoring/ExternalHogClassifierPrompt.d.ts +29 -0
- package/dist/monitoring/ExternalHogClassifierPrompt.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogClassifierPrompt.js +70 -0
- package/dist/monitoring/ExternalHogClassifierPrompt.js.map +1 -0
- package/dist/monitoring/ExternalHogCpuDelta.d.ts +50 -0
- package/dist/monitoring/ExternalHogCpuDelta.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogCpuDelta.js +79 -0
- package/dist/monitoring/ExternalHogCpuDelta.js.map +1 -0
- package/dist/monitoring/ExternalHogFactBuilder.d.ts +71 -0
- package/dist/monitoring/ExternalHogFactBuilder.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogFactBuilder.js +111 -0
- package/dist/monitoring/ExternalHogFactBuilder.js.map +1 -0
- package/dist/monitoring/ExternalHogFloor.d.ts +87 -0
- package/dist/monitoring/ExternalHogFloor.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogFloor.js +123 -0
- package/dist/monitoring/ExternalHogFloor.js.map +1 -0
- package/dist/monitoring/ExternalHogGuardStatus.d.ts +29 -0
- package/dist/monitoring/ExternalHogGuardStatus.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogGuardStatus.js +27 -0
- package/dist/monitoring/ExternalHogGuardStatus.js.map +1 -0
- package/dist/monitoring/ExternalHogKillFunnel.d.ts +77 -0
- package/dist/monitoring/ExternalHogKillFunnel.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogKillFunnel.js +72 -0
- package/dist/monitoring/ExternalHogKillFunnel.js.map +1 -0
- package/dist/monitoring/ExternalHogKillLedger.d.ts +76 -0
- package/dist/monitoring/ExternalHogKillLedger.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogKillLedger.js +84 -0
- package/dist/monitoring/ExternalHogKillLedger.js.map +1 -0
- package/dist/monitoring/ExternalHogNoticeCoalescer.d.ts +46 -0
- package/dist/monitoring/ExternalHogNoticeCoalescer.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogNoticeCoalescer.js +67 -0
- package/dist/monitoring/ExternalHogNoticeCoalescer.js.map +1 -0
- package/dist/monitoring/ExternalHogOwnership.d.ts +48 -0
- package/dist/monitoring/ExternalHogOwnership.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogOwnership.js +60 -0
- package/dist/monitoring/ExternalHogOwnership.js.map +1 -0
- package/dist/monitoring/ExternalHogProcTable.d.ts +37 -0
- package/dist/monitoring/ExternalHogProcTable.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogProcTable.js +65 -0
- package/dist/monitoring/ExternalHogProcTable.js.map +1 -0
- package/dist/monitoring/ExternalHogRealAdapters.d.ts +91 -0
- package/dist/monitoring/ExternalHogRealAdapters.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogRealAdapters.js +247 -0
- package/dist/monitoring/ExternalHogRealAdapters.js.map +1 -0
- package/dist/monitoring/ExternalHogSampler.d.ts +62 -0
- package/dist/monitoring/ExternalHogSampler.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogSampler.js +0 -0
- package/dist/monitoring/ExternalHogSampler.js.map +1 -0
- package/dist/monitoring/ExternalHogScanTick.d.ts +89 -0
- package/dist/monitoring/ExternalHogScanTick.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogScanTick.js +126 -0
- package/dist/monitoring/ExternalHogScanTick.js.map +1 -0
- package/dist/monitoring/ExternalHogSentinel.d.ts +127 -0
- package/dist/monitoring/ExternalHogSentinel.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogSentinel.js +168 -0
- package/dist/monitoring/ExternalHogSentinel.js.map +1 -0
- package/dist/monitoring/ExternalHogServerPrimitives.d.ts +50 -0
- package/dist/monitoring/ExternalHogServerPrimitives.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogServerPrimitives.js +93 -0
- package/dist/monitoring/ExternalHogServerPrimitives.js.map +1 -0
- package/dist/monitoring/ExternalHogSustained.d.ts +49 -0
- package/dist/monitoring/ExternalHogSustained.d.ts.map +1 -0
- package/dist/monitoring/ExternalHogSustained.js +62 -0
- package/dist/monitoring/ExternalHogSustained.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +24 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +2 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +3 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +1 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +64 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/testing/selfActionRegistry.d.ts.map +1 -1
- package/dist/testing/selfActionRegistry.js +51 -0
- package/dist/testing/selfActionRegistry.js.map +1 -1
- package/package.json +1 -1
- package/scripts/lint-scrape-fixture-realness.js +14 -0
- package/scripts/model-registry-freshness.manifest.json +2 -2
- package/src/data/builtin-manifest.json +64 -64
- package/src/data/llmBenchCoverage.ts +18 -0
- package/src/scaffold/templates.ts +2 -1
- package/upgrades/1.3.762.md +29 -0
- package/upgrades/1.3.763.md +23 -0
- package/upgrades/side-effects/doorway-model-registry-inc5.md +118 -0
- package/upgrades/side-effects/external-hog-sentinel.md +832 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExternalHogRealAdapters — the IMPURE edge that binds the reviewed pure modules to the real OS
|
|
3
|
+
* (CMT-1901, docs/specs/external-hog-zombie-autokill-sentinel.md §1-§6). It builds the
|
|
4
|
+
* `ExternalHogAdapters` object the ExternalHogSentinel shell consumes.
|
|
5
|
+
*
|
|
6
|
+
* Every raw side-effect (spawn `ps`/`launchctl`/`lsof` off-loop, `process.kill`, the model call,
|
|
7
|
+
* raising an attention item, reading the clock + arm file) is a single INJECTED primitive, so the
|
|
8
|
+
* wiring here is unit-testable with fakes and NO real process is ever spawned or signalled in a
|
|
9
|
+
* test. The server supplies the real primitives (`defaultPrimitives`-style) at construction.
|
|
10
|
+
*
|
|
11
|
+
* This module holds NO kill decision — it only READS the OS to produce facts and EXECUTES the
|
|
12
|
+
* signals the reviewed funnel decides on. The watch-only guarantee, the floor veto, the arm gate
|
|
13
|
+
* and the classifier authority all live in the modules it wires together, unchanged.
|
|
14
|
+
*/
|
|
15
|
+
import { type ExternalHogAdapters } from './ExternalHogSentinel.js';
|
|
16
|
+
import { type ArmMarker } from './ExternalHogArmMarker.js';
|
|
17
|
+
/** The raw side-effect primitives — the ONLY things that touch the real OS / network. */
|
|
18
|
+
export interface ExternalHogPrimitives {
|
|
19
|
+
/** Run a command off the event loop, resolve stdout. Reject/throw on non-zero exit is fine —
|
|
20
|
+
* each caller decides the fail-safe direction. */
|
|
21
|
+
exec(cmd: string, args: readonly string[]): Promise<string>;
|
|
22
|
+
/** Send a signal to a pid; `0` is an aliveness probe. Returns false if the pid is gone. */
|
|
23
|
+
signal(pid: number, sig: 'SIGTERM' | 'SIGKILL' | 0): boolean;
|
|
24
|
+
/** Kill-time CPU RE-CONFIRM (§4.5): sample the pid's cumulative cputime twice over `windowMs`
|
|
25
|
+
* (monotonic Δwall) and resolve the core-equivalents right now; null if the pid vanished /
|
|
26
|
+
* is unreadable. This is the fresh "is it STILL pinning cores, or did it go idle?" probe that
|
|
27
|
+
* gates every signal — a null or below-threshold reading must abort the kill (fail-safe). */
|
|
28
|
+
cpuCoresOver(pid: number, windowMs: number): Promise<number | null>;
|
|
29
|
+
/** Call the classifier model with a prompt (wrapped by the caller in the LlmQueue background lane). */
|
|
30
|
+
callModel(prompt: string): Promise<string>;
|
|
31
|
+
/** Raise ONE attention item for the coalesced notices. */
|
|
32
|
+
raiseAttention(item: {
|
|
33
|
+
title: string;
|
|
34
|
+
body: string;
|
|
35
|
+
priority?: 'low' | 'medium' | 'high';
|
|
36
|
+
source?: string;
|
|
37
|
+
}): Promise<unknown> | unknown;
|
|
38
|
+
/** A monotonic clock reading (ms). */
|
|
39
|
+
now(): number;
|
|
40
|
+
/** The sentinel's own effective uid. */
|
|
41
|
+
ownEuid(): number;
|
|
42
|
+
/** The server process pid (an instar-owned root of the ownership walk). */
|
|
43
|
+
serverPid(): number;
|
|
44
|
+
/** The pids of live tmux panes (instar-owned session roots). */
|
|
45
|
+
listTmuxPanePids(): Promise<readonly number[]>;
|
|
46
|
+
/** Read the durable armed state (marker + lastDisarmEpoch) — loadArmState(stateDir). */
|
|
47
|
+
loadArm(): {
|
|
48
|
+
marker: ArmMarker | null;
|
|
49
|
+
lastDisarmEpoch: number;
|
|
50
|
+
};
|
|
51
|
+
/** The LIVE kill-capability config (read fresh each call). */
|
|
52
|
+
config(): {
|
|
53
|
+
enabled: boolean;
|
|
54
|
+
dryRun: boolean;
|
|
55
|
+
};
|
|
56
|
+
/** Append one scrubbed audit row per tick (best-effort). */
|
|
57
|
+
auditRow?(row: unknown): void;
|
|
58
|
+
}
|
|
59
|
+
export interface ExternalHogAdapterOpts {
|
|
60
|
+
readonly cpuCoreThreshold: number;
|
|
61
|
+
readonly maxAncestorHops: number;
|
|
62
|
+
/** The kill-time CPU re-confirm micro-window (§4.5, ~2.5s) and its core threshold (~0.5) — the
|
|
63
|
+
* fresh "still pinning cores vs went idle" gate applied at every reReadFacts before a signal. */
|
|
64
|
+
readonly killTimeCpuRecheckWindowMs: number;
|
|
65
|
+
readonly killTimeCpuCoreThreshold: number;
|
|
66
|
+
/** Paths that count as user-document / workspace roots for the fd-skip (kill-time write) check.
|
|
67
|
+
* Empty → the conservative default (a writable regular file under $HOME but not Library/caches). */
|
|
68
|
+
readonly workspacePathHints?: readonly string[];
|
|
69
|
+
/** Home dir for the default workspace heuristic. */
|
|
70
|
+
readonly homeDir?: string;
|
|
71
|
+
}
|
|
72
|
+
/** Parse `lsof -F fatn` output into fd records. Pure. */
|
|
73
|
+
export declare function parseLsofFdRecords(out: string): Array<{
|
|
74
|
+
access: string;
|
|
75
|
+
type: string;
|
|
76
|
+
name: string;
|
|
77
|
+
}>;
|
|
78
|
+
/** Does this pid hold an open WRITABLE regular file under a user-document path? Pure over lsof out. */
|
|
79
|
+
export declare function hasWritableUserFile(lsofOut: string, opts: {
|
|
80
|
+
workspacePathHints?: readonly string[];
|
|
81
|
+
homeDir?: string;
|
|
82
|
+
}): boolean;
|
|
83
|
+
/** Parse `launchctl list` output → the set of pids that are labeled launchd jobs. Pure. */
|
|
84
|
+
export declare function parseLaunchctlPids(out: string): Set<number>;
|
|
85
|
+
/**
|
|
86
|
+
* Build the live `ExternalHogAdapters` from the raw primitives. A short-lived per-tick cache
|
|
87
|
+
* (the last parsed table + resolved ownership + launchctl set) lets the per-candidate `factsFor`
|
|
88
|
+
* calls reuse one ps/launchctl read instead of re-spawning per candidate.
|
|
89
|
+
*/
|
|
90
|
+
export declare function createExternalHogAdapters(prims: ExternalHogPrimitives, opts: ExternalHogAdapterOpts): ExternalHogAdapters;
|
|
91
|
+
//# sourceMappingURL=ExternalHogRealAdapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalHogRealAdapters.d.ts","sourceRoot":"","sources":["../../src/monitoring/ExternalHogRealAdapters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExternalHogRealAdapters — the IMPURE edge that binds the reviewed pure modules to the real OS
|
|
3
|
+
* (CMT-1901, docs/specs/external-hog-zombie-autokill-sentinel.md §1-§6). It builds the
|
|
4
|
+
* `ExternalHogAdapters` object the ExternalHogSentinel shell consumes.
|
|
5
|
+
*
|
|
6
|
+
* Every raw side-effect (spawn `ps`/`launchctl`/`lsof` off-loop, `process.kill`, the model call,
|
|
7
|
+
* raising an attention item, reading the clock + arm file) is a single INJECTED primitive, so the
|
|
8
|
+
* wiring here is unit-testable with fakes and NO real process is ever spawned or signalled in a
|
|
9
|
+
* test. The server supplies the real primitives (`defaultPrimitives`-style) at construction.
|
|
10
|
+
*
|
|
11
|
+
* This module holds NO kill decision — it only READS the OS to produce facts and EXECUTES the
|
|
12
|
+
* signals the reviewed funnel decides on. The watch-only guarantee, the floor veto, the arm gate
|
|
13
|
+
* and the classifier authority all live in the modules it wires together, unchanged.
|
|
14
|
+
*/
|
|
15
|
+
import { parseProcTable } from './ExternalHogProcTable.js';
|
|
16
|
+
import { buildProcTree } from './ExternalHogSentinel.js';
|
|
17
|
+
import { buildFacts, buildIdentity } from './ExternalHogFactBuilder.js';
|
|
18
|
+
import { matchAllowlistClass, classRuleSources } from './ExternalHogFloor.js';
|
|
19
|
+
import { classContentHash, isMarkerValid } from './ExternalHogArmMarker.js';
|
|
20
|
+
import { buildClassifierPrompt } from './ExternalHogClassifierPrompt.js';
|
|
21
|
+
const PS_TABLE_ARGS = ['-o', 'pid=,ppid=,uid=,lstart=,time=,comm='];
|
|
22
|
+
/** Parse `lsof -F fatn` output into fd records. Pure. */
|
|
23
|
+
export function parseLsofFdRecords(out) {
|
|
24
|
+
const recs = [];
|
|
25
|
+
let cur = null;
|
|
26
|
+
for (const line of out.split('\n')) {
|
|
27
|
+
if (line.length === 0)
|
|
28
|
+
continue;
|
|
29
|
+
const tag = line[0];
|
|
30
|
+
const val = line.slice(1);
|
|
31
|
+
if (tag === 'f') { // a new fd record begins
|
|
32
|
+
if (cur)
|
|
33
|
+
recs.push(cur);
|
|
34
|
+
cur = { access: '', type: '', name: '' };
|
|
35
|
+
}
|
|
36
|
+
else if (cur) {
|
|
37
|
+
if (tag === 'a')
|
|
38
|
+
cur.access = val;
|
|
39
|
+
else if (tag === 't')
|
|
40
|
+
cur.type = val;
|
|
41
|
+
else if (tag === 'n')
|
|
42
|
+
cur.name = val;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (cur)
|
|
46
|
+
recs.push(cur);
|
|
47
|
+
return recs;
|
|
48
|
+
}
|
|
49
|
+
/** Does this pid hold an open WRITABLE regular file under a user-document path? Pure over lsof out. */
|
|
50
|
+
export function hasWritableUserFile(lsofOut, opts) {
|
|
51
|
+
const hints = opts.workspacePathHints ?? [];
|
|
52
|
+
const home = opts.homeDir ?? '';
|
|
53
|
+
for (const r of parseLsofFdRecords(lsofOut)) {
|
|
54
|
+
if (r.type !== 'REG')
|
|
55
|
+
continue;
|
|
56
|
+
if (!(r.access.includes('w') || r.access.includes('u')))
|
|
57
|
+
continue; // write or read+write
|
|
58
|
+
const name = r.name;
|
|
59
|
+
if (hints.length > 0) {
|
|
60
|
+
if (hints.some((h) => h && name.startsWith(h)))
|
|
61
|
+
return true;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Default heuristic: a writable regular file under $HOME but NOT under a cache/library/system dir.
|
|
65
|
+
if (home && name.startsWith(home)) {
|
|
66
|
+
const rel = name.slice(home.length);
|
|
67
|
+
if (/^\/(Library|\.cache|\.Trash|\.npm|\.cache|Caches)\b/i.test(rel))
|
|
68
|
+
continue;
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/** Parse `launchctl list` output → the set of pids that are labeled launchd jobs. Pure. */
|
|
75
|
+
export function parseLaunchctlPids(out) {
|
|
76
|
+
const pids = new Set();
|
|
77
|
+
for (const line of out.split('\n')) {
|
|
78
|
+
// Columns: PID Status Label. A '-' PID means not-currently-running (skip).
|
|
79
|
+
const m = /^\s*(\d+)\s+\S+\s+\S/.exec(line);
|
|
80
|
+
if (m) {
|
|
81
|
+
const pid = Number(m[1]);
|
|
82
|
+
if (Number.isInteger(pid) && pid > 0)
|
|
83
|
+
pids.add(pid);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return pids;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Build the live `ExternalHogAdapters` from the raw primitives. A short-lived per-tick cache
|
|
90
|
+
* (the last parsed table + resolved ownership + launchctl set) lets the per-candidate `factsFor`
|
|
91
|
+
* calls reuse one ps/launchctl read instead of re-spawning per candidate.
|
|
92
|
+
*/
|
|
93
|
+
export function createExternalHogAdapters(prims, opts) {
|
|
94
|
+
let lastTable = [];
|
|
95
|
+
let lastOwned = new Map();
|
|
96
|
+
let launchctlCache = null;
|
|
97
|
+
async function readProcTable() {
|
|
98
|
+
try {
|
|
99
|
+
lastTable = parseProcTable(await prims.exec('ps', PS_TABLE_ARGS));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
lastTable = []; // a failed ps read → empty table → the sampler heartbeat won't advance (→ on-stale)
|
|
103
|
+
}
|
|
104
|
+
return lastTable;
|
|
105
|
+
}
|
|
106
|
+
async function ownedRefs() {
|
|
107
|
+
const owned = new Map();
|
|
108
|
+
const rootPids = [prims.serverPid()];
|
|
109
|
+
try {
|
|
110
|
+
rootPids.push(...(await prims.listTmuxPanePids()));
|
|
111
|
+
}
|
|
112
|
+
catch { /* tmux unavailable → server pid only */ }
|
|
113
|
+
for (const pid of rootPids) {
|
|
114
|
+
const row = lastTable.find((r) => r.pid === pid);
|
|
115
|
+
if (row)
|
|
116
|
+
owned.set(pid, row.startTime);
|
|
117
|
+
}
|
|
118
|
+
lastOwned = owned;
|
|
119
|
+
return owned;
|
|
120
|
+
}
|
|
121
|
+
async function launchctlPids() {
|
|
122
|
+
const now = prims.now();
|
|
123
|
+
if (launchctlCache && now - launchctlCache.at < 30_000)
|
|
124
|
+
return launchctlCache.pids;
|
|
125
|
+
try {
|
|
126
|
+
const pids = parseLaunchctlPids(await prims.exec('launchctl', ['list']));
|
|
127
|
+
launchctlCache = { at: now, pids };
|
|
128
|
+
return pids;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// @silent-fallback-ok: reviewed decision (round 8) — launchctl failed → EMPTY set.
|
|
132
|
+
// hasLaunchctlLabel:false does NOT open a kill on its own (every OTHER floor invariant
|
|
133
|
+
// must still hold), and a genuinely labeled job that we fail to detect is a rare edge;
|
|
134
|
+
// the conservative alternative (mark everything labeled → never kill) would break the
|
|
135
|
+
// feature entirely. Fail toward the feature working, floor-bounded.
|
|
136
|
+
return new Set();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function fetchArgv(pid) {
|
|
140
|
+
try {
|
|
141
|
+
const out = (await prims.exec('ps', ['-o', 'args=', '-p', String(pid)])).trim();
|
|
142
|
+
return out.length > 0 ? out : null;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// @silent-fallback-ok: fail-SAFE direction — can't read argv → the caller returns null
|
|
146
|
+
// facts → candidate skipped entirely (a missing fact always blocks, never permits).
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function factsFor(candidate, table) {
|
|
151
|
+
const row = table.find((r) => r.pid === candidate.pid && r.startTime === candidate.startTime);
|
|
152
|
+
if (!row)
|
|
153
|
+
return null; // vanished / identity changed since candidacy
|
|
154
|
+
const argv = await fetchArgv(candidate.pid);
|
|
155
|
+
if (argv === null)
|
|
156
|
+
return null;
|
|
157
|
+
const tree = buildProcTree(table);
|
|
158
|
+
const launchctlLabeledPids = await launchctlPids();
|
|
159
|
+
return buildFacts({
|
|
160
|
+
row, argv, tree, ownedRefs: lastOwned, maxAncestorHops: opts.maxAncestorHops,
|
|
161
|
+
ownEuid: prims.ownEuid(), launchctlLabeledPids,
|
|
162
|
+
sustainedThisWindow: candidate.coreEquivalents >= opts.cpuCoreThreshold,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function identityFor(_candidate, facts) {
|
|
166
|
+
return buildIdentity(facts);
|
|
167
|
+
}
|
|
168
|
+
async function classify(facts) {
|
|
169
|
+
const classId = matchAllowlistClass(facts.name, facts.argv);
|
|
170
|
+
if (!classId)
|
|
171
|
+
return null; // not an allowlist class → decider-unavailable → alert (never happens: only classified after identity)
|
|
172
|
+
return prims.callModel(buildClassifierPrompt(facts, classId));
|
|
173
|
+
}
|
|
174
|
+
function currentClassContentHash(classId) {
|
|
175
|
+
const sources = classRuleSources(classId);
|
|
176
|
+
// A class with no rule sources can't be armed; return a sentinel hash that matches NOTHING in
|
|
177
|
+
// any snapshot (so the arm-scope check fails closed → no kill).
|
|
178
|
+
return sources ? classContentHash(sources) : 'no-such-class';
|
|
179
|
+
}
|
|
180
|
+
const killFunnelDeps = {
|
|
181
|
+
reReadFacts: async (pid, startTime) => {
|
|
182
|
+
const table = await readProcTable();
|
|
183
|
+
const row = table.find((r) => r.pid === pid && r.startTime === startTime);
|
|
184
|
+
if (!row)
|
|
185
|
+
return null; // gone or pid reused (startTime mismatch) → identity changed
|
|
186
|
+
const argv = await fetchArgv(pid);
|
|
187
|
+
if (argv === null)
|
|
188
|
+
return null;
|
|
189
|
+
// §4.5 kill-time CPU re-confirm — a FRESH micro-sample RIGHT NOW: is it still pinning cores,
|
|
190
|
+
// or did it go idle since classify? A null (probe failed / pid gone) or below-threshold
|
|
191
|
+
// reading sets sustainedHighCpu:false → the floor re-check vetoes → the kill aborts (safe).
|
|
192
|
+
const cores = await prims.cpuCoresOver(pid, opts.killTimeCpuRecheckWindowMs);
|
|
193
|
+
const stillHog = cores !== null && Number.isFinite(cores) && cores >= opts.killTimeCpuCoreThreshold;
|
|
194
|
+
return buildFacts({
|
|
195
|
+
row, argv, tree: buildProcTree(table), ownedRefs: lastOwned, maxAncestorHops: opts.maxAncestorHops,
|
|
196
|
+
ownEuid: prims.ownEuid(), launchctlLabeledPids: await launchctlPids(),
|
|
197
|
+
sustainedThisWindow: stillHog,
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
reReadArmState: () => {
|
|
201
|
+
const arm = prims.loadArm();
|
|
202
|
+
return { config: prims.config(), marker: arm.marker, lastDisarmEpoch: arm.lastDisarmEpoch };
|
|
203
|
+
},
|
|
204
|
+
currentClassContentHash,
|
|
205
|
+
hasOpenWritableWorkspaceFile: async (pid) => {
|
|
206
|
+
try {
|
|
207
|
+
return hasWritableUserFile(await prims.exec('lsof', ['-p', String(pid), '-F', 'fatn']), opts);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return true; // lsof error → can't rule out an in-progress write → DEFER (bounded, safe)
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
sendSignal: (pid, signal) => { prims.signal(pid, signal); },
|
|
214
|
+
stillAlive: (pid) => prims.signal(pid, 0),
|
|
215
|
+
wait: (ms) => new Promise((res) => setTimeout(res, Math.max(0, ms))),
|
|
216
|
+
};
|
|
217
|
+
function deliverNotices(result) {
|
|
218
|
+
if (!result || result.emitted.length === 0)
|
|
219
|
+
return;
|
|
220
|
+
const hasKill = result.emitted.some((n) => n.cls === 'kill');
|
|
221
|
+
const body = result.emitted.map((n) => `• ${n.text}`).join('\n');
|
|
222
|
+
void Promise.resolve(prims.raiseAttention({
|
|
223
|
+
title: hasKill ? 'External-hog sentinel: auto-killed a zombie' : 'External-hog sentinel: sustained CPU hog',
|
|
224
|
+
body,
|
|
225
|
+
priority: hasKill ? 'high' : 'medium',
|
|
226
|
+
source: 'external-hog-sentinel',
|
|
227
|
+
})).catch(() => undefined); // delivery is best-effort; never throw into the tick
|
|
228
|
+
}
|
|
229
|
+
function armStatus() {
|
|
230
|
+
const cfg = prims.config();
|
|
231
|
+
const arm = prims.loadArm();
|
|
232
|
+
return { enabled: cfg.enabled === true, dryRun: cfg.dryRun !== false, markerValid: isMarkerValid(arm.marker, arm.lastDisarmEpoch) };
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
readProcTable,
|
|
236
|
+
ownedRefs,
|
|
237
|
+
factsFor,
|
|
238
|
+
identityFor,
|
|
239
|
+
classify,
|
|
240
|
+
killFunnelDeps,
|
|
241
|
+
deliverNotices,
|
|
242
|
+
armStatus,
|
|
243
|
+
nowMs: () => prims.now(),
|
|
244
|
+
...(prims.auditRow ? { auditTick: (row) => prims.auditRow(row) } : {}),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=ExternalHogRealAdapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalHogRealAdapters.js","sourceRoot":"","sources":["../../src/monitoring/ExternalHogRealAdapters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExternalHogSampler — the PURE stage-1 candidacy state machine of the External-Hog sentinel
|
|
3
|
+
* (CMT-1901, docs/specs/external-hog-zombie-autokill-sentinel.md §1).
|
|
4
|
+
*
|
|
5
|
+
* Given two successive `ps` snapshots, compute the stage-1 CANDIDATES: external (own-uid,
|
|
6
|
+
* not-instar-owned) processes whose cross-tick `Δcputime / Δwall` crosses the core threshold.
|
|
7
|
+
* This is the cheap whole-table pass that selects the small set (typically 0–3) the expensive
|
|
8
|
+
* N-window confirmation + classifier then act on. PURE over its inputs (the actual `ps` spawn
|
|
9
|
+
* + the wall clock live in the thin I/O worker shell) so the candidacy logic is fully testable.
|
|
10
|
+
*
|
|
11
|
+
* Two round-reviewed properties carried here:
|
|
12
|
+
* - candidacy uses the DELTA (Δcputime/Δwall), NOT `ps %cpu` — a process idle for 23h that
|
|
13
|
+
* only NOW pins cores is caught (its lifetime average is diluted, but its cross-tick delta
|
|
14
|
+
* is high). The map is rebuilt from the current table each tick (bounded; no accumulate).
|
|
15
|
+
* - a LIVENESS HEARTBEAT (`lastSnapshotAt`) advances on any SUCCESSFUL parse (≥1 plausible
|
|
16
|
+
* row), regardless of candidate count — so an idle no-hog machine is never read as
|
|
17
|
+
* sampler-dead, and a failed/empty parse does NOT advance it (→ eventually sampler-dead).
|
|
18
|
+
*/
|
|
19
|
+
import { type CpuSample } from './ExternalHogCpuDelta.js';
|
|
20
|
+
import { type ProcTree, type OwnedRefs } from './ExternalHogOwnership.js';
|
|
21
|
+
import type { ProcTableRow } from './ExternalHogProcTable.js';
|
|
22
|
+
export interface SamplerState {
|
|
23
|
+
/** Previous tick's identity-key → { cumulativeCpuSeconds, monotonicWallMs }. */
|
|
24
|
+
readonly prev: ReadonlyMap<string, CpuSample>;
|
|
25
|
+
/** The liveness heartbeat — advances on any successful (plausible) parse. */
|
|
26
|
+
readonly lastSnapshotAt: number | null;
|
|
27
|
+
}
|
|
28
|
+
export declare const EMPTY_SAMPLER_STATE: SamplerState;
|
|
29
|
+
export interface Candidate {
|
|
30
|
+
readonly pid: number;
|
|
31
|
+
readonly startTime: string;
|
|
32
|
+
readonly comm: string;
|
|
33
|
+
readonly coreEquivalents: number;
|
|
34
|
+
}
|
|
35
|
+
export interface SamplerTick {
|
|
36
|
+
readonly nextState: SamplerState;
|
|
37
|
+
readonly candidates: readonly Candidate[];
|
|
38
|
+
/** True when this tick's parse was plausible (heartbeat advanced). */
|
|
39
|
+
readonly parsedOk: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface SamplerOpts {
|
|
42
|
+
readonly ownEuid: number;
|
|
43
|
+
readonly cpuCoreThreshold: number;
|
|
44
|
+
readonly sampleWindowMs: number;
|
|
45
|
+
readonly maxAncestorHops: number;
|
|
46
|
+
/** Minimum plausible row count for a "successful" parse (heartbeat gate). Default 1. */
|
|
47
|
+
readonly minPlausibleRows?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Advance the sampler by one tick. `table` is the current parsed `ps` snapshot; `tree`/`owned`
|
|
51
|
+
* are built from it by the caller (the ownership sets). `monotonicWallMs` is a monotonic-clock
|
|
52
|
+
* reading. Returns the next state (with the rebuilt map + advanced heartbeat) and the stage-1
|
|
53
|
+
* candidates. Pure — mutates nothing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function advanceSampler(state: SamplerState, table: readonly ProcTableRow[], tree: ProcTree, owned: OwnedRefs, monotonicWallMs: number, opts: SamplerOpts): SamplerTick;
|
|
56
|
+
/**
|
|
57
|
+
* Is the sampler DEAD (heartbeat too old)? Never-run (null heartbeat) is NOT dead — it just
|
|
58
|
+
* hasn't started. A non-finite `now` fails toward not-declaring-dead (avoid a false restart on
|
|
59
|
+
* a bad clock read). `deadThresholdMs = max(2*scanInterval, N*window)` per §1.
|
|
60
|
+
*/
|
|
61
|
+
export declare function isSamplerDead(state: SamplerState, nowMs: number, deadThresholdMs: number): boolean;
|
|
62
|
+
//# sourceMappingURL=ExternalHogSampler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalHogSampler.d.ts","sourceRoot":"","sources":["../../src/monitoring/ExternalHogSampler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAiB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAO9D,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC9C,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,mBAAmB,EAAE,YAAwD,CAAC;AAE3F,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,wFAAwF;IACxF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,SAAS,EAChB,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,WAAW,GAChB,WAAW,CA8Cb;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAIlG"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalHogSampler.js","sourceRoot":"","sources":["../../src/monitoring/ExternalHogSampler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,sBAAsB,EAAE,SAAS,EAAkB,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAiC,MAAM,2BAA2B,CAAC;AAGzF,qFAAqF;AACrF,SAAS,KAAK,CAAC,GAAW,EAAE,SAAiB;IAC3C,OAAO,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;AAC/B,CAAC;AASD,MAAM,CAAC,MAAM,mBAAmB,GAAiB,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;AAyB3F;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAmB,EACnB,KAA8B,EAC9B,IAAc,EACd,KAAgB,EAChB,eAAuB,EACvB,IAAiB;IAEjB,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAErG,0FAA0F;IAC1F,wFAAwF;IACxF,2DAA2D;IAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC/D,CAAC;IAED,6FAA6F;IAC7F,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1C,MAAM,UAAU,GAAgB,EAAE,CAAC;IAEnC,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;YAAE,SAAS;QACzD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1C,0FAA0F;QAC1F,gFAAgF;QAChF,MAAM,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC;QAClC,MAAM,MAAM,GAAc;YACxB,oBAAoB,EAAE,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG;YACjG,eAAe;SAChB,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAEtB,kFAAkF;QAClF,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,CAAC,OAAO;YAAE,SAAS;QACvC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAS,CAAC,oCAAoC;QAC1G,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC;YAAE,SAAS;QAExE,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU;YAAE,SAAS,CAAC,gDAAgD;QAC3E,MAAM,IAAI,GAAG,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,gBAAgB,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QACnG,IAAI,SAAS,CAAC,IAAI,CAAC;YAAE,SAAS;QAC9B,IAAI,IAAI,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAClC,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QACrG,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE;QAC1D,UAAU;QACV,QAAQ,EAAE,IAAI;KACf,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAmB,EAAE,KAAa,EAAE,eAAuB;IACvF,IAAI,KAAK,CAAC,cAAc,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/E,OAAO,KAAK,GAAG,KAAK,CAAC,cAAc,GAAG,eAAe,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExternalHogScanTick — the orchestrator that composes the External-Hog sentinel's modules into
|
|
3
|
+
* ONE scan tick (CMT-1901, docs/specs/external-hog-zombie-autokill-sentinel.md §1-§6).
|
|
4
|
+
*
|
|
5
|
+
* This is the "make it alive" integration: discovery (sampler) → classify (worst-CPU-first under
|
|
6
|
+
* the cap) → floor → kill funnel → P19 ledger → P17 coalesced notices. All I/O is INJECTED
|
|
7
|
+
* (read ps, build ownership, classify, the kill-funnel deps, clock, deliver) so the whole tick
|
|
8
|
+
* is end-to-end testable without a real ps read, a real model call, or a real signal. The thin
|
|
9
|
+
* server-side wiring (the actual ps spawn, LlmQueue call, notice delivery, interval) is a
|
|
10
|
+
* separate slice; this is the pure control flow that ties the reviewed modules together.
|
|
11
|
+
*
|
|
12
|
+
* Watch-only rides through: the kill funnel returns `would-kill` (no signal) unless a live kill
|
|
13
|
+
* is authorized, so in the shipped dryRun state a scan tick produces would-kill records + the
|
|
14
|
+
* §4 observability notices, and kills NOTHING.
|
|
15
|
+
*/
|
|
16
|
+
import type { ProcTableRow } from './ExternalHogProcTable.js';
|
|
17
|
+
import { type SamplerState, type SamplerOpts, type Candidate } from './ExternalHogSampler.js';
|
|
18
|
+
import type { ProcTree, OwnedRefs } from './ExternalHogOwnership.js';
|
|
19
|
+
import { type ClassifierVerdict } from './ExternalHogClassifier.js';
|
|
20
|
+
import { type ExternalHogFacts } from './ExternalHogFloor.js';
|
|
21
|
+
import { type KillOutcome, type KillFunnelDeps, type KillFunnelOpts } from './ExternalHogKillFunnel.js';
|
|
22
|
+
import { type KillLedgerState, type BreakerOpts } from './ExternalHogKillLedger.js';
|
|
23
|
+
import { type CoalesceResult } from './ExternalHogNoticeCoalescer.js';
|
|
24
|
+
import { type SustainedState } from './ExternalHogSustained.js';
|
|
25
|
+
export interface ScanState {
|
|
26
|
+
readonly sampler: SamplerState;
|
|
27
|
+
readonly ledger: KillLedgerState;
|
|
28
|
+
/** Stage-2 N-window sustained-CPU streaks (§1 anti-spike; feeds sustainedHighCpu authoritatively). */
|
|
29
|
+
readonly sustained: SustainedState;
|
|
30
|
+
}
|
|
31
|
+
export interface ScanDeps {
|
|
32
|
+
/** The current parsed ps table (the sampler's input). */
|
|
33
|
+
readProcTable(): readonly ProcTableRow[];
|
|
34
|
+
/** Build the ownership sets (tree + owned pids) from the current table + instar pids. */
|
|
35
|
+
buildOwnership(table: readonly ProcTableRow[]): {
|
|
36
|
+
tree: ProcTree;
|
|
37
|
+
owned: OwnedRefs;
|
|
38
|
+
};
|
|
39
|
+
/** Full deterministic facts for a candidate (the floor input); null if it vanished. May be async
|
|
40
|
+
* (a per-candidate ps -o args= read + launchctl) — the orchestrator awaits it. */
|
|
41
|
+
factsFor(candidate: Candidate): ExternalHogFacts | null | Promise<ExternalHogFacts | null>;
|
|
42
|
+
/** The command-hash + ledger key + class for a candidate (identity for the ledger/funnel). */
|
|
43
|
+
identityFor(candidate: Candidate, facts: ExternalHogFacts): {
|
|
44
|
+
commandHash: string;
|
|
45
|
+
ledgerKey: string;
|
|
46
|
+
classId: string;
|
|
47
|
+
} | null;
|
|
48
|
+
/** Call the classifier (LlmQueue). Returns raw model output, or null if the decider is unavailable. */
|
|
49
|
+
classify(facts: ExternalHogFacts): Promise<unknown>;
|
|
50
|
+
/** The kill-funnel I/O (re-read facts/arm, fd-probe, signal, aliveness, wait). */
|
|
51
|
+
killFunnelDeps: KillFunnelDeps;
|
|
52
|
+
/** A monotonic clock reading (ms). */
|
|
53
|
+
nowMs(): number;
|
|
54
|
+
/** How many times a target signature has already been deferred (for maxKillDeferrals). */
|
|
55
|
+
deferralsFor(ledgerKey: string): number;
|
|
56
|
+
}
|
|
57
|
+
export interface ScanOpts {
|
|
58
|
+
readonly sampler: SamplerOpts;
|
|
59
|
+
/** N consecutive delta windows over threshold before sustainedHighCpu is true (§1 anti-spike). */
|
|
60
|
+
readonly sustainedSampleCount: number;
|
|
61
|
+
readonly maxClassificationsPerScan: number;
|
|
62
|
+
readonly breaker: Omit<BreakerOpts, 'nowMs'>;
|
|
63
|
+
readonly killFunnel: Omit<KillFunnelOpts, 'currentDeferrals'>;
|
|
64
|
+
readonly noticeBudgetPerWindow: number;
|
|
65
|
+
readonly killLedgerRetentionMs: number;
|
|
66
|
+
}
|
|
67
|
+
/** One per-candidate outcome row (for the audit/soak log AND cross-tick deferral tracking).
|
|
68
|
+
* `ledgerKey`/`classId` carry the target IDENTITY so a consumer (the sentinel shell) can
|
|
69
|
+
* persist how many times a signature has been deferred without re-deriving it. */
|
|
70
|
+
export interface ScanOutcome {
|
|
71
|
+
readonly pid: number;
|
|
72
|
+
readonly ledgerKey: string;
|
|
73
|
+
readonly classId: string;
|
|
74
|
+
readonly verdict: ClassifierVerdict | 'decider-unavailable';
|
|
75
|
+
readonly outcome: KillOutcome | 'alert-only';
|
|
76
|
+
}
|
|
77
|
+
export interface ScanResult {
|
|
78
|
+
readonly nextState: ScanState;
|
|
79
|
+
/** Per-candidate outcomes (for the audit/soak log). */
|
|
80
|
+
readonly outcomes: ReadonlyArray<ScanOutcome>;
|
|
81
|
+
/** The coalesced notices to deliver. */
|
|
82
|
+
readonly notices: CoalesceResult;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Run one scan tick. Pure control flow over the injected I/O; mutates nothing. In the shipped
|
|
86
|
+
* dryRun state every `outcome` is `would-kill`/`alert-only` and no signal is sent.
|
|
87
|
+
*/
|
|
88
|
+
export declare function runScanTick(state: ScanState, deps: ScanDeps, opts: ScanOpts): Promise<ScanResult>;
|
|
89
|
+
//# sourceMappingURL=ExternalHogScanTick.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalHogScanTick.d.ts","sourceRoot":"","sources":["../../src/monitoring/ExternalHogScanTick.ts"],"names":[],"mappings":"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"}
|