@llblab/pi-actors 0.41.1 → 0.42.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 +11 -6
- package/BACKLOG.md +1 -65
- package/CHANGELOG.md +25 -0
- package/README.md +24 -4
- package/dist/index.js +25 -121
- package/dist/lib/async-runs.d.ts +37 -5
- package/dist/lib/async-runs.js +181 -51
- package/dist/lib/automatic-review-runtime.d.ts +18 -0
- package/dist/lib/automatic-review-runtime.js +96 -0
- package/dist/lib/command-templates.js +1 -1
- package/dist/lib/draft-consolidation-transaction.d.ts +65 -0
- package/dist/lib/draft-consolidation-transaction.js +610 -0
- package/dist/lib/draft-consolidation.d.ts +35 -0
- package/dist/lib/draft-consolidation.js +126 -0
- package/dist/lib/draft-review.d.ts +56 -0
- package/dist/lib/draft-review.js +254 -0
- package/dist/lib/draft-sleep.d.ts +65 -0
- package/dist/lib/draft-sleep.js +468 -0
- package/dist/lib/file-state.d.ts +8 -1
- package/dist/lib/file-state.js +115 -18
- package/dist/lib/inspector-actions.d.ts +16 -0
- package/dist/lib/inspector-actions.js +57 -0
- package/dist/lib/inspector-command.d.ts +7 -0
- package/dist/lib/inspector-command.js +37 -0
- package/dist/lib/inspector-overlay.d.ts +23 -3
- package/dist/lib/inspector-overlay.js +327 -70
- package/dist/lib/inspector.d.ts +9 -0
- package/dist/lib/inspector.js +49 -1
- package/dist/lib/observability.d.ts +13 -0
- package/dist/lib/observability.js +160 -6
- package/dist/lib/paths.d.ts +7 -0
- package/dist/lib/paths.js +28 -0
- package/dist/lib/recipes-discovery.js +32 -24
- package/dist/lib/recipes-usage.d.ts +18 -6
- package/dist/lib/recipes-usage.js +445 -34
- package/dist/lib/review-control.d.ts +14 -0
- package/dist/lib/review-control.js +111 -0
- package/dist/lib/review-diagnostics.d.ts +11 -0
- package/dist/lib/review-diagnostics.js +148 -0
- package/dist/lib/review-projection.d.ts +14 -0
- package/dist/lib/review-projection.js +170 -0
- package/dist/lib/run-ui-runtime.d.ts +18 -0
- package/dist/lib/run-ui-runtime.js +123 -0
- package/dist/lib/runs-artifacts.d.ts +1 -1
- package/dist/lib/runs-artifacts.js +1 -1
- package/dist/lib/runs-control.d.ts +10 -2
- package/dist/lib/runs-control.js +37 -7
- package/dist/lib/runs-identity.d.ts +1 -1
- package/dist/lib/runs-identity.js +1 -1
- package/dist/lib/runs-index.d.ts +11 -2
- package/dist/lib/runs-index.js +46 -23
- package/dist/lib/runs-mailbox.d.ts +1 -1
- package/dist/lib/runs-mailbox.js +1 -1
- package/dist/lib/runs-messages.d.ts +1 -1
- package/dist/lib/runs-messages.js +1 -1
- package/dist/lib/runs-outbox.d.ts +1 -1
- package/dist/lib/runs-outbox.js +1 -1
- package/dist/lib/runs-ownership.d.ts +1 -1
- package/dist/lib/runs-ownership.js +18 -4
- package/dist/lib/runs-parent-teardown.d.ts +51 -0
- package/dist/lib/runs-parent-teardown.js +172 -0
- package/dist/lib/runs-process.d.ts +1 -1
- package/dist/lib/runs-process.js +5 -4
- package/dist/lib/runs-retention.d.ts +1 -1
- package/dist/lib/runs-retention.js +1 -1
- package/dist/lib/runs-start.d.ts +5 -3
- package/dist/lib/runs-start.js +7 -48
- package/dist/lib/runs-status.d.ts +5 -3
- package/dist/lib/runs-status.js +7 -6
- package/dist/lib/runtime.d.ts +7 -1
- package/dist/lib/runtime.js +32 -18
- package/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
- package/dist/lib/tool-review-lineage-transaction.js +597 -0
- package/dist/lib/tool-review-lineage.d.ts +24 -0
- package/dist/lib/tool-review-lineage.js +98 -0
- package/dist/lib/tool-review-scheduler.d.ts +80 -0
- package/dist/lib/tool-review-scheduler.js +494 -0
- package/dist/lib/tool-review-transaction.d.ts +50 -0
- package/dist/lib/tool-review-transaction.js +362 -0
- package/dist/lib/tool-review.d.ts +56 -0
- package/dist/lib/tool-review.js +197 -0
- package/dist/lib/tools-inspect.js +28 -4
- package/dist/lib/tools-local.js +21 -4
- package/dist/lib/tools-message.d.ts +1 -0
- package/dist/lib/tools-message.js +29 -17
- package/dist/lib/tools-spawn.js +14 -2
- package/dist/lib/tools.d.ts +1 -0
- package/dist/lib/tools.js +1 -0
- package/dist/recipes/draft-review.json +24 -0
- package/dist/recipes/tool-review.json +24 -0
- package/dist/scripts/async-runner.mjs +9 -9
- package/dist/scripts/build-dist.mjs +6 -1
- package/dist/scripts/conformance.mjs +6 -1
- package/dist/scripts/recipe-utils.mjs +3 -3
- package/dist/scripts/release-gates.mjs +165 -0
- package/dist/skills/actors/SKILL.md +9 -8
- package/dist/skills/swarm/SKILL.md +1 -1
- package/docs/actor-inspector.md +20 -11
- package/docs/async-runs.md +16 -2
- package/docs/recipe-library.md +7 -3
- package/docs/template-recipes.md +4 -11
- package/docs/tool-registry.md +13 -4
- package/index.ts +27 -142
- package/lib/async-runs.ts +283 -67
- package/lib/automatic-review-runtime.ts +135 -0
- package/lib/command-templates.ts +1 -1
- package/lib/draft-consolidation-transaction.ts +821 -0
- package/lib/draft-consolidation.ts +181 -0
- package/lib/draft-review.ts +325 -0
- package/lib/draft-sleep.ts +576 -0
- package/lib/file-state.ts +143 -19
- package/lib/inspector-actions.ts +79 -0
- package/lib/inspector-command.ts +54 -0
- package/lib/inspector-overlay.ts +377 -91
- package/lib/inspector.ts +73 -1
- package/lib/observability.ts +194 -5
- package/lib/paths.ts +43 -0
- package/lib/recipes-discovery.ts +34 -26
- package/lib/recipes-usage.ts +569 -40
- package/lib/review-control.ts +137 -0
- package/lib/review-diagnostics.ts +164 -0
- package/lib/review-projection.ts +200 -0
- package/lib/run-ui-runtime.ts +153 -0
- package/lib/runs-artifacts.ts +1 -1
- package/lib/runs-control.ts +69 -6
- package/lib/runs-identity.ts +1 -1
- package/lib/runs-index.ts +57 -21
- package/lib/runs-mailbox.ts +1 -1
- package/lib/runs-messages.ts +1 -1
- package/lib/runs-outbox.ts +1 -1
- package/lib/runs-ownership.ts +23 -4
- package/lib/runs-parent-teardown.ts +257 -0
- package/lib/runs-process.ts +5 -4
- package/lib/runs-retention.ts +1 -1
- package/lib/runs-start.ts +13 -68
- package/lib/runs-status.ts +17 -8
- package/lib/runtime.ts +34 -17
- package/lib/tool-review-lineage-transaction.ts +881 -0
- package/lib/tool-review-lineage.ts +145 -0
- package/lib/tool-review-scheduler.ts +635 -0
- package/lib/tool-review-transaction.ts +563 -0
- package/lib/tool-review.ts +270 -0
- package/lib/tools-inspect.ts +35 -4
- package/lib/tools-local.ts +29 -4
- package/lib/tools-message.ts +45 -30
- package/lib/tools-spawn.ts +22 -2
- package/lib/tools.ts +5 -0
- package/package.json +5 -3
- package/recipes/draft-review.json +24 -0
- package/recipes/tool-review.json +24 -0
- package/scripts/async-runner.mjs +9 -9
- package/scripts/build-dist.mjs +6 -1
- package/scripts/conformance.mjs +6 -1
- package/scripts/recipe-utils.mjs +3 -3
- package/scripts/release-gates.mjs +165 -0
- package/skills/actors/SKILL.md +9 -8
- package/skills/swarm/SKILL.md +1 -1
package/scripts/async-runner.mjs
CHANGED
|
@@ -135,7 +135,7 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
135
135
|
try {
|
|
136
136
|
return readdirSync(sessionDir, { withFileTypes: true })
|
|
137
137
|
.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl"))
|
|
138
|
-
.map((entry) => relative(stateDir, join(sessionDir, entry.name)))
|
|
138
|
+
.map((entry) => relative(stateDir, join(sessionDir, entry.name)).replaceAll("\\", "/"))
|
|
139
139
|
.sort();
|
|
140
140
|
} catch {
|
|
141
141
|
return [];
|
|
@@ -167,12 +167,12 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
167
167
|
...(recipeContext ? { recipe_context: recipeContext } : {}),
|
|
168
168
|
command: commandDetail,
|
|
169
169
|
...(materialized.promptFile
|
|
170
|
-
? { prompt_file: relative(stateDir, materialized.promptFile) }
|
|
170
|
+
? { prompt_file: relative(stateDir, materialized.promptFile).replaceAll("\\", "/") }
|
|
171
171
|
: {}),
|
|
172
172
|
...(materialized.promptBytes
|
|
173
173
|
? { prompt_bytes: materialized.promptBytes }
|
|
174
174
|
: {}),
|
|
175
|
-
...(sessionDir ? { session_dir: relative(stateDir, sessionDir) } : {}),
|
|
175
|
+
...(sessionDir ? { session_dir: relative(stateDir, sessionDir).replaceAll("\\", "/") } : {}),
|
|
176
176
|
attempts: [],
|
|
177
177
|
semantic_acceptance:
|
|
178
178
|
options?.evidenceContext?.acceptOutput === "review_evidence" ||
|
|
@@ -209,11 +209,11 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
209
209
|
attempts.push({
|
|
210
210
|
attempt,
|
|
211
211
|
stdout: {
|
|
212
|
-
path: relative(stateDir, stdoutFile),
|
|
212
|
+
path: relative(stateDir, stdoutFile).replaceAll("\\", "/"),
|
|
213
213
|
bytes: existsSync(stdoutFile) ? statSync(stdoutFile).size : 0,
|
|
214
214
|
},
|
|
215
215
|
stderr: {
|
|
216
|
-
path: relative(stateDir, stderrFile),
|
|
216
|
+
path: relative(stateDir, stderrFile).replaceAll("\\", "/"),
|
|
217
217
|
bytes: existsSync(stderrFile) ? statSync(stderrFile).size : 0,
|
|
218
218
|
},
|
|
219
219
|
});
|
|
@@ -248,12 +248,12 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
248
248
|
...(recipeContext ? { recipe_context: recipeContext } : {}),
|
|
249
249
|
command: commandDetail,
|
|
250
250
|
...(materialized.promptFile
|
|
251
|
-
? { prompt_file: relative(stateDir, materialized.promptFile) }
|
|
251
|
+
? { prompt_file: relative(stateDir, materialized.promptFile).replaceAll("\\", "/") }
|
|
252
252
|
: {}),
|
|
253
253
|
...(materialized.promptBytes
|
|
254
254
|
? { prompt_bytes: materialized.promptBytes }
|
|
255
255
|
: {}),
|
|
256
|
-
...(sessionDir ? { session_dir: relative(stateDir, sessionDir) } : {}),
|
|
256
|
+
...(sessionDir ? { session_dir: relative(stateDir, sessionDir).replaceAll("\\", "/") } : {}),
|
|
257
257
|
...(commandSessionFiles(sessionDir).length > 0
|
|
258
258
|
? { session_files: commandSessionFiles(sessionDir) }
|
|
259
259
|
: {}),
|
|
@@ -386,7 +386,7 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
386
386
|
command: commandDetail,
|
|
387
387
|
...(materialized.promptFile ? { prompt_file: materialized.promptFile } : {}),
|
|
388
388
|
...(materialized.promptBytes ? { prompt_bytes: materialized.promptBytes } : {}),
|
|
389
|
-
...(session.sessionDir ? { session_dir: relative(stateDir, session.sessionDir) } : {}),
|
|
389
|
+
...(session.sessionDir ? { session_dir: relative(stateDir, session.sessionDir).replaceAll("\\", "/") } : {}),
|
|
390
390
|
});
|
|
391
391
|
progressRunning();
|
|
392
392
|
const captureDir = join(stateDir, "captures", commandId);
|
|
@@ -457,7 +457,7 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
457
457
|
...captureDetails(result),
|
|
458
458
|
...(materialized.promptFile ? { prompt_file: materialized.promptFile } : {}),
|
|
459
459
|
...(materialized.promptBytes ? { prompt_bytes: materialized.promptBytes } : {}),
|
|
460
|
-
...(session.sessionDir ? { session_dir: relative(stateDir, session.sessionDir) } : {}),
|
|
460
|
+
...(session.sessionDir ? { session_dir: relative(stateDir, session.sessionDir).replaceAll("\\", "/") } : {}),
|
|
461
461
|
...(commandSessionFiles(session.sessionDir).length > 0
|
|
462
462
|
? { session_files: commandSessionFiles(session.sessionDir) }
|
|
463
463
|
: {}),
|
package/scripts/build-dist.mjs
CHANGED
|
@@ -20,13 +20,18 @@ import { join } from "node:path";
|
|
|
20
20
|
|
|
21
21
|
function run(command, args) {
|
|
22
22
|
const result = spawnSync(command, args, { stdio: "inherit" });
|
|
23
|
+
if (result.error) throw result.error;
|
|
23
24
|
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
rmSync("dist", { recursive: true, force: true });
|
|
27
28
|
mkdirSync("dist", { recursive: true });
|
|
28
29
|
|
|
29
|
-
run(
|
|
30
|
+
run(process.execPath, [
|
|
31
|
+
join("node_modules", "typescript", "bin", "tsc"),
|
|
32
|
+
"-p",
|
|
33
|
+
"tsconfig.build.json",
|
|
34
|
+
]);
|
|
30
35
|
|
|
31
36
|
mkdirSync(join("dist", "pi-actors"), { recursive: true });
|
|
32
37
|
writeFileSync(
|
package/scripts/conformance.mjs
CHANGED
|
@@ -28,7 +28,12 @@ function packageRoot() {
|
|
|
28
28
|
|
|
29
29
|
const result = spawnSync(
|
|
30
30
|
process.execPath,
|
|
31
|
-
[
|
|
31
|
+
[
|
|
32
|
+
"--experimental-strip-types",
|
|
33
|
+
"--test",
|
|
34
|
+
"--test-concurrency=1",
|
|
35
|
+
...conformanceSuites,
|
|
36
|
+
],
|
|
32
37
|
{ cwd: packageRoot(), encoding: "utf8", stdio: "pipe" },
|
|
33
38
|
);
|
|
34
39
|
|
package/scripts/recipe-utils.mjs
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
statSync,
|
|
17
17
|
writeFileSync,
|
|
18
18
|
} from "node:fs";
|
|
19
|
-
import { dirname, extname, join, relative, resolve } from "node:path";
|
|
19
|
+
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
20
20
|
|
|
21
21
|
function usage() {
|
|
22
22
|
console.error(`Usage:
|
|
@@ -101,7 +101,7 @@ function collectRunSummary(rootValue) {
|
|
|
101
101
|
const root = resolve(
|
|
102
102
|
rootValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
|
|
103
103
|
);
|
|
104
|
-
const files = walkFiles(root, 2).filter((file) => file
|
|
104
|
+
const files = walkFiles(root, 2).filter((file) => basename(file) === "run.json");
|
|
105
105
|
const rows = [];
|
|
106
106
|
for (const file of files) {
|
|
107
107
|
const run = readJson(file);
|
|
@@ -118,7 +118,7 @@ function collectRunSummary(rootValue) {
|
|
|
118
118
|
const progress = readJson(join(runDir, "progress.json"));
|
|
119
119
|
const result = readJson(join(runDir, "result.json"));
|
|
120
120
|
rows.push({
|
|
121
|
-
run: run.run_id ?? run.run ?? relative(root, file).split(
|
|
121
|
+
run: run.run_id ?? run.run ?? relative(root, file).split(sep)[0],
|
|
122
122
|
status: getRunStatus(run, progress, result),
|
|
123
123
|
recipe: run.recipe ?? run.recipe_file ?? "",
|
|
124
124
|
updated:
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** Reproducible exact-tree, Domain DAG, secret-hygiene, and ABCd release gates. */
|
|
3
|
+
|
|
4
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { dirname, extname, join, normalize, relative, resolve } from "node:path";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
+
const temp = mkdtempSync(join(tmpdir(), "pi-actors-release-index-"));
|
|
12
|
+
const indexPath = join(temp, "index");
|
|
13
|
+
const gitEnv = { ...process.env, GIT_INDEX_FILE: indexPath };
|
|
14
|
+
const failures = [];
|
|
15
|
+
|
|
16
|
+
function run(command, args, options = {}) {
|
|
17
|
+
const result = spawnSync(command, args, {
|
|
18
|
+
cwd: root,
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
21
|
+
...options,
|
|
22
|
+
});
|
|
23
|
+
if (result.status !== 0) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`${command} ${args.join(" ")} failed (${result.status}): ${(result.stderr || result.stdout || "no output").trim()}`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return result.stdout;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function check(condition, message) {
|
|
32
|
+
if (!condition) failures.push(message);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function stagedText(path) {
|
|
36
|
+
const result = spawnSync("git", ["show", `:${path}`], {
|
|
37
|
+
cwd: root,
|
|
38
|
+
env: gitEnv,
|
|
39
|
+
encoding: "buffer",
|
|
40
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
41
|
+
});
|
|
42
|
+
if (result.status !== 0) {
|
|
43
|
+
failures.push(`could not read staged file: ${path}`);
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const bytes = result.stdout;
|
|
47
|
+
if (bytes.includes(0)) return undefined;
|
|
48
|
+
return bytes.toString("utf8");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function sourceImports(source) {
|
|
52
|
+
return [...source.matchAll(/^import(?:\s+type)?\s+(?:[^"']+?\s+from\s+)?["']([^"']+)["'];?$/gmu)]
|
|
53
|
+
.map((match) => match[1]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function resolveLocalImport(from, specifier, sourceSet) {
|
|
57
|
+
if (!specifier.startsWith(".")) return undefined;
|
|
58
|
+
const base = normalize(join(dirname(from), specifier)).replaceAll("\\", "/");
|
|
59
|
+
const candidates = extname(base)
|
|
60
|
+
? [base.replace(/\.js$/u, ".ts")]
|
|
61
|
+
: [`${base}.ts`, `${base}/index.ts`];
|
|
62
|
+
return candidates.find((candidate) => sourceSet.has(candidate));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
run("git", ["read-tree", "HEAD"], { env: gitEnv });
|
|
67
|
+
run("git", ["add", "-A"], { env: gitEnv });
|
|
68
|
+
run("git", ["diff", "--cached", "--check"], { env: gitEnv });
|
|
69
|
+
const files = run("git", ["ls-files", "-z"], { env: gitEnv })
|
|
70
|
+
.split("\0")
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
const fileSet = new Set(files);
|
|
73
|
+
console.log(`[release] exact temporary index: ${files.length} files`);
|
|
74
|
+
|
|
75
|
+
const secretPatterns = [
|
|
76
|
+
[/-----BEGIN(?: [A-Z0-9]+)? PRIVATE KEY-----[\s\S]{80,}?-----END(?: [A-Z0-9]+)? PRIVATE KEY-----/u, "private-key block"],
|
|
77
|
+
[/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/u, "AWS access key"],
|
|
78
|
+
[/\bgithub_pat_[A-Za-z0-9_]{20,}\b|\bgh[pousr]_[A-Za-z0-9]{20,}\b/u, "GitHub token"],
|
|
79
|
+
[/\bglpat-[A-Za-z0-9_-]{20,}\b|\bnpm_[A-Za-z0-9]{20,}\b|\bxox[baprs]-[A-Za-z0-9-]{10,}\b/u, "service token"],
|
|
80
|
+
];
|
|
81
|
+
const publicPath = /^(?:README\.md|AGENTS\.md|BACKLOG\.md|CHANGELOG\.md|docs\/|skills\/|recipes\/)/u;
|
|
82
|
+
for (const path of files) {
|
|
83
|
+
const text = stagedText(path);
|
|
84
|
+
if (text === undefined) continue;
|
|
85
|
+
if (!path.startsWith("tests/") && !path.startsWith("fixtures/")) {
|
|
86
|
+
for (const [pattern, label] of secretPatterns) {
|
|
87
|
+
check(!pattern.test(text), `${label} detected in ${path}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (publicPath.test(path)) {
|
|
91
|
+
check(!/(?:^|[\s"'`])\/home\/[A-Za-z0-9._-]+\//u.test(text), `machine-local path in ${path}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
console.log("[release] bounded secret and public-path hygiene checked");
|
|
95
|
+
|
|
96
|
+
const sources = files.filter((path) => path === "index.ts" || (path.startsWith("lib/") && path.endsWith(".ts")));
|
|
97
|
+
const sourceSet = new Set(sources);
|
|
98
|
+
const graph = new Map();
|
|
99
|
+
for (const path of sources) {
|
|
100
|
+
const text = stagedText(path) ?? "";
|
|
101
|
+
const headerEnd = text.indexOf("*/");
|
|
102
|
+
const header = headerEnd >= 0 ? text.slice(0, headerEnd + 2) : "";
|
|
103
|
+
check(
|
|
104
|
+
header.startsWith("/**") && (header.includes("Zones:") || header.includes("Owns:")),
|
|
105
|
+
`missing domain header: ${path}`,
|
|
106
|
+
);
|
|
107
|
+
const edges = sourceImports(text)
|
|
108
|
+
.map((specifier) => resolveLocalImport(path, specifier, sourceSet))
|
|
109
|
+
.filter(Boolean);
|
|
110
|
+
graph.set(path, edges);
|
|
111
|
+
if (path.startsWith("lib/")) {
|
|
112
|
+
check(!edges.includes("index.ts"), `domain imports entrypoint: ${path}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const visiting = new Set();
|
|
116
|
+
const visited = new Set();
|
|
117
|
+
function visit(path, stack = []) {
|
|
118
|
+
if (visiting.has(path)) {
|
|
119
|
+
failures.push(`Domain DAG cycle: ${[...stack, path].join(" -> ")}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (visited.has(path)) return;
|
|
123
|
+
visiting.add(path);
|
|
124
|
+
for (const next of graph.get(path) ?? []) visit(next, [...stack, path]);
|
|
125
|
+
visiting.delete(path);
|
|
126
|
+
visited.add(path);
|
|
127
|
+
}
|
|
128
|
+
for (const path of sources) visit(path);
|
|
129
|
+
console.log(`[release] strict Domain DAG: ${sources.length} sources, acyclic`);
|
|
130
|
+
|
|
131
|
+
for (const path of ["README.md", "AGENTS.md", "BACKLOG.md", "CHANGELOG.md", "docs/README.md"]) {
|
|
132
|
+
check(fileSet.has(path), `missing ABCd root/context file: ${path}`);
|
|
133
|
+
}
|
|
134
|
+
const readStaged = (path) => stagedText(path) ?? "";
|
|
135
|
+
const readme = readStaged("README.md");
|
|
136
|
+
for (const path of ["AGENTS.md", "BACKLOG.md", "CHANGELOG.md", "docs/README.md"]) {
|
|
137
|
+
check(readme.includes(path), `README.md does not route to ${path}`);
|
|
138
|
+
}
|
|
139
|
+
for (const path of files.filter((candidate) => candidate.endsWith(".md"))) {
|
|
140
|
+
const text = readStaged(path);
|
|
141
|
+
for (const match of text.matchAll(/\[[^\]]*\]\(([^)]+)\)/gu)) {
|
|
142
|
+
const target = match[1].split("#", 1)[0];
|
|
143
|
+
if (!target || /^(?:https?:|mailto:)/u.test(target)) continue;
|
|
144
|
+
const resolved = normalize(join(dirname(path), decodeURIComponent(target))).replaceAll("\\", "/");
|
|
145
|
+
check(fileSet.has(resolved), `broken Markdown link: ${path} -> ${target}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const docsIndex = readStaged("docs/README.md");
|
|
149
|
+
for (const path of files.filter((candidate) => candidate.startsWith("docs/") && candidate.endsWith(".md") && candidate !== "docs/README.md")) {
|
|
150
|
+
check(docsIndex.includes(relative("docs", path).replaceAll("\\", "/")), `docs/README.md omits ${path}`);
|
|
151
|
+
}
|
|
152
|
+
console.log("[release] ABCd context roots, routing, and Markdown links checked");
|
|
153
|
+
|
|
154
|
+
if (failures.length > 0) {
|
|
155
|
+
for (const failure of failures) console.error(`[FAIL] ${failure}`);
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
} else {
|
|
158
|
+
console.log("[release] all supplemental release gates passed");
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(`[FAIL] ${error instanceof Error ? error.message : String(error)}`);
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
} finally {
|
|
164
|
+
rmSync(temp, { recursive: true, force: true });
|
|
165
|
+
}
|
package/skills/actors/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: actors
|
|
3
3
|
description: Required practical guide for non-trivial pi-actors use, including parallel actor launches, subagent fanout, and autonomous coordinator workflows. Read before using or changing spawn, message, inspect, actor runs, tools, recipes, command templates, async lifecycle, mailboxes, artifacts, and local orchestration mechanics.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.42.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Actors (pi-actors)
|
|
@@ -40,7 +40,7 @@ Trusted local capability
|
|
|
40
40
|
- **Command template**: portable execution graph. String leaf, sequence array, or object node with controls.
|
|
41
41
|
- **Recipe**: saved JSON definition wrapping a template with args, defaults, imports, mailbox, artifacts, metadata, and optional `async: true`.
|
|
42
42
|
- **Run actor**: one detached execution instance addressable as `run:<id>` with status, logs, messages, mailbox metadata, files, and artifacts.
|
|
43
|
-
- **Tool actor**: registered persistent capability addressable as `tool:<name>` and callable through the generated tool or `message`. `tool:pi-actors` is reserved for runtime
|
|
43
|
+
- **Tool actor**: registered persistent capability addressable as `tool:<name>` and callable through the generated tool or `message`. `tool:pi-actors` is reserved for runtime status and explicit automatic-review retry/reset control.
|
|
44
44
|
- **Artifact**: named durable output path declared by a recipe/run.
|
|
45
45
|
- **Mailbox**: interaction contract: message types the actor accepts/emits.
|
|
46
46
|
- **Advanced group/coordination surfaces**: `branch:<run>/<branch>`, `room:<run>`, `coordinator`, `session:<id>`, and communication snapshots exist for multi-actor workflows and diagnostics; do not make them the default mental model.
|
|
@@ -94,7 +94,8 @@ Envelope fields:
|
|
|
94
94
|
- Group posts to `room:<run>` require `from` from the same run (`run:<run>` or `branch:<run>/<branch>`).
|
|
95
95
|
- Runtime termination message: `control.kill` is the only documented actor message that kills a run. `control.stop` and `control.cancel` are actor-local mailbox vocabulary only when a recipe declares and handles them. Terminal retention messages: `control.archive`, `control.prune`.
|
|
96
96
|
- Long-lived child processes should remain in the run-owned process group unless the recipe implements an explicit daemon termination bridge; do not leave unowned detached services behind `control.kill`.
|
|
97
|
-
- Run controls revalidate a persisted cross-platform process identity proof
|
|
97
|
+
- Run controls revalidate a persisted cross-platform process identity proof at authorization and again immediately before signaling. Treat `dead pid`, `owner mismatch`, and `unsupported proof` as distinct fail-closed states; on Unix, only process-group `ESRCH` plus one more matching identity check permits exact-pid fallback, while permission/authorization errors remain terminal. Node exposes no portable pidfd/process-group handle, so retain the documented residual exit/reuse window instead of claiming atomic signaling or bypassing control with direct pid signals.
|
|
98
|
+
- Detached actors survive ordinary agent turns. On `session_shutdown` (quit, reload, or session replacement), pi-actors attempts canonical `control.kill` for each discovered readable still-running exact-owner run. Control compares immutable run generation inside the canonical boundary and serializes against same-directory restart; terminal, ambiguous, changed-generation, and other-session runs remain untouched. Teardown scans without the ordinary index depth cap, reports unreadable/corrupt state as failures, and persists a bounded summary under the run root. Descendant Pi sessions remain separate owners and rely on their own shutdown hooks; hard host termination can still leave an orphan requiring summary-guided OS/manual recovery, so never describe teardown as an absolute no-survivor guarantee.
|
|
98
99
|
|
|
99
100
|
Check `inspect view=mailbox` before domain-specific messages.
|
|
100
101
|
|
|
@@ -216,15 +217,15 @@ Only matching filename ids compete. Higher priority shadows lower priority; with
|
|
|
216
217
|
Muscle-memory lens: pi-actors has two durable executable-memory layers.
|
|
217
218
|
|
|
218
219
|
1. `~/.pi/agent/recipes/*.json` and `*.md` are the agent's active capability memory. Every recipe in that directory becomes an easy-to-call tool automatically and survives into later sessions. Descriptions matter here because they become the tool's operator-facing title/context.
|
|
219
|
-
2. `~/.pi/agent/recipes/drafts/*.json` is draft memory captured from successful inline `spawn template=...` runs. Drafts do not enter the injected tool surface
|
|
220
|
+
2. `~/.pi/agent/recipes/drafts/*.json` is draft memory captured from successful inline `spawn template=...` runs. Drafts do not enter the injected tool surface and remain reusable by explicit path, e.g. `spawn file="~/.pi/agent/recipes/drafts/<name>.json"`.
|
|
220
221
|
|
|
221
|
-
Agents grow
|
|
222
|
+
Agents grow draft memory by trying ad hoc actors successfully. Active memory grows through explicit `register_tool`, deliberate operator recipe edits, or the bounded automatic review cycle. Treat drafts as the workbench and root recipes as active muscle memory.
|
|
222
223
|
|
|
223
|
-
Usage lens: user recipe launches update extension-maintained `.usage/<recipe-
|
|
224
|
+
Usage lens: user recipe launches update an extension-maintained canonical name-and-priority lineage ledger under `.usage/recipes/<recipe-name>.json`; authored recipe files are not rewritten for telemetry. Accounting briefly shares the portfolio mutation fence so source quarantine cannot erase an authorized launch; if another session already changed the source, the stale invocation rejects and requests reload rather than executing without evidence. Lifetime calls survive rename, revision, promotion, and demotion, while revision-local calls restart when executable content changes. The bounded unversioned ledger retains former names/paths, revision ancestry, transition events, and review epochs. Discovery merges lineage usage into inspection. Agents should not hand-edit counters; usage remains evidence rather than a sufficient usefulness verdict.
|
|
224
225
|
|
|
225
|
-
|
|
226
|
+
Automatic review lens: successful transient/ad hoc actor runs leave replayable drafts rather than active tools. At twelve eligible drafts, pi-actors captures one exact trusted batch and attaches only its identity-opaque value-free structural projection to a silent no-tools reviewer after the foreground turn and active actors finish. Its complete quota-free `promote`/`discard` result contains no recipe content: the deterministic executor derives promotions from exact captured sources and revalidates source/target CAS, complete recipes, root identity, quarantine hashes, and recovery state before commit. Newer drafts remain for a later batch; malformed, stale, unsafe, or incomplete decisions fail closed. Unchanged automatic demotions remain in cooldown until their executable fingerprint changes. Prefer fenced `register_tool draft=...` for an explicit single-draft promotion. A deliberate move/copy into the recipe root also remains valid, but may invalidate and defer an already captured batch; do not reconstruct removed batch commands or ask the operator to drive an automatic batch.
|
|
226
227
|
|
|
227
|
-
|
|
228
|
+
Portfolio lens: thirty-six eligible non-sensitive active revisions trigger a no-tools review of an attached value-free structural projection; canonical names, draft basenames, raw hashes, recipe bodies, template/default values, authored prose, and filesystem paths remain in the separate trusted capture; batch-local occurrence IDs and equality-only content groups preserve correlation and deduplication. Set `PI_ACTORS_AUTOMATIC_REVIEW=off` before Pi starts to disable both reviewer scheduling and safe-boundary portfolio activation; verify the effective value with `inspect target=tool:pi-actors view=status`. The reviewer may select keep, unchanged-source rename, unchanged-source demotion, or deduplication of canonically identical captured recipes; it cannot return recipe content. Replacement, split, and executable contract changes require explicit operator authoring. Approval remains immutable until the next safe session boundary, where journaled filesystem and lineage executors apply only the captured recipe bytes. Use `inspect target=recipes view=reviews` for bounded evidence including failed stage/error/next action. Recover a failed cycle through `message to=tool:pi-actors type=review.retry body={"scope":"draft"|"tool"}`. Draft retry resumes an existing authenticated transaction plan and original reviewer run rather than generating decisions after filesystem commit; `review.reset` clears only disposable terminal admission state and rejects tool recovery evidence that must roll forward.
|
|
228
229
|
|
|
229
230
|
## Registered Tools
|
|
230
231
|
|
package/skills/swarm/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: swarm
|
|
3
3
|
description: Subagent and actor orchestration with scoped locks, fanout, and quorum consensus. Use before launching multiple parallel actors or subagents for independent implementation, artifact generation, review, delegated audit, coordinated execution, or any workflow that needs autonomous coordinator decomposition and integration.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.
|
|
5
|
+
version: 0.42.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Swarm
|