@llblab/pi-actors 0.45.1 → 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.
Files changed (212) hide show
  1. package/AGENTS.md +9 -7
  2. package/CHANGELOG.md +8 -1
  3. package/README.md +26 -12
  4. package/dist/fixtures/protocol/recipe-summary.json +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/lib/async-runs.d.ts +4 -1
  7. package/dist/lib/async-runs.js +22 -23
  8. package/dist/lib/automatic-review-runtime.d.ts +2 -0
  9. package/dist/lib/automatic-review-runtime.js +12 -5
  10. package/dist/lib/draft-sleep.js +0 -1
  11. package/dist/lib/extension-runtime.d.ts +1 -1
  12. package/dist/lib/extension-runtime.js +8 -2
  13. package/dist/lib/inspector.js +45 -7
  14. package/dist/lib/paths.d.ts +0 -1
  15. package/dist/lib/paths.js +0 -7
  16. package/dist/lib/prompts.d.ts +1 -1
  17. package/dist/lib/prompts.js +2 -2
  18. package/dist/lib/recipes-context.js +2 -2
  19. package/dist/lib/recipes-references.d.ts +24 -9
  20. package/dist/lib/recipes-references.js +152 -126
  21. package/dist/lib/runtime.d.ts +0 -1
  22. package/dist/lib/runtime.js +1 -3
  23. package/dist/lib/tools-inspect.d.ts +0 -1
  24. package/dist/lib/tools-inspect.js +35 -8
  25. package/dist/lib/tools-local.d.ts +2 -0
  26. package/dist/lib/tools-local.js +1 -1
  27. package/dist/lib/tools-spawn.d.ts +2 -0
  28. package/dist/lib/tools-spawn.js +24 -52
  29. package/dist/scripts/build-dist.mjs +13 -4
  30. package/dist/skills/actors/SKILL.md +6 -6
  31. package/dist/skills/actors/recipes/recipe-validate.json +11 -0
  32. package/{recipes/utility-coordinator-lock-snapshot.json → dist/skills/actors/recipes/resource-locker-snapshot.json} +1 -3
  33. package/dist/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
  34. package/dist/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
  35. package/dist/skills/actors/recipes/run-summary.json +9 -0
  36. package/dist/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -2
  37. package/dist/skills/actors/scripts/run-utils.mjs +164 -0
  38. package/{scripts → dist/skills/actors/scripts}/validate-recipe.mjs +134 -17
  39. package/dist/skills/artifacts/SKILL.md +16 -0
  40. package/{recipes/pipeline-artifact-bundle.json → dist/skills/artifacts/recipes/bundle.json} +4 -4
  41. package/dist/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
  42. package/dist/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
  43. package/{recipes/pipeline-artifact-report.json → dist/skills/artifacts/recipes/report.json} +2 -2
  44. package/dist/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
  45. package/dist/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  46. package/dist/skills/media/SKILL.md +16 -0
  47. package/dist/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
  48. package/{recipes/music-player.json → dist/skills/media/recipes/player.json} +1 -3
  49. package/dist/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
  50. package/dist/skills/media/scripts/media-utils.mjs +47 -0
  51. package/dist/{scripts → skills/media/scripts}/music-player.mjs +9 -3
  52. package/dist/skills/project-work/SKILL.md +16 -0
  53. package/dist/skills/project-work/recipes/changelog-section.json +11 -0
  54. package/{recipes/pipeline-docs-maintenance.json → dist/skills/project-work/recipes/docs-maintenance.json} +4 -4
  55. package/dist/skills/project-work/recipes/package-summary.json +9 -0
  56. package/{recipes/pipeline-release-readiness.json → dist/skills/project-work/recipes/release-readiness.json} +6 -6
  57. package/dist/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
  58. package/{recipes/pipeline-repo-health.json → dist/skills/project-work/recipes/repo-health.json} +6 -6
  59. package/{recipes/pipeline-async-run-ops.json → dist/skills/project-work/recipes/run-ops.json} +3 -3
  60. package/dist/skills/project-work/recipes/skill-summary.json +11 -0
  61. package/dist/skills/project-work/scripts/project-utils.mjs +89 -0
  62. package/dist/skills/recipe-memory/SKILL.md +16 -0
  63. package/dist/skills/swarm/SKILL.md +4 -4
  64. package/{recipes/pipeline-architect-coordinator.json → dist/skills/swarm/recipes/architect.json} +5 -5
  65. package/{recipes/pipeline-checkpoint-continuation.json → dist/skills/swarm/recipes/checkpoint-continuation.json} +3 -3
  66. package/dist/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
  67. package/dist/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
  68. package/dist/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
  69. package/{recipes/pipeline-research-synthesis.json → dist/skills/swarm/recipes/research-synthesis.json} +6 -6
  70. package/{recipes/pipeline-review-readiness.json → dist/skills/swarm/recipes/review-readiness.json} +1 -1
  71. package/{recipes/subagents-prompts.json → dist/skills/swarm/recipes/subagent-prompts.json} +1 -1
  72. package/{recipes → dist/skills/swarm/recipes}/subagent-quorum.json +1 -1
  73. package/dist/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
  74. package/docs/actor-inspector.md +4 -3
  75. package/docs/async-runs.md +2 -2
  76. package/docs/recipe-library.md +23 -23
  77. package/docs/releasing.md +2 -2
  78. package/docs/template-recipes.md +30 -14
  79. package/docs/tool-registry.md +2 -2
  80. package/fixtures/protocol/recipe-summary.json +1 -1
  81. package/index.ts +2 -1
  82. package/lib/async-runs.ts +47 -24
  83. package/lib/automatic-review-runtime.ts +16 -3
  84. package/lib/draft-sleep.ts +0 -1
  85. package/lib/extension-runtime.ts +21 -2
  86. package/lib/inspector.ts +56 -11
  87. package/lib/paths.ts +0 -7
  88. package/lib/prompts.ts +2 -2
  89. package/lib/recipes-context.ts +2 -2
  90. package/lib/recipes-references.ts +223 -134
  91. package/lib/runtime.ts +1 -5
  92. package/lib/tools-inspect.ts +42 -9
  93. package/lib/tools-local.ts +2 -0
  94. package/lib/tools-spawn.ts +37 -74
  95. package/package.json +2 -4
  96. package/scripts/build-dist.mjs +13 -4
  97. package/skills/actors/SKILL.md +6 -6
  98. package/skills/actors/recipes/recipe-validate.json +11 -0
  99. package/{dist/recipes/utility-coordinator-lock-snapshot.json → skills/actors/recipes/resource-locker-snapshot.json} +1 -3
  100. package/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
  101. package/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
  102. package/skills/actors/recipes/run-summary.json +9 -0
  103. package/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -2
  104. package/skills/actors/scripts/run-utils.mjs +164 -0
  105. package/{dist → skills/actors}/scripts/validate-recipe.mjs +134 -17
  106. package/skills/artifacts/SKILL.md +16 -0
  107. package/{dist/recipes/pipeline-artifact-bundle.json → skills/artifacts/recipes/bundle.json} +4 -4
  108. package/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
  109. package/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
  110. package/{dist/recipes/pipeline-artifact-report.json → skills/artifacts/recipes/report.json} +2 -2
  111. package/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
  112. package/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  113. package/skills/media/SKILL.md +16 -0
  114. package/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
  115. package/{dist/recipes/music-player.json → skills/media/recipes/player.json} +1 -3
  116. package/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
  117. package/skills/media/scripts/media-utils.mjs +47 -0
  118. package/{scripts → skills/media/scripts}/music-player.mjs +9 -3
  119. package/skills/project-work/SKILL.md +16 -0
  120. package/skills/project-work/recipes/changelog-section.json +11 -0
  121. package/{dist/recipes/pipeline-docs-maintenance.json → skills/project-work/recipes/docs-maintenance.json} +4 -4
  122. package/skills/project-work/recipes/package-summary.json +9 -0
  123. package/{dist/recipes/pipeline-release-readiness.json → skills/project-work/recipes/release-readiness.json} +6 -6
  124. package/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
  125. package/{dist/recipes/pipeline-repo-health.json → skills/project-work/recipes/repo-health.json} +6 -6
  126. package/{dist/recipes/pipeline-async-run-ops.json → skills/project-work/recipes/run-ops.json} +3 -3
  127. package/skills/project-work/recipes/skill-summary.json +11 -0
  128. package/skills/project-work/scripts/project-utils.mjs +89 -0
  129. package/skills/recipe-memory/SKILL.md +16 -0
  130. package/skills/swarm/SKILL.md +4 -4
  131. package/{dist/recipes/pipeline-architect-coordinator.json → skills/swarm/recipes/architect.json} +5 -5
  132. package/{dist/recipes/pipeline-checkpoint-continuation.json → skills/swarm/recipes/checkpoint-continuation.json} +3 -3
  133. package/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
  134. package/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
  135. package/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
  136. package/{dist/recipes/pipeline-research-synthesis.json → skills/swarm/recipes/research-synthesis.json} +6 -6
  137. package/{dist/recipes/pipeline-review-readiness.json → skills/swarm/recipes/review-readiness.json} +1 -1
  138. package/{dist/recipes/subagents-prompts.json → skills/swarm/recipes/subagent-prompts.json} +1 -1
  139. package/{dist → skills/swarm}/recipes/subagent-quorum.json +1 -1
  140. package/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
  141. package/dist/recipes/utility-changelog-section.json +0 -13
  142. package/dist/recipes/utility-package-summary.json +0 -11
  143. package/dist/recipes/utility-run-summary.json +0 -11
  144. package/dist/recipes/utility-skill-summary.json +0 -13
  145. package/dist/recipes/utility-validate-recipe.json +0 -13
  146. package/dist/scripts/executable-block-style.d.mts +0 -1
  147. package/dist/scripts/executable-block-style.mjs +0 -73
  148. package/dist/scripts/recipe-utils.mjs +0 -404
  149. package/dist/scripts/release-gates.mjs +0 -281
  150. package/recipes/utility-changelog-section.json +0 -13
  151. package/recipes/utility-package-summary.json +0 -11
  152. package/recipes/utility-run-summary.json +0 -11
  153. package/recipes/utility-skill-summary.json +0 -13
  154. package/recipes/utility-validate-recipe.json +0 -13
  155. package/scripts/executable-block-style.d.mts +0 -1
  156. package/scripts/executable-block-style.mjs +0 -73
  157. package/scripts/recipe-utils.mjs +0 -404
  158. package/scripts/release-gates.mjs +0 -281
  159. /package/dist/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
  160. /package/dist/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
  161. /package/dist/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
  162. /package/dist/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
  163. /package/dist/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
  164. /package/dist/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
  165. /package/dist/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
  166. /package/dist/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
  167. /package/dist/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
  168. /package/dist/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
  169. /package/dist/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
  170. /package/dist/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
  171. /package/dist/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
  172. /package/dist/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
  173. /package/dist/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
  174. /package/dist/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
  175. /package/dist/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
  176. /package/dist/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
  177. /package/dist/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
  178. /package/dist/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
  179. /package/dist/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
  180. /package/dist/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
  181. /package/dist/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
  182. /package/dist/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
  183. /package/dist/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
  184. /package/dist/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
  185. /package/dist/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
  186. /package/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
  187. /package/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
  188. /package/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
  189. /package/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
  190. /package/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
  191. /package/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
  192. /package/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
  193. /package/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
  194. /package/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
  195. /package/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
  196. /package/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
  197. /package/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
  198. /package/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
  199. /package/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
  200. /package/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
  201. /package/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
  202. /package/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
  203. /package/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
  204. /package/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
  205. /package/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
  206. /package/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
  207. /package/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
  208. /package/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
  209. /package/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
  210. /package/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
  211. /package/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
  212. /package/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
