@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.
- package/AGENTS.md +9 -7
- package/CHANGELOG.md +8 -1
- package/README.md +26 -12
- package/dist/fixtures/protocol/recipe-summary.json +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/async-runs.d.ts +4 -1
- package/dist/lib/async-runs.js +22 -23
- package/dist/lib/automatic-review-runtime.d.ts +2 -0
- package/dist/lib/automatic-review-runtime.js +12 -5
- package/dist/lib/draft-sleep.js +0 -1
- package/dist/lib/extension-runtime.d.ts +1 -1
- package/dist/lib/extension-runtime.js +8 -2
- package/dist/lib/inspector.js +45 -7
- package/dist/lib/paths.d.ts +0 -1
- package/dist/lib/paths.js +0 -7
- package/dist/lib/prompts.d.ts +1 -1
- package/dist/lib/prompts.js +2 -2
- package/dist/lib/recipes-context.js +2 -2
- package/dist/lib/recipes-references.d.ts +24 -9
- package/dist/lib/recipes-references.js +152 -126
- package/dist/lib/runtime.d.ts +0 -1
- package/dist/lib/runtime.js +1 -3
- package/dist/lib/tools-inspect.d.ts +0 -1
- package/dist/lib/tools-inspect.js +35 -8
- package/dist/lib/tools-local.d.ts +2 -0
- package/dist/lib/tools-local.js +1 -1
- package/dist/lib/tools-spawn.d.ts +2 -0
- package/dist/lib/tools-spawn.js +24 -52
- package/dist/scripts/build-dist.mjs +13 -4
- package/dist/skills/actors/SKILL.md +6 -6
- package/dist/skills/actors/recipes/recipe-validate.json +11 -0
- package/{recipes/utility-coordinator-lock-snapshot.json → dist/skills/actors/recipes/resource-locker-snapshot.json} +1 -3
- package/dist/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
- package/dist/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
- package/dist/skills/actors/recipes/run-summary.json +9 -0
- package/dist/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -2
- package/dist/skills/actors/scripts/run-utils.mjs +164 -0
- package/{scripts → dist/skills/actors/scripts}/validate-recipe.mjs +134 -17
- package/dist/skills/artifacts/SKILL.md +16 -0
- package/{recipes/pipeline-artifact-bundle.json → dist/skills/artifacts/recipes/bundle.json} +4 -4
- package/dist/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
- package/dist/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
- package/{recipes/pipeline-artifact-report.json → dist/skills/artifacts/recipes/report.json} +2 -2
- package/dist/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
- package/dist/skills/artifacts/scripts/artifact-utils.mjs +63 -0
- package/dist/skills/media/SKILL.md +16 -0
- package/dist/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
- package/{recipes/music-player.json → dist/skills/media/recipes/player.json} +1 -3
- package/dist/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
- package/dist/skills/media/scripts/media-utils.mjs +47 -0
- package/dist/{scripts → skills/media/scripts}/music-player.mjs +9 -3
- package/dist/skills/project-work/SKILL.md +16 -0
- package/dist/skills/project-work/recipes/changelog-section.json +11 -0
- package/{recipes/pipeline-docs-maintenance.json → dist/skills/project-work/recipes/docs-maintenance.json} +4 -4
- package/dist/skills/project-work/recipes/package-summary.json +9 -0
- package/{recipes/pipeline-release-readiness.json → dist/skills/project-work/recipes/release-readiness.json} +6 -6
- package/dist/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
- package/{recipes/pipeline-repo-health.json → dist/skills/project-work/recipes/repo-health.json} +6 -6
- package/{recipes/pipeline-async-run-ops.json → dist/skills/project-work/recipes/run-ops.json} +3 -3
- package/dist/skills/project-work/recipes/skill-summary.json +11 -0
- package/dist/skills/project-work/scripts/project-utils.mjs +89 -0
- package/dist/skills/recipe-memory/SKILL.md +16 -0
- package/dist/skills/swarm/SKILL.md +4 -4
- package/{recipes/pipeline-architect-coordinator.json → dist/skills/swarm/recipes/architect.json} +5 -5
- package/{recipes/pipeline-checkpoint-continuation.json → dist/skills/swarm/recipes/checkpoint-continuation.json} +3 -3
- package/dist/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
- package/dist/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
- package/dist/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
- package/{recipes/pipeline-research-synthesis.json → dist/skills/swarm/recipes/research-synthesis.json} +6 -6
- package/{recipes/pipeline-review-readiness.json → dist/skills/swarm/recipes/review-readiness.json} +1 -1
- package/{recipes/subagents-prompts.json → dist/skills/swarm/recipes/subagent-prompts.json} +1 -1
- package/{recipes → dist/skills/swarm/recipes}/subagent-quorum.json +1 -1
- package/dist/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
- package/docs/actor-inspector.md +4 -3
- package/docs/async-runs.md +2 -2
- package/docs/recipe-library.md +23 -23
- package/docs/releasing.md +2 -2
- package/docs/template-recipes.md +30 -14
- package/docs/tool-registry.md +2 -2
- package/fixtures/protocol/recipe-summary.json +1 -1
- package/index.ts +2 -1
- package/lib/async-runs.ts +47 -24
- package/lib/automatic-review-runtime.ts +16 -3
- package/lib/draft-sleep.ts +0 -1
- package/lib/extension-runtime.ts +21 -2
- package/lib/inspector.ts +56 -11
- package/lib/paths.ts +0 -7
- package/lib/prompts.ts +2 -2
- package/lib/recipes-context.ts +2 -2
- package/lib/recipes-references.ts +223 -134
- package/lib/runtime.ts +1 -5
- package/lib/tools-inspect.ts +42 -9
- package/lib/tools-local.ts +2 -0
- package/lib/tools-spawn.ts +37 -74
- package/package.json +2 -4
- package/scripts/build-dist.mjs +13 -4
- package/skills/actors/SKILL.md +6 -6
- package/skills/actors/recipes/recipe-validate.json +11 -0
- package/{dist/recipes/utility-coordinator-lock-snapshot.json → skills/actors/recipes/resource-locker-snapshot.json} +1 -3
- package/{recipes → skills/actors/recipes}/resource-locker.json +1 -3
- package/{recipes/utility-run-ops-snapshot.json → skills/actors/recipes/run-ops-snapshot.json} +1 -3
- package/skills/actors/recipes/run-summary.json +9 -0
- package/{scripts/locker.mjs → skills/actors/scripts/resource-locker.mjs} +2 -2
- package/skills/actors/scripts/run-utils.mjs +164 -0
- package/{dist → skills/actors}/scripts/validate-recipe.mjs +134 -17
- package/skills/artifacts/SKILL.md +16 -0
- package/{dist/recipes/pipeline-artifact-bundle.json → skills/artifacts/recipes/bundle.json} +4 -4
- package/{recipes/utility-artifact-write.json → skills/artifacts/recipes/file-write.json} +1 -3
- package/{recipes/utility-artifact-manifest.json → skills/artifacts/recipes/manifest.json} +1 -3
- package/{dist/recipes/pipeline-artifact-report.json → skills/artifacts/recipes/report.json} +2 -2
- package/{recipes/pipeline-artifact-write.json → skills/artifacts/recipes/write.json} +3 -3
- package/skills/artifacts/scripts/artifact-utils.mjs +63 -0
- package/skills/media/SKILL.md +16 -0
- package/{recipes/pipeline-media-library.json → skills/media/recipes/library.json} +2 -2
- package/{dist/recipes/music-player.json → skills/media/recipes/player.json} +1 -3
- package/{recipes/utility-playlist-build.json → skills/media/recipes/playlist-build.json} +1 -3
- package/skills/media/scripts/media-utils.mjs +47 -0
- package/{scripts → skills/media/scripts}/music-player.mjs +9 -3
- package/skills/project-work/SKILL.md +16 -0
- package/skills/project-work/recipes/changelog-section.json +11 -0
- package/{dist/recipes/pipeline-docs-maintenance.json → skills/project-work/recipes/docs-maintenance.json} +4 -4
- package/skills/project-work/recipes/package-summary.json +9 -0
- package/{dist/recipes/pipeline-release-readiness.json → skills/project-work/recipes/release-readiness.json} +6 -6
- package/{recipes/pipeline-release-summary.json → skills/project-work/recipes/release-summary.json} +5 -5
- package/{dist/recipes/pipeline-repo-health.json → skills/project-work/recipes/repo-health.json} +6 -6
- package/{dist/recipes/pipeline-async-run-ops.json → skills/project-work/recipes/run-ops.json} +3 -3
- package/skills/project-work/recipes/skill-summary.json +11 -0
- package/skills/project-work/scripts/project-utils.mjs +89 -0
- package/skills/recipe-memory/SKILL.md +16 -0
- package/skills/swarm/SKILL.md +4 -4
- package/{dist/recipes/pipeline-architect-coordinator.json → skills/swarm/recipes/architect.json} +5 -5
- package/{dist/recipes/pipeline-checkpoint-continuation.json → skills/swarm/recipes/checkpoint-continuation.json} +3 -3
- package/{recipes/pipeline-development-tasking.json → skills/swarm/recipes/development-tasking.json} +4 -4
- package/{recipes/lens-swarm.json → skills/swarm/recipes/lens-review.json} +1 -1
- package/{recipes/pipeline-quorum-review.json → skills/swarm/recipes/quorum-review.json} +4 -4
- package/{dist/recipes/pipeline-research-synthesis.json → skills/swarm/recipes/research-synthesis.json} +6 -6
- package/{dist/recipes/pipeline-review-readiness.json → skills/swarm/recipes/review-readiness.json} +1 -1
- package/{dist/recipes/subagents-prompts.json → skills/swarm/recipes/subagent-prompts.json} +1 -1
- package/{dist → skills/swarm}/recipes/subagent-quorum.json +1 -1
- package/{recipes → skills/swarm/recipes}/subagent-review-coordinator.json +6 -6
- package/dist/recipes/utility-changelog-section.json +0 -13
- package/dist/recipes/utility-package-summary.json +0 -11
- package/dist/recipes/utility-run-summary.json +0 -11
- package/dist/recipes/utility-skill-summary.json +0 -13
- package/dist/recipes/utility-validate-recipe.json +0 -13
- package/dist/scripts/executable-block-style.d.mts +0 -1
- package/dist/scripts/executable-block-style.mjs +0 -73
- package/dist/scripts/recipe-utils.mjs +0 -404
- package/dist/scripts/release-gates.mjs +0 -281
- package/recipes/utility-changelog-section.json +0 -13
- package/recipes/utility-package-summary.json +0 -11
- package/recipes/utility-run-summary.json +0 -11
- package/recipes/utility-skill-summary.json +0 -13
- package/recipes/utility-validate-recipe.json +0 -13
- package/scripts/executable-block-style.d.mts +0 -1
- package/scripts/executable-block-style.mjs +0 -73
- package/scripts/recipe-utils.mjs +0 -404
- package/scripts/release-gates.mjs +0 -281
- /package/dist/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
- /package/dist/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
- /package/dist/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
- /package/dist/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
- /package/dist/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
- /package/dist/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
- /package/dist/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
- /package/dist/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
- /package/dist/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
- /package/dist/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
- /package/dist/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
- /package/{recipes/utility-validation-wrapper.json → skills/actors/recipes/command-validate.json} +0 -0
- /package/{recipes/utility-jsonl-tail.json → skills/actors/recipes/jsonl-tail.json} +0 -0
- /package/{recipes/utility-run-state-files.json → skills/actors/recipes/run-state-files.json} +0 -0
- /package/{recipes/utility-playlist-scan.json → skills/media/recipes/playlist-scan.json} +0 -0
- /package/{recipes/utility-changelog-head.json → skills/project-work/recipes/changelog-head.json} +0 -0
- /package/{recipes/utility-git-log.json → skills/project-work/recipes/git-log.json} +0 -0
- /package/{recipes/utility-git-status.json → skills/project-work/recipes/git-status.json} +0 -0
- /package/{recipes/utility-markdown-index.json → skills/project-work/recipes/markdown-index.json} +0 -0
- /package/{recipes → skills/recipe-memory/recipes}/draft-review.json +0 -0
- /package/{recipes → skills/recipe-memory/recipes}/tool-review.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-artifact.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-checkpoint.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-conflict-report.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-contradiction-map.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-critic.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-evidence-map.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-followup.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-judge.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-merge.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-normalize.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-plan.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-preflight.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-prompt.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-review.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-task-card.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-tools.json +0 -0
- /package/{recipes → skills/swarm/recipes}/subagent-verify.json +0 -0
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* Owns detection, loading, and recipe-layer expansion for template recipe files
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
8
|
-
import {
|
|
9
|
-
import { basename, dirname, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
8
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
10
9
|
|
|
11
10
|
import type {
|
|
12
11
|
CommandTemplateConfig,
|
|
@@ -29,7 +28,6 @@ export interface TemplateRecipeImportBinding {
|
|
|
29
28
|
export type TemplateRecipeImport = string | TemplateRecipeImportBinding;
|
|
30
29
|
|
|
31
30
|
export interface TemplateRecipeDefinition {
|
|
32
|
-
name?: string;
|
|
33
31
|
description?: string;
|
|
34
32
|
disabled?: boolean;
|
|
35
33
|
imports?: Record<string, TemplateRecipeImport>;
|
|
@@ -57,6 +55,7 @@ export interface TemplateRecipeDefinition {
|
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
export interface TemplateRecipeConfig extends TemplateRecipeDefinition {
|
|
58
|
+
name?: string;
|
|
60
59
|
async?: boolean;
|
|
61
60
|
recipe_dir?: string;
|
|
62
61
|
skill_dir?: string;
|
|
@@ -66,7 +65,7 @@ interface ImportedRecipe {
|
|
|
66
65
|
alias: string;
|
|
67
66
|
file: string;
|
|
68
67
|
name: string;
|
|
69
|
-
config:
|
|
68
|
+
config: TemplateRecipeConfig;
|
|
70
69
|
defaults: Record<string, unknown>;
|
|
71
70
|
values: Record<string, unknown>;
|
|
72
71
|
}
|
|
@@ -74,20 +73,25 @@ interface ImportedRecipe {
|
|
|
74
73
|
export interface TemplateRecipeContextRecord {
|
|
75
74
|
alias?: string;
|
|
76
75
|
depth: number;
|
|
77
|
-
file: string;
|
|
78
76
|
import_path: string[];
|
|
77
|
+
logical_reference: string;
|
|
79
78
|
name: string;
|
|
80
|
-
qualified_name?: string;
|
|
81
79
|
recipe: Record<string, unknown>;
|
|
82
80
|
role: "entry" | "import";
|
|
81
|
+
skill?: string;
|
|
82
|
+
source_file: string;
|
|
83
|
+
source_kind:
|
|
84
|
+
| "active_skill_component"
|
|
85
|
+
| "explicit_file_recipe"
|
|
86
|
+
| "user_registry_capability";
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
export interface ReadResolvedRecipeConfigOptions {
|
|
86
90
|
includeActorRecipeContext?: boolean;
|
|
91
|
+
skillContext?: ActiveSkillRecipeContext;
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
const RUNTIME_RECIPE_VALUE_NAMES = new Set(["recipe_dir", "skill_dir"]);
|
|
90
|
-
const activeSkillRecipeRoots = new Map<string, Set<string>>();
|
|
91
95
|
|
|
92
96
|
export interface ActiveSkillRecipeSource {
|
|
93
97
|
name: string;
|
|
@@ -95,10 +99,14 @@ export interface ActiveSkillRecipeSource {
|
|
|
95
99
|
baseDir?: string;
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
export
|
|
102
|
+
export interface ActiveSkillRecipeContext {
|
|
103
|
+
readonly namespaces: Readonly<Record<string, readonly string[]>>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function createActiveSkillRecipeContext(
|
|
99
107
|
skills: ActiveSkillRecipeSource[],
|
|
100
|
-
):
|
|
101
|
-
|
|
108
|
+
): ActiveSkillRecipeContext {
|
|
109
|
+
const rootsByName = new Map<string, Set<string>>();
|
|
102
110
|
for (const skill of skills) {
|
|
103
111
|
const name = skill.name.trim();
|
|
104
112
|
const skillDir = skill.baseDir
|
|
@@ -107,72 +115,179 @@ export function setActiveSkillRecipeSources(
|
|
|
107
115
|
? dirname(resolve(skill.filePath))
|
|
108
116
|
: undefined;
|
|
109
117
|
if (!name || !skillDir) continue;
|
|
110
|
-
const roots =
|
|
118
|
+
const roots = rootsByName.get(name) ?? new Set<string>();
|
|
111
119
|
roots.add(resolve(skillDir, "recipes"));
|
|
112
|
-
|
|
120
|
+
rootsByName.set(name, roots);
|
|
113
121
|
}
|
|
122
|
+
const namespaces = Object.fromEntries(
|
|
123
|
+
[...rootsByName.entries()]
|
|
124
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
125
|
+
.map(([name, roots]) => [name, Object.freeze([...roots].sort())]),
|
|
126
|
+
);
|
|
127
|
+
return Object.freeze({ namespaces: Object.freeze(namespaces) });
|
|
114
128
|
}
|
|
115
129
|
|
|
116
|
-
export
|
|
130
|
+
export const EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT =
|
|
131
|
+
createActiveSkillRecipeContext([]);
|
|
132
|
+
|
|
133
|
+
export function getActiveSkillRecipeNamespaces(
|
|
134
|
+
context: ActiveSkillRecipeContext,
|
|
135
|
+
): Record<string, string[]> {
|
|
117
136
|
return Object.fromEntries(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
137
|
+
Object.entries(context.namespaces).map(([name, roots]) => [
|
|
138
|
+
name,
|
|
139
|
+
[...roots],
|
|
140
|
+
]),
|
|
121
141
|
);
|
|
122
142
|
}
|
|
123
143
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
export interface ActiveSkillRecipeComponent {
|
|
145
|
+
file: string;
|
|
146
|
+
identity: string;
|
|
147
|
+
imports: Record<string, string>;
|
|
148
|
+
skill: string;
|
|
149
|
+
stem: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function nestedRecipeFiles(root: string): string[] {
|
|
153
|
+
if (!existsSync(root)) return [];
|
|
154
|
+
return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
|
|
155
|
+
const path = join(root, entry.name);
|
|
156
|
+
if (entry.isDirectory()) return nestedRecipeFiles(path);
|
|
157
|
+
return entry.isFile() && /\.(?:json|md)$/u.test(entry.name) ? [path] : [];
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function listActiveSkillRecipeComponents(
|
|
162
|
+
context: ActiveSkillRecipeContext,
|
|
163
|
+
): ActiveSkillRecipeComponent[] {
|
|
164
|
+
const components: ActiveSkillRecipeComponent[] = [];
|
|
165
|
+
for (const [skill, roots] of Object.entries(context.namespaces)) {
|
|
166
|
+
if (roots.length > 1)
|
|
167
|
+
throw new Error(`Duplicate active Skill identity ${skill}: ${roots.join(", ")}`);
|
|
168
|
+
const root = roots[0];
|
|
169
|
+
if (!root || !existsSync(root)) continue;
|
|
170
|
+
const direct = readdirSync(root, { withFileTypes: true });
|
|
171
|
+
for (const entry of direct.filter((candidate) => candidate.isDirectory())) {
|
|
172
|
+
const nested = nestedRecipeFiles(join(root, entry.name));
|
|
173
|
+
if (nested.length > 0)
|
|
174
|
+
throw new Error(`Nested Skill Recipe file is not addressable: ${nested[0]}`);
|
|
175
|
+
}
|
|
176
|
+
const files = direct
|
|
177
|
+
.filter(
|
|
178
|
+
(entry) => entry.isFile() && /\.(?:json|md)$/u.test(entry.name),
|
|
179
|
+
)
|
|
180
|
+
.map((entry) => join(root, entry.name));
|
|
181
|
+
const byStem = new Map<string, string[]>();
|
|
182
|
+
for (const file of files) {
|
|
183
|
+
const stem = getRecipeIdFromPath(file);
|
|
184
|
+
const matches = byStem.get(stem) ?? [];
|
|
185
|
+
matches.push(file);
|
|
186
|
+
byStem.set(stem, matches);
|
|
187
|
+
}
|
|
188
|
+
for (const [stem, matches] of [...byStem].sort(([a], [b]) => a.localeCompare(b))) {
|
|
189
|
+
if (!/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u.test(stem))
|
|
190
|
+
throw new Error(`Invalid Skill Recipe filename stem: ${stem}`);
|
|
191
|
+
if (matches.length > 1)
|
|
192
|
+
throw new Error(`Skill Recipe stem collision: ${skill}/${stem} has both .json and .md files`);
|
|
193
|
+
const file = matches[0];
|
|
194
|
+
const raw = readRawRecipeConfig(file);
|
|
195
|
+
if (!raw || !Object.hasOwn(raw, "template"))
|
|
196
|
+
throw new Error(`Invalid Skill Recipe component: ${skill}/${stem}`);
|
|
197
|
+
assertRecipeHasNoDeclaredName(raw);
|
|
198
|
+
components.push({
|
|
199
|
+
file,
|
|
200
|
+
identity: `${skill}/${stem}`,
|
|
201
|
+
imports: Object.fromEntries(
|
|
202
|
+
Object.entries(getRecipeImports(raw)).map(([alias, value]) => [
|
|
203
|
+
alias,
|
|
204
|
+
getImportFrom(value),
|
|
205
|
+
]),
|
|
206
|
+
),
|
|
207
|
+
skill,
|
|
208
|
+
stem,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
133
211
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
212
|
+
return components;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const SKILL_RECIPE_REFERENCE =
|
|
216
|
+
/^([a-z][a-z0-9]*(?:-[a-z0-9]+)*)\/([a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/;
|
|
217
|
+
|
|
218
|
+
function qualifiedRecipeNameForFile(
|
|
219
|
+
file: string,
|
|
220
|
+
context: ActiveSkillRecipeContext,
|
|
221
|
+
): string | undefined {
|
|
222
|
+
const path = resolve(file);
|
|
223
|
+
for (const [skillName, roots] of Object.entries(context.namespaces)) {
|
|
224
|
+
if (roots.length !== 1) continue;
|
|
225
|
+
const root = roots[0];
|
|
137
226
|
const relation = relative(root, path);
|
|
138
|
-
if (
|
|
139
|
-
|
|
227
|
+
if (
|
|
228
|
+
relation &&
|
|
229
|
+
dirname(relation) === "." &&
|
|
230
|
+
!relation.startsWith("..") &&
|
|
231
|
+
!isAbsolute(relation)
|
|
232
|
+
) {
|
|
233
|
+
return `${skillName}/${basename(relation, extname(relation))}`;
|
|
234
|
+
}
|
|
140
235
|
}
|
|
141
236
|
return undefined;
|
|
142
237
|
}
|
|
143
238
|
|
|
144
|
-
function
|
|
239
|
+
function assertRecipeReferencePrefixWasNotRemoved(value: string): void {
|
|
145
240
|
if (value.startsWith("std:")) {
|
|
146
|
-
|
|
147
|
-
|
|
241
|
+
throw new Error(
|
|
242
|
+
"std: Recipe references were removed in pi-actors 0.46.\nUse <skill>/<recipe> or an explicit .json/.md file path.",
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
if (value.startsWith("skill:")) {
|
|
246
|
+
throw new Error(
|
|
247
|
+
"skill: Recipe references were removed in pi-actors 0.46.\nUse <skill>/<recipe> without a prefix.",
|
|
148
248
|
);
|
|
149
249
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function skillRecipeCandidates(
|
|
253
|
+
value: string,
|
|
254
|
+
context: ActiveSkillRecipeContext,
|
|
255
|
+
): string[] | undefined {
|
|
256
|
+
const match = SKILL_RECIPE_REFERENCE.exec(value);
|
|
257
|
+
if (!match) return undefined;
|
|
258
|
+
const [, skillName, recipeName] = match;
|
|
259
|
+
const roots = [...(context.namespaces[skillName] ?? [])];
|
|
158
260
|
if (roots.length === 0)
|
|
159
|
-
throw new Error(`Active Skill Recipe
|
|
261
|
+
throw new Error(`Active Skill Recipe not found: ${skillName}/${recipeName}`);
|
|
160
262
|
if (roots.length > 1)
|
|
161
263
|
throw new Error(
|
|
162
|
-
`
|
|
264
|
+
`Duplicate active Skill identity ${skillName}: ${roots.join(", ")}`,
|
|
163
265
|
);
|
|
164
266
|
const root = roots[0];
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
267
|
+
const candidates = ["json", "md"].map((extension) =>
|
|
268
|
+
resolve(root, `${recipeName}.${extension}`),
|
|
269
|
+
);
|
|
270
|
+
const existing = candidates.filter((candidate) => existsSync(candidate));
|
|
271
|
+
if (existing.length > 1) {
|
|
272
|
+
throw new Error(
|
|
273
|
+
`Skill Recipe stem collision: ${skillName}/${recipeName} has both .json and .md files`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
return candidates;
|
|
172
277
|
}
|
|
173
278
|
|
|
174
|
-
function
|
|
175
|
-
|
|
279
|
+
function recipeReferenceCandidates(
|
|
280
|
+
value: string,
|
|
281
|
+
baseDir: string,
|
|
282
|
+
context: ActiveSkillRecipeContext,
|
|
283
|
+
): string[] | undefined {
|
|
284
|
+
const trimmed = value.trim();
|
|
285
|
+
if (!trimmed) return undefined;
|
|
286
|
+
assertRecipeReferencePrefixWasNotRemoved(trimmed);
|
|
287
|
+
if (trimmed.endsWith(".json") || trimmed.endsWith(".md")) {
|
|
288
|
+
return [resolve(baseDir, trimmed)];
|
|
289
|
+
}
|
|
290
|
+
return skillRecipeCandidates(trimmed, context);
|
|
176
291
|
}
|
|
177
292
|
|
|
178
293
|
function findOwningSkillDir(recipeFile: string): string | undefined {
|
|
@@ -185,6 +300,13 @@ function findOwningSkillDir(recipeFile: string): string | undefined {
|
|
|
185
300
|
}
|
|
186
301
|
}
|
|
187
302
|
|
|
303
|
+
function assertRecipeHasNoDeclaredName(raw: Record<string, unknown>): void {
|
|
304
|
+
if (!Object.hasOwn(raw, "name")) return;
|
|
305
|
+
throw new Error(
|
|
306
|
+
"Recipe.name was removed in pi-actors 0.46.\nFile-backed Recipe identity is derived from its file name.",
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
188
310
|
function assertRuntimeRecipeValuesNotDeclared(raw: Record<string, unknown>): void {
|
|
189
311
|
const args = Array.isArray(raw.args)
|
|
190
312
|
? Schema.getExplicitToolArgNames(raw.args.map(String))
|
|
@@ -202,100 +324,51 @@ function assertRuntimeRecipeValuesNotDeclared(raw: Record<string, unknown>): voi
|
|
|
202
324
|
|
|
203
325
|
export function resolveRecipePath(
|
|
204
326
|
value: string,
|
|
205
|
-
|
|
327
|
+
baseDir = Paths.getRecipeRoot(),
|
|
206
328
|
): string {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
.replaceAll("{agent}", Paths.getAgentDir());
|
|
212
|
-
if (expanded.startsWith("~/")) return resolve(homedir(), expanded.slice(2));
|
|
213
|
-
if (expanded.includes("/")) return resolve(expanded);
|
|
214
|
-
return resolve(
|
|
215
|
-
recipeRoot,
|
|
216
|
-
expanded.endsWith(".json") || expanded.endsWith(".md")
|
|
217
|
-
? expanded
|
|
218
|
-
: `${expanded}.json`,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function isBareRecipeName(value: string): boolean {
|
|
223
|
-
const trimmed = value.trim();
|
|
224
|
-
return (
|
|
225
|
-
Boolean(trimmed) &&
|
|
226
|
-
!trimmed.includes("/") &&
|
|
227
|
-
!trimmed.startsWith("~") &&
|
|
228
|
-
!trimmed.includes("{")
|
|
329
|
+
const candidates = recipeReferenceCandidates(
|
|
330
|
+
value,
|
|
331
|
+
baseDir,
|
|
332
|
+
EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT,
|
|
229
333
|
);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return [
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function recipeCandidatePaths(
|
|
239
|
-
value: string,
|
|
240
|
-
currentRecipeRoot: string,
|
|
241
|
-
): string[] {
|
|
242
|
-
const qualified = qualifiedRecipeCandidates(value.trim());
|
|
243
|
-
if (qualified) return qualified;
|
|
244
|
-
if (!isBareRecipeName(value))
|
|
245
|
-
return [resolveRecipePath(value, currentRecipeRoot)];
|
|
246
|
-
const roots = [
|
|
247
|
-
Paths.getRecipeRoot(),
|
|
248
|
-
currentRecipeRoot,
|
|
249
|
-
Paths.getPackagedRecipeRoot(),
|
|
250
|
-
];
|
|
251
|
-
return [
|
|
252
|
-
...new Set(
|
|
253
|
-
roots.flatMap((root) =>
|
|
254
|
-
recipeNameFiles(value).map((file) => resolve(root, file)),
|
|
255
|
-
),
|
|
256
|
-
),
|
|
257
|
-
];
|
|
334
|
+
if (!candidates || candidates.length !== 1) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
`Recipe file reference must be an explicit .json or .md path: ${value}`,
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
return candidates[0];
|
|
258
340
|
}
|
|
259
341
|
|
|
260
342
|
function resolveRecipeImportPath(
|
|
261
343
|
value: string,
|
|
262
|
-
|
|
344
|
+
recipeDir: string,
|
|
345
|
+
context: ActiveSkillRecipeContext,
|
|
263
346
|
): string {
|
|
264
|
-
const candidates =
|
|
347
|
+
const candidates = recipeReferenceCandidates(value, recipeDir, context);
|
|
348
|
+
if (!candidates) {
|
|
349
|
+
throw new Error(
|
|
350
|
+
`Recipe import must use <skill>/<recipe> or an explicit .json/.md file path: ${value}`,
|
|
351
|
+
);
|
|
352
|
+
}
|
|
265
353
|
return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
|
|
266
354
|
}
|
|
267
355
|
|
|
268
356
|
export function resolveRecipeReferencePath(
|
|
269
357
|
value: unknown,
|
|
270
|
-
|
|
358
|
+
baseDir = Paths.getRecipeRoot(),
|
|
359
|
+
context = EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT,
|
|
271
360
|
): string | undefined {
|
|
272
361
|
if (typeof value !== "string") return undefined;
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
for (const path of recipeCandidatePaths(trimmed, currentRecipeRoot)) {
|
|
276
|
-
if (!existsSync(path)) continue;
|
|
277
|
-
try {
|
|
278
|
-
const raw = readRawRecipeConfig(path);
|
|
279
|
-
if (raw && typeof raw === "object" && Object.hasOwn(raw, "template"))
|
|
280
|
-
return path;
|
|
281
|
-
return path;
|
|
282
|
-
} catch {
|
|
283
|
-
return path;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return undefined;
|
|
362
|
+
const candidates = recipeReferenceCandidates(value, baseDir, context);
|
|
363
|
+
return candidates?.find((candidate) => existsSync(candidate));
|
|
287
364
|
}
|
|
288
365
|
|
|
289
366
|
export function getRecipePath(
|
|
290
367
|
value: unknown,
|
|
291
|
-
|
|
368
|
+
baseDir = Paths.getRecipeRoot(),
|
|
369
|
+
context = EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT,
|
|
292
370
|
): string | undefined {
|
|
293
|
-
|
|
294
|
-
const trimmed = value.trim();
|
|
295
|
-
if (!trimmed || hasWhitespace(trimmed)) return undefined;
|
|
296
|
-
if (trimmed.endsWith(".json") || trimmed.endsWith(".md"))
|
|
297
|
-
return resolveRecipePath(trimmed, recipeRoot);
|
|
298
|
-
return resolveRecipeReferencePath(trimmed, recipeRoot);
|
|
371
|
+
return resolveRecipeReferencePath(value, baseDir, context);
|
|
299
372
|
}
|
|
300
373
|
|
|
301
374
|
function isImportNode(value: unknown): boolean {
|
|
@@ -873,7 +946,11 @@ function loadDelegatedRecipe(
|
|
|
873
946
|
stack: string[],
|
|
874
947
|
options: ReadResolvedRecipeConfigOptions,
|
|
875
948
|
): TemplateRecipeConfig | undefined {
|
|
876
|
-
const path = resolveRecipeReferencePath(
|
|
949
|
+
const path = resolveRecipeReferencePath(
|
|
950
|
+
value,
|
|
951
|
+
dirname(currentRecipeFile),
|
|
952
|
+
options.skillContext,
|
|
953
|
+
);
|
|
877
954
|
if (!path) return undefined;
|
|
878
955
|
const config = readResolvedRecipeConfig(
|
|
879
956
|
path,
|
|
@@ -1082,6 +1159,7 @@ export function readResolvedRecipeConfig(
|
|
|
1082
1159
|
}
|
|
1083
1160
|
const raw = readRawRecipeConfig(path);
|
|
1084
1161
|
if (!raw || !Object.hasOwn(raw, "template")) return undefined;
|
|
1162
|
+
assertRecipeHasNoDeclaredName(raw);
|
|
1085
1163
|
RecipeControl.assertRecipeHasNoMailbox(raw);
|
|
1086
1164
|
assertRuntimeRecipeValuesNotDeclared(raw);
|
|
1087
1165
|
assertRecipeArgumentContract(raw as unknown as TemplateRecipeDefinition);
|
|
@@ -1090,6 +1168,7 @@ export function readResolvedRecipeConfig(
|
|
|
1090
1168
|
const importPath = resolveRecipeImportPath(
|
|
1091
1169
|
getImportFrom(binding),
|
|
1092
1170
|
dirname(path),
|
|
1171
|
+
options.skillContext ?? EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT,
|
|
1093
1172
|
);
|
|
1094
1173
|
const config = readResolvedRecipeConfig(
|
|
1095
1174
|
importPath,
|
|
@@ -1109,7 +1188,7 @@ export function readResolvedRecipeConfig(
|
|
|
1109
1188
|
imports[alias] = {
|
|
1110
1189
|
alias,
|
|
1111
1190
|
file: importPath,
|
|
1112
|
-
name:
|
|
1191
|
+
name: getRecipeIdFromPath(importPath),
|
|
1113
1192
|
config,
|
|
1114
1193
|
defaults: { ...(config.defaults ?? {}), ...(bindingDefaults ?? {}) },
|
|
1115
1194
|
values: {
|
|
@@ -1286,6 +1365,7 @@ function collectRecipeContextRecords(
|
|
|
1286
1365
|
file: string,
|
|
1287
1366
|
stack: string[],
|
|
1288
1367
|
importPath: string[],
|
|
1368
|
+
context: ActiveSkillRecipeContext,
|
|
1289
1369
|
alias?: string,
|
|
1290
1370
|
): TemplateRecipeContextRecord[] {
|
|
1291
1371
|
const path = resolveRecipePath(
|
|
@@ -1302,27 +1382,35 @@ function collectRecipeContextRecords(
|
|
|
1302
1382
|
}
|
|
1303
1383
|
const raw = readRawRecipeConfig(path);
|
|
1304
1384
|
if (!raw || !Object.hasOwn(raw, "template")) return [];
|
|
1305
|
-
|
|
1385
|
+
assertRecipeHasNoDeclaredName(raw);
|
|
1386
|
+
const qualifiedName = qualifiedRecipeNameForFile(path, context);
|
|
1387
|
+
const skill = qualifiedName?.split("/", 1)[0];
|
|
1306
1388
|
const record: TemplateRecipeContextRecord = {
|
|
1307
1389
|
...(alias ? { alias } : {}),
|
|
1308
1390
|
depth: stack.length,
|
|
1309
|
-
file: path,
|
|
1310
1391
|
import_path: importPath,
|
|
1392
|
+
logical_reference: qualifiedName ?? basename(path),
|
|
1311
1393
|
name: getRecipeIdFromPath(path),
|
|
1312
|
-
...(qualifiedName ? { qualified_name: qualifiedName } : {}),
|
|
1313
1394
|
recipe: raw,
|
|
1314
1395
|
role: stack.length === 0 ? "entry" : "import",
|
|
1396
|
+
...(skill ? { skill } : {}),
|
|
1397
|
+
source_file: path,
|
|
1398
|
+
source_kind: qualifiedName
|
|
1399
|
+
? "active_skill_component"
|
|
1400
|
+
: "explicit_file_recipe",
|
|
1315
1401
|
};
|
|
1316
1402
|
const imports = getRecipeImports(raw);
|
|
1317
1403
|
const children = Object.entries(imports).flatMap(([childAlias, binding]) => {
|
|
1318
1404
|
const importFile = resolveRecipeImportPath(
|
|
1319
1405
|
getImportFrom(binding),
|
|
1320
1406
|
dirname(path),
|
|
1407
|
+
context,
|
|
1321
1408
|
);
|
|
1322
1409
|
return collectRecipeContextRecords(
|
|
1323
1410
|
importFile,
|
|
1324
1411
|
[...stack, path],
|
|
1325
1412
|
[...importPath, childAlias],
|
|
1413
|
+
context,
|
|
1326
1414
|
childAlias,
|
|
1327
1415
|
);
|
|
1328
1416
|
});
|
|
@@ -1331,8 +1419,9 @@ function collectRecipeContextRecords(
|
|
|
1331
1419
|
|
|
1332
1420
|
export function buildRecipeContextRecords(
|
|
1333
1421
|
file: string,
|
|
1422
|
+
context = EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT,
|
|
1334
1423
|
): TemplateRecipeContextRecord[] {
|
|
1335
|
-
return collectRecipeContextRecords(file, [], []);
|
|
1424
|
+
return collectRecipeContextRecords(file, [], [], context);
|
|
1336
1425
|
}
|
|
1337
1426
|
|
|
1338
1427
|
export function getRecipeTemplate(
|
package/lib/runtime.ts
CHANGED
|
@@ -23,7 +23,6 @@ export interface RuntimeContext {
|
|
|
23
23
|
export interface ToolRegistryRuntimeDeps {
|
|
24
24
|
configPath: string;
|
|
25
25
|
exec: RegisteredToolExec;
|
|
26
|
-
packagedRecipeRoot?: string;
|
|
27
26
|
recipeRoot?: string;
|
|
28
27
|
getActiveTools?: () => string[];
|
|
29
28
|
registerTool: (
|
|
@@ -125,7 +124,7 @@ export function createAutoToolsRuntime(
|
|
|
125
124
|
);
|
|
126
125
|
const lines = ["pi-actors recipe registry warning"];
|
|
127
126
|
if (shadowed.length > 0) {
|
|
128
|
-
lines.push("User recipes
|
|
127
|
+
lines.push("User recipes shadow lower-priority user sources:");
|
|
129
128
|
lines.push(...shadowed.map((warning) => `• ${warning}`));
|
|
130
129
|
}
|
|
131
130
|
if (skipped.length > 0) {
|
|
@@ -141,11 +140,8 @@ export function createAutoToolsRuntime(
|
|
|
141
140
|
function loadTools(ctx: RuntimeContext) {
|
|
142
141
|
const warnings: string[] = [];
|
|
143
142
|
const recipeRoot = deps.recipeRoot ?? Paths.getRecipeRoot();
|
|
144
|
-
const packagedRecipeRoot =
|
|
145
|
-
deps.packagedRecipeRoot ?? Paths.getPackagedRecipeRoot();
|
|
146
143
|
const discovered = RecipesDiscovery.discoverRecipeSources([
|
|
147
144
|
{ root: recipeRoot, defaultTool: true, mutableUsage: true },
|
|
148
|
-
{ root: packagedRecipeRoot },
|
|
149
145
|
]);
|
|
150
146
|
warnings.push(...discovered.diagnostics);
|
|
151
147
|
tools.clear();
|
package/lib/tools-inspect.ts
CHANGED
|
@@ -33,7 +33,6 @@ export interface InspectToolDeps<TContext = unknown> {
|
|
|
33
33
|
getRunStatus?: (runOrDir: string) => Record<string, any>;
|
|
34
34
|
getTool?: (name: string) => any | undefined;
|
|
35
35
|
listRuns?: () => Array<Record<string, any>>;
|
|
36
|
-
packagedRecipeRoot?: string;
|
|
37
36
|
recipeRoot?: string;
|
|
38
37
|
}
|
|
39
38
|
|
|
@@ -195,6 +194,7 @@ function inspectRuntime(
|
|
|
195
194
|
function inspectRecipes(
|
|
196
195
|
view: string,
|
|
197
196
|
deps: InspectToolDeps,
|
|
197
|
+
context: unknown,
|
|
198
198
|
): Record<string, unknown> {
|
|
199
199
|
if (
|
|
200
200
|
view !== "status" &&
|
|
@@ -213,18 +213,51 @@ function inspectRecipes(
|
|
|
213
213
|
}
|
|
214
214
|
const discovered = RecipesDiscovery.discoverRecipeSources([
|
|
215
215
|
{ root: recipeRoot, defaultTool: true, mutableUsage: true },
|
|
216
|
-
{ root: deps.packagedRecipeRoot ?? Paths.getPackagedRecipeRoot() },
|
|
217
216
|
]);
|
|
218
|
-
const
|
|
219
|
-
|
|
217
|
+
const skillContext =
|
|
218
|
+
context && typeof context === "object" && "activeSkillRecipeContext" in context
|
|
219
|
+
? (context as {
|
|
220
|
+
activeSkillRecipeContext?: RecipesReferences.ActiveSkillRecipeContext;
|
|
221
|
+
}).activeSkillRecipeContext
|
|
222
|
+
: undefined;
|
|
223
|
+
const activeSkillContext =
|
|
224
|
+
skillContext ?? RecipesReferences.EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT;
|
|
225
|
+
const skillRecipeNamespaces = RecipesReferences.getActiveSkillRecipeNamespaces(
|
|
226
|
+
activeSkillContext,
|
|
227
|
+
);
|
|
228
|
+
let skillRecipeComponents: Array<Record<string, unknown>> = [];
|
|
229
|
+
const skillRecipeComponentDiagnostics: Array<Record<string, unknown>> = [];
|
|
230
|
+
try {
|
|
231
|
+
skillRecipeComponents = RecipesReferences.listActiveSkillRecipeComponents(
|
|
232
|
+
activeSkillContext,
|
|
233
|
+
).map((component) => ({
|
|
234
|
+
identity: component.identity,
|
|
235
|
+
source_kind: "active_skill_component",
|
|
236
|
+
skill: component.skill,
|
|
237
|
+
stem: component.stem,
|
|
238
|
+
imports: component.imports,
|
|
239
|
+
}));
|
|
240
|
+
} catch (error) {
|
|
241
|
+
skillRecipeComponentDiagnostics.push({
|
|
242
|
+
error: error instanceof Error ? error.message : String(error),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
const discoverySummary = RecipesDiscovery.summarizeDiscovery(discovered);
|
|
220
246
|
const summary = {
|
|
221
|
-
...
|
|
222
|
-
|
|
247
|
+
...discoverySummary,
|
|
248
|
+
active: Array.isArray(discoverySummary.active)
|
|
249
|
+
? discoverySummary.active.map((entry) => ({
|
|
250
|
+
...(entry as Record<string, unknown>),
|
|
251
|
+
source_kind: "user_registry_capability",
|
|
252
|
+
}))
|
|
253
|
+
: discoverySummary.active,
|
|
254
|
+
skill_recipe_components: skillRecipeComponents,
|
|
255
|
+
skill_recipe_component_diagnostics: skillRecipeComponentDiagnostics,
|
|
256
|
+
active_skill_recipe_identities: Object.keys(skillRecipeNamespaces).sort(),
|
|
223
257
|
skill_recipe_namespace_diagnostics: Object.entries(skillRecipeNamespaces)
|
|
224
258
|
.filter(([, roots]) => roots.length > 1)
|
|
225
|
-
.map(([name
|
|
259
|
+
.map(([name]) => ({
|
|
226
260
|
name,
|
|
227
|
-
roots,
|
|
228
261
|
error: `Ambiguous active Skill Recipe namespace ${name}`,
|
|
229
262
|
})),
|
|
230
263
|
drafts: RecipesDiscovery.listDraftRecipes(join(recipeRoot, "drafts")),
|
|
@@ -386,7 +419,7 @@ export function createInspectToolDefinition<TContext = unknown>(
|
|
|
386
419
|
if (target === "runtime") {
|
|
387
420
|
details = inspectRuntime(view, input, ctx, deps);
|
|
388
421
|
} else if (target === "recipes") {
|
|
389
|
-
details = inspectRecipes(view, deps);
|
|
422
|
+
details = inspectRecipes(view, deps, ctx);
|
|
390
423
|
} else {
|
|
391
424
|
const run = parseRunTarget(target);
|
|
392
425
|
if (run) details = inspectRun(run, view, input, ctx, deps);
|
package/lib/tools-local.ts
CHANGED
|
@@ -18,6 +18,7 @@ import * as ToolsResponse from "./tools-response.ts";
|
|
|
18
18
|
type JsonSchema = Schema.JsonSchema;
|
|
19
19
|
|
|
20
20
|
export interface RuntimeToolContext extends ModelContext.CurrentModelContext {
|
|
21
|
+
activeSkillRecipeContext?: RecipesReferences.ActiveSkillRecipeContext;
|
|
21
22
|
cwd: string;
|
|
22
23
|
sessionManager?: { getSessionId?: () => string };
|
|
23
24
|
}
|
|
@@ -243,6 +244,7 @@ export function createRuntimeToolDefinition(
|
|
|
243
244
|
values: resolveRecipeToolValues(cfg, values, ctx),
|
|
244
245
|
},
|
|
245
246
|
ctx.cwd,
|
|
247
|
+
{ skillContext: ctx.activeSkillRecipeContext },
|
|
246
248
|
);
|
|
247
249
|
return {
|
|
248
250
|
content: [
|