@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
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { statSync } from "node:fs";
8
- import { join } from "node:path";
8
+ import { isAbsolute, join, relative } from "node:path";
9
9
 
10
10
  import * as AsyncRuns from "./async-runs.ts";
11
11
  import * as ControlProjection from "./control-projection.ts";
@@ -13,12 +13,14 @@ import * as Inspector from "./inspector.ts";
13
13
  import * as Limits from "./limits.ts";
14
14
  import { computeRunControlCapacity } from "./run-evidence-policy.ts";
15
15
  import * as Paths from "./paths.ts";
16
+ import type * as RecipeResolution from "./recipes-context.ts";
16
17
  import * as RecipesDiscovery from "./recipes-discovery.ts";
17
18
  import * as RecipesReferences from "./recipes-references.ts";
18
19
  import * as ReviewDiagnostics from "./review-diagnostics.ts";
19
20
  import * as RunsControls from "./runs-controls.ts";
20
21
  import * as RunControlDelivery from "./runs-control-delivery.ts";
21
22
  import * as RunsTrace from "./runs-trace.ts";
23
+ import * as Runtime from "./runtime.ts";
22
24
  import * as RuntimeIdentity from "./runtime-identity.ts";
23
25
  import * as RuntimeTriage from "./runtime-triage.ts";
24
26
  import * as Schema from "./schema.ts";
@@ -32,9 +34,10 @@ const maybeJsonText = ToolsResponse.maybeJsonText;
32
34
  export interface InspectToolDeps<TContext = unknown> {
33
35
  getRunStatus?: (runOrDir: string) => Record<string, any>;
34
36
  getTool?: (name: string) => any | undefined;
37
+ getToolStatus?: (name: string) => Record<string, unknown> | undefined;
35
38
  listRuns?: () => Array<Record<string, any>>;
36
- packagedRecipeRoot?: string;
37
39
  recipeRoot?: string;
40
+ registryStatus?: () => Runtime.RecipeRegistryStatus;
38
41
  }
39
42
 
