@llblab/pi-actors 0.45.1 → 0.46.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.
Files changed (228) hide show
  1. package/AGENTS.md +9 -7
  2. package/BACKLOG.md +582 -0
  3. package/CHANGELOG.md +17 -1
  4. package/README.md +27 -13
  5. package/dist/fixtures/protocol/recipe-summary.json +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/lib/async-runs.d.ts +5 -1
  8. package/dist/lib/async-runs.js +26 -24
  9. package/dist/lib/automatic-review-runtime.d.ts +2 -0
  10. package/dist/lib/automatic-review-runtime.js +12 -5
  11. package/dist/lib/draft-sleep.js +0 -1
  12. package/dist/lib/execution.d.ts +1 -0
  13. package/dist/lib/execution.js +1 -0
  14. package/dist/lib/extension-runtime.d.ts +1 -1
  15. package/dist/lib/extension-runtime.js +26 -4
  16. package/dist/lib/inspector.js +46 -7
  17. package/dist/lib/paths.d.ts +0 -1
  18. package/dist/lib/paths.js +0 -7
  19. package/dist/lib/prompts.d.ts +1 -1
  20. package/dist/lib/prompts.js +4 -4
  21. package/dist/lib/recipes-context.d.ts +12 -3
  22. package/dist/lib/recipes-context.js +30 -6
  23. package/dist/lib/recipes-discovery.d.ts +18 -0
  24. package/dist/lib/recipes-discovery.js +95 -22
  25. package/dist/lib/recipes-references.d.ts +42 -9
  26. package/dist/lib/recipes-references.js +248 -135
  27. package/dist/lib/registry.d.ts +14 -1
  28. package/dist/lib/registry.js +110 -87
  29. package/dist/lib/runtime.d.ts +30 -4
  30. package/dist/lib/runtime.js +74 -12
  31. package/dist/lib/tools-inspect.d.ts +3 -1
  32. package/dist/lib/tools-inspect.js +56 -9
  33. package/dist/lib/tools-local.d.ts +2 -0
  34. package/dist/lib/tools-local.js +5 -2
  35. package/dist/lib/tools-response.js +2 -0
  36. package/dist/lib/tools-spawn.d.ts +2 -0
  37. package/dist/lib/tools-spawn.js +24 -52
  38. package/dist/lib/tools.d.ts +4 -1
  39. package/dist/lib/tools.js +2 -0
  40. package/dist/scripts/build-dist.mjs +13 -4
  41. package/dist/skills/actors/SKILL.md +8 -8
  42. package/dist/skills/actors/recipes/recipe-validate.json +11 -0
  43. package/{recipes/utility-coordinator-lock-snapshot.json → dist/skills/actors/recipes/resource-locker-snapshot.json} +1 -3
  44. package/dist/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
  45. package/dist/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
  46. package/dist/skills/actors/recipes/run-summary.json +9 -0
  47. package/dist/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -2
  48. package/dist/skills/actors/scripts/run-utils.mjs +164 -0
  49. package/{scripts → dist/skills/actors/scripts}/validate-recipe.mjs +134 -17
  50. package/dist/skills/artifacts/SKILL.md +16 -0
  51. package/{recipes/pipeline-artifact-bundle.json → dist/skills/artifacts/recipes/bundle.json} +4 -4
  52. package/dist/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
  53. package/dist/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
  54. package/{recipes/pipeline-artifact-report.json → dist/skills/artifacts/recipes/report.json} +2 -2
  55. package/dist/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
  56. package/dist/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  57. package/dist/skills/media/SKILL.md +16 -0
  58. package/dist/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
  59. package/{recipes/music-player.json → dist/skills/media/recipes/player.json} +1 -3
  60. package/dist/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
  61. package/dist/skills/media/scripts/media-utils.mjs +47 -0
  62. package/dist/{scripts → skills/media/scripts}/music-player.mjs +9 -3
  63. package/dist/skills/project-work/SKILL.md +16 -0
  64. package/dist/skills/project-work/recipes/changelog-section.json +11 -0
  65. package/{recipes/pipeline-docs-maintenance.json → dist/skills/project-work/recipes/docs-maintenance.json} +4 -4
  66. package/dist/skills/project-work/recipes/package-summary.json +9 -0
  67. package/{recipes/pipeline-release-readiness.json → dist/skills/project-work/recipes/release-readiness.json} +6 -6
  68. package/dist/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
  69. package/{recipes/pipeline-repo-health.json → dist/skills/project-work/recipes/repo-health.json} +6 -6
  70. package/{recipes/pipeline-async-run-ops.json → dist/skills/project-work/recipes/run-ops.json} +3 -3
  71. package/dist/skills/project-work/recipes/skill-summary.json +11 -0
  72. package/dist/skills/project-work/scripts/project-utils.mjs +89 -0
  73. package/dist/skills/recipe-memory/SKILL.md +16 -0
  74. package/dist/skills/swarm/SKILL.md +4 -4
  75. package/{recipes/pipeline-architect-coordinator.json → dist/skills/swarm/recipes/architect.json} +5 -5
  76. package/{recipes/pipeline-checkpoint-continuation.json → dist/skills/swarm/recipes/checkpoint-continuation.json} +3 -3
  77. package/dist/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
  78. package/dist/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
  79. package/dist/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
  80. package/{recipes/pipeline-research-synthesis.json → dist/skills/swarm/recipes/research-synthesis.json} +6 -6
  81. package/{recipes/pipeline-review-readiness.json → dist/skills/swarm/recipes/review-readiness.json} +1 -1
  82. package/{recipes/subagents-prompts.json → dist/skills/swarm/recipes/subagent-prompts.json} +1 -1
  83. package/{recipes → dist/skills/swarm/recipes}/subagent-quorum.json +1 -1
  84. package/dist/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
  85. package/docs/actor-inspector.md +4 -3
  86. package/docs/async-runs.md +2 -2
  87. package/docs/recipe-library.md +23 -23
  88. package/docs/releasing.md +2 -2
  89. package/docs/template-recipes.md +32 -14
  90. package/docs/tool-registry.md +10 -4
  91. package/fixtures/protocol/recipe-summary.json +1 -1
  92. package/index.ts +2 -1
  93. package/lib/async-runs.ts +52 -25
  94. package/lib/automatic-review-runtime.ts +16 -3
  95. package/lib/draft-sleep.ts +0 -1
  96. package/lib/execution.ts +2 -0
  97. package/lib/extension-runtime.ts +42 -4
  98. package/lib/inspector.ts +57 -11
  99. package/lib/paths.ts +0 -7
  100. package/lib/prompts.ts +4 -4
  101. package/lib/recipes-context.ts +51 -6
  102. package/lib/recipes-discovery.ts +164 -24
  103. package/lib/recipes-references.ts +359 -146
  104. package/lib/registry.ts +185 -94
  105. package/lib/runtime.ts +109 -17
  106. package/lib/tools-inspect.ts +77 -10
  107. package/lib/tools-local.ts +9 -1
  108. package/lib/tools-response.ts +2 -0
  109. package/lib/tools-spawn.ts +38 -74
  110. package/lib/tools.ts +4 -1
  111. package/package.json +2 -4
  112. package/scripts/build-dist.mjs +13 -4
  113. package/skills/actors/SKILL.md +8 -8
  114. package/skills/actors/recipes/recipe-validate.json +11 -0
  115. package/{dist/recipes/utility-coordinator-lock-snapshot.json → skills/actors/recipes/resource-locker-snapshot.json} +1 -3
  116. package/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
  117. package/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
  118. package/skills/actors/recipes/run-summary.json +9 -0
  119. package/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -2
  120. package/skills/actors/scripts/run-utils.mjs +164 -0
  121. package/{dist → skills/actors}/scripts/validate-recipe.mjs +134 -17
  122. package/skills/artifacts/SKILL.md +16 -0
  123. package/{dist/recipes/pipeline-artifact-bundle.json → skills/artifacts/recipes/bundle.json} +4 -4
  124. package/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
  125. package/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
  126. package/{dist/recipes/pipeline-artifact-report.json → skills/artifacts/recipes/report.json} +2 -2
  127. package/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
  128. package/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  129. package/skills/media/SKILL.md +16 -0
  130. package/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
  131. package/{dist/recipes/music-player.json → skills/media/recipes/player.json} +1 -3
  132. package/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
  133. package/skills/media/scripts/media-utils.mjs +47 -0
  134. package/{scripts → skills/media/scripts}/music-player.mjs +9 -3
  135. package/skills/project-work/SKILL.md +16 -0
  136. package/skills/project-work/recipes/changelog-section.json +11 -0
  137. package/{dist/recipes/pipeline-docs-maintenance.json → skills/project-work/recipes/docs-maintenance.json} +4 -4
  138. package/skills/project-work/recipes/package-summary.json +9 -0
  139. package/{dist/recipes/pipeline-release-readiness.json → skills/project-work/recipes/release-readiness.json} +6 -6
  140. package/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
  141. package/{dist/recipes/pipeline-repo-health.json → skills/project-work/recipes/repo-health.json} +6 -6
  142. package/{dist/recipes/pipeline-async-run-ops.json → skills/project-work/recipes/run-ops.json} +3 -3
  143. package/skills/project-work/recipes/skill-summary.json +11 -0
  144. package/skills/project-work/scripts/project-utils.mjs +89 -0
  145. package/skills/recipe-memory/SKILL.md +16 -0
  146. package/skills/swarm/SKILL.md +4 -4
  147. package/{dist/recipes/pipeline-architect-coordinator.json → skills/swarm/recipes/architect.json} +5 -5
  148. package/{dist/recipes/pipeline-checkpoint-continuation.json → skills/swarm/recipes/checkpoint-continuation.json} +3 -3
  149. package/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
  150. package/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
  151. package/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
  152. package/{dist/recipes/pipeline-research-synthesis.json → skills/swarm/recipes/research-synthesis.json} +6 -6
  153. package/{dist/recipes/pipeline-review-readiness.json → skills/swarm/recipes/review-readiness.json} +1 -1
  154. package/{dist/recipes/subagents-prompts.json → skills/swarm/recipes/subagent-prompts.json} +1 -1
  155. package/{dist → skills/swarm}/recipes/subagent-quorum.json +1 -1
  156. package/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
  157. package/dist/recipes/utility-changelog-section.json +0 -13
  158. package/dist/recipes/utility-package-summary.json +0 -11
  159. package/dist/recipes/utility-run-summary.json +0 -11
  160. package/dist/recipes/utility-skill-summary.json +0 -13
  161. package/dist/recipes/utility-validate-recipe.json +0 -13
  162. package/dist/scripts/executable-block-style.d.mts +0 -1
  163. package/dist/scripts/executable-block-style.mjs +0 -73
  164. package/dist/scripts/recipe-utils.mjs +0 -404
  165. package/dist/scripts/release-gates.mjs +0 -281
  166. package/recipes/utility-changelog-section.json +0 -13
  167. package/recipes/utility-package-summary.json +0 -11
  168. package/recipes/utility-run-summary.json +0 -11
  169. package/recipes/utility-skill-summary.json +0 -13
  170. package/recipes/utility-validate-recipe.json +0 -13
  171. package/scripts/executable-block-style.d.mts +0 -1
  172. package/scripts/executable-block-style.mjs +0 -73
  173. package/scripts/recipe-utils.mjs +0 -404
  174. package/scripts/release-gates.mjs +0 -281
  175. /package/dist/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
  176. /package/dist/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
  177. /package/dist/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
  178. /package/dist/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
  179. /package/dist/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
  180. /package/dist/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
  181. /package/dist/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
  182. /package/dist/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
  183. /package/dist/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
  184. /package/dist/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
  185. /package/dist/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
  186. /package/dist/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
  187. /package/dist/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
  188. /package/dist/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
  189. /package/dist/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
  190. /package/dist/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
  191. /package/dist/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
  192. /package/dist/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
  193. /package/dist/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
  194. /package/dist/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
  195. /package/dist/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
  196. /package/dist/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
  197. /package/dist/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
  198. /package/dist/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
  199. /package/dist/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
  200. /package/dist/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
  201. /package/dist/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
  202. /package/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
  203. /package/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
  204. /package/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
  205. /package/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
  206. /package/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
  207. /package/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
  208. /package/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
  209. /package/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
  210. /package/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
  211. /package/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
  212. /package/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
  213. /package/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
  214. /package/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
  215. /package/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
  216. /package/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
  217. /package/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
  218. /package/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
  219. /package/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
  220. /package/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
  221. /package/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
  222. /package/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
  223. /package/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
  224. /package/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
  225. /package/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
  226. /package/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
  227. /package/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
  228. /package/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
