@llblab/pi-actors 0.23.0 → 0.24.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/AGENTS.md +125 -60
- package/BACKLOG.md +133 -176
- package/CHANGELOG.md +27 -0
- package/README.md +13 -0
- package/dist/fixtures/protocol/actor-message-branch.json +13 -0
- package/dist/fixtures/protocol/artifact-manifest.json +9 -0
- package/dist/fixtures/protocol/mailbox-contract.json +15 -0
- package/dist/fixtures/protocol/recipe-summary.json +16 -0
- package/dist/fixtures/protocol/room-message.json +11 -0
- package/dist/fixtures/protocol/room-roster.json +11 -0
- package/dist/fixtures/protocol/run-inbox-message.json +9 -0
- package/dist/fixtures/protocol/run-outbox-event.json +9 -0
- package/dist/fixtures/protocol/run-state.json +10 -0
- package/dist/index.js +3 -2
- package/dist/lib/actor-inspector-tui.js +5 -32
- package/dist/lib/actor-rooms.d.ts +8 -0
- package/dist/lib/actor-rooms.js +64 -20
- package/dist/lib/actor-worker.d.ts +13 -0
- package/dist/lib/actor-worker.js +86 -0
- package/dist/lib/async-runner.d.ts +5 -0
- package/dist/lib/async-runner.js +134 -0
- package/dist/lib/async-runs.js +9 -28
- package/dist/lib/conformance.d.ts +12 -0
- package/dist/lib/conformance.js +28 -0
- package/dist/lib/coordinator.d.ts +5 -0
- package/dist/lib/coordinator.js +574 -0
- package/dist/lib/locker.d.ts +5 -0
- package/dist/lib/locker.js +310 -0
- package/dist/lib/mailbox-loop.d.ts +41 -0
- package/dist/lib/mailbox-loop.js +62 -0
- package/dist/lib/observability.d.ts +2 -2
- package/dist/lib/observability.js +51 -53
- package/dist/lib/prompts.d.ts +1 -1
- package/dist/lib/prompts.js +1 -1
- package/dist/lib/recipe-references.js +25 -2
- package/dist/lib/recipe-utils.d.ts +5 -0
- package/dist/lib/recipe-utils.js +385 -0
- package/dist/lib/runtime-notifier.js +3 -7
- package/dist/lib/state-readers.d.ts +21 -0
- package/dist/lib/state-readers.js +74 -0
- package/dist/lib/tools.js +1 -1
- package/dist/lib/validate-recipe.d.ts +6 -0
- package/dist/lib/validate-recipe.js +104 -0
- package/dist/recipes/actor-worker.json +35 -0
- package/dist/recipes/coordinator-locker.json +45 -0
- package/dist/recipes/lens-swarm.json +66 -0
- package/dist/recipes/locker.json +45 -0
- package/dist/recipes/music-player.json +38 -0
- package/dist/recipes/pipeline-architect-coordinator.json +95 -0
- package/dist/recipes/pipeline-artifact-bundle.json +100 -0
- package/dist/recipes/pipeline-artifact-report.json +58 -0
- package/dist/recipes/pipeline-artifact-write.json +72 -0
- package/dist/recipes/pipeline-async-run-ops.json +70 -0
- package/dist/recipes/pipeline-checkpoint-continuation.json +67 -0
- package/dist/recipes/pipeline-development-tasking.json +81 -0
- package/dist/recipes/pipeline-docs-maintenance.json +80 -0
- package/dist/recipes/pipeline-media-library.json +59 -0
- package/dist/recipes/pipeline-quorum-review.json +79 -0
- package/dist/recipes/pipeline-release-readiness.json +110 -0
- package/dist/recipes/pipeline-release-summary.json +88 -0
- package/dist/recipes/pipeline-repo-health.json +89 -0
- package/dist/recipes/pipeline-research-synthesis.json +94 -0
- package/dist/recipes/pipeline-review-readiness.json +54 -0
- package/dist/recipes/pipeline-room-swarm.json +50 -0
- package/dist/recipes/subagent-artifact.json +32 -0
- package/dist/recipes/subagent-checkpoint.json +33 -0
- package/dist/recipes/subagent-conflict-report.json +32 -0
- package/dist/recipes/subagent-contradiction-map.json +33 -0
- package/dist/recipes/subagent-critic.json +35 -0
- package/dist/recipes/subagent-evidence-map.json +33 -0
- package/dist/recipes/subagent-followup.json +33 -0
- package/dist/recipes/subagent-judge.json +33 -0
- package/dist/recipes/subagent-merge.json +33 -0
- package/dist/recipes/subagent-message.json +34 -0
- package/dist/recipes/subagent-normalize.json +31 -0
- package/dist/recipes/subagent-plan.json +33 -0
- package/dist/recipes/subagent-prompt.json +28 -0
- package/dist/recipes/subagent-quorum.json +43 -0
- package/dist/recipes/subagent-review-coordinator.json +114 -0
- package/dist/recipes/subagent-review.json +37 -0
- package/dist/recipes/subagent-task-card.json +35 -0
- package/dist/recipes/subagent-tools.json +27 -0
- package/dist/recipes/subagent-verify.json +34 -0
- package/dist/recipes/subagents-prompts.json +51 -0
- package/dist/recipes/utility-actor-message.json +23 -0
- package/dist/recipes/utility-artifact-manifest.json +16 -0
- package/dist/recipes/utility-artifact-write.json +16 -0
- package/dist/recipes/utility-changelog-head.json +11 -0
- package/dist/recipes/utility-changelog-section.json +13 -0
- package/dist/recipes/utility-coordinator-lock-snapshot.json +13 -0
- package/dist/recipes/utility-git-log.json +11 -0
- package/dist/recipes/utility-git-status.json +9 -0
- package/dist/recipes/utility-jsonl-tail.json +10 -0
- package/dist/recipes/utility-markdown-index.json +14 -0
- package/dist/recipes/utility-package-summary.json +11 -0
- package/dist/recipes/utility-playlist-build.json +17 -0
- package/dist/recipes/utility-playlist-scan.json +11 -0
- package/dist/recipes/utility-run-ops-snapshot.json +17 -0
- package/dist/recipes/utility-run-state-files.json +13 -0
- package/dist/recipes/utility-run-summary.json +11 -0
- package/dist/recipes/utility-skill-summary.json +13 -0
- package/dist/recipes/utility-validate-recipe.json +13 -0
- package/dist/recipes/utility-validation-wrapper.json +13 -0
- package/dist/scripts/actor-worker.mjs +31 -0
- package/dist/scripts/async-runner.mjs +31 -0
- package/dist/scripts/build-dist.mjs +33 -0
- package/dist/scripts/conformance.mjs +33 -0
- package/dist/scripts/coordinator.mjs +31 -0
- package/dist/scripts/locker.mjs +33 -0
- package/dist/scripts/music-player.mjs +964 -0
- package/dist/scripts/recipe-utils.mjs +31 -0
- package/dist/scripts/validate-recipe.mjs +34 -0
- package/dist/skills/actors/SKILL.md +377 -0
- package/dist/skills/swarm/SKILL.md +467 -0
- package/dist/skills/swarm/references/development-swarm.md +596 -0
- package/docs/actor-messages.md +2 -2
- package/docs/async-runs.md +11 -0
- package/docs/template-recipes.md +1 -1
- package/fixtures/protocol/actor-message-branch.json +13 -0
- package/fixtures/protocol/artifact-manifest.json +9 -0
- package/fixtures/protocol/mailbox-contract.json +15 -0
- package/fixtures/protocol/recipe-summary.json +16 -0
- package/fixtures/protocol/room-message.json +11 -0
- package/fixtures/protocol/room-roster.json +11 -0
- package/fixtures/protocol/run-inbox-message.json +9 -0
- package/fixtures/protocol/run-outbox-event.json +9 -0
- package/fixtures/protocol/run-state.json +10 -0
- package/index.ts +3 -0
- package/lib/actor-inspector-tui.ts +11 -34
- package/lib/actor-rooms.ts +88 -18
- package/lib/actor-worker.ts +118 -0
- package/lib/async-runner.ts +173 -0
- package/lib/async-runs.ts +12 -22
- package/lib/conformance.ts +46 -0
- package/lib/coordinator.ts +664 -0
- package/lib/locker.ts +340 -0
- package/lib/mailbox-loop.ts +148 -0
- package/lib/observability.ts +24 -19
- package/lib/prompts.ts +1 -1
- package/lib/recipe-references.ts +37 -2
- package/lib/recipe-utils.ts +486 -0
- package/lib/runtime-notifier.ts +4 -6
- package/lib/state-readers.ts +93 -0
- package/lib/tools.ts +1 -1
- package/lib/validate-recipe.ts +110 -0
- package/package.json +10 -2
- package/recipes/actor-worker.json +35 -0
- package/recipes/pipeline-quorum-review.json +12 -7
- package/scripts/actor-worker.mjs +31 -0
- package/scripts/async-runner.mjs +11 -201
- package/scripts/build-dist.mjs +33 -0
- package/scripts/conformance.mjs +21 -35
- package/scripts/coordinator.mjs +15 -625
- package/scripts/locker.mjs +20 -332
- package/scripts/recipe-utils.mjs +17 -477
- package/scripts/validate-recipe.mjs +18 -121
- package/skills/actors/SKILL.md +8 -3
- package/skills/swarm/SKILL.md +3 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detached async-runner entrypoint logic.
|
|
3
|
+
* Zones: async run process, command-template execution telemetry
|
|
4
|
+
*/
|
|
5
|
+
import { appendFileSync, readFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { appendRecipeContextToPiArgs } from "./actor-recipe-context.js";
|
|
8
|
+
import { execCommandTemplate } from "./command-templates.js";
|
|
9
|
+
import { executeRegisteredTool } from "./execution.js";
|
|
10
|
+
import { writeJsonAtomic } from "./file-state.js";
|
|
11
|
+
function quoteCommandDetailPart(value) {
|
|
12
|
+
if (value === "")
|
|
13
|
+
return "''";
|
|
14
|
+
if (/^[A-Za-z0-9_/:=.,@%+\-]+$/.test(value))
|
|
15
|
+
return value;
|
|
16
|
+
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
17
|
+
}
|
|
18
|
+
function formatCommandDetail(command, args) {
|
|
19
|
+
return [command, ...args].map(quoteCommandDetailPart).join(" ");
|
|
20
|
+
}
|
|
21
|
+
function summarizeCommandDetail(commandDetail) {
|
|
22
|
+
return commandDetail.length > 160
|
|
23
|
+
? `${commandDetail.slice(0, 157)}...`
|
|
24
|
+
: commandDetail;
|
|
25
|
+
}
|
|
26
|
+
export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
27
|
+
if (!stateDir)
|
|
28
|
+
throw new Error("missing state dir");
|
|
29
|
+
const runPath = join(stateDir, "run.json");
|
|
30
|
+
const progressPath = join(stateDir, "progress.json");
|
|
31
|
+
const resultPath = join(stateDir, "result.json");
|
|
32
|
+
const eventsPath = join(stateDir, "events.jsonl");
|
|
33
|
+
const outboxPath = join(stateDir, "outbox.jsonl");
|
|
34
|
+
const stdoutPath = join(stateDir, "stdout.log");
|
|
35
|
+
const stderrPath = join(stateDir, "stderr.log");
|
|
36
|
+
const meta = JSON.parse(readFileSync(runPath, "utf8"));
|
|
37
|
+
function event(name, data = {}) {
|
|
38
|
+
appendFileSync(eventsPath, `${JSON.stringify({ event: name, ts: new Date().toISOString(), ...data })}\n`);
|
|
39
|
+
}
|
|
40
|
+
function outbox(name, summary, data = {}, delivery = "log", level = "info") {
|
|
41
|
+
appendFileSync(outboxPath, `${JSON.stringify({ body: data, data, delivery, event: name, from: `run:${meta.run}`, level, summary, to: "coordinator", ts: new Date().toISOString(), type: name })}\n`);
|
|
42
|
+
}
|
|
43
|
+
function progress(phase, extra = {}) {
|
|
44
|
+
writeJsonAtomic(progressPath, {
|
|
45
|
+
phase,
|
|
46
|
+
updatedAt: new Date().toISOString(),
|
|
47
|
+
...extra,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
let activeSubagents = 0;
|
|
51
|
+
let completedSubagents = 0;
|
|
52
|
+
const subagentFailures = [];
|
|
53
|
+
function getCommandDoneDelivery(result) {
|
|
54
|
+
return result.code !== 0 || activeSubagents > 0 ? "followup" : "log";
|
|
55
|
+
}
|
|
56
|
+
function progressRunning() {
|
|
57
|
+
progress("running", {
|
|
58
|
+
activeSubagents,
|
|
59
|
+
completed: completedSubagents,
|
|
60
|
+
failures: subagentFailures,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async function observedExec(command, args, options) {
|
|
64
|
+
const commandDetail = formatCommandDetail(command, args);
|
|
65
|
+
const execArgs = appendRecipeContextToPiArgs(command, args, meta.recipe_context_records, options?.actorRecipeContext);
|
|
66
|
+
activeSubagents += 1;
|
|
67
|
+
event("command.start", { activeSubagents, command: commandDetail });
|
|
68
|
+
progressRunning();
|
|
69
|
+
const result = await execCommandTemplate(command, execArgs, options);
|
|
70
|
+
activeSubagents = Math.max(0, activeSubagents - 1);
|
|
71
|
+
completedSubagents += 1;
|
|
72
|
+
if (result.code !== 0) {
|
|
73
|
+
subagentFailures.push({
|
|
74
|
+
code: result.code,
|
|
75
|
+
command: commandDetail,
|
|
76
|
+
killed: result.killed,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
event("command.done", {
|
|
80
|
+
activeSubagents,
|
|
81
|
+
code: result.code,
|
|
82
|
+
command: commandDetail,
|
|
83
|
+
killed: result.killed,
|
|
84
|
+
});
|
|
85
|
+
outbox("command.done", `Command ${summarizeCommandDetail(commandDetail)} completed with code ${result.code}`, {
|
|
86
|
+
activeSubagents,
|
|
87
|
+
...(meta.artifacts ? { artifacts: meta.artifacts } : {}),
|
|
88
|
+
run_files: [stdoutPath, stderrPath, resultPath, eventsPath, outboxPath],
|
|
89
|
+
code: result.code,
|
|
90
|
+
command: commandDetail,
|
|
91
|
+
killed: result.killed,
|
|
92
|
+
}, getCommandDoneDelivery(result), result.code === 0 ? "info" : "error");
|
|
93
|
+
progressRunning();
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
event("run.runner.start", { pid: process.pid });
|
|
98
|
+
progressRunning();
|
|
99
|
+
const result = await executeRegisteredTool({
|
|
100
|
+
name: "run_actor",
|
|
101
|
+
description: "Detached command-template run actor",
|
|
102
|
+
template: meta.template,
|
|
103
|
+
args: [],
|
|
104
|
+
defaults: {},
|
|
105
|
+
}, meta.values || {}, observedExec, meta.cwd);
|
|
106
|
+
const text = result.content?.[0]?.text || "";
|
|
107
|
+
appendFileSync(stdoutPath, text);
|
|
108
|
+
writeJsonAtomic(resultPath, {
|
|
109
|
+
code: result.details.code,
|
|
110
|
+
command: result.details.command,
|
|
111
|
+
killed: result.details.killed,
|
|
112
|
+
truncated: result.details.truncated,
|
|
113
|
+
completedAt: new Date().toISOString(),
|
|
114
|
+
});
|
|
115
|
+
progress("done", {
|
|
116
|
+
completed: 1,
|
|
117
|
+
failures: result.details.nonCriticalFailures || [],
|
|
118
|
+
});
|
|
119
|
+
event("run.done", { code: result.details.code });
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
123
|
+
appendFileSync(stderrPath, `${message}\n`);
|
|
124
|
+
writeJsonAtomic(resultPath, {
|
|
125
|
+
code: 1,
|
|
126
|
+
error: message,
|
|
127
|
+
killed: false,
|
|
128
|
+
completedAt: new Date().toISOString(),
|
|
129
|
+
});
|
|
130
|
+
progress("failed", { completed: 0, failures: [{ message }] });
|
|
131
|
+
event("run.failed", { error: message });
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
package/dist/lib/async-runs.js
CHANGED
|
@@ -12,6 +12,7 @@ import { basename, dirname, extname, join, resolve } from "node:path";
|
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { substituteCommandTemplateToken } from "./command-templates.js";
|
|
14
14
|
import { writeJsonAtomic } from "./file-state.js";
|
|
15
|
+
import { readJsonFileResilient, readJsonlFileResilient } from "./state-readers.js";
|
|
15
16
|
import * as Paths from "./paths.js";
|
|
16
17
|
import * as RecipeReferences from "./recipe-references.js";
|
|
17
18
|
import * as RecipeUsage from "./recipe-usage.js";
|
|
@@ -189,12 +190,7 @@ function resolveStartParams(params) {
|
|
|
189
190
|
};
|
|
190
191
|
}
|
|
191
192
|
function readJson(path) {
|
|
192
|
-
|
|
193
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
194
|
-
}
|
|
195
|
-
catch {
|
|
196
|
-
return undefined;
|
|
197
|
-
}
|
|
193
|
+
return readJsonFileResilient(path, undefined).value;
|
|
198
194
|
}
|
|
199
195
|
function isAlive(pid) {
|
|
200
196
|
try {
|
|
@@ -232,20 +228,12 @@ function tailLines(path, lines) {
|
|
|
232
228
|
return content ? content.split("\n") : [];
|
|
233
229
|
}
|
|
234
230
|
function getInterruptedRunStatus(stateDir) {
|
|
235
|
-
const events =
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (event.event === "run.kill")
|
|
242
|
-
return "killed";
|
|
243
|
-
if (event.event === "run.cancel")
|
|
244
|
-
return "cancelled";
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
// Ignore malformed event lines.
|
|
248
|
-
}
|
|
231
|
+
const events = readJsonlFileResilient(join(stateDir, "events.jsonl")).records.slice(-200);
|
|
232
|
+
for (const event of events.reverse()) {
|
|
233
|
+
if (event.event === "run.kill")
|
|
234
|
+
return "killed";
|
|
235
|
+
if (event.event === "run.cancel")
|
|
236
|
+
return "cancelled";
|
|
249
237
|
}
|
|
250
238
|
return undefined;
|
|
251
239
|
}
|
|
@@ -655,14 +643,7 @@ function parseRunInboxLine(line) {
|
|
|
655
643
|
}
|
|
656
644
|
}
|
|
657
645
|
function readRunInboxMessagesFromStateDir(stateDir) {
|
|
658
|
-
|
|
659
|
-
if (!existsSync(file))
|
|
660
|
-
return [];
|
|
661
|
-
return readFileSync(file, "utf8")
|
|
662
|
-
.split("\n")
|
|
663
|
-
.filter((line) => line.trim())
|
|
664
|
-
.map(parseRunInboxLine)
|
|
665
|
-
.filter((message) => Boolean(message));
|
|
646
|
+
return readJsonlFileResilient(runInboxFile(stateDir)).records;
|
|
666
647
|
}
|
|
667
648
|
function writeRunInboxMessages(stateDir, messages) {
|
|
668
649
|
writeFileSync(runInboxFile(stateDir), messages.length
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal conformance runner logic.
|
|
3
|
+
* Zones: CI/release validation, protocol regression suite selection
|
|
4
|
+
*/
|
|
5
|
+
export declare const conformanceSuites: string[];
|
|
6
|
+
export interface ConformanceReport {
|
|
7
|
+
code: number;
|
|
8
|
+
output: string;
|
|
9
|
+
summary: string;
|
|
10
|
+
suites: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function runConformance(cwd?: URL): ConformanceReport;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal conformance runner logic.
|
|
3
|
+
* Zones: CI/release validation, protocol regression suite selection
|
|
4
|
+
*/
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
export const conformanceSuites = [
|
|
7
|
+
"tests/protocol-examples.test.ts",
|
|
8
|
+
"tests/recipe-discovery.test.ts",
|
|
9
|
+
"tests/registry.test.ts",
|
|
10
|
+
"tests/runtime-registry.test.ts",
|
|
11
|
+
"tests/async-runs.test.ts",
|
|
12
|
+
"tests/actor-rooms.test.ts",
|
|
13
|
+
"tests/tools.test.ts",
|
|
14
|
+
];
|
|
15
|
+
export function runConformance(cwd = new URL("..", import.meta.url)) {
|
|
16
|
+
const result = spawnSync(process.execPath, ["--experimental-strip-types", "--test", ...conformanceSuites], { cwd, encoding: "utf8", stdio: "pipe" });
|
|
17
|
+
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
18
|
+
const summary = output
|
|
19
|
+
.split("\n")
|
|
20
|
+
.filter((line) => /^ℹ (tests|pass|fail|cancelled|skipped|todo|duration_ms) /.test(line))
|
|
21
|
+
.join("\n");
|
|
22
|
+
return {
|
|
23
|
+
code: result.status ?? 1,
|
|
24
|
+
output,
|
|
25
|
+
summary,
|
|
26
|
+
suites: conformanceSuites.length,
|
|
27
|
+
};
|
|
28
|
+
}
|