@synergenius/flow-weaver 0.15.2 → 0.17.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-personas.d.ts +87 -0
- package/dist/cli/commands/init-personas.js +492 -0
- package/dist/cli/commands/init.d.ts +30 -2
- package/dist/cli/commands/init.js +309 -94
- package/dist/cli/commands/market.js +14 -6
- package/dist/cli/commands/mcp-setup.d.ts +17 -0
- package/dist/cli/commands/mcp-setup.js +44 -0
- 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 +2973 -2295
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +259 -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
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* mcp-setup command — detect AI coding tools and configure the Flow Weaver MCP server.
|
|
3
3
|
*/
|
|
4
4
|
export type ToolId = 'claude' | 'cursor' | 'vscode' | 'windsurf' | 'codex' | 'openclaw';
|
|
5
|
+
/** Tools that can be spawned as interactive CLI sessions */
|
|
6
|
+
export declare const CLI_TOOL_IDS: ReadonlySet<ToolId>;
|
|
7
|
+
/** Binary name to spawn for each CLI tool */
|
|
8
|
+
export declare const CLI_TOOL_BINARY: Partial<Record<ToolId, string>>;
|
|
5
9
|
export interface McpSetupDeps {
|
|
6
10
|
execCommand: (cmd: string) => Promise<{
|
|
7
11
|
stdout: string;
|
|
@@ -40,6 +44,19 @@ export declare function mergeJsonConfig(deps: McpSetupDeps, filePath: string, ro
|
|
|
40
44
|
}>;
|
|
41
45
|
export declare const TOOL_REGISTRY: ToolDefinition[];
|
|
42
46
|
export declare function detectTools(deps: McpSetupDeps): Promise<DetectedTool[]>;
|
|
47
|
+
export interface McpSetupFromInitResult {
|
|
48
|
+
configured: string[];
|
|
49
|
+
failed: string[];
|
|
50
|
+
/** Tool IDs that can be spawned as interactive CLI sessions (e.g. claude, codex) */
|
|
51
|
+
cliTools: ToolId[];
|
|
52
|
+
/** Tool IDs that are GUI-only editors (e.g. cursor, vscode, windsurf) */
|
|
53
|
+
guiTools: ToolId[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect and configure all AI tools without interactive prompts.
|
|
57
|
+
* Used by the init command after the user has already consented.
|
|
58
|
+
*/
|
|
59
|
+
export declare function runMcpSetupFromInit(deps?: McpSetupDeps): Promise<McpSetupFromInitResult>;
|
|
43
60
|
export declare function mcpSetupCommand(options: McpSetupOptions, deps?: McpSetupDeps): Promise<void>;
|
|
44
61
|
export {};
|
|
45
62
|
//# sourceMappingURL=mcp-setup.d.ts.map
|
|
@@ -12,6 +12,13 @@ import { isNonInteractive } from './init.js';
|
|
|
12
12
|
const MCP_COMMAND = 'npx';
|
|
13
13
|
const MCP_ARGS = ['@synergenius/flow-weaver@latest', 'mcp-server', '--stdio'];
|
|
14
14
|
const MCP_ENTRY = { command: MCP_COMMAND, args: [...MCP_ARGS] };
|
|
15
|
+
/** Tools that can be spawned as interactive CLI sessions */
|
|
16
|
+
export const CLI_TOOL_IDS = new Set(['claude', 'codex']);
|
|
17
|
+
/** Binary name to spawn for each CLI tool */
|
|
18
|
+
export const CLI_TOOL_BINARY = {
|
|
19
|
+
claude: 'claude',
|
|
20
|
+
codex: 'codex',
|
|
21
|
+
};
|
|
15
22
|
// ── Deps ─────────────────────────────────────────────────────────────────────
|
|
16
23
|
export function defaultDeps() {
|
|
17
24
|
return {
|
|
@@ -261,6 +268,43 @@ async function configureTool(tool, deps) {
|
|
|
261
268
|
return { id: tool.id, displayName: tool.displayName, action: 'failed', detail: msg };
|
|
262
269
|
}
|
|
263
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Detect and configure all AI tools without interactive prompts.
|
|
273
|
+
* Used by the init command after the user has already consented.
|
|
274
|
+
*/
|
|
275
|
+
export async function runMcpSetupFromInit(deps) {
|
|
276
|
+
const d = deps ?? defaultDeps();
|
|
277
|
+
const detected = await detectTools(d);
|
|
278
|
+
const toConfig = detected.filter((t) => t.detected && !t.configured);
|
|
279
|
+
const configured = [];
|
|
280
|
+
const failed = [];
|
|
281
|
+
const toolMap = new Map(TOOL_REGISTRY.map((t) => [t.id, t]));
|
|
282
|
+
for (const t of toConfig) {
|
|
283
|
+
const tool = toolMap.get(t.id);
|
|
284
|
+
if (!tool)
|
|
285
|
+
continue;
|
|
286
|
+
const result = await configureTool(tool, d);
|
|
287
|
+
if (result.action === 'configured') {
|
|
288
|
+
configured.push(result.displayName);
|
|
289
|
+
}
|
|
290
|
+
else if (result.action === 'failed') {
|
|
291
|
+
failed.push(result.displayName);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Include already-configured tools in the configured list
|
|
295
|
+
for (const t of detected) {
|
|
296
|
+
if (t.configured) {
|
|
297
|
+
configured.push(t.displayName);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Classify configured/detected tools as CLI or GUI
|
|
301
|
+
const allConfiguredIds = detected
|
|
302
|
+
.filter((t) => t.detected && (t.configured || configured.includes(t.displayName)))
|
|
303
|
+
.map((t) => t.id);
|
|
304
|
+
const cliTools = allConfiguredIds.filter((id) => CLI_TOOL_IDS.has(id));
|
|
305
|
+
const guiTools = allConfiguredIds.filter((id) => !CLI_TOOL_IDS.has(id));
|
|
306
|
+
return { configured, failed, cliTools, guiTools };
|
|
307
|
+
}
|
|
264
308
|
// ── Command ──────────────────────────────────────────────────────────────────
|
|
265
309
|
export async function mcpSetupCommand(options, deps) {
|
|
266
310
|
const d = deps ?? defaultDeps();
|
|
@@ -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
|