@farmslot/recipe-harness 0.3.2 → 0.3.3
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 +11 -0
- package/README.md +46 -0
- package/dist/cli/flows-command.d.ts +3 -0
- package/dist/cli/flows-command.d.ts.map +1 -0
- package/dist/cli/flows-command.js +145 -0
- package/dist/cli/flows-command.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/run-command.d.ts.map +1 -1
- package/dist/cli/run-command.js +7 -0
- package/dist/cli/run-command.js.map +1 -1
- package/dist/cli/support.d.ts +4 -2
- package/dist/cli/support.d.ts.map +1 -1
- package/dist/cli/support.js +7 -3
- package/dist/cli/support.js.map +1 -1
- package/dist/cli/validate-command.d.ts.map +1 -1
- package/dist/cli/validate-command.js +7 -0
- package/dist/cli/validate-command.js.map +1 -1
- package/dist/core/flows.d.ts +6 -0
- package/dist/core/flows.d.ts.map +1 -1
- package/dist/core/flows.js +12 -6
- package/dist/core/flows.js.map +1 -1
- package/dist/core/library.d.ts +72 -0
- package/dist/core/library.d.ts.map +1 -0
- package/dist/core/library.js +240 -0
- package/dist/core/library.js.map +1 -0
- package/dist/core/promote.d.ts +41 -0
- package/dist/core/promote.d.ts.map +1 -0
- package/dist/core/promote.js +249 -0
- package/dist/core/promote.js.map +1 -0
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +62 -3
- package/dist/core/runner.js.map +1 -1
- package/dist/core/types.d.ts +46 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/validation.d.ts +2 -2
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +2 -2
- package/dist/core/validation.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type InlineFlow } from './flows.js';
|
|
2
|
+
import type { LoadedRecipeLibrarySource, RecipeLibrarySource, RecipeLogger } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Structural stand-in for `NodeJS.ProcessEnv` so the public API typechecks for
|
|
5
|
+
* consumers without `@types/node`.
|
|
6
|
+
*/
|
|
7
|
+
export type RecipeLibraryEnv = Record<string, string | undefined>;
|
|
8
|
+
export interface ResolvedLibraryFlow {
|
|
9
|
+
ref: string;
|
|
10
|
+
flow: InlineFlow;
|
|
11
|
+
raw: Record<string, unknown>;
|
|
12
|
+
source: string;
|
|
13
|
+
/** Catalog file path relative to the library root. */
|
|
14
|
+
file: string;
|
|
15
|
+
/** Source names that also declare this ref at lower precedence. */
|
|
16
|
+
shadows: string[];
|
|
17
|
+
lastVerified?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface RecipeLibraryResolution {
|
|
20
|
+
sources: LoadedRecipeLibrarySource[];
|
|
21
|
+
flows: ReadonlyMap<string, ResolvedLibraryFlow>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parse a `RECIPE_LIBRARY_PATH`-style value: ordered, colon-separated
|
|
25
|
+
* `name=path` or bare-path entries. Order is precedence (first wins).
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseRecipeLibraryPath(value: string): RecipeLibrarySource[];
|
|
28
|
+
/**
|
|
29
|
+
* The personal library location: `<farmslot home>/recipe-library`
|
|
30
|
+
* (FARMSLOT_HOME env, default ~/.farmslot). The directory may not exist yet.
|
|
31
|
+
*/
|
|
32
|
+
export declare function personalRecipeLibraryRoot(env?: RecipeLibraryEnv): string;
|
|
33
|
+
/**
|
|
34
|
+
* Default sources when nothing is configured: the personal library when it
|
|
35
|
+
* exists.
|
|
36
|
+
*/
|
|
37
|
+
export declare function defaultRecipeLibrarySources(env?: RecipeLibraryEnv): Promise<RecipeLibrarySource[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the ordered library sources for a run: explicit entries (CLI flags
|
|
40
|
+
* first, then RECIPE_LIBRARY_PATH) replace the defaults entirely so a run's
|
|
41
|
+
* precedence is always fully spelled out by whoever configured it.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveRecipeLibrarySources(options?: {
|
|
44
|
+
cliEntries?: string[];
|
|
45
|
+
env?: RecipeLibraryEnv;
|
|
46
|
+
}): Promise<RecipeLibrarySource[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Load and merge ordered library sources into one flow resolution. Shadowing
|
|
49
|
+
* across sources is recorded and logged; duplicate refs within one source are
|
|
50
|
+
* an error, matching recipe-local catalog behavior.
|
|
51
|
+
*/
|
|
52
|
+
export declare function loadRecipeLibraries(sources: readonly RecipeLibrarySource[], logger?: RecipeLogger): Promise<RecipeLibraryResolution>;
|
|
53
|
+
export interface EffectiveFlowCatalog {
|
|
54
|
+
catalog: ReadonlyMap<string, InlineFlow>;
|
|
55
|
+
/** Recipe-local declarations that overrode a library-provided ref. */
|
|
56
|
+
overrides: Array<{
|
|
57
|
+
ref: string;
|
|
58
|
+
source: string;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Merge recipe-local flows over library flows. Recipe-local declarations
|
|
63
|
+
* (inline `flows` and explicit `uses` catalogs) always win — the recipe author
|
|
64
|
+
* spelled them out — and any library refs they override are returned (and
|
|
65
|
+
* logged) so runs can report them even for programmatic consumers without a
|
|
66
|
+
* logger. Library flow lookups are recorded into `usedLibraryFlows` so runs
|
|
67
|
+
* can report exactly which library flows produced the proof.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createEffectiveFlowCatalog(recipeFlows: ReadonlyMap<string, InlineFlow>, resolution: RecipeLibraryResolution | undefined, usedLibraryFlows: Map<string, ResolvedLibraryFlow>, logger?: RecipeLogger): EffectiveFlowCatalog;
|
|
70
|
+
/** Catalog file names (relative to `<root>/flows/`) of a library, sorted. */
|
|
71
|
+
export declare function listFlowCatalogFiles(root: string): Promise<string[]>;
|
|
72
|
+
//# sourceMappingURL=library.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../src/core/library.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,YAAY,CAAC;AAE/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAO/F;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAElE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,yBAAyB,EAAE,CAAC;IACrC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAe3E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,gBAA8B,GAAG,MAAM,CAErF;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,GAAG,GAAE,gBAA8B,GAClC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAQhC;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,CAAC,OAAO,CAAC,EAAE;IAC1D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAQjC;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,uBAAuB,CAAC,CAgDlC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACzC,sEAAsE;IACtE,SAAS,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EAC5C,UAAU,EAAE,uBAAuB,GAAG,SAAS,EAC/C,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAClD,MAAM,CAAC,EAAE,YAAY,GACpB,oBAAoB,CAuBtB;AA8DD,6EAA6E;AAC7E,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgB1E"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { farmslotHome } from '@farmslot/protocol/node/farmslot-home';
|
|
5
|
+
import { readCatalogFlows } from './flows.js';
|
|
6
|
+
import { isRecord, readJsonFile } from './json.js';
|
|
7
|
+
const LIBRARY_MANIFEST_FILE = 'library.json';
|
|
8
|
+
const LIBRARY_FLOWS_DIR = 'flows';
|
|
9
|
+
const LIBRARY_FLOW_CATALOG_SUFFIX = '.flows.json';
|
|
10
|
+
const LAST_VERIFIED_WARN_AFTER_DAYS = 30;
|
|
11
|
+
/**
|
|
12
|
+
* Parse a `RECIPE_LIBRARY_PATH`-style value: ordered, colon-separated
|
|
13
|
+
* `name=path` or bare-path entries. Order is precedence (first wins).
|
|
14
|
+
*/
|
|
15
|
+
export function parseRecipeLibraryPath(value) {
|
|
16
|
+
return value
|
|
17
|
+
.split(':')
|
|
18
|
+
.map((entry) => entry.trim())
|
|
19
|
+
.filter(Boolean)
|
|
20
|
+
.map((entry) => {
|
|
21
|
+
const separator = entry.indexOf('=');
|
|
22
|
+
if (separator < 0)
|
|
23
|
+
return { root: expandTilde(entry) };
|
|
24
|
+
const name = entry.slice(0, separator).trim();
|
|
25
|
+
const root = entry.slice(separator + 1).trim();
|
|
26
|
+
if (!name || !root) {
|
|
27
|
+
throw new Error(`Recipe library entry ${JSON.stringify(entry)} must be name=path or path.`);
|
|
28
|
+
}
|
|
29
|
+
return { name, root: expandTilde(root) };
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The personal library location: `<farmslot home>/recipe-library`
|
|
34
|
+
* (FARMSLOT_HOME env, default ~/.farmslot). The directory may not exist yet.
|
|
35
|
+
*/
|
|
36
|
+
export function personalRecipeLibraryRoot(env = process.env) {
|
|
37
|
+
return path.join(farmslotHome(env), 'recipe-library');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Default sources when nothing is configured: the personal library when it
|
|
41
|
+
* exists.
|
|
42
|
+
*/
|
|
43
|
+
export async function defaultRecipeLibrarySources(env = process.env) {
|
|
44
|
+
const personalRoot = personalRecipeLibraryRoot(env);
|
|
45
|
+
try {
|
|
46
|
+
await readFile(path.join(personalRoot, LIBRARY_MANIFEST_FILE), 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return [{ name: 'personal', root: personalRoot }];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the ordered library sources for a run: explicit entries (CLI flags
|
|
55
|
+
* first, then RECIPE_LIBRARY_PATH) replace the defaults entirely so a run's
|
|
56
|
+
* precedence is always fully spelled out by whoever configured it.
|
|
57
|
+
*/
|
|
58
|
+
export async function resolveRecipeLibrarySources(options) {
|
|
59
|
+
const env = options?.env ?? process.env;
|
|
60
|
+
const explicit = [
|
|
61
|
+
...(options?.cliEntries ?? []).flatMap((entry) => parseRecipeLibraryPath(entry)),
|
|
62
|
+
...(env.RECIPE_LIBRARY_PATH ? parseRecipeLibraryPath(env.RECIPE_LIBRARY_PATH) : []),
|
|
63
|
+
];
|
|
64
|
+
if (explicit.length > 0)
|
|
65
|
+
return explicit;
|
|
66
|
+
return defaultRecipeLibrarySources(env);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load and merge ordered library sources into one flow resolution. Shadowing
|
|
70
|
+
* across sources is recorded and logged; duplicate refs within one source are
|
|
71
|
+
* an error, matching recipe-local catalog behavior.
|
|
72
|
+
*/
|
|
73
|
+
export async function loadRecipeLibraries(sources, logger) {
|
|
74
|
+
const loadedSources = [];
|
|
75
|
+
const flows = new Map();
|
|
76
|
+
const seenNames = new Set();
|
|
77
|
+
for (const source of sources) {
|
|
78
|
+
const root = path.resolve(expandTilde(source.root));
|
|
79
|
+
const manifest = await readLibraryManifest(root);
|
|
80
|
+
const name = source.name ?? manifest.name ?? path.basename(root);
|
|
81
|
+
if (seenNames.has(name)) {
|
|
82
|
+
throw new Error(`Recipe library source ${name} is configured more than once.`);
|
|
83
|
+
}
|
|
84
|
+
seenNames.add(name);
|
|
85
|
+
const sourceFlows = new Map();
|
|
86
|
+
for (const file of await listFlowCatalogFiles(root)) {
|
|
87
|
+
const catalogPath = path.join(root, LIBRARY_FLOWS_DIR, file);
|
|
88
|
+
const catalog = await readJsonFile(catalogPath);
|
|
89
|
+
assertFlowCatalogKind(catalog, catalogPath);
|
|
90
|
+
for (const entry of readCatalogFlows(catalog, catalogPath)) {
|
|
91
|
+
if (sourceFlows.has(entry.ref)) {
|
|
92
|
+
throw new Error(`Flow ${entry.ref} is declared more than once in library ${name}.`);
|
|
93
|
+
}
|
|
94
|
+
sourceFlows.set(entry.ref, {
|
|
95
|
+
ref: entry.ref,
|
|
96
|
+
flow: entry.flow,
|
|
97
|
+
raw: entry.raw,
|
|
98
|
+
source: name,
|
|
99
|
+
file: path.join(LIBRARY_FLOWS_DIR, file),
|
|
100
|
+
shadows: [],
|
|
101
|
+
...(lastVerifiedDate(entry.raw) ? { lastVerified: lastVerifiedDate(entry.raw) } : {}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
loadedSources.push({ name, root, flowCount: sourceFlows.size });
|
|
106
|
+
for (const [ref, resolved] of sourceFlows) {
|
|
107
|
+
const winner = flows.get(ref);
|
|
108
|
+
if (winner) {
|
|
109
|
+
winner.shadows.push(name);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
flows.set(ref, resolved);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (logger)
|
|
117
|
+
logResolution(logger, { sources: loadedSources, flows });
|
|
118
|
+
return { sources: loadedSources, flows };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Merge recipe-local flows over library flows. Recipe-local declarations
|
|
122
|
+
* (inline `flows` and explicit `uses` catalogs) always win — the recipe author
|
|
123
|
+
* spelled them out — and any library refs they override are returned (and
|
|
124
|
+
* logged) so runs can report them even for programmatic consumers without a
|
|
125
|
+
* logger. Library flow lookups are recorded into `usedLibraryFlows` so runs
|
|
126
|
+
* can report exactly which library flows produced the proof.
|
|
127
|
+
*/
|
|
128
|
+
export function createEffectiveFlowCatalog(recipeFlows, resolution, usedLibraryFlows, logger) {
|
|
129
|
+
if (!resolution || resolution.flows.size === 0) {
|
|
130
|
+
return { catalog: recipeFlows, overrides: [] };
|
|
131
|
+
}
|
|
132
|
+
const fromLibrary = new Map();
|
|
133
|
+
const merged = new TrackingFlowCatalog(fromLibrary, usedLibraryFlows);
|
|
134
|
+
const overrides = [];
|
|
135
|
+
for (const [ref, resolved] of resolution.flows) {
|
|
136
|
+
merged.set(ref, resolved.flow);
|
|
137
|
+
fromLibrary.set(ref, resolved);
|
|
138
|
+
}
|
|
139
|
+
for (const [ref, flow] of recipeFlows) {
|
|
140
|
+
const overridden = fromLibrary.get(ref);
|
|
141
|
+
if (overridden) {
|
|
142
|
+
fromLibrary.delete(ref);
|
|
143
|
+
overrides.push({ ref, source: overridden.source });
|
|
144
|
+
logger?.warn(`Flow ${ref} is declared by the recipe and overrides the ${overridden.source} library declaration.`);
|
|
145
|
+
}
|
|
146
|
+
merged.set(ref, flow);
|
|
147
|
+
}
|
|
148
|
+
return { catalog: merged, overrides };
|
|
149
|
+
}
|
|
150
|
+
class TrackingFlowCatalog extends Map {
|
|
151
|
+
#fromLibrary;
|
|
152
|
+
#used;
|
|
153
|
+
constructor(fromLibrary, used) {
|
|
154
|
+
super();
|
|
155
|
+
this.#fromLibrary = fromLibrary;
|
|
156
|
+
this.#used = used;
|
|
157
|
+
}
|
|
158
|
+
get(ref) {
|
|
159
|
+
const flow = super.get(ref);
|
|
160
|
+
if (flow) {
|
|
161
|
+
const resolved = this.#fromLibrary.get(ref);
|
|
162
|
+
if (resolved)
|
|
163
|
+
this.#used.set(ref, resolved);
|
|
164
|
+
}
|
|
165
|
+
return flow;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function logResolution(logger, resolution) {
|
|
169
|
+
const summary = resolution.sources
|
|
170
|
+
.map((source) => `${source.name}=${source.root} (${source.flowCount} flows)`)
|
|
171
|
+
.join(', ');
|
|
172
|
+
logger.info(`Recipe libraries: ${summary || 'none'}`);
|
|
173
|
+
for (const flow of resolution.flows.values()) {
|
|
174
|
+
if (flow.shadows.length > 0) {
|
|
175
|
+
logger.warn(`Flow ${flow.ref} resolves from ${flow.source} and shadows ${flow.shadows.join(', ')}.`);
|
|
176
|
+
}
|
|
177
|
+
const staleDays = daysSince(flow.lastVerified);
|
|
178
|
+
if (staleDays != null && staleDays > LAST_VERIFIED_WARN_AFTER_DAYS) {
|
|
179
|
+
logger.warn(`Flow ${flow.ref} (${flow.source}) was last verified ${staleDays} days ago; re-verify before trusting it as proof setup.`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async function readLibraryManifest(root) {
|
|
184
|
+
const manifestPath = path.join(root, LIBRARY_MANIFEST_FILE);
|
|
185
|
+
let manifest;
|
|
186
|
+
try {
|
|
187
|
+
manifest = await readJsonFile(manifestPath);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
191
|
+
throw new Error(`${root} is not a recipe library: ${message}. A library needs a ${LIBRARY_MANIFEST_FILE} with kind "recipe-library".`);
|
|
192
|
+
}
|
|
193
|
+
if (!isRecord(manifest) || manifest.kind !== 'recipe-library') {
|
|
194
|
+
throw new Error(`${manifestPath} must declare kind "recipe-library".`);
|
|
195
|
+
}
|
|
196
|
+
return { ...(typeof manifest.name === 'string' && manifest.name ? { name: manifest.name } : {}) };
|
|
197
|
+
}
|
|
198
|
+
/** Catalog file names (relative to `<root>/flows/`) of a library, sorted. */
|
|
199
|
+
export async function listFlowCatalogFiles(root) {
|
|
200
|
+
let entries;
|
|
201
|
+
try {
|
|
202
|
+
entries = await readdir(path.join(root, LIBRARY_FLOWS_DIR), { withFileTypes: true });
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
if (error?.code === 'ENOENT')
|
|
206
|
+
return [];
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
return entries
|
|
210
|
+
.filter((entry) => (entry.isFile() || entry.isSymbolicLink()) &&
|
|
211
|
+
entry.name.endsWith(LIBRARY_FLOW_CATALOG_SUFFIX))
|
|
212
|
+
.map((entry) => entry.name)
|
|
213
|
+
.sort();
|
|
214
|
+
}
|
|
215
|
+
function assertFlowCatalogKind(catalog, catalogPath) {
|
|
216
|
+
if (!isRecord(catalog) || catalog.kind !== 'recipe-flow-catalog') {
|
|
217
|
+
throw new Error(`${catalogPath} must declare kind "recipe-flow-catalog".`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function lastVerifiedDate(raw) {
|
|
221
|
+
const provenance = raw.provenance;
|
|
222
|
+
if (!isRecord(provenance))
|
|
223
|
+
return undefined;
|
|
224
|
+
const lastVerified = provenance.lastVerified;
|
|
225
|
+
if (isRecord(lastVerified) && typeof lastVerified.date === 'string')
|
|
226
|
+
return lastVerified.date;
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
function daysSince(date) {
|
|
230
|
+
if (!date)
|
|
231
|
+
return undefined;
|
|
232
|
+
const timestamp = Date.parse(date);
|
|
233
|
+
if (Number.isNaN(timestamp))
|
|
234
|
+
return undefined;
|
|
235
|
+
return Math.floor((Date.now() - timestamp) / (24 * 60 * 60 * 1000));
|
|
236
|
+
}
|
|
237
|
+
function expandTilde(p) {
|
|
238
|
+
return p === '~' || p.startsWith('~/') ? path.join(homedir(), p.slice(1)) : p;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=library.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library.js","sourceRoot":"","sources":["../../src/core/library.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RecipeLogger } from './types.js';
|
|
2
|
+
export interface PromoteFlowRequest {
|
|
3
|
+
/** Per-change recipe declaring the flow inline under `flows`. */
|
|
4
|
+
recipePath: string;
|
|
5
|
+
/** Flow ref to promote. */
|
|
6
|
+
flowRef: string;
|
|
7
|
+
/** Target library root; a library skeleton is created when missing. */
|
|
8
|
+
targetRoot: string;
|
|
9
|
+
/** Target library name, used when creating the skeleton and in messages. */
|
|
10
|
+
targetName: string;
|
|
11
|
+
/** Catalog file stem override; defaults to the ref minus its last segment. */
|
|
12
|
+
domain?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Artifacts directory of a passing run that exercised the flow. Stamps
|
|
15
|
+
* `provenance.lastVerified` from its summary.json; without it the promoted
|
|
16
|
+
* flow carries no verification claim.
|
|
17
|
+
*/
|
|
18
|
+
runArtifactsDir?: string;
|
|
19
|
+
/** Overwrite an existing declaration of the same ref in the target library. */
|
|
20
|
+
force?: boolean;
|
|
21
|
+
logger?: RecipeLogger;
|
|
22
|
+
}
|
|
23
|
+
export interface PromoteFlowResult {
|
|
24
|
+
ref: string;
|
|
25
|
+
/** Absolute catalog file path the flow was written to. */
|
|
26
|
+
catalogPath: string;
|
|
27
|
+
/** True when the library skeleton (library.json + flows/) was created. */
|
|
28
|
+
createdLibrary: boolean;
|
|
29
|
+
lastVerified?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Promote an inline flow from a per-change recipe into a recipe library.
|
|
33
|
+
* Per ADR-style recipe semantics the recipe itself stays throwaway; promote is
|
|
34
|
+
* the explicit "keep" step that turns a proven setup flow into a durable,
|
|
35
|
+
* contract-checked library entry. Promotion enforces the flow-catalog
|
|
36
|
+
* contract: a description is required, `ensure_*` flows must declare a
|
|
37
|
+
* postcondition, and provenance (origin recipe, promotion date, optional
|
|
38
|
+
* last-verified evidence) is stamped onto the stored flow.
|
|
39
|
+
*/
|
|
40
|
+
export declare function promoteRecipeFlow(request: PromoteFlowRequest): Promise<PromoteFlowResult>;
|
|
41
|
+
//# sourceMappingURL=promote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote.d.ts","sourceRoot":"","sources":["../../src/core/promote.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmF/F"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { mkdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
4
|
+
import { readCatalogFlows } from './flows.js';
|
|
5
|
+
import { isRecord, readJsonFile, writeJsonFile } from './json.js';
|
|
6
|
+
import { listFlowCatalogFiles } from './library.js';
|
|
7
|
+
const LIBRARY_MANIFEST_FILE = 'library.json';
|
|
8
|
+
const LIBRARY_FLOWS_DIR = 'flows';
|
|
9
|
+
/**
|
|
10
|
+
* Promote an inline flow from a per-change recipe into a recipe library.
|
|
11
|
+
* Per ADR-style recipe semantics the recipe itself stays throwaway; promote is
|
|
12
|
+
* the explicit "keep" step that turns a proven setup flow into a durable,
|
|
13
|
+
* contract-checked library entry. Promotion enforces the flow-catalog
|
|
14
|
+
* contract: a description is required, `ensure_*` flows must declare a
|
|
15
|
+
* postcondition, and provenance (origin recipe, promotion date, optional
|
|
16
|
+
* last-verified evidence) is stamped onto the stored flow.
|
|
17
|
+
*/
|
|
18
|
+
export async function promoteRecipeFlow(request) {
|
|
19
|
+
const recipePath = path.resolve(request.recipePath);
|
|
20
|
+
const recipe = await readJsonFile(recipePath);
|
|
21
|
+
if (!isRecord(recipe))
|
|
22
|
+
throw new Error(`${request.recipePath} is not a recipe document.`);
|
|
23
|
+
const inlineFlows = isRecord(recipe.flows) ? recipe.flows : {};
|
|
24
|
+
const flow = inlineFlows[request.flowRef];
|
|
25
|
+
if (!isRecord(flow)) {
|
|
26
|
+
const available = Object.keys(inlineFlows);
|
|
27
|
+
throw new Error(`Flow ${request.flowRef} is not declared inline in ${request.recipePath}. Promote extracts inline flows from per-change recipes${available.length > 0 ? `; available: ${available.join(', ')}` : ''}.`);
|
|
28
|
+
}
|
|
29
|
+
assertPromotableFlow(request.flowRef, flow, request.logger);
|
|
30
|
+
const lastVerified = request.runArtifactsDir
|
|
31
|
+
? await readVerifiedRunDate(request.runArtifactsDir, request.flowRef, flow)
|
|
32
|
+
: undefined;
|
|
33
|
+
const targetRoot = path.resolve(request.targetRoot);
|
|
34
|
+
const createdLibrary = await ensureLibrarySkeleton(targetRoot, request.targetName);
|
|
35
|
+
// The whole library is checked, not just the target catalog file: one
|
|
36
|
+
// library must never declare the same ref twice, or every later resolution
|
|
37
|
+
// of it fails. With --force the flow is overwritten in the file that
|
|
38
|
+
// already declares it, never written to a second one.
|
|
39
|
+
const declaringCatalogs = await findFlowDeclarations(targetRoot, request.flowRef);
|
|
40
|
+
if (declaringCatalogs.length > 1) {
|
|
41
|
+
// Pre-existing corruption: promote cannot pick which declaration is the
|
|
42
|
+
// stale one, and overwriting only one of them would leave the library
|
|
43
|
+
// unloadable. Fail loudly with every offending file, --force or not.
|
|
44
|
+
throw new Error(`Recipe library ${targetRoot} already declares ${request.flowRef} in ${declaringCatalogs.length} catalogs (${declaringCatalogs
|
|
45
|
+
.map((file) => path.basename(file))
|
|
46
|
+
.join(', ')}); the library cannot load until exactly one declaration remains. Remove the stale duplicate(s), then re-run promote.`);
|
|
47
|
+
}
|
|
48
|
+
const existingCatalogPath = declaringCatalogs[0];
|
|
49
|
+
if (existingCatalogPath && !request.force) {
|
|
50
|
+
throw new Error(`Flow ${request.flowRef} already exists in ${existingCatalogPath}. Edit the catalog directly or pass --force to overwrite it in place.`);
|
|
51
|
+
}
|
|
52
|
+
const stem = request.domain ?? domainStem(request.flowRef);
|
|
53
|
+
const catalogPath = existingCatalogPath ?? path.join(targetRoot, LIBRARY_FLOWS_DIR, `${stem}.flows.json`);
|
|
54
|
+
if (existingCatalogPath &&
|
|
55
|
+
request.domain &&
|
|
56
|
+
path.basename(existingCatalogPath) !== `${request.domain}.flows.json`) {
|
|
57
|
+
request.logger?.warn(`Flow ${request.flowRef} already lives in ${path.basename(existingCatalogPath)}; --domain ${request.domain} is ignored to avoid declaring the ref twice.`);
|
|
58
|
+
}
|
|
59
|
+
const catalog = await readCatalog(catalogPath);
|
|
60
|
+
const promoted = {
|
|
61
|
+
...flow,
|
|
62
|
+
version: typeof flow.version === 'number' ? flow.version : 1,
|
|
63
|
+
provenance: {
|
|
64
|
+
promotedFrom: {
|
|
65
|
+
recipe: typeof recipe.title === 'string' ? recipe.title : path.basename(recipePath),
|
|
66
|
+
},
|
|
67
|
+
promotedAt: isoDate(new Date()),
|
|
68
|
+
...(lastVerified ? { lastVerified: { date: lastVerified } } : {}),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
catalog.flows = {
|
|
72
|
+
...(isRecord(catalog.flows) ? catalog.flows : {}),
|
|
73
|
+
[request.flowRef]: promoted,
|
|
74
|
+
};
|
|
75
|
+
await writeJsonFile(catalogPath, catalog);
|
|
76
|
+
return {
|
|
77
|
+
ref: request.flowRef,
|
|
78
|
+
catalogPath,
|
|
79
|
+
createdLibrary,
|
|
80
|
+
...(lastVerified ? { lastVerified } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function assertPromotableFlow(ref, flow, logger) {
|
|
84
|
+
// Reuse catalog normalization so promotion fails on the same shapes a
|
|
85
|
+
// library load would reject.
|
|
86
|
+
readCatalogFlows({ flows: { [ref]: flow } }, 'promote');
|
|
87
|
+
if (typeof flow.description !== 'string' || !flow.description.trim()) {
|
|
88
|
+
throw new Error(`Flow ${ref} needs a description before promotion — library flows are agent-facing contracts.`);
|
|
89
|
+
}
|
|
90
|
+
const localName = ref.split('.').at(-1) ?? ref;
|
|
91
|
+
if (localName.startsWith('ensure_') && flow.postcondition == null) {
|
|
92
|
+
throw new Error(`Flow ${ref} is an ensure_* flow and must declare a postcondition proving convergence before promotion.`);
|
|
93
|
+
}
|
|
94
|
+
if (flow.paramsSchema == null) {
|
|
95
|
+
logger?.warn(`Flow ${ref} has no paramsSchema; add one so agents can discover valid parameters.`);
|
|
96
|
+
}
|
|
97
|
+
if (flow.postcondition == null) {
|
|
98
|
+
logger?.warn(`Flow ${ref} has no postcondition; stale library flows fail loudly only when they assert their outcome.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function readVerifiedRunDate(artifactsDir, flowRef, flow) {
|
|
102
|
+
const resolvedDir = path.resolve(artifactsDir);
|
|
103
|
+
const summaryPath = path.join(resolvedDir, 'summary.json');
|
|
104
|
+
const summary = await readJsonFile(summaryPath);
|
|
105
|
+
if (!isRecord(summary))
|
|
106
|
+
throw new Error(`${summaryPath} is not a run summary.`);
|
|
107
|
+
if (summary.status !== 'pass') {
|
|
108
|
+
throw new Error(`Run summary ${summaryPath} has status ${String(summary.status)}; only passing runs can stamp lastVerified.`);
|
|
109
|
+
}
|
|
110
|
+
const endedAt = typeof summary.endedAt === 'string' ? Date.parse(summary.endedAt) : Number.NaN;
|
|
111
|
+
if (Number.isNaN(endedAt)) {
|
|
112
|
+
throw new Error(`Run summary ${summaryPath} has no parseable endedAt; refusing to stamp lastVerified from incomplete evidence.`);
|
|
113
|
+
}
|
|
114
|
+
await assertRunExercisedFlow(resolvedDir, summary, flowRef, flow);
|
|
115
|
+
return isoDate(new Date(endedAt));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* lastVerified is a claim reviewers rely on, so it must be backed by evidence
|
|
119
|
+
* the run actually executed this flow — a bare passing summary is not enough.
|
|
120
|
+
* Accepted evidence: the run resolved the ref from a library
|
|
121
|
+
* (summary.flowResolution.used), or the run's copied recipe declares exactly
|
|
122
|
+
* this flow inline and its trace shows a successful call to it.
|
|
123
|
+
* Honor-system limit: the developer owns both the artifacts and the catalog,
|
|
124
|
+
* so hand-forged artifacts can still pass — detecting that would need signed
|
|
125
|
+
* run evidence, which is out of scope.
|
|
126
|
+
*/
|
|
127
|
+
async function assertRunExercisedFlow(artifactsDir, summary, flowRef, flow) {
|
|
128
|
+
const flowResolution = summary.flowResolution;
|
|
129
|
+
if (isRecord(flowResolution) && Array.isArray(flowResolution.used)) {
|
|
130
|
+
if (flowResolution.used.some((entry) => isRecord(entry) && entry.ref === flowRef))
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
let runRecipe;
|
|
134
|
+
try {
|
|
135
|
+
runRecipe = await readJsonFile(path.join(artifactsDir, 'recipe.json'));
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
throw evidenceError(flowRef, artifactsDir, 'the run artifacts have no readable recipe.json');
|
|
139
|
+
}
|
|
140
|
+
const runFlow = isRecord(runRecipe) && isRecord(runRecipe.flows) ? runRecipe.flows[flowRef] : undefined;
|
|
141
|
+
if (!isRecord(runFlow)) {
|
|
142
|
+
throw evidenceError(flowRef, artifactsDir, 'the run neither resolved the flow from a library nor declared it inline in its recipe');
|
|
143
|
+
}
|
|
144
|
+
if (!isDeepStrictEqual(runFlow, flow)) {
|
|
145
|
+
throw evidenceError(flowRef, artifactsDir, 'the run recipe declares a different definition of the flow than the one being promoted');
|
|
146
|
+
}
|
|
147
|
+
const callNodeIds = collectCallNodeIds(runRecipe, flowRef);
|
|
148
|
+
if (callNodeIds.size === 0) {
|
|
149
|
+
throw evidenceError(flowRef, artifactsDir, 'the run recipe never calls the flow');
|
|
150
|
+
}
|
|
151
|
+
const traceEntries = await readTraceEntries(artifactsDir);
|
|
152
|
+
const executed = traceEntries.some((entry) => isRecord(entry) &&
|
|
153
|
+
entry.ok === true &&
|
|
154
|
+
typeof entry.nodeId === 'string' &&
|
|
155
|
+
callNodeIds.has(entry.nodeId));
|
|
156
|
+
if (!executed) {
|
|
157
|
+
throw evidenceError(flowRef, artifactsDir, 'the run trace has no successful call to the flow');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function evidenceError(flowRef, artifactsDir, reason) {
|
|
161
|
+
return new Error(`Cannot stamp lastVerified for ${flowRef} from ${artifactsDir}: ${reason}. Pass artifacts of a run that exercised this flow, or promote without --run.`);
|
|
162
|
+
}
|
|
163
|
+
async function readTraceEntries(artifactsDir) {
|
|
164
|
+
let trace;
|
|
165
|
+
try {
|
|
166
|
+
trace = await readJsonFile(path.join(artifactsDir, 'trace.json'));
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
if (Array.isArray(trace))
|
|
172
|
+
return trace;
|
|
173
|
+
if (isRecord(trace) && Array.isArray(trace.entries))
|
|
174
|
+
return trace.entries;
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
/** Node ids of every `call` to the ref, anywhere a recipe can declare nodes. */
|
|
178
|
+
function collectCallNodeIds(recipe, flowRef, out = new Set()) {
|
|
179
|
+
if (!isRecord(recipe))
|
|
180
|
+
return out;
|
|
181
|
+
if (isRecord(recipe.startState) &&
|
|
182
|
+
recipe.startState.action === 'call' &&
|
|
183
|
+
recipe.startState.ref === flowRef) {
|
|
184
|
+
out.add('startState');
|
|
185
|
+
}
|
|
186
|
+
for (const [key, child] of Object.entries(recipe)) {
|
|
187
|
+
if (key === 'nodes' && isRecord(child)) {
|
|
188
|
+
for (const [nodeId, node] of Object.entries(child)) {
|
|
189
|
+
if (isRecord(node) && node.action === 'call' && node.ref === flowRef)
|
|
190
|
+
out.add(nodeId);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
collectCallNodeIds(child, flowRef, out);
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
async function ensureLibrarySkeleton(targetRoot, name) {
|
|
198
|
+
const manifestPath = path.join(targetRoot, LIBRARY_MANIFEST_FILE);
|
|
199
|
+
let manifestText;
|
|
200
|
+
try {
|
|
201
|
+
manifestText = await readFile(manifestPath, 'utf-8');
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
manifestText = undefined;
|
|
205
|
+
}
|
|
206
|
+
if (manifestText === undefined) {
|
|
207
|
+
await mkdir(path.join(targetRoot, LIBRARY_FLOWS_DIR), { recursive: true });
|
|
208
|
+
await writeJsonFile(manifestPath, { kind: 'recipe-library', schema_version: 1, name });
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
const manifest = JSON.parse(manifestText);
|
|
212
|
+
if (!isRecord(manifest) || manifest.kind !== 'recipe-library') {
|
|
213
|
+
throw new Error(`${manifestPath} must declare kind "recipe-library".`);
|
|
214
|
+
}
|
|
215
|
+
await mkdir(path.join(targetRoot, LIBRARY_FLOWS_DIR), { recursive: true });
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
async function findFlowDeclarations(targetRoot, ref) {
|
|
219
|
+
const declarations = [];
|
|
220
|
+
for (const file of await listFlowCatalogFiles(targetRoot)) {
|
|
221
|
+
const catalogPath = path.join(targetRoot, LIBRARY_FLOWS_DIR, file);
|
|
222
|
+
const catalog = await readJsonFile(catalogPath);
|
|
223
|
+
if (isRecord(catalog) && isRecord(catalog.flows) && catalog.flows[ref] != null) {
|
|
224
|
+
declarations.push(catalogPath);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return declarations;
|
|
228
|
+
}
|
|
229
|
+
async function readCatalog(catalogPath) {
|
|
230
|
+
let catalog;
|
|
231
|
+
try {
|
|
232
|
+
catalog = await readJsonFile(catalogPath);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return { schema_version: 1, kind: 'recipe-flow-catalog', flows: {} };
|
|
236
|
+
}
|
|
237
|
+
if (!isRecord(catalog) || catalog.kind !== 'recipe-flow-catalog') {
|
|
238
|
+
throw new Error(`${catalogPath} must declare kind "recipe-flow-catalog".`);
|
|
239
|
+
}
|
|
240
|
+
return { ...catalog };
|
|
241
|
+
}
|
|
242
|
+
function domainStem(ref) {
|
|
243
|
+
const segments = ref.split('.').filter(Boolean);
|
|
244
|
+
return segments.length > 1 ? segments.slice(0, -1).join('.') : 'main';
|
|
245
|
+
}
|
|
246
|
+
function isoDate(date) {
|
|
247
|
+
return date.toISOString().slice(0, 10);
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=promote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promote.js","sourceRoot":"","sources":["../../src/core/promote.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,aAAa,EAEb,yBAAyB,EAMzB,YAAY,EAOb,MAAM,YAAY,CAAC;AAapB,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAGzE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,YAAY,CA+CnF"}
|