40
43
  function runtimeStatus(): Record<string, unknown> {
@@ -192,9 +195,23 @@ function inspectRuntime(
192
195
  throw new Error("inspect runtime supports view=status, view=runs, or view=triage.");
193
196
  }
194
197
 
198
+ function portableSkillRecipePath(
199
+ file: string,
200
+ skill: string,
201
+ namespaces: Record<string, string[]>,
202
+ ): string {
203
+ const root = namespaces[skill]?.[0];
204
+ if (!root) return `<active-skill:${skill}>`;
205
+ const relation = relative(root, file);
206
+ return !relation.startsWith("..") && !isAbsolute(relation)
207
+ ? `<active-skill:${skill}>/${relation.replaceAll("\\", "/")}`
208
+ : `<active-skill:${skill}>`;
209
+ }
210
+
195
211
  function inspectRecipes(
196
212
  view: string,
197
213
  deps: InspectToolDeps,
214
+ context: unknown,
198
215
  ): Record<string, unknown> {
199
216
  if (
200
217
  view !== "status" &&
@@ -213,18 +230,67 @@ function inspectRecipes(
213
230
  }
214
231
  const discovered = RecipesDiscovery.discoverRecipeSources([
215
232
  { root: recipeRoot, defaultTool: true, mutableUsage: true },
216
- { root: deps.packagedRecipeRoot ?? Paths.getPackagedRecipeRoot() },
217
233
  ]);
218
- const skillRecipeNamespaces =
219
- RecipesReferences.getActiveSkillRecipeNamespaces();
234
+ const resolutionContext =
235
+ context && typeof context === "object" && "recipeResolutionContext" in context
236
+ ? (context as {
237
+ recipeResolutionContext?: RecipeResolution.RecipeResolutionContext;
238
+ }).recipeResolutionContext
239
+ : undefined;
240
+ const activeSkillContext =
241
+ resolutionContext?.activeSkills ??
242
+ RecipesReferences.EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT;
243
+ const skillRecipeNamespaces = RecipesReferences.getActiveSkillRecipeNamespaces(
244
+ activeSkillContext,
245
+ );
246
+ const skillInventory =
247
+ RecipesReferences.inventoryActiveSkillRecipeComponents(activeSkillContext);
248
+ const skillRecipeComponents = skillInventory.components.map((component) => ({
249
+ identity: component.identity,
250
+ source_kind: "active_skill_component",
251
+ skill: component.skill,
252
+ stem: component.stem,
253
+ imports: component.imports,
254
+ }));
255
+ const skillRecipeComponentDiagnostics = skillInventory.rejected.map(
256
+ (diagnostic) => ({
257
+ error: diagnostic.reason,
258
+ ...(diagnostic.file
259
+ ? {
260
+ file: portableSkillRecipePath(
261
+ diagnostic.file,
262
+ diagnostic.skill,
263
+ skillRecipeNamespaces,
264
+ ),
265
+ }
266
+ : {}),
267
+ skill: diagnostic.skill,
268
+ ...(diagnostic.stem ? { stem: diagnostic.stem } : {}),
269
+ }),
270
+ );
271
+ const discoverySummary = RecipesDiscovery.summarizeDiscovery(discovered);
220
272
  const summary = {
221
- ...RecipesDiscovery.summarizeDiscovery(discovered),
222
- skill_recipe_namespaces: skillRecipeNamespaces,
273
+ ...discoverySummary,
274
+ ...(deps.registryStatus
275
+ ? {
276
+ ...deps.registryStatus(),
277
+ watched_root: "~/.pi/agent/recipes",
278
+ }
279
+ : {}),
280
+ active: Array.isArray(discoverySummary.active)
281
+ ? discoverySummary.active.map((entry) => ({
282
+ ...(entry as Record<string, unknown>),
283
+ source_kind: "user_registry_capability",
284
+ }))
285
+ : discoverySummary.active,
286
+ skill_recipe_components: skillRecipeComponents,
287
+ skill_recipe_component_diagnostics: skillRecipeComponentDiagnostics,
288
+ skill_recipe_catalog_partial: skillInventory.partial,
289
+ active_skill_recipe_identities: Object.keys(skillRecipeNamespaces).sort(),
223
290
  skill_recipe_namespace_diagnostics: Object.entries(skillRecipeNamespaces)
224
291
  .filter(([, roots]) => roots.length > 1)
225
- .map(([name, roots]) => ({
292
+ .map(([name]) => ({
226
293
  name,
227
- roots,
228
294
  error: `Ambiguous active Skill Recipe namespace ${name}`,
229
295
  })),
230
296
  drafts: RecipesDiscovery.listDraftRecipes(join(recipeRoot, "drafts")),
@@ -336,6 +402,7 @@ function inspectTool(
336
402
  if (!tool) throw new Error(`registered tool not found: ${name}`);
337
403
  return {
338
404
  name,
405
+ ...(view === "status" ? deps.getToolStatus?.(name) : {}),
339
406
  description: tool.description,
340
407
  parameters: tool.parameters,
341
408
  promptSnippet: tool.promptSnippet,
@@ -386,7 +453,7 @@ export function createInspectToolDefinition<TContext = unknown>(
386
453
  if (target === "runtime") {
387
454
  details = inspectRuntime(view, input, ctx, deps);
388
455
  } else if (target === "recipes") {
389
- details = inspectRecipes(view, deps);
456
+ details = inspectRecipes(view, deps, ctx);
390
457
  } else {
391
458
  const run = parseRunTarget(target);
392
459
  if (run) details = inspectRun(run, view, input, ctx, deps);
@@ -10,6 +10,7 @@ import * as ModelContext from "./model-context.ts";
10
10
  import type { RegisteredTool } from "./config.ts";
11
11
  import * as Execution from "./execution.ts";
12
12
  import * as Prompts from "./prompts.ts";
13
+ import type * as RecipeResolution from "./recipes-context.ts";
13
14
  import * as RecipesReferences from "./recipes-references.ts";
14
15
  import * as RecipesUsage from "./recipes-usage.ts";
15
16
  import * as Schema from "./schema.ts";
@@ -18,6 +19,7 @@ import * as ToolsResponse from "./tools-response.ts";
18
19
  type JsonSchema = Schema.JsonSchema;
19
20
 
20
21
  export interface RuntimeToolContext extends ModelContext.CurrentModelContext {
22
+ recipeResolutionContext?: RecipeResolution.RecipeResolutionContext;
21
23
  cwd: string;
22
24
  sessionManager?: { getSessionId?: () => string };
23
25
  }
@@ -66,7 +68,11 @@ function formatRuntimeToolUsageHint(
66
68
  required: string[],
67
69
  includeRunId: boolean,
68
70
  ): string {
69
- const optional = cfg.args.filter((arg) => !required.includes(arg));
71
+ const optional = cfg.args.filter(
72
+ (arg) =>
73
+ !RecipesReferences.isRuntimeOwnedRecipeInput(arg) &&
74
+ !required.includes(arg),
75
+ );
70
76
  const exampleDefaults = {
71
77
  ...Schema.getExplicitToolArgDefaults(cfg.recipe?.args),
72
78
  ...cfg.defaults,
@@ -175,6 +181,7 @@ export function createRuntimeToolDefinition(
175
181
  ? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
176
182
  : Schema.getRequiredToolArgNames(requiredTemplateConfig);
177
183
  for (const arg of cfg.args) {
184
+ if (RecipesReferences.isRuntimeOwnedRecipeInput(arg)) continue;
178
185
  paramSchema[arg] = typedArgSchema(arg, cfg.argTypes?.[arg]);
179
186
  if (requiredArgs.has(arg)) required.push(arg);
180
187
  }
@@ -243,6 +250,7 @@ export function createRuntimeToolDefinition(
243
250
  values: resolveRecipeToolValues(cfg, values, ctx),
244
251
  },
245
252
  ctx.cwd,
253
+ { skillContext: ctx.recipeResolutionContext?.activeSkills },
246
254
  );
247
255
  return {
248
256
  content: [
@@ -106,6 +106,8 @@ export function compactAsyncRunStatus(value: unknown): string {
106
106
  const result = asRecord(status.result);
107
107
  const run = String(status.run ?? "<unknown>");
108
108
  const tokens = [`run=${run}`, `status=${String(status.status ?? "unknown")}`];
109
+ if (status.launch_kind)
110
+ tokens.push(`launch_kind=${String(status.launch_kind)}`);
109
111
  tokens.push(...compactModelPolicy(status.model_policy ?? progress.model_policy));
110
112
  if (status.tool) tokens.push(`tool=${String(status.tool)}`);
111
113
  if (status.recipe) tokens.push(`recipe=${String(status.recipe)}`);
@@ -11,12 +11,14 @@ 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 type * as RecipeResolution from "./recipes-context.ts";
15
+ import * as RecipesReferences from "./recipes-references.ts";
15
16
  import * as RecipesUsage from "./recipes-usage.ts";
16
17
  import * as Schema from "./schema.ts";
17
18
  import * as ToolsResponse from "./tools-response.ts";
18
19
 
19
20
  export interface SpawnToolContext extends ModelContext.CurrentModelContext {
21
+ recipeResolutionContext?: RecipeResolution.RecipeResolutionContext;
20
22
  cwd: string;
21
23
  sessionManager?: { getSessionId?: () => string };
22
24
  }
@@ -28,22 +30,6 @@ function getRunOwnerId(ctx: SpawnToolContext): string | undefined {
28
30
  return ctx.sessionManager?.getSessionId?.();
29
31
  }
30
32
 
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
33
  function draftRecipeName(run: string): string {
48
34
  return `${run.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "spawn"}.json`;
49
35
  }
@@ -93,22 +79,6 @@ function writeSpawnDraftRecipe(
93
79
  return path;
94
80
  }
95
81
 
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
82
  function runIdFromTarget(target: string | undefined): string | undefined {
113
83
  if (!target) return undefined;
114
84
  if (!target.startsWith("run:")) {
@@ -138,11 +108,9 @@ export function createSpawnToolDefinition<
138
108
  "Optional Run identity in exact run:<id> form.",
139
109
  ),
140
110
  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.",
111
+ "Optional Recipe reference as <skill>/<recipe> or an explicit .json/.md file path.",
145
112
  ),
113
+ recipe: Schema.stringSchema("Alias for file."),
146
114
  template: Schema.unionSchema([
147
115
  Schema.stringSchema("Inline command template string"),
148
116
  Schema.arraySchema(
@@ -186,43 +154,39 @@ export function createSpawnToolDefinition<
186
154
  : typeof input.recipe === "string"
187
155
  ? input.recipe
188
156
  : 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
- }
157
+ const meta = AsyncRuns.startRun(
158
+ {
159
+ file: recipe,
160
+ launch_source: "spawn",
161
+ launch_correlation: { tool_call_id: toolCallId },
162
+ ownerId: getRunOwnerId(ctx),
163
+ ...(input.transport_context
164
+ ? { transport_context: asRecord(input.transport_context) } : {}),
165
+ run_id: runId,
166
+ ...(input.template !== undefined
167
+ ? {
168
+ template:
169
+ input.template as AsyncRuns.AsyncRunStartParams["template"],
170
+ }
171
+ : {}),
172
+ values: ModelContext.withCurrentModelValues(
173
+ asRecord(input.values),
174
+ ctx,
175
+ ),
176
+ ...(input.artifacts &&
177
+ typeof input.artifacts === "object" &&
178
+ !Array.isArray(input.artifacts)
179
+ ? {
180
+ artifacts: input.artifacts as Record<
181
+ string,
182
+ AsyncRuns.RunArtifactDeclaration
183
+ >,
184
+ }
185
+ : {}),
186
+ },
187
+ ctx.cwd,
188
+ { skillContext: ctx.recipeResolutionContext?.activeSkills },
189
+ );
226
190
  const draftRecipe = writeSpawnDraftRecipe(input, meta);
227
191
  const nextActions = ToolsResponse.runNextActions(meta.run);
228
192
  const details = {
package/lib/tools.ts CHANGED
@@ -25,6 +25,7 @@ export interface CoreActorToolDefinitionDeps<
25
25
  configPath: string;
26
26
  getActiveTools: () => string[];
27
27
  getRuntimeTool: (name: string) => unknown;
28
+ getRuntimeToolStatus: (name: string) => Record<string, unknown> | undefined;
28
29
  handleRuntimeControl?: (
29
30
  action: string,
30
31
  input: unknown,
@@ -32,7 +33,7 @@ export interface CoreActorToolDefinitionDeps<
32
33
  registryRuntime: Pick<
33
34
  RegisterToolRuntimeDeps<TContext>,
34
35
  "getToolNameBlocker" | "getTools" | "notify" | "registerRuntimeTool"
35
- >;
36
+ > & { getStatus(): import("./runtime.ts").RecipeRegistryStatus };
36
37
  setActiveTools: (toolNames: string[]) => void;
37
38
  }
38
39
 
@@ -78,6 +79,8 @@ export function createCoreActorToolDefinitions<
78
79
  }),
79
80
  ToolsInspect.createInspectToolDefinition<TContext>({
80
81
  getTool: (name) => deps.getRuntimeTool(name),
82
+ getToolStatus: deps.getRuntimeToolStatus,
83
+ registryStatus: deps.registryRuntime.getStatus,
81
84
  }),
82
85
  ];
83
86
  }
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.1",
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]);
@@ -19,9 +19,9 @@ Use the swarm skill separately for decomposition, quorum design, reviewer lenses
19
19
  - `spawn`: create one Run from a Recipe or inline command template.
20
20
  - `message`: send one actor-local Control to `run:<id>`, or the reserved review actions to `runtime`.
21
21
  - `inspect`: inspect `run:<id>`, `runtime`, `recipes`, or `tool:<name>`.
22
- - `register_tool`: persist a trusted capability; it does not address a running actor.
22
+ - `register_tool`: persist a trusted capability; it does not address a running actor. Trust current-session callability only when its result says `callable_now: true`.
23
23
 
24
- A Run target exposes exactly three inspect views: `recipe`, `trace`, and `control`.
24
+ A Run target exposes exactly three inspect views: `recipe`, `trace`, and `control`. Spawning a user Recipe is still a Recipe launch (`launch_kind: "spawn"`), not evidence that its registered tool was exposed or invoked; registered-tool execution reports `launch_kind: "tool"`, and `inspect target=tool:<name> view=status` separates both usage counts.
25
25
 
26
26
  ## Recipe
27
27
 
@@ -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. A rejected component makes catalog inspection partial without blocking exact resolution of unrelated valid components in the same live session context. 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
  }