@synergenius/flow-weaver 0.15.2 → 0.16.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/dist/cli/commands/compile.js +158 -149
- package/dist/cli/commands/dev.js +14 -11
- package/dist/cli/commands/diff.js +6 -1
- package/dist/cli/commands/doctor.js +16 -25
- package/dist/cli/commands/export.js +2 -0
- package/dist/cli/commands/grammar.js +3 -1
- package/dist/cli/commands/init.js +18 -28
- package/dist/cli/commands/market.js +14 -6
- package/dist/cli/commands/migrate.js +3 -2
- package/dist/cli/commands/openapi.js +4 -1
- package/dist/cli/commands/run.js +44 -16
- package/dist/cli/commands/status.js +5 -3
- package/dist/cli/commands/strip.js +3 -1
- package/dist/cli/commands/templates.js +1 -1
- package/dist/cli/commands/validate.js +27 -24
- package/dist/cli/env-setup.d.ts +5 -0
- package/dist/cli/env-setup.js +12 -0
- package/dist/cli/flow-weaver.mjs +762 -794
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +254 -508
- package/dist/cli/utils/logger.d.ts +14 -0
- package/dist/cli/utils/logger.js +96 -16
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/mcp/workflow-executor.js +7 -1
- package/package.json +2 -1
|
@@ -191,8 +191,9 @@ export async function marketPackCommand(directory, options = {}) {
|
|
|
191
191
|
validation,
|
|
192
192
|
parsedFiles: parsedFiles.length,
|
|
193
193
|
}, null, 2));
|
|
194
|
-
if (!validation.valid)
|
|
195
|
-
process.
|
|
194
|
+
if (!validation.valid) {
|
|
195
|
+
process.exitCode = 1;
|
|
196
|
+
}
|
|
196
197
|
return;
|
|
197
198
|
}
|
|
198
199
|
// Display results
|
|
@@ -277,7 +278,8 @@ export async function marketInstallCommand(packageSpec, options = {}) {
|
|
|
277
278
|
else {
|
|
278
279
|
logger.error(`npm install failed: ${getErrorMessage(err)}`);
|
|
279
280
|
}
|
|
280
|
-
process.
|
|
281
|
+
process.exitCode = 1;
|
|
282
|
+
return;
|
|
281
283
|
}
|
|
282
284
|
// 2. Read manifest from installed package
|
|
283
285
|
// Resolve the package name from the spec (could be a tarball path or name@version)
|
|
@@ -316,13 +318,18 @@ export async function marketSearchCommand(query, options = {}) {
|
|
|
316
318
|
logger.newline();
|
|
317
319
|
}
|
|
318
320
|
try {
|
|
319
|
-
|
|
321
|
+
let results = await searchPackages({ query, limit, registryUrl: registry });
|
|
322
|
+
// Client-side filtering: npm search may return broad results, narrow to query match
|
|
323
|
+
if (query) {
|
|
324
|
+
const q = query.toLowerCase();
|
|
325
|
+
results = results.filter((pkg) => pkg.name.toLowerCase().includes(q) || (pkg.description && pkg.description.toLowerCase().includes(q)));
|
|
326
|
+
}
|
|
320
327
|
if (json) {
|
|
321
328
|
console.log(JSON.stringify(results, null, 2));
|
|
322
329
|
return;
|
|
323
330
|
}
|
|
324
331
|
if (results.length === 0) {
|
|
325
|
-
logger.info('No packages found');
|
|
332
|
+
logger.info(query ? `No packages matching "${query}"` : 'No packages found');
|
|
326
333
|
return;
|
|
327
334
|
}
|
|
328
335
|
for (const pkg of results) {
|
|
@@ -342,7 +349,8 @@ export async function marketSearchCommand(query, options = {}) {
|
|
|
342
349
|
else {
|
|
343
350
|
logger.error(`Search failed: ${getErrorMessage(err)}`);
|
|
344
351
|
}
|
|
345
|
-
process.
|
|
352
|
+
process.exitCode = 1;
|
|
353
|
+
return;
|
|
346
354
|
}
|
|
347
355
|
}
|
|
348
356
|
/**
|
|
@@ -25,6 +25,7 @@ export async function migrateCommand(globPattern, options = {}) {
|
|
|
25
25
|
if (registeredMigrations.length > 0) {
|
|
26
26
|
logger.info(`Registered edge-case migrations: ${registeredMigrations.map((m) => m.name).join(', ')}`);
|
|
27
27
|
}
|
|
28
|
+
const t = logger.timer();
|
|
28
29
|
let migratedCount = 0;
|
|
29
30
|
let skippedCount = 0;
|
|
30
31
|
let errorCount = 0;
|
|
@@ -80,10 +81,10 @@ export async function migrateCommand(globPattern, options = {}) {
|
|
|
80
81
|
// Summary
|
|
81
82
|
logger.newline();
|
|
82
83
|
if (dryRun) {
|
|
83
|
-
logger.info(`Dry run
|
|
84
|
+
logger.info(`Dry run: ${migratedCount} file(s) would be updated, ${skippedCount} already current, ${errorCount} error(s) in ${t.elapsed()}`);
|
|
84
85
|
}
|
|
85
86
|
else {
|
|
86
|
-
logger.info(
|
|
87
|
+
logger.info(`${migratedCount} file(s) migrated, ${skippedCount} already current, ${errorCount} error(s) in ${t.elapsed()}`);
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
//# sourceMappingURL=migrate.js.map
|
|
@@ -40,7 +40,10 @@ export async function openapiCommand(dir, options) {
|
|
|
40
40
|
if (endpoints.length === 0) {
|
|
41
41
|
throw new Error(`No workflows found in ${workflowDir}`);
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
// Only print info when writing to file (not stdout) to avoid contaminating JSON/YAML output
|
|
44
|
+
if (options.output) {
|
|
45
|
+
logger.info(`Found ${endpoints.length} workflow(s)`);
|
|
46
|
+
}
|
|
44
47
|
// Generate options
|
|
45
48
|
const generatorOptions = {
|
|
46
49
|
title: options.title || 'Flow Weaver API',
|
package/dist/cli/commands/run.js
CHANGED
|
@@ -13,6 +13,14 @@ import { logger } from '../utils/logger.js';
|
|
|
13
13
|
import { getFriendlyError } from '../../friendly-errors.js';
|
|
14
14
|
import { getErrorMessage } from '../../utils/error-utils.js';
|
|
15
15
|
import { parseWorkflow } from '../../api/index.js';
|
|
16
|
+
/** Show path relative to cwd for cleaner output */
|
|
17
|
+
function displayPath(filePath) {
|
|
18
|
+
const rel = path.relative(process.cwd(), filePath);
|
|
19
|
+
if (rel && !rel.startsWith('..') && rel.length < filePath.length) {
|
|
20
|
+
return rel;
|
|
21
|
+
}
|
|
22
|
+
return filePath;
|
|
23
|
+
}
|
|
16
24
|
/**
|
|
17
25
|
* Execute a workflow file and output the result.
|
|
18
26
|
*
|
|
@@ -38,10 +46,24 @@ import { parseWorkflow } from '../../api/index.js';
|
|
|
38
46
|
* ```
|
|
39
47
|
*/
|
|
40
48
|
export async function runCommand(input, options) {
|
|
49
|
+
// Wrap entire body in JSON-aware error handler when --json is set (0b fix)
|
|
50
|
+
if (options.json) {
|
|
51
|
+
try {
|
|
52
|
+
await runCommandInner(input, options);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
console.log(JSON.stringify({ success: false, error: getErrorMessage(e) }));
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
await runCommandInner(input, options);
|
|
61
|
+
}
|
|
62
|
+
async function runCommandInner(input, options) {
|
|
41
63
|
const filePath = path.resolve(input);
|
|
42
64
|
// Validate file exists
|
|
43
65
|
if (!fs.existsSync(filePath)) {
|
|
44
|
-
throw new Error(`File not found: ${filePath}`);
|
|
66
|
+
throw new Error(`File not found: ${displayPath(filePath)}`);
|
|
45
67
|
}
|
|
46
68
|
// Parse params from --params or --params-file
|
|
47
69
|
let params = {};
|
|
@@ -119,7 +141,7 @@ export async function runCommand(input, options) {
|
|
|
119
141
|
? options.resume
|
|
120
142
|
: findLatestCheckpoint(filePath, options.workflow);
|
|
121
143
|
if (!checkpointPath) {
|
|
122
|
-
throw new Error(`No checkpoint file found for ${filePath}. ` +
|
|
144
|
+
throw new Error(`No checkpoint file found for ${displayPath(filePath)}. ` +
|
|
123
145
|
'Checkpoints are created when running with --checkpoint.');
|
|
124
146
|
}
|
|
125
147
|
const { data, stale, rerunNodes, skipNodes } = loadCheckpoint(checkpointPath, filePath);
|
|
@@ -147,9 +169,9 @@ export async function runCommand(input, options) {
|
|
|
147
169
|
}
|
|
148
170
|
}
|
|
149
171
|
// Determine trace inclusion:
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
172
|
+
// Include trace data if --trace or --stream is explicitly set.
|
|
173
|
+
// Also include when not in production mode (needed for debug/checkpoint).
|
|
174
|
+
// Display of trace results is gated separately on options.trace/options.stream.
|
|
153
175
|
const includeTrace = options.stream || options.trace || !options.production;
|
|
154
176
|
if (!options.json && mocks) {
|
|
155
177
|
logger.info('Running with mock data');
|
|
@@ -317,17 +339,20 @@ export async function runCommand(input, options) {
|
|
|
317
339
|
logger.newline();
|
|
318
340
|
logger.section('Result');
|
|
319
341
|
logger.log(JSON.stringify(result.result, null, 2));
|
|
320
|
-
|
|
342
|
+
// Show trace summary only when --trace is explicitly set (not on --stream, which already printed live)
|
|
343
|
+
if (options.trace && !options.stream && result.trace && result.trace.length > 0) {
|
|
321
344
|
logger.newline();
|
|
322
345
|
logger.section('Trace');
|
|
323
346
|
logger.log(`${result.trace.length} events captured`);
|
|
324
|
-
// Show first few trace events as summary
|
|
325
|
-
const
|
|
347
|
+
// Show first few trace events as summary (skip events without nodeId)
|
|
348
|
+
const meaningful = result.trace.filter((e) => e.data?.nodeId || e.data?.id);
|
|
349
|
+
const preview = meaningful.slice(0, 5);
|
|
326
350
|
for (const event of preview) {
|
|
327
|
-
|
|
351
|
+
const nodeId = (event.data?.nodeId || event.data?.id || '');
|
|
352
|
+
logger.log(` [${event.type}] ${nodeId}`);
|
|
328
353
|
}
|
|
329
|
-
if (
|
|
330
|
-
logger.log(` ... and ${
|
|
354
|
+
if (meaningful.length > 5) {
|
|
355
|
+
logger.log(` ... and ${meaningful.length - 5} more events`);
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
}
|
|
@@ -344,7 +369,7 @@ export async function runCommand(input, options) {
|
|
|
344
369
|
const friendly = getFriendlyError(err);
|
|
345
370
|
if (friendly) {
|
|
346
371
|
logger.error(` ${friendly.title}: ${friendly.explanation}`);
|
|
347
|
-
logger.
|
|
372
|
+
logger.warn(` How to fix: ${friendly.fix}`);
|
|
348
373
|
}
|
|
349
374
|
else {
|
|
350
375
|
logger.error(` - ${err.message}`);
|
|
@@ -355,7 +380,7 @@ export async function runCommand(input, options) {
|
|
|
355
380
|
const friendly = getFriendlyError({ code: errorObj.code, message: errorMsg });
|
|
356
381
|
if (friendly) {
|
|
357
382
|
logger.error(`${friendly.title}: ${friendly.explanation}`);
|
|
358
|
-
logger.
|
|
383
|
+
logger.warn(` How to fix: ${friendly.fix}`);
|
|
359
384
|
}
|
|
360
385
|
else {
|
|
361
386
|
logger.error(`Workflow execution failed: ${errorMsg}`);
|
|
@@ -364,11 +389,14 @@ export async function runCommand(input, options) {
|
|
|
364
389
|
else {
|
|
365
390
|
logger.error(`Workflow execution failed: ${errorMsg}`);
|
|
366
391
|
}
|
|
367
|
-
if (
|
|
368
|
-
|
|
392
|
+
if (options.json) {
|
|
393
|
+
// JSON mode: output structured error (0a fix: set exit code)
|
|
394
|
+
process.stdout.write(JSON.stringify({ success: false, error: errorMsg }, null, 2) + '\n');
|
|
395
|
+
process.exitCode = 1;
|
|
369
396
|
}
|
|
370
397
|
else {
|
|
371
|
-
|
|
398
|
+
// Non-json mode: don't re-throw to avoid duplicate error from wrapAction (0c fix)
|
|
399
|
+
process.exitCode = 1;
|
|
372
400
|
}
|
|
373
401
|
}
|
|
374
402
|
finally {
|
|
@@ -23,7 +23,8 @@ export async function statusCommand(input, options = {}) {
|
|
|
23
23
|
else {
|
|
24
24
|
logger.error(`File not found: ${input}`);
|
|
25
25
|
}
|
|
26
|
-
process.
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
return;
|
|
27
28
|
}
|
|
28
29
|
const parseResult = await parseWorkflow(filePath, { workflowName });
|
|
29
30
|
if (parseResult.errors.length > 0) {
|
|
@@ -34,7 +35,8 @@ export async function statusCommand(input, options = {}) {
|
|
|
34
35
|
logger.error('Parse errors:');
|
|
35
36
|
parseResult.errors.forEach((e) => logger.error(` ${e}`));
|
|
36
37
|
}
|
|
37
|
-
process.
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
38
40
|
}
|
|
39
41
|
const ast = parseResult.ast;
|
|
40
42
|
// Collect node statuses
|
|
@@ -115,7 +117,7 @@ export async function statusCommand(input, options = {}) {
|
|
|
115
117
|
else {
|
|
116
118
|
logger.error(`Status failed: ${getErrorMessage(error)}`);
|
|
117
119
|
}
|
|
118
|
-
process.
|
|
120
|
+
process.exitCode = 1;
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
//# sourceMappingURL=status.js.map
|
|
@@ -28,6 +28,7 @@ export async function stripCommand(input, options = {}) {
|
|
|
28
28
|
logger.error(`No files found matching pattern: ${input}`);
|
|
29
29
|
process.exit(1);
|
|
30
30
|
}
|
|
31
|
+
const t = logger.timer();
|
|
31
32
|
let stripped = 0;
|
|
32
33
|
let skipped = 0;
|
|
33
34
|
for (const filePath of files) {
|
|
@@ -57,6 +58,7 @@ export async function stripCommand(input, options = {}) {
|
|
|
57
58
|
logger.success(`Stripped: ${path.relative(process.cwd(), outPath)}`);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
+
const verb = dryRun ? 'would be stripped' : 'stripped';
|
|
62
|
+
logger.success(`${stripped} file${stripped !== 1 ? 's' : ''} ${verb}, ${skipped} skipped in ${t.elapsed()}`);
|
|
61
63
|
}
|
|
62
64
|
//# sourceMappingURL=strip.js.map
|
|
@@ -48,7 +48,7 @@ export async function templatesCommand(options = {}) {
|
|
|
48
48
|
logger.newline();
|
|
49
49
|
logger.section("Usage");
|
|
50
50
|
logger.log(" $ flow-weaver create workflow <template> <file> [--async] [--line N]");
|
|
51
|
-
logger.log(" $ flow-weaver create node <
|
|
51
|
+
logger.log(" $ flow-weaver create node <name> <file> [-t <template>] [--line N]");
|
|
52
52
|
logger.newline();
|
|
53
53
|
}
|
|
54
54
|
//# sourceMappingURL=templates.js.map
|
|
@@ -37,16 +37,18 @@ export async function validateCommand(input, options = {}) {
|
|
|
37
37
|
if (files.length === 0) {
|
|
38
38
|
if (json) {
|
|
39
39
|
console.log(JSON.stringify({ error: `No files found matching pattern: ${input}` }));
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
return;
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
logger.error(`No files found matching pattern: ${input}`);
|
|
43
|
-
}
|
|
44
|
-
process.exit(1);
|
|
43
|
+
throw new Error(`No files found matching pattern: ${input}`);
|
|
45
44
|
}
|
|
45
|
+
const totalTimer = logger.timer();
|
|
46
46
|
if (!json) {
|
|
47
47
|
logger.section('Validating Workflows');
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
if (verbose) {
|
|
49
|
+
logger.info(`Found ${files.length} file(s)`);
|
|
50
|
+
logger.newline();
|
|
51
|
+
}
|
|
50
52
|
}
|
|
51
53
|
let totalErrors = 0;
|
|
52
54
|
let totalWarnings = 0;
|
|
@@ -55,7 +57,7 @@ export async function validateCommand(input, options = {}) {
|
|
|
55
57
|
for (let i = 0; i < files.length; i++) {
|
|
56
58
|
const file = files[i];
|
|
57
59
|
const fileName = path.basename(file);
|
|
58
|
-
if (!json) {
|
|
60
|
+
if (!json && verbose) {
|
|
59
61
|
logger.progress(i + 1, files.length, fileName);
|
|
60
62
|
}
|
|
61
63
|
try {
|
|
@@ -139,9 +141,9 @@ export async function validateCommand(input, options = {}) {
|
|
|
139
141
|
if (friendly) {
|
|
140
142
|
const loc = err.location ? `[line ${err.location.line}] ` : '';
|
|
141
143
|
logger.error(` ${loc}${friendly.title}: ${friendly.explanation}`);
|
|
142
|
-
logger.
|
|
144
|
+
logger.warn(` How to fix: ${friendly.fix}`);
|
|
143
145
|
if (err.docUrl) {
|
|
144
|
-
logger.
|
|
146
|
+
logger.warn(` See: ${err.docUrl}`);
|
|
145
147
|
}
|
|
146
148
|
}
|
|
147
149
|
else {
|
|
@@ -157,7 +159,7 @@ export async function validateCommand(input, options = {}) {
|
|
|
157
159
|
}
|
|
158
160
|
logger.error(msg);
|
|
159
161
|
if (err.docUrl) {
|
|
160
|
-
logger.
|
|
162
|
+
logger.warn(` See: ${err.docUrl}`);
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
});
|
|
@@ -172,9 +174,9 @@ export async function validateCommand(input, options = {}) {
|
|
|
172
174
|
if (friendly) {
|
|
173
175
|
const loc = warn.location ? `[line ${warn.location.line}] ` : '';
|
|
174
176
|
logger.warn(` ${loc}${friendly.title}: ${friendly.explanation}`);
|
|
175
|
-
logger.
|
|
177
|
+
logger.warn(` How to fix: ${friendly.fix}`);
|
|
176
178
|
if (warn.docUrl) {
|
|
177
|
-
logger.
|
|
179
|
+
logger.warn(` See: ${warn.docUrl}`);
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
182
|
else {
|
|
@@ -187,7 +189,7 @@ export async function validateCommand(input, options = {}) {
|
|
|
187
189
|
}
|
|
188
190
|
logger.warn(msg);
|
|
189
191
|
if (warn.docUrl) {
|
|
190
|
-
logger.
|
|
192
|
+
logger.warn(` See: ${warn.docUrl}`);
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
});
|
|
@@ -229,17 +231,19 @@ export async function validateCommand(input, options = {}) {
|
|
|
229
231
|
}
|
|
230
232
|
else {
|
|
231
233
|
// Summary
|
|
234
|
+
const elapsed = totalTimer.elapsed();
|
|
232
235
|
logger.newline();
|
|
233
|
-
logger.section('Validation Summary');
|
|
234
|
-
logger.success(`${successCount} file(s) valid`);
|
|
235
|
-
if (totalWarnings > 0) {
|
|
236
|
-
logger.warn(`${totalWarnings} warning(s) found`);
|
|
237
|
-
}
|
|
238
236
|
if (totalErrors > 0) {
|
|
239
|
-
|
|
237
|
+
const parts = [`${successCount} valid`, `${totalErrors} error${totalErrors !== 1 ? 's' : ''}`];
|
|
238
|
+
if (totalWarnings > 0)
|
|
239
|
+
parts.push(`${totalWarnings} warning${totalWarnings !== 1 ? 's' : ''}`);
|
|
240
|
+
logger.log(` ${parts.join(', ')} in ${elapsed}`);
|
|
241
|
+
}
|
|
242
|
+
else if (totalWarnings > 0) {
|
|
243
|
+
logger.log(` ${successCount} valid, ${totalWarnings} warning${totalWarnings !== 1 ? 's' : ''} in ${elapsed}`);
|
|
240
244
|
}
|
|
241
245
|
else {
|
|
242
|
-
logger.success('
|
|
246
|
+
logger.success(`${successCount} file${successCount !== 1 ? 's' : ''} valid in ${elapsed}`);
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
if (totalErrors > 0) {
|
|
@@ -249,11 +253,10 @@ export async function validateCommand(input, options = {}) {
|
|
|
249
253
|
catch (error) {
|
|
250
254
|
if (json) {
|
|
251
255
|
console.log(JSON.stringify({ error: getErrorMessage(error) }));
|
|
256
|
+
process.exitCode = 1;
|
|
257
|
+
return;
|
|
252
258
|
}
|
|
253
|
-
|
|
254
|
-
logger.error(`Validation failed: ${getErrorMessage(error)}`);
|
|
255
|
-
}
|
|
256
|
-
process.exit(1);
|
|
259
|
+
throw error;
|
|
257
260
|
}
|
|
258
261
|
}
|
|
259
262
|
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Environment setup that must run before any color library imports.
|
|
4
|
+
* This module is imported first in index.ts to ensure picocolors reads the correct env vars.
|
|
5
|
+
*/
|
|
6
|
+
// FORCE_COLOR=0 should disable colors, but picocolors treats any non-empty
|
|
7
|
+
// FORCE_COLOR as "enable colors". Translate to NO_COLOR which picocolors checks first.
|
|
8
|
+
if (process.env.FORCE_COLOR === '0') {
|
|
9
|
+
process.env.NO_COLOR = '1';
|
|
10
|
+
delete process.env.FORCE_COLOR;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=env-setup.js.map
|