@farmslot/agent-runtime 0.3.0 → 0.4.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 +8 -0
- package/bin/farmslot-agent.mjs +1 -1
- package/dist/execution-template/execution-template.test.js +278 -1
- package/dist/execution-template/execution-template.test.js.map +1 -1
- package/dist/execution-template/frontmatter.js +1 -1
- package/dist/execution-template/frontmatter.js.map +1 -1
- package/dist/execution-template/index.d.ts +8 -1
- package/dist/execution-template/index.d.ts.map +1 -1
- package/dist/execution-template/index.js +5 -0
- package/dist/execution-template/index.js.map +1 -1
- package/dist/execution-template/infer.d.ts.map +1 -1
- package/dist/execution-template/infer.js +12 -1
- package/dist/execution-template/infer.js.map +1 -1
- package/dist/execution-template/project-worker.d.ts +19 -0
- package/dist/execution-template/project-worker.d.ts.map +1 -0
- package/dist/execution-template/project-worker.js +143 -0
- package/dist/execution-template/project-worker.js.map +1 -0
- package/dist/execution-template/resolve.d.ts +1 -1
- package/dist/execution-template/resolve.d.ts.map +1 -1
- package/dist/execution-template/resolve.js +12 -2
- package/dist/execution-template/resolve.js.map +1 -1
- package/dist/execution-template/select.d.ts +8 -0
- package/dist/execution-template/select.d.ts.map +1 -0
- package/dist/execution-template/select.js +80 -0
- package/dist/execution-template/select.js.map +1 -0
- package/dist/execution-template/snapshot.d.ts +13 -0
- package/dist/execution-template/snapshot.d.ts.map +1 -0
- package/dist/execution-template/snapshot.js +46 -0
- package/dist/execution-template/snapshot.js.map +1 -0
- package/dist/execution-template/source-config.d.ts +19 -0
- package/dist/execution-template/source-config.d.ts.map +1 -0
- package/dist/execution-template/source-config.js +90 -0
- package/dist/execution-template/source-config.js.map +1 -0
- package/dist/execution-template/types.d.ts +35 -1
- package/dist/execution-template/types.d.ts.map +1 -1
- package/dist/execution-template/types.js +7 -2
- package/dist/execution-template/types.js.map +1 -1
- package/package.json +4 -3
- package/scripts/check-task-artifact-contract.mjs +25 -34
- package/scripts/execution-template-cli.mjs +150 -19
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export class ExecutionTemplateSelectionError extends Error {
|
|
2
|
+
constructor(code, message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.code = code;
|
|
5
|
+
this.name = 'ExecutionTemplateSelectionError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
3
8
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/execution-template/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/execution-template/types.ts"],"names":[],"mappings":"AAmGA,MAAM,OAAO,+BAAgC,SAAQ,KAAK;IACxD,YACkB,IAAyC,EACzD,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAqC;QAIzD,IAAI,CAAC,IAAI,GAAG,iCAAiC,CAAC;IAChD,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farmslot/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"./scripts/mark-checklist-step.cjs": "./scripts/mark-checklist-step.cjs",
|
|
17
17
|
"./scripts/checklist-target.cjs": "./scripts/checklist-target.cjs",
|
|
18
18
|
"./scripts/worker-terminal-contract.cjs": "./scripts/worker-terminal-contract.cjs",
|
|
19
|
-
"./scripts/check-task-artifact-contract.mjs": "./scripts/check-task-artifact-contract.mjs"
|
|
19
|
+
"./scripts/check-task-artifact-contract.mjs": "./scripts/check-task-artifact-contract.mjs",
|
|
20
|
+
"./scripts/execution-template-cli.mjs": "./scripts/execution-template-cli.mjs"
|
|
20
21
|
},
|
|
21
22
|
"scripts": {
|
|
22
23
|
"typecheck": "yarn workspace @farmslot/protocol build && tsc --noEmit --project tsconfig.json",
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"prepublishOnly": "node ../../scripts/quality/check-farmslot-package-readiness.mjs --publish --packages @farmslot/agent-runtime"
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
34
|
-
"@farmslot/protocol": "0.
|
|
35
|
+
"@farmslot/protocol": "0.13.0"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"@types/node": "^22.0.0",
|
|
@@ -39,14 +39,14 @@ try {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
let recipeProtocol = null;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
if (process.env.FARMSLOT_TEST_DISABLE_RECIPE_PROTOCOL !== '1') {
|
|
43
|
+
try {
|
|
44
|
+
recipeProtocol = await import('@farmslot/protocol/recipe');
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (!isMissingWorkspaceProtocolBuild(error, 'dist/recipe/index.js')) throw error;
|
|
47
|
+
if (process.env.FARMSLOT_DEBUG_AGENT_RUNTIME) {
|
|
48
|
+
console.warn(`[agent-runtime] shared Recipe v1 validator unavailable: ${error.message}`);
|
|
49
|
+
}
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
if (recipeProtocol) {
|
|
@@ -325,6 +325,7 @@ function validateRecipeDocumentArtifact() {
|
|
|
325
325
|
`${packageRoot}/artifact-manifest.json`,
|
|
326
326
|
'recipe-run/artifact-manifest.json',
|
|
327
327
|
);
|
|
328
|
+
const trace = readJsonArtifact(`${packageRoot}/trace.json`, 'recipe-run/trace.json');
|
|
328
329
|
const recipeResolution = readJsonArtifact(
|
|
329
330
|
`${packageRoot}/recipe-resolution.json`,
|
|
330
331
|
'recipe-run/recipe-resolution.json',
|
|
@@ -339,34 +340,24 @@ function validateRecipeDocumentArtifact() {
|
|
|
339
340
|
if (document !== undefined) resolvedRecipes[String(dependency.digest)] = document;
|
|
340
341
|
}
|
|
341
342
|
}
|
|
342
|
-
if (sharedRecipeArtifactPackageValidator) {
|
|
343
|
-
|
|
344
|
-
recipe,
|
|
345
|
-
|
|
346
|
-
recipeResolution,
|
|
347
|
-
resolvedRecipes,
|
|
348
|
-
artifactPaths: listArtifactPaths(path.join(taskDir, packageRoot)),
|
|
349
|
-
});
|
|
350
|
-
for (const finding of result.findings) {
|
|
351
|
-
if (finding.severity === 'error') {
|
|
352
|
-
issues.push(`${finding.code} ${finding.path}: ${finding.message}`);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
343
|
+
if (!sharedRecipeArtifactPackageValidator) {
|
|
344
|
+
issues.push(
|
|
345
|
+
'recipe-run package validation requires built @farmslot/protocol; build the protocol package and retry',
|
|
346
|
+
);
|
|
355
347
|
return;
|
|
356
348
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
validateRecipeDocumentValue(document, `resolved recipe ${digest}`, { externalRecipeIds });
|
|
349
|
+
const result = sharedRecipeArtifactPackageValidator({
|
|
350
|
+
recipe,
|
|
351
|
+
manifest,
|
|
352
|
+
trace,
|
|
353
|
+
recipeResolution,
|
|
354
|
+
resolvedRecipes,
|
|
355
|
+
artifactPaths: listArtifactPaths(path.join(taskDir, packageRoot)),
|
|
356
|
+
});
|
|
357
|
+
for (const finding of result.findings) {
|
|
358
|
+
if (finding.severity === 'error') {
|
|
359
|
+
issues.push(`${finding.code} ${finding.path}: ${finding.message}`);
|
|
360
|
+
}
|
|
370
361
|
}
|
|
371
362
|
}
|
|
372
363
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Standalone execution-template CLI for ADR-049.
|
|
4
4
|
* Used by `farmslot-agent execution-template` and thin Consensys wrappers.
|
|
5
5
|
*/
|
|
6
|
-
import { existsSync, statSync } from 'node:fs';
|
|
6
|
+
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs';
|
|
7
7
|
import { dirname, resolve } from 'node:path';
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
9
9
|
|
|
@@ -12,11 +12,13 @@ const distEntry = resolve(packageRoot, 'dist', 'index.js');
|
|
|
12
12
|
|
|
13
13
|
function usage(exitCode = 0) {
|
|
14
14
|
const text = [
|
|
15
|
-
'Usage: execution-template <list|lint|new> [options]',
|
|
15
|
+
'Usage: execution-template <list|materialize|lint|new> [options]',
|
|
16
16
|
'',
|
|
17
|
-
'list --dir <path> --project-worker <path> --package-templates <path>',
|
|
17
|
+
'list --dir <path> --domain-dir <domain=path> --project-worker <path> --package-templates <path>',
|
|
18
18
|
' [--project-name name] [--package-id id] [--flow f] [--run-mode m]',
|
|
19
|
-
' [--platform p] [--no-include-shadowed] [--json]',
|
|
19
|
+
' [--platform p] [--domain d] [--no-include-shadowed] [--json]',
|
|
20
|
+
'materialize <output> --flow f --run-mode m --platform p [--domain d] [--id id]',
|
|
21
|
+
' [the same source options as list] [--provenance path] [--json]',
|
|
20
22
|
'lint <file-or-dir> [--json]',
|
|
21
23
|
'new <path> [--flow f] [--run-mode m] [--platform p] [--title t] [--force] [--json]',
|
|
22
24
|
].join('\n');
|
|
@@ -44,9 +46,22 @@ function parseRunMode(value) {
|
|
|
44
46
|
throw new Error(`--run-mode must be autonomous|interactive|validation (got ${value})`);
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
function parseDomainDir(value) {
|
|
50
|
+
const separator = value.indexOf('=');
|
|
51
|
+
if (separator <= 0 || separator === value.length - 1) {
|
|
52
|
+
throw new Error('--domain-dir must use domain=path');
|
|
53
|
+
}
|
|
54
|
+
const domain = value.slice(0, separator);
|
|
55
|
+
if (!/^[a-z][a-z0-9-]*$/.test(domain)) {
|
|
56
|
+
throw new Error(`--domain-dir domain must be a lowercase slug (got ${domain})`);
|
|
57
|
+
}
|
|
58
|
+
return { domain, root: value.slice(separator + 1) };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parseCatalogArgs(args, { materialize = false } = {}) {
|
|
48
62
|
const opts = {
|
|
49
63
|
dirs: [],
|
|
64
|
+
domainDirs: [],
|
|
50
65
|
projectWorker: null,
|
|
51
66
|
projectName: 'project',
|
|
52
67
|
packageTemplates: null,
|
|
@@ -54,12 +69,18 @@ async function cmdList(args, runtime) {
|
|
|
54
69
|
flow: undefined,
|
|
55
70
|
runMode: undefined,
|
|
56
71
|
platform: undefined,
|
|
72
|
+
domain: undefined,
|
|
73
|
+
id: undefined,
|
|
57
74
|
includeShadowed: true,
|
|
75
|
+
output: null,
|
|
76
|
+
provenance: null,
|
|
58
77
|
json: false,
|
|
59
78
|
};
|
|
60
79
|
for (let i = 0; i < args.length; i += 1) {
|
|
61
80
|
const arg = args[i];
|
|
62
81
|
if (arg === '--dir') opts.dirs.push(takeValue(args, i++, arg));
|
|
82
|
+
else if (arg === '--domain-dir')
|
|
83
|
+
opts.domainDirs.push(parseDomainDir(takeValue(args, i++, arg)));
|
|
63
84
|
else if (arg === '--project-worker') opts.projectWorker = takeValue(args, i++, arg);
|
|
64
85
|
else if (arg === '--project-name') opts.projectName = takeValue(args, i++, arg);
|
|
65
86
|
else if (arg === '--package-templates') opts.packageTemplates = takeValue(args, i++, arg);
|
|
@@ -67,20 +88,51 @@ async function cmdList(args, runtime) {
|
|
|
67
88
|
else if (arg === '--flow') opts.flow = takeValue(args, i++, arg);
|
|
68
89
|
else if (arg === '--run-mode') opts.runMode = parseRunMode(takeValue(args, i++, arg));
|
|
69
90
|
else if (arg === '--platform') opts.platform = takeValue(args, i++, arg);
|
|
91
|
+
else if (arg === '--domain') opts.domain = takeValue(args, i++, arg);
|
|
92
|
+
else if (arg === '--id') opts.id = takeValue(args, i++, arg);
|
|
93
|
+
else if (arg === '--provenance' && materialize) opts.provenance = takeValue(args, i++, arg);
|
|
70
94
|
else if (arg === '--include-shadowed') opts.includeShadowed = true;
|
|
71
95
|
else if (arg === '--no-include-shadowed') opts.includeShadowed = false;
|
|
72
96
|
else if (arg === '--json') opts.json = true;
|
|
73
97
|
else if (arg === '-h' || arg === '--help') usage(0);
|
|
98
|
+
else if (materialize && !arg.startsWith('-') && !opts.output) opts.output = arg;
|
|
74
99
|
else throw new Error(`unknown option ${arg}`);
|
|
75
100
|
}
|
|
101
|
+
return opts;
|
|
102
|
+
}
|
|
76
103
|
|
|
104
|
+
function buildSources(opts, runtime) {
|
|
77
105
|
const sources = [];
|
|
106
|
+
const domainSourceIds = new Set();
|
|
78
107
|
for (const [index, dir] of opts.dirs.entries()) {
|
|
79
108
|
const root = resolve(dir);
|
|
80
109
|
if (!existsSync(root) || !statSync(root).isDirectory()) {
|
|
81
110
|
throw new Error(`--dir is not a directory: ${root}`);
|
|
82
111
|
}
|
|
83
|
-
|
|
112
|
+
const source = runtime.customTemplateSource(`dir-${index + 1}`, root, 'flow-tree');
|
|
113
|
+
source.sourceRevision = runtime.executionTemplateSourceRevision(root);
|
|
114
|
+
source.sourceDirty = runtime.executionTemplateSourceDirty(root);
|
|
115
|
+
sources.push(source);
|
|
116
|
+
}
|
|
117
|
+
for (const item of opts.domainDirs) {
|
|
118
|
+
const root = resolve(item.root);
|
|
119
|
+
if (!existsSync(root) || !statSync(root).isDirectory()) {
|
|
120
|
+
throw new Error(`--domain-dir is not a directory: ${root}`);
|
|
121
|
+
}
|
|
122
|
+
const sourceId = `team:${item.domain}`;
|
|
123
|
+
if (domainSourceIds.has(sourceId)) {
|
|
124
|
+
throw new Error(`--domain-dir repeats domain ${item.domain}`);
|
|
125
|
+
}
|
|
126
|
+
domainSourceIds.add(sourceId);
|
|
127
|
+
sources.push({
|
|
128
|
+
id: sourceId,
|
|
129
|
+
kind: 'workspace',
|
|
130
|
+
root,
|
|
131
|
+
layout: 'flow-tree',
|
|
132
|
+
domains: [item.domain],
|
|
133
|
+
sourceRevision: runtime.executionTemplateSourceRevision(root),
|
|
134
|
+
sourceDirty: runtime.executionTemplateSourceDirty(root),
|
|
135
|
+
});
|
|
84
136
|
}
|
|
85
137
|
if (opts.projectWorker) {
|
|
86
138
|
const input = resolve(opts.projectWorker);
|
|
@@ -92,34 +144,112 @@ async function cmdList(args, runtime) {
|
|
|
92
144
|
if (!existsSync(workerRoot) || !statSync(workerRoot).isDirectory()) {
|
|
93
145
|
throw new Error(`--project-worker is not a directory: ${workerRoot}`);
|
|
94
146
|
}
|
|
95
|
-
sources.push(
|
|
147
|
+
sources.push(
|
|
148
|
+
runtime.projectWorkerTemplateSource(
|
|
149
|
+
opts.projectName,
|
|
150
|
+
projectTemplatesDir,
|
|
151
|
+
runtime.executionTemplateSourceRevision(projectTemplatesDir),
|
|
152
|
+
runtime.executionTemplateSourceDirty(projectTemplatesDir),
|
|
153
|
+
),
|
|
154
|
+
);
|
|
96
155
|
}
|
|
97
156
|
if (opts.packageTemplates) {
|
|
98
157
|
const root = resolve(opts.packageTemplates);
|
|
99
158
|
if (!existsSync(root) || !statSync(root).isDirectory()) {
|
|
100
159
|
throw new Error(`--package-templates is not a directory: ${root}`);
|
|
101
160
|
}
|
|
102
|
-
|
|
161
|
+
const source = runtime.packageFlowTreeTemplateSource(opts.packageId, root);
|
|
162
|
+
source.sourceRevision = runtime.executionTemplateSourceRevision(root);
|
|
163
|
+
source.sourceDirty = runtime.executionTemplateSourceDirty(root);
|
|
164
|
+
sources.push(source);
|
|
103
165
|
}
|
|
104
166
|
if (sources.length === 0) {
|
|
105
|
-
throw new Error('provide --dir, --project-worker, and/or --package-templates');
|
|
167
|
+
throw new Error('provide --dir, --domain-dir, --project-worker, and/or --package-templates');
|
|
106
168
|
}
|
|
169
|
+
return sources;
|
|
170
|
+
}
|
|
107
171
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
172
|
+
async function cmdList(args, runtime) {
|
|
173
|
+
const opts = parseCatalogArgs(args);
|
|
174
|
+
if (opts.id) throw new Error('--id is only valid with materialize');
|
|
175
|
+
const sources = buildSources(opts, runtime);
|
|
176
|
+
const templates =
|
|
177
|
+
opts.flow && opts.platform && opts.runMode
|
|
178
|
+
? runtime.listCompatibleExecutionTemplates({
|
|
179
|
+
sources,
|
|
180
|
+
flow: opts.flow,
|
|
181
|
+
platform: opts.platform,
|
|
182
|
+
runMode: opts.runMode,
|
|
183
|
+
...(opts.domain ? { domain: opts.domain } : {}),
|
|
184
|
+
})
|
|
185
|
+
: runtime.listExecutionTemplates({
|
|
186
|
+
sources,
|
|
187
|
+
flow: opts.flow,
|
|
188
|
+
runMode: opts.runMode,
|
|
189
|
+
platform: opts.platform,
|
|
190
|
+
domain: opts.domain,
|
|
191
|
+
includeShadowed: opts.includeShadowed,
|
|
192
|
+
});
|
|
193
|
+
const catalog = templates.map((entry) => ({
|
|
194
|
+
...runtime.executionTemplateReference(entry),
|
|
195
|
+
title: entry.title,
|
|
196
|
+
sourceKind: entry.sourceKind,
|
|
197
|
+
...(entry.shadowedBy ? { shadowedBy: entry.shadowedBy } : {}),
|
|
198
|
+
}));
|
|
115
199
|
if (opts.json) {
|
|
116
|
-
process.stdout.write(`${JSON.stringify({ templates }, null, 2)}\n`);
|
|
200
|
+
process.stdout.write(`${JSON.stringify({ templates: catalog }, null, 2)}\n`);
|
|
117
201
|
return;
|
|
118
202
|
}
|
|
119
|
-
for (const entry of
|
|
203
|
+
for (const entry of catalog) {
|
|
120
204
|
const shadow = entry.shadowedBy ? ` (shadowed by ${entry.shadowedBy})` : '';
|
|
121
205
|
process.stdout.write(
|
|
122
|
-
`${entry.id}\t${entry.flow}\t${entry.runMode ?? '-'}\t${entry.platforms.join(',')}\t${entry.sourceId}
|
|
206
|
+
`${entry.id}\t${entry.flow}\t${entry.runMode ?? '-'}\t${entry.platforms.join(',')}\t${entry.sourceId}${shadow}\n`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function cmdMaterialize(args, runtime) {
|
|
212
|
+
const opts = parseCatalogArgs(args, { materialize: true });
|
|
213
|
+
if (!opts.output) throw new Error('materialize requires <output>');
|
|
214
|
+
if (!opts.flow) throw new Error('materialize requires --flow');
|
|
215
|
+
if (!opts.runMode) throw new Error('materialize requires --run-mode');
|
|
216
|
+
if (!opts.platform) throw new Error('materialize requires --platform');
|
|
217
|
+
const output = resolve(opts.output);
|
|
218
|
+
if (existsSync(output)) {
|
|
219
|
+
throw new Error(`Execution-template destination already exists: ${output}`);
|
|
220
|
+
}
|
|
221
|
+
if (opts.provenance && existsSync(resolve(opts.provenance))) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`Execution-template provenance destination already exists: ${resolve(opts.provenance)}`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
const selected = runtime.selectExecutionTemplate({
|
|
227
|
+
sources: buildSources(opts, runtime),
|
|
228
|
+
flow: opts.flow,
|
|
229
|
+
platform: opts.platform,
|
|
230
|
+
runMode: opts.runMode,
|
|
231
|
+
...(opts.domain ? { domain: opts.domain } : {}),
|
|
232
|
+
...(opts.id ? { explicitId: opts.id } : {}),
|
|
233
|
+
});
|
|
234
|
+
const materialized = runtime.materializeExecutionTemplate(selected.entry, output);
|
|
235
|
+
const provenance = {
|
|
236
|
+
schemaVersion: 1,
|
|
237
|
+
selectionReason: selected.reason,
|
|
238
|
+
executionTemplate: materialized.reference,
|
|
239
|
+
};
|
|
240
|
+
if (opts.provenance) {
|
|
241
|
+
const destination = resolve(opts.provenance);
|
|
242
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
243
|
+
writeFileSync(destination, `${JSON.stringify(provenance, null, 2)}\n`, {
|
|
244
|
+
encoding: 'utf8',
|
|
245
|
+
flag: 'wx',
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
const result = { ...materialized, provenance };
|
|
249
|
+
if (opts.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
250
|
+
else {
|
|
251
|
+
process.stdout.write(
|
|
252
|
+
`materialized ${selected.entry.id} from ${selected.entry.sourceId} -> ${materialized.path}\n`,
|
|
123
253
|
);
|
|
124
254
|
}
|
|
125
255
|
}
|
|
@@ -192,6 +322,7 @@ async function main() {
|
|
|
192
322
|
if (!command || command === '-h' || command === '--help') usage(0);
|
|
193
323
|
const runtime = await loadRuntime();
|
|
194
324
|
if (command === 'list') await cmdList(rest, runtime);
|
|
325
|
+
else if (command === 'materialize') await cmdMaterialize(rest, runtime);
|
|
195
326
|
else if (command === 'lint') await cmdLint(rest, runtime);
|
|
196
327
|
else if (command === 'new') await cmdNew(rest, runtime);
|
|
197
328
|
else usage(2);
|