@llblab/pi-actors 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +72 -0
- package/BACKLOG.md +38 -0
- package/CHANGELOG.md +179 -0
- package/README.md +338 -0
- package/docs/README.md +21 -0
- package/docs/actor-messages.md +149 -0
- package/docs/async-runs.md +335 -0
- package/docs/command-templates.md +424 -0
- package/docs/component-recipes.md +148 -0
- package/docs/recipe-library.md +176 -0
- package/docs/task-first-recipes.md +233 -0
- package/docs/template-recipes.md +285 -0
- package/docs/tool-registry.md +142 -0
- package/index.ts +198 -0
- package/lib/actor-messages.ts +120 -0
- package/lib/async-runs.ts +688 -0
- package/lib/command-templates.ts +795 -0
- package/lib/config.ts +266 -0
- package/lib/execution.ts +720 -0
- package/lib/file-state.ts +24 -0
- package/lib/identity.ts +29 -0
- package/lib/observability.ts +525 -0
- package/lib/output.ts +123 -0
- package/lib/paths.ts +35 -0
- package/lib/prompts.ts +75 -0
- package/lib/recipe-references.ts +586 -0
- package/lib/registry.ts +302 -0
- package/lib/runtime.ts +101 -0
- package/lib/schema.ts +402 -0
- package/lib/temp.ts +44 -0
- package/lib/tools.ts +651 -0
- package/package.json +52 -0
- package/recipes/music-player.json +25 -0
- package/recipes/pipeline-architect-coordinator.json +88 -0
- package/recipes/pipeline-artifact-report.json +52 -0
- package/recipes/pipeline-artifact-write.json +66 -0
- package/recipes/pipeline-async-run-ops.json +67 -0
- package/recipes/pipeline-checkpoint-continuation.json +57 -0
- package/recipes/pipeline-development-tasking.json +73 -0
- package/recipes/pipeline-docs-maintenance.json +72 -0
- package/recipes/pipeline-media-library.json +51 -0
- package/recipes/pipeline-quorum-review.json +72 -0
- package/recipes/pipeline-release-readiness.json +83 -0
- package/recipes/pipeline-repo-health.json +81 -0
- package/recipes/pipeline-research-synthesis.json +87 -0
- package/recipes/pipeline-review-readiness.json +49 -0
- package/recipes/subagent-artifact.json +26 -0
- package/recipes/subagent-checkpoint.json +27 -0
- package/recipes/subagent-conflict-report.json +25 -0
- package/recipes/subagent-contradiction-map.json +26 -0
- package/recipes/subagent-critic.json +28 -0
- package/recipes/subagent-evidence-map.json +26 -0
- package/recipes/subagent-followup.json +27 -0
- package/recipes/subagent-judge.json +26 -0
- package/recipes/subagent-merge.json +26 -0
- package/recipes/subagent-message.json +29 -0
- package/recipes/subagent-normalize.json +24 -0
- package/recipes/subagent-plan.json +26 -0
- package/recipes/subagent-prompt.json +22 -0
- package/recipes/subagent-quorum.json +41 -0
- package/recipes/subagent-review-coordinator.json +107 -0
- package/recipes/subagent-review.json +30 -0
- package/recipes/subagent-task-card.json +28 -0
- package/recipes/subagent-tools.json +17 -0
- package/recipes/subagent-verify.json +27 -0
- package/recipes/subagents-prompts.json +32 -0
- package/recipes/utility-actor-message.json +24 -0
- package/recipes/utility-artifact-manifest.json +17 -0
- package/recipes/utility-artifact-write.json +17 -0
- package/recipes/utility-changelog-head.json +12 -0
- package/recipes/utility-changelog-section.json +14 -0
- package/recipes/utility-git-log.json +12 -0
- package/recipes/utility-git-status.json +10 -0
- package/recipes/utility-jsonl-tail.json +11 -0
- package/recipes/utility-markdown-index.json +15 -0
- package/recipes/utility-package-summary.json +12 -0
- package/recipes/utility-playlist-build.json +18 -0
- package/recipes/utility-playlist-scan.json +12 -0
- package/recipes/utility-run-state-files.json +14 -0
- package/recipes/utility-run-summary.json +12 -0
- package/recipes/utility-validate-recipe.json +14 -0
- package/recipes/utility-validation-wrapper.json +14 -0
- package/scripts/async-runner.mjs +170 -0
- package/scripts/music-player.mjs +637 -0
- package/scripts/recipe-utils.mjs +273 -0
- package/scripts/validate-recipe.mjs +89 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Detached async-runner.
|
|
5
|
+
*
|
|
6
|
+
* This process is intentionally thin: the parent tool prepares state files and
|
|
7
|
+
* starts this script in the background; this script loads the recorded run,
|
|
8
|
+
* executes its command template, and writes ordinary files that status/tail/list
|
|
9
|
+
* tools can inspect later.
|
|
10
|
+
*
|
|
11
|
+
* Keep orchestration policy out of this file.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { appendFileSync, readFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
const stateDir = process.argv[2];
|
|
18
|
+
if (!stateDir) {
|
|
19
|
+
console.error("missing state dir");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const { executeRegisteredTool } = await import("../lib/execution.ts");
|
|
23
|
+
const { execCommandTemplate } = await import("../lib/command-templates.ts");
|
|
24
|
+
const { writeJsonAtomic } = await import("../lib/file-state.ts");
|
|
25
|
+
const runPath = join(stateDir, "run.json");
|
|
26
|
+
const progressPath = join(stateDir, "progress.json");
|
|
27
|
+
const resultPath = join(stateDir, "result.json");
|
|
28
|
+
const eventsPath = join(stateDir, "events.jsonl");
|
|
29
|
+
const outboxPath = join(stateDir, "outbox.jsonl");
|
|
30
|
+
const stdoutPath = join(stateDir, "stdout.log");
|
|
31
|
+
const stderrPath = join(stateDir, "stderr.log");
|
|
32
|
+
const meta = JSON.parse(readFileSync(runPath, "utf8"));
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Appends one lifecycle event.
|
|
36
|
+
*
|
|
37
|
+
* events.jsonl is append-only so observers can tail transitions even while the
|
|
38
|
+
* run is still running.
|
|
39
|
+
*/
|
|
40
|
+
function event(name, data = {}) {
|
|
41
|
+
appendFileSync(
|
|
42
|
+
eventsPath,
|
|
43
|
+
`${JSON.stringify({ event: name, ts: new Date().toISOString(), ...data })}\n`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function getMessageDelivery(name) {
|
|
47
|
+
return name === "command.done" ? "followup" : "log";
|
|
48
|
+
}
|
|
49
|
+
function outbox(name, summary, data = {}, delivery = "log", level = "info") {
|
|
50
|
+
appendFileSync(
|
|
51
|
+
outboxPath,
|
|
52
|
+
`${JSON.stringify({ body: data, data, delivery, event: name, from: `run:${meta.run}`, level, summary, to: "coordinator", ts: new Date().toISOString(), type: name })}\n`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Writes the compact status snapshot.
|
|
57
|
+
*
|
|
58
|
+
* progress.json is rewritten atomically because observers may read it
|
|
59
|
+
* concurrently.
|
|
60
|
+
*/
|
|
61
|
+
function progress(phase, extra = {}) {
|
|
62
|
+
writeJsonAtomic(progressPath, {
|
|
63
|
+
phase,
|
|
64
|
+
updatedAt: new Date().toISOString(),
|
|
65
|
+
...extra,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
let activeSubagents = 0;
|
|
69
|
+
let completedSubagents = 0;
|
|
70
|
+
const subagentFailures = [];
|
|
71
|
+
function progressRunning() {
|
|
72
|
+
progress("running", {
|
|
73
|
+
activeSubagents,
|
|
74
|
+
completed: completedSubagents,
|
|
75
|
+
failures: subagentFailures,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async function observedExec(command, args, options) {
|
|
79
|
+
activeSubagents += 1;
|
|
80
|
+
event("command.start", { activeSubagents, command });
|
|
81
|
+
progressRunning();
|
|
82
|
+
const result = await execCommandTemplate(command, args, options);
|
|
83
|
+
activeSubagents = Math.max(0, activeSubagents - 1);
|
|
84
|
+
completedSubagents += 1;
|
|
85
|
+
if (result.code !== 0) {
|
|
86
|
+
subagentFailures.push({ code: result.code, command, killed: result.killed });
|
|
87
|
+
}
|
|
88
|
+
event("command.done", {
|
|
89
|
+
activeSubagents,
|
|
90
|
+
code: result.code,
|
|
91
|
+
command,
|
|
92
|
+
killed: result.killed,
|
|
93
|
+
});
|
|
94
|
+
outbox(
|
|
95
|
+
"command.done",
|
|
96
|
+
`Command ${command} completed with code ${result.code}`,
|
|
97
|
+
{
|
|
98
|
+
activeSubagents,
|
|
99
|
+
...(meta.artifacts ? { artifacts: meta.artifacts } : {}),
|
|
100
|
+
run_files: [stdoutPath, stderrPath, resultPath, eventsPath, outboxPath],
|
|
101
|
+
code: result.code,
|
|
102
|
+
command,
|
|
103
|
+
killed: result.killed,
|
|
104
|
+
},
|
|
105
|
+
getMessageDelivery("command.done"),
|
|
106
|
+
result.code === 0 ? "info" : "error",
|
|
107
|
+
);
|
|
108
|
+
progressRunning();
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
event("run.runner.start", { pid: process.pid });
|
|
113
|
+
progressRunning();
|
|
114
|
+
/**
|
|
115
|
+
* Reuse the same registered-tool execution path as foreground tools.
|
|
116
|
+
*
|
|
117
|
+
* The synthetic tool name is only for reporting; meta.template is the real
|
|
118
|
+
* work.
|
|
119
|
+
*/
|
|
120
|
+
const result = await executeRegisteredTool(
|
|
121
|
+
{
|
|
122
|
+
name: "run_actor",
|
|
123
|
+
description: "Detached command-template run actor",
|
|
124
|
+
template: meta.template,
|
|
125
|
+
args: [],
|
|
126
|
+
defaults: {},
|
|
127
|
+
},
|
|
128
|
+
meta.values || {},
|
|
129
|
+
observedExec,
|
|
130
|
+
meta.cwd,
|
|
131
|
+
);
|
|
132
|
+
/**
|
|
133
|
+
* Tool output is already formatted/truncated by the shared execution layer.
|
|
134
|
+
* The runner persists that agent-facing text for later tail/status analysis.
|
|
135
|
+
*/
|
|
136
|
+
const text = result.content?.[0]?.text || "";
|
|
137
|
+
appendFileSync(stdoutPath, text);
|
|
138
|
+
writeJsonAtomic(resultPath, {
|
|
139
|
+
code: result.details.code,
|
|
140
|
+
command: result.details.command,
|
|
141
|
+
killed: result.details.killed,
|
|
142
|
+
truncated: result.details.truncated,
|
|
143
|
+
completedAt: new Date().toISOString(),
|
|
144
|
+
});
|
|
145
|
+
progress("done", {
|
|
146
|
+
completed: 1,
|
|
147
|
+
failures: result.details.nonCriticalFailures || [],
|
|
148
|
+
});
|
|
149
|
+
event("run.done", { code: result.details.code });
|
|
150
|
+
} catch (error) {
|
|
151
|
+
/**
|
|
152
|
+
* Represent failure in every observable channel:
|
|
153
|
+
*
|
|
154
|
+
* - stderr.log for humans
|
|
155
|
+
* - result.json for structured readers
|
|
156
|
+
* - progress.json for status
|
|
157
|
+
* - events.jsonl for tail/watch flows
|
|
158
|
+
*/
|
|
159
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
160
|
+
appendFileSync(stderrPath, `${message}\n`);
|
|
161
|
+
writeJsonAtomic(resultPath, {
|
|
162
|
+
code: 1,
|
|
163
|
+
error: message,
|
|
164
|
+
killed: false,
|
|
165
|
+
completedAt: new Date().toISOString(),
|
|
166
|
+
});
|
|
167
|
+
progress("failed", { completed: 0, failures: [{ message }] });
|
|
168
|
+
event("run.failed", { error: message });
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|