@aiready/cli 0.9.40 → 0.9.41
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/.aiready/aiready-report-20260227-133806.json +40 -141
- package/.aiready/aiready-report-20260227-133938.json +40 -141
- package/.github/FUNDING.yml +2 -2
- package/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-test.log +5 -5
- package/CONTRIBUTING.md +11 -2
- package/dist/chunk-HLBKROD3.mjs +237 -0
- package/dist/cli.js +688 -178
- package/dist/cli.mjs +679 -178
- package/dist/index.js +12 -3
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/__tests__/cli.test.ts +1 -1
- package/src/cli.ts +114 -28
- package/src/commands/agent-grounding.ts +22 -7
- package/src/commands/ai-signal-clarity.ts +13 -8
- package/src/commands/consistency.ts +69 -29
- package/src/commands/context.ts +108 -38
- package/src/commands/deps-health.ts +15 -6
- package/src/commands/doc-drift.ts +10 -4
- package/src/commands/index.ts +6 -2
- package/src/commands/patterns.ts +67 -26
- package/src/commands/scan.ts +399 -126
- package/src/commands/testability.ts +22 -9
- package/src/commands/visualize.ts +102 -45
- package/src/index.ts +34 -10
- package/src/utils/helpers.ts +57 -32
package/dist/cli.js
CHANGED
|
@@ -54,8 +54,14 @@ function sortBySeverity(results) {
|
|
|
54
54
|
});
|
|
55
55
|
return { ...file, issues: sortedIssues };
|
|
56
56
|
}).sort((a, b) => {
|
|
57
|
-
const aMaxSeverity = Math.max(
|
|
58
|
-
|
|
57
|
+
const aMaxSeverity = Math.max(
|
|
58
|
+
...a.issues.map((i) => severityOrder[i.severity] || 0),
|
|
59
|
+
0
|
|
60
|
+
);
|
|
61
|
+
const bMaxSeverity = Math.max(
|
|
62
|
+
...b.issues.map((i) => severityOrder[i.severity] || 0),
|
|
63
|
+
0
|
|
64
|
+
);
|
|
59
65
|
if (aMaxSeverity !== bMaxSeverity) {
|
|
60
66
|
return bMaxSeverity - aMaxSeverity;
|
|
61
67
|
}
|
|
@@ -154,7 +160,10 @@ async function analyzeUnified(options) {
|
|
|
154
160
|
options.progressCallback({ tool: "aiSignalClarity", data: report });
|
|
155
161
|
}
|
|
156
162
|
result.aiSignalClarity = report;
|
|
157
|
-
result.summary.totalIssues += report.results?.reduce(
|
|
163
|
+
result.summary.totalIssues += report.results?.reduce(
|
|
164
|
+
(sum, r) => sum + (r.issues?.length || 0),
|
|
165
|
+
0
|
|
166
|
+
) || 0;
|
|
158
167
|
}
|
|
159
168
|
if (tools.includes("grounding")) {
|
|
160
169
|
const { analyzeAgentGrounding } = await import("@aiready/agent-grounding");
|
|
@@ -213,19 +222,28 @@ function findLatestScanReport(dirPath) {
|
|
|
213
222
|
if (!(0, import_fs.existsSync)(aireadyDir)) {
|
|
214
223
|
return null;
|
|
215
224
|
}
|
|
216
|
-
let files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
225
|
+
let files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
226
|
+
(f) => f.startsWith("aiready-report-") && f.endsWith(".json")
|
|
227
|
+
);
|
|
217
228
|
if (files.length === 0) {
|
|
218
|
-
files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
229
|
+
files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
230
|
+
(f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
|
|
231
|
+
);
|
|
219
232
|
}
|
|
220
233
|
if (files.length === 0) {
|
|
221
234
|
return null;
|
|
222
235
|
}
|
|
223
|
-
const sortedFiles = files.map((f) => ({
|
|
236
|
+
const sortedFiles = files.map((f) => ({
|
|
237
|
+
name: f,
|
|
238
|
+
path: (0, import_path.resolve)(aireadyDir, f),
|
|
239
|
+
mtime: (0, import_fs.statSync)((0, import_path.resolve)(aireadyDir, f)).mtime
|
|
240
|
+
})).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
224
241
|
return sortedFiles[0].path;
|
|
225
242
|
}
|
|
226
|
-
function warnIfGraphCapExceeded(report, dirPath) {
|
|
243
|
+
async function warnIfGraphCapExceeded(report, dirPath) {
|
|
227
244
|
try {
|
|
228
|
-
const { loadConfig: loadConfig4 } =
|
|
245
|
+
const { loadConfig: loadConfig4 } = await import("@aiready/core");
|
|
246
|
+
void loadConfig4;
|
|
229
247
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
230
248
|
const configPath = (0, import_path.resolve)(dirPath, "aiready.json");
|
|
231
249
|
if ((0, import_fs.existsSync)(configPath)) {
|
|
@@ -237,7 +255,8 @@ function warnIfGraphCapExceeded(report, dirPath) {
|
|
|
237
255
|
maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges
|
|
238
256
|
};
|
|
239
257
|
}
|
|
240
|
-
} catch (
|
|
258
|
+
} catch (err) {
|
|
259
|
+
void err;
|
|
241
260
|
}
|
|
242
261
|
}
|
|
243
262
|
const nodeCount = (report.context?.length || 0) + (report.patterns?.length || 0);
|
|
@@ -248,21 +267,30 @@ function warnIfGraphCapExceeded(report, dirPath) {
|
|
|
248
267
|
}, 0) || 0;
|
|
249
268
|
if (nodeCount > graphConfig.maxNodes || edgeCount > graphConfig.maxEdges) {
|
|
250
269
|
console.log("");
|
|
251
|
-
console.log(
|
|
270
|
+
console.log(
|
|
271
|
+
import_chalk.default.yellow(`\u26A0\uFE0F Graph may be truncated at visualization time:`)
|
|
272
|
+
);
|
|
252
273
|
if (nodeCount > graphConfig.maxNodes) {
|
|
253
|
-
console.log(
|
|
274
|
+
console.log(
|
|
275
|
+
import_chalk.default.dim(` \u2022 Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`)
|
|
276
|
+
);
|
|
254
277
|
}
|
|
255
278
|
if (edgeCount > graphConfig.maxEdges) {
|
|
256
|
-
console.log(
|
|
279
|
+
console.log(
|
|
280
|
+
import_chalk.default.dim(` \u2022 Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`)
|
|
281
|
+
);
|
|
257
282
|
}
|
|
258
283
|
console.log(import_chalk.default.dim(` To increase limits, add to aiready.json:`));
|
|
259
284
|
console.log(import_chalk.default.dim(` {`));
|
|
260
285
|
console.log(import_chalk.default.dim(` "visualizer": {`));
|
|
261
|
-
console.log(
|
|
286
|
+
console.log(
|
|
287
|
+
import_chalk.default.dim(` "graph": { "maxNodes": 2000, "maxEdges": 5000 }`)
|
|
288
|
+
);
|
|
262
289
|
console.log(import_chalk.default.dim(` }`));
|
|
263
290
|
console.log(import_chalk.default.dim(` }`));
|
|
264
291
|
}
|
|
265
|
-
} catch (
|
|
292
|
+
} catch (err) {
|
|
293
|
+
void err;
|
|
266
294
|
}
|
|
267
295
|
}
|
|
268
296
|
function generateMarkdownReport(report, elapsedTime) {
|
|
@@ -311,7 +339,17 @@ async function scanAction(directory, options) {
|
|
|
311
339
|
const resolvedDir = (0, import_path2.resolve)(process.cwd(), directory || ".");
|
|
312
340
|
try {
|
|
313
341
|
const defaults = {
|
|
314
|
-
tools: [
|
|
342
|
+
tools: [
|
|
343
|
+
"patterns",
|
|
344
|
+
"context",
|
|
345
|
+
"consistency",
|
|
346
|
+
"aiSignalClarity",
|
|
347
|
+
"grounding",
|
|
348
|
+
"testability",
|
|
349
|
+
"doc-drift",
|
|
350
|
+
"deps-health",
|
|
351
|
+
"changeAmplification"
|
|
352
|
+
],
|
|
315
353
|
include: void 0,
|
|
316
354
|
exclude: void 0,
|
|
317
355
|
output: {
|
|
@@ -321,7 +359,8 @@ async function scanAction(directory, options) {
|
|
|
321
359
|
};
|
|
322
360
|
let profileTools = options.tools ? options.tools.split(",").map((t) => {
|
|
323
361
|
const tool = t.trim();
|
|
324
|
-
if (tool === "hallucination" || tool === "hallucination-risk")
|
|
362
|
+
if (tool === "hallucination" || tool === "hallucination-risk")
|
|
363
|
+
return "aiSignalClarity";
|
|
325
364
|
return tool;
|
|
326
365
|
}) : void 0;
|
|
327
366
|
if (options.profile) {
|
|
@@ -339,8 +378,12 @@ async function scanAction(directory, options) {
|
|
|
339
378
|
profileTools = ["context", "consistency", "grounding"];
|
|
340
379
|
break;
|
|
341
380
|
default:
|
|
342
|
-
console.log(
|
|
343
|
-
|
|
381
|
+
console.log(
|
|
382
|
+
import_chalk2.default.yellow(
|
|
383
|
+
`
|
|
384
|
+
\u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`
|
|
385
|
+
)
|
|
386
|
+
);
|
|
344
387
|
}
|
|
345
388
|
}
|
|
346
389
|
const cliOverrides = {
|
|
@@ -350,20 +393,41 @@ async function scanAction(directory, options) {
|
|
|
350
393
|
if (profileTools) {
|
|
351
394
|
cliOverrides.tools = profileTools;
|
|
352
395
|
}
|
|
353
|
-
const baseOptions = await (0, import_core.loadMergedConfig)(
|
|
396
|
+
const baseOptions = await (0, import_core.loadMergedConfig)(
|
|
397
|
+
resolvedDir,
|
|
398
|
+
defaults,
|
|
399
|
+
cliOverrides
|
|
400
|
+
);
|
|
354
401
|
let finalOptions = { ...baseOptions };
|
|
355
402
|
if (baseOptions.tools.includes("patterns")) {
|
|
356
403
|
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
357
|
-
const patternSmartDefaults = await getSmartDefaults(
|
|
358
|
-
|
|
404
|
+
const patternSmartDefaults = await getSmartDefaults(
|
|
405
|
+
resolvedDir,
|
|
406
|
+
baseOptions
|
|
407
|
+
);
|
|
408
|
+
finalOptions = {
|
|
409
|
+
...patternSmartDefaults,
|
|
410
|
+
...finalOptions,
|
|
411
|
+
...baseOptions
|
|
412
|
+
};
|
|
359
413
|
}
|
|
360
414
|
console.log(import_chalk2.default.cyan("\n=== AIReady Run Preview ==="));
|
|
361
|
-
console.log(
|
|
415
|
+
console.log(
|
|
416
|
+
import_chalk2.default.white("Tools to run:"),
|
|
417
|
+
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
418
|
+
);
|
|
362
419
|
console.log(import_chalk2.default.white("Will use settings from config and defaults."));
|
|
363
420
|
console.log(import_chalk2.default.white("\nGeneral settings:"));
|
|
364
|
-
if (finalOptions.rootDir)
|
|
365
|
-
|
|
366
|
-
if (finalOptions.
|
|
421
|
+
if (finalOptions.rootDir)
|
|
422
|
+
console.log(` rootDir: ${import_chalk2.default.bold(String(finalOptions.rootDir))}`);
|
|
423
|
+
if (finalOptions.include)
|
|
424
|
+
console.log(
|
|
425
|
+
` include: ${import_chalk2.default.bold(truncateArray(finalOptions.include, 6))}`
|
|
426
|
+
);
|
|
427
|
+
if (finalOptions.exclude)
|
|
428
|
+
console.log(
|
|
429
|
+
` exclude: ${import_chalk2.default.bold(truncateArray(finalOptions.exclude, 6))}`
|
|
430
|
+
);
|
|
367
431
|
if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
|
|
368
432
|
const patternDetectConfig = finalOptions["pattern-detect"] || {
|
|
369
433
|
minSimilarity: finalOptions.minSimilarity,
|
|
@@ -377,15 +441,40 @@ async function scanAction(directory, options) {
|
|
|
377
441
|
includeTests: finalOptions.includeTests
|
|
378
442
|
};
|
|
379
443
|
console.log(import_chalk2.default.white("\nPattern-detect settings:"));
|
|
380
|
-
console.log(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (patternDetectConfig.
|
|
387
|
-
|
|
388
|
-
|
|
444
|
+
console.log(
|
|
445
|
+
` minSimilarity: ${import_chalk2.default.bold(patternDetectConfig.minSimilarity ?? "default")}`
|
|
446
|
+
);
|
|
447
|
+
console.log(
|
|
448
|
+
` minLines: ${import_chalk2.default.bold(patternDetectConfig.minLines ?? "default")}`
|
|
449
|
+
);
|
|
450
|
+
if (patternDetectConfig.approx !== void 0)
|
|
451
|
+
console.log(
|
|
452
|
+
` approx: ${import_chalk2.default.bold(String(patternDetectConfig.approx))}`
|
|
453
|
+
);
|
|
454
|
+
if (patternDetectConfig.minSharedTokens !== void 0)
|
|
455
|
+
console.log(
|
|
456
|
+
` minSharedTokens: ${import_chalk2.default.bold(String(patternDetectConfig.minSharedTokens))}`
|
|
457
|
+
);
|
|
458
|
+
if (patternDetectConfig.maxCandidatesPerBlock !== void 0)
|
|
459
|
+
console.log(
|
|
460
|
+
` maxCandidatesPerBlock: ${import_chalk2.default.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`
|
|
461
|
+
);
|
|
462
|
+
if (patternDetectConfig.batchSize !== void 0)
|
|
463
|
+
console.log(
|
|
464
|
+
` batchSize: ${import_chalk2.default.bold(String(patternDetectConfig.batchSize))}`
|
|
465
|
+
);
|
|
466
|
+
if (patternDetectConfig.streamResults !== void 0)
|
|
467
|
+
console.log(
|
|
468
|
+
` streamResults: ${import_chalk2.default.bold(String(patternDetectConfig.streamResults))}`
|
|
469
|
+
);
|
|
470
|
+
if (patternDetectConfig.severity !== void 0)
|
|
471
|
+
console.log(
|
|
472
|
+
` severity: ${import_chalk2.default.bold(String(patternDetectConfig.severity))}`
|
|
473
|
+
);
|
|
474
|
+
if (patternDetectConfig.includeTests !== void 0)
|
|
475
|
+
console.log(
|
|
476
|
+
` includeTests: ${import_chalk2.default.bold(String(patternDetectConfig.includeTests))}`
|
|
477
|
+
);
|
|
389
478
|
}
|
|
390
479
|
if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
|
|
391
480
|
const ca = finalOptions["context-analyzer"] || {
|
|
@@ -397,20 +486,42 @@ async function scanAction(directory, options) {
|
|
|
397
486
|
};
|
|
398
487
|
console.log(import_chalk2.default.white("\nContext-analyzer settings:"));
|
|
399
488
|
console.log(` maxDepth: ${import_chalk2.default.bold(ca.maxDepth ?? "default")}`);
|
|
400
|
-
console.log(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (ca.
|
|
489
|
+
console.log(
|
|
490
|
+
` maxContextBudget: ${import_chalk2.default.bold(ca.maxContextBudget ?? "default")}`
|
|
491
|
+
);
|
|
492
|
+
if (ca.minCohesion !== void 0)
|
|
493
|
+
console.log(` minCohesion: ${import_chalk2.default.bold(String(ca.minCohesion))}`);
|
|
494
|
+
if (ca.maxFragmentation !== void 0)
|
|
495
|
+
console.log(
|
|
496
|
+
` maxFragmentation: ${import_chalk2.default.bold(String(ca.maxFragmentation))}`
|
|
497
|
+
);
|
|
498
|
+
if (ca.includeNodeModules !== void 0)
|
|
499
|
+
console.log(
|
|
500
|
+
` includeNodeModules: ${import_chalk2.default.bold(String(ca.includeNodeModules))}`
|
|
501
|
+
);
|
|
404
502
|
}
|
|
405
503
|
if (finalOptions.consistency) {
|
|
406
504
|
const c = finalOptions.consistency;
|
|
407
505
|
console.log(import_chalk2.default.white("\nConsistency settings:"));
|
|
408
|
-
console.log(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
506
|
+
console.log(
|
|
507
|
+
` checkNaming: ${import_chalk2.default.bold(String(c.checkNaming ?? true))}`
|
|
508
|
+
);
|
|
509
|
+
console.log(
|
|
510
|
+
` checkPatterns: ${import_chalk2.default.bold(String(c.checkPatterns ?? true))}`
|
|
511
|
+
);
|
|
512
|
+
console.log(
|
|
513
|
+
` checkArchitecture: ${import_chalk2.default.bold(String(c.checkArchitecture ?? false))}`
|
|
514
|
+
);
|
|
515
|
+
if (c.minSeverity)
|
|
516
|
+
console.log(` minSeverity: ${import_chalk2.default.bold(c.minSeverity)}`);
|
|
517
|
+
if (c.acceptedAbbreviations)
|
|
518
|
+
console.log(
|
|
519
|
+
` acceptedAbbreviations: ${import_chalk2.default.bold(truncateArray(c.acceptedAbbreviations, 8))}`
|
|
520
|
+
);
|
|
521
|
+
if (c.shortWords)
|
|
522
|
+
console.log(
|
|
523
|
+
` shortWords: ${import_chalk2.default.bold(truncateArray(c.shortWords, 8))}`
|
|
524
|
+
);
|
|
414
525
|
}
|
|
415
526
|
console.log(import_chalk2.default.white("\nStarting analysis..."));
|
|
416
527
|
const progressCallback = (event) => {
|
|
@@ -419,40 +530,62 @@ async function scanAction(directory, options) {
|
|
|
419
530
|
try {
|
|
420
531
|
if (event.tool === "patterns") {
|
|
421
532
|
const pr = event.data;
|
|
422
|
-
console.log(
|
|
423
|
-
|
|
533
|
+
console.log(
|
|
534
|
+
` Duplicate patterns: ${import_chalk2.default.bold(String(pr.duplicates?.length || 0))}`
|
|
535
|
+
);
|
|
536
|
+
console.log(
|
|
537
|
+
` Files with pattern issues: ${import_chalk2.default.bold(String(pr.results?.length || 0))}`
|
|
538
|
+
);
|
|
424
539
|
if (pr.duplicates && pr.duplicates.length > 0) {
|
|
425
540
|
pr.duplicates.slice(0, 5).forEach((d, i) => {
|
|
426
|
-
console.log(
|
|
541
|
+
console.log(
|
|
542
|
+
` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`
|
|
543
|
+
);
|
|
427
544
|
});
|
|
428
545
|
}
|
|
429
546
|
if (pr.results && pr.results.length > 0) {
|
|
430
547
|
console.log(` Top files with pattern issues:`);
|
|
431
|
-
const sortedByIssues = [...pr.results].sort(
|
|
548
|
+
const sortedByIssues = [...pr.results].sort(
|
|
549
|
+
(a, b) => (b.issues?.length || 0) - (a.issues?.length || 0)
|
|
550
|
+
);
|
|
432
551
|
sortedByIssues.slice(0, 5).forEach((r, i) => {
|
|
433
|
-
console.log(
|
|
552
|
+
console.log(
|
|
553
|
+
` ${i + 1}. ${r.fileName.split("/").pop()} - ${r.issues.length} issue(s)`
|
|
554
|
+
);
|
|
434
555
|
});
|
|
435
556
|
}
|
|
436
557
|
if (pr.groups && pr.groups.length >= 0) {
|
|
437
|
-
console.log(
|
|
558
|
+
console.log(
|
|
559
|
+
` \u2705 Grouped ${import_chalk2.default.bold(String(pr.duplicates?.length || 0))} duplicates into ${import_chalk2.default.bold(String(pr.groups.length))} file pairs`
|
|
560
|
+
);
|
|
438
561
|
}
|
|
439
562
|
if (pr.clusters && pr.clusters.length >= 0) {
|
|
440
|
-
console.log(
|
|
563
|
+
console.log(
|
|
564
|
+
` \u2705 Created ${import_chalk2.default.bold(String(pr.clusters.length))} refactor clusters`
|
|
565
|
+
);
|
|
441
566
|
pr.clusters.slice(0, 3).forEach((cl, idx) => {
|
|
442
567
|
const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
|
|
443
|
-
console.log(
|
|
568
|
+
console.log(
|
|
569
|
+
` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`
|
|
570
|
+
);
|
|
444
571
|
});
|
|
445
572
|
}
|
|
446
573
|
} else if (event.tool === "context") {
|
|
447
574
|
const cr = event.data;
|
|
448
|
-
console.log(
|
|
575
|
+
console.log(
|
|
576
|
+
` Context issues found: ${import_chalk2.default.bold(String(cr.length || 0))}`
|
|
577
|
+
);
|
|
449
578
|
cr.slice(0, 5).forEach((c, i) => {
|
|
450
579
|
const msg = c.message ? ` - ${c.message}` : "";
|
|
451
|
-
console.log(
|
|
580
|
+
console.log(
|
|
581
|
+
` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`
|
|
582
|
+
);
|
|
452
583
|
});
|
|
453
584
|
} else if (event.tool === "consistency") {
|
|
454
585
|
const rep = event.data;
|
|
455
|
-
console.log(
|
|
586
|
+
console.log(
|
|
587
|
+
` Consistency totalIssues: ${import_chalk2.default.bold(String(rep.summary?.totalIssues || 0))}`
|
|
588
|
+
);
|
|
456
589
|
if (rep.results && rep.results.length > 0) {
|
|
457
590
|
const fileMap = /* @__PURE__ */ new Map();
|
|
458
591
|
rep.results.forEach((r) => {
|
|
@@ -462,68 +595,126 @@ async function scanAction(directory, options) {
|
|
|
462
595
|
fileMap.get(file).push(issue);
|
|
463
596
|
});
|
|
464
597
|
});
|
|
465
|
-
const files = Array.from(fileMap.entries()).sort(
|
|
598
|
+
const files = Array.from(fileMap.entries()).sort(
|
|
599
|
+
(a, b) => b[1].length - a[1].length
|
|
600
|
+
);
|
|
466
601
|
const topFiles = files.slice(0, 10);
|
|
467
602
|
topFiles.forEach(([file, issues], idx) => {
|
|
468
|
-
const counts = issues.reduce(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
603
|
+
const counts = issues.reduce(
|
|
604
|
+
(acc, it) => {
|
|
605
|
+
const s = (it.severity || "info").toLowerCase();
|
|
606
|
+
acc[s] = (acc[s] || 0) + 1;
|
|
607
|
+
return acc;
|
|
608
|
+
},
|
|
609
|
+
{}
|
|
610
|
+
);
|
|
611
|
+
const sample = issues.find(
|
|
612
|
+
(it) => it.severity === "critical" || it.severity === "major"
|
|
613
|
+
) || issues[0];
|
|
474
614
|
const sampleMsg = sample ? ` \u2014 ${sample.message}` : "";
|
|
475
|
-
console.log(
|
|
615
|
+
console.log(
|
|
616
|
+
` ${idx + 1}. ${file} \u2014 ${issues.length} issue(s) (critical:${counts.critical || 0} major:${counts.major || 0} minor:${counts.minor || 0} info:${counts.info || 0})${sampleMsg}`
|
|
617
|
+
);
|
|
476
618
|
});
|
|
477
619
|
const remaining = files.length - topFiles.length;
|
|
478
620
|
if (remaining > 0) {
|
|
479
|
-
console.log(
|
|
621
|
+
console.log(
|
|
622
|
+
import_chalk2.default.dim(
|
|
623
|
+
` ... and ${remaining} more files with issues (use --output json for full details)`
|
|
624
|
+
)
|
|
625
|
+
);
|
|
480
626
|
}
|
|
481
627
|
}
|
|
482
628
|
} else if (event.tool === "doc-drift") {
|
|
483
629
|
const dr = event.data;
|
|
484
|
-
console.log(
|
|
630
|
+
console.log(
|
|
631
|
+
` Issues found: ${import_chalk2.default.bold(String(dr.issues?.length || 0))}`
|
|
632
|
+
);
|
|
485
633
|
if (dr.rawData) {
|
|
486
|
-
console.log(
|
|
487
|
-
|
|
634
|
+
console.log(
|
|
635
|
+
` Signature Mismatches: ${import_chalk2.default.bold(dr.rawData.outdatedComments || 0)}`
|
|
636
|
+
);
|
|
637
|
+
console.log(
|
|
638
|
+
` Undocumented Complexity: ${import_chalk2.default.bold(dr.rawData.undocumentedComplexity || 0)}`
|
|
639
|
+
);
|
|
488
640
|
}
|
|
489
641
|
} else if (event.tool === "deps-health") {
|
|
490
642
|
const dr = event.data;
|
|
491
|
-
console.log(
|
|
643
|
+
console.log(
|
|
644
|
+
` Packages Analyzed: ${import_chalk2.default.bold(String(dr.summary?.packagesAnalyzed || 0))}`
|
|
645
|
+
);
|
|
492
646
|
if (dr.rawData) {
|
|
493
|
-
console.log(
|
|
494
|
-
|
|
647
|
+
console.log(
|
|
648
|
+
` Deprecated Packages: ${import_chalk2.default.bold(dr.rawData.deprecatedPackages || 0)}`
|
|
649
|
+
);
|
|
650
|
+
console.log(
|
|
651
|
+
` AI Cutoff Skew Score: ${import_chalk2.default.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`
|
|
652
|
+
);
|
|
495
653
|
}
|
|
496
654
|
} else if (event.tool === "change-amplification" || event.tool === "changeAmplification") {
|
|
497
655
|
const dr = event.data;
|
|
498
|
-
console.log(
|
|
656
|
+
console.log(
|
|
657
|
+
` Coupling issues: ${import_chalk2.default.bold(String(dr.issues?.length || 0))}`
|
|
658
|
+
);
|
|
499
659
|
if (dr.summary) {
|
|
500
|
-
console.log(
|
|
660
|
+
console.log(
|
|
661
|
+
` Complexity Score: ${import_chalk2.default.bold(dr.summary.score || 0)}/100`
|
|
662
|
+
);
|
|
501
663
|
}
|
|
502
664
|
}
|
|
503
665
|
} catch (err) {
|
|
666
|
+
void err;
|
|
504
667
|
}
|
|
505
668
|
};
|
|
506
|
-
const results = await analyzeUnified({
|
|
669
|
+
const results = await analyzeUnified({
|
|
670
|
+
...finalOptions,
|
|
671
|
+
progressCallback,
|
|
672
|
+
suppressToolConfig: true
|
|
673
|
+
});
|
|
507
674
|
console.log(import_chalk2.default.cyan("\n=== AIReady Run Summary ==="));
|
|
508
|
-
console.log(
|
|
675
|
+
console.log(
|
|
676
|
+
import_chalk2.default.white("Tools run:"),
|
|
677
|
+
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
678
|
+
);
|
|
509
679
|
console.log(import_chalk2.default.cyan("\nResults summary:"));
|
|
510
|
-
console.log(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if (results.
|
|
514
|
-
|
|
515
|
-
|
|
680
|
+
console.log(
|
|
681
|
+
` Total issues (all tools): ${import_chalk2.default.bold(String(results.summary.totalIssues || 0))}`
|
|
682
|
+
);
|
|
683
|
+
if (results.duplicates)
|
|
684
|
+
console.log(
|
|
685
|
+
` Duplicate patterns found: ${import_chalk2.default.bold(String(results.duplicates.length || 0))}`
|
|
686
|
+
);
|
|
687
|
+
if (results.patterns)
|
|
688
|
+
console.log(
|
|
689
|
+
` Pattern files with issues: ${import_chalk2.default.bold(String(results.patterns.length || 0))}`
|
|
690
|
+
);
|
|
691
|
+
if (results.context)
|
|
692
|
+
console.log(
|
|
693
|
+
` Context issues: ${import_chalk2.default.bold(String(results.context.length || 0))}`
|
|
694
|
+
);
|
|
695
|
+
console.log(
|
|
696
|
+
` Consistency issues: ${import_chalk2.default.bold(String(results.consistency?.summary?.totalIssues || 0))}`
|
|
697
|
+
);
|
|
698
|
+
if (results.changeAmplification)
|
|
699
|
+
console.log(
|
|
700
|
+
` Change amplification: ${import_chalk2.default.bold(String(results.changeAmplification.summary?.score || 0))}/100`
|
|
701
|
+
);
|
|
516
702
|
console.log(import_chalk2.default.cyan("===========================\n"));
|
|
517
703
|
const elapsedTime = (0, import_core.getElapsedTime)(startTime);
|
|
704
|
+
void elapsedTime;
|
|
518
705
|
let scoringResult;
|
|
519
706
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
520
707
|
const toolScores = /* @__PURE__ */ new Map();
|
|
521
708
|
if (results.duplicates) {
|
|
522
709
|
const { calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
523
710
|
try {
|
|
524
|
-
const patternScore = calculatePatternScore(
|
|
711
|
+
const patternScore = calculatePatternScore(
|
|
712
|
+
results.duplicates,
|
|
713
|
+
results.patterns?.length || 0
|
|
714
|
+
);
|
|
525
715
|
toolScores.set("pattern-detect", patternScore);
|
|
526
716
|
} catch (err) {
|
|
717
|
+
void err;
|
|
527
718
|
}
|
|
528
719
|
}
|
|
529
720
|
if (results.context) {
|
|
@@ -533,6 +724,7 @@ async function scanAction(directory, options) {
|
|
|
533
724
|
const contextScore = calculateContextScore(ctxSummary);
|
|
534
725
|
toolScores.set("context-analyzer", contextScore);
|
|
535
726
|
} catch (err) {
|
|
727
|
+
void err;
|
|
536
728
|
}
|
|
537
729
|
}
|
|
538
730
|
if (results.consistency) {
|
|
@@ -540,17 +732,24 @@ async function scanAction(directory, options) {
|
|
|
540
732
|
try {
|
|
541
733
|
const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
|
|
542
734
|
const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
|
|
543
|
-
const consistencyScore = calculateConsistencyScore(
|
|
735
|
+
const consistencyScore = calculateConsistencyScore(
|
|
736
|
+
issues,
|
|
737
|
+
totalFiles
|
|
738
|
+
);
|
|
544
739
|
toolScores.set("consistency", consistencyScore);
|
|
545
740
|
} catch (err) {
|
|
741
|
+
void err;
|
|
546
742
|
}
|
|
547
743
|
}
|
|
548
744
|
if (results.aiSignalClarity) {
|
|
549
745
|
const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
|
|
550
746
|
try {
|
|
551
|
-
const hrScore = calculateAiSignalClarityScore(
|
|
747
|
+
const hrScore = calculateAiSignalClarityScore(
|
|
748
|
+
results.aiSignalClarity
|
|
749
|
+
);
|
|
552
750
|
toolScores.set("ai-signal-clarity", hrScore);
|
|
553
751
|
} catch (err) {
|
|
752
|
+
void err;
|
|
554
753
|
}
|
|
555
754
|
}
|
|
556
755
|
if (results.grounding) {
|
|
@@ -559,6 +758,7 @@ async function scanAction(directory, options) {
|
|
|
559
758
|
const agScore = calculateGroundingScore(results.grounding);
|
|
560
759
|
toolScores.set("agent-grounding", agScore);
|
|
561
760
|
} catch (err) {
|
|
761
|
+
void err;
|
|
562
762
|
}
|
|
563
763
|
}
|
|
564
764
|
if (results.testability) {
|
|
@@ -567,6 +767,7 @@ async function scanAction(directory, options) {
|
|
|
567
767
|
const tbScore = calculateTestabilityScore(results.testability);
|
|
568
768
|
toolScores.set("testability", tbScore);
|
|
569
769
|
} catch (err) {
|
|
770
|
+
void err;
|
|
570
771
|
}
|
|
571
772
|
}
|
|
572
773
|
if (results.docDrift) {
|
|
@@ -575,7 +776,13 @@ async function scanAction(directory, options) {
|
|
|
575
776
|
score: results.docDrift.summary.score,
|
|
576
777
|
rawMetrics: results.docDrift.rawData,
|
|
577
778
|
factors: [],
|
|
578
|
-
recommendations: (results.docDrift.recommendations || []).map(
|
|
779
|
+
recommendations: (results.docDrift.recommendations || []).map(
|
|
780
|
+
(action) => ({
|
|
781
|
+
action,
|
|
782
|
+
estimatedImpact: 5,
|
|
783
|
+
priority: "medium"
|
|
784
|
+
})
|
|
785
|
+
)
|
|
579
786
|
});
|
|
580
787
|
}
|
|
581
788
|
if (results.deps) {
|
|
@@ -584,7 +791,13 @@ async function scanAction(directory, options) {
|
|
|
584
791
|
score: results.deps.summary.score,
|
|
585
792
|
rawMetrics: results.deps.rawData,
|
|
586
793
|
factors: [],
|
|
587
|
-
recommendations: (results.deps.recommendations || []).map(
|
|
794
|
+
recommendations: (results.deps.recommendations || []).map(
|
|
795
|
+
(action) => ({
|
|
796
|
+
action,
|
|
797
|
+
estimatedImpact: 5,
|
|
798
|
+
priority: "medium"
|
|
799
|
+
})
|
|
800
|
+
)
|
|
588
801
|
});
|
|
589
802
|
}
|
|
590
803
|
if (results.changeAmplification) {
|
|
@@ -593,17 +806,28 @@ async function scanAction(directory, options) {
|
|
|
593
806
|
score: results.changeAmplification.summary.score,
|
|
594
807
|
rawMetrics: results.changeAmplification.rawData,
|
|
595
808
|
factors: [],
|
|
596
|
-
recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
|
|
809
|
+
recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
|
|
810
|
+
action,
|
|
811
|
+
estimatedImpact: 5,
|
|
812
|
+
priority: "medium"
|
|
813
|
+
}))
|
|
597
814
|
});
|
|
598
815
|
}
|
|
599
816
|
const cliWeights = (0, import_core.parseWeightString)(options.weights);
|
|
600
817
|
if (toolScores.size > 0) {
|
|
601
|
-
scoringResult = (0, import_core.calculateOverallScore)(
|
|
818
|
+
scoringResult = (0, import_core.calculateOverallScore)(
|
|
819
|
+
toolScores,
|
|
820
|
+
finalOptions,
|
|
821
|
+
cliWeights.size ? cliWeights : void 0
|
|
822
|
+
);
|
|
602
823
|
console.log(import_chalk2.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
603
824
|
console.log(` ${(0, import_core.formatScore)(scoringResult)}`);
|
|
604
825
|
if (options.compareTo) {
|
|
605
826
|
try {
|
|
606
|
-
const prevReportStr = (0, import_fs2.readFileSync)(
|
|
827
|
+
const prevReportStr = (0, import_fs2.readFileSync)(
|
|
828
|
+
(0, import_path2.resolve)(process.cwd(), options.compareTo),
|
|
829
|
+
"utf8"
|
|
830
|
+
);
|
|
607
831
|
const prevReport = JSON.parse(prevReportStr);
|
|
608
832
|
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
609
833
|
if (typeof prevScore === "number") {
|
|
@@ -611,23 +835,44 @@ async function scanAction(directory, options) {
|
|
|
611
835
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
612
836
|
console.log();
|
|
613
837
|
if (diff > 0) {
|
|
614
|
-
console.log(
|
|
838
|
+
console.log(
|
|
839
|
+
import_chalk2.default.green(
|
|
840
|
+
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
841
|
+
)
|
|
842
|
+
);
|
|
615
843
|
} else if (diff < 0) {
|
|
616
|
-
console.log(
|
|
844
|
+
console.log(
|
|
845
|
+
import_chalk2.default.red(
|
|
846
|
+
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
847
|
+
)
|
|
848
|
+
);
|
|
617
849
|
} else {
|
|
618
|
-
console.log(
|
|
850
|
+
console.log(
|
|
851
|
+
import_chalk2.default.blue(
|
|
852
|
+
` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
853
|
+
)
|
|
854
|
+
);
|
|
619
855
|
}
|
|
620
856
|
scoringResult.trend = {
|
|
621
857
|
previousScore: prevScore,
|
|
622
858
|
difference: diff
|
|
623
859
|
};
|
|
624
860
|
} else {
|
|
625
|
-
console.log(
|
|
626
|
-
|
|
861
|
+
console.log(
|
|
862
|
+
import_chalk2.default.yellow(
|
|
863
|
+
`
|
|
864
|
+
\u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
|
|
865
|
+
)
|
|
866
|
+
);
|
|
627
867
|
}
|
|
628
868
|
} catch (e) {
|
|
629
|
-
|
|
630
|
-
|
|
869
|
+
void e;
|
|
870
|
+
console.log(
|
|
871
|
+
import_chalk2.default.yellow(
|
|
872
|
+
`
|
|
873
|
+
\u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
|
|
874
|
+
)
|
|
875
|
+
);
|
|
631
876
|
}
|
|
632
877
|
}
|
|
633
878
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
@@ -635,7 +880,9 @@ async function scanAction(directory, options) {
|
|
|
635
880
|
scoringResult.breakdown.forEach((tool) => {
|
|
636
881
|
const rating = (0, import_core.getRating)(tool.score);
|
|
637
882
|
const rd = (0, import_core.getRatingDisplay)(rating);
|
|
638
|
-
console.log(
|
|
883
|
+
console.log(
|
|
884
|
+
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
|
|
885
|
+
);
|
|
639
886
|
});
|
|
640
887
|
console.log();
|
|
641
888
|
if (finalOptions.scoring?.showBreakdown) {
|
|
@@ -653,20 +900,33 @@ async function scanAction(directory, options) {
|
|
|
653
900
|
if (outputFormat === "json") {
|
|
654
901
|
const timestamp = getReportTimestamp();
|
|
655
902
|
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
656
|
-
const outputPath = (0, import_core.resolveOutputPath)(
|
|
903
|
+
const outputPath = (0, import_core.resolveOutputPath)(
|
|
904
|
+
userOutputFile,
|
|
905
|
+
defaultFilename,
|
|
906
|
+
resolvedDir
|
|
907
|
+
);
|
|
657
908
|
const outputData = { ...results, scoring: scoringResult };
|
|
658
|
-
(0, import_core.handleJSONOutput)(
|
|
659
|
-
|
|
909
|
+
(0, import_core.handleJSONOutput)(
|
|
910
|
+
outputData,
|
|
911
|
+
outputPath,
|
|
912
|
+
`\u2705 Report saved to ${outputPath}`
|
|
913
|
+
);
|
|
914
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
660
915
|
} else {
|
|
661
916
|
const timestamp = getReportTimestamp();
|
|
662
917
|
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
663
|
-
const outputPath = (0, import_core.resolveOutputPath)(
|
|
918
|
+
const outputPath = (0, import_core.resolveOutputPath)(
|
|
919
|
+
userOutputFile,
|
|
920
|
+
defaultFilename,
|
|
921
|
+
resolvedDir
|
|
922
|
+
);
|
|
664
923
|
const outputData = { ...results, scoring: scoringResult };
|
|
665
924
|
try {
|
|
666
925
|
(0, import_fs2.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
|
|
667
926
|
console.log(import_chalk2.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
|
|
668
|
-
warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
927
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
669
928
|
} catch (err) {
|
|
929
|
+
void err;
|
|
670
930
|
}
|
|
671
931
|
}
|
|
672
932
|
const isCI = options.ci || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
|
|
@@ -684,16 +944,22 @@ async function scanAction(directory, options) {
|
|
|
684
944
|
}
|
|
685
945
|
console.log("::endgroup::");
|
|
686
946
|
if (threshold && scoringResult.overall < threshold) {
|
|
687
|
-
console.log(
|
|
947
|
+
console.log(
|
|
948
|
+
`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`
|
|
949
|
+
);
|
|
688
950
|
} else if (threshold) {
|
|
689
|
-
console.log(
|
|
951
|
+
console.log(
|
|
952
|
+
`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
953
|
+
);
|
|
690
954
|
}
|
|
691
955
|
if (results.patterns) {
|
|
692
956
|
const criticalPatterns = results.patterns.flatMap(
|
|
693
957
|
(p) => p.issues.filter((i) => i.severity === "critical")
|
|
694
958
|
);
|
|
695
959
|
criticalPatterns.slice(0, 10).forEach((issue) => {
|
|
696
|
-
console.log(
|
|
960
|
+
console.log(
|
|
961
|
+
`::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`
|
|
962
|
+
);
|
|
697
963
|
});
|
|
698
964
|
}
|
|
699
965
|
}
|
|
@@ -742,16 +1008,30 @@ async function scanAction(directory, options) {
|
|
|
742
1008
|
console.log(import_chalk2.default.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
|
|
743
1009
|
console.log(import_chalk2.default.red(` Reason: ${failReason}`));
|
|
744
1010
|
console.log(import_chalk2.default.dim("\n Remediation steps:"));
|
|
745
|
-
console.log(
|
|
1011
|
+
console.log(
|
|
1012
|
+
import_chalk2.default.dim(" 1. Run `aiready scan` locally to see detailed issues")
|
|
1013
|
+
);
|
|
746
1014
|
console.log(import_chalk2.default.dim(" 2. Fix the critical issues before merging"));
|
|
747
|
-
console.log(
|
|
1015
|
+
console.log(
|
|
1016
|
+
import_chalk2.default.dim(
|
|
1017
|
+
" 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"
|
|
1018
|
+
)
|
|
1019
|
+
);
|
|
748
1020
|
process.exit(1);
|
|
749
1021
|
} else {
|
|
750
1022
|
console.log(import_chalk2.default.green("\n\u2705 PR PASSED: AI Readiness Check"));
|
|
751
1023
|
if (threshold) {
|
|
752
|
-
console.log(
|
|
1024
|
+
console.log(
|
|
1025
|
+
import_chalk2.default.green(
|
|
1026
|
+
` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
753
1029
|
}
|
|
754
|
-
console.log(
|
|
1030
|
+
console.log(
|
|
1031
|
+
import_chalk2.default.dim(
|
|
1032
|
+
"\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"
|
|
1033
|
+
)
|
|
1034
|
+
);
|
|
755
1035
|
}
|
|
756
1036
|
}
|
|
757
1037
|
} catch (error) {
|
|
@@ -823,7 +1103,11 @@ async function patternsAction(directory, options) {
|
|
|
823
1103
|
if (options.minSharedTokens) {
|
|
824
1104
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
825
1105
|
}
|
|
826
|
-
const finalOptions = await (0, import_core2.loadMergedConfig)(
|
|
1106
|
+
const finalOptions = await (0, import_core2.loadMergedConfig)(
|
|
1107
|
+
resolvedDir,
|
|
1108
|
+
defaults,
|
|
1109
|
+
cliOptions
|
|
1110
|
+
);
|
|
827
1111
|
const { analyzePatterns: analyzePatterns2, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
828
1112
|
const { results, duplicates } = await analyzePatterns2(finalOptions);
|
|
829
1113
|
const elapsedTime = (0, import_core2.getElapsedTime)(startTime);
|
|
@@ -845,7 +1129,11 @@ async function patternsAction(directory, options) {
|
|
|
845
1129
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
846
1130
|
resolvedDir
|
|
847
1131
|
);
|
|
848
|
-
(0, import_core2.handleJSONOutput)(
|
|
1132
|
+
(0, import_core2.handleJSONOutput)(
|
|
1133
|
+
outputData,
|
|
1134
|
+
outputPath,
|
|
1135
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1136
|
+
);
|
|
849
1137
|
} else {
|
|
850
1138
|
const terminalWidth = process.stdout.columns || 80;
|
|
851
1139
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
@@ -853,10 +1141,22 @@ async function patternsAction(directory, options) {
|
|
|
853
1141
|
console.log(import_chalk3.default.cyan(divider));
|
|
854
1142
|
console.log(import_chalk3.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
855
1143
|
console.log(import_chalk3.default.cyan(divider) + "\n");
|
|
856
|
-
console.log(
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
console.log(
|
|
1144
|
+
console.log(
|
|
1145
|
+
import_chalk3.default.white(`\u{1F4C1} Files analyzed: ${import_chalk3.default.bold(results.length)}`)
|
|
1146
|
+
);
|
|
1147
|
+
console.log(
|
|
1148
|
+
import_chalk3.default.yellow(
|
|
1149
|
+
`\u26A0 Duplicate patterns found: ${import_chalk3.default.bold(summary.totalPatterns)}`
|
|
1150
|
+
)
|
|
1151
|
+
);
|
|
1152
|
+
console.log(
|
|
1153
|
+
import_chalk3.default.red(
|
|
1154
|
+
`\u{1F4B0} Token cost (wasted): ${import_chalk3.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1155
|
+
)
|
|
1156
|
+
);
|
|
1157
|
+
console.log(
|
|
1158
|
+
import_chalk3.default.gray(`\u23F1 Analysis time: ${import_chalk3.default.bold(elapsedTime + "s")}`)
|
|
1159
|
+
);
|
|
860
1160
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
861
1161
|
if (sortedTypes.length > 0) {
|
|
862
1162
|
console.log(import_chalk3.default.cyan("\n" + divider));
|
|
@@ -876,13 +1176,21 @@ async function patternsAction(directory, options) {
|
|
|
876
1176
|
const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
|
|
877
1177
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
878
1178
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
879
|
-
console.log(
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1179
|
+
console.log(
|
|
1180
|
+
`${severityIcon} ${severity}: ${import_chalk3.default.bold(file1Name)} \u2194 ${import_chalk3.default.bold(file2Name)}`
|
|
1181
|
+
);
|
|
1182
|
+
console.log(
|
|
1183
|
+
` Similarity: ${import_chalk3.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk3.default.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1184
|
+
);
|
|
1185
|
+
console.log(
|
|
1186
|
+
` Lines: ${import_chalk3.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk3.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1187
|
+
`
|
|
1188
|
+
);
|
|
883
1189
|
});
|
|
884
1190
|
} else {
|
|
885
|
-
console.log(
|
|
1191
|
+
console.log(
|
|
1192
|
+
import_chalk3.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1193
|
+
);
|
|
886
1194
|
}
|
|
887
1195
|
if (patternScore) {
|
|
888
1196
|
console.log(import_chalk3.default.cyan(divider));
|
|
@@ -922,7 +1230,7 @@ async function contextAction(directory, options) {
|
|
|
922
1230
|
file: void 0
|
|
923
1231
|
}
|
|
924
1232
|
};
|
|
925
|
-
|
|
1233
|
+
const baseOptions = await (0, import_core3.loadMergedConfig)(resolvedDir, defaults, {
|
|
926
1234
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
927
1235
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
928
1236
|
include: options.include?.split(","),
|
|
@@ -930,13 +1238,20 @@ async function contextAction(directory, options) {
|
|
|
930
1238
|
});
|
|
931
1239
|
let finalOptions = { ...baseOptions };
|
|
932
1240
|
const { getSmartDefaults } = await import("@aiready/context-analyzer");
|
|
933
|
-
const contextSmartDefaults = await getSmartDefaults(
|
|
1241
|
+
const contextSmartDefaults = await getSmartDefaults(
|
|
1242
|
+
resolvedDir,
|
|
1243
|
+
baseOptions
|
|
1244
|
+
);
|
|
934
1245
|
finalOptions = { ...contextSmartDefaults, ...finalOptions };
|
|
935
1246
|
console.log("\u{1F4CB} Configuration:");
|
|
936
1247
|
console.log(` Max depth: ${finalOptions.maxDepth}`);
|
|
937
1248
|
console.log(` Max context budget: ${finalOptions.maxContextBudget}`);
|
|
938
|
-
console.log(
|
|
939
|
-
|
|
1249
|
+
console.log(
|
|
1250
|
+
` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
|
|
1251
|
+
);
|
|
1252
|
+
console.log(
|
|
1253
|
+
` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
|
|
1254
|
+
);
|
|
940
1255
|
console.log(` Analysis focus: ${finalOptions.focus}`);
|
|
941
1256
|
console.log("");
|
|
942
1257
|
const { analyzeContext: analyzeContext2, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
@@ -960,7 +1275,11 @@ async function contextAction(directory, options) {
|
|
|
960
1275
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
961
1276
|
resolvedDir
|
|
962
1277
|
);
|
|
963
|
-
(0, import_core3.handleJSONOutput)(
|
|
1278
|
+
(0, import_core3.handleJSONOutput)(
|
|
1279
|
+
outputData,
|
|
1280
|
+
outputPath,
|
|
1281
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1282
|
+
);
|
|
964
1283
|
} else {
|
|
965
1284
|
const terminalWidth = process.stdout.columns || 80;
|
|
966
1285
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
@@ -968,59 +1287,103 @@ async function contextAction(directory, options) {
|
|
|
968
1287
|
console.log(import_chalk4.default.cyan(divider));
|
|
969
1288
|
console.log(import_chalk4.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
970
1289
|
console.log(import_chalk4.default.cyan(divider) + "\n");
|
|
971
|
-
console.log(
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
console.log(
|
|
975
|
-
|
|
1290
|
+
console.log(
|
|
1291
|
+
import_chalk4.default.white(`\u{1F4C1} Files analyzed: ${import_chalk4.default.bold(summary.totalFiles)}`)
|
|
1292
|
+
);
|
|
1293
|
+
console.log(
|
|
1294
|
+
import_chalk4.default.white(
|
|
1295
|
+
`\u{1F4CA} Total tokens: ${import_chalk4.default.bold(summary.totalTokens.toLocaleString())}`
|
|
1296
|
+
)
|
|
1297
|
+
);
|
|
1298
|
+
console.log(
|
|
1299
|
+
import_chalk4.default.yellow(
|
|
1300
|
+
`\u{1F4B0} Avg context budget: ${import_chalk4.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
|
|
1301
|
+
)
|
|
1302
|
+
);
|
|
1303
|
+
console.log(
|
|
1304
|
+
import_chalk4.default.white(`\u23F1 Analysis time: ${import_chalk4.default.bold(elapsedTime + "s")}
|
|
1305
|
+
`)
|
|
1306
|
+
);
|
|
976
1307
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
977
1308
|
if (totalIssues > 0) {
|
|
978
1309
|
console.log(import_chalk4.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
979
1310
|
if (summary.criticalIssues > 0) {
|
|
980
|
-
console.log(
|
|
1311
|
+
console.log(
|
|
1312
|
+
import_chalk4.default.red(` \u{1F534} Critical: ${import_chalk4.default.bold(summary.criticalIssues)}`)
|
|
1313
|
+
);
|
|
981
1314
|
}
|
|
982
1315
|
if (summary.majorIssues > 0) {
|
|
983
|
-
console.log(
|
|
1316
|
+
console.log(
|
|
1317
|
+
import_chalk4.default.yellow(` \u{1F7E1} Major: ${import_chalk4.default.bold(summary.majorIssues)}`)
|
|
1318
|
+
);
|
|
984
1319
|
}
|
|
985
1320
|
if (summary.minorIssues > 0) {
|
|
986
|
-
console.log(
|
|
1321
|
+
console.log(
|
|
1322
|
+
import_chalk4.default.blue(` \u{1F535} Minor: ${import_chalk4.default.bold(summary.minorIssues)}`)
|
|
1323
|
+
);
|
|
987
1324
|
}
|
|
988
|
-
console.log(
|
|
1325
|
+
console.log(
|
|
1326
|
+
import_chalk4.default.green(
|
|
1327
|
+
`
|
|
989
1328
|
\u{1F4A1} Potential savings: ${import_chalk4.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
990
|
-
`
|
|
1329
|
+
`
|
|
1330
|
+
)
|
|
1331
|
+
);
|
|
991
1332
|
} else {
|
|
992
1333
|
console.log(import_chalk4.default.green("\u2705 No significant issues found!\n"));
|
|
993
1334
|
}
|
|
994
1335
|
if (summary.deepFiles.length > 0) {
|
|
995
1336
|
console.log(import_chalk4.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
996
|
-
console.log(
|
|
997
|
-
|
|
998
|
-
|
|
1337
|
+
console.log(
|
|
1338
|
+
import_chalk4.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
|
|
1339
|
+
);
|
|
1340
|
+
console.log(
|
|
1341
|
+
import_chalk4.default.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
1342
|
+
`)
|
|
1343
|
+
);
|
|
999
1344
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1000
1345
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1001
|
-
console.log(
|
|
1346
|
+
console.log(
|
|
1347
|
+
` ${import_chalk4.default.cyan("\u2192")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(depth: ${item.depth})`)}`
|
|
1348
|
+
);
|
|
1002
1349
|
});
|
|
1003
1350
|
console.log();
|
|
1004
1351
|
}
|
|
1005
1352
|
if (summary.fragmentedModules.length > 0) {
|
|
1006
1353
|
console.log(import_chalk4.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
1007
|
-
console.log(
|
|
1008
|
-
|
|
1354
|
+
console.log(
|
|
1355
|
+
import_chalk4.default.gray(
|
|
1356
|
+
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1357
|
+
`
|
|
1358
|
+
)
|
|
1359
|
+
);
|
|
1009
1360
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
1010
|
-
console.log(
|
|
1011
|
-
|
|
1361
|
+
console.log(
|
|
1362
|
+
` ${import_chalk4.default.yellow("\u25CF")} ${import_chalk4.default.white(module2.domain)} - ${import_chalk4.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
|
|
1363
|
+
);
|
|
1364
|
+
console.log(
|
|
1365
|
+
import_chalk4.default.dim(
|
|
1366
|
+
` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
|
|
1367
|
+
)
|
|
1368
|
+
);
|
|
1012
1369
|
});
|
|
1013
1370
|
console.log();
|
|
1014
1371
|
}
|
|
1015
1372
|
if (summary.lowCohesionFiles.length > 0) {
|
|
1016
1373
|
console.log(import_chalk4.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1017
|
-
console.log(
|
|
1018
|
-
|
|
1374
|
+
console.log(
|
|
1375
|
+
import_chalk4.default.gray(
|
|
1376
|
+
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1377
|
+
`
|
|
1378
|
+
)
|
|
1379
|
+
);
|
|
1019
1380
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
1020
1381
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1021
1382
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
1022
1383
|
const color = item.score < 0.4 ? import_chalk4.default.red : import_chalk4.default.yellow;
|
|
1023
|
-
console.log(
|
|
1384
|
+
console.log(
|
|
1385
|
+
` ${color("\u25CB")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(${scorePercent}% cohesion)`)}`
|
|
1386
|
+
);
|
|
1024
1387
|
});
|
|
1025
1388
|
console.log();
|
|
1026
1389
|
}
|
|
@@ -1029,7 +1392,9 @@ async function contextAction(directory, options) {
|
|
|
1029
1392
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1030
1393
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1031
1394
|
const severityColor = item.severity === "critical" ? import_chalk4.default.red : item.severity === "major" ? import_chalk4.default.yellow : import_chalk4.default.blue;
|
|
1032
|
-
console.log(
|
|
1395
|
+
console.log(
|
|
1396
|
+
` ${severityColor("\u25CF")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1397
|
+
);
|
|
1033
1398
|
});
|
|
1034
1399
|
console.log();
|
|
1035
1400
|
}
|
|
@@ -1080,7 +1445,10 @@ async function consistencyAction(directory, options) {
|
|
|
1080
1445
|
let consistencyScore;
|
|
1081
1446
|
if (options.score) {
|
|
1082
1447
|
const issues = report.results?.flatMap((r) => r.issues) || [];
|
|
1083
|
-
consistencyScore = calculateConsistencyScore(
|
|
1448
|
+
consistencyScore = calculateConsistencyScore(
|
|
1449
|
+
issues,
|
|
1450
|
+
report.summary.filesAnalyzed
|
|
1451
|
+
);
|
|
1084
1452
|
}
|
|
1085
1453
|
const outputFormat = options.output || finalOptions.output?.format || "console";
|
|
1086
1454
|
const userOutputFile = options.outputFile || finalOptions.output?.file;
|
|
@@ -1098,7 +1466,11 @@ async function consistencyAction(directory, options) {
|
|
|
1098
1466
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
1099
1467
|
resolvedDir
|
|
1100
1468
|
);
|
|
1101
|
-
(0, import_core4.handleJSONOutput)(
|
|
1469
|
+
(0, import_core4.handleJSONOutput)(
|
|
1470
|
+
outputData,
|
|
1471
|
+
outputPath,
|
|
1472
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1473
|
+
);
|
|
1102
1474
|
} else if (outputFormat === "markdown") {
|
|
1103
1475
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1104
1476
|
const outputPath = (0, import_core4.resolveOutputPath)(
|
|
@@ -1110,15 +1482,23 @@ async function consistencyAction(directory, options) {
|
|
|
1110
1482
|
console.log(import_chalk5.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1111
1483
|
} else {
|
|
1112
1484
|
console.log(import_chalk5.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1113
|
-
console.log(
|
|
1485
|
+
console.log(
|
|
1486
|
+
`Files Analyzed: ${import_chalk5.default.cyan(report.summary.filesAnalyzed)}`
|
|
1487
|
+
);
|
|
1114
1488
|
console.log(`Total Issues: ${import_chalk5.default.yellow(report.summary.totalIssues)}`);
|
|
1115
1489
|
console.log(` Naming: ${import_chalk5.default.yellow(report.summary.namingIssues)}`);
|
|
1116
1490
|
console.log(` Patterns: ${import_chalk5.default.yellow(report.summary.patternIssues)}`);
|
|
1117
|
-
console.log(
|
|
1491
|
+
console.log(
|
|
1492
|
+
` Architecture: ${import_chalk5.default.yellow(report.summary.architectureIssues || 0)}`
|
|
1493
|
+
);
|
|
1118
1494
|
console.log(`Analysis Time: ${import_chalk5.default.gray(elapsedTime + "s")}
|
|
1119
1495
|
`);
|
|
1120
1496
|
if (report.summary.totalIssues === 0) {
|
|
1121
|
-
console.log(
|
|
1497
|
+
console.log(
|
|
1498
|
+
import_chalk5.default.green(
|
|
1499
|
+
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1500
|
+
)
|
|
1501
|
+
);
|
|
1122
1502
|
} else {
|
|
1123
1503
|
const namingResults = report.results.filter(
|
|
1124
1504
|
(r) => r.issues.some((i) => i.category === "naming")
|
|
@@ -1134,10 +1514,14 @@ async function consistencyAction(directory, options) {
|
|
|
1134
1514
|
for (const issue of result.issues) {
|
|
1135
1515
|
if (shown >= 5) break;
|
|
1136
1516
|
const severityColor = issue.severity === "critical" ? import_chalk5.default.red : issue.severity === "major" ? import_chalk5.default.yellow : issue.severity === "minor" ? import_chalk5.default.blue : import_chalk5.default.gray;
|
|
1137
|
-
console.log(
|
|
1517
|
+
console.log(
|
|
1518
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk5.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1519
|
+
);
|
|
1138
1520
|
console.log(` ${issue.message}`);
|
|
1139
1521
|
if (issue.suggestion) {
|
|
1140
|
-
console.log(
|
|
1522
|
+
console.log(
|
|
1523
|
+
` ${import_chalk5.default.dim("\u2192")} ${import_chalk5.default.italic(issue.suggestion)}`
|
|
1524
|
+
);
|
|
1141
1525
|
}
|
|
1142
1526
|
console.log();
|
|
1143
1527
|
shown++;
|
|
@@ -1157,10 +1541,14 @@ async function consistencyAction(directory, options) {
|
|
|
1157
1541
|
for (const issue of result.issues) {
|
|
1158
1542
|
if (shown >= 5) break;
|
|
1159
1543
|
const severityColor = issue.severity === "critical" ? import_chalk5.default.red : issue.severity === "major" ? import_chalk5.default.yellow : issue.severity === "minor" ? import_chalk5.default.blue : import_chalk5.default.gray;
|
|
1160
|
-
console.log(
|
|
1544
|
+
console.log(
|
|
1545
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk5.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1546
|
+
);
|
|
1161
1547
|
console.log(` ${issue.message}`);
|
|
1162
1548
|
if (issue.suggestion) {
|
|
1163
|
-
console.log(
|
|
1549
|
+
console.log(
|
|
1550
|
+
` ${import_chalk5.default.dim("\u2192")} ${import_chalk5.default.italic(issue.suggestion)}`
|
|
1551
|
+
);
|
|
1164
1552
|
}
|
|
1165
1553
|
console.log();
|
|
1166
1554
|
shown++;
|
|
@@ -1206,15 +1594,21 @@ async function visualizeAction(directory, options) {
|
|
|
1206
1594
|
const latestScan = findLatestScanReport(dirPath);
|
|
1207
1595
|
if (latestScan) {
|
|
1208
1596
|
reportPath = latestScan;
|
|
1209
|
-
console.log(
|
|
1597
|
+
console.log(
|
|
1598
|
+
import_chalk6.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1599
|
+
);
|
|
1210
1600
|
} else {
|
|
1211
1601
|
console.error(import_chalk6.default.red("\u274C No AI readiness report found"));
|
|
1212
|
-
console.log(
|
|
1602
|
+
console.log(
|
|
1603
|
+
import_chalk6.default.dim(
|
|
1604
|
+
`
|
|
1213
1605
|
Generate a report with:
|
|
1214
1606
|
aiready scan --output json
|
|
1215
1607
|
|
|
1216
1608
|
Or specify a custom report:
|
|
1217
|
-
aiready visualise --report <path-to-report.json>`
|
|
1609
|
+
aiready visualise --report <path-to-report.json>`
|
|
1610
|
+
)
|
|
1611
|
+
);
|
|
1218
1612
|
return;
|
|
1219
1613
|
}
|
|
1220
1614
|
}
|
|
@@ -1232,6 +1626,7 @@ Or specify a custom report:
|
|
|
1232
1626
|
};
|
|
1233
1627
|
}
|
|
1234
1628
|
} catch (e) {
|
|
1629
|
+
void e;
|
|
1235
1630
|
}
|
|
1236
1631
|
}
|
|
1237
1632
|
const envVisualizerConfig = JSON.stringify(graphConfig);
|
|
@@ -1252,11 +1647,18 @@ Or specify a custom report:
|
|
|
1252
1647
|
} else {
|
|
1253
1648
|
const nodemodulesLocations = [
|
|
1254
1649
|
(0, import_path6.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
|
|
1255
|
-
(0, import_path6.resolve)(
|
|
1650
|
+
(0, import_path6.resolve)(
|
|
1651
|
+
process.cwd(),
|
|
1652
|
+
"node_modules",
|
|
1653
|
+
"@aiready",
|
|
1654
|
+
"visualizer"
|
|
1655
|
+
)
|
|
1256
1656
|
];
|
|
1257
1657
|
let currentDir = dirPath;
|
|
1258
1658
|
while (currentDir !== "/" && currentDir !== ".") {
|
|
1259
|
-
nodemodulesLocations.push(
|
|
1659
|
+
nodemodulesLocations.push(
|
|
1660
|
+
(0, import_path6.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
|
|
1661
|
+
);
|
|
1260
1662
|
const parent = (0, import_path6.resolve)(currentDir, "..");
|
|
1261
1663
|
if (parent === currentDir) break;
|
|
1262
1664
|
currentDir = parent;
|
|
@@ -1273,7 +1675,8 @@ Or specify a custom report:
|
|
|
1273
1675
|
const vizPkgPath = require.resolve("@aiready/visualizer/package.json");
|
|
1274
1676
|
webDir = (0, import_path6.resolve)(vizPkgPath, "..");
|
|
1275
1677
|
visualizerAvailable = true;
|
|
1276
|
-
} catch (
|
|
1678
|
+
} catch (err) {
|
|
1679
|
+
void err;
|
|
1277
1680
|
}
|
|
1278
1681
|
}
|
|
1279
1682
|
}
|
|
@@ -1301,30 +1704,46 @@ Or specify a custom report:
|
|
|
1301
1704
|
AIREADY_REPORT_PATH: reportPath,
|
|
1302
1705
|
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1303
1706
|
};
|
|
1304
|
-
const vite = (0, import_child_process.spawn)("pnpm", ["run", "dev:web"], {
|
|
1707
|
+
const vite = (0, import_child_process.spawn)("pnpm", ["run", "dev:web"], {
|
|
1708
|
+
cwd: spawnCwd,
|
|
1709
|
+
stdio: "inherit",
|
|
1710
|
+
shell: true,
|
|
1711
|
+
env: envForSpawn
|
|
1712
|
+
});
|
|
1305
1713
|
const onExit = () => {
|
|
1306
1714
|
try {
|
|
1307
1715
|
reportWatcher.close();
|
|
1308
|
-
} catch (
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
void err;
|
|
1309
1718
|
}
|
|
1310
1719
|
try {
|
|
1311
1720
|
vite.kill();
|
|
1312
|
-
} catch (
|
|
1721
|
+
} catch (err) {
|
|
1722
|
+
void err;
|
|
1313
1723
|
}
|
|
1314
1724
|
process.exit(0);
|
|
1315
1725
|
};
|
|
1316
1726
|
process.on("SIGINT", onExit);
|
|
1317
1727
|
process.on("SIGTERM", onExit);
|
|
1318
1728
|
devServerStarted = true;
|
|
1729
|
+
void devServerStarted;
|
|
1319
1730
|
return;
|
|
1320
1731
|
} else {
|
|
1321
|
-
console.log(
|
|
1322
|
-
|
|
1732
|
+
console.log(
|
|
1733
|
+
import_chalk6.default.yellow(
|
|
1734
|
+
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1735
|
+
)
|
|
1736
|
+
);
|
|
1737
|
+
console.log(
|
|
1738
|
+
import_chalk6.default.cyan(" Falling back to static HTML generation...\n")
|
|
1739
|
+
);
|
|
1323
1740
|
useDevMode = false;
|
|
1324
1741
|
}
|
|
1325
1742
|
} catch (err) {
|
|
1326
1743
|
console.error("Failed to start dev server:", err);
|
|
1327
|
-
console.log(
|
|
1744
|
+
console.log(
|
|
1745
|
+
import_chalk6.default.cyan(" Falling back to static HTML generation...\n")
|
|
1746
|
+
);
|
|
1328
1747
|
useDevMode = false;
|
|
1329
1748
|
}
|
|
1330
1749
|
}
|
|
@@ -1346,20 +1765,25 @@ Or specify a custom report:
|
|
|
1346
1765
|
const urlPath = req.url || "/";
|
|
1347
1766
|
if (urlPath === "/" || urlPath === "/index.html") {
|
|
1348
1767
|
const content = await fsp.readFile(outPath, "utf8");
|
|
1349
|
-
res.writeHead(200, {
|
|
1768
|
+
res.writeHead(200, {
|
|
1769
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1770
|
+
});
|
|
1350
1771
|
res.end(content);
|
|
1351
1772
|
return;
|
|
1352
1773
|
}
|
|
1353
1774
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1354
1775
|
res.end("Not found");
|
|
1355
1776
|
} catch (e) {
|
|
1777
|
+
void e;
|
|
1356
1778
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1357
1779
|
res.end("Server error");
|
|
1358
1780
|
}
|
|
1359
1781
|
});
|
|
1360
1782
|
server.listen(port, () => {
|
|
1361
1783
|
const addr = `http://localhost:${port}/`;
|
|
1362
|
-
console.log(
|
|
1784
|
+
console.log(
|
|
1785
|
+
import_chalk6.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1786
|
+
);
|
|
1363
1787
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1364
1788
|
});
|
|
1365
1789
|
process.on("SIGINT", () => {
|
|
@@ -1425,9 +1849,13 @@ var getDirname = () => {
|
|
|
1425
1849
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
1426
1850
|
return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
1427
1851
|
};
|
|
1428
|
-
var packageJson = JSON.parse(
|
|
1852
|
+
var packageJson = JSON.parse(
|
|
1853
|
+
(0, import_fs5.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
|
|
1854
|
+
);
|
|
1429
1855
|
var program = new import_commander.Command();
|
|
1430
|
-
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
|
|
1856
|
+
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
|
|
1857
|
+
"after",
|
|
1858
|
+
`
|
|
1431
1859
|
AI READINESS SCORING:
|
|
1432
1860
|
Get a 0-100 score indicating how AI-ready your codebase is.
|
|
1433
1861
|
Use --score flag with any analysis command for detailed breakdown.
|
|
@@ -1462,23 +1890,105 @@ CONFIGURATION:
|
|
|
1462
1890
|
VERSION: ${packageJson.version}
|
|
1463
1891
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
1464
1892
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
1465
|
-
LANDING: https://github.com/caopengau/aiready-landing`
|
|
1466
|
-
|
|
1893
|
+
LANDING: https://github.com/caopengau/aiready-landing`
|
|
1894
|
+
);
|
|
1895
|
+
program.command("scan").description(
|
|
1896
|
+
"Run comprehensive AI-readiness analysis (patterns + context + consistency)"
|
|
1897
|
+
).argument("[directory]", "Directory to analyze", ".").option(
|
|
1898
|
+
"-t, --tools <tools>",
|
|
1899
|
+
"Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
|
|
1900
|
+
).option(
|
|
1901
|
+
"--profile <type>",
|
|
1902
|
+
"Scan profile to use (agentic, cost, security, onboarding)"
|
|
1903
|
+
).option(
|
|
1904
|
+
"--compare-to <path>",
|
|
1905
|
+
"Compare results against a previous AIReady report JSON"
|
|
1906
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
|
|
1907
|
+
"--no-score",
|
|
1908
|
+
"Disable calculating AI Readiness Score (enabled by default)"
|
|
1909
|
+
).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
|
|
1910
|
+
"--ci",
|
|
1911
|
+
"CI mode: GitHub Actions annotations, no colors, fail on threshold"
|
|
1912
|
+
).option(
|
|
1913
|
+
"--fail-on <level>",
|
|
1914
|
+
"Fail on issues: critical, major, any",
|
|
1915
|
+
"critical"
|
|
1916
|
+
).addHelpText("after", scanHelpText).action(async (directory, options) => {
|
|
1467
1917
|
await scanAction(directory, options);
|
|
1468
1918
|
});
|
|
1469
|
-
program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
|
|
1919
|
+
program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
|
|
1920
|
+
"--max-candidates <number>",
|
|
1921
|
+
"Maximum candidates per block (performance tuning)"
|
|
1922
|
+
).option(
|
|
1923
|
+
"--min-shared-tokens <number>",
|
|
1924
|
+
"Minimum shared tokens for candidates (performance tuning)"
|
|
1925
|
+
).option(
|
|
1926
|
+
"--full-scan",
|
|
1927
|
+
"Disable smart defaults for comprehensive analysis (slower)"
|
|
1928
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
|
|
1929
|
+
"--score",
|
|
1930
|
+
"Calculate and display AI Readiness Score for patterns (0-100)"
|
|
1931
|
+
).addHelpText("after", patternsHelpText).action(async (directory, options) => {
|
|
1470
1932
|
await patternsAction(directory, options);
|
|
1471
1933
|
});
|
|
1472
|
-
program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
|
|
1934
|
+
program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
|
|
1935
|
+
"--max-context <number>",
|
|
1936
|
+
"Maximum acceptable context budget (tokens)",
|
|
1937
|
+
"10000"
|
|
1938
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
|
|
1939
|
+
"--score",
|
|
1940
|
+
"Calculate and display AI Readiness Score for context (0-100)"
|
|
1941
|
+
).action(async (directory, options) => {
|
|
1473
1942
|
await contextAction(directory, options);
|
|
1474
1943
|
});
|
|
1475
|
-
program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
|
|
1944
|
+
program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
|
|
1945
|
+
"--min-severity <level>",
|
|
1946
|
+
"Minimum severity: info|minor|major|critical",
|
|
1947
|
+
"info"
|
|
1948
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
1949
|
+
"-o, --output <format>",
|
|
1950
|
+
"Output format: console, json, markdown",
|
|
1951
|
+
"console"
|
|
1952
|
+
).option("--output-file <path>", "Output file path (for json/markdown)").option(
|
|
1953
|
+
"--score",
|
|
1954
|
+
"Calculate and display AI Readiness Score for consistency (0-100)"
|
|
1955
|
+
).action(async (directory, options) => {
|
|
1476
1956
|
await consistencyAction(directory, options);
|
|
1477
1957
|
});
|
|
1478
|
-
program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
|
|
1958
|
+
program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
|
|
1959
|
+
"--report <path>",
|
|
1960
|
+
"Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
|
|
1961
|
+
).option(
|
|
1962
|
+
"-o, --output <path>",
|
|
1963
|
+
"Output HTML path (relative to directory)",
|
|
1964
|
+
"packages/visualizer/visualization.html"
|
|
1965
|
+
).option("--open", "Open generated HTML in default browser").option(
|
|
1966
|
+
"--serve [port]",
|
|
1967
|
+
"Start a local static server to serve the visualization (optional port number)",
|
|
1968
|
+
false
|
|
1969
|
+
).option(
|
|
1970
|
+
"--dev",
|
|
1971
|
+
"Start Vite dev server (live reload) for interactive development",
|
|
1972
|
+
true
|
|
1973
|
+
).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
|
|
1479
1974
|
await visualizeAction(directory, options);
|
|
1480
1975
|
});
|
|
1481
|
-
program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
|
|
1976
|
+
program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
|
|
1977
|
+
"--report <path>",
|
|
1978
|
+
"Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
|
|
1979
|
+
).option(
|
|
1980
|
+
"-o, --output <path>",
|
|
1981
|
+
"Output HTML path (relative to directory)",
|
|
1982
|
+
"packages/visualizer/visualization.html"
|
|
1983
|
+
).option("--open", "Open generated HTML in default browser").option(
|
|
1984
|
+
"--serve [port]",
|
|
1985
|
+
"Start a local static server to serve the visualization (optional port number)",
|
|
1986
|
+
false
|
|
1987
|
+
).option(
|
|
1988
|
+
"--dev",
|
|
1989
|
+
"Start Vite dev server (live reload) for interactive development",
|
|
1990
|
+
false
|
|
1991
|
+
).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
|
|
1482
1992
|
await visualizeAction(directory, options);
|
|
1483
1993
|
});
|
|
1484
1994
|
program.command("change-amplification").description("Analyze graph metrics for change amplification").argument("[directory]", "Directory to analyze", ".").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
|