@@ -11,12 +11,13 @@ import * as AsyncRuns from "./async-runs.ts";
11
11
  import { withFileMutationLock } from "./file-state.ts";
12
12
  import * as ModelContext from "./model-context.ts";
13
13
  import * as Paths from "./paths.ts";
14
- import * as RecipesDiscovery from "./recipes-discovery.ts";
14
+ import * as RecipesReferences from "./recipes-references.ts";
15
15
  import * as RecipesUsage from "./recipes-usage.ts";
16
16
  import * as Schema from "./schema.ts";
17
17
  import * as ToolsResponse from "./tools-response.ts";
18
18
 
19
19
  export interface SpawnToolContext extends ModelContext.CurrentModelContext {
20
+ activeSkillRecipeContext?: RecipesReferences.ActiveSkillRecipeContext;
20
21
  cwd: string;
21
22
  sessionManager?: { getSessionId?: () => string };
22
23
  }
@@ -28,22 +29,6 @@ function getRunOwnerId(ctx: SpawnToolContext): string | undefined {
28
29
  return ctx.sessionManager?.getSessionId?.();
29
30
  }
30
31
 
31
- function shadowedRecipeLaunchDiagnostic(
32
- recipe: unknown,
33
- ): Record<string, unknown> | undefined {
34
- if (
35
- typeof recipe !== "string" ||
36
- recipe.includes("/") ||
37
- recipe.includes("~")
38
- )
39
- return undefined;
40
- const discovery = RecipesDiscovery.discoverRecipeSources([
41
- { root: Paths.getRecipeRoot(), defaultTool: true, mutableUsage: true },
42
- { root: Paths.getPackagedRecipeRoot(), defaultTool: false },
43
- ]);
44
- return RecipesDiscovery.getShadowedLaunchDiagnostic(discovery, recipe);
45
- }
46
-
47
32
  function draftRecipeName(run: string): string {
48
33
  return `${run.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "spawn"}.json`;
49
34
  }
