@farmslot/recipe-cli 0.4.1 → 0.6.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/CHANGELOG.md +32 -0
- package/README.md +11 -11
- package/dist/harness/acceptance-ledger.d.ts +18 -0
- package/dist/harness/acceptance-ledger.d.ts.map +1 -0
- package/dist/harness/acceptance-ledger.js +119 -0
- package/dist/harness/acceptance-ledger.js.map +1 -0
- package/dist/harness/adapter-plugins.d.ts +105 -0
- package/dist/harness/adapter-plugins.d.ts.map +1 -0
- package/dist/harness/adapter-plugins.js +388 -0
- package/dist/harness/adapter-plugins.js.map +1 -0
- package/dist/harness/catalog.d.ts +71 -0
- package/dist/harness/catalog.d.ts.map +1 -0
- package/dist/harness/catalog.js +280 -0
- package/dist/harness/catalog.js.map +1 -0
- package/dist/harness/commands/call.d.ts +18 -0
- package/dist/harness/commands/call.d.ts.map +1 -0
- package/dist/harness/commands/call.js +667 -0
- package/dist/harness/commands/call.js.map +1 -0
- package/dist/harness/commands/discover.d.ts +29 -0
- package/dist/harness/commands/discover.d.ts.map +1 -0
- package/dist/harness/commands/discover.js +563 -0
- package/dist/harness/commands/discover.js.map +1 -0
- package/dist/harness/commands/run.d.ts +40 -0
- package/dist/harness/commands/run.d.ts.map +1 -0
- package/dist/harness/commands/run.js +760 -0
- package/dist/harness/commands/run.js.map +1 -0
- package/dist/harness/heal-bounds.d.ts +8 -0
- package/dist/harness/heal-bounds.d.ts.map +1 -1
- package/dist/harness/heal-bounds.js +10 -0
- package/dist/harness/heal-bounds.js.map +1 -1
- package/dist/harness/host.d.ts +5 -0
- package/dist/harness/host.d.ts.map +1 -1
- package/dist/harness/host.js +7 -0
- package/dist/harness/host.js.map +1 -1
- package/dist/harness/index.d.ts +10 -1
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +10 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/live-adapter-contract.d.ts +9 -0
- package/dist/harness/live-adapter-contract.d.ts.map +1 -1
- package/dist/harness/live-adapter-contract.js +38 -7
- package/dist/harness/live-adapter-contract.js.map +1 -1
- package/dist/harness/network-observation.d.ts +16 -0
- package/dist/harness/network-observation.d.ts.map +1 -0
- package/dist/harness/network-observation.js +197 -0
- package/dist/harness/network-observation.js.map +1 -0
- package/dist/harness/plugin-imports.d.ts +23 -0
- package/dist/harness/plugin-imports.d.ts.map +1 -0
- package/dist/harness/plugin-imports.js +126 -0
- package/dist/harness/plugin-imports.js.map +1 -0
- package/dist/harness/recipe-library.d.ts +65 -0
- package/dist/harness/recipe-library.d.ts.map +1 -0
- package/dist/harness/recipe-library.js +182 -0
- package/dist/harness/recipe-library.js.map +1 -0
- package/dist/harness/recipe-validation.d.ts +29 -0
- package/dist/harness/recipe-validation.d.ts.map +1 -0
- package/dist/harness/recipe-validation.js +291 -0
- package/dist/harness/recipe-validation.js.map +1 -0
- package/dist/harness/run-engine.d.ts +98 -0
- package/dist/harness/run-engine.d.ts.map +1 -0
- package/dist/harness/run-engine.js +632 -0
- package/dist/harness/run-engine.js.map +1 -0
- package/dist/harness/run-observers.d.ts +10 -0
- package/dist/harness/run-observers.d.ts.map +1 -0
- package/dist/harness/run-observers.js +24 -0
- package/dist/harness/run-observers.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type RecipeActionManifestDocument, type RecipeValidationFinding, type RecipeValidationResult } from '@farmslot/protocol';
|
|
2
|
+
import { type RecipeLibrarySource } from '@farmslot/recipe-runner';
|
|
3
|
+
import type { RecipeCatalog } from './catalog.js';
|
|
4
|
+
import { type CliOptions } from './parse-args.js';
|
|
5
|
+
/** `value` with every exact `{{params.<path>}}` string replaced by the parameter it names, when present. */
|
|
6
|
+
export declare function resolveRecipeParamValue(value: unknown, params: Record<string, unknown>): unknown;
|
|
7
|
+
/** The adapter's `actions.inputFindings` on every workflow node, with parameters resolved. */
|
|
8
|
+
export declare function validateActionInputs(recipe: unknown, adapter: string, params?: Record<string, unknown>): RecipeValidationFinding[];
|
|
9
|
+
/** Warnings for `command` nodes whose exit code cannot prove what the recipe relies on it for. */
|
|
10
|
+
export declare function validateCommandNodes(recipe: unknown): RecipeValidationFinding[];
|
|
11
|
+
export declare function validateRecipeAdapterAware(adapter: string, recipe: unknown, manifest: RecipeActionManifestDocument, librarySources?: RecipeLibrarySource[], rootRef?: string, params?: Record<string, unknown>, proof?: boolean): Promise<RecipeValidationResult>;
|
|
12
|
+
export interface RunRecipeStaticValidation {
|
|
13
|
+
recipe: unknown;
|
|
14
|
+
recipeFile: string;
|
|
15
|
+
findings: RecipeValidationFinding[];
|
|
16
|
+
errorCount: number;
|
|
17
|
+
manifestOk: boolean;
|
|
18
|
+
schemaValid: boolean;
|
|
19
|
+
effectiveParams: Record<string, unknown>;
|
|
20
|
+
/** The library sources this validation resolved — returned so callers (run's
|
|
21
|
+
* runtime options) reuse them instead of re-resolving. */
|
|
22
|
+
librarySources?: RecipeLibrarySource[];
|
|
23
|
+
usageError?: {
|
|
24
|
+
code: string;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare function validateRunRecipeStatic(catalog: RecipeCatalog, recipeArg: string, adapter: string, options: CliOptions, params?: Record<string, unknown>): Promise<RunRecipeStaticValidation>;
|
|
29
|
+
//# sourceMappingURL=recipe-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-validation.d.ts","sourceRoot":"","sources":["../../src/harness/recipe-validation.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAG5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,mBAAmB,EAIzB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAEL,KAAK,UAAU,EAOhB,MAAM,iBAAiB,CAAC;AAIzB,4GAA4G;AAC5G,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAgBhG;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,uBAAuB,EAAE,CAa3B;AAUD,kGAAkG;AAClG,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,uBAAuB,EAAE,CAiC/E;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,4BAA4B,EACtC,cAAc,CAAC,EAAE,mBAAmB,EAAE,EACtC,OAAO,CAAC,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,UAAQ,GACZ,OAAO,CAAC,sBAAsB,CAAC,CA+GjC;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,uBAAuB,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC;8DAC0D;IAC1D,cAAc,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACvC,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,UAAU,EACnB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,yBAAyB,CAAC,CAoGpC"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// Static recipe validation for `run` and `call`: the manifest, the declared
|
|
2
|
+
// parameters, the platform's input checks on every node, called library
|
|
3
|
+
// recipes, and behavioral proof bindings.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { applyRecipeParamDefaults, digestRecipeDocument, getRecipeActionManifestActionNames, normalizeRecipeRef, validateRecipeParams, validateRecipeWithManifest, } from '@farmslot/protocol';
|
|
7
|
+
import { loadRecipeLibraries, RecipeResolutionError, resolveRecipeDependencies, validateRecipeDependencyParams, } from '@farmslot/recipe-runner';
|
|
8
|
+
import { harnessAdapters } from './adapters.js';
|
|
9
|
+
import { harnessHost } from './host.js';
|
|
10
|
+
import { actionManifestPathOption, isRecord, optionFlag, optionString, optionStrings, shellQuoteArg, targetPath, } from './parse-args.js';
|
|
11
|
+
import { resolveLibrarySources, resolveRunRecipeArg } from './recipe-library.js';
|
|
12
|
+
import { validateRuntimeProofPlan } from './runtime-proof.js';
|
|
13
|
+
/** `value` with every exact `{{params.<path>}}` string replaced by the parameter it names, when present. */
|
|
14
|
+
export function resolveRecipeParamValue(value, params) {
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
|
+
const exact = /^\{\{params\.([A-Za-z0-9_.-]+)\}\}$/u.exec(value);
|
|
17
|
+
if (!exact)
|
|
18
|
+
return value;
|
|
19
|
+
let current = params;
|
|
20
|
+
for (const segment of exact[1].split('.')) {
|
|
21
|
+
if (!isRecord(current) || !Object.hasOwn(current, segment))
|
|
22
|
+
return value;
|
|
23
|
+
current = current[segment];
|
|
24
|
+
}
|
|
25
|
+
return current;
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(value))
|
|
28
|
+
return value.map((entry) => resolveRecipeParamValue(entry, params));
|
|
29
|
+
if (!isRecord(value))
|
|
30
|
+
return value;
|
|
31
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, resolveRecipeParamValue(entry, params)]));
|
|
32
|
+
}
|
|
33
|
+
/** The adapter's `actions.inputFindings` on every workflow node, with parameters resolved. */
|
|
34
|
+
export function validateActionInputs(recipe, adapter, params) {
|
|
35
|
+
if (!isRecord(recipe) || !isRecord(recipe.workflow))
|
|
36
|
+
return [];
|
|
37
|
+
const nodes = isRecord(recipe.workflow.nodes) ? recipe.workflow.nodes : undefined;
|
|
38
|
+
if (!nodes)
|
|
39
|
+
return [];
|
|
40
|
+
const registry = harnessAdapters();
|
|
41
|
+
const actions = registry.has(adapter) ? registry.get(adapter).actions : undefined;
|
|
42
|
+
const findings = [];
|
|
43
|
+
for (const [nodeId, rawNode] of Object.entries(nodes)) {
|
|
44
|
+
const node = params ? resolveRecipeParamValue(rawNode, params) : rawNode;
|
|
45
|
+
if (!isRecord(node))
|
|
46
|
+
continue;
|
|
47
|
+
findings.push(...(actions?.inputFindings?.(nodeId, node) ?? []));
|
|
48
|
+
}
|
|
49
|
+
return findings;
|
|
50
|
+
}
|
|
51
|
+
// A pipe into tail/head makes the shell report tail's exit code, so a failing
|
|
52
|
+
// command passes; the runner already captures full stdout and stderr.
|
|
53
|
+
const PIPE_TO_TAIL_OR_HEAD_RE = /(?:^|[^|])\|(?!\|)\s*(?:tail|head)\b/u;
|
|
54
|
+
// A test runner as its own word (not jest.config.ts), or a `test` script such as
|
|
55
|
+
// `test:verbose` (not `testing`).
|
|
56
|
+
const TEST_RUNNER_RE = /(?:^|[\s;&|(/])(?:jest|vitest|mocha)(?=\s|$)|\b(?:yarn|npm|pnpm)\b[^|;&]*\stest(?:[:.-][\w:.-]*)?(?=\s|$)/u;
|
|
57
|
+
/** Warnings for `command` nodes whose exit code cannot prove what the recipe relies on it for. */
|
|
58
|
+
export function validateCommandNodes(recipe) {
|
|
59
|
+
if (!isRecord(recipe) || !isRecord(recipe.workflow))
|
|
60
|
+
return [];
|
|
61
|
+
const nodes = isRecord(recipe.workflow.nodes) ? recipe.workflow.nodes : undefined;
|
|
62
|
+
if (!nodes)
|
|
63
|
+
return [];
|
|
64
|
+
const outputAsserted = new Set(Object.values(nodes).flatMap((node) => isRecord(node) && node.action === 'assert_output' ? [node.source ?? node.node] : []));
|
|
65
|
+
const findings = [];
|
|
66
|
+
for (const [nodeId, node] of Object.entries(nodes)) {
|
|
67
|
+
if (!isRecord(node) || node.action !== 'command')
|
|
68
|
+
continue;
|
|
69
|
+
const field = node.cmd !== undefined ? 'cmd' : 'command';
|
|
70
|
+
const command = node[field];
|
|
71
|
+
if (typeof command !== 'string')
|
|
72
|
+
continue;
|
|
73
|
+
if (PIPE_TO_TAIL_OR_HEAD_RE.test(command)) {
|
|
74
|
+
findings.push({
|
|
75
|
+
severity: 'warning',
|
|
76
|
+
code: 'recipe.command_pipe_masks_exit',
|
|
77
|
+
path: `workflow.nodes.${nodeId}.${field}`,
|
|
78
|
+
message: `${nodeId} pipes into tail/head, so its exit code is tail's and a failing command passes. Drop the pipe: the node already records full stdout and stderr for assert_output.`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (TEST_RUNNER_RE.test(command) && !outputAsserted.has(nodeId)) {
|
|
82
|
+
findings.push({
|
|
83
|
+
severity: 'warning',
|
|
84
|
+
code: 'recipe.test_command_exit_code_only',
|
|
85
|
+
path: `workflow.nodes.${nodeId}`,
|
|
86
|
+
message: `${nodeId} runs tests but only its exit code is checked. Add assert_output on the literal pass count: jest -t exits 0 when no test matches.`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return findings;
|
|
91
|
+
}
|
|
92
|
+
export async function validateRecipeAdapterAware(adapter, recipe, manifest, librarySources, rootRef, params, proof = false) {
|
|
93
|
+
let externalRecipeIds;
|
|
94
|
+
let libraryResolution;
|
|
95
|
+
if (librarySources && librarySources.length > 0) {
|
|
96
|
+
libraryResolution = await loadRecipeLibraries(librarySources, {
|
|
97
|
+
adapter,
|
|
98
|
+
});
|
|
99
|
+
externalRecipeIds = new Set(libraryResolution.recipes.keys());
|
|
100
|
+
}
|
|
101
|
+
const validationOptions = externalRecipeIds !== undefined ? { externalRecipeIds } : undefined;
|
|
102
|
+
const withManifest = validateRecipeWithManifest(recipe, manifest, validationOptions);
|
|
103
|
+
const findings = [
|
|
104
|
+
...withManifest.findings,
|
|
105
|
+
...(withManifest.status === 'valid' && params
|
|
106
|
+
? validateRecipeWithManifest(resolveRecipeParamValue(recipe, params), manifest, validationOptions).findings
|
|
107
|
+
: []),
|
|
108
|
+
...validateActionInputs(recipe, adapter, params),
|
|
109
|
+
...validateCommandNodes(params ? resolveRecipeParamValue(recipe, params) : recipe),
|
|
110
|
+
];
|
|
111
|
+
if (withManifest.status === 'valid' && isRecord(recipe) && libraryResolution) {
|
|
112
|
+
try {
|
|
113
|
+
const digest = digestRecipeDocument(recipe);
|
|
114
|
+
const dependencies = resolveRecipeDependencies({
|
|
115
|
+
rootRef: rootRef ?? `$root:${digest}`,
|
|
116
|
+
root: recipe,
|
|
117
|
+
rootSource: {
|
|
118
|
+
kind: 'recipe-file',
|
|
119
|
+
trust: 'unknown',
|
|
120
|
+
name: rootRef ?? 'recipe file',
|
|
121
|
+
digest,
|
|
122
|
+
},
|
|
123
|
+
recipes: libraryResolution.recipes,
|
|
124
|
+
});
|
|
125
|
+
if (params) {
|
|
126
|
+
validateRecipeDependencyParams({
|
|
127
|
+
root: recipe,
|
|
128
|
+
params,
|
|
129
|
+
recipes: dependencies.recipes,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
for (const dependency of dependencies.recipes.values()) {
|
|
133
|
+
findings.push(...validateRecipeWithManifest(dependency.document, manifest, validationOptions).findings);
|
|
134
|
+
}
|
|
135
|
+
const validateDependencyInstances = (document, parentParams) => {
|
|
136
|
+
if (!isRecord(document) ||
|
|
137
|
+
!isRecord(document.workflow) ||
|
|
138
|
+
!isRecord(document.workflow.nodes))
|
|
139
|
+
return;
|
|
140
|
+
for (const rawNode of Object.values(document.workflow.nodes)) {
|
|
141
|
+
const node = resolveRecipeParamValue(rawNode, parentParams);
|
|
142
|
+
if (!isRecord(node) || node.action !== 'call' || typeof node.ref !== 'string')
|
|
143
|
+
continue;
|
|
144
|
+
const dependency = dependencies.recipes.get(normalizeRecipeRef(node.ref));
|
|
145
|
+
if (!dependency)
|
|
146
|
+
continue;
|
|
147
|
+
const supplied = isRecord(node.params) ? node.params : {};
|
|
148
|
+
const childParams = applyRecipeParamDefaults(supplied, isRecord(dependency.document) ? dependency.document.paramsSchema : undefined);
|
|
149
|
+
findings.push(...validateRecipeWithManifest(resolveRecipeParamValue(dependency.document, childParams), manifest, validationOptions).findings);
|
|
150
|
+
findings.push(...validateActionInputs(dependency.document, adapter, childParams));
|
|
151
|
+
validateDependencyInstances(dependency.document, childParams);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
validateDependencyInstances(recipe, params ?? {});
|
|
155
|
+
if (proof && !findings.some((finding) => finding.severity === 'error')) {
|
|
156
|
+
findings.push(...validateRuntimeProofPlan(recipe, new Map([...dependencies.recipes].map(([ref, dependency]) => [
|
|
157
|
+
ref,
|
|
158
|
+
dependency.document,
|
|
159
|
+
]))));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
if (!(error instanceof RecipeResolutionError))
|
|
164
|
+
throw error;
|
|
165
|
+
findings.push({
|
|
166
|
+
severity: 'error',
|
|
167
|
+
code: error.code,
|
|
168
|
+
path: 'workflow',
|
|
169
|
+
message: `${error.message} Next: ${error.userAction}`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const errors = findings.filter((finding) => finding.severity === 'error').length;
|
|
174
|
+
const warnings = findings.length - errors;
|
|
175
|
+
return {
|
|
176
|
+
status: errors > 0 ? 'invalid' : 'valid',
|
|
177
|
+
findings,
|
|
178
|
+
summary: { errors, warnings },
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
export async function validateRunRecipeStatic(catalog, recipeArg, adapter, options, params = {}) {
|
|
182
|
+
// Resolve library sources first so resolveRunRecipeArg can probe personal and team
|
|
183
|
+
// recipe dirs with correct precedence before the canonical packaged library.
|
|
184
|
+
let librarySources = await resolveLibrarySources(catalog, optionStrings(options, 'library'));
|
|
185
|
+
const resolved = await resolveRunRecipeArg(catalog, recipeArg, adapter, librarySources);
|
|
186
|
+
const recipeFile = 'recipeFile' in resolved ? resolved.recipeFile : path.resolve(recipeArg);
|
|
187
|
+
if ('recipeFile' in resolved && !resolved.ref) {
|
|
188
|
+
librarySources = await resolveLibrarySources(catalog, optionStrings(options, 'library'), recipeFile);
|
|
189
|
+
}
|
|
190
|
+
const empty = {
|
|
191
|
+
recipe: undefined,
|
|
192
|
+
recipeFile,
|
|
193
|
+
findings: [],
|
|
194
|
+
errorCount: 0,
|
|
195
|
+
manifestOk: false,
|
|
196
|
+
schemaValid: false,
|
|
197
|
+
effectiveParams: params,
|
|
198
|
+
librarySources,
|
|
199
|
+
};
|
|
200
|
+
if ('notFound' in resolved) {
|
|
201
|
+
return {
|
|
202
|
+
...empty,
|
|
203
|
+
usageError: {
|
|
204
|
+
code: 'RECIPE_NOT_FOUND',
|
|
205
|
+
message: resolved.notFound +
|
|
206
|
+
(await actionInsteadOfRecipeHint(catalog, recipeArg, adapter, options, librarySources)),
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
let recipe;
|
|
211
|
+
try {
|
|
212
|
+
recipe = JSON.parse(fs.readFileSync(recipeFile, 'utf8'));
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
return {
|
|
216
|
+
...empty,
|
|
217
|
+
usageError: {
|
|
218
|
+
code: 'RECIPE_UNPARSEABLE',
|
|
219
|
+
message: `recipe is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const findings = [];
|
|
224
|
+
const { manifest } = await catalog.resolveActionManifest(adapter, optionString(options, 'actionManifest'), librarySources);
|
|
225
|
+
let manifestOk = true;
|
|
226
|
+
try {
|
|
227
|
+
await catalog.validateManifest(manifest);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
manifestOk = false;
|
|
231
|
+
findings.push({
|
|
232
|
+
severity: 'error',
|
|
233
|
+
code: 'manifest.invalid',
|
|
234
|
+
path: actionManifestPathOption(options, adapter),
|
|
235
|
+
message: error instanceof Error ? error.message : String(error),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
let effectiveParams = params;
|
|
239
|
+
if (isRecord(recipe)) {
|
|
240
|
+
effectiveParams = applyRecipeParamDefaults(params, recipe.paramsSchema);
|
|
241
|
+
findings.push(...validateRecipeParams(effectiveParams, recipe.paramsSchema).findings);
|
|
242
|
+
}
|
|
243
|
+
// Reuse librarySources already resolved above — no second resolution needed.
|
|
244
|
+
const validation = manifestOk
|
|
245
|
+
? await validateRecipeAdapterAware(adapter, recipe, manifest, librarySources, resolved.ref, effectiveParams, optionFlag(options, 'proof'))
|
|
246
|
+
: {
|
|
247
|
+
status: 'invalid',
|
|
248
|
+
findings: [],
|
|
249
|
+
summary: { errors: 1, warnings: 0 },
|
|
250
|
+
};
|
|
251
|
+
findings.push(...validation.findings);
|
|
252
|
+
const errorCount = findings.filter((finding) => finding.severity === 'error').length;
|
|
253
|
+
return {
|
|
254
|
+
recipe,
|
|
255
|
+
recipeFile,
|
|
256
|
+
findings,
|
|
257
|
+
errorCount,
|
|
258
|
+
manifestOk,
|
|
259
|
+
schemaValid: validation.status === 'valid' && errorCount === 0,
|
|
260
|
+
effectiveParams,
|
|
261
|
+
librarySources,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// A bare name that is one action, not a recipe: the `call` that runs it,
|
|
265
|
+
// judged against the library sources the recipe lookup already resolved.
|
|
266
|
+
async function actionInsteadOfRecipeHint(catalog, recipeArg, adapter, options, librarySources) {
|
|
267
|
+
if (recipeArg.includes('/') || recipeArg.includes(path.sep))
|
|
268
|
+
return '';
|
|
269
|
+
try {
|
|
270
|
+
const { manifest } = await catalog.resolveActionManifest(adapter, optionString(options, 'actionManifest'), librarySources);
|
|
271
|
+
const actions = getRecipeActionManifestActionNames(manifest);
|
|
272
|
+
const matches = actions.includes(recipeArg)
|
|
273
|
+
? [recipeArg]
|
|
274
|
+
: actions.filter((name) => name.split('.').pop() === recipeArg);
|
|
275
|
+
if (matches.length !== 1)
|
|
276
|
+
return '';
|
|
277
|
+
const device = optionString(options, 'device');
|
|
278
|
+
const actionManifest = optionString(options, 'actionManifest');
|
|
279
|
+
const parts = [harnessHost().name, 'call', matches[0]];
|
|
280
|
+
parts.push('--adapter', adapter, '--target', shellQuoteArg(targetPath(options)));
|
|
281
|
+
if (device)
|
|
282
|
+
parts.push('--device', shellQuoteArg(device));
|
|
283
|
+
if (actionManifest)
|
|
284
|
+
parts.push('--action-manifest', shellQuoteArg(actionManifest));
|
|
285
|
+
return ` This is an action, not a recipe. Use: ${parts.join(' ')}.`;
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return '';
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=recipe-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipe-validation.js","sourceRoot":"","sources":["../../src/harness/recipe-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { CommandOptions, HealBoundViolation, HealPolicy, HealState, RecipeNodeEvent, RecipeRunOptions } from '@farmslot/adapter-sdk';
|
|
2
|
+
import type { RecipeActionManifestDocument, RecipeExecutionPlan } from '@farmslot/protocol';
|
|
3
|
+
import { type RecipeRunner, type RecipeRunRequest, type RecipeRunResult } from '@farmslot/recipe-runner';
|
|
4
|
+
import type { ActionCapabilitySource, RecipeCatalog } from './catalog.js';
|
|
5
|
+
import { type ExecutionProvenanceInput, type ExecutionProvenanceSnapshot } from './execution-provenance.js';
|
|
6
|
+
import { type CliOptions } from './parse-args.js';
|
|
7
|
+
import { type ConsoleAllowlist, type ConsoleClassifier, type RecipeRunEvidence } from './run-diagnostics.js';
|
|
8
|
+
export interface RecipeRunnerOptions<TMutation> {
|
|
9
|
+
quietStdout?: boolean;
|
|
10
|
+
suppressLibraryResolutionLogs?: boolean;
|
|
11
|
+
autoHud?: boolean;
|
|
12
|
+
actionSources: ReadonlyMap<string, ActionCapabilitySource>;
|
|
13
|
+
trustTaskActions: boolean;
|
|
14
|
+
trustedMutation?: TMutation;
|
|
15
|
+
onActionEvent?(event: RecipeNodeEvent): void;
|
|
16
|
+
}
|
|
17
|
+
/** What `trustedMutation.load` receives: the run's command line and what the command resolved. */
|
|
18
|
+
export interface TrustedMutationLoadInput {
|
|
19
|
+
/** The adapter the command resolved: `--adapter`, a `--platform` target, or the detected one. */
|
|
20
|
+
adapter: string;
|
|
21
|
+
cli: CommandOptions;
|
|
22
|
+
artifactsDir: string;
|
|
23
|
+
projectRoot: string;
|
|
24
|
+
rootRecipe: unknown;
|
|
25
|
+
}
|
|
26
|
+
/** What `trustedMutation.authorize` receives besides the loaded mutation and the plan. */
|
|
27
|
+
export interface TrustedMutationAuthorizeContext {
|
|
28
|
+
/** The adapter the command resolved, the same one `load` received. */
|
|
29
|
+
adapter: string;
|
|
30
|
+
}
|
|
31
|
+
/** What a host executes recipes with, on top of its catalog. */
|
|
32
|
+
export interface RecipeEngine<TMutation = unknown, TAllowlist extends ConsoleAllowlist = ConsoleAllowlist> extends RecipeCatalog {
|
|
33
|
+
createRunner(adapter: string, manifest: RecipeActionManifestDocument, options: RecipeRunnerOptions<TMutation>): Promise<RecipeRunner>;
|
|
34
|
+
/**
|
|
35
|
+
* Funded external mutations: the context loaded from the run's command line,
|
|
36
|
+
* then bound to the run's execution plan. Absent: no run binds one. The plan is
|
|
37
|
+
* computed without the mutation; `authorize` returning undefined means there is
|
|
38
|
+
* nothing to bind for this plan, and the run executes with no trusted mutation.
|
|
39
|
+
*/
|
|
40
|
+
trustedMutation?: {
|
|
41
|
+
load(input: TrustedMutationLoadInput): Promise<TMutation | undefined>;
|
|
42
|
+
authorize(base: TMutation, plan: RecipeExecutionPlan, context: TrustedMutationAuthorizeContext): Promise<TMutation | undefined>;
|
|
43
|
+
};
|
|
44
|
+
/** The console rules run diagnostics classify with. */
|
|
45
|
+
console: ConsoleClassifier<TAllowlist>;
|
|
46
|
+
/** The host package paths a run's provenance binds. */
|
|
47
|
+
runnerIncludes: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
/** A run's options: the generic ones (with the platform's own) and the command line it came from. */
|
|
50
|
+
export type RecipeEngineRunOptions = RecipeRunOptions & {
|
|
51
|
+
cli?: CommandOptions;
|
|
52
|
+
};
|
|
53
|
+
export interface PreparedRecipeExecution {
|
|
54
|
+
runner: RecipeRunner;
|
|
55
|
+
runRequest: RecipeRunRequest;
|
|
56
|
+
absoluteArtifactsDir: string;
|
|
57
|
+
useFramedRecording: boolean;
|
|
58
|
+
provenanceInput: ExecutionProvenanceInput;
|
|
59
|
+
provenanceSnapshots: ExecutionProvenanceSnapshot[];
|
|
60
|
+
}
|
|
61
|
+
/** Execute a recipe inside the caller's `activateRecipeRuntimeEnvironment` scope. */
|
|
62
|
+
export declare function runRecipe<TMutation, TAllowlist extends ConsoleAllowlist>(engine: RecipeEngine<TMutation, TAllowlist>, adapter: string, recipe: string | object, artifactsDir: string, projectRoot: string, actionManifestPath?: string, runtimeOptions?: RecipeEngineRunOptions, preflightedExecution?: PreparedRecipeExecution, effectsState?: HealState): Promise<RecipeRunEvidence>;
|
|
63
|
+
/** Resolve and preflight a recipe inside the caller's `activateRecipeRuntimeEnvironment` scope. */
|
|
64
|
+
export declare function preflightRecipe<TMutation, TAllowlist extends ConsoleAllowlist>(engine: RecipeEngine<TMutation, TAllowlist>, adapter: string, recipe: string | object, artifactsDir: string, projectRoot: string, actionManifestPath?: string, runtimeOptions?: RecipeEngineRunOptions): Promise<PreparedRecipeExecution>;
|
|
65
|
+
/** Record the run's recoveries and mutations in its summary and artifact manifest. */
|
|
66
|
+
export declare function persistRunEffects(summaryPath: string, artifactManifestPath: string, state: HealState): void;
|
|
67
|
+
/**
|
|
68
|
+
* The run's ports and platform environment: the slot's ports, then the explicit
|
|
69
|
+
* ones, then the platform's own. `run` and `call` open one scope around
|
|
70
|
+
* preflight, the runtime check, the observers and the execution, so all of them
|
|
71
|
+
* see the same ports. Returns the restore.
|
|
72
|
+
*/
|
|
73
|
+
export declare function activateRecipeRuntimeEnvironment(adapter: string, projectRoot: string, runtimeOptions: RecipeRunOptions): () => void;
|
|
74
|
+
export declare function prepareRuntimeIfNeeded(adapter: string, projectRoot: string, runtimeOptions: RecipeRunOptions): Promise<void>;
|
|
75
|
+
/** A one-node recipe that runs `action` with `args` through the real engine path. */
|
|
76
|
+
export declare function synthesizeOneNodeRecipe(action: string, args: Record<string, unknown>): Record<string, unknown>;
|
|
77
|
+
interface PreparedHeal {
|
|
78
|
+
state: HealState;
|
|
79
|
+
heal: HealPolicy;
|
|
80
|
+
}
|
|
81
|
+
interface PrepareHealOptions {
|
|
82
|
+
appRestartAuthored?: boolean;
|
|
83
|
+
onPhase?: (phase: 'install' | 'healthcheck' | 'recover', fields?: Record<string, unknown>) => void;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Refuse a concurrent recipe, parse --heal, ensure the runtime overlay, and run
|
|
87
|
+
* the platform's runtime check: the heal state to run with, or the exit code.
|
|
88
|
+
*/
|
|
89
|
+
export declare function prepareHeal(adapter: string, target: string, options: CliOptions, json: boolean, prepareOptions?: PrepareHealOptions): Promise<PreparedHeal | number>;
|
|
90
|
+
/** Run once; a failed run is classified against the recovery bounds. */
|
|
91
|
+
export declare function executeWithHealBounds<T extends RecipeRunResult>(exec: () => Promise<T>, target: string, state: HealState): Promise<{
|
|
92
|
+
result: T;
|
|
93
|
+
violation: HealBoundViolation | null;
|
|
94
|
+
}>;
|
|
95
|
+
export declare function emitHealViolation(json: boolean, command: 'run' | 'call', result: Pick<RecipeRunResult, 'summaryPath' | 'tracePath' | 'artifactManifestPath'>, violation: HealBoundViolation, state: HealState, adapter?: string): number;
|
|
96
|
+
export declare function countRecipeNodes(recipe: unknown): number | undefined;
|
|
97
|
+
export {};
|
|
98
|
+
//# sourceMappingURL=run-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-engine.d.ts","sourceRoot":"","sources":["../../src/harness/run-engine.ts"],"names":[],"mappings":"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"}
|