@bluewombat/runtime 0.10.0 → 0.11.1
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 +202 -94
- package/SPECS.md +151 -25
- package/dist/cli.js +95 -1
- package/dist/cli.js.map +1 -1
- package/dist/config/agent-shorthand.d.ts +3 -4
- package/dist/config/agent-shorthand.d.ts.map +1 -1
- package/dist/config/agent-shorthand.js +3 -4
- package/dist/config/agent-shorthand.js.map +1 -1
- package/dist/config/fixture-yaml.d.ts +8 -0
- package/dist/config/fixture-yaml.d.ts.map +1 -0
- package/dist/config/fixture-yaml.js +30 -0
- package/dist/config/fixture-yaml.js.map +1 -0
- package/dist/config/load-config.d.ts.map +1 -1
- package/dist/config/load-config.js +90 -102
- package/dist/config/load-config.js.map +1 -1
- package/dist/config/parse-args.d.ts.map +1 -1
- package/dist/config/parse-args.js +3 -4
- package/dist/config/parse-args.js.map +1 -1
- package/dist/config/types.d.ts +15 -16
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/loop/authority.d.ts +2 -0
- package/dist/loop/authority.d.ts.map +1 -1
- package/dist/loop/authority.js +11 -1
- package/dist/loop/authority.js.map +1 -1
- package/dist/loop/deliveries.d.ts.map +1 -1
- package/dist/loop/deliveries.js +19 -0
- package/dist/loop/deliveries.js.map +1 -1
- package/dist/loop/features.d.ts +30 -0
- package/dist/loop/features.d.ts.map +1 -1
- package/dist/loop/features.js +195 -73
- package/dist/loop/features.js.map +1 -1
- package/dist/loop/journal.d.ts +7 -0
- package/dist/loop/journal.d.ts.map +1 -1
- package/dist/loop/journal.js +23 -1
- package/dist/loop/journal.js.map +1 -1
- package/dist/loop/lock.d.ts +2 -0
- package/dist/loop/lock.d.ts.map +1 -1
- package/dist/loop/lock.js +10 -0
- package/dist/loop/lock.js.map +1 -1
- package/dist/loop/open-host.d.ts +10 -0
- package/dist/loop/open-host.d.ts.map +1 -1
- package/dist/loop/open-host.js +8 -8
- package/dist/loop/open-host.js.map +1 -1
- package/dist/loop/run-slot.d.ts +14 -0
- package/dist/loop/run-slot.d.ts.map +1 -1
- package/dist/loop/run-slot.js +53 -5
- package/dist/loop/run-slot.js.map +1 -1
- package/dist/loop/streams.d.ts +3 -0
- package/dist/loop/streams.d.ts.map +1 -1
- package/dist/loop/streams.js +4 -3
- package/dist/loop/streams.js.map +1 -1
- package/dist/loop/tick.d.ts +3 -0
- package/dist/loop/tick.d.ts.map +1 -1
- package/dist/loop/tick.js +2 -1
- package/dist/loop/tick.js.map +1 -1
- package/dist/loop/trace.d.ts +1 -0
- package/dist/loop/trace.d.ts.map +1 -1
- package/dist/loop/trace.js +1 -1
- package/dist/loop/trace.js.map +1 -1
- package/dist/loop/transformers.d.ts +4 -4
- package/dist/loop/transformers.d.ts.map +1 -1
- package/dist/loop/transformers.js +16 -25
- package/dist/loop/transformers.js.map +1 -1
- package/dist/operator/board.d.ts +43 -4
- package/dist/operator/board.d.ts.map +1 -1
- package/dist/operator/board.js +153 -10
- package/dist/operator/board.js.map +1 -1
- package/dist/operator/dash-model.d.ts +65 -0
- package/dist/operator/dash-model.d.ts.map +1 -0
- package/dist/operator/dash-model.js +209 -0
- package/dist/operator/dash-model.js.map +1 -0
- package/dist/operator/dash-view.d.ts +16 -0
- package/dist/operator/dash-view.d.ts.map +1 -0
- package/dist/operator/dash-view.js +226 -0
- package/dist/operator/dash-view.js.map +1 -0
- package/dist/operator/dash.d.ts +34 -0
- package/dist/operator/dash.d.ts.map +1 -0
- package/dist/operator/dash.js +141 -0
- package/dist/operator/dash.js.map +1 -0
- package/dist/operator/doctor.d.ts.map +1 -1
- package/dist/operator/doctor.js +48 -8
- package/dist/operator/doctor.js.map +1 -1
- package/dist/operator/explain.d.ts.map +1 -1
- package/dist/operator/explain.js +6 -11
- package/dist/operator/explain.js.map +1 -1
- package/dist/operator/incident-dossier.d.ts +154 -0
- package/dist/operator/incident-dossier.d.ts.map +1 -0
- package/dist/operator/incident-dossier.js +692 -0
- package/dist/operator/incident-dossier.js.map +1 -0
- package/dist/operator/incident-system.d.ts +57 -0
- package/dist/operator/incident-system.d.ts.map +1 -0
- package/dist/operator/incident-system.js +214 -0
- package/dist/operator/incident-system.js.map +1 -0
- package/dist/operator/incident.d.ts +27 -0
- package/dist/operator/incident.d.ts.map +1 -0
- package/dist/operator/incident.js +220 -0
- package/dist/operator/incident.js.map +1 -0
- package/dist/operator/init.js +24 -24
- package/dist/operator/init.js.map +1 -1
- package/dist/operator/install.d.ts +9 -0
- package/dist/operator/install.d.ts.map +1 -0
- package/dist/operator/install.js +14 -0
- package/dist/operator/install.js.map +1 -0
- package/dist/operator/live.js +4 -4
- package/dist/operator/live.js.map +1 -1
- package/dist/operator/log.d.ts +2 -0
- package/dist/operator/log.d.ts.map +1 -1
- package/dist/operator/log.js +2 -5
- package/dist/operator/log.js.map +1 -1
- package/dist/operator/restart.d.ts +20 -0
- package/dist/operator/restart.d.ts.map +1 -0
- package/dist/operator/restart.js +63 -0
- package/dist/operator/restart.js.map +1 -0
- package/dist/operator/supervise/act.d.ts +37 -0
- package/dist/operator/supervise/act.d.ts.map +1 -0
- package/dist/operator/supervise/act.js +354 -0
- package/dist/operator/supervise/act.js.map +1 -0
- package/dist/operator/supervise/config.d.ts +74 -0
- package/dist/operator/supervise/config.d.ts.map +1 -0
- package/dist/operator/supervise/config.js +175 -0
- package/dist/operator/supervise/config.js.map +1 -0
- package/dist/operator/supervise/council.d.ts +45 -0
- package/dist/operator/supervise/council.d.ts.map +1 -0
- package/dist/operator/supervise/council.js +97 -0
- package/dist/operator/supervise/council.js.map +1 -0
- package/dist/operator/supervise/decision.d.ts +46 -0
- package/dist/operator/supervise/decision.d.ts.map +1 -0
- package/dist/operator/supervise/decision.js +137 -0
- package/dist/operator/supervise/decision.js.map +1 -0
- package/dist/operator/supervise/exec.d.ts +28 -0
- package/dist/operator/supervise/exec.d.ts.map +1 -0
- package/dist/operator/supervise/exec.js +47 -0
- package/dist/operator/supervise/exec.js.map +1 -0
- package/dist/operator/supervise/memory.d.ts +33 -0
- package/dist/operator/supervise/memory.d.ts.map +1 -0
- package/dist/operator/supervise/memory.js +73 -0
- package/dist/operator/supervise/memory.js.map +1 -0
- package/dist/operator/supervise/observe.d.ts +47 -0
- package/dist/operator/supervise/observe.d.ts.map +1 -0
- package/dist/operator/supervise/observe.js +73 -0
- package/dist/operator/supervise/observe.js.map +1 -0
- package/dist/operator/supervise/prompts.d.ts +60 -0
- package/dist/operator/supervise/prompts.d.ts.map +1 -0
- package/dist/operator/supervise/prompts.js +338 -0
- package/dist/operator/supervise/prompts.js.map +1 -0
- package/dist/operator/supervise/review.d.ts +24 -0
- package/dist/operator/supervise/review.d.ts.map +1 -0
- package/dist/operator/supervise/review.js +51 -0
- package/dist/operator/supervise/review.js.map +1 -0
- package/dist/operator/supervise/supervise.d.ts +26 -0
- package/dist/operator/supervise/supervise.d.ts.map +1 -0
- package/dist/operator/supervise/supervise.js +484 -0
- package/dist/operator/supervise/supervise.js.map +1 -0
- package/package.json +14 -14
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SupervisorConfig } from "./config.js";
|
|
2
|
+
import { type Decision } from "./decision.js";
|
|
3
|
+
import { type Exec } from "./exec.js";
|
|
4
|
+
import { type Brief } from "./prompts.js";
|
|
5
|
+
export type Deliberation = {
|
|
6
|
+
ok: true;
|
|
7
|
+
decision: Decision;
|
|
8
|
+
reports: Record<string, string>;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
reason: string;
|
|
12
|
+
reports: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
export type AgentRunInput = {
|
|
15
|
+
config: SupervisorConfig;
|
|
16
|
+
exec: Exec;
|
|
17
|
+
role: string;
|
|
18
|
+
prompt: string;
|
|
19
|
+
/** Where the prompt and the answer are filed. */
|
|
20
|
+
dir: string;
|
|
21
|
+
cwd: string;
|
|
22
|
+
addDirs: string[];
|
|
23
|
+
};
|
|
24
|
+
/** One agent, once: its prompt written down, its answer kept. */
|
|
25
|
+
export declare function runAgent(input: AgentRunInput): Promise<{
|
|
26
|
+
ok: boolean;
|
|
27
|
+
text: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Three members read the same stop from different seats; an arbiter decides.
|
|
31
|
+
*
|
|
32
|
+
* The members run together and apart: none sees another's answer, so they
|
|
33
|
+
* cannot settle on the first idea. The arbiter sees all three and the code.
|
|
34
|
+
* A member that fails does not stop the others; fewer than two answers is no
|
|
35
|
+
* council. An arbiter whose answer is refused for its shape has it corrected by a small
|
|
36
|
+
* agent from its own text; one that fails is asked again as before.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deliberate(input: {
|
|
39
|
+
config: SupervisorConfig;
|
|
40
|
+
exec: Exec;
|
|
41
|
+
brief: Brief;
|
|
42
|
+
dir: string;
|
|
43
|
+
cwd: string;
|
|
44
|
+
}): Promise<Deliberation>;
|
|
45
|
+
//# sourceMappingURL=council.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../../src/operator/supervise/council.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,KAAK,QAAQ,EAA2B,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,EAA0C,MAAM,WAAW,CAAC;AAC9E,OAAO,EAEL,KAAK,KAAK,EAKX,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACjE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAWnE,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,iEAAiE;AACjE,wBAAsB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB3F;AAWD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE;IACtC,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAAC,YAAY,CAAC,CAqDxB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { lastJson, parseDecision } from "./decision.js";
|
|
4
|
+
import { fill, succeeded, tail } from "./exec.js";
|
|
5
|
+
import { arbiterPrompt, formPrompt, remedyPrompt, rootcausePrompt, skepticPrompt, } from "./prompts.js";
|
|
6
|
+
const ANALYSTS = [
|
|
7
|
+
["rootcause", rootcausePrompt],
|
|
8
|
+
["remedy", remedyPrompt],
|
|
9
|
+
["skeptic", skepticPrompt],
|
|
10
|
+
];
|
|
11
|
+
/** Cap what one member's report adds to the arbiter's page. */
|
|
12
|
+
const REPORT_CHARS = 30_000;
|
|
13
|
+
/** One agent, once: its prompt written down, its answer kept. */
|
|
14
|
+
export async function runAgent(input) {
|
|
15
|
+
mkdirSync(input.dir, { recursive: true });
|
|
16
|
+
const promptFile = join(input.dir, `${input.role}.prompt.md`);
|
|
17
|
+
writeFileSync(promptFile, input.prompt);
|
|
18
|
+
const spec = input.config.agents[input.role];
|
|
19
|
+
if (spec === undefined) {
|
|
20
|
+
return { ok: false, text: `no agent configured for ${input.role}` };
|
|
21
|
+
}
|
|
22
|
+
const result = await input.exec(fill(spec.cmd, { prompt: input.prompt, promptFile }, { addDirArgs: input.addDirs.flatMap((dir) => ["--add-dir", dir]) }), { cwd: input.cwd, timeoutMs: spec.timeoutMs });
|
|
23
|
+
const ok = succeeded(result) || answeredBeforeCeiling(result);
|
|
24
|
+
const text = ok ? result.stdout : tail(result);
|
|
25
|
+
writeFileSync(join(input.dir, `${input.role}.out.md`), text);
|
|
26
|
+
return { ok, text };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Every role ends its answer with a JSON block. An agent cut at its ceiling
|
|
30
|
+
* after writing one finished its work: the answer is kept, not counted as lost.
|
|
31
|
+
*/
|
|
32
|
+
function answeredBeforeCeiling(result) {
|
|
33
|
+
const value = result.atCeiling === true ? lastJson(result.stdout) : undefined;
|
|
34
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Three members read the same stop from different seats; an arbiter decides.
|
|
38
|
+
*
|
|
39
|
+
* The members run together and apart: none sees another's answer, so they
|
|
40
|
+
* cannot settle on the first idea. The arbiter sees all three and the code.
|
|
41
|
+
* A member that fails does not stop the others; fewer than two answers is no
|
|
42
|
+
* council. An arbiter whose answer is refused for its shape has it corrected by a small
|
|
43
|
+
* agent from its own text; one that fails is asked again as before.
|
|
44
|
+
*/
|
|
45
|
+
export async function deliberate(input) {
|
|
46
|
+
const addDirs = [...new Set([...input.brief.codeRoots, input.brief.ledgerRoot])];
|
|
47
|
+
const base = { config: input.config, exec: input.exec, dir: input.dir, cwd: input.cwd, addDirs };
|
|
48
|
+
const answers = await Promise.all(ANALYSTS.map(async ([role, prompt]) => ({
|
|
49
|
+
role,
|
|
50
|
+
...(await runAgent({ ...base, role, prompt: prompt(input.brief) })),
|
|
51
|
+
})));
|
|
52
|
+
const reports = {};
|
|
53
|
+
for (const answer of answers) {
|
|
54
|
+
if (answer.ok) {
|
|
55
|
+
reports[answer.role] = answer.text.slice(-REPORT_CHARS);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (Object.keys(reports).length < 2) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
reason: `only ${Object.keys(reports).length} of ${ANALYSTS.length} members answered: ${answers
|
|
62
|
+
.filter((a) => !a.ok)
|
|
63
|
+
.map((a) => `${a.role}: ${a.text.slice(0, 200)}`)
|
|
64
|
+
.join(" | ")}`,
|
|
65
|
+
reports,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const targets = input.config.targets.map((target) => target.name);
|
|
69
|
+
const prompt = arbiterPrompt(input.brief, reports);
|
|
70
|
+
let reason = "";
|
|
71
|
+
for (let round = 0; round < 2; round++) {
|
|
72
|
+
const arbiter = await runAgent({ ...base, role: "arbiter", prompt });
|
|
73
|
+
if (!arbiter.ok) {
|
|
74
|
+
reason = `the arbiter failed: ${arbiter.text.slice(0, 300)}`;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const parsed = parseDecision(arbiter.text, targets);
|
|
78
|
+
if (parsed.ok) {
|
|
79
|
+
return { ok: true, decision: parsed.decision, reports };
|
|
80
|
+
}
|
|
81
|
+
reason = `the arbiter's answer was refused: ${parsed.reason}`;
|
|
82
|
+
const corrected = await runAgent({
|
|
83
|
+
...base,
|
|
84
|
+
role: "reformatter",
|
|
85
|
+
prompt: formPrompt(arbiter.text, parsed.reason),
|
|
86
|
+
addDirs: [],
|
|
87
|
+
});
|
|
88
|
+
const again = corrected.ok ? parseDecision(corrected.text, targets) : undefined;
|
|
89
|
+
if (again?.ok) {
|
|
90
|
+
return { ok: true, decision: again.decision, reports };
|
|
91
|
+
}
|
|
92
|
+
reason = `the arbiter's answer was refused: ${again === undefined ? parsed.reason : again.reason}`;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
return { ok: false, reason, reports };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=council.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"council.js","sourceRoot":"","sources":["../../../src/operator/supervise/council.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const UNBLOCK_KINDS: readonly ["resume", "restart", "cancel", "start-worker", "restart-worker", "cleanup-disk"];
|
|
2
|
+
export type UnblockKind = (typeof UNBLOCK_KINDS)[number];
|
|
3
|
+
/** What puts the run back in motion, now or once the fixes have landed. */
|
|
4
|
+
export type Unblock = {
|
|
5
|
+
do: UnblockKind;
|
|
6
|
+
key?: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
/** A change to a repository the supervisor was given, so that this does not happen again. */
|
|
10
|
+
export type Fix = {
|
|
11
|
+
target: string;
|
|
12
|
+
title: string;
|
|
13
|
+
/** The result to reach and what proves it, inside the rules. Not the design: the fixer designs. */
|
|
14
|
+
instruction: string;
|
|
15
|
+
/** The rules and accepted decisions the change touches, and why it conforms to each. */
|
|
16
|
+
conformity: string;
|
|
17
|
+
/**
|
|
18
|
+
* Set when no change can reach the result without revisiting an accepted decision or rule: which one.
|
|
19
|
+
* Such a fix is not made; a person decides.
|
|
20
|
+
*/
|
|
21
|
+
revises?: string;
|
|
22
|
+
};
|
|
23
|
+
export type Decision = {
|
|
24
|
+
summary: string;
|
|
25
|
+
cause: string;
|
|
26
|
+
/** `file:line`, a log line, a command and what it printed. Nothing that was not seen. */
|
|
27
|
+
evidence: string[];
|
|
28
|
+
confidence: "high" | "medium" | "low";
|
|
29
|
+
/** The unblock needs the fixes first (the same stop would come straight back). */
|
|
30
|
+
unblockAfterFixes: boolean;
|
|
31
|
+
unblock: Unblock[];
|
|
32
|
+
fixes: Fix[];
|
|
33
|
+
/** Set when no one but a person can go on: what only they can decide. */
|
|
34
|
+
needsHuman?: string;
|
|
35
|
+
};
|
|
36
|
+
export type Parsed = {
|
|
37
|
+
ok: true;
|
|
38
|
+
decision: Decision;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
reason: string;
|
|
42
|
+
};
|
|
43
|
+
/** The last JSON object an agent printed: in a ```json fence, else the last balanced braces. */
|
|
44
|
+
export declare function lastJson(output: string): unknown;
|
|
45
|
+
export declare function parseDecision(output: string, targets: readonly string[]): Parsed;
|
|
46
|
+
//# sourceMappingURL=decision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../../../src/operator/supervise/decision.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,4FAOhB,CAAC;AACX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,2EAA2E;AAC3E,MAAM,MAAM,OAAO,GAAG;IAAE,EAAE,EAAE,WAAW,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,6FAA6F;AAC7F,MAAM,MAAM,GAAG,GAAG;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,mGAAmG;IACnG,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,kFAAkF;IAClF,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAItF,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAqBhD;AAUD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CA2GhF"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
export const UNBLOCK_KINDS = [
|
|
2
|
+
"resume",
|
|
3
|
+
"restart",
|
|
4
|
+
"cancel",
|
|
5
|
+
"start-worker",
|
|
6
|
+
"restart-worker",
|
|
7
|
+
"cleanup-disk",
|
|
8
|
+
];
|
|
9
|
+
const NEEDS_KEY = ["resume", "restart", "cancel"];
|
|
10
|
+
/** The last JSON object an agent printed: in a ```json fence, else the last balanced braces. */
|
|
11
|
+
export function lastJson(output) {
|
|
12
|
+
const fenced = [...output.matchAll(/```json\s*([\s\S]*?)```/g)].map((m) => m[1] ?? "");
|
|
13
|
+
for (const body of fenced.reverse()) {
|
|
14
|
+
const value = tryParse(body);
|
|
15
|
+
if (value !== undefined) {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
for (let end = output.lastIndexOf("}"); end >= 0; end = output.lastIndexOf("}", end - 1)) {
|
|
20
|
+
for (let start = output.lastIndexOf("{", end); start >= 0; start = output.lastIndexOf("{", start - 1)) {
|
|
21
|
+
const value = tryParse(output.slice(start, end + 1));
|
|
22
|
+
if (value !== undefined) {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function tryParse(body) {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(body);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function parseDecision(output, targets) {
|
|
38
|
+
const value = lastJson(output);
|
|
39
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
40
|
+
return { ok: false, reason: "no JSON object in the arbiter's answer" };
|
|
41
|
+
}
|
|
42
|
+
const o = value;
|
|
43
|
+
const problems = [];
|
|
44
|
+
const str = (name) => {
|
|
45
|
+
const v = o[name];
|
|
46
|
+
if (typeof v !== "string" || v.trim().length === 0) {
|
|
47
|
+
problems.push(`${name} must be a non-empty string`);
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
return v;
|
|
51
|
+
};
|
|
52
|
+
const summary = str("summary");
|
|
53
|
+
const cause = str("cause");
|
|
54
|
+
const evidence = Array.isArray(o.evidence) ? o.evidence.map(String) : [];
|
|
55
|
+
if (evidence.length === 0) {
|
|
56
|
+
problems.push("evidence must name what was seen");
|
|
57
|
+
}
|
|
58
|
+
const confidence = o.confidence;
|
|
59
|
+
if (confidence !== "high" && confidence !== "medium" && confidence !== "low") {
|
|
60
|
+
problems.push("confidence must be high, medium or low");
|
|
61
|
+
}
|
|
62
|
+
const unblock = [];
|
|
63
|
+
for (const raw of Array.isArray(o.unblock) ? o.unblock : []) {
|
|
64
|
+
const u = (raw ?? {});
|
|
65
|
+
const kind = UNBLOCK_KINDS.find((k) => k === u.do);
|
|
66
|
+
if (kind === undefined) {
|
|
67
|
+
problems.push(`unblock.do ${JSON.stringify(u.do)} is not one of ${UNBLOCK_KINDS.join(", ")}`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (NEEDS_KEY.includes(kind) && typeof u.key !== "string") {
|
|
71
|
+
problems.push(`unblock ${kind} needs a key`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
unblock.push({
|
|
75
|
+
do: kind,
|
|
76
|
+
...(typeof u.key === "string" ? { key: u.key } : {}),
|
|
77
|
+
reason: typeof u.reason === "string" ? u.reason : "",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const fixes = [];
|
|
81
|
+
for (const raw of Array.isArray(o.fixes) ? o.fixes : []) {
|
|
82
|
+
const f = (raw ?? {});
|
|
83
|
+
if (typeof f.target !== "string" || !targets.includes(f.target)) {
|
|
84
|
+
problems.push(`fix.target ${JSON.stringify(f.target)} is not one of ${targets.join(", ") || "(none configured)"}`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (typeof f.title !== "string" ||
|
|
88
|
+
typeof f.instruction !== "string" ||
|
|
89
|
+
f.instruction.length < 20) {
|
|
90
|
+
problems.push("a fix needs a title and an instruction a stranger could carry out");
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (typeof f.conformity !== "string" || f.conformity.trim().length < 20) {
|
|
94
|
+
problems.push("a fix needs its conformity: the rules and accepted decisions it touches, and why it conforms");
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
fixes.push({
|
|
98
|
+
target: f.target,
|
|
99
|
+
title: f.title,
|
|
100
|
+
instruction: f.instruction,
|
|
101
|
+
conformity: f.conformity,
|
|
102
|
+
...(typeof f.revises === "string" && f.revises.trim().length > 0
|
|
103
|
+
? { revises: f.revises }
|
|
104
|
+
: {}),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const asked = typeof o.needsHuman === "string" && o.needsHuman.length > 0 ? o.needsHuman : undefined;
|
|
108
|
+
if (asked !== undefined && unblock.length > 0) {
|
|
109
|
+
problems.push("needsHuman and unblock contradict: a stop for a person is not resumed");
|
|
110
|
+
}
|
|
111
|
+
// A change that would revisit an accepted decision is a product choice, not the supervisor's.
|
|
112
|
+
const revising = fixes.filter((fix) => fix.revises !== undefined);
|
|
113
|
+
const needsHuman = asked ??
|
|
114
|
+
(revising.length === 0
|
|
115
|
+
? undefined
|
|
116
|
+
: `A person must decide: ${revising.map((fix) => `"${fix.title}" would revise ${fix.revises}`).join("; ")}.`);
|
|
117
|
+
if (o.unblockAfterFixes === true && unblock.length === 0) {
|
|
118
|
+
problems.push("unblockAfterFixes is true but there is nothing to unblock");
|
|
119
|
+
}
|
|
120
|
+
if (problems.length > 0) {
|
|
121
|
+
return { ok: false, reason: problems.join("; ") };
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
ok: true,
|
|
125
|
+
decision: {
|
|
126
|
+
summary,
|
|
127
|
+
cause,
|
|
128
|
+
evidence,
|
|
129
|
+
confidence: confidence,
|
|
130
|
+
unblockAfterFixes: o.unblockAfterFixes === true,
|
|
131
|
+
unblock,
|
|
132
|
+
fixes,
|
|
133
|
+
...(needsHuman === undefined ? {} : { needsHuman }),
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../../../src/operator/supervise/decision.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type ExecResult = {
|
|
2
|
+
/** Null when the command never ran or was cut at its ceiling. */
|
|
3
|
+
code: number | null;
|
|
4
|
+
stdout: string;
|
|
5
|
+
stderr: string;
|
|
6
|
+
/** Milliseconds the clock ran while the supervisor did not (machine asleep, paused). */
|
|
7
|
+
suspendedMs?: number;
|
|
8
|
+
/** The ceiling ended it; what it wrote before is in `stdout`. */
|
|
9
|
+
atCeiling?: boolean;
|
|
10
|
+
/** Why it did not run to its end, when it did not. */
|
|
11
|
+
error?: string;
|
|
12
|
+
};
|
|
13
|
+
export type Exec = (cmd: string[], options: {
|
|
14
|
+
cwd?: string;
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
}) => Promise<ExecResult>;
|
|
17
|
+
/** The supervisor's one way to start anything: a command, a ceiling, a result. Never throws. */
|
|
18
|
+
export declare const exec: Exec;
|
|
19
|
+
/**
|
|
20
|
+
* Replace `{name}` in each word of a command. A name nobody gave stays as
|
|
21
|
+
* written. A word that is only `{name}` and names a list becomes that list's
|
|
22
|
+
* words, so `{addDirArgs}` can stand for any number of `--add-dir X` pairs.
|
|
23
|
+
*/
|
|
24
|
+
export declare function fill(cmd: string[], vars: Record<string, string>, lists?: Record<string, string[]>): string[];
|
|
25
|
+
export declare function succeeded(result: ExecResult): boolean;
|
|
26
|
+
/** What a failed command said, cut to what a reader needs. */
|
|
27
|
+
export declare function tail(result: ExecResult, chars?: number): string;
|
|
28
|
+
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/operator/supervise/exec.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG;IACvB,iEAAiE;IACjE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG,CACjB,GAAG,EAAE,MAAM,EAAE,EACb,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KACzC,OAAO,CAAC,UAAU,CAAC,CAAC;AAEzB,gGAAgG;AAChG,eAAO,MAAM,IAAI,EAAE,IAmBlB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,IAAI,CAClB,GAAG,EAAE,MAAM,EAAE,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAM,GACnC,MAAM,EAAE,CAQV;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAErD;AAED,8DAA8D;AAC9D,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,SAAO,GAAG,MAAM,CAK7D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { runSlot } from "../../loop/run-slot.js";
|
|
2
|
+
/** The supervisor's one way to start anything: a command, a ceiling, a result. Never throws. */
|
|
3
|
+
export const exec = async (cmd, options) => {
|
|
4
|
+
const [command, ...args] = cmd;
|
|
5
|
+
if (command === undefined) {
|
|
6
|
+
return { code: null, stdout: "", stderr: "", error: "empty command" };
|
|
7
|
+
}
|
|
8
|
+
const run = await runSlot({
|
|
9
|
+
command,
|
|
10
|
+
args,
|
|
11
|
+
...(options.cwd === undefined ? {} : { cwd: options.cwd }),
|
|
12
|
+
timeoutMs: options.timeoutMs,
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
code: run.status,
|
|
16
|
+
stdout: run.stdout,
|
|
17
|
+
stderr: run.stderr,
|
|
18
|
+
...(run.atCeiling ? { atCeiling: true } : {}),
|
|
19
|
+
...(run.suspendedMs > 0 ? { suspendedMs: run.suspendedMs } : {}),
|
|
20
|
+
...(run.error === undefined ? {} : { error: run.error.message }),
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Replace `{name}` in each word of a command. A name nobody gave stays as
|
|
25
|
+
* written. A word that is only `{name}` and names a list becomes that list's
|
|
26
|
+
* words, so `{addDirArgs}` can stand for any number of `--add-dir X` pairs.
|
|
27
|
+
*/
|
|
28
|
+
export function fill(cmd, vars, lists = {}) {
|
|
29
|
+
return cmd.flatMap((word) => {
|
|
30
|
+
const whole = /^\{(\w+)\}$/.exec(word)?.[1];
|
|
31
|
+
if (whole !== undefined && lists[whole] !== undefined) {
|
|
32
|
+
return lists[whole];
|
|
33
|
+
}
|
|
34
|
+
return [word.replace(/\{(\w+)\}/g, (all, name) => vars[name] ?? all)];
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function succeeded(result) {
|
|
38
|
+
return result.code === 0 && result.error === undefined;
|
|
39
|
+
}
|
|
40
|
+
/** What a failed command said, cut to what a reader needs. */
|
|
41
|
+
export function tail(result, chars = 4000) {
|
|
42
|
+
const text = [result.error, result.stderr, result.stdout]
|
|
43
|
+
.filter((part) => part !== undefined && part.length > 0)
|
|
44
|
+
.join("\n");
|
|
45
|
+
return text.length > chars ? `…${text.slice(-chars)}` : text;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/operator/supervise/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAoBjD,gGAAgG;AAChG,MAAM,CAAC,MAAM,IAAI,GAAS,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;IAC/C,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;IAC/B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;IACxE,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;QACxB,OAAO;QACP,IAAI;QACJ,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1D,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,MAAM;QAChB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;KACjE,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAClB,GAAa,EACb,IAA4B,EAC5B,QAAkC,EAAE;IAEpC,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1B,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;YACtD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAkB;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC;AACzD,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,IAAI,CAAC,MAAkB,EAAE,KAAK,GAAG,IAAI;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;SACtD,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACvE,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** What the supervisor did about one subject, so that it does not do it forever. */
|
|
2
|
+
export type Entry = {
|
|
3
|
+
attempts: number;
|
|
4
|
+
/** The last thing seen, as `observe` fingerprints it. */
|
|
5
|
+
fingerprint: string;
|
|
6
|
+
lastAt: number;
|
|
7
|
+
/** Handed to a person: nothing more is tried until the subject changes or ends. */
|
|
8
|
+
human: boolean;
|
|
9
|
+
/** One line each: what was decided and how it went. Fed back to the next council. */
|
|
10
|
+
history: string[];
|
|
11
|
+
};
|
|
12
|
+
export type Memory = {
|
|
13
|
+
entries: Record<string, Entry>;
|
|
14
|
+
};
|
|
15
|
+
export declare function loadMemory(dir: string): Memory;
|
|
16
|
+
export declare function saveMemory(dir: string, memory: Memory): void;
|
|
17
|
+
/** Append-only film of what the supervisor saw and did. Not truth: the ledger is. */
|
|
18
|
+
export declare function note(dir: string, line: Record<string, unknown>, now?: () => Date): void;
|
|
19
|
+
/**
|
|
20
|
+
* Whether this finding is the supervisor's to handle now.
|
|
21
|
+
*
|
|
22
|
+
* Not while a person holds it. Not while what it did last time may still be
|
|
23
|
+
* taking effect (the same thing seen again inside the cooldown). A different
|
|
24
|
+
* fingerprint is a different problem and starts again at the cost already paid.
|
|
25
|
+
*/
|
|
26
|
+
export declare function due(entry: Entry | undefined, fingerprint: string, now: number, cooldownMs: number): boolean;
|
|
27
|
+
export declare function spent(entry: Entry | undefined, maxAttempts: number): boolean;
|
|
28
|
+
/** Take one attempt at `subject`. */
|
|
29
|
+
export declare function attempt(memory: Memory, subject: string, fingerprint: string, now: number): Entry;
|
|
30
|
+
export declare function remember(entry: Entry, line: string): void;
|
|
31
|
+
/** Forget what was kept of a subject that reached an end. */
|
|
32
|
+
export declare function forgetKeys(memory: Memory, keys: string[]): void;
|
|
33
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/operator/supervise/memory.ts"],"names":[],"mappings":"AAGA,oFAAoF;AACpF,MAAM,MAAM,KAAK,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,KAAK,EAAE,OAAO,CAAC;IACf,qFAAqF;IACrF,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;CAAE,CAAC;AAIxD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAK5D;AAED,qFAAqF;AACrF,wBAAgB,IAAI,CAClB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,GAAE,MAAM,IAAuB,GACjC,IAAI,CAMN;AAED;;;;;;GAMG;AACH,wBAAgB,GAAG,CACjB,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,OAAO,CAQT;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED,qCAAqC;AACrC,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAchG;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAKzD;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAM/D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const FILE = "memory.json";
|
|
4
|
+
export function loadMemory(dir) {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = JSON.parse(readFileSync(join(dir, FILE), "utf8"));
|
|
7
|
+
return { entries: parsed.entries ?? {} };
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return { entries: {} };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function saveMemory(dir, memory) {
|
|
14
|
+
mkdirSync(dir, { recursive: true });
|
|
15
|
+
const tmp = join(dir, `${FILE}.tmp`);
|
|
16
|
+
writeFileSync(tmp, `${JSON.stringify(memory, null, 2)}\n`);
|
|
17
|
+
renameSync(tmp, join(dir, FILE));
|
|
18
|
+
}
|
|
19
|
+
/** Append-only film of what the supervisor saw and did. Not truth: the ledger is. */
|
|
20
|
+
export function note(dir, line, now = () => new Date()) {
|
|
21
|
+
mkdirSync(dir, { recursive: true });
|
|
22
|
+
appendFileSync(join(dir, "events.jsonl"), `${JSON.stringify({ ...line, at: now().toISOString() })}\n`);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Whether this finding is the supervisor's to handle now.
|
|
26
|
+
*
|
|
27
|
+
* Not while a person holds it. Not while what it did last time may still be
|
|
28
|
+
* taking effect (the same thing seen again inside the cooldown). A different
|
|
29
|
+
* fingerprint is a different problem and starts again at the cost already paid.
|
|
30
|
+
*/
|
|
31
|
+
export function due(entry, fingerprint, now, cooldownMs) {
|
|
32
|
+
if (entry === undefined) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (entry.human) {
|
|
36
|
+
return entry.fingerprint !== fingerprint;
|
|
37
|
+
}
|
|
38
|
+
return entry.fingerprint !== fingerprint || now - entry.lastAt >= cooldownMs;
|
|
39
|
+
}
|
|
40
|
+
export function spent(entry, maxAttempts) {
|
|
41
|
+
return entry !== undefined && entry.attempts >= maxAttempts;
|
|
42
|
+
}
|
|
43
|
+
/** Take one attempt at `subject`. */
|
|
44
|
+
export function attempt(memory, subject, fingerprint, now) {
|
|
45
|
+
const entry = memory.entries[subject] ?? {
|
|
46
|
+
attempts: 0,
|
|
47
|
+
fingerprint,
|
|
48
|
+
lastAt: now,
|
|
49
|
+
human: false,
|
|
50
|
+
history: [],
|
|
51
|
+
};
|
|
52
|
+
entry.attempts += 1;
|
|
53
|
+
entry.fingerprint = fingerprint;
|
|
54
|
+
entry.lastAt = now;
|
|
55
|
+
entry.human = false;
|
|
56
|
+
memory.entries[subject] = entry;
|
|
57
|
+
return entry;
|
|
58
|
+
}
|
|
59
|
+
export function remember(entry, line) {
|
|
60
|
+
entry.history.push(line);
|
|
61
|
+
if (entry.history.length > 8) {
|
|
62
|
+
entry.history.splice(0, entry.history.length - 8);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Forget what was kept of a subject that reached an end. */
|
|
66
|
+
export function forgetKeys(memory, keys) {
|
|
67
|
+
for (const subject of Object.keys(memory.entries)) {
|
|
68
|
+
if (keys.some((key) => subject.endsWith(`:${key}`))) {
|
|
69
|
+
delete memory.entries[subject];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/operator/supervise/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type Item = {
|
|
2
|
+
key: string;
|
|
3
|
+
scope: "ticket" | "feature";
|
|
4
|
+
state: string;
|
|
5
|
+
escalation?: {
|
|
6
|
+
report?: string;
|
|
7
|
+
refusedBy?: string;
|
|
8
|
+
at?: number;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
/** What the supervisor can see of a run without asking anyone. */
|
|
12
|
+
export type Snapshot = {
|
|
13
|
+
now: number;
|
|
14
|
+
items: Item[];
|
|
15
|
+
/** The process that holds the ledger, when it is alive. */
|
|
16
|
+
workerPid?: number;
|
|
17
|
+
/** When the journal last grew. */
|
|
18
|
+
journalAt?: number;
|
|
19
|
+
freeBytes?: number;
|
|
20
|
+
/** The supervisor is able to start a worker, so a missing one is its to fix. */
|
|
21
|
+
canStartWorker: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type Thresholds = {
|
|
24
|
+
stallAfterMs: number;
|
|
25
|
+
diskMinBytes: number;
|
|
26
|
+
settleMs: number;
|
|
27
|
+
};
|
|
28
|
+
export type Finding = {
|
|
29
|
+
kind: "escalated" | "stalled" | "worker-down" | "disk-low";
|
|
30
|
+
/** What the memory is keyed by: one per thing that can go wrong in one place. */
|
|
31
|
+
subject: string;
|
|
32
|
+
/** Changes when the thing that went wrong changes. */
|
|
33
|
+
fingerprint: string;
|
|
34
|
+
key?: string;
|
|
35
|
+
scope?: "ticket" | "feature";
|
|
36
|
+
detail: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* What is wrong, from what can be seen. Pure: no ledger, no clock, no disk.
|
|
40
|
+
*
|
|
41
|
+
* Judging is not done here. A finding says that something needs looking at,
|
|
42
|
+
* and carries enough to tell it from the same thing seen again.
|
|
43
|
+
*/
|
|
44
|
+
export declare function observe(snapshot: Snapshot, limits: Thresholds): Finding[];
|
|
45
|
+
/** Keys that reached an end: whatever the supervisor remembered of them is spent. */
|
|
46
|
+
export declare function finished(items: Item[]): string[];
|
|
47
|
+
//# sourceMappingURL=observe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/operator/supervise/observe.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,IAAI,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1F,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;IAC3D,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,EAAE,CAoDzE;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAEhD"}
|