@@ -93,22 +78,6 @@ function writeSpawnDraftRecipe(
93
78
  return path;
94
79
  }
95
80
 
96
- function enhanceSpawnRecipeError(error: unknown, recipe: unknown): Error {
97
- const diagnostic = shadowedRecipeLaunchDiagnostic(recipe);
98
- if (!diagnostic)
99
- return error instanceof Error ? error : new Error(String(error));
100
- const original = error instanceof Error ? error.message : String(error);
101
- return Object.assign(
102
- new Error(
103
- `${original} reason=${diagnostic.reason} active_path=${diagnostic.active_path} blocked_fallback=${diagnostic.blocked_fallback} hint=${diagnostic.hint}`,
104
- ),
105
- {
106
- ...diagnostic,
107
- original_error: original,
108
- },
109
- );
110
- }
111
-
112
81
  function runIdFromTarget(target: string | undefined): string | undefined {
113
82
  if (!target) return undefined;
114
83
  if (!target.startsWith("run:")) {
@@ -138,11 +107,9 @@ export function createSpawnToolDefinition<
138
107
  "Optional Run identity in exact run:<id> form.",
139
108
  ),
140
109
  file: Schema.stringSchema(
141
- "Optional template Recipe reference. Supports paths, bare user/adjacent/std names, std:<name>, and skill:<skill>/<recipe>.",
142
- ),
143
- recipe: Schema.stringSchema(
144
- "Alias for file; qualified Skill/std or ordinary Recipe reference to spawn.",
110
+ "Optional Recipe reference as <skill>/<recipe> or an explicit .json/.md file path.",
145
111
  ),
112
+ recipe: Schema.stringSchema("Alias for file."),
146
113
  template: Schema.unionSchema([
147
114
  Schema.stringSchema("Inline command template string"),
148
115
  Schema.arraySchema(
@@ -186,43 +153,39 @@ export function createSpawnToolDefinition<
186
153
  : typeof input.recipe === "string"
187
154
  ? input.recipe
188
155
  : undefined;
189
- let meta: AsyncRuns.AsyncRunMeta;
190
- try {
191
- meta = AsyncRuns.startRun(
192
- {
193
- file: recipe,
194
- launch_source: "spawn",
195
- launch_correlation: { tool_call_id: toolCallId },
196
- ownerId: getRunOwnerId(ctx),
197
- ...(input.transport_context
198
- ? { transport_context: asRecord(input.transport_context) } : {}),
199
- run_id: runId,
200
- ...(input.template !== undefined
201
- ? {
202
- template:
203
- input.template as AsyncRuns.AsyncRunStartParams["template"],
204
- }
205
- : {}),
206
- values: ModelContext.withCurrentModelValues(
207
- asRecord(input.values),
208
- ctx,
209
- ),
210
- ...(input.artifacts &&
211
- typeof input.artifacts === "object" &&
212
- !Array.isArray(input.artifacts)
213
- ? {
214
- artifacts: input.artifacts as Record<
215
- string,
216
- AsyncRuns.RunArtifactDeclaration
217
- >,
218
- }
219
- : {}),
220
- },
221
- ctx.cwd,
222
- );
223
- } catch (error) {
224
- throw enhanceSpawnRecipeError(error, recipe);
225
- }
156
+ const meta = AsyncRuns.startRun(
157
+ {
158
+ file: recipe,
159
+ launch_source: "spawn",
160
+ launch_correlation: { tool_call_id: toolCallId },
161
+ ownerId: getRunOwnerId(ctx),
162
+ ...(input.transport_context
163
+ ? { transport_context: asRecord(input.transport_context) } : {}),
164
+ run_id: runId,
165
+ ...(input.template !== undefined
166
+ ? {
167
+ template:
168
+ input.template as AsyncRuns.AsyncRunStartParams["template"],
169
+ }
170
+ : {}),
171
+ values: ModelContext.withCurrentModelValues(
172
+ asRecord(input.values),
173
+ ctx,
174
+ ),
175
+ ...(input.artifacts &&
176
+ typeof input.artifacts === "object" &&
177
+ !Array.isArray(input.artifacts)
178
+ ? {
179
+ artifacts: input.artifacts as Record<
180
+ string,
181
+ AsyncRuns.RunArtifactDeclaration
182
+ >,
183
+ }
184
+ : {}),
185
+ },
186
+ ctx.cwd,
187
+ { skillContext: ctx.activeSkillRecipeContext },
188
+ );
226
189
  const draftRecipe = writeSpawnDraftRecipe(input, meta);
227
190
  const nextActions = ToolsResponse.runNextActions(meta.run);
228
191
  const details = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-actors",
3
- "version": "0.45.1",
3
+ "version": "0.46.0",
4
4
  "private": false,
5
5
  "description": "Local Actor Kernel for Pi",
6
6
  "keywords": [
@@ -30,8 +30,7 @@
30
30
  "test": "node --experimental-strip-types --test --test-concurrency=1 tests/*.test.ts",
31
31
  "test:preservation": "node --experimental-strip-types --test --test-concurrency=1 tests/async-runs.test.ts tests/observability.test.ts tests/session-evidence.test.ts tests/inspector-security.test.ts tests/inspector-overlay.test.ts tests/review-control.test.ts",
32
32
  "pack:dry": "npm pack --dry-run",
33
- "recipes:qa": "node scripts/validate-recipe.mjs recipes --all --qa --summary",
34
- "release:validate": "npm run validate && node scripts/release-gates.mjs",
33
+ "recipes:qa": "node skills/actors/scripts/validate-recipe.mjs skills --skills --qa --summary",
35
34
  "validate": "npx tsc --noEmit && npm run recipes:qa && npm run build && npm run check && npm test && npm run conformance && npm run pack:dry",
36
35
  "audit:dependencies": "npm audit --audit-level=high --omit=peer",
37
36
  "build": "node scripts/build-dist.mjs",
@@ -42,7 +41,6 @@
42
41
  "dist",
43
42
  "lib",
44
43
  "scripts",
45
- "recipes",
46
44
  "skills",
47
45
  "README.md",
48
46
  "AGENTS.md",
@@ -40,12 +40,21 @@ writeFileSync(
40
40
  "utf8",
41
41
  );
42
42
 
43
- for (const dir of ["scripts", "recipes", "fixtures", "skills"]) {
43
+ for (const dir of ["scripts", "fixtures", "skills"]) {
44
44
  cpSync(dir, join("dist", dir), { recursive: true });
45
45
  }
46
46
 
47
- const builtScripts = readdirSync(join("dist", "scripts"))
48
- .filter((name) => name.endsWith(".mjs"))
49
- .map((name) => join("dist", "scripts", name));
47
+ function listModuleScripts(root) {
48
+ return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
49
+ const path = join(root, entry.name);
50
+ if (entry.isDirectory()) return listModuleScripts(path);
51
+ return entry.isFile() && entry.name.endsWith(".mjs") ? [path] : [];
52
+ });
53
+ }
54
+
55
+ const builtScripts = [
56
+ ...listModuleScripts(join("dist", "scripts")),
57
+ ...listModuleScripts(join("dist", "skills")),
58
+ ];
50
59
 
51
60
  run(process.execPath, ["--check", ...builtScripts]);
@@ -29,7 +29,7 @@ A Recipe defines execution. It may declare named typed args, inline fallbacks, c
29
29
 
30
30
  Do not declare Control for ordinary one-shot work. Runtime lifecycle actions such as `kill` stay runtime-owned and must not appear in Recipe Control declarations. Imported Recipes act as local definitions inside one Run; they do not create nested Runs unless execution explicitly spawns them.
31
31
 
32
- Prefer maintained packaged Recipes over ad hoc wrappers. Use `std:<recipe>` for exact packaged lookup and `skill:<skill>/<recipe-path>` for a component bundled with a Pi-active Skill. File-backed Recipes own `{recipe_dir}` and Skill Recipes own `{skill_dir}`; callers never pass or override these origins. Skill Recipes are components, not automatic tools. Keep model, thinking, mission, concurrency, quorum, and timeout choices caller-owned unless a Recipe documents a stable policy.
32
+ Prefer maintained Skill-owned Recipes over ad hoc wrappers. Skill Recipe identity is `<active Skill name>/<Recipe filename stem>`; Recipe files have no top-level `name`. `SKILL.md` `name` is Pi host metadata matching its directory, not an additional pi-actors identity field. Use `<skill>/<recipe>` for an exact direct component or an explicit `.json` / `.md` path. Entry paths resolve from invocation `cwd`; relative imports resolve from the importing Recipe directory. File-backed Recipes own `{recipe_dir}` and Skill Recipes own `{skill_dir}`; callers never pass or override these origins. Skill Recipes are components, not automatic tools. Keep model, thinking, mission, concurrency, quorum, and timeout choices caller-owned unless a Recipe documents a stable policy.
33
33
 
34
34
  ## Trace
35
35
 
@@ -90,11 +90,11 @@ If work may outlive the current turn, needs steering, produces artifacts, fans o
90
90
 
91
91
  ## Top Recipes
92
92
 
93
- - [Repository health](../../recipes/pipeline-repo-health.json)
94
- - [Quorum review](../../recipes/pipeline-quorum-review.json)
95
- - [Artifact bundle](../../recipes/pipeline-artifact-bundle.json)
96
- - [Music player service](../../recipes/music-player.json)
97
- - [Resource locker service](../../recipes/resource-locker.json)
93
+ - [Repository health](../project-work/recipes/repo-health.json)
94
+ - [Quorum review](../swarm/recipes/quorum-review.json)
95
+ - [Artifact bundle](../artifacts/recipes/bundle.json)
96
+ - [Music player service](../media/recipes/player.json)
97
+ - [Resource locker service](./recipes/resource-locker.json)
98
98
 
99
99
  ## Deep References
100
100
 
@@ -0,0 +1,11 @@
1
+ {
2
+ "args": [
3
+ "target:path",
4
+ "all:bool"
5
+ ],
6
+ "defaults": {
7
+ "target": "recipes",
8
+ "all": "true"
9
+ },
10
+ "template": "{skill_dir}/scripts/validate-recipe.mjs {target} {all?--all:}"
11
+ }
@@ -1,13 +1,11 @@
1
1
  {
2
2
  "args": [
3
- "repo:path",
4
3
  "state_dir:path",
5
4
  "lines:int"
6
5
  ],
7
6
  "defaults": {
8
- "repo": "~/.pi/agent/extensions/pi-actors",
9
7
  "state_dir": "~/.pi/agent/tmp/pi-actors/runs/coordinator-locker",
10
8
  "lines": "20"
11
9
  },
12
- "template": "{repo}/scripts/locker.mjs snapshot --state-dir {state_dir} --lines {lines}"
10
+ "template": "{skill_dir}/scripts/resource-locker.mjs snapshot --state-dir {state_dir} --lines {lines}"
13
11
  }
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "async": true,
3
3
  "args": [
4
- "repo:path",
5
4
  "lease_ms:int"
6
5
  ],
7
6
  "defaults": {
8
- "repo": "~/.pi/agent/extensions/pi-actors",
9
7
  "lease_ms": "600000"
10
8
  },
11
9
  "control": [
@@ -23,5 +21,5 @@
23
21
  "locks": "{state_dir}/locks.json",
24
22
  "journal": "{state_dir}/journal.jsonl"
25
23
  },
26
- "template": "{repo}/scripts/locker.mjs serve --state-dir {state_dir} --lease-ms {lease_ms}"
24
+ "template": "{skill_dir}/scripts/resource-locker.mjs serve --state-dir {state_dir} --lease-ms {lease_ms}"
27
25
  }
@@ -1,17 +1,15 @@
1
1
  {
2
2
  "args": [
3
- "repo:path",
4
3
  "state_root:path",
5
4
  "run_id:string",
6
5
  "lines:int",
7
6
  "stale_minutes:int"
8
7
  ],
9
8
  "defaults": {
10
- "repo": "~/.pi/agent/extensions/pi-actors",
11
9
  "state_root": "~/.pi/agent/tmp/pi-actors/runs",
12
10
  "run_id": "music",
13
11
  "lines": "80",
14
12
  "stale_minutes": "60"
15
13
  },
16
- "template": "{repo}/scripts/recipe-utils.mjs run-ops-snapshot {state_root} {run_id} {lines} {stale_minutes}"
14
+ "template": "{skill_dir}/scripts/run-utils.mjs run-ops-snapshot {state_root} {run_id} {lines} {stale_minutes}"
17
15
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "args": [
3
+ "state_root:path"
4
+ ],
5
+ "defaults": {
6
+ "state_root": "~/.pi/agent/tmp/pi-actors/runs"
7
+ },
8
+ "template": "{skill_dir}/scripts/run-utils.mjs run-summary {state_root}"
9
+ }
@@ -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, "dist", "lib", `${name}.js`);
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
  }
@@ -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
+ }