@llblab/pi-actors 0.45.0 → 0.46.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 +10 -6
- package/CHANGELOG.md +14 -1
- package/README.md +28 -12
- package/dist/fixtures/protocol/recipe-summary.json +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +10 -110
- package/dist/lib/async-runs.d.ts +4 -1
- package/dist/lib/async-runs.js +22 -23
- package/dist/lib/automatic-review-runtime.d.ts +2 -0
- package/dist/lib/automatic-review-runtime.js +12 -5
- package/dist/lib/draft-sleep.js +0 -1
- package/dist/lib/extension-runtime.d.ts +21 -0
- package/dist/lib/extension-runtime.js +122 -0
- package/dist/lib/inspector.js +45 -7
- package/dist/lib/paths.d.ts +0 -1
- package/dist/lib/paths.js +0 -7
- package/dist/lib/prompts.d.ts +1 -1
- package/dist/lib/prompts.js +2 -2
- package/dist/lib/recipes-context.js +2 -2
- package/dist/lib/recipes-references.d.ts +24 -9
- package/dist/lib/recipes-references.js +152 -126
- package/dist/lib/runtime.d.ts +0 -1
- package/dist/lib/runtime.js +1 -3
- package/dist/lib/tools-inspect.d.ts +0 -1
- package/dist/lib/tools-inspect.js +35 -8
- package/dist/lib/tools-local.d.ts +2 -0
- package/dist/lib/tools-local.js +1 -1
- package/dist/lib/tools-spawn.d.ts +2 -0
- package/dist/lib/tools-spawn.js +24 -52
- package/dist/scripts/async-runner.mjs +0 -16
- package/dist/scripts/build-dist.mjs +13 -4
- package/dist/skills/actors/SKILL.md +6 -6
- package/dist/skills/actors/recipes/recipe-validate.json +11 -0
- package/{recipes/utility-coordinator-lock-snapshot.json → dist/skills/actors/recipes/resource-locker-snapshot.json} +1 -3
- package/dist/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
- package/dist/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
- package/dist/skills/actors/recipes/run-summary.json +9 -0
- package/dist/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -23
- package/dist/skills/actors/scripts/run-utils.mjs +164 -0
- package/{scripts → dist/skills/actors/scripts}/validate-recipe.mjs +134 -18
- package/dist/skills/artifacts/SKILL.md +16 -0
- package/{recipes/pipeline-artifact-bundle.json → dist/skills/artifacts/recipes/bundle.json} +4 -4
- package/dist/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
- package/dist/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
- package/{recipes/pipeline-artifact-report.json → dist/skills/artifacts/recipes/report.json} +2 -2
- package/dist/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
- package/dist/skills/artifacts/scripts/artifact-utils.mjs +63 -0
- package/dist/skills/media/SKILL.md +16 -0
- package/dist/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
- package/{recipes/music-player.json → dist/skills/media/recipes/player.json} +1 -3
- package/dist/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
- package/dist/skills/media/scripts/media-utils.mjs +47 -0
- package/dist/{scripts → skills/media/scripts}/music-player.mjs +9 -3
- package/dist/skills/project-work/SKILL.md +16 -0
- package/dist/skills/project-work/recipes/changelog-section.json +11 -0
- package/{recipes/pipeline-docs-maintenance.json → dist/skills/project-work/recipes/docs-maintenance.json} +4 -4
- package/dist/skills/project-work/recipes/package-summary.json +9 -0
- package/{recipes/pipeline-release-readiness.json → dist/skills/project-work/recipes/release-readiness.json} +6 -6
- package/dist/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
- package/{recipes/pipeline-repo-health.json → dist/skills/project-work/recipes/repo-health.json} +6 -6
- package/{recipes/pipeline-async-run-ops.json → dist/skills/project-work/recipes/run-ops.json} +3 -3
- package/dist/skills/project-work/recipes/skill-summary.json +11 -0
- package/dist/skills/project-work/scripts/project-utils.mjs +89 -0
- package/dist/skills/recipe-memory/SKILL.md +16 -0
- package/dist/skills/swarm/SKILL.md +4 -4
- package/{recipes/pipeline-architect-coordinator.json → dist/skills/swarm/recipes/architect.json} +5 -5
- package/{recipes/pipeline-checkpoint-continuation.json → dist/skills/swarm/recipes/checkpoint-continuation.json} +3 -3
- package/dist/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
- package/dist/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
- package/dist/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
- package/{recipes/pipeline-research-synthesis.json → dist/skills/swarm/recipes/research-synthesis.json} +6 -6
- package/{recipes/pipeline-review-readiness.json → dist/skills/swarm/recipes/review-readiness.json} +1 -1
- package/{recipes/subagents-prompts.json → dist/skills/swarm/recipes/subagent-prompts.json} +1 -1
- package/{recipes → dist/skills/swarm/recipes}/subagent-quorum.json +1 -1
- package/dist/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
- package/docs/actor-inspector.md +4 -3
- package/docs/async-runs.md +2 -2
- package/docs/recipe-library.md +23 -23
- package/docs/releasing.md +2 -2
- package/docs/template-recipes.md +30 -14
- package/docs/tool-registry.md +2 -2
- package/fixtures/protocol/recipe-summary.json +1 -1
- package/index.ts +18 -112
- package/lib/async-runs.ts +47 -24
- package/lib/automatic-review-runtime.ts +16 -3
- package/lib/draft-sleep.ts +0 -1
- package/lib/extension-runtime.ts +158 -0
- package/lib/inspector.ts +56 -11
- package/lib/paths.ts +0 -7
- package/lib/prompts.ts +2 -2
- package/lib/recipes-context.ts +2 -2
- package/lib/recipes-references.ts +223 -134
- package/lib/runtime.ts +1 -5
- package/lib/tools-inspect.ts +42 -9
- package/lib/tools-local.ts +2 -0
- package/lib/tools-spawn.ts +37 -74
- package/package.json +3 -5
- package/scripts/async-runner.mjs +0 -16
- package/scripts/build-dist.mjs +13 -4
- package/skills/actors/SKILL.md +6 -6
- package/skills/actors/recipes/recipe-validate.json +11 -0
- package/{dist/recipes/utility-coordinator-lock-snapshot.json → skills/actors/recipes/resource-locker-snapshot.json} +1 -3
- package/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
- package/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
- package/skills/actors/recipes/run-summary.json +9 -0
- package/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -23
- package/skills/actors/scripts/run-utils.mjs +164 -0
- package/{dist → skills/actors}/scripts/validate-recipe.mjs +134 -18
- package/skills/artifacts/SKILL.md +16 -0
- package/{dist/recipes/pipeline-artifact-bundle.json → skills/artifacts/recipes/bundle.json} +4 -4
- package/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
- package/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
- package/{dist/recipes/pipeline-artifact-report.json → skills/artifacts/recipes/report.json} +2 -2
- package/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
- package/skills/artifacts/scripts/artifact-utils.mjs +63 -0
- package/skills/media/SKILL.md +16 -0
- package/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
- package/{dist/recipes/music-player.json → skills/media/recipes/player.json} +1 -3
- package/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
- package/skills/media/scripts/media-utils.mjs +47 -0
- package/{scripts → skills/media/scripts}/music-player.mjs +9 -3
- package/skills/project-work/SKILL.md +16 -0
- package/skills/project-work/recipes/changelog-section.json +11 -0
- package/{dist/recipes/pipeline-docs-maintenance.json → skills/project-work/recipes/docs-maintenance.json} +4 -4
- package/skills/project-work/recipes/package-summary.json +9 -0
- package/{dist/recipes/pipeline-release-readiness.json → skills/project-work/recipes/release-readiness.json} +6 -6
- package/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
- package/{dist/recipes/pipeline-repo-health.json → skills/project-work/recipes/repo-health.json} +6 -6
- package/{dist/recipes/pipeline-async-run-ops.json → skills/project-work/recipes/run-ops.json} +3 -3
- package/skills/project-work/recipes/skill-summary.json +11 -0
- package/skills/project-work/scripts/project-utils.mjs +89 -0
- package/skills/recipe-memory/SKILL.md +16 -0
- package/skills/swarm/SKILL.md +4 -4
- package/{dist/recipes/pipeline-architect-coordinator.json → skills/swarm/recipes/architect.json} +5 -5
- package/{dist/recipes/pipeline-checkpoint-continuation.json → skills/swarm/recipes/checkpoint-continuation.json} +3 -3
- package/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
- package/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
- package/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
- package/{dist/recipes/pipeline-research-synthesis.json → skills/swarm/recipes/research-synthesis.json} +6 -6
- package/{dist/recipes/pipeline-review-readiness.json → skills/swarm/recipes/review-readiness.json} +1 -1
- package/{dist/recipes/subagents-prompts.json → skills/swarm/recipes/subagent-prompts.json} +1 -1
- package/{dist → skills/swarm}/recipes/subagent-quorum.json +1 -1
- package/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
- package/dist/recipes/utility-changelog-section.json +0 -13
- package/dist/recipes/utility-package-summary.json +0 -11
- package/dist/recipes/utility-run-summary.json +0 -11
- package/dist/recipes/utility-skill-summary.json +0 -13
- package/dist/recipes/utility-validate-recipe.json +0 -13
- package/dist/scripts/recipe-utils.mjs +0 -405
- package/dist/scripts/release-gates.mjs +0 -278
- package/recipes/utility-changelog-section.json +0 -13
- package/recipes/utility-package-summary.json +0 -11
- package/recipes/utility-run-summary.json +0 -11
- package/recipes/utility-skill-summary.json +0 -13
- package/recipes/utility-validate-recipe.json +0 -13
- package/scripts/recipe-utils.mjs +0 -405
- package/scripts/release-gates.mjs +0 -278
- /package/dist/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
- /package/dist/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
- /package/dist/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
- /package/dist/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
- /package/dist/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
- /package/dist/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
- /package/dist/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
- /package/dist/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
- /package/dist/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
- /package/dist/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
- /package/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
- /package/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
- /package/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
- /package/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
- /package/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
- /package/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
- /package/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
- /package/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
- /package/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
- /package/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
|
@@ -21,12 +21,12 @@ import readline from "node:readline";
|
|
|
21
21
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
22
22
|
|
|
23
23
|
function packageRoot() {
|
|
24
|
-
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
24
|
+
return dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url)))));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
async function importRuntimeModule(name) {
|
|
28
28
|
const root = packageRoot();
|
|
29
|
-
const compiled = join(root, "
|
|
29
|
+
const compiled = join(root, "lib", `${name}.js`);
|
|
30
30
|
const source = join(root, "lib", `${name}.ts`);
|
|
31
31
|
return await import(pathToFileURL(existsSync(compiled) ? compiled : source).href);
|
|
32
32
|
}
|
|
@@ -65,7 +65,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
65
65
|
const controlPath = join(stateDir, "control.fifo");
|
|
66
66
|
let runInstanceId;
|
|
67
67
|
mkdirSync(stateDir, { recursive: true });
|
|
68
|
-
|
|
69
68
|
function readJson(path, fallback) {
|
|
70
69
|
if (!existsSync(path)) return fallback;
|
|
71
70
|
try {
|
|
@@ -74,11 +73,9 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
74
73
|
return fallback;
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
|
-
|
|
78
76
|
function writeJson(path, value) {
|
|
79
77
|
writeJsonAtomic(path, value);
|
|
80
78
|
}
|
|
81
|
-
|
|
82
79
|
function getControlEndpoint() {
|
|
83
80
|
if (process.platform !== "win32") return { path: controlPath, type: "fifo" };
|
|
84
81
|
const hash = createHash("sha256")
|
|
@@ -87,7 +84,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
87
84
|
.slice(0, 20);
|
|
88
85
|
return { path: `\\\\.\\pipe\\pi-actors-locker-${hash}`, type: "named-pipe" };
|
|
89
86
|
}
|
|
90
|
-
|
|
91
87
|
function writeControlEndpoint(endpoint) {
|
|
92
88
|
if (!runInstanceId) throw new Error("Run generation unavailable for Control endpoint");
|
|
93
89
|
writeJson(join(stateDir, "control-endpoint.json"), {
|
|
@@ -96,7 +92,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
96
92
|
run_instance_id: runInstanceId,
|
|
97
93
|
});
|
|
98
94
|
}
|
|
99
|
-
|
|
100
95
|
function journal(event, data = {}) {
|
|
101
96
|
const release = acquireFileMutationLock(journalPath);
|
|
102
97
|
try {
|
|
@@ -111,11 +106,9 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
111
106
|
writeTextAtomic(journalPath, content);
|
|
112
107
|
} finally { release(); }
|
|
113
108
|
}
|
|
114
|
-
|
|
115
109
|
function encodeJournal(records) {
|
|
116
110
|
return records.length ? `${records.map((record) => JSON.stringify(record)).join("\n")}\n` : "";
|
|
117
111
|
}
|
|
118
|
-
|
|
119
112
|
function emitTrace(kind, summary, data = {}, level = "info") {
|
|
120
113
|
appendRunTraceEvent(stateDir, {
|
|
121
114
|
attention: "followup",
|
|
@@ -125,11 +118,9 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
125
118
|
summary,
|
|
126
119
|
});
|
|
127
120
|
}
|
|
128
|
-
|
|
129
121
|
function now() {
|
|
130
122
|
return Date.now();
|
|
131
123
|
}
|
|
132
|
-
|
|
133
124
|
function cleanExpiredLocks(locks) {
|
|
134
125
|
const current = now();
|
|
135
126
|
const kept = {};
|
|
@@ -139,7 +130,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
139
130
|
}
|
|
140
131
|
return kept;
|
|
141
132
|
}
|
|
142
|
-
|
|
143
133
|
function normalizeControl(line) {
|
|
144
134
|
const trimmed = line.trim();
|
|
145
135
|
if (!trimmed) return undefined;
|
|
@@ -160,8 +150,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
160
150
|
);
|
|
161
151
|
}
|
|
162
152
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
153
|
function tailJournal(count) {
|
|
166
154
|
if (!existsSync(journalPath)) return [];
|
|
167
155
|
return readFileSync(journalPath, "utf8")
|
|
@@ -177,7 +165,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
177
165
|
}
|
|
178
166
|
});
|
|
179
167
|
}
|
|
180
|
-
|
|
181
168
|
function printSnapshot() {
|
|
182
169
|
const locks = cleanExpiredLocks(readJson(locksPath, {}));
|
|
183
170
|
writeJson(locksPath, locks);
|
|
@@ -195,7 +182,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
195
182
|
),
|
|
196
183
|
);
|
|
197
184
|
}
|
|
198
|
-
|
|
199
185
|
function nextTask(queue, locks) {
|
|
200
186
|
const items = Array.isArray(queue.items) ? queue.items : [];
|
|
201
187
|
const index = items.findIndex((item) => {
|
|
@@ -205,7 +191,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
205
191
|
if (index < 0) return undefined;
|
|
206
192
|
return items.splice(index, 1)[0];
|
|
207
193
|
}
|
|
208
|
-
|
|
209
194
|
function handle(control) {
|
|
210
195
|
const action = control.action;
|
|
211
196
|
const body =
|
|
@@ -333,18 +318,15 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
333
318
|
journal("lock.unknown", { action, input: body });
|
|
334
319
|
emitTrace("lock.unknown", `Unknown Control ${action}`, { action, input: body }, "warning");
|
|
335
320
|
}
|
|
336
|
-
|
|
337
321
|
if (mode === "snapshot") {
|
|
338
322
|
printSnapshot();
|
|
339
323
|
process.exit(0);
|
|
340
324
|
}
|
|
341
|
-
|
|
342
325
|
const startupRun = readJson(join(stateDir, "run.json"), undefined);
|
|
343
326
|
if (!startupRun || typeof startupRun.run_instance_id !== "string") {
|
|
344
327
|
throw new Error("Run generation unavailable for Control service");
|
|
345
328
|
}
|
|
346
329
|
runInstanceId = startupRun.run_instance_id;
|
|
347
|
-
|
|
348
330
|
function handleLine(line) {
|
|
349
331
|
const control = normalizeControl(line);
|
|
350
332
|
if (!control) return false;
|
|
@@ -376,7 +358,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
376
358
|
return false;
|
|
377
359
|
}
|
|
378
360
|
}
|
|
379
|
-
|
|
380
361
|
async function serveFifo(endpoint) {
|
|
381
362
|
if (!existsSync(endpoint.path)) {
|
|
382
363
|
const result = spawnSync("mkfifo", [endpoint.path]);
|
|
@@ -403,7 +384,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
403
384
|
fs.closeSync(fd);
|
|
404
385
|
}
|
|
405
386
|
}
|
|
406
|
-
|
|
407
387
|
async function serveNamedPipe(endpoint) {
|
|
408
388
|
let resolveStopped;
|
|
409
389
|
const stopped = new Promise((resolve) => {
|
|
@@ -428,7 +408,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
428
408
|
});
|
|
429
409
|
await stopped;
|
|
430
410
|
}
|
|
431
|
-
|
|
432
411
|
const endpoint = getControlEndpoint();
|
|
433
412
|
writeJson(queuePath, readJson(queuePath, { items: [] }));
|
|
434
413
|
writeJson(locksPath, cleanExpiredLocks(readJson(locksPath, {})));
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/** Actor-owned Run summary utilities. */
|
|
4
|
+
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
|
|
7
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
8
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
9
|
+
|
|
10
|
+
function fail(message) {
|
|
11
|
+
console.error(message);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function usage() {
|
|
16
|
+
console.error(`Usage:
|
|
17
|
+
run-utils.mjs run-summary <state-root>
|
|
18
|
+
run-utils.mjs run-ops-snapshot <state-root> <run-id> [lines] [stale-minutes]`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function walkFiles(dir, maxDepth = 2, depth = 0, out = []) {
|
|
22
|
+
if (depth > maxDepth || !existsSync(dir)) return out;
|
|
23
|
+
for (const entry of readdirSync(dir)) {
|
|
24
|
+
const path = join(dir, entry);
|
|
25
|
+
const stat = statSync(path);
|
|
26
|
+
if (stat.isDirectory()) walkFiles(path, maxDepth, depth + 1, out);
|
|
27
|
+
else if (stat.isFile()) out.push(path);
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readJson(file) {
|
|
33
|
+
if (!existsSync(file)) return undefined;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
36
|
+
} catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getRunStatus(run, progress, result) {
|
|
42
|
+
if (progress?.phase) return progress.phase;
|
|
43
|
+
if (result?.code !== undefined) return result.code === 0 ? "done" : "failed";
|
|
44
|
+
return run.status ?? "unknown";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function collectRunSummary(rootValue) {
|
|
48
|
+
const root = resolve(rootValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"));
|
|
49
|
+
const files = walkFiles(root, 2).filter((file) => basename(file) === "run.json");
|
|
50
|
+
const rows = [];
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
const run = readJson(file);
|
|
53
|
+
if (!run) {
|
|
54
|
+
rows.push({ run: relative(root, file), status: "invalid-json", recipe: "", updated: "" });
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const runDir = dirname(file);
|
|
58
|
+
const progress = readJson(join(runDir, "progress.json"));
|
|
59
|
+
const result = readJson(join(runDir, "result.json"));
|
|
60
|
+
rows.push({
|
|
61
|
+
run: run.run_id ?? run.run ?? relative(root, file).split(sep)[0],
|
|
62
|
+
status: getRunStatus(run, progress, result),
|
|
63
|
+
recipe: run.recipe ?? run.recipe_file ?? "",
|
|
64
|
+
updated:
|
|
65
|
+
progress?.updatedAt ??
|
|
66
|
+
result?.completedAt ??
|
|
67
|
+
run.updated_at ??
|
|
68
|
+
run.completed_at ??
|
|
69
|
+
run.started_at ??
|
|
70
|
+
"",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
rows.sort((a, b) => `${a.status}:${a.run}`.localeCompare(`${b.status}:${b.run}`));
|
|
74
|
+
return rows;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function tailJsonl(fileValue, linesValue = "80") {
|
|
78
|
+
const file = resolve(fileValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"));
|
|
79
|
+
if (!existsSync(file)) return [];
|
|
80
|
+
const lines = Number.parseInt(linesValue, 10);
|
|
81
|
+
const count = Number.isFinite(lines) && lines > 0 ? lines : 80;
|
|
82
|
+
return readFileSync(file, "utf8")
|
|
83
|
+
.trimEnd()
|
|
84
|
+
.split("\n")
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.slice(-count)
|
|
87
|
+
.map((line) => {
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(line);
|
|
90
|
+
} catch {
|
|
91
|
+
return { raw: line };
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function runOpsSnapshot(
|
|
97
|
+
rootValue,
|
|
98
|
+
runIdValue = "music",
|
|
99
|
+
linesValue = "80",
|
|
100
|
+
staleMinutesValue = "60",
|
|
101
|
+
) {
|
|
102
|
+
const runs = collectRunSummary(rootValue);
|
|
103
|
+
const root = resolve(rootValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"));
|
|
104
|
+
const inspectedRun = String(runIdValue || "music");
|
|
105
|
+
const staleMs = Number(staleMinutesValue) * 60 * 1000;
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
const recommendations = runs.flatMap((run) => {
|
|
108
|
+
const updatedMs = Date.parse(run.updated || "");
|
|
109
|
+
const stale =
|
|
110
|
+
Number.isFinite(updatedMs) &&
|
|
111
|
+
Number.isFinite(staleMs) &&
|
|
112
|
+
now - updatedMs > staleMs;
|
|
113
|
+
if (run.status === "running" && stale) {
|
|
114
|
+
return [{
|
|
115
|
+
run: run.run,
|
|
116
|
+
reason: "running-stale",
|
|
117
|
+
suggested_inspect: { target: `run:${run.run}`, view: "control" },
|
|
118
|
+
}];
|
|
119
|
+
}
|
|
120
|
+
if (["failed", "exited", "killed"].includes(run.status)) {
|
|
121
|
+
return [{
|
|
122
|
+
run: run.run,
|
|
123
|
+
reason: `terminal-${run.status}`,
|
|
124
|
+
suggested_inspect: { target: `run:${run.run}`, view: "trace" },
|
|
125
|
+
}];
|
|
126
|
+
}
|
|
127
|
+
return [];
|
|
128
|
+
});
|
|
129
|
+
console.log(JSON.stringify({
|
|
130
|
+
runs,
|
|
131
|
+
inspectedRun,
|
|
132
|
+
trace: tailJsonl(join(root, inspectedRun, "trace.jsonl"), linesValue),
|
|
133
|
+
recommendations,
|
|
134
|
+
}, null, 2));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function runSummary(rootValue) {
|
|
138
|
+
console.log(JSON.stringify(collectRunSummary(rootValue), null, 2));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function run(argv = process.argv.slice(2)) {
|
|
142
|
+
const [command, ...args] = argv;
|
|
143
|
+
if (command === "run-summary") {
|
|
144
|
+
runSummary(args[0] ?? "~/.pi/agent/tmp/pi-actors/runs");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (command === "run-ops-snapshot") {
|
|
148
|
+
runOpsSnapshot(
|
|
149
|
+
args[0] ?? "~/.pi/agent/tmp/pi-actors/runs",
|
|
150
|
+
args[1] ?? "music",
|
|
151
|
+
args[2],
|
|
152
|
+
args[3],
|
|
153
|
+
);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
usage();
|
|
157
|
+
fail(`Unknown command: ${command ?? ""}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
run();
|
|
162
|
+
} catch (error) {
|
|
163
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
164
|
+
}
|
|
@@ -9,27 +9,49 @@
|
|
|
9
9
|
|
|
10
10
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
|
-
import { dirname, join, resolve } from "node:path";
|
|
12
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
14
14
|
|
|
15
15
|
function packageRoot() {
|
|
16
|
-
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
16
|
+
return dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url)))));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
async function importRuntimeModule(name) {
|
|
20
20
|
const root = packageRoot();
|
|
21
|
-
const
|
|
21
|
+
const localCompiled = join(root, "lib", `${name}.js`);
|
|
22
|
+
const installedCompiled = join(root, "dist", "lib", `${name}.js`);
|
|
22
23
|
const source = join(root, "lib", `${name}.ts`);
|
|
23
|
-
|
|
24
|
+
const module = existsSync(localCompiled)
|
|
25
|
+
? localCompiled
|
|
26
|
+
: root.includes(`${sep}node_modules${sep}`) && existsSync(installedCompiled)
|
|
27
|
+
? installedCompiled
|
|
28
|
+
: source;
|
|
29
|
+
return await import(pathToFileURL(module).href);
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
createActiveSkillRecipeContext,
|
|
34
|
+
readRawRecipeConfig,
|
|
35
|
+
readResolvedRecipeConfig,
|
|
36
|
+
} = await importRuntimeModule("recipes-references");
|
|
37
|
+
|
|
38
|
+
const skillsDir = join(packageRoot(), "skills");
|
|
39
|
+
const packageSkillContext = createActiveSkillRecipeContext(
|
|
40
|
+
existsSync(skillsDir)
|
|
41
|
+
? readdirSync(skillsDir, { withFileTypes: true })
|
|
42
|
+
.filter((entry) => entry.isDirectory())
|
|
43
|
+
.map((entry) => ({
|
|
44
|
+
name: entry.name,
|
|
45
|
+
baseDir: join(skillsDir, entry.name),
|
|
46
|
+
}))
|
|
47
|
+
: [],
|
|
48
|
+
);
|
|
27
49
|
|
|
28
50
|
export function validateRecipeUsage() {
|
|
29
51
|
return `Usage:
|
|
30
|
-
validate-recipe.mjs <recipe-file-or-dir> [--all] [--qa] [--summary]
|
|
52
|
+
validate-recipe.mjs <recipe-file-or-dir> [--all] [--skills] [--qa] [--summary]
|
|
31
53
|
|
|
32
|
-
Validates one template
|
|
54
|
+
Validates one template Recipe file or all direct *.json/*.md files in a directory with --all. Use --skills on a Skills root to validate every direct <skill>/recipes component and reject nested files or duplicate stems. Add --qa for shipped-component capability checks, where diagnostics and warnings fail validation. Add --summary for compact CLI output.`;
|
|
33
55
|
}
|
|
34
56
|
|
|
35
57
|
function expandPath(value) {
|
|
@@ -63,6 +85,79 @@ function recipeFiles(target, all) {
|
|
|
63
85
|
.map((file) => resolve(target, file));
|
|
64
86
|
}
|
|
65
87
|
|
|
88
|
+
function nestedRecipeFiles(root) {
|
|
89
|
+
return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
|
|
90
|
+
const path = join(root, entry.name);
|
|
91
|
+
if (entry.isDirectory()) return nestedRecipeFiles(path);
|
|
92
|
+
return entry.isFile() && /\.(?:json|md)$/.test(entry.name) ? [path] : [];
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function scanSkillRecipes(target) {
|
|
97
|
+
if (!existsSync(target) || !statSync(target).isDirectory())
|
|
98
|
+
throw new Error(`Skills root is not a directory: ${target}`);
|
|
99
|
+
const skills = readdirSync(target, { withFileTypes: true })
|
|
100
|
+
.filter((entry) => entry.isDirectory())
|
|
101
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
102
|
+
const files = [];
|
|
103
|
+
const failures = [];
|
|
104
|
+
for (const skill of skills) {
|
|
105
|
+
const recipeDir = join(target, skill.name, "recipes");
|
|
106
|
+
if (!existsSync(recipeDir)) continue;
|
|
107
|
+
const direct = readdirSync(recipeDir, { withFileTypes: true });
|
|
108
|
+
const byStem = new Map();
|
|
109
|
+
for (const entry of direct) {
|
|
110
|
+
const path = join(recipeDir, entry.name);
|
|
111
|
+
if (entry.isDirectory()) {
|
|
112
|
+
for (const nested of nestedRecipeFiles(path)) {
|
|
113
|
+
failures.push({
|
|
114
|
+
file: nested,
|
|
115
|
+
ok: false,
|
|
116
|
+
error: `Nested Skill Recipe files are not allowed: ${relative(recipeDir, nested)}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (!entry.isFile() || !/\.(?:json|md)$/.test(entry.name)) continue;
|
|
122
|
+
files.push(path);
|
|
123
|
+
const stem = basename(entry.name, extname(entry.name));
|
|
124
|
+
const previous = byStem.get(stem);
|
|
125
|
+
if (previous) {
|
|
126
|
+
failures.push({
|
|
127
|
+
file: path,
|
|
128
|
+
ok: false,
|
|
129
|
+
error: `Skill Recipe stem collision: ${skill.name}/${stem} has both ${extname(previous)} and ${extname(path)} files`,
|
|
130
|
+
});
|
|
131
|
+
} else byStem.set(stem, path);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let skillContext = packageSkillContext;
|
|
135
|
+
try {
|
|
136
|
+
skillContext = createActiveSkillRecipeContext(
|
|
137
|
+
skills.map((entry) => ({ name: entry.name, baseDir: join(target, entry.name) })),
|
|
138
|
+
);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
failures.push({
|
|
141
|
+
file: target,
|
|
142
|
+
ok: false,
|
|
143
|
+
error: error instanceof Error ? error.message : String(error),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
files: files.sort((a, b) => a.localeCompare(b)),
|
|
148
|
+
failures,
|
|
149
|
+
skillContext,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function collectStrings(value, out = []) {
|
|
154
|
+
if (typeof value === "string") out.push(value);
|
|
155
|
+
else if (Array.isArray(value)) value.forEach((item) => collectStrings(item, out));
|
|
156
|
+
else if (value && typeof value === "object")
|
|
157
|
+
Object.values(value).forEach((item) => collectStrings(item, out));
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
|
|
66
161
|
function collectTemplateStrings(value, out = []) {
|
|
67
162
|
if (typeof value === "string") out.push(value);
|
|
68
163
|
else if (Array.isArray(value)) value.forEach((item) => collectTemplateStrings(item, out));
|
|
@@ -105,24 +200,35 @@ function validateArtifactDeclarations(config) {
|
|
|
105
200
|
|
|
106
201
|
function validateHelperPaths(file, config) {
|
|
107
202
|
const diagnostics = [];
|
|
203
|
+
const skillDir = dirname(dirname(file));
|
|
108
204
|
for (const template of collectTemplateStrings(config.template)) {
|
|
109
205
|
if (/(^|\s)(?:node\s+)?scripts\/[\w.-]+\.mjs/.test(template))
|
|
110
|
-
diagnostics.push("template: helper scripts must be referenced through {
|
|
111
|
-
for (const match of template.matchAll(/\{
|
|
112
|
-
const
|
|
113
|
-
if (!existsSync(
|
|
114
|
-
diagnostics.push(`template: referenced helper
|
|
206
|
+
diagnostics.push("template: Skill helper scripts must be referenced through {skill_dir}/scripts");
|
|
207
|
+
for (const match of template.matchAll(/\{skill_dir\}\/([^\s"']+)/g)) {
|
|
208
|
+
const target = match[1].replace(/[),;]+$/, "");
|
|
209
|
+
if (!existsSync(join(skillDir, target)))
|
|
210
|
+
diagnostics.push(`template: referenced Skill helper not found: ${target}`);
|
|
115
211
|
}
|
|
116
212
|
}
|
|
117
213
|
return diagnostics;
|
|
118
214
|
}
|
|
119
215
|
|
|
216
|
+
function validatePortablePaths(config) {
|
|
217
|
+
const diagnostics = [];
|
|
218
|
+
for (const value of collectStrings(config)) {
|
|
219
|
+
if (/^(?:\/home\/|\/Users\/|[A-Za-z]:[\\/])/.test(value))
|
|
220
|
+
diagnostics.push(`recipe: must not use a machine-local absolute path: ${value}`);
|
|
221
|
+
}
|
|
222
|
+
return diagnostics;
|
|
223
|
+
}
|
|
224
|
+
|
|
120
225
|
function qaDiagnostics(file, config) {
|
|
121
226
|
const diagnostics = [];
|
|
122
227
|
const warnings = [];
|
|
123
228
|
if (config.mailbox !== undefined)
|
|
124
229
|
diagnostics.push("recipe.mailbox was removed; use control actions and Trace events");
|
|
125
230
|
diagnostics.push(...validateArtifactDeclarations(config));
|
|
231
|
+
diagnostics.push(...validatePortablePaths(config));
|
|
126
232
|
diagnostics.push(...validateHelperPaths(file, config));
|
|
127
233
|
const platformSpecificTemplate = collectTemplateStrings(config.template).some(
|
|
128
234
|
(template) =>
|
|
@@ -139,12 +245,16 @@ function qaOk(qaReport) {
|
|
|
139
245
|
return qaReport.diagnostics.length === 0 && qaReport.warnings.length === 0;
|
|
140
246
|
}
|
|
141
247
|
|
|
142
|
-
function validateFile(file, qa = false) {
|
|
248
|
+
function validateFile(file, qa = false, skillContext = packageSkillContext) {
|
|
143
249
|
try {
|
|
144
|
-
const
|
|
250
|
+
const rawConfig = readRawRecipeConfig(file);
|
|
251
|
+
const config = readResolvedRecipeConfig(file, [], { skillContext });
|
|
145
252
|
if (!config?.template)
|
|
146
253
|
throw new Error("Recipe must define a non-empty template.");
|
|
147
|
-
const
|
|
254
|
+
const expectedName = basename(file, extname(file));
|
|
255
|
+
if (config.name !== expectedName)
|
|
256
|
+
throw new Error(`Recipe identity mismatch: expected ${expectedName}, received ${config.name ?? "<none>"}`);
|
|
257
|
+
const qaReport = qa ? qaDiagnostics(file, rawConfig) : { diagnostics: [], warnings: [] };
|
|
148
258
|
return {
|
|
149
259
|
file,
|
|
150
260
|
ok: qaOk(qaReport),
|
|
@@ -183,13 +293,19 @@ function validateFile(file, qa = false) {
|
|
|
183
293
|
export function validateRecipes(argv) {
|
|
184
294
|
const targetArg = argv.find((arg) => !arg.startsWith("-"));
|
|
185
295
|
const all = argv.includes("--all");
|
|
296
|
+
const skills = argv.includes("--skills");
|
|
186
297
|
const qa = argv.includes("--qa");
|
|
187
298
|
if (!targetArg || argv.includes("--help") || argv.includes("-h")) {
|
|
188
299
|
return { help: true, ok: Boolean(targetArg), usage: validateRecipeUsage() };
|
|
189
300
|
}
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
301
|
+
const target = expandPath(targetArg);
|
|
302
|
+
const scan = skills
|
|
303
|
+
? scanSkillRecipes(target)
|
|
304
|
+
: { files: recipeFiles(target, all), failures: [], skillContext: packageSkillContext };
|
|
305
|
+
const results = [
|
|
306
|
+
...scan.failures,
|
|
307
|
+
...scan.files.map((file) => validateFile(file, qa, scan.skillContext)),
|
|
308
|
+
];
|
|
193
309
|
const failed = results.filter((result) => !result.ok).length;
|
|
194
310
|
return {
|
|
195
311
|
ok: failed === 0,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: artifacts
|
|
3
|
+
description: Deterministic artifact writing, reporting, manifests, and bundles for reusable actor workflows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Artifacts
|
|
7
|
+
|
|
8
|
+
Own reusable capabilities that turn bounded input or prior command output into declared files, reports, manifests, and artifact bundles.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
- Write or assemble caller-declared artifacts with explicit paths and overwrite policy.
|
|
13
|
+
- Produce bounded human-readable reports and machine-readable manifests.
|
|
14
|
+
- Compose validation evidence into artifact outputs without owning the validation policy.
|
|
15
|
+
|
|
16
|
+
This Skill does not own repository workflow, multi-agent review methodology, Run lifecycle, retention policy, or transport delivery. Its Recipe identity is `artifacts/<filename stem>`; Recipe files have no top-level `name`. Cross-capability composition uses exact `<skill>/<recipe>` references; helper-backed Recipes use only this Skill's `scripts/` through `{skill_dir}`.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"async": true,
|
|
3
3
|
"imports": {
|
|
4
|
-
"artifactWrite": "
|
|
5
|
-
"manifest": "
|
|
6
|
-
"manifestWrite": "
|
|
7
|
-
"validation": "
|
|
4
|
+
"artifactWrite": "artifacts/write",
|
|
5
|
+
"manifest": "artifacts/manifest",
|
|
6
|
+
"manifestWrite": "artifacts/file-write",
|
|
7
|
+
"validation": "actors/command-validate"
|
|
8
8
|
},
|
|
9
9
|
"args": [
|
|
10
10
|
"input:string",
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"async": false,
|
|
3
3
|
"args": [
|
|
4
|
-
"repo:path",
|
|
5
4
|
"artifact_path:path",
|
|
6
5
|
"mode:enum(create,overwrite,append)"
|
|
7
6
|
],
|
|
8
7
|
"defaults": {
|
|
9
|
-
"repo": "~/.pi/agent/extensions/pi-actors",
|
|
10
8
|
"mode": "create"
|
|
11
9
|
},
|
|
12
10
|
"template": {
|
|
13
|
-
"template": "{
|
|
11
|
+
"template": "{skill_dir}/scripts/artifact-utils.mjs write {artifact_path} {mode}",
|
|
14
12
|
"output": "stdout"
|
|
15
13
|
}
|
|
16
14
|
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"args": [
|
|
3
|
-
"repo:path",
|
|
4
3
|
"artifact_path:path",
|
|
5
4
|
"title:string",
|
|
6
5
|
"status:enum(draft,ready,blocked,accepted)",
|
|
7
6
|
"summary:string"
|
|
8
7
|
],
|
|
9
8
|
"defaults": {
|
|
10
|
-
"repo": "~/.pi/agent/extensions/pi-actors",
|
|
11
9
|
"title": "Artifact",
|
|
12
10
|
"status": "draft",
|
|
13
11
|
"summary": "Machine-readable artifact manifest."
|
|
14
12
|
},
|
|
15
|
-
"template": "{
|
|
13
|
+
"template": "{skill_dir}/scripts/artifact-utils.mjs manifest {artifact_path} {title} {status} {summary}"
|
|
16
14
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"async": true,
|
|
3
3
|
"imports": {
|
|
4
|
-
"normalizer": "subagent-normalize
|
|
5
|
-
"artifact": "subagent-artifact
|
|
6
|
-
"writer": "
|
|
4
|
+
"normalizer": "swarm/subagent-normalize",
|
|
5
|
+
"artifact": "swarm/subagent-artifact",
|
|
6
|
+
"writer": "artifacts/file-write"
|
|
7
7
|
},
|
|
8
8
|
"args": [
|
|
9
9
|
"input:string",
|