@principal-ai/principal-view-cli 0.1.29 → 0.1.30
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/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +155 -34
- package/dist/index.cjs +640 -42
- package/dist/index.cjs.map +4 -4
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwTpC,wBAAgB,iBAAiB,IAAI,OAAO,CAwQ3C"}
|
package/dist/commands/lint.js
CHANGED
|
@@ -7,7 +7,7 @@ import { resolve, relative, dirname, basename } from 'node:path';
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { globby } from 'globby';
|
|
9
9
|
import yaml from 'js-yaml';
|
|
10
|
-
import { createDefaultRulesEngine, validatePrivuConfig, mergeConfigs, getDefaultConfig, } from '@principal-ai/principal-view-core';
|
|
10
|
+
import { createDefaultRulesEngine, validatePrivuConfig, mergeConfigs, getDefaultConfig, createNarrativeValidator, } from '@principal-ai/principal-view-core';
|
|
11
11
|
// ============================================================================
|
|
12
12
|
// Config File Loading
|
|
13
13
|
// ============================================================================
|
|
@@ -116,6 +116,56 @@ function loadGraphConfig(filePath) {
|
|
|
116
116
|
return null;
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Load a narrative template file
|
|
121
|
+
*/
|
|
122
|
+
function loadNarrativeTemplate(filePath) {
|
|
123
|
+
if (!existsSync(filePath)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
128
|
+
const narrative = JSON.parse(raw);
|
|
129
|
+
return { narrative, raw };
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Load a canvas file for narrative validation
|
|
137
|
+
*/
|
|
138
|
+
function loadCanvas(filePath) {
|
|
139
|
+
if (!existsSync(filePath)) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const content = readFileSync(filePath, 'utf8');
|
|
144
|
+
const ext = filePath.toLowerCase();
|
|
145
|
+
if (ext.endsWith('.json')) {
|
|
146
|
+
return JSON.parse(content);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
return yaml.load(content);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Determine file type
|
|
158
|
+
*/
|
|
159
|
+
function getFileType(filePath) {
|
|
160
|
+
const name = basename(filePath).toLowerCase();
|
|
161
|
+
if (name.endsWith('.narrative.json')) {
|
|
162
|
+
return 'narrative';
|
|
163
|
+
}
|
|
164
|
+
if (name.endsWith('.canvas') || name.endsWith('.otel.canvas')) {
|
|
165
|
+
return 'canvas';
|
|
166
|
+
}
|
|
167
|
+
return 'config';
|
|
168
|
+
}
|
|
119
169
|
// ============================================================================
|
|
120
170
|
// Output Formatting
|
|
121
171
|
// ============================================================================
|
|
@@ -282,15 +332,14 @@ export function createLintCommand() {
|
|
|
282
332
|
ignore: privuConfig.exclude || ['**/node_modules/**'],
|
|
283
333
|
expandDirectories: false,
|
|
284
334
|
});
|
|
285
|
-
// Filter out library files, config files,
|
|
335
|
+
// Filter out library files, config files, and execution artifacts
|
|
336
|
+
// INCLUDE both canvas files and narrative templates for linting
|
|
286
337
|
const configFiles = matchedFiles.filter((f) => {
|
|
287
338
|
const name = basename(f).toLowerCase();
|
|
288
339
|
const isLibraryFile = name.startsWith('library.');
|
|
289
340
|
const isConfigFile = name.startsWith('.privurc');
|
|
290
|
-
const isCanvasFile = f.toLowerCase().endsWith('.canvas');
|
|
291
|
-
const isNarrativeTemplate = name.endsWith('.narrative.json');
|
|
292
341
|
const isExecutionArtifact = f.includes('__executions__/');
|
|
293
|
-
return !isLibraryFile && !isConfigFile && !
|
|
342
|
+
return !isLibraryFile && !isConfigFile && !isExecutionArtifact;
|
|
294
343
|
});
|
|
295
344
|
if (configFiles.length === 0) {
|
|
296
345
|
if (options.json) {
|
|
@@ -315,44 +364,116 @@ export function createLintCommand() {
|
|
|
315
364
|
console.log(chalk.yellow(`Warning: Could not load library from ${libraryPath}`));
|
|
316
365
|
}
|
|
317
366
|
}
|
|
318
|
-
//
|
|
367
|
+
// Helper function to count violations by rule
|
|
368
|
+
function countByRule(violations) {
|
|
369
|
+
const counts = {};
|
|
370
|
+
for (const v of violations) {
|
|
371
|
+
counts[v.ruleId] = (counts[v.ruleId] || 0) + 1;
|
|
372
|
+
}
|
|
373
|
+
return counts;
|
|
374
|
+
}
|
|
375
|
+
// Create validators
|
|
319
376
|
const engine = createDefaultRulesEngine();
|
|
377
|
+
const narrativeValidator = createNarrativeValidator();
|
|
320
378
|
// Lint each file
|
|
321
379
|
const results = new Map();
|
|
322
380
|
for (const filePath of configFiles) {
|
|
323
381
|
const absolutePath = resolve(cwd, filePath);
|
|
324
382
|
const relativePath = relative(cwd, absolutePath);
|
|
325
|
-
const
|
|
326
|
-
if (
|
|
327
|
-
//
|
|
383
|
+
const fileType = getFileType(absolutePath);
|
|
384
|
+
if (fileType === 'narrative') {
|
|
385
|
+
// Validate narrative template
|
|
386
|
+
const loaded = loadNarrativeTemplate(absolutePath);
|
|
387
|
+
if (!loaded) {
|
|
388
|
+
// File couldn't be loaded - report as error
|
|
389
|
+
results.set(relativePath, {
|
|
390
|
+
violations: [
|
|
391
|
+
{
|
|
392
|
+
ruleId: 'parse-error',
|
|
393
|
+
severity: 'error',
|
|
394
|
+
file: relativePath,
|
|
395
|
+
message: `Could not parse narrative file: ${filePath}`,
|
|
396
|
+
impact: 'File cannot be validated',
|
|
397
|
+
fixable: false,
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
errorCount: 1,
|
|
401
|
+
warningCount: 0,
|
|
402
|
+
fixableCount: 0,
|
|
403
|
+
byCategory: { schema: 1, reference: 0, structure: 0, pattern: 0, library: 0 },
|
|
404
|
+
byRule: { 'parse-error': 1 },
|
|
405
|
+
});
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
// Load the referenced canvas if it exists
|
|
409
|
+
const canvasPath = loaded.narrative.canvas
|
|
410
|
+
? resolve(dirname(absolutePath), loaded.narrative.canvas)
|
|
411
|
+
: undefined;
|
|
412
|
+
const canvas = canvasPath ? loadCanvas(canvasPath) : undefined;
|
|
413
|
+
// Run narrative validation
|
|
414
|
+
const narrativeResult = await narrativeValidator.validate({
|
|
415
|
+
narrative: loaded.narrative,
|
|
416
|
+
narrativePath: relativePath,
|
|
417
|
+
canvas: canvas ?? undefined,
|
|
418
|
+
canvasPath: canvasPath ? relative(cwd, canvasPath) : undefined,
|
|
419
|
+
basePath: dirname(absolutePath),
|
|
420
|
+
rawContent: loaded.raw,
|
|
421
|
+
});
|
|
422
|
+
// Convert narrative violations to graph violations format
|
|
423
|
+
const violations = narrativeResult.violations.map((v) => ({
|
|
424
|
+
ruleId: v.ruleId,
|
|
425
|
+
severity: v.severity,
|
|
426
|
+
file: v.file,
|
|
427
|
+
line: v.line,
|
|
428
|
+
path: v.path,
|
|
429
|
+
message: v.message,
|
|
430
|
+
impact: v.impact,
|
|
431
|
+
suggestion: v.suggestion,
|
|
432
|
+
fixable: v.fixable,
|
|
433
|
+
}));
|
|
328
434
|
results.set(relativePath, {
|
|
329
|
-
violations
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
435
|
+
violations,
|
|
436
|
+
errorCount: narrativeResult.errorCount,
|
|
437
|
+
warningCount: narrativeResult.warningCount,
|
|
438
|
+
fixableCount: narrativeResult.fixableCount,
|
|
439
|
+
byCategory: { schema: 0, reference: 0, structure: 0, pattern: 0, library: 0 }, // Could categorize narrative rules
|
|
440
|
+
byRule: countByRule(violations),
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
// Validate canvas/graph configuration
|
|
445
|
+
const loaded = loadGraphConfig(absolutePath);
|
|
446
|
+
if (!loaded) {
|
|
447
|
+
// File couldn't be loaded - report as error
|
|
448
|
+
results.set(relativePath, {
|
|
449
|
+
violations: [
|
|
450
|
+
{
|
|
451
|
+
ruleId: 'parse-error',
|
|
452
|
+
severity: 'error',
|
|
453
|
+
file: relativePath,
|
|
454
|
+
message: `Could not parse file: ${filePath}`,
|
|
455
|
+
impact: 'File cannot be validated',
|
|
456
|
+
fixable: false,
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
errorCount: 1,
|
|
460
|
+
warningCount: 0,
|
|
461
|
+
fixableCount: 0,
|
|
462
|
+
byCategory: { schema: 1, reference: 0, structure: 0, pattern: 0, library: 0 },
|
|
463
|
+
byRule: { 'parse-error': 1 },
|
|
464
|
+
});
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
// Run linting
|
|
468
|
+
const result = await engine.lintWithConfig(loaded.config, privuConfig, {
|
|
469
|
+
library,
|
|
470
|
+
configPath: relativePath,
|
|
471
|
+
rawContent: loaded.raw,
|
|
472
|
+
enabledRules: options.rule,
|
|
473
|
+
disabledRules: options.ignoreRule,
|
|
344
474
|
});
|
|
345
|
-
|
|
475
|
+
results.set(relativePath, result);
|
|
346
476
|
}
|
|
347
|
-
// Run linting
|
|
348
|
-
const result = await engine.lintWithConfig(loaded.config, privuConfig, {
|
|
349
|
-
library,
|
|
350
|
-
configPath: relativePath,
|
|
351
|
-
rawContent: loaded.raw,
|
|
352
|
-
enabledRules: options.rule,
|
|
353
|
-
disabledRules: options.ignoreRule,
|
|
354
|
-
});
|
|
355
|
-
results.set(relativePath, result);
|
|
356
477
|
}
|
|
357
478
|
// Output results
|
|
358
479
|
if (options.json) {
|