@principal-ai/principal-view-cli 0.1.13
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/README.md +157 -0
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +50 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +274 -0
- package/dist/commands/hooks.d.ts +9 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +295 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +290 -0
- package/dist/commands/lint.d.ts +6 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +375 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +80 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +333 -0
- package/dist/commands/validate.d.ts +6 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +389 -0
- package/dist/index.cjs +17286 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/package.json +57 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lint command - Lint graph configuration files using the rules engine
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
6
|
+
import { resolve, relative, dirname, basename } from 'node:path';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { globby } from 'globby';
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { createDefaultRulesEngine, validatePrivuConfig, mergeConfigs, getDefaultConfig, } from '@principal-ai/principal-view-core';
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Config File Loading
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Config file names in resolution order
|
|
16
|
+
*/
|
|
17
|
+
const CONFIG_FILE_NAMES = [
|
|
18
|
+
'.principal-viewsrc.json',
|
|
19
|
+
'.principal-viewsrc.yaml',
|
|
20
|
+
'.principal-viewsrc.yml',
|
|
21
|
+
'privu.config.json',
|
|
22
|
+
'privu.config.yaml',
|
|
23
|
+
'privu.config.yml',
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Find and load VGC config file
|
|
27
|
+
*/
|
|
28
|
+
function findConfig(startDir) {
|
|
29
|
+
let currentDir = resolve(startDir);
|
|
30
|
+
while (true) {
|
|
31
|
+
// Check for config files
|
|
32
|
+
for (const fileName of CONFIG_FILE_NAMES) {
|
|
33
|
+
const configPath = resolve(currentDir, fileName);
|
|
34
|
+
if (existsSync(configPath)) {
|
|
35
|
+
const config = loadConfigFile(configPath);
|
|
36
|
+
if (config) {
|
|
37
|
+
return { config, path: configPath };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Check package.json for "privu" key
|
|
42
|
+
const packageJsonPath = resolve(currentDir, 'package.json');
|
|
43
|
+
if (existsSync(packageJsonPath)) {
|
|
44
|
+
try {
|
|
45
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
46
|
+
if (packageJson.privu && typeof packageJson.privu === 'object') {
|
|
47
|
+
return { config: packageJson.privu, path: packageJsonPath };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore parse errors
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Check for root flag or filesystem root
|
|
55
|
+
const parentDir = dirname(currentDir);
|
|
56
|
+
if (parentDir === currentDir) {
|
|
57
|
+
break; // Reached filesystem root
|
|
58
|
+
}
|
|
59
|
+
currentDir = parentDir;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Load a config file (JSON or YAML)
|
|
65
|
+
*/
|
|
66
|
+
function loadConfigFile(filePath) {
|
|
67
|
+
try {
|
|
68
|
+
const content = readFileSync(filePath, 'utf8');
|
|
69
|
+
const ext = filePath.toLowerCase();
|
|
70
|
+
if (ext.endsWith('.json')) {
|
|
71
|
+
return JSON.parse(content);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
return yaml.load(content);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Load a component library file
|
|
83
|
+
*/
|
|
84
|
+
function loadLibrary(libraryPath) {
|
|
85
|
+
if (!existsSync(libraryPath)) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const content = readFileSync(libraryPath, 'utf8');
|
|
90
|
+
const ext = libraryPath.toLowerCase();
|
|
91
|
+
if (ext.endsWith('.json')) {
|
|
92
|
+
return JSON.parse(content);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return yaml.load(content);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Load a graph configuration file (YAML or JSON)
|
|
104
|
+
*/
|
|
105
|
+
function loadGraphConfig(filePath) {
|
|
106
|
+
if (!existsSync(filePath)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
111
|
+
const ext = filePath.toLowerCase();
|
|
112
|
+
let config;
|
|
113
|
+
if (ext.endsWith('.json')) {
|
|
114
|
+
config = JSON.parse(raw);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
config = yaml.load(raw);
|
|
118
|
+
}
|
|
119
|
+
return { config, raw };
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// Output Formatting
|
|
127
|
+
// ============================================================================
|
|
128
|
+
/**
|
|
129
|
+
* Format violations for pretty console output
|
|
130
|
+
*/
|
|
131
|
+
function formatPrettyOutput(results, quiet) {
|
|
132
|
+
const lines = [];
|
|
133
|
+
let totalErrors = 0;
|
|
134
|
+
let totalWarnings = 0;
|
|
135
|
+
let totalFixable = 0;
|
|
136
|
+
for (const [filePath, result] of results) {
|
|
137
|
+
totalErrors += result.errorCount;
|
|
138
|
+
totalWarnings += result.warningCount;
|
|
139
|
+
totalFixable += result.fixableCount;
|
|
140
|
+
if (result.violations.length === 0) {
|
|
141
|
+
if (!quiet) {
|
|
142
|
+
lines.push(chalk.green(`✓ ${filePath}`));
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
lines.push('');
|
|
147
|
+
lines.push(chalk.cyan(filePath));
|
|
148
|
+
lines.push('');
|
|
149
|
+
for (const violation of result.violations) {
|
|
150
|
+
const severityColor = violation.severity === 'error' ? chalk.red : chalk.yellow;
|
|
151
|
+
const severityLabel = violation.severity === 'error' ? 'error' : 'warn ';
|
|
152
|
+
// Format: " error rule-id message"
|
|
153
|
+
const ruleId = chalk.dim(violation.ruleId.padEnd(30));
|
|
154
|
+
lines.push(` ${severityColor(severityLabel)} ${ruleId} ${violation.message}`);
|
|
155
|
+
if (violation.suggestion) {
|
|
156
|
+
lines.push(chalk.dim(` ${''.padEnd(30)} → ${violation.suggestion}`));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Summary
|
|
161
|
+
lines.push('');
|
|
162
|
+
if (totalErrors === 0 && totalWarnings === 0) {
|
|
163
|
+
lines.push(chalk.green(`✓ All files passed linting`));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const parts = [];
|
|
167
|
+
if (totalErrors > 0) {
|
|
168
|
+
parts.push(chalk.red(`${totalErrors} error${totalErrors === 1 ? '' : 's'}`));
|
|
169
|
+
}
|
|
170
|
+
if (totalWarnings > 0) {
|
|
171
|
+
parts.push(chalk.yellow(`${totalWarnings} warning${totalWarnings === 1 ? '' : 's'}`));
|
|
172
|
+
}
|
|
173
|
+
lines.push(`✖ ${parts.join(', ')}`);
|
|
174
|
+
if (totalFixable > 0) {
|
|
175
|
+
lines.push(chalk.dim(` ${totalFixable} fixable with --fix (coming soon)`));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
output: lines.join('\n'),
|
|
180
|
+
hasErrors: totalErrors > 0,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Format violations for JSON output
|
|
185
|
+
*/
|
|
186
|
+
function formatJsonOutput(results) {
|
|
187
|
+
const files = [];
|
|
188
|
+
let totalErrors = 0;
|
|
189
|
+
let totalWarnings = 0;
|
|
190
|
+
let totalFixable = 0;
|
|
191
|
+
for (const [filePath, result] of results) {
|
|
192
|
+
totalErrors += result.errorCount;
|
|
193
|
+
totalWarnings += result.warningCount;
|
|
194
|
+
totalFixable += result.fixableCount;
|
|
195
|
+
files.push({
|
|
196
|
+
file: filePath,
|
|
197
|
+
errorCount: result.errorCount,
|
|
198
|
+
warningCount: result.warningCount,
|
|
199
|
+
fixableCount: result.fixableCount,
|
|
200
|
+
violations: result.violations,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
files,
|
|
205
|
+
summary: {
|
|
206
|
+
totalFiles: files.length,
|
|
207
|
+
totalErrors,
|
|
208
|
+
totalWarnings,
|
|
209
|
+
totalFixable,
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// ============================================================================
|
|
214
|
+
// Command Implementation
|
|
215
|
+
// ============================================================================
|
|
216
|
+
export function createLintCommand() {
|
|
217
|
+
const command = new Command('lint');
|
|
218
|
+
command
|
|
219
|
+
.description('Lint graph configuration files')
|
|
220
|
+
.argument('[files...]', 'Files or glob patterns to lint (defaults to .principal-views/**/*.yaml)')
|
|
221
|
+
.option('-c, --config <path>', 'Path to config file')
|
|
222
|
+
.option('--library <path>', 'Path to component library file')
|
|
223
|
+
.option('-q, --quiet', 'Only output errors')
|
|
224
|
+
.option('--json', 'Output results as JSON')
|
|
225
|
+
.option('--rule <rules...>', 'Only run specific rules')
|
|
226
|
+
.option('--ignore-rule <rules...>', 'Skip specific rules')
|
|
227
|
+
.action(async (files, options) => {
|
|
228
|
+
try {
|
|
229
|
+
const cwd = process.cwd();
|
|
230
|
+
// Load VGC config
|
|
231
|
+
let privuConfig = getDefaultConfig();
|
|
232
|
+
let configPath;
|
|
233
|
+
if (options.config) {
|
|
234
|
+
// Use specified config file
|
|
235
|
+
const loadedConfig = loadConfigFile(resolve(cwd, options.config));
|
|
236
|
+
if (!loadedConfig) {
|
|
237
|
+
console.error(chalk.red(`Error: Could not load config file: ${options.config}`));
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
// Validate config
|
|
241
|
+
const validation = validatePrivuConfig(loadedConfig);
|
|
242
|
+
if (!validation.valid) {
|
|
243
|
+
console.error(chalk.red('Configuration Error:'), options.config);
|
|
244
|
+
for (const error of validation.errors) {
|
|
245
|
+
console.error(chalk.red(` ${error.path}: ${error.message}`));
|
|
246
|
+
if (error.suggestion) {
|
|
247
|
+
console.error(chalk.dim(` → ${error.suggestion}`));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
privuConfig = mergeConfigs(privuConfig, loadedConfig);
|
|
253
|
+
configPath = resolve(cwd, options.config);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// Search for config file
|
|
257
|
+
const found = findConfig(cwd);
|
|
258
|
+
if (found) {
|
|
259
|
+
const validation = validatePrivuConfig(found.config);
|
|
260
|
+
if (!validation.valid) {
|
|
261
|
+
console.error(chalk.red('Configuration Error:'), found.path);
|
|
262
|
+
for (const error of validation.errors) {
|
|
263
|
+
console.error(chalk.red(` ${error.path}: ${error.message}`));
|
|
264
|
+
if (error.suggestion) {
|
|
265
|
+
console.error(chalk.dim(` → ${error.suggestion}`));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
privuConfig = mergeConfigs(privuConfig, found.config);
|
|
271
|
+
configPath = found.path;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Determine files to lint
|
|
275
|
+
let patterns;
|
|
276
|
+
if (files.length > 0) {
|
|
277
|
+
patterns = files;
|
|
278
|
+
}
|
|
279
|
+
else if (privuConfig.include && privuConfig.include.length > 0) {
|
|
280
|
+
patterns = privuConfig.include;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
patterns = ['.principal-views/**/*.yaml', '.principal-views/**/*.yml', '.principal-views/**/*.json'];
|
|
284
|
+
}
|
|
285
|
+
// Find matching files
|
|
286
|
+
const matchedFiles = await globby(patterns, {
|
|
287
|
+
ignore: privuConfig.exclude || ['**/node_modules/**'],
|
|
288
|
+
expandDirectories: false,
|
|
289
|
+
});
|
|
290
|
+
// Filter out library files and config files
|
|
291
|
+
const configFiles = matchedFiles.filter((f) => {
|
|
292
|
+
const name = basename(f).toLowerCase();
|
|
293
|
+
return !name.startsWith('library.') && !name.startsWith('.principal-viewsrc') && !name.startsWith('privu.config');
|
|
294
|
+
});
|
|
295
|
+
if (configFiles.length === 0) {
|
|
296
|
+
if (options.json) {
|
|
297
|
+
console.log(JSON.stringify({ files: [], summary: { totalFiles: 0, totalErrors: 0, totalWarnings: 0, totalFixable: 0 } }));
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
console.log(chalk.yellow('No configuration files found matching the specified patterns.'));
|
|
301
|
+
console.log(chalk.dim(`Patterns searched: ${patterns.join(', ')}`));
|
|
302
|
+
}
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
// Load library if specified
|
|
306
|
+
let library;
|
|
307
|
+
const libraryPath = options.library || privuConfig.library;
|
|
308
|
+
if (libraryPath) {
|
|
309
|
+
const resolvedLibraryPath = resolve(cwd, libraryPath);
|
|
310
|
+
library = loadLibrary(resolvedLibraryPath) ?? undefined;
|
|
311
|
+
if (!library && !options.quiet) {
|
|
312
|
+
console.log(chalk.yellow(`Warning: Could not load library from ${libraryPath}`));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Create rules engine
|
|
316
|
+
const engine = createDefaultRulesEngine();
|
|
317
|
+
// Lint each file
|
|
318
|
+
const results = new Map();
|
|
319
|
+
for (const filePath of configFiles) {
|
|
320
|
+
const absolutePath = resolve(cwd, filePath);
|
|
321
|
+
const relativePath = relative(cwd, absolutePath);
|
|
322
|
+
const loaded = loadGraphConfig(absolutePath);
|
|
323
|
+
if (!loaded) {
|
|
324
|
+
// File couldn't be loaded - report as error
|
|
325
|
+
results.set(relativePath, {
|
|
326
|
+
violations: [{
|
|
327
|
+
ruleId: 'parse-error',
|
|
328
|
+
severity: 'error',
|
|
329
|
+
file: relativePath,
|
|
330
|
+
message: `Could not parse file: ${filePath}`,
|
|
331
|
+
impact: 'File cannot be validated',
|
|
332
|
+
fixable: false,
|
|
333
|
+
}],
|
|
334
|
+
errorCount: 1,
|
|
335
|
+
warningCount: 0,
|
|
336
|
+
fixableCount: 0,
|
|
337
|
+
byCategory: { schema: 1, reference: 0, structure: 0, pattern: 0, library: 0 },
|
|
338
|
+
byRule: { 'parse-error': 1 },
|
|
339
|
+
});
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
// Run linting
|
|
343
|
+
const result = await engine.lintWithConfig(loaded.config, privuConfig, {
|
|
344
|
+
library,
|
|
345
|
+
configPath: relativePath,
|
|
346
|
+
rawContent: loaded.raw,
|
|
347
|
+
enabledRules: options.rule,
|
|
348
|
+
disabledRules: options.ignoreRule,
|
|
349
|
+
});
|
|
350
|
+
results.set(relativePath, result);
|
|
351
|
+
}
|
|
352
|
+
// Output results
|
|
353
|
+
if (options.json) {
|
|
354
|
+
console.log(JSON.stringify(formatJsonOutput(results), null, 2));
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
const { output, hasErrors } = formatPrettyOutput(results, options.quiet);
|
|
358
|
+
console.log(output);
|
|
359
|
+
if (hasErrors) {
|
|
360
|
+
process.exit(1);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
if (options.json) {
|
|
366
|
+
console.log(JSON.stringify({ error: error.message }));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
console.error(chalk.red('Error:'), error.message);
|
|
370
|
+
}
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
return command;
|
|
375
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmCpC,wBAAgB,iBAAiB,IAAI,OAAO,CAwD3C"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List command - List all .canvas files in a project
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
6
|
+
import { resolve, relative } from 'node:path';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { globby } from 'globby';
|
|
9
|
+
function getCanvasInfo(filePath) {
|
|
10
|
+
try {
|
|
11
|
+
const absolutePath = resolve(filePath);
|
|
12
|
+
const content = readFileSync(absolutePath, 'utf8');
|
|
13
|
+
const canvas = JSON.parse(content);
|
|
14
|
+
const stats = statSync(absolutePath);
|
|
15
|
+
return {
|
|
16
|
+
file: relative(process.cwd(), absolutePath),
|
|
17
|
+
name: canvas.pv?.name || 'Untitled',
|
|
18
|
+
version: canvas.pv?.version,
|
|
19
|
+
nodeCount: Array.isArray(canvas.nodes) ? canvas.nodes.length : 0,
|
|
20
|
+
edgeCount: Array.isArray(canvas.edges) ? canvas.edges.length : 0,
|
|
21
|
+
modified: stats.mtime,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function createListCommand() {
|
|
29
|
+
const command = new Command('list');
|
|
30
|
+
command
|
|
31
|
+
.alias('ls')
|
|
32
|
+
.description('List all .canvas files in the project')
|
|
33
|
+
.option('-a, --all', 'Search all directories (not just .principal-views)')
|
|
34
|
+
.option('--json', 'Output as JSON')
|
|
35
|
+
.action(async (options) => {
|
|
36
|
+
try {
|
|
37
|
+
const patterns = options.all
|
|
38
|
+
? ['**/*.canvas', '!node_modules/**']
|
|
39
|
+
: ['.principal-views/*.canvas'];
|
|
40
|
+
const files = await globby(patterns, {
|
|
41
|
+
expandDirectories: false,
|
|
42
|
+
});
|
|
43
|
+
if (files.length === 0) {
|
|
44
|
+
if (options.json) {
|
|
45
|
+
console.log(JSON.stringify({ files: [] }));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(chalk.yellow('No .canvas files found.'));
|
|
49
|
+
if (!options.all) {
|
|
50
|
+
console.log(chalk.dim('Run with --all to search all directories'));
|
|
51
|
+
}
|
|
52
|
+
console.log(chalk.dim('\nTo create a new canvas, run: privu init'));
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const canvasInfos = files
|
|
57
|
+
.map(getCanvasInfo)
|
|
58
|
+
.filter((info) => info !== null)
|
|
59
|
+
.sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
60
|
+
if (options.json) {
|
|
61
|
+
console.log(JSON.stringify({ files: canvasInfos }, null, 2));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.log(chalk.bold(`\nFound ${canvasInfos.length} canvas file(s):\n`));
|
|
65
|
+
for (const info of canvasInfos) {
|
|
66
|
+
const version = info.version ? chalk.dim(` v${info.version}`) : '';
|
|
67
|
+
console.log(` ${chalk.cyan(info.file)}`);
|
|
68
|
+
console.log(` ${chalk.bold(info.name)}${version}`);
|
|
69
|
+
console.log(chalk.dim(` ${info.nodeCount} nodes, ${info.edgeCount} edges`));
|
|
70
|
+
console.log('');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error(chalk.red('Error:'), error.message);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return command;
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/commands/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2TpC,wBAAgB,mBAAmB,IAAI,OAAO,CA0B7C"}
|