@@ -1,11 +0,0 @@
1
- {
2
- "args": [
3
- "package_json:path",
4
- "repo:path"
5
- ],
6
- "defaults": {
7
- "package_json": "package.json",
8
- "repo": "~/.pi/agent/extensions/pi-actors"
9
- },
10
- "template": "{repo}/scripts/recipe-utils.mjs package-summary {package_json}"
11
- }
@@ -1,11 +0,0 @@
1
- {
2
- "args": [
3
- "repo:path",
4
- "state_root:path"
5
- ],
6
- "defaults": {
7
- "repo": "~/.pi/agent/extensions/pi-actors",
8
- "state_root": "~/.pi/agent/tmp/pi-actors/runs"
9
- },
10
- "template": "{repo}/scripts/recipe-utils.mjs run-summary {state_root}"
11
- }
@@ -1,13 +0,0 @@
1
- {
2
- "args": [
3
- "skill:path",
4
- "package_json:path",
5
- "repo:path"
6
- ],
7
- "defaults": {
8
- "skill": "skills/actors/SKILL.md",
9
- "package_json": "package.json",
10
- "repo": "~/.pi/agent/extensions/pi-actors"
11
- },
12
- "template": "{repo}/scripts/recipe-utils.mjs skill-summary {skill} {package_json}"
13
- }
@@ -1,13 +0,0 @@
1
- {
2
- "args": [
3
- "target:path",
4
- "all:bool",
5
- "repo:path"
6
- ],
7
- "defaults": {
8
- "target": "recipes",
9
- "all": "true",
10
- "repo": "~/.pi/agent/extensions/pi-actors"
11
- },
12
- "template": "{repo}/scripts/validate-recipe.mjs {target} {all?--all:}"
13
- }
@@ -1 +0,0 @@
1
- export function executableBlockBlankLines(source: string): number[];
@@ -1,73 +0,0 @@
1
- /** Detect blank lines inside executable JavaScript and TypeScript blocks. */
2
-
3
- export function executableBlockBlankLines(source) {
4
- const lines = source.split(/\r?\n/u);
5
- const blanks = [];
6
- const stack = [];
7
- let blockComment = false;
8
- let currentExecutableDepth = 0;
9
- let previousCode = "";
10
- let quote;
11
- for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
12
- const line = lines[lineIndex];
13
- if (
14
- /^\s*$/u.test(line) &&
15
- currentExecutableDepth > 0 &&
16
- quote !== "`"
17
- )
18
- blanks.push(lineIndex + 1);
19
- let code = "";
20
- let regularExpression = false;
21
- for (let index = 0; index < line.length; index += 1) {
22
- const char = line[index];
23
- const next = line[index + 1];
24
- if (blockComment) {
25
- if (char === "*" && next === "/") {
26
- blockComment = false;
27
- index += 1;
28
- }
29
- continue;
30
- }
31
- if (quote) {
32
- if (char === "\\") index += 1;
33
- else if (char === quote) quote = undefined;
34
- continue;
35
- }
36
- if (regularExpression) {
37
- if (char === "\\") index += 1;
38
- else if (char === "/") regularExpression = false;
39
- continue;
40
- }
41
- if (char === "/" && next === "*") {
42
- blockComment = true;
43
- index += 1;
44
- continue;
45
- }
46
- if (char === "/" && next === "/") break;
47
- if (
48
- char === "/" &&
49
- /^(?:|.*(?:[=(,:;!&|?{}]|\b(?:return|case|throw)))\s*$/u.test(code)
50
- ) {
51
- regularExpression = true;
52
- continue;
53
- }
54
- if (char === '"' || char === "'" || char === "`") {
55
- quote = char;
56
- continue;
57
- }
58
- if (char === "{") {
59
- const prefix = code.trimEnd() || previousCode;
60
- const executable =
61
- /\)\s*$|=>\s*$|\b(?:else|try|finally|do)\s*$/u.test(prefix);
62
- stack.push(executable);
63
- if (executable) currentExecutableDepth += 1;
64
- } else if (char === "}") {
65
- if (stack.pop()) currentExecutableDepth -= 1;
66
- }
67
- code += char;
68
- }
69
- if (quote !== "`") quote = undefined;
70
- if (code.trim()) previousCode = code.trim();
71
- }
72
- return blanks;
73
- }
@@ -1,404 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Recipe utility command bundle.
5
- * Zones: recipe utilities, deterministic helper subcommands
6
- */
7
-
8
- // @ts-nocheck
9
-
10
- import {
11
- appendFileSync,
12
- existsSync,
13
- mkdirSync,
14
- readFileSync,
15
- readdirSync,
16
- statSync,
17
- writeFileSync,
18
- } from "node:fs";
19
- import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
20
-
21
- function usage() {
22
- console.error(`Usage:
23
- recipe-utils.mjs run-summary <state-root>
24
- recipe-utils.mjs run-ops-snapshot <state-root> <run-id> [lines] [stale-minutes]
25
- recipe-utils.mjs playlist <source-dir> [extensions] [max-depth] [paths|m3u|inline]
26
- recipe-utils.mjs changelog-section <file> <version>
27
- recipe-utils.mjs artifact-manifest <artifact-path> <title> <status> [summary]
28
- recipe-utils.mjs artifact-write <artifact-path> [create|overwrite|append]
29
- recipe-utils.mjs package-summary <package-json>
30
- recipe-utils.mjs skill-summary <skill-md> [package-json]`);
31
- }
32
-
33
- function fail(message) {
34
- console.error(message);
35
- process.exit(1);
36
- }
37
-
38
- function walkFiles(dir, maxDepth = 2, depth = 0, out = []) {
39
- if (depth > maxDepth || !existsSync(dir)) return out;
40
- for (const entry of readdirSync(dir)) {
41
- const path = join(dir, entry);
42
- const stat = statSync(path);
43
- if (stat.isDirectory()) walkFiles(path, maxDepth, depth + 1, out);
44
- else if (stat.isFile()) out.push(path);
45
- }
46
- return out;
47
- }
48
-
49
- function readJson(file) {
50
- if (!existsSync(file)) return undefined;
51
- try {
52
- return JSON.parse(readFileSync(file, "utf8"));
53
- } catch {
54
- return undefined;
55
- }
56
- }
57
-
58
- function getRunStatus(run, progress, result) {
59
- if (progress?.phase) return progress.phase;
60
- if (result?.code !== undefined) return result.code === 0 ? "done" : "failed";
61
- return run.status ?? "unknown";
62
- }
63
-
64
- function collectRunSummary(rootValue) {
65
- const root = resolve(
66
- rootValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
67
- );
68
- const files = walkFiles(root, 2).filter((file) => basename(file) === "run.json");
69
- const rows = [];
70
- for (const file of files) {
71
- const run = readJson(file);
72
- if (!run) {
73
- rows.push({
74
- run: relative(root, file),
75
- status: "invalid-json",
76
- recipe: "",
77
- updated: "",
78
- });
79
- continue;
80
- }
81
- const runDir = dirname(file);
82
- const progress = readJson(join(runDir, "progress.json"));
83
- const result = readJson(join(runDir, "result.json"));
84
- rows.push({
85
- run: run.run_id ?? run.run ?? relative(root, file).split(sep)[0],
86
- status: getRunStatus(run, progress, result),
87
- recipe: run.recipe ?? run.recipe_file ?? "",
88
- updated:
89
- progress?.updatedAt ??
90
- result?.completedAt ??
91
- run.updated_at ??
92
- run.completed_at ??
93
- run.started_at ??
94
- "",
95
- });
96
- }
97
- rows.sort((a, b) =>
98
- `${a.status}:${a.run}`.localeCompare(`${b.status}:${b.run}`),
99
- );
100
- return rows;
101
- }
102
-
103
- function runSummary(rootValue) {
104
- console.log(JSON.stringify(collectRunSummary(rootValue), null, 2));
105
- }
106
-
107
- function tailJsonl(fileValue, linesValue = "80") {
108
- const file = resolve(
109
- fileValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
110
- );
111
- if (!existsSync(file)) return [];
112
- const lines = Number.parseInt(linesValue, 10);
113
- const count = Number.isFinite(lines) && lines > 0 ? lines : 80;
114
- return readFileSync(file, "utf8")
115
- .trimEnd()
116
- .split("\n")
117
- .filter(Boolean)
118
- .slice(-count)
119
- .map((line) => {
120
- try {
121
- return JSON.parse(line);
122
- } catch {
123
- return { raw: line };
124
- }
125
- });
126
- }
127
-
128
- function runOpsSnapshot(
129
- rootValue,
130
- runIdValue = "music",
131
- linesValue = "80",
132
- staleMinutesValue = "60",
133
- ) {
134
- const runs = collectRunSummary(rootValue);
135
- const root = resolve(
136
- rootValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
137
- );
138
- const inspectedRun = String(runIdValue || "music");
139
- const traceFile = join(root, inspectedRun, "trace.jsonl");
140
- const staleMs = Number(staleMinutesValue) * 60 * 1000;
141
- const now = Date.now();
142
- const recommendations = runs.flatMap((run) => {
143
- const updatedMs = Date.parse(run.updated || "");
144
- const stale =
145
- Number.isFinite(updatedMs) &&
146
- Number.isFinite(staleMs) &&
147
- now - updatedMs > staleMs;
148
- if (run.status === "running" && stale) {
149
- return [
150
- {
151
- run: run.run,
152
- reason: "running-stale",
153
- suggested_inspect: {
154
- target: `run:${run.run}`,
155
- view: "control",
156
- },
157
- },
158
- ];
159
- }
160
- if (["failed", "exited", "killed"].includes(run.status)) {
161
- return [
162
- {
163
- run: run.run,
164
- reason: `terminal-${run.status}`,
165
- suggested_inspect: { target: `run:${run.run}`, view: "trace" },
166
- },
167
- ];
168
- }
169
- return [];
170
- });
171
- console.log(
172
- JSON.stringify(
173
- {
174
- runs,
175
- inspectedRun,
176
- trace: tailJsonl(traceFile, linesValue),
177
- recommendations,
178
- },
179
- null,
180
- 2,
181
- ),
182
- );
183
- }
184
-
185
- function playlist(
186
- sourceValue,
187
- extensionsValue = ".mp3,.ogg,.wav,.flac,.m4a",
188
- maxDepthValue = "2",
189
- outputMode = "paths",
190
- ) {
191
- const source = resolve(
192
- sourceValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
193
- );
194
- const maxDepth = Number.parseInt(maxDepthValue, 10);
195
- const extensions = new Set(
196
- extensionsValue
197
- .split(",")
198
- .map((item) => item.trim().toLowerCase())
199
- .filter(Boolean),
200
- );
201
- const files = walkFiles(source, Number.isFinite(maxDepth) ? maxDepth : 2)
202
- .filter((file) => extensions.has(extname(file).toLowerCase()))
203
- .sort((a, b) => a.localeCompare(b));
204
- if (outputMode === "m3u") console.log(["#EXTM3U", ...files].join("\n"));
205
- else if (outputMode === "inline") console.log(files.join("|"));
206
- else console.log(files.join("\n"));
207
- }
208
-
209
- function artifactManifest(
210
- pathValue,
211
- title = "Artifact",
212
- status = "draft",
213
- summary = "",
214
- ) {
215
- const path = resolve(
216
- pathValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
217
- );
218
- const exists = existsSync(path);
219
- const stat = exists ? statSync(path) : undefined;
220
- console.log(
221
- JSON.stringify(
222
- {
223
- title,
224
- status,
225
- path,
226
- exists,
227
- bytes: stat?.size ?? 0,
228
- modified: stat?.mtime?.toISOString?.() ?? null,
229
- summary,
230
- },
231
- null,
232
- 2,
233
- ),
234
- );
235
- }
236
-
237
- function artifactWrite(pathValue, mode = "create") {
238
- const path = resolve(
239
- pathValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
240
- );
241
- if (!["create", "overwrite", "append"].includes(mode)) {
242
- fail(`Invalid artifact write mode: ${mode}`);
243
- }
244
- if (mode === "create" && existsSync(path)) {
245
- fail(`Artifact already exists: ${path}`);
246
- }
247
- const content = readFileSync(0, "utf8");
248
- mkdirSync(dirname(path), { recursive: true });
249
- if (mode === "append") appendFileSync(path, content);
250
- else writeFileSync(path, content, "utf8");
251
- const stat = statSync(path);
252
- console.log(
253
- JSON.stringify({ path, mode, bytes: stat.size, written: true }, null, 2),
254
- );
255
- }
256
-
257
- function packageSummary(fileValue = "package.json") {
258
- const file = resolve(
259
- fileValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
260
- );
261
- const pkg = readJson(file);
262
- if (!pkg) fail(`Package JSON not found or invalid: ${fileValue}`);
263
- const scripts =
264
- pkg.scripts && typeof pkg.scripts === "object"
265
- ? Object.keys(pkg.scripts).sort()
266
- : [];
267
- const dependencies =
268
- pkg.dependencies && typeof pkg.dependencies === "object"
269
- ? Object.keys(pkg.dependencies).sort()
270
- : [];
271
- const devDependencies =
272
- pkg.devDependencies && typeof pkg.devDependencies === "object"
273
- ? Object.keys(pkg.devDependencies).sort()
274
- : [];
275
- console.log(
276
- JSON.stringify(
277
- {
278
- name: pkg.name ?? "",
279
- version: pkg.version ?? "",
280
- type: pkg.type ?? "",
281
- private: Boolean(pkg.private),
282
- packageManager: pkg.packageManager ?? "",
283
- files: Array.isArray(pkg.files) ? pkg.files : [],
284
- bin: pkg.bin ?? null,
285
- main: pkg.main ?? "",
286
- exports: pkg.exports ?? null,
287
- scripts,
288
- dependencyCount: dependencies.length,
289
- devDependencyCount: devDependencies.length,
290
- dependencies,
291
- devDependencies,
292
- },
293
- null,
294
- 2,
295
- ),
296
- );
297
- }
298
-
299
- function parseSkillFrontmatter(content) {
300
- const frontmatter = content.match(/^---\n([\s\S]*?)\n---/)?.[1] ?? "";
301
- const fields = {};
302
- for (const line of frontmatter.split(/\r?\n/)) {
303
- const match = line.match(/^([A-Za-z_][\w-]*):\s*(.*)$/);
304
- if (match) fields[match[1]] = match[2].trim();
305
- }
306
- return { frontmatter, fields };
307
- }
308
-
309
- function skillSummary(skillValue, packageValue = "package.json") {
310
- const skillFile = resolve(
311
- skillValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
312
- );
313
- const packageFile = resolve(
314
- packageValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
315
- );
316
- const content = readFileSync(skillFile, "utf8");
317
- const pkg = readJson(packageFile) ?? {};
318
- const { frontmatter, fields } = parseSkillFrontmatter(content);
319
- const scalarLines = frontmatter
320
- .split(/\r?\n/)
321
- .filter((line) => /^\w+:\s*\S/.test(line));
322
- const extraColonLines = scalarLines.filter(
323
- (line) => (line.match(/:/g) ?? []).length > 1,
324
- );
325
- const body = content.replace(/^---\n[\s\S]*?\n---\n?/, "");
326
- const version =
327
- fields.version ??
328
- frontmatter.match(/^\s+version:\s*([^\n]+)\s*$/m)?.[1]?.trim() ??
329
- "";
330
- console.log(
331
- JSON.stringify(
332
- {
333
- path: skillValue,
334
- name: fields.name ?? "",
335
- description: fields.description ?? "",
336
- version,
337
- packageVersion: pkg.version ?? "",
338
- versionMatchesPackage: version === pkg.version,
339
- frontmatterExtraColonLines: extraColonLines,
340
- bodyLineCount: body.split(/\r?\n/).length,
341
- headings: body.split(/\r?\n/).filter((line) => /^#{1,6}\s/.test(line)),
342
- },
343
- null,
344
- 2,
345
- ),
346
- );
347
- }
348
-
349
- function changelogSection(fileValue, version) {
350
- const file = resolve(fileValue);
351
- const lines = readFileSync(file, "utf8").split(/\r?\n/);
352
- const start = lines.findIndex(
353
- (line) => line.startsWith("## ") && line.includes(version),
354
- );
355
- if (start < 0) fail(`Version section not found: ${version}`);
356
- let end = lines.length;
357
- for (let index = start + 1; index < lines.length; index += 1) {
358
- if (lines[index].startsWith("## ")) {
359
- end = index;
360
- break;
361
- }
362
- }
363
- console.log(lines.slice(start, end).join("\n").trimEnd());
364
- }
365
-
366
- function runRecipeUtils(argv = process.argv.slice(2)) {
367
- const [command, ...args] = argv;
368
- if (!command) {
369
- usage();
370
- process.exit(1);
371
- }
372
- if (command === "run-summary")
373
- runSummary(args[0] ?? "~/.pi/agent/tmp/pi-actors/runs");
374
- else if (command === "run-ops-snapshot")
375
- runOpsSnapshot(
376
- args[0] ?? "~/.pi/agent/tmp/pi-actors/runs",
377
- args[1] ?? "music",
378
- args[2],
379
- args[3],
380
- );
381
- else if (command === "playlist")
382
- playlist(args[0] ?? "~/Music", args[1], args[2], args[3]);
383
- else if (command === "changelog-section")
384
- changelogSection(args[0] ?? "CHANGELOG.md", args[1] ?? "Unreleased");
385
- else if (command === "artifact-manifest")
386
- artifactManifest(args[0] ?? "artifact.md", args[1], args[2], args[3]);
387
- else if (command === "artifact-write")
388
- artifactWrite(args[0] ?? "artifact.md", args[1] ?? "create");
389
- else if (command === "package-summary")
390
- packageSummary(args[0] ?? "package.json");
391
- else if (command === "skill-summary")
392
- skillSummary(args[0] ?? "skills/actors/SKILL.md", args[1] ?? "package.json");
393
- else {
394
- usage();
395
- fail(`Unknown command: ${command}`);
396
- }
397
- }
398
-
399
- try {
400
- runRecipeUtils(process.argv.slice(2));
401
- } catch (error) {
402
- console.error(error instanceof Error ? error.message : String(error));
403
- process.exit(1);
404
- }