@aiready/cli 0.9.39 → 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 +7805 -0
- package/.aiready/aiready-report-20260227-133938.json +7951 -0
- 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 +719 -179
- package/dist/cli.mjs +711 -180
- 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 +118 -32
- 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 +430 -119
- 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,17 +339,28 @@ 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: {
|
|
318
|
-
format: "
|
|
356
|
+
format: "console",
|
|
319
357
|
file: void 0
|
|
320
358
|
}
|
|
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,28 +378,56 @@ 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
|
-
const
|
|
347
|
-
tools: profileTools,
|
|
389
|
+
const cliOverrides = {
|
|
348
390
|
include: options.include?.split(","),
|
|
349
391
|
exclude: options.exclude?.split(",")
|
|
350
|
-
}
|
|
392
|
+
};
|
|
393
|
+
if (profileTools) {
|
|
394
|
+
cliOverrides.tools = profileTools;
|
|
395
|
+
}
|
|
396
|
+
const baseOptions = await (0, import_core.loadMergedConfig)(
|
|
397
|
+
resolvedDir,
|
|
398
|
+
defaults,
|
|
399
|
+
cliOverrides
|
|
400
|
+
);
|
|
351
401
|
let finalOptions = { ...baseOptions };
|
|
352
402
|
if (baseOptions.tools.includes("patterns")) {
|
|
353
403
|
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
354
|
-
const patternSmartDefaults = await getSmartDefaults(
|
|
355
|
-
|
|
404
|
+
const patternSmartDefaults = await getSmartDefaults(
|
|
405
|
+
resolvedDir,
|
|
406
|
+
baseOptions
|
|
407
|
+
);
|
|
408
|
+
finalOptions = {
|
|
409
|
+
...patternSmartDefaults,
|
|
410
|
+
...finalOptions,
|
|
411
|
+
...baseOptions
|
|
412
|
+
};
|
|
356
413
|
}
|
|
357
414
|
console.log(import_chalk2.default.cyan("\n=== AIReady Run Preview ==="));
|
|
358
|
-
console.log(
|
|
415
|
+
console.log(
|
|
416
|
+
import_chalk2.default.white("Tools to run:"),
|
|
417
|
+
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
418
|
+
);
|
|
359
419
|
console.log(import_chalk2.default.white("Will use settings from config and defaults."));
|
|
360
420
|
console.log(import_chalk2.default.white("\nGeneral settings:"));
|
|
361
|
-
if (finalOptions.rootDir)
|
|
362
|
-
|
|
363
|
-
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
|
+
);
|
|
364
431
|
if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
|
|
365
432
|
const patternDetectConfig = finalOptions["pattern-detect"] || {
|
|
366
433
|
minSimilarity: finalOptions.minSimilarity,
|
|
@@ -374,15 +441,40 @@ async function scanAction(directory, options) {
|
|
|
374
441
|
includeTests: finalOptions.includeTests
|
|
375
442
|
};
|
|
376
443
|
console.log(import_chalk2.default.white("\nPattern-detect settings:"));
|
|
377
|
-
console.log(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (patternDetectConfig.
|
|
384
|
-
|
|
385
|
-
|
|
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
|
+
);
|
|
386
478
|
}
|
|
387
479
|
if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
|
|
388
480
|
const ca = finalOptions["context-analyzer"] || {
|
|
@@ -394,20 +486,42 @@ async function scanAction(directory, options) {
|
|
|
394
486
|
};
|
|
395
487
|
console.log(import_chalk2.default.white("\nContext-analyzer settings:"));
|
|
396
488
|
console.log(` maxDepth: ${import_chalk2.default.bold(ca.maxDepth ?? "default")}`);
|
|
397
|
-
console.log(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
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
|
+
);
|
|
401
502
|
}
|
|
402
503
|
if (finalOptions.consistency) {
|
|
403
504
|
const c = finalOptions.consistency;
|
|
404
505
|
console.log(import_chalk2.default.white("\nConsistency settings:"));
|
|
405
|
-
console.log(
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
+
);
|
|
411
525
|
}
|
|
412
526
|
console.log(import_chalk2.default.white("\nStarting analysis..."));
|
|
413
527
|
const progressCallback = (event) => {
|
|
@@ -416,40 +530,62 @@ async function scanAction(directory, options) {
|
|
|
416
530
|
try {
|
|
417
531
|
if (event.tool === "patterns") {
|
|
418
532
|
const pr = event.data;
|
|
419
|
-
console.log(
|
|
420
|
-
|
|
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
|
+
);
|
|
421
539
|
if (pr.duplicates && pr.duplicates.length > 0) {
|
|
422
540
|
pr.duplicates.slice(0, 5).forEach((d, i) => {
|
|
423
|
-
console.log(
|
|
541
|
+
console.log(
|
|
542
|
+
` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`
|
|
543
|
+
);
|
|
424
544
|
});
|
|
425
545
|
}
|
|
426
546
|
if (pr.results && pr.results.length > 0) {
|
|
427
547
|
console.log(` Top files with pattern issues:`);
|
|
428
|
-
const sortedByIssues = [...pr.results].sort(
|
|
548
|
+
const sortedByIssues = [...pr.results].sort(
|
|
549
|
+
(a, b) => (b.issues?.length || 0) - (a.issues?.length || 0)
|
|
550
|
+
);
|
|
429
551
|
sortedByIssues.slice(0, 5).forEach((r, i) => {
|
|
430
|
-
console.log(
|
|
552
|
+
console.log(
|
|
553
|
+
` ${i + 1}. ${r.fileName.split("/").pop()} - ${r.issues.length} issue(s)`
|
|
554
|
+
);
|
|
431
555
|
});
|
|
432
556
|
}
|
|
433
557
|
if (pr.groups && pr.groups.length >= 0) {
|
|
434
|
-
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
|
+
);
|
|
435
561
|
}
|
|
436
562
|
if (pr.clusters && pr.clusters.length >= 0) {
|
|
437
|
-
console.log(
|
|
563
|
+
console.log(
|
|
564
|
+
` \u2705 Created ${import_chalk2.default.bold(String(pr.clusters.length))} refactor clusters`
|
|
565
|
+
);
|
|
438
566
|
pr.clusters.slice(0, 3).forEach((cl, idx) => {
|
|
439
567
|
const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
|
|
440
|
-
console.log(
|
|
568
|
+
console.log(
|
|
569
|
+
` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`
|
|
570
|
+
);
|
|
441
571
|
});
|
|
442
572
|
}
|
|
443
573
|
} else if (event.tool === "context") {
|
|
444
574
|
const cr = event.data;
|
|
445
|
-
console.log(
|
|
575
|
+
console.log(
|
|
576
|
+
` Context issues found: ${import_chalk2.default.bold(String(cr.length || 0))}`
|
|
577
|
+
);
|
|
446
578
|
cr.slice(0, 5).forEach((c, i) => {
|
|
447
579
|
const msg = c.message ? ` - ${c.message}` : "";
|
|
448
|
-
console.log(
|
|
580
|
+
console.log(
|
|
581
|
+
` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`
|
|
582
|
+
);
|
|
449
583
|
});
|
|
450
584
|
} else if (event.tool === "consistency") {
|
|
451
585
|
const rep = event.data;
|
|
452
|
-
console.log(
|
|
586
|
+
console.log(
|
|
587
|
+
` Consistency totalIssues: ${import_chalk2.default.bold(String(rep.summary?.totalIssues || 0))}`
|
|
588
|
+
);
|
|
453
589
|
if (rep.results && rep.results.length > 0) {
|
|
454
590
|
const fileMap = /* @__PURE__ */ new Map();
|
|
455
591
|
rep.results.forEach((r) => {
|
|
@@ -459,61 +595,126 @@ async function scanAction(directory, options) {
|
|
|
459
595
|
fileMap.get(file).push(issue);
|
|
460
596
|
});
|
|
461
597
|
});
|
|
462
|
-
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
|
+
);
|
|
463
601
|
const topFiles = files.slice(0, 10);
|
|
464
602
|
topFiles.forEach(([file, issues], idx) => {
|
|
465
|
-
const counts = issues.reduce(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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];
|
|
471
614
|
const sampleMsg = sample ? ` \u2014 ${sample.message}` : "";
|
|
472
|
-
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
|
+
);
|
|
473
618
|
});
|
|
474
619
|
const remaining = files.length - topFiles.length;
|
|
475
620
|
if (remaining > 0) {
|
|
476
|
-
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
|
+
);
|
|
477
626
|
}
|
|
478
627
|
}
|
|
479
628
|
} else if (event.tool === "doc-drift") {
|
|
480
629
|
const dr = event.data;
|
|
481
|
-
console.log(
|
|
630
|
+
console.log(
|
|
631
|
+
` Issues found: ${import_chalk2.default.bold(String(dr.issues?.length || 0))}`
|
|
632
|
+
);
|
|
482
633
|
if (dr.rawData) {
|
|
483
|
-
console.log(
|
|
484
|
-
|
|
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
|
+
);
|
|
485
640
|
}
|
|
486
641
|
} else if (event.tool === "deps-health") {
|
|
487
642
|
const dr = event.data;
|
|
488
|
-
console.log(
|
|
643
|
+
console.log(
|
|
644
|
+
` Packages Analyzed: ${import_chalk2.default.bold(String(dr.summary?.packagesAnalyzed || 0))}`
|
|
645
|
+
);
|
|
489
646
|
if (dr.rawData) {
|
|
490
|
-
console.log(
|
|
491
|
-
|
|
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
|
+
);
|
|
653
|
+
}
|
|
654
|
+
} else if (event.tool === "change-amplification" || event.tool === "changeAmplification") {
|
|
655
|
+
const dr = event.data;
|
|
656
|
+
console.log(
|
|
657
|
+
` Coupling issues: ${import_chalk2.default.bold(String(dr.issues?.length || 0))}`
|
|
658
|
+
);
|
|
659
|
+
if (dr.summary) {
|
|
660
|
+
console.log(
|
|
661
|
+
` Complexity Score: ${import_chalk2.default.bold(dr.summary.score || 0)}/100`
|
|
662
|
+
);
|
|
492
663
|
}
|
|
493
664
|
}
|
|
494
665
|
} catch (err) {
|
|
666
|
+
void err;
|
|
495
667
|
}
|
|
496
668
|
};
|
|
497
|
-
const results = await analyzeUnified({
|
|
669
|
+
const results = await analyzeUnified({
|
|
670
|
+
...finalOptions,
|
|
671
|
+
progressCallback,
|
|
672
|
+
suppressToolConfig: true
|
|
673
|
+
});
|
|
498
674
|
console.log(import_chalk2.default.cyan("\n=== AIReady Run Summary ==="));
|
|
499
|
-
console.log(
|
|
675
|
+
console.log(
|
|
676
|
+
import_chalk2.default.white("Tools run:"),
|
|
677
|
+
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
678
|
+
);
|
|
500
679
|
console.log(import_chalk2.default.cyan("\nResults summary:"));
|
|
501
|
-
console.log(
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if (results.
|
|
505
|
-
|
|
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
|
+
);
|
|
506
702
|
console.log(import_chalk2.default.cyan("===========================\n"));
|
|
507
703
|
const elapsedTime = (0, import_core.getElapsedTime)(startTime);
|
|
704
|
+
void elapsedTime;
|
|
508
705
|
let scoringResult;
|
|
509
706
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
510
707
|
const toolScores = /* @__PURE__ */ new Map();
|
|
511
708
|
if (results.duplicates) {
|
|
512
709
|
const { calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
513
710
|
try {
|
|
514
|
-
const patternScore = calculatePatternScore(
|
|
711
|
+
const patternScore = calculatePatternScore(
|
|
712
|
+
results.duplicates,
|
|
713
|
+
results.patterns?.length || 0
|
|
714
|
+
);
|
|
515
715
|
toolScores.set("pattern-detect", patternScore);
|
|
516
716
|
} catch (err) {
|
|
717
|
+
void err;
|
|
517
718
|
}
|
|
518
719
|
}
|
|
519
720
|
if (results.context) {
|
|
@@ -523,6 +724,7 @@ async function scanAction(directory, options) {
|
|
|
523
724
|
const contextScore = calculateContextScore(ctxSummary);
|
|
524
725
|
toolScores.set("context-analyzer", contextScore);
|
|
525
726
|
} catch (err) {
|
|
727
|
+
void err;
|
|
526
728
|
}
|
|
527
729
|
}
|
|
528
730
|
if (results.consistency) {
|
|
@@ -530,17 +732,24 @@ async function scanAction(directory, options) {
|
|
|
530
732
|
try {
|
|
531
733
|
const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
|
|
532
734
|
const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
|
|
533
|
-
const consistencyScore = calculateConsistencyScore(
|
|
735
|
+
const consistencyScore = calculateConsistencyScore(
|
|
736
|
+
issues,
|
|
737
|
+
totalFiles
|
|
738
|
+
);
|
|
534
739
|
toolScores.set("consistency", consistencyScore);
|
|
535
740
|
} catch (err) {
|
|
741
|
+
void err;
|
|
536
742
|
}
|
|
537
743
|
}
|
|
538
744
|
if (results.aiSignalClarity) {
|
|
539
|
-
const {
|
|
745
|
+
const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
|
|
540
746
|
try {
|
|
541
|
-
const hrScore =
|
|
747
|
+
const hrScore = calculateAiSignalClarityScore(
|
|
748
|
+
results.aiSignalClarity
|
|
749
|
+
);
|
|
542
750
|
toolScores.set("ai-signal-clarity", hrScore);
|
|
543
751
|
} catch (err) {
|
|
752
|
+
void err;
|
|
544
753
|
}
|
|
545
754
|
}
|
|
546
755
|
if (results.grounding) {
|
|
@@ -549,6 +758,7 @@ async function scanAction(directory, options) {
|
|
|
549
758
|
const agScore = calculateGroundingScore(results.grounding);
|
|
550
759
|
toolScores.set("agent-grounding", agScore);
|
|
551
760
|
} catch (err) {
|
|
761
|
+
void err;
|
|
552
762
|
}
|
|
553
763
|
}
|
|
554
764
|
if (results.testability) {
|
|
@@ -557,6 +767,7 @@ async function scanAction(directory, options) {
|
|
|
557
767
|
const tbScore = calculateTestabilityScore(results.testability);
|
|
558
768
|
toolScores.set("testability", tbScore);
|
|
559
769
|
} catch (err) {
|
|
770
|
+
void err;
|
|
560
771
|
}
|
|
561
772
|
}
|
|
562
773
|
if (results.docDrift) {
|
|
@@ -565,7 +776,13 @@ async function scanAction(directory, options) {
|
|
|
565
776
|
score: results.docDrift.summary.score,
|
|
566
777
|
rawMetrics: results.docDrift.rawData,
|
|
567
778
|
factors: [],
|
|
568
|
-
recommendations: results.docDrift.recommendations.map(
|
|
779
|
+
recommendations: (results.docDrift.recommendations || []).map(
|
|
780
|
+
(action) => ({
|
|
781
|
+
action,
|
|
782
|
+
estimatedImpact: 5,
|
|
783
|
+
priority: "medium"
|
|
784
|
+
})
|
|
785
|
+
)
|
|
569
786
|
});
|
|
570
787
|
}
|
|
571
788
|
if (results.deps) {
|
|
@@ -574,17 +791,43 @@ async function scanAction(directory, options) {
|
|
|
574
791
|
score: results.deps.summary.score,
|
|
575
792
|
rawMetrics: results.deps.rawData,
|
|
576
793
|
factors: [],
|
|
577
|
-
recommendations: results.deps.recommendations.map(
|
|
794
|
+
recommendations: (results.deps.recommendations || []).map(
|
|
795
|
+
(action) => ({
|
|
796
|
+
action,
|
|
797
|
+
estimatedImpact: 5,
|
|
798
|
+
priority: "medium"
|
|
799
|
+
})
|
|
800
|
+
)
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
if (results.changeAmplification) {
|
|
804
|
+
toolScores.set("change-amplification", {
|
|
805
|
+
toolName: "change-amplification",
|
|
806
|
+
score: results.changeAmplification.summary.score,
|
|
807
|
+
rawMetrics: results.changeAmplification.rawData,
|
|
808
|
+
factors: [],
|
|
809
|
+
recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
|
|
810
|
+
action,
|
|
811
|
+
estimatedImpact: 5,
|
|
812
|
+
priority: "medium"
|
|
813
|
+
}))
|
|
578
814
|
});
|
|
579
815
|
}
|
|
580
816
|
const cliWeights = (0, import_core.parseWeightString)(options.weights);
|
|
581
817
|
if (toolScores.size > 0) {
|
|
582
|
-
scoringResult = (0, import_core.calculateOverallScore)(
|
|
818
|
+
scoringResult = (0, import_core.calculateOverallScore)(
|
|
819
|
+
toolScores,
|
|
820
|
+
finalOptions,
|
|
821
|
+
cliWeights.size ? cliWeights : void 0
|
|
822
|
+
);
|
|
583
823
|
console.log(import_chalk2.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
584
824
|
console.log(` ${(0, import_core.formatScore)(scoringResult)}`);
|
|
585
825
|
if (options.compareTo) {
|
|
586
826
|
try {
|
|
587
|
-
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
|
+
);
|
|
588
831
|
const prevReport = JSON.parse(prevReportStr);
|
|
589
832
|
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
590
833
|
if (typeof prevScore === "number") {
|
|
@@ -592,23 +835,44 @@ async function scanAction(directory, options) {
|
|
|
592
835
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
593
836
|
console.log();
|
|
594
837
|
if (diff > 0) {
|
|
595
|
-
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
|
+
);
|
|
596
843
|
} else if (diff < 0) {
|
|
597
|
-
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
|
+
);
|
|
598
849
|
} else {
|
|
599
|
-
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
|
+
);
|
|
600
855
|
}
|
|
601
856
|
scoringResult.trend = {
|
|
602
857
|
previousScore: prevScore,
|
|
603
858
|
difference: diff
|
|
604
859
|
};
|
|
605
860
|
} else {
|
|
606
|
-
console.log(
|
|
607
|
-
|
|
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
|
+
);
|
|
608
867
|
}
|
|
609
868
|
} catch (e) {
|
|
610
|
-
|
|
611
|
-
|
|
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
|
+
);
|
|
612
876
|
}
|
|
613
877
|
}
|
|
614
878
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
@@ -616,7 +880,9 @@ async function scanAction(directory, options) {
|
|
|
616
880
|
scoringResult.breakdown.forEach((tool) => {
|
|
617
881
|
const rating = (0, import_core.getRating)(tool.score);
|
|
618
882
|
const rd = (0, import_core.getRatingDisplay)(rating);
|
|
619
|
-
console.log(
|
|
883
|
+
console.log(
|
|
884
|
+
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
|
|
885
|
+
);
|
|
620
886
|
});
|
|
621
887
|
console.log();
|
|
622
888
|
if (finalOptions.scoring?.showBreakdown) {
|
|
@@ -634,10 +900,34 @@ async function scanAction(directory, options) {
|
|
|
634
900
|
if (outputFormat === "json") {
|
|
635
901
|
const timestamp = getReportTimestamp();
|
|
636
902
|
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
637
|
-
const outputPath = (0, import_core.resolveOutputPath)(
|
|
903
|
+
const outputPath = (0, import_core.resolveOutputPath)(
|
|
904
|
+
userOutputFile,
|
|
905
|
+
defaultFilename,
|
|
906
|
+
resolvedDir
|
|
907
|
+
);
|
|
908
|
+
const outputData = { ...results, scoring: scoringResult };
|
|
909
|
+
(0, import_core.handleJSONOutput)(
|
|
910
|
+
outputData,
|
|
911
|
+
outputPath,
|
|
912
|
+
`\u2705 Report saved to ${outputPath}`
|
|
913
|
+
);
|
|
914
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
915
|
+
} else {
|
|
916
|
+
const timestamp = getReportTimestamp();
|
|
917
|
+
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
918
|
+
const outputPath = (0, import_core.resolveOutputPath)(
|
|
919
|
+
userOutputFile,
|
|
920
|
+
defaultFilename,
|
|
921
|
+
resolvedDir
|
|
922
|
+
);
|
|
638
923
|
const outputData = { ...results, scoring: scoringResult };
|
|
639
|
-
|
|
640
|
-
|
|
924
|
+
try {
|
|
925
|
+
(0, import_fs2.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
|
|
926
|
+
console.log(import_chalk2.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
|
|
927
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
928
|
+
} catch (err) {
|
|
929
|
+
void err;
|
|
930
|
+
}
|
|
641
931
|
}
|
|
642
932
|
const isCI = options.ci || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
|
|
643
933
|
if (isCI && scoringResult) {
|
|
@@ -654,16 +944,22 @@ async function scanAction(directory, options) {
|
|
|
654
944
|
}
|
|
655
945
|
console.log("::endgroup::");
|
|
656
946
|
if (threshold && scoringResult.overall < threshold) {
|
|
657
|
-
console.log(
|
|
947
|
+
console.log(
|
|
948
|
+
`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`
|
|
949
|
+
);
|
|
658
950
|
} else if (threshold) {
|
|
659
|
-
console.log(
|
|
951
|
+
console.log(
|
|
952
|
+
`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
953
|
+
);
|
|
660
954
|
}
|
|
661
955
|
if (results.patterns) {
|
|
662
956
|
const criticalPatterns = results.patterns.flatMap(
|
|
663
957
|
(p) => p.issues.filter((i) => i.severity === "critical")
|
|
664
958
|
);
|
|
665
959
|
criticalPatterns.slice(0, 10).forEach((issue) => {
|
|
666
|
-
console.log(
|
|
960
|
+
console.log(
|
|
961
|
+
`::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`
|
|
962
|
+
);
|
|
667
963
|
});
|
|
668
964
|
}
|
|
669
965
|
}
|
|
@@ -712,16 +1008,30 @@ async function scanAction(directory, options) {
|
|
|
712
1008
|
console.log(import_chalk2.default.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
|
|
713
1009
|
console.log(import_chalk2.default.red(` Reason: ${failReason}`));
|
|
714
1010
|
console.log(import_chalk2.default.dim("\n Remediation steps:"));
|
|
715
|
-
console.log(
|
|
1011
|
+
console.log(
|
|
1012
|
+
import_chalk2.default.dim(" 1. Run `aiready scan` locally to see detailed issues")
|
|
1013
|
+
);
|
|
716
1014
|
console.log(import_chalk2.default.dim(" 2. Fix the critical issues before merging"));
|
|
717
|
-
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
|
+
);
|
|
718
1020
|
process.exit(1);
|
|
719
1021
|
} else {
|
|
720
1022
|
console.log(import_chalk2.default.green("\n\u2705 PR PASSED: AI Readiness Check"));
|
|
721
1023
|
if (threshold) {
|
|
722
|
-
console.log(
|
|
1024
|
+
console.log(
|
|
1025
|
+
import_chalk2.default.green(
|
|
1026
|
+
` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
723
1029
|
}
|
|
724
|
-
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
|
+
);
|
|
725
1035
|
}
|
|
726
1036
|
}
|
|
727
1037
|
} catch (error) {
|
|
@@ -793,7 +1103,11 @@ async function patternsAction(directory, options) {
|
|
|
793
1103
|
if (options.minSharedTokens) {
|
|
794
1104
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
795
1105
|
}
|
|
796
|
-
const finalOptions = await (0, import_core2.loadMergedConfig)(
|
|
1106
|
+
const finalOptions = await (0, import_core2.loadMergedConfig)(
|
|
1107
|
+
resolvedDir,
|
|
1108
|
+
defaults,
|
|
1109
|
+
cliOptions
|
|
1110
|
+
);
|
|
797
1111
|
const { analyzePatterns: analyzePatterns2, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
798
1112
|
const { results, duplicates } = await analyzePatterns2(finalOptions);
|
|
799
1113
|
const elapsedTime = (0, import_core2.getElapsedTime)(startTime);
|
|
@@ -815,7 +1129,11 @@ async function patternsAction(directory, options) {
|
|
|
815
1129
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
816
1130
|
resolvedDir
|
|
817
1131
|
);
|
|
818
|
-
(0, import_core2.handleJSONOutput)(
|
|
1132
|
+
(0, import_core2.handleJSONOutput)(
|
|
1133
|
+
outputData,
|
|
1134
|
+
outputPath,
|
|
1135
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1136
|
+
);
|
|
819
1137
|
} else {
|
|
820
1138
|
const terminalWidth = process.stdout.columns || 80;
|
|
821
1139
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
@@ -823,10 +1141,22 @@ async function patternsAction(directory, options) {
|
|
|
823
1141
|
console.log(import_chalk3.default.cyan(divider));
|
|
824
1142
|
console.log(import_chalk3.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
825
1143
|
console.log(import_chalk3.default.cyan(divider) + "\n");
|
|
826
|
-
console.log(
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
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
|
+
);
|
|
830
1160
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
831
1161
|
if (sortedTypes.length > 0) {
|
|
832
1162
|
console.log(import_chalk3.default.cyan("\n" + divider));
|
|
@@ -846,13 +1176,21 @@ async function patternsAction(directory, options) {
|
|
|
846
1176
|
const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
|
|
847
1177
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
848
1178
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
849
|
-
console.log(
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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
|
+
);
|
|
853
1189
|
});
|
|
854
1190
|
} else {
|
|
855
|
-
console.log(
|
|
1191
|
+
console.log(
|
|
1192
|
+
import_chalk3.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1193
|
+
);
|
|
856
1194
|
}
|
|
857
1195
|
if (patternScore) {
|
|
858
1196
|
console.log(import_chalk3.default.cyan(divider));
|
|
@@ -892,7 +1230,7 @@ async function contextAction(directory, options) {
|
|
|
892
1230
|
file: void 0
|
|
893
1231
|
}
|
|
894
1232
|
};
|
|
895
|
-
|
|
1233
|
+
const baseOptions = await (0, import_core3.loadMergedConfig)(resolvedDir, defaults, {
|
|
896
1234
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
897
1235
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
898
1236
|
include: options.include?.split(","),
|
|
@@ -900,13 +1238,20 @@ async function contextAction(directory, options) {
|
|
|
900
1238
|
});
|
|
901
1239
|
let finalOptions = { ...baseOptions };
|
|
902
1240
|
const { getSmartDefaults } = await import("@aiready/context-analyzer");
|
|
903
|
-
const contextSmartDefaults = await getSmartDefaults(
|
|
1241
|
+
const contextSmartDefaults = await getSmartDefaults(
|
|
1242
|
+
resolvedDir,
|
|
1243
|
+
baseOptions
|
|
1244
|
+
);
|
|
904
1245
|
finalOptions = { ...contextSmartDefaults, ...finalOptions };
|
|
905
1246
|
console.log("\u{1F4CB} Configuration:");
|
|
906
1247
|
console.log(` Max depth: ${finalOptions.maxDepth}`);
|
|
907
1248
|
console.log(` Max context budget: ${finalOptions.maxContextBudget}`);
|
|
908
|
-
console.log(
|
|
909
|
-
|
|
1249
|
+
console.log(
|
|
1250
|
+
` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
|
|
1251
|
+
);
|
|
1252
|
+
console.log(
|
|
1253
|
+
` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
|
|
1254
|
+
);
|
|
910
1255
|
console.log(` Analysis focus: ${finalOptions.focus}`);
|
|
911
1256
|
console.log("");
|
|
912
1257
|
const { analyzeContext: analyzeContext2, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
@@ -930,7 +1275,11 @@ async function contextAction(directory, options) {
|
|
|
930
1275
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
931
1276
|
resolvedDir
|
|
932
1277
|
);
|
|
933
|
-
(0, import_core3.handleJSONOutput)(
|
|
1278
|
+
(0, import_core3.handleJSONOutput)(
|
|
1279
|
+
outputData,
|
|
1280
|
+
outputPath,
|
|
1281
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1282
|
+
);
|
|
934
1283
|
} else {
|
|
935
1284
|
const terminalWidth = process.stdout.columns || 80;
|
|
936
1285
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
@@ -938,59 +1287,103 @@ async function contextAction(directory, options) {
|
|
|
938
1287
|
console.log(import_chalk4.default.cyan(divider));
|
|
939
1288
|
console.log(import_chalk4.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
940
1289
|
console.log(import_chalk4.default.cyan(divider) + "\n");
|
|
941
|
-
console.log(
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
console.log(
|
|
945
|
-
|
|
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
|
+
);
|
|
946
1307
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
947
1308
|
if (totalIssues > 0) {
|
|
948
1309
|
console.log(import_chalk4.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
949
1310
|
if (summary.criticalIssues > 0) {
|
|
950
|
-
console.log(
|
|
1311
|
+
console.log(
|
|
1312
|
+
import_chalk4.default.red(` \u{1F534} Critical: ${import_chalk4.default.bold(summary.criticalIssues)}`)
|
|
1313
|
+
);
|
|
951
1314
|
}
|
|
952
1315
|
if (summary.majorIssues > 0) {
|
|
953
|
-
console.log(
|
|
1316
|
+
console.log(
|
|
1317
|
+
import_chalk4.default.yellow(` \u{1F7E1} Major: ${import_chalk4.default.bold(summary.majorIssues)}`)
|
|
1318
|
+
);
|
|
954
1319
|
}
|
|
955
1320
|
if (summary.minorIssues > 0) {
|
|
956
|
-
console.log(
|
|
1321
|
+
console.log(
|
|
1322
|
+
import_chalk4.default.blue(` \u{1F535} Minor: ${import_chalk4.default.bold(summary.minorIssues)}`)
|
|
1323
|
+
);
|
|
957
1324
|
}
|
|
958
|
-
console.log(
|
|
1325
|
+
console.log(
|
|
1326
|
+
import_chalk4.default.green(
|
|
1327
|
+
`
|
|
959
1328
|
\u{1F4A1} Potential savings: ${import_chalk4.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
960
|
-
`
|
|
1329
|
+
`
|
|
1330
|
+
)
|
|
1331
|
+
);
|
|
961
1332
|
} else {
|
|
962
1333
|
console.log(import_chalk4.default.green("\u2705 No significant issues found!\n"));
|
|
963
1334
|
}
|
|
964
1335
|
if (summary.deepFiles.length > 0) {
|
|
965
1336
|
console.log(import_chalk4.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
966
|
-
console.log(
|
|
967
|
-
|
|
968
|
-
|
|
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
|
+
);
|
|
969
1344
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
970
1345
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
971
|
-
console.log(
|
|
1346
|
+
console.log(
|
|
1347
|
+
` ${import_chalk4.default.cyan("\u2192")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(depth: ${item.depth})`)}`
|
|
1348
|
+
);
|
|
972
1349
|
});
|
|
973
1350
|
console.log();
|
|
974
1351
|
}
|
|
975
1352
|
if (summary.fragmentedModules.length > 0) {
|
|
976
1353
|
console.log(import_chalk4.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
977
|
-
console.log(
|
|
978
|
-
|
|
1354
|
+
console.log(
|
|
1355
|
+
import_chalk4.default.gray(
|
|
1356
|
+
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1357
|
+
`
|
|
1358
|
+
)
|
|
1359
|
+
);
|
|
979
1360
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
980
|
-
console.log(
|
|
981
|
-
|
|
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
|
+
);
|
|
982
1369
|
});
|
|
983
1370
|
console.log();
|
|
984
1371
|
}
|
|
985
1372
|
if (summary.lowCohesionFiles.length > 0) {
|
|
986
1373
|
console.log(import_chalk4.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
987
|
-
console.log(
|
|
988
|
-
|
|
1374
|
+
console.log(
|
|
1375
|
+
import_chalk4.default.gray(
|
|
1376
|
+
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1377
|
+
`
|
|
1378
|
+
)
|
|
1379
|
+
);
|
|
989
1380
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
990
1381
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
991
1382
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
992
1383
|
const color = item.score < 0.4 ? import_chalk4.default.red : import_chalk4.default.yellow;
|
|
993
|
-
console.log(
|
|
1384
|
+
console.log(
|
|
1385
|
+
` ${color("\u25CB")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(${scorePercent}% cohesion)`)}`
|
|
1386
|
+
);
|
|
994
1387
|
});
|
|
995
1388
|
console.log();
|
|
996
1389
|
}
|
|
@@ -999,7 +1392,9 @@ async function contextAction(directory, options) {
|
|
|
999
1392
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1000
1393
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1001
1394
|
const severityColor = item.severity === "critical" ? import_chalk4.default.red : item.severity === "major" ? import_chalk4.default.yellow : import_chalk4.default.blue;
|
|
1002
|
-
console.log(
|
|
1395
|
+
console.log(
|
|
1396
|
+
` ${severityColor("\u25CF")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1397
|
+
);
|
|
1003
1398
|
});
|
|
1004
1399
|
console.log();
|
|
1005
1400
|
}
|
|
@@ -1050,7 +1445,10 @@ async function consistencyAction(directory, options) {
|
|
|
1050
1445
|
let consistencyScore;
|
|
1051
1446
|
if (options.score) {
|
|
1052
1447
|
const issues = report.results?.flatMap((r) => r.issues) || [];
|
|
1053
|
-
consistencyScore = calculateConsistencyScore(
|
|
1448
|
+
consistencyScore = calculateConsistencyScore(
|
|
1449
|
+
issues,
|
|
1450
|
+
report.summary.filesAnalyzed
|
|
1451
|
+
);
|
|
1054
1452
|
}
|
|
1055
1453
|
const outputFormat = options.output || finalOptions.output?.format || "console";
|
|
1056
1454
|
const userOutputFile = options.outputFile || finalOptions.output?.file;
|
|
@@ -1068,7 +1466,11 @@ async function consistencyAction(directory, options) {
|
|
|
1068
1466
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
1069
1467
|
resolvedDir
|
|
1070
1468
|
);
|
|
1071
|
-
(0, import_core4.handleJSONOutput)(
|
|
1469
|
+
(0, import_core4.handleJSONOutput)(
|
|
1470
|
+
outputData,
|
|
1471
|
+
outputPath,
|
|
1472
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1473
|
+
);
|
|
1072
1474
|
} else if (outputFormat === "markdown") {
|
|
1073
1475
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1074
1476
|
const outputPath = (0, import_core4.resolveOutputPath)(
|
|
@@ -1080,15 +1482,23 @@ async function consistencyAction(directory, options) {
|
|
|
1080
1482
|
console.log(import_chalk5.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1081
1483
|
} else {
|
|
1082
1484
|
console.log(import_chalk5.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1083
|
-
console.log(
|
|
1485
|
+
console.log(
|
|
1486
|
+
`Files Analyzed: ${import_chalk5.default.cyan(report.summary.filesAnalyzed)}`
|
|
1487
|
+
);
|
|
1084
1488
|
console.log(`Total Issues: ${import_chalk5.default.yellow(report.summary.totalIssues)}`);
|
|
1085
1489
|
console.log(` Naming: ${import_chalk5.default.yellow(report.summary.namingIssues)}`);
|
|
1086
1490
|
console.log(` Patterns: ${import_chalk5.default.yellow(report.summary.patternIssues)}`);
|
|
1087
|
-
console.log(
|
|
1491
|
+
console.log(
|
|
1492
|
+
` Architecture: ${import_chalk5.default.yellow(report.summary.architectureIssues || 0)}`
|
|
1493
|
+
);
|
|
1088
1494
|
console.log(`Analysis Time: ${import_chalk5.default.gray(elapsedTime + "s")}
|
|
1089
1495
|
`);
|
|
1090
1496
|
if (report.summary.totalIssues === 0) {
|
|
1091
|
-
console.log(
|
|
1497
|
+
console.log(
|
|
1498
|
+
import_chalk5.default.green(
|
|
1499
|
+
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1500
|
+
)
|
|
1501
|
+
);
|
|
1092
1502
|
} else {
|
|
1093
1503
|
const namingResults = report.results.filter(
|
|
1094
1504
|
(r) => r.issues.some((i) => i.category === "naming")
|
|
@@ -1104,10 +1514,14 @@ async function consistencyAction(directory, options) {
|
|
|
1104
1514
|
for (const issue of result.issues) {
|
|
1105
1515
|
if (shown >= 5) break;
|
|
1106
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;
|
|
1107
|
-
console.log(
|
|
1517
|
+
console.log(
|
|
1518
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk5.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1519
|
+
);
|
|
1108
1520
|
console.log(` ${issue.message}`);
|
|
1109
1521
|
if (issue.suggestion) {
|
|
1110
|
-
console.log(
|
|
1522
|
+
console.log(
|
|
1523
|
+
` ${import_chalk5.default.dim("\u2192")} ${import_chalk5.default.italic(issue.suggestion)}`
|
|
1524
|
+
);
|
|
1111
1525
|
}
|
|
1112
1526
|
console.log();
|
|
1113
1527
|
shown++;
|
|
@@ -1127,10 +1541,14 @@ async function consistencyAction(directory, options) {
|
|
|
1127
1541
|
for (const issue of result.issues) {
|
|
1128
1542
|
if (shown >= 5) break;
|
|
1129
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;
|
|
1130
|
-
console.log(
|
|
1544
|
+
console.log(
|
|
1545
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk5.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1546
|
+
);
|
|
1131
1547
|
console.log(` ${issue.message}`);
|
|
1132
1548
|
if (issue.suggestion) {
|
|
1133
|
-
console.log(
|
|
1549
|
+
console.log(
|
|
1550
|
+
` ${import_chalk5.default.dim("\u2192")} ${import_chalk5.default.italic(issue.suggestion)}`
|
|
1551
|
+
);
|
|
1134
1552
|
}
|
|
1135
1553
|
console.log();
|
|
1136
1554
|
shown++;
|
|
@@ -1176,15 +1594,21 @@ async function visualizeAction(directory, options) {
|
|
|
1176
1594
|
const latestScan = findLatestScanReport(dirPath);
|
|
1177
1595
|
if (latestScan) {
|
|
1178
1596
|
reportPath = latestScan;
|
|
1179
|
-
console.log(
|
|
1597
|
+
console.log(
|
|
1598
|
+
import_chalk6.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1599
|
+
);
|
|
1180
1600
|
} else {
|
|
1181
1601
|
console.error(import_chalk6.default.red("\u274C No AI readiness report found"));
|
|
1182
|
-
console.log(
|
|
1602
|
+
console.log(
|
|
1603
|
+
import_chalk6.default.dim(
|
|
1604
|
+
`
|
|
1183
1605
|
Generate a report with:
|
|
1184
1606
|
aiready scan --output json
|
|
1185
1607
|
|
|
1186
1608
|
Or specify a custom report:
|
|
1187
|
-
aiready visualise --report <path-to-report.json>`
|
|
1609
|
+
aiready visualise --report <path-to-report.json>`
|
|
1610
|
+
)
|
|
1611
|
+
);
|
|
1188
1612
|
return;
|
|
1189
1613
|
}
|
|
1190
1614
|
}
|
|
@@ -1202,6 +1626,7 @@ Or specify a custom report:
|
|
|
1202
1626
|
};
|
|
1203
1627
|
}
|
|
1204
1628
|
} catch (e) {
|
|
1629
|
+
void e;
|
|
1205
1630
|
}
|
|
1206
1631
|
}
|
|
1207
1632
|
const envVisualizerConfig = JSON.stringify(graphConfig);
|
|
@@ -1222,11 +1647,18 @@ Or specify a custom report:
|
|
|
1222
1647
|
} else {
|
|
1223
1648
|
const nodemodulesLocations = [
|
|
1224
1649
|
(0, import_path6.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
|
|
1225
|
-
(0, import_path6.resolve)(
|
|
1650
|
+
(0, import_path6.resolve)(
|
|
1651
|
+
process.cwd(),
|
|
1652
|
+
"node_modules",
|
|
1653
|
+
"@aiready",
|
|
1654
|
+
"visualizer"
|
|
1655
|
+
)
|
|
1226
1656
|
];
|
|
1227
1657
|
let currentDir = dirPath;
|
|
1228
1658
|
while (currentDir !== "/" && currentDir !== ".") {
|
|
1229
|
-
nodemodulesLocations.push(
|
|
1659
|
+
nodemodulesLocations.push(
|
|
1660
|
+
(0, import_path6.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
|
|
1661
|
+
);
|
|
1230
1662
|
const parent = (0, import_path6.resolve)(currentDir, "..");
|
|
1231
1663
|
if (parent === currentDir) break;
|
|
1232
1664
|
currentDir = parent;
|
|
@@ -1243,7 +1675,8 @@ Or specify a custom report:
|
|
|
1243
1675
|
const vizPkgPath = require.resolve("@aiready/visualizer/package.json");
|
|
1244
1676
|
webDir = (0, import_path6.resolve)(vizPkgPath, "..");
|
|
1245
1677
|
visualizerAvailable = true;
|
|
1246
|
-
} catch (
|
|
1678
|
+
} catch (err) {
|
|
1679
|
+
void err;
|
|
1247
1680
|
}
|
|
1248
1681
|
}
|
|
1249
1682
|
}
|
|
@@ -1271,30 +1704,46 @@ Or specify a custom report:
|
|
|
1271
1704
|
AIREADY_REPORT_PATH: reportPath,
|
|
1272
1705
|
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1273
1706
|
};
|
|
1274
|
-
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
|
+
});
|
|
1275
1713
|
const onExit = () => {
|
|
1276
1714
|
try {
|
|
1277
1715
|
reportWatcher.close();
|
|
1278
|
-
} catch (
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
void err;
|
|
1279
1718
|
}
|
|
1280
1719
|
try {
|
|
1281
1720
|
vite.kill();
|
|
1282
|
-
} catch (
|
|
1721
|
+
} catch (err) {
|
|
1722
|
+
void err;
|
|
1283
1723
|
}
|
|
1284
1724
|
process.exit(0);
|
|
1285
1725
|
};
|
|
1286
1726
|
process.on("SIGINT", onExit);
|
|
1287
1727
|
process.on("SIGTERM", onExit);
|
|
1288
1728
|
devServerStarted = true;
|
|
1729
|
+
void devServerStarted;
|
|
1289
1730
|
return;
|
|
1290
1731
|
} else {
|
|
1291
|
-
console.log(
|
|
1292
|
-
|
|
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
|
+
);
|
|
1293
1740
|
useDevMode = false;
|
|
1294
1741
|
}
|
|
1295
1742
|
} catch (err) {
|
|
1296
1743
|
console.error("Failed to start dev server:", err);
|
|
1297
|
-
console.log(
|
|
1744
|
+
console.log(
|
|
1745
|
+
import_chalk6.default.cyan(" Falling back to static HTML generation...\n")
|
|
1746
|
+
);
|
|
1298
1747
|
useDevMode = false;
|
|
1299
1748
|
}
|
|
1300
1749
|
}
|
|
@@ -1316,20 +1765,25 @@ Or specify a custom report:
|
|
|
1316
1765
|
const urlPath = req.url || "/";
|
|
1317
1766
|
if (urlPath === "/" || urlPath === "/index.html") {
|
|
1318
1767
|
const content = await fsp.readFile(outPath, "utf8");
|
|
1319
|
-
res.writeHead(200, {
|
|
1768
|
+
res.writeHead(200, {
|
|
1769
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1770
|
+
});
|
|
1320
1771
|
res.end(content);
|
|
1321
1772
|
return;
|
|
1322
1773
|
}
|
|
1323
1774
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1324
1775
|
res.end("Not found");
|
|
1325
1776
|
} catch (e) {
|
|
1777
|
+
void e;
|
|
1326
1778
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1327
1779
|
res.end("Server error");
|
|
1328
1780
|
}
|
|
1329
1781
|
});
|
|
1330
1782
|
server.listen(port, () => {
|
|
1331
1783
|
const addr = `http://localhost:${port}/`;
|
|
1332
|
-
console.log(
|
|
1784
|
+
console.log(
|
|
1785
|
+
import_chalk6.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1786
|
+
);
|
|
1333
1787
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1334
1788
|
});
|
|
1335
1789
|
process.on("SIGINT", () => {
|
|
@@ -1395,19 +1849,23 @@ var getDirname = () => {
|
|
|
1395
1849
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
1396
1850
|
return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
1397
1851
|
};
|
|
1398
|
-
var packageJson = JSON.parse(
|
|
1852
|
+
var packageJson = JSON.parse(
|
|
1853
|
+
(0, import_fs5.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
|
|
1854
|
+
);
|
|
1399
1855
|
var program = new import_commander.Command();
|
|
1400
|
-
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
|
+
`
|
|
1401
1859
|
AI READINESS SCORING:
|
|
1402
1860
|
Get a 0-100 score indicating how AI-ready your codebase is.
|
|
1403
1861
|
Use --score flag with any analysis command for detailed breakdown.
|
|
1404
1862
|
|
|
1405
1863
|
EXAMPLES:
|
|
1406
|
-
$ aiready scan #
|
|
1864
|
+
$ aiready scan # Comprehensive analysis of current directory
|
|
1407
1865
|
$ aiready scan --score # Get AI Readiness Score (0-100)
|
|
1408
1866
|
$ aiready scan --tools patterns # Run only pattern detection
|
|
1409
|
-
$ aiready
|
|
1410
|
-
$ aiready scan --output json
|
|
1867
|
+
$ npx @aiready/cli scan # Industry standard way to run standard scan
|
|
1868
|
+
$ aiready scan --output json # Output raw JSON for piping
|
|
1411
1869
|
|
|
1412
1870
|
GETTING STARTED:
|
|
1413
1871
|
1. Run 'aiready scan' to analyze your codebase
|
|
@@ -1432,23 +1890,105 @@ CONFIGURATION:
|
|
|
1432
1890
|
VERSION: ${packageJson.version}
|
|
1433
1891
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
1434
1892
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
1435
|
-
LANDING: https://github.com/caopengau/aiready-landing`
|
|
1436
|
-
|
|
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) => {
|
|
1437
1917
|
await scanAction(directory, options);
|
|
1438
1918
|
});
|
|
1439
|
-
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) => {
|
|
1440
1932
|
await patternsAction(directory, options);
|
|
1441
1933
|
});
|
|
1442
|
-
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) => {
|
|
1443
1942
|
await contextAction(directory, options);
|
|
1444
1943
|
});
|
|
1445
|
-
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) => {
|
|
1446
1956
|
await consistencyAction(directory, options);
|
|
1447
1957
|
});
|
|
1448
|
-
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) => {
|
|
1449
1974
|
await visualizeAction(directory, options);
|
|
1450
1975
|
});
|
|
1451
|
-
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) => {
|
|
1452
1992
|
await visualizeAction(directory, options);
|
|
1453
1993
|
});
|
|
1454
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) => {
|