@aiready/cli 0.14.2 → 0.14.4
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-20260314-164626.json +2 -5
- package/.aiready/aiready-report-20260314-164741.json +2 -5
- package/.turbo/turbo-build.log +29 -28
- package/.turbo/turbo-lint.log +0 -32
- package/.turbo/turbo-test.log +35 -125
- package/aiready-report.json +30703 -0
- package/dist/cli.js +415 -378
- package/dist/cli.mjs +358 -320
- package/package.json +12 -12
- package/packages/core/src/.aiready/aiready-report-20260314-161145.json +4 -10
- package/packages/core/src/.aiready/aiready-report-20260314-161152.json +10 -28
- package/packages/pattern-detect/src/.aiready/aiready-report-20260314-161139.json +4 -10
- package/src/.aiready/aiready-report-20260312-103623.json +3 -9
- package/src/.aiready/aiready-report-20260312-110843.json +3 -9
- package/src/.aiready/aiready-report-20260312-110955.json +3 -9
- package/src/.aiready/aiready-report-20260314-203209.json +3 -9
- package/src/.aiready/aiready-report-20260314-203736.json +3 -9
- package/src/.aiready/aiready-report-20260314-203857.json +3 -9
- package/src/.aiready/aiready-report-20260314-204047.json +3 -9
- package/src/__tests__/cli.test.ts +1 -1
- package/src/__tests__/config-shape.test.ts +0 -1
- package/src/__tests__/unified.test.ts +1 -1
- package/src/cli.ts +2 -1
- package/src/commands/__tests__/consistency.test.ts +3 -0
- package/src/commands/__tests__/extra-commands.test.ts +29 -38
- package/src/commands/__tests__/init.test.ts +56 -0
- package/src/commands/__tests__/scan.test.ts +4 -2
- package/src/commands/__tests__/upload.test.ts +0 -1
- package/src/commands/__tests__/visualize.test.ts +3 -7
- package/src/commands/ai-signal-clarity.ts +1 -56
- package/src/commands/bug.ts +1 -2
- package/src/commands/deps-health.ts +1 -65
- package/src/commands/doc-drift.ts +1 -62
- package/src/commands/init.ts +58 -2
- package/src/commands/patterns.ts +3 -1
- package/src/commands/report-formatter.ts +128 -0
- package/src/commands/scan.ts +29 -120
- package/src/commands/shared/configured-tool-action.ts +35 -0
- package/src/commands/shared/standard-tool-actions.ts +126 -0
- package/src/commands/upload.ts +15 -13
- package/src/commands/visualize.ts +11 -4
- package/src/index.ts +18 -3
- package/src/utils/helpers.ts +86 -37
- package/vitest.config.ts +5 -12
package/dist/cli.js
CHANGED
|
@@ -30,10 +30,10 @@ var import_path9 = require("path");
|
|
|
30
30
|
var import_url = require("url");
|
|
31
31
|
|
|
32
32
|
// src/commands/scan.ts
|
|
33
|
-
var
|
|
33
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
34
34
|
var import_fs3 = require("fs");
|
|
35
35
|
var import_path3 = require("path");
|
|
36
|
-
var
|
|
36
|
+
var import_core6 = require("@aiready/core");
|
|
37
37
|
|
|
38
38
|
// src/index.ts
|
|
39
39
|
var import_core = require("@aiready/core");
|
|
@@ -294,34 +294,13 @@ async function scoreUnified(results, options) {
|
|
|
294
294
|
var import_path = require("path");
|
|
295
295
|
var import_fs = require("fs");
|
|
296
296
|
var import_chalk = __toESM(require("chalk"));
|
|
297
|
+
var import_core2 = require("@aiready/core");
|
|
298
|
+
var import_core3 = require("@aiready/core");
|
|
297
299
|
function getReportTimestamp() {
|
|
298
300
|
const now = /* @__PURE__ */ new Date();
|
|
299
301
|
const pad = (n) => String(n).padStart(2, "0");
|
|
300
302
|
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
301
303
|
}
|
|
302
|
-
function findLatestScanReport(dirPath) {
|
|
303
|
-
const aireadyDir = (0, import_path.resolve)(dirPath, ".aiready");
|
|
304
|
-
if (!(0, import_fs.existsSync)(aireadyDir)) {
|
|
305
|
-
return null;
|
|
306
|
-
}
|
|
307
|
-
let files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
308
|
-
(f) => f.startsWith("aiready-report-") && f.endsWith(".json")
|
|
309
|
-
);
|
|
310
|
-
if (files.length === 0) {
|
|
311
|
-
files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
312
|
-
(f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
if (files.length === 0) {
|
|
316
|
-
return null;
|
|
317
|
-
}
|
|
318
|
-
const sortedFiles = files.map((f) => ({
|
|
319
|
-
name: f,
|
|
320
|
-
path: (0, import_path.resolve)(aireadyDir, f),
|
|
321
|
-
mtime: (0, import_fs.statSync)((0, import_path.resolve)(aireadyDir, f)).mtime
|
|
322
|
-
})).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
323
|
-
return sortedFiles[0].path;
|
|
324
|
-
}
|
|
325
304
|
async function warnIfGraphCapExceeded(report, dirPath) {
|
|
326
305
|
try {
|
|
327
306
|
const { loadConfig: loadConfig4 } = await import("@aiready/core");
|
|
@@ -408,42 +387,129 @@ function generateMarkdownReport(report, elapsedTime) {
|
|
|
408
387
|
return markdown;
|
|
409
388
|
}
|
|
410
389
|
|
|
390
|
+
// src/commands/report-formatter.ts
|
|
391
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
392
|
+
var import_core4 = require("@aiready/core");
|
|
393
|
+
function printScanSummary(results, startTime) {
|
|
394
|
+
console.log(import_chalk2.default.cyan("\n=== AIReady Run Summary ==="));
|
|
395
|
+
console.log(
|
|
396
|
+
` Total issues (all tools): ${import_chalk2.default.bold(String(results.summary.totalIssues || 0))}`
|
|
397
|
+
);
|
|
398
|
+
console.log(
|
|
399
|
+
` Execution time: ${import_chalk2.default.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
function printBusinessImpact(roi, unifiedBudget) {
|
|
403
|
+
console.log(import_chalk2.default.bold("\n\u{1F4B0} Business Impact Analysis (Monthly)"));
|
|
404
|
+
console.log(
|
|
405
|
+
` Potential Savings: ${import_chalk2.default.green(import_chalk2.default.bold("$" + roi.monthlySavings.toLocaleString()))}`
|
|
406
|
+
);
|
|
407
|
+
console.log(
|
|
408
|
+
` Productivity Gain: ${import_chalk2.default.cyan(import_chalk2.default.bold(roi.productivityGainHours + "h"))} (est. dev time)`
|
|
409
|
+
);
|
|
410
|
+
console.log(
|
|
411
|
+
` Context Efficiency: ${import_chalk2.default.yellow((unifiedBudget.efficiencyRatio * 100).toFixed(0) + "%")}`
|
|
412
|
+
);
|
|
413
|
+
console.log(
|
|
414
|
+
` Annual Value: ${import_chalk2.default.bold("$" + roi.annualValue.toLocaleString())} (ROI Prediction)`
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
function printScoring(scoringResult, scoringProfile) {
|
|
418
|
+
console.log(import_chalk2.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
419
|
+
console.log(` ${(0, import_core4.formatScore)(scoringResult)}`);
|
|
420
|
+
console.log(import_chalk2.default.dim(` (Scoring Profile: ${scoringProfile})`));
|
|
421
|
+
if (scoringResult.breakdown) {
|
|
422
|
+
console.log(import_chalk2.default.bold("\nTool breakdown:"));
|
|
423
|
+
scoringResult.breakdown.forEach((tool) => {
|
|
424
|
+
const rating = (0, import_core4.getRating)(tool.score);
|
|
425
|
+
const emoji = (0, import_core4.getRatingDisplay)(rating).emoji;
|
|
426
|
+
console.log(
|
|
427
|
+
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
|
|
428
|
+
);
|
|
429
|
+
});
|
|
430
|
+
const allRecs = scoringResult.breakdown.flatMap(
|
|
431
|
+
(t) => (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
|
|
432
|
+
).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
|
|
433
|
+
if (allRecs.length > 0) {
|
|
434
|
+
console.log(import_chalk2.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
|
|
435
|
+
allRecs.forEach((rec, i) => {
|
|
436
|
+
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
437
|
+
console.log(` ${i + 1}. ${priorityIcon} ${import_chalk2.default.bold(rec.action)}`);
|
|
438
|
+
console.log(
|
|
439
|
+
` Impact: ${import_chalk2.default.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
|
|
440
|
+
);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function mapToUnifiedReport(res, scoring) {
|
|
446
|
+
const allResults = [];
|
|
447
|
+
const totalFilesSet = /* @__PURE__ */ new Set();
|
|
448
|
+
let criticalCount = 0;
|
|
449
|
+
let majorCount = 0;
|
|
450
|
+
res.summary.toolsRun.forEach((toolId) => {
|
|
451
|
+
const spokeRes = res[toolId];
|
|
452
|
+
if (!spokeRes || !spokeRes.results) return;
|
|
453
|
+
spokeRes.results.forEach((r) => {
|
|
454
|
+
totalFilesSet.add(r.fileName);
|
|
455
|
+
allResults.push(r);
|
|
456
|
+
r.issues?.forEach((i) => {
|
|
457
|
+
if (i.severity === import_core4.Severity.Critical || i.severity === "critical")
|
|
458
|
+
criticalCount++;
|
|
459
|
+
if (i.severity === import_core4.Severity.Major || i.severity === "major")
|
|
460
|
+
majorCount++;
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
return {
|
|
465
|
+
...res,
|
|
466
|
+
results: allResults,
|
|
467
|
+
summary: {
|
|
468
|
+
...res.summary,
|
|
469
|
+
totalFiles: totalFilesSet.size,
|
|
470
|
+
criticalIssues: criticalCount,
|
|
471
|
+
majorIssues: majorCount
|
|
472
|
+
},
|
|
473
|
+
scoring
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
411
477
|
// src/commands/upload.ts
|
|
412
478
|
var import_fs2 = __toESM(require("fs"));
|
|
413
479
|
var import_path2 = require("path");
|
|
414
|
-
var
|
|
415
|
-
var
|
|
480
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
481
|
+
var import_core5 = require("@aiready/core");
|
|
416
482
|
async function uploadAction(file, options) {
|
|
417
483
|
const startTime = Date.now();
|
|
418
484
|
const filePath = (0, import_path2.resolve)(process.cwd(), file);
|
|
419
485
|
const serverUrl = options.server || process.env.AIREADY_SERVER || "https://dev.platform.getaiready.dev";
|
|
420
486
|
const apiKey = options.apiKey || process.env.AIREADY_API_KEY;
|
|
421
487
|
if (!apiKey) {
|
|
422
|
-
console.error(
|
|
488
|
+
console.error(import_chalk3.default.red("\u274C API Key is required for upload."));
|
|
423
489
|
console.log(
|
|
424
|
-
|
|
490
|
+
import_chalk3.default.dim(
|
|
425
491
|
" Set AIREADY_API_KEY environment variable or use --api-key flag."
|
|
426
492
|
)
|
|
427
493
|
);
|
|
428
494
|
console.log(
|
|
429
|
-
|
|
495
|
+
import_chalk3.default.dim(
|
|
430
496
|
" Get an API key from https://platform.getaiready.dev/dashboard"
|
|
431
497
|
)
|
|
432
498
|
);
|
|
433
499
|
process.exit(1);
|
|
434
500
|
}
|
|
435
501
|
if (!import_fs2.default.existsSync(filePath)) {
|
|
436
|
-
console.error(
|
|
502
|
+
console.error(import_chalk3.default.red(`\u274C File not found: ${filePath}`));
|
|
437
503
|
process.exit(1);
|
|
438
504
|
}
|
|
439
505
|
try {
|
|
440
|
-
console.log(
|
|
441
|
-
console.log(
|
|
506
|
+
console.log(import_chalk3.default.blue(`\u{1F680} Uploading report to ${serverUrl}...`));
|
|
507
|
+
console.log(import_chalk3.default.dim(` Reading report from ${filePath}...`));
|
|
442
508
|
const reportContent = import_fs2.default.readFileSync(filePath, "utf-8");
|
|
443
509
|
const reportData = JSON.parse(reportContent);
|
|
444
|
-
console.log(
|
|
510
|
+
console.log(import_chalk3.default.dim(` Successfully parsed report JSON.`));
|
|
445
511
|
const repoId = options.repoId || reportData.repository?.repoId;
|
|
446
|
-
const
|
|
512
|
+
const response = await fetch(`${serverUrl}/api/analysis/upload`, {
|
|
447
513
|
method: "POST",
|
|
448
514
|
headers: {
|
|
449
515
|
"Content-Type": "application/json",
|
|
@@ -455,49 +521,51 @@ async function uploadAction(file, options) {
|
|
|
455
521
|
// Might be null, server will handle mapping
|
|
456
522
|
})
|
|
457
523
|
});
|
|
458
|
-
const contentType =
|
|
459
|
-
let
|
|
524
|
+
const contentType = response.headers.get("content-type");
|
|
525
|
+
let uploadResult = {};
|
|
460
526
|
if (contentType?.includes("application/json")) {
|
|
461
|
-
|
|
527
|
+
uploadResult = await response.json();
|
|
462
528
|
} else {
|
|
463
|
-
const text = await
|
|
464
|
-
|
|
529
|
+
const text = await response.text();
|
|
530
|
+
uploadResult = { error: text || response.statusText };
|
|
465
531
|
}
|
|
466
|
-
if (!
|
|
532
|
+
if (!response.ok) {
|
|
467
533
|
console.error(
|
|
468
|
-
|
|
534
|
+
import_chalk3.default.red(
|
|
535
|
+
`\u274C Upload failed: ${uploadResult.error || response.statusText}`
|
|
536
|
+
)
|
|
469
537
|
);
|
|
470
538
|
if (contentType?.includes("text/html")) {
|
|
471
539
|
console.log(
|
|
472
|
-
|
|
540
|
+
import_chalk3.default.yellow(
|
|
473
541
|
" Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
|
|
474
542
|
)
|
|
475
543
|
);
|
|
476
|
-
if (
|
|
544
|
+
if (uploadResult.error?.includes("Redirecting")) {
|
|
477
545
|
console.log(
|
|
478
|
-
|
|
546
|
+
import_chalk3.default.dim(
|
|
479
547
|
" Detected redirect. Check if the API endpoint requires authentication or has changed."
|
|
480
548
|
)
|
|
481
549
|
);
|
|
482
550
|
}
|
|
483
551
|
}
|
|
484
|
-
if (
|
|
552
|
+
if (response.status === 401) {
|
|
485
553
|
console.log(
|
|
486
|
-
|
|
554
|
+
import_chalk3.default.dim(" Hint: Your API key may be invalid or expired.")
|
|
487
555
|
);
|
|
488
556
|
}
|
|
489
557
|
process.exit(1);
|
|
490
558
|
}
|
|
491
559
|
const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
492
|
-
console.log(
|
|
560
|
+
console.log(import_chalk3.default.green(`
|
|
493
561
|
\u2705 Upload successful! (${duration}s)`));
|
|
494
|
-
console.log(
|
|
495
|
-
if (
|
|
496
|
-
console.log(
|
|
497
|
-
console.log(
|
|
562
|
+
console.log(import_chalk3.default.cyan(` View results: ${serverUrl}/dashboard`));
|
|
563
|
+
if (uploadResult.analysis) {
|
|
564
|
+
console.log(import_chalk3.default.dim(` Analysis ID: ${uploadResult.analysis.id}`));
|
|
565
|
+
console.log(import_chalk3.default.dim(` Score: ${uploadResult.analysis.aiScore}/100`));
|
|
498
566
|
}
|
|
499
567
|
} catch (error) {
|
|
500
|
-
(0,
|
|
568
|
+
(0, import_core5.handleCLIError)(error, "Upload");
|
|
501
569
|
}
|
|
502
570
|
}
|
|
503
571
|
var uploadHelpText = `
|
|
@@ -513,10 +581,10 @@ ENVIRONMENT VARIABLES:
|
|
|
513
581
|
|
|
514
582
|
// src/commands/scan.ts
|
|
515
583
|
async function scanAction(directory, options) {
|
|
516
|
-
console.log(
|
|
584
|
+
console.log(import_chalk4.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
517
585
|
const startTime = Date.now();
|
|
518
586
|
const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory || ".");
|
|
519
|
-
const repoMetadata = (0,
|
|
587
|
+
const repoMetadata = (0, import_core6.getRepoMetadata)(resolvedDir);
|
|
520
588
|
try {
|
|
521
589
|
const defaults = {
|
|
522
590
|
tools: [
|
|
@@ -542,48 +610,48 @@ async function scanAction(directory, options) {
|
|
|
542
610
|
switch (options.profile.toLowerCase()) {
|
|
543
611
|
case "agentic":
|
|
544
612
|
profileTools = [
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
613
|
+
import_core6.ToolName.AiSignalClarity,
|
|
614
|
+
import_core6.ToolName.AgentGrounding,
|
|
615
|
+
import_core6.ToolName.TestabilityIndex
|
|
548
616
|
];
|
|
549
617
|
break;
|
|
550
618
|
case "cost":
|
|
551
|
-
profileTools = [
|
|
619
|
+
profileTools = [import_core6.ToolName.PatternDetect, import_core6.ToolName.ContextAnalyzer];
|
|
552
620
|
break;
|
|
553
621
|
case "logic":
|
|
554
622
|
profileTools = [
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
623
|
+
import_core6.ToolName.TestabilityIndex,
|
|
624
|
+
import_core6.ToolName.NamingConsistency,
|
|
625
|
+
import_core6.ToolName.ContextAnalyzer,
|
|
626
|
+
import_core6.ToolName.PatternDetect,
|
|
627
|
+
import_core6.ToolName.ChangeAmplification
|
|
560
628
|
];
|
|
561
629
|
break;
|
|
562
630
|
case "ui":
|
|
563
631
|
profileTools = [
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
632
|
+
import_core6.ToolName.NamingConsistency,
|
|
633
|
+
import_core6.ToolName.ContextAnalyzer,
|
|
634
|
+
import_core6.ToolName.PatternDetect,
|
|
635
|
+
import_core6.ToolName.DocDrift,
|
|
636
|
+
import_core6.ToolName.AiSignalClarity
|
|
569
637
|
];
|
|
570
638
|
break;
|
|
571
639
|
case "security":
|
|
572
640
|
profileTools = [
|
|
573
|
-
|
|
574
|
-
|
|
641
|
+
import_core6.ToolName.NamingConsistency,
|
|
642
|
+
import_core6.ToolName.TestabilityIndex
|
|
575
643
|
];
|
|
576
644
|
break;
|
|
577
645
|
case "onboarding":
|
|
578
646
|
profileTools = [
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
647
|
+
import_core6.ToolName.ContextAnalyzer,
|
|
648
|
+
import_core6.ToolName.NamingConsistency,
|
|
649
|
+
import_core6.ToolName.AgentGrounding
|
|
582
650
|
];
|
|
583
651
|
break;
|
|
584
652
|
default:
|
|
585
653
|
console.log(
|
|
586
|
-
|
|
654
|
+
import_chalk4.default.yellow(
|
|
587
655
|
`
|
|
588
656
|
\u26A0\uFE0F Unknown profile '${options.profile}'. Using defaults.`
|
|
589
657
|
)
|
|
@@ -595,27 +663,27 @@ async function scanAction(directory, options) {
|
|
|
595
663
|
exclude: options.exclude?.split(",")
|
|
596
664
|
};
|
|
597
665
|
if (profileTools) cliOverrides.tools = profileTools;
|
|
598
|
-
const baseOptions = await (0,
|
|
666
|
+
const baseOptions = await (0, import_core6.loadMergedConfig)(
|
|
599
667
|
resolvedDir,
|
|
600
668
|
defaults,
|
|
601
669
|
cliOverrides
|
|
602
670
|
);
|
|
603
|
-
|
|
604
|
-
if (baseOptions.tools.includes(
|
|
671
|
+
const finalOptions = { ...baseOptions };
|
|
672
|
+
if (baseOptions.tools.includes(import_core6.ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
|
|
605
673
|
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
606
674
|
const patternSmartDefaults = await getSmartDefaults(
|
|
607
675
|
resolvedDir,
|
|
608
|
-
finalOptions.toolConfigs?.[
|
|
676
|
+
finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] || {}
|
|
609
677
|
);
|
|
610
678
|
if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
|
|
611
|
-
finalOptions.toolConfigs[
|
|
679
|
+
finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
|
|
612
680
|
...patternSmartDefaults,
|
|
613
|
-
...finalOptions.toolConfigs[
|
|
681
|
+
...finalOptions.toolConfigs[import_core6.ToolName.PatternDetect]
|
|
614
682
|
};
|
|
615
683
|
}
|
|
616
|
-
console.log(
|
|
684
|
+
console.log(import_chalk4.default.cyan("\n=== AIReady Run Preview ==="));
|
|
617
685
|
console.log(
|
|
618
|
-
|
|
686
|
+
import_chalk4.default.white("Tools to run:"),
|
|
619
687
|
(finalOptions.tools || []).join(", ")
|
|
620
688
|
);
|
|
621
689
|
const progressCallback = (event) => {
|
|
@@ -624,16 +692,16 @@ async function scanAction(directory, options) {
|
|
|
624
692
|
return;
|
|
625
693
|
}
|
|
626
694
|
process.stdout.write("\r\x1B[K");
|
|
627
|
-
console.log(
|
|
695
|
+
console.log(import_chalk4.default.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
628
696
|
const res = event.data;
|
|
629
697
|
if (res && res.summary) {
|
|
630
698
|
if (res.summary.totalIssues !== void 0)
|
|
631
|
-
console.log(` Issues found: ${
|
|
699
|
+
console.log(` Issues found: ${import_chalk4.default.bold(res.summary.totalIssues)}`);
|
|
632
700
|
if (res.summary.score !== void 0)
|
|
633
|
-
console.log(` Tool Score: ${
|
|
701
|
+
console.log(` Tool Score: ${import_chalk4.default.bold(res.summary.score)}/100`);
|
|
634
702
|
if (res.summary.totalFiles !== void 0)
|
|
635
703
|
console.log(
|
|
636
|
-
` Files analyzed: ${
|
|
704
|
+
` Files analyzed: ${import_chalk4.default.bold(res.summary.totalFiles)}`
|
|
637
705
|
);
|
|
638
706
|
}
|
|
639
707
|
};
|
|
@@ -645,13 +713,7 @@ async function scanAction(directory, options) {
|
|
|
645
713
|
},
|
|
646
714
|
suppressToolConfig: true
|
|
647
715
|
});
|
|
648
|
-
|
|
649
|
-
console.log(
|
|
650
|
-
` Total issues (all tools): ${import_chalk3.default.bold(String(results.summary.totalIssues || 0))}`
|
|
651
|
-
);
|
|
652
|
-
console.log(
|
|
653
|
-
` Execution time: ${import_chalk3.default.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
|
|
654
|
-
);
|
|
716
|
+
printScanSummary(results, startTime);
|
|
655
717
|
let scoringResult;
|
|
656
718
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
657
719
|
scoringResult = await scoreUnified(results, {
|
|
@@ -661,9 +723,7 @@ async function scanAction(directory, options) {
|
|
|
661
723
|
profile: scoringProfile
|
|
662
724
|
}
|
|
663
725
|
});
|
|
664
|
-
|
|
665
|
-
console.log(` ${(0, import_core3.formatScore)(scoringResult)}`);
|
|
666
|
-
console.log(import_chalk3.default.dim(` (Scoring Profile: ${scoringProfile})`));
|
|
726
|
+
printScoring(scoringResult, scoringProfile);
|
|
667
727
|
if (options.compareTo) {
|
|
668
728
|
try {
|
|
669
729
|
const prevReport = JSON.parse(
|
|
@@ -675,19 +735,19 @@ async function scanAction(directory, options) {
|
|
|
675
735
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
676
736
|
if (diff > 0)
|
|
677
737
|
console.log(
|
|
678
|
-
|
|
738
|
+
import_chalk4.default.green(
|
|
679
739
|
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
680
740
|
)
|
|
681
741
|
);
|
|
682
742
|
else if (diff < 0)
|
|
683
743
|
console.log(
|
|
684
|
-
|
|
744
|
+
import_chalk4.default.red(
|
|
685
745
|
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
686
746
|
)
|
|
687
747
|
);
|
|
688
748
|
else
|
|
689
749
|
console.log(
|
|
690
|
-
|
|
750
|
+
import_chalk4.default.blue(
|
|
691
751
|
` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
|
|
692
752
|
)
|
|
693
753
|
);
|
|
@@ -711,7 +771,7 @@ async function scanAction(directory, options) {
|
|
|
711
771
|
0
|
|
712
772
|
);
|
|
713
773
|
if (totalContext > 0) {
|
|
714
|
-
const unifiedBudget = (0,
|
|
774
|
+
const unifiedBudget = (0, import_core6.calculateTokenBudget)({
|
|
715
775
|
totalContextTokens: totalContext,
|
|
716
776
|
wastedTokens: {
|
|
717
777
|
duplication: totalWastedDuplication,
|
|
@@ -736,19 +796,7 @@ async function scanAction(directory, options) {
|
|
|
736
796
|
issues: allIssues,
|
|
737
797
|
modelId
|
|
738
798
|
});
|
|
739
|
-
|
|
740
|
-
console.log(
|
|
741
|
-
` Potential Savings: ${import_chalk3.default.green(import_chalk3.default.bold("$" + roi.monthlySavings.toLocaleString()))}`
|
|
742
|
-
);
|
|
743
|
-
console.log(
|
|
744
|
-
` Productivity Gain: ${import_chalk3.default.cyan(import_chalk3.default.bold(roi.productivityGainHours + "h"))} (est. dev time)`
|
|
745
|
-
);
|
|
746
|
-
console.log(
|
|
747
|
-
` Context Efficiency: ${import_chalk3.default.yellow((unifiedBudget.efficiencyRatio * 100).toFixed(0) + "%")}`
|
|
748
|
-
);
|
|
749
|
-
console.log(
|
|
750
|
-
` Annual Value: ${import_chalk3.default.bold("$" + roi.annualValue.toLocaleString())} (ROI Prediction)`
|
|
751
|
-
);
|
|
799
|
+
printBusinessImpact(roi, unifiedBudget);
|
|
752
800
|
results.summary.businessImpact = {
|
|
753
801
|
estimatedMonthlyWaste: roi.monthlySavings,
|
|
754
802
|
potentialSavings: roi.monthlySavings,
|
|
@@ -757,90 +805,36 @@ async function scanAction(directory, options) {
|
|
|
757
805
|
scoringResult.tokenBudget = unifiedBudget;
|
|
758
806
|
scoringResult.businessROI = roi;
|
|
759
807
|
}
|
|
760
|
-
if (scoringResult.breakdown) {
|
|
761
|
-
console.log(import_chalk3.default.bold("\nTool breakdown:"));
|
|
762
|
-
scoringResult.breakdown.forEach((tool) => {
|
|
763
|
-
const rating = (0, import_core3.getRating)(tool.score);
|
|
764
|
-
const emoji = (0, import_core3.getRatingDisplay)(rating).emoji;
|
|
765
|
-
console.log(
|
|
766
|
-
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
|
|
767
|
-
);
|
|
768
|
-
});
|
|
769
|
-
const allRecs = scoringResult.breakdown.flatMap(
|
|
770
|
-
(t) => (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
|
|
771
|
-
).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
|
|
772
|
-
if (allRecs.length > 0) {
|
|
773
|
-
console.log(import_chalk3.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
|
|
774
|
-
allRecs.forEach((rec, i) => {
|
|
775
|
-
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
776
|
-
console.log(
|
|
777
|
-
` ${i + 1}. ${priorityIcon} ${import_chalk3.default.bold(rec.action)}`
|
|
778
|
-
);
|
|
779
|
-
console.log(
|
|
780
|
-
` Impact: ${import_chalk3.default.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
|
|
781
|
-
);
|
|
782
|
-
});
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
808
|
}
|
|
786
809
|
console.log(
|
|
787
|
-
|
|
810
|
+
import_chalk4.default.dim(
|
|
788
811
|
"\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
789
812
|
)
|
|
790
813
|
);
|
|
791
|
-
console.log(
|
|
792
|
-
console.log(
|
|
814
|
+
console.log(import_chalk4.default.dim("\u{1F4AC} Found a bug or have a metric idea?"));
|
|
815
|
+
console.log(import_chalk4.default.dim("\u{1F449} Copy/paste this to your AI agent:"));
|
|
793
816
|
console.log(
|
|
794
|
-
|
|
817
|
+
import_chalk4.default.cyan(
|
|
795
818
|
` "Any feedback for the tools? Please use 'aiready bug' to report \u2764\uFE0F"`
|
|
796
819
|
)
|
|
797
820
|
);
|
|
798
821
|
console.log(
|
|
799
|
-
|
|
822
|
+
import_chalk4.default.dim(
|
|
800
823
|
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
801
824
|
)
|
|
802
825
|
);
|
|
803
|
-
const mapToUnifiedReport = (res, scoring) => {
|
|
804
|
-
const allResults = [];
|
|
805
|
-
const totalFilesSet = /* @__PURE__ */ new Set();
|
|
806
|
-
let criticalCount = 0;
|
|
807
|
-
let majorCount = 0;
|
|
808
|
-
res.summary.toolsRun.forEach((toolId) => {
|
|
809
|
-
const spokeRes = res[toolId];
|
|
810
|
-
if (!spokeRes || !spokeRes.results) return;
|
|
811
|
-
spokeRes.results.forEach((r) => {
|
|
812
|
-
totalFilesSet.add(r.fileName);
|
|
813
|
-
allResults.push(r);
|
|
814
|
-
r.issues?.forEach((i) => {
|
|
815
|
-
if (i.severity === import_core3.Severity.Critical) criticalCount++;
|
|
816
|
-
if (i.severity === import_core3.Severity.Major) majorCount++;
|
|
817
|
-
});
|
|
818
|
-
});
|
|
819
|
-
});
|
|
820
|
-
return {
|
|
821
|
-
...res,
|
|
822
|
-
results: allResults,
|
|
823
|
-
summary: {
|
|
824
|
-
...res.summary,
|
|
825
|
-
totalFiles: totalFilesSet.size,
|
|
826
|
-
criticalIssues: criticalCount,
|
|
827
|
-
majorIssues: majorCount
|
|
828
|
-
},
|
|
829
|
-
scoring
|
|
830
|
-
};
|
|
831
|
-
};
|
|
832
826
|
const outputData = {
|
|
833
827
|
...mapToUnifiedReport(results, scoringResult),
|
|
834
828
|
repository: repoMetadata
|
|
835
829
|
};
|
|
836
830
|
const outputFormat = options.output || finalOptions.output?.format || "console";
|
|
837
|
-
const outputPath = (0,
|
|
831
|
+
const outputPath = (0, import_core6.resolveOutputPath)(
|
|
838
832
|
options.outputFile || finalOptions.output?.file,
|
|
839
833
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
840
834
|
resolvedDir
|
|
841
835
|
);
|
|
842
836
|
if (outputFormat === "json") {
|
|
843
|
-
(0,
|
|
837
|
+
(0, import_core6.handleJSONOutput)(
|
|
844
838
|
outputData,
|
|
845
839
|
outputPath,
|
|
846
840
|
`\u2705 Report saved to ${outputPath}`
|
|
@@ -848,7 +842,7 @@ async function scanAction(directory, options) {
|
|
|
848
842
|
} else {
|
|
849
843
|
try {
|
|
850
844
|
(0, import_fs3.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
|
|
851
|
-
console.log(
|
|
845
|
+
console.log(import_chalk4.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
|
|
852
846
|
} catch (err) {
|
|
853
847
|
void err;
|
|
854
848
|
}
|
|
@@ -860,21 +854,21 @@ async function scanAction(directory, options) {
|
|
|
860
854
|
});
|
|
861
855
|
}
|
|
862
856
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
863
|
-
|
|
864
|
-
if (isCI && scoringResult) {
|
|
857
|
+
if (scoringResult) {
|
|
865
858
|
const threshold = options.threshold ? parseInt(options.threshold) : void 0;
|
|
866
859
|
const failOnLevel = options.failOn || "critical";
|
|
860
|
+
const isCI = options.ci || process.env.CI === "true";
|
|
867
861
|
let shouldFail = false;
|
|
868
862
|
let failReason = "";
|
|
869
863
|
const report = mapToUnifiedReport(results, scoringResult);
|
|
870
|
-
if (report.results && report.results.length > 0) {
|
|
864
|
+
if (isCI && report.results && report.results.length > 0) {
|
|
871
865
|
console.log(
|
|
872
|
-
|
|
866
|
+
import_chalk4.default.cyan(
|
|
873
867
|
`
|
|
874
868
|
\u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
|
|
875
869
|
)
|
|
876
870
|
);
|
|
877
|
-
(0,
|
|
871
|
+
(0, import_core6.emitIssuesAsAnnotations)(report.results);
|
|
878
872
|
}
|
|
879
873
|
if (threshold && scoringResult.overall < threshold) {
|
|
880
874
|
shouldFail = true;
|
|
@@ -890,15 +884,15 @@ async function scanAction(directory, options) {
|
|
|
890
884
|
}
|
|
891
885
|
}
|
|
892
886
|
if (shouldFail) {
|
|
893
|
-
console.log(
|
|
894
|
-
\u{1F6AB}
|
|
887
|
+
console.log(import_chalk4.default.red(`
|
|
888
|
+
\u{1F6AB} SCAN FAILED: ${failReason}`));
|
|
895
889
|
process.exit(1);
|
|
896
890
|
} else {
|
|
897
|
-
console.log(
|
|
891
|
+
console.log(import_chalk4.default.green("\n\u2705 SCAN PASSED"));
|
|
898
892
|
}
|
|
899
893
|
}
|
|
900
894
|
} catch (error) {
|
|
901
|
-
(0,
|
|
895
|
+
(0, import_core6.handleCLIError)(error, "Analysis");
|
|
902
896
|
}
|
|
903
897
|
}
|
|
904
898
|
var scanHelpText = `...`;
|
|
@@ -906,19 +900,19 @@ var scanHelpText = `...`;
|
|
|
906
900
|
// src/commands/init.ts
|
|
907
901
|
var import_fs4 = require("fs");
|
|
908
902
|
var import_path4 = require("path");
|
|
909
|
-
var
|
|
910
|
-
var
|
|
903
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
904
|
+
var import_core7 = require("@aiready/core");
|
|
911
905
|
async function initAction(options) {
|
|
912
906
|
const fileExt = options.format === "js" ? "js" : "json";
|
|
913
907
|
const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
|
|
914
908
|
const filePath = (0, import_path4.join)(process.cwd(), fileName);
|
|
915
909
|
if ((0, import_fs4.existsSync)(filePath) && !options.force) {
|
|
916
910
|
console.error(
|
|
917
|
-
|
|
911
|
+
import_chalk5.default.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
|
|
918
912
|
);
|
|
919
913
|
process.exit(1);
|
|
920
914
|
}
|
|
921
|
-
const
|
|
915
|
+
const baseConfig = {
|
|
922
916
|
scan: {
|
|
923
917
|
include: [
|
|
924
918
|
"src/**/*.ts",
|
|
@@ -934,42 +928,84 @@ async function initAction(options) {
|
|
|
934
928
|
"**/*.spec.ts"
|
|
935
929
|
],
|
|
936
930
|
tools: [
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
931
|
+
import_core7.ToolName.PatternDetect,
|
|
932
|
+
import_core7.ToolName.ContextAnalyzer,
|
|
933
|
+
import_core7.ToolName.NamingConsistency,
|
|
934
|
+
import_core7.ToolName.AiSignalClarity,
|
|
935
|
+
import_core7.ToolName.AgentGrounding,
|
|
936
|
+
import_core7.ToolName.TestabilityIndex,
|
|
937
|
+
import_core7.ToolName.DocDrift,
|
|
938
|
+
import_core7.ToolName.DependencyHealth,
|
|
939
|
+
import_core7.ToolName.ChangeAmplification
|
|
946
940
|
]
|
|
947
941
|
},
|
|
948
942
|
tools: {
|
|
949
|
-
[
|
|
943
|
+
[import_core7.ToolName.PatternDetect]: {
|
|
950
944
|
minSimilarity: 0.8,
|
|
951
|
-
minLines: 5
|
|
945
|
+
minLines: 5,
|
|
946
|
+
...options.full ? {
|
|
947
|
+
batchSize: 50,
|
|
948
|
+
approx: true,
|
|
949
|
+
minSharedTokens: 10,
|
|
950
|
+
maxCandidatesPerBlock: 100
|
|
951
|
+
} : {}
|
|
952
952
|
},
|
|
953
|
-
[
|
|
953
|
+
[import_core7.ToolName.ContextAnalyzer]: {
|
|
954
954
|
maxContextBudget: 128e3,
|
|
955
|
-
minCohesion: 0.6
|
|
955
|
+
minCohesion: 0.6,
|
|
956
|
+
...options.full ? {
|
|
957
|
+
maxDepth: 7,
|
|
958
|
+
maxFragmentation: 0.4,
|
|
959
|
+
focus: "all",
|
|
960
|
+
includeNodeModules: false
|
|
961
|
+
} : {}
|
|
956
962
|
},
|
|
957
|
-
[
|
|
958
|
-
shortWords: ["id", "db", "ui", "ai"]
|
|
963
|
+
[import_core7.ToolName.NamingConsistency]: {
|
|
964
|
+
shortWords: ["id", "db", "ui", "ai"],
|
|
965
|
+
...options.full ? { acceptedAbbreviations: [], disableChecks: [] } : {}
|
|
959
966
|
},
|
|
960
|
-
[
|
|
967
|
+
[import_core7.ToolName.AiSignalClarity]: {
|
|
961
968
|
checkMagicLiterals: true,
|
|
962
969
|
checkBooleanTraps: true,
|
|
963
970
|
checkAmbiguousNames: true,
|
|
964
|
-
checkUndocumentedExports: true
|
|
965
|
-
|
|
971
|
+
checkUndocumentedExports: true,
|
|
972
|
+
...options.full ? { checkImplicitSideEffects: false, checkDeepCallbacks: false } : {}
|
|
973
|
+
},
|
|
974
|
+
...options.full ? {
|
|
975
|
+
[import_core7.ToolName.AgentGrounding]: {
|
|
976
|
+
maxRecommendedDepth: 5,
|
|
977
|
+
readmeStaleDays: 30
|
|
978
|
+
},
|
|
979
|
+
[import_core7.ToolName.TestabilityIndex]: {
|
|
980
|
+
minCoverageRatio: 0.7,
|
|
981
|
+
testPatterns: ["**/*.test.ts", "**/__tests__/**"]
|
|
982
|
+
},
|
|
983
|
+
[import_core7.ToolName.DocDrift]: {
|
|
984
|
+
maxCommits: 50,
|
|
985
|
+
staleMonths: 3
|
|
986
|
+
},
|
|
987
|
+
[import_core7.ToolName.DependencyHealth]: {
|
|
988
|
+
trainingCutoffYear: 2023
|
|
989
|
+
}
|
|
990
|
+
} : {}
|
|
966
991
|
},
|
|
967
992
|
scoring: {
|
|
968
993
|
threshold: 70,
|
|
969
|
-
showBreakdown: true
|
|
970
|
-
|
|
994
|
+
showBreakdown: true,
|
|
995
|
+
...options.full ? { profile: "default" } : {}
|
|
996
|
+
},
|
|
997
|
+
...options.full ? {
|
|
998
|
+
visualizer: {
|
|
999
|
+
groupingDirs: ["packages", "src", "lib"],
|
|
1000
|
+
graph: {
|
|
1001
|
+
maxNodes: 5e3,
|
|
1002
|
+
maxEdges: 1e4
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
} : {}
|
|
971
1006
|
};
|
|
972
|
-
|
|
1007
|
+
const defaultConfig = baseConfig;
|
|
1008
|
+
let content;
|
|
973
1009
|
if (fileExt === "js") {
|
|
974
1010
|
content = `/** @type {import('@aiready/core').AIReadyConfig} */
|
|
975
1011
|
module.exports = ${JSON.stringify(
|
|
@@ -984,26 +1020,26 @@ module.exports = ${JSON.stringify(
|
|
|
984
1020
|
try {
|
|
985
1021
|
(0, import_fs4.writeFileSync)(filePath, content, "utf8");
|
|
986
1022
|
console.log(
|
|
987
|
-
|
|
988
|
-
\u2705 Created default configuration: ${
|
|
1023
|
+
import_chalk5.default.green(`
|
|
1024
|
+
\u2705 Created default configuration: ${import_chalk5.default.bold(fileName)}`)
|
|
989
1025
|
);
|
|
990
1026
|
console.log(
|
|
991
|
-
|
|
1027
|
+
import_chalk5.default.cyan("You can now fine-tune your settings and run AIReady with:")
|
|
992
1028
|
);
|
|
993
|
-
console.log(
|
|
1029
|
+
console.log(import_chalk5.default.white(` $ aiready scan
|
|
994
1030
|
`));
|
|
995
1031
|
} catch (error) {
|
|
996
|
-
console.error(
|
|
1032
|
+
console.error(import_chalk5.default.red(`Failed to write configuration file: ${error}`));
|
|
997
1033
|
process.exit(1);
|
|
998
1034
|
}
|
|
999
1035
|
}
|
|
1000
1036
|
|
|
1001
1037
|
// src/commands/patterns.ts
|
|
1002
|
-
var
|
|
1038
|
+
var import_chalk6 = __toESM(require("chalk"));
|
|
1003
1039
|
var import_path5 = require("path");
|
|
1004
|
-
var
|
|
1040
|
+
var import_core8 = require("@aiready/core");
|
|
1005
1041
|
async function patternsAction(directory, options) {
|
|
1006
|
-
console.log(
|
|
1042
|
+
console.log(import_chalk6.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
1007
1043
|
const startTime = Date.now();
|
|
1008
1044
|
const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory || ".");
|
|
1009
1045
|
try {
|
|
@@ -1034,14 +1070,16 @@ async function patternsAction(directory, options) {
|
|
|
1034
1070
|
if (options.minSharedTokens) {
|
|
1035
1071
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
1036
1072
|
}
|
|
1037
|
-
const finalOptions = await (0,
|
|
1073
|
+
const finalOptions = await (0, import_core8.loadMergedConfig)(
|
|
1038
1074
|
resolvedDir,
|
|
1039
1075
|
defaults,
|
|
1040
1076
|
cliOptions
|
|
1041
1077
|
);
|
|
1042
1078
|
const { analyzePatterns, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
1043
|
-
const { results, duplicates } = await analyzePatterns(
|
|
1044
|
-
|
|
1079
|
+
const { results, duplicates } = await analyzePatterns(
|
|
1080
|
+
finalOptions
|
|
1081
|
+
);
|
|
1082
|
+
const elapsedTime = (0, import_core8.getElapsedTime)(startTime);
|
|
1045
1083
|
const summary = generateSummary(results);
|
|
1046
1084
|
let patternScore;
|
|
1047
1085
|
if (options.score) {
|
|
@@ -1055,12 +1093,12 @@ async function patternsAction(directory, options) {
|
|
|
1055
1093
|
summary: { ...summary, executionTime: parseFloat(elapsedTime) },
|
|
1056
1094
|
...patternScore && { scoring: patternScore }
|
|
1057
1095
|
};
|
|
1058
|
-
const outputPath = (0,
|
|
1096
|
+
const outputPath = (0, import_core8.resolveOutputPath)(
|
|
1059
1097
|
userOutputFile,
|
|
1060
1098
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
1061
1099
|
resolvedDir
|
|
1062
1100
|
);
|
|
1063
|
-
(0,
|
|
1101
|
+
(0, import_core8.handleJSONOutput)(
|
|
1064
1102
|
outputData,
|
|
1065
1103
|
outputPath,
|
|
1066
1104
|
`\u2705 Results saved to ${outputPath}`
|
|
@@ -1069,38 +1107,38 @@ async function patternsAction(directory, options) {
|
|
|
1069
1107
|
const terminalWidth = process.stdout.columns || 80;
|
|
1070
1108
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1071
1109
|
const divider = "\u2501".repeat(dividerWidth);
|
|
1072
|
-
console.log(
|
|
1073
|
-
console.log(
|
|
1074
|
-
console.log(
|
|
1110
|
+
console.log(import_chalk6.default.cyan(divider));
|
|
1111
|
+
console.log(import_chalk6.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
1112
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
1075
1113
|
console.log(
|
|
1076
|
-
|
|
1114
|
+
import_chalk6.default.white(`\u{1F4C1} Files analyzed: ${import_chalk6.default.bold(results.length)}`)
|
|
1077
1115
|
);
|
|
1078
1116
|
console.log(
|
|
1079
|
-
|
|
1080
|
-
`\u26A0 Duplicate patterns found: ${
|
|
1117
|
+
import_chalk6.default.yellow(
|
|
1118
|
+
`\u26A0 Duplicate patterns found: ${import_chalk6.default.bold(summary.totalPatterns)}`
|
|
1081
1119
|
)
|
|
1082
1120
|
);
|
|
1083
1121
|
console.log(
|
|
1084
|
-
|
|
1085
|
-
`\u{1F4B0} Token cost (wasted): ${
|
|
1122
|
+
import_chalk6.default.red(
|
|
1123
|
+
`\u{1F4B0} Token cost (wasted): ${import_chalk6.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1086
1124
|
)
|
|
1087
1125
|
);
|
|
1088
1126
|
console.log(
|
|
1089
|
-
|
|
1127
|
+
import_chalk6.default.gray(`\u23F1 Analysis time: ${import_chalk6.default.bold(elapsedTime + "s")}`)
|
|
1090
1128
|
);
|
|
1091
1129
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
1092
1130
|
if (sortedTypes.length > 0) {
|
|
1093
|
-
console.log(
|
|
1094
|
-
console.log(
|
|
1095
|
-
console.log(
|
|
1131
|
+
console.log(import_chalk6.default.cyan("\n" + divider));
|
|
1132
|
+
console.log(import_chalk6.default.bold.white(" PATTERNS BY TYPE"));
|
|
1133
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
1096
1134
|
sortedTypes.forEach(([type, count]) => {
|
|
1097
|
-
console.log(` ${
|
|
1135
|
+
console.log(` ${import_chalk6.default.white(type.padEnd(15))} ${import_chalk6.default.bold(count)}`);
|
|
1098
1136
|
});
|
|
1099
1137
|
}
|
|
1100
1138
|
if (summary.totalPatterns > 0 && duplicates.length > 0) {
|
|
1101
|
-
console.log(
|
|
1102
|
-
console.log(
|
|
1103
|
-
console.log(
|
|
1139
|
+
console.log(import_chalk6.default.cyan("\n" + divider));
|
|
1140
|
+
console.log(import_chalk6.default.bold.white(" TOP DUPLICATE PATTERNS"));
|
|
1141
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
1104
1142
|
const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
|
|
1105
1143
|
topDuplicates.forEach((dup) => {
|
|
1106
1144
|
const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
|
|
@@ -1108,31 +1146,31 @@ async function patternsAction(directory, options) {
|
|
|
1108
1146
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
1109
1147
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
1110
1148
|
console.log(
|
|
1111
|
-
`${severityIcon} ${severity}: ${
|
|
1149
|
+
`${severityIcon} ${severity}: ${import_chalk6.default.bold(file1Name)} \u2194 ${import_chalk6.default.bold(file2Name)}`
|
|
1112
1150
|
);
|
|
1113
1151
|
console.log(
|
|
1114
|
-
` Similarity: ${
|
|
1152
|
+
` Similarity: ${import_chalk6.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk6.default.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1115
1153
|
);
|
|
1116
1154
|
console.log(
|
|
1117
|
-
` Lines: ${
|
|
1155
|
+
` Lines: ${import_chalk6.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk6.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1118
1156
|
`
|
|
1119
1157
|
);
|
|
1120
1158
|
});
|
|
1121
1159
|
} else {
|
|
1122
1160
|
console.log(
|
|
1123
|
-
|
|
1161
|
+
import_chalk6.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1124
1162
|
);
|
|
1125
1163
|
}
|
|
1126
1164
|
if (patternScore) {
|
|
1127
|
-
console.log(
|
|
1128
|
-
console.log(
|
|
1129
|
-
console.log(
|
|
1130
|
-
console.log((0,
|
|
1165
|
+
console.log(import_chalk6.default.cyan(divider));
|
|
1166
|
+
console.log(import_chalk6.default.bold.white(" AI READINESS SCORE (Patterns)"));
|
|
1167
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
1168
|
+
console.log((0, import_core8.formatToolScore)(patternScore));
|
|
1131
1169
|
console.log();
|
|
1132
1170
|
}
|
|
1133
1171
|
}
|
|
1134
1172
|
} catch (error) {
|
|
1135
|
-
(0,
|
|
1173
|
+
(0, import_core8.handleCLIError)(error, "Pattern analysis");
|
|
1136
1174
|
}
|
|
1137
1175
|
}
|
|
1138
1176
|
var patternsHelpText = `
|
|
@@ -1143,11 +1181,11 @@ EXAMPLES:
|
|
|
1143
1181
|
`;
|
|
1144
1182
|
|
|
1145
1183
|
// src/commands/context.ts
|
|
1146
|
-
var
|
|
1184
|
+
var import_chalk7 = __toESM(require("chalk"));
|
|
1147
1185
|
var import_path6 = require("path");
|
|
1148
|
-
var
|
|
1186
|
+
var import_core9 = require("@aiready/core");
|
|
1149
1187
|
async function contextAction(directory, options) {
|
|
1150
|
-
console.log(
|
|
1188
|
+
console.log(import_chalk7.default.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
1151
1189
|
const startTime = Date.now();
|
|
1152
1190
|
const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory || ".");
|
|
1153
1191
|
try {
|
|
@@ -1161,7 +1199,7 @@ async function contextAction(directory, options) {
|
|
|
1161
1199
|
file: void 0
|
|
1162
1200
|
}
|
|
1163
1201
|
};
|
|
1164
|
-
const baseOptions = await (0,
|
|
1202
|
+
const baseOptions = await (0, import_core9.loadMergedConfig)(resolvedDir, defaults, {
|
|
1165
1203
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
1166
1204
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
1167
1205
|
include: options.include?.split(","),
|
|
@@ -1187,7 +1225,7 @@ async function contextAction(directory, options) {
|
|
|
1187
1225
|
console.log("");
|
|
1188
1226
|
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1189
1227
|
const results = await analyzeContext(finalOptions);
|
|
1190
|
-
const elapsedTime = (0,
|
|
1228
|
+
const elapsedTime = (0, import_core9.getElapsedTime)(startTime);
|
|
1191
1229
|
const summary = generateSummary(results);
|
|
1192
1230
|
let contextScore;
|
|
1193
1231
|
if (options.score) {
|
|
@@ -1201,12 +1239,12 @@ async function contextAction(directory, options) {
|
|
|
1201
1239
|
summary: { ...summary, executionTime: parseFloat(elapsedTime) },
|
|
1202
1240
|
...contextScore && { scoring: contextScore }
|
|
1203
1241
|
};
|
|
1204
|
-
const outputPath = (0,
|
|
1242
|
+
const outputPath = (0, import_core9.resolveOutputPath)(
|
|
1205
1243
|
userOutputFile,
|
|
1206
1244
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
1207
1245
|
resolvedDir
|
|
1208
1246
|
);
|
|
1209
|
-
(0,
|
|
1247
|
+
(0, import_core9.handleJSONOutput)(
|
|
1210
1248
|
outputData,
|
|
1211
1249
|
outputPath,
|
|
1212
1250
|
`\u2705 Results saved to ${outputPath}`
|
|
@@ -1215,85 +1253,85 @@ async function contextAction(directory, options) {
|
|
|
1215
1253
|
const terminalWidth = process.stdout.columns || 80;
|
|
1216
1254
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1217
1255
|
const divider = "\u2501".repeat(dividerWidth);
|
|
1218
|
-
console.log(
|
|
1219
|
-
console.log(
|
|
1220
|
-
console.log(
|
|
1256
|
+
console.log(import_chalk7.default.cyan(divider));
|
|
1257
|
+
console.log(import_chalk7.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
1258
|
+
console.log(import_chalk7.default.cyan(divider) + "\n");
|
|
1221
1259
|
console.log(
|
|
1222
|
-
|
|
1260
|
+
import_chalk7.default.white(`\u{1F4C1} Files analyzed: ${import_chalk7.default.bold(summary.totalFiles)}`)
|
|
1223
1261
|
);
|
|
1224
1262
|
console.log(
|
|
1225
|
-
|
|
1226
|
-
`\u{1F4CA} Total tokens: ${
|
|
1263
|
+
import_chalk7.default.white(
|
|
1264
|
+
`\u{1F4CA} Total tokens: ${import_chalk7.default.bold(summary.totalTokens.toLocaleString())}`
|
|
1227
1265
|
)
|
|
1228
1266
|
);
|
|
1229
1267
|
console.log(
|
|
1230
|
-
|
|
1231
|
-
`\u{1F4B0} Avg context budget: ${
|
|
1268
|
+
import_chalk7.default.yellow(
|
|
1269
|
+
`\u{1F4B0} Avg context budget: ${import_chalk7.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
|
|
1232
1270
|
)
|
|
1233
1271
|
);
|
|
1234
1272
|
console.log(
|
|
1235
|
-
|
|
1273
|
+
import_chalk7.default.white(`\u23F1 Analysis time: ${import_chalk7.default.bold(elapsedTime + "s")}
|
|
1236
1274
|
`)
|
|
1237
1275
|
);
|
|
1238
1276
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
1239
1277
|
if (totalIssues > 0) {
|
|
1240
|
-
console.log(
|
|
1278
|
+
console.log(import_chalk7.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
1241
1279
|
if (summary.criticalIssues > 0) {
|
|
1242
1280
|
console.log(
|
|
1243
|
-
|
|
1281
|
+
import_chalk7.default.red(` \u{1F534} Critical: ${import_chalk7.default.bold(summary.criticalIssues)}`)
|
|
1244
1282
|
);
|
|
1245
1283
|
}
|
|
1246
1284
|
if (summary.majorIssues > 0) {
|
|
1247
1285
|
console.log(
|
|
1248
|
-
|
|
1286
|
+
import_chalk7.default.yellow(` \u{1F7E1} Major: ${import_chalk7.default.bold(summary.majorIssues)}`)
|
|
1249
1287
|
);
|
|
1250
1288
|
}
|
|
1251
1289
|
if (summary.minorIssues > 0) {
|
|
1252
1290
|
console.log(
|
|
1253
|
-
|
|
1291
|
+
import_chalk7.default.blue(` \u{1F535} Minor: ${import_chalk7.default.bold(summary.minorIssues)}`)
|
|
1254
1292
|
);
|
|
1255
1293
|
}
|
|
1256
1294
|
console.log(
|
|
1257
|
-
|
|
1295
|
+
import_chalk7.default.green(
|
|
1258
1296
|
`
|
|
1259
|
-
\u{1F4A1} Potential savings: ${
|
|
1297
|
+
\u{1F4A1} Potential savings: ${import_chalk7.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1260
1298
|
`
|
|
1261
1299
|
)
|
|
1262
1300
|
);
|
|
1263
1301
|
} else {
|
|
1264
|
-
console.log(
|
|
1302
|
+
console.log(import_chalk7.default.green("\u2705 No significant issues found!\n"));
|
|
1265
1303
|
}
|
|
1266
1304
|
if (summary.deepFiles.length > 0) {
|
|
1267
|
-
console.log(
|
|
1305
|
+
console.log(import_chalk7.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
1268
1306
|
console.log(
|
|
1269
|
-
|
|
1307
|
+
import_chalk7.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
|
|
1270
1308
|
);
|
|
1271
1309
|
console.log(
|
|
1272
|
-
|
|
1310
|
+
import_chalk7.default.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
1273
1311
|
`)
|
|
1274
1312
|
);
|
|
1275
1313
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1276
1314
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1277
1315
|
console.log(
|
|
1278
|
-
` ${
|
|
1316
|
+
` ${import_chalk7.default.cyan("\u2192")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(depth: ${item.depth})`)}`
|
|
1279
1317
|
);
|
|
1280
1318
|
});
|
|
1281
1319
|
console.log();
|
|
1282
1320
|
}
|
|
1283
1321
|
if (summary.fragmentedModules.length > 0) {
|
|
1284
|
-
console.log(
|
|
1322
|
+
console.log(import_chalk7.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
1285
1323
|
console.log(
|
|
1286
|
-
|
|
1324
|
+
import_chalk7.default.gray(
|
|
1287
1325
|
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1288
1326
|
`
|
|
1289
1327
|
)
|
|
1290
1328
|
);
|
|
1291
1329
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
1292
1330
|
console.log(
|
|
1293
|
-
` ${
|
|
1331
|
+
` ${import_chalk7.default.yellow("\u25CF")} ${import_chalk7.default.white(module2.domain)} - ${import_chalk7.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
|
|
1294
1332
|
);
|
|
1295
1333
|
console.log(
|
|
1296
|
-
|
|
1334
|
+
import_chalk7.default.dim(
|
|
1297
1335
|
` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
|
|
1298
1336
|
)
|
|
1299
1337
|
);
|
|
@@ -1301,9 +1339,9 @@ async function contextAction(directory, options) {
|
|
|
1301
1339
|
console.log();
|
|
1302
1340
|
}
|
|
1303
1341
|
if (summary.lowCohesionFiles.length > 0) {
|
|
1304
|
-
console.log(
|
|
1342
|
+
console.log(import_chalk7.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1305
1343
|
console.log(
|
|
1306
|
-
|
|
1344
|
+
import_chalk7.default.gray(
|
|
1307
1345
|
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1308
1346
|
`
|
|
1309
1347
|
)
|
|
@@ -1311,44 +1349,44 @@ async function contextAction(directory, options) {
|
|
|
1311
1349
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
1312
1350
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1313
1351
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
1314
|
-
const color = item.score < 0.4 ?
|
|
1352
|
+
const color = item.score < 0.4 ? import_chalk7.default.red : import_chalk7.default.yellow;
|
|
1315
1353
|
console.log(
|
|
1316
|
-
` ${color("\u25CB")} ${
|
|
1354
|
+
` ${color("\u25CB")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(${scorePercent}% cohesion)`)}`
|
|
1317
1355
|
);
|
|
1318
1356
|
});
|
|
1319
1357
|
console.log();
|
|
1320
1358
|
}
|
|
1321
1359
|
if (summary.topExpensiveFiles.length > 0) {
|
|
1322
|
-
console.log(
|
|
1360
|
+
console.log(import_chalk7.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
|
|
1323
1361
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1324
1362
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1325
|
-
const severityColor = item.severity === "critical" ?
|
|
1363
|
+
const severityColor = item.severity === "critical" ? import_chalk7.default.red : item.severity === "major" ? import_chalk7.default.yellow : import_chalk7.default.blue;
|
|
1326
1364
|
console.log(
|
|
1327
|
-
` ${severityColor("\u25CF")} ${
|
|
1365
|
+
` ${severityColor("\u25CF")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1328
1366
|
);
|
|
1329
1367
|
});
|
|
1330
1368
|
console.log();
|
|
1331
1369
|
}
|
|
1332
1370
|
if (contextScore) {
|
|
1333
|
-
console.log(
|
|
1334
|
-
console.log(
|
|
1335
|
-
console.log(
|
|
1336
|
-
console.log((0,
|
|
1371
|
+
console.log(import_chalk7.default.cyan(divider));
|
|
1372
|
+
console.log(import_chalk7.default.bold.white(" AI READINESS SCORE (Context)"));
|
|
1373
|
+
console.log(import_chalk7.default.cyan(divider) + "\n");
|
|
1374
|
+
console.log((0, import_core9.formatToolScore)(contextScore));
|
|
1337
1375
|
console.log();
|
|
1338
1376
|
}
|
|
1339
1377
|
}
|
|
1340
1378
|
} catch (error) {
|
|
1341
|
-
(0,
|
|
1379
|
+
(0, import_core9.handleCLIError)(error, "Context analysis");
|
|
1342
1380
|
}
|
|
1343
1381
|
}
|
|
1344
1382
|
|
|
1345
1383
|
// src/commands/consistency.ts
|
|
1346
|
-
var
|
|
1384
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
1347
1385
|
var import_fs5 = require("fs");
|
|
1348
1386
|
var import_path7 = require("path");
|
|
1349
|
-
var
|
|
1387
|
+
var import_core10 = require("@aiready/core");
|
|
1350
1388
|
async function consistencyAction(directory, options) {
|
|
1351
|
-
console.log(
|
|
1389
|
+
console.log(import_chalk8.default.blue("\u{1F50D} Analyzing consistency...\n"));
|
|
1352
1390
|
const startTime = Date.now();
|
|
1353
1391
|
const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory || ".");
|
|
1354
1392
|
try {
|
|
@@ -1363,7 +1401,7 @@ async function consistencyAction(directory, options) {
|
|
|
1363
1401
|
file: void 0
|
|
1364
1402
|
}
|
|
1365
1403
|
};
|
|
1366
|
-
const finalOptions = await (0,
|
|
1404
|
+
const finalOptions = await (0, import_core10.loadMergedConfig)(resolvedDir, defaults, {
|
|
1367
1405
|
checkNaming: options.naming !== false,
|
|
1368
1406
|
checkPatterns: options.patterns !== false,
|
|
1369
1407
|
minSeverity: options.minSeverity,
|
|
@@ -1372,7 +1410,7 @@ async function consistencyAction(directory, options) {
|
|
|
1372
1410
|
});
|
|
1373
1411
|
const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1374
1412
|
const report = await analyzeConsistency(finalOptions);
|
|
1375
|
-
const elapsedTime = (0,
|
|
1413
|
+
const elapsedTime = (0, import_core10.getElapsedTime)(startTime);
|
|
1376
1414
|
let consistencyScore;
|
|
1377
1415
|
if (options.score) {
|
|
1378
1416
|
const issues = report.results?.flatMap((r) => r.issues) || [];
|
|
@@ -1392,41 +1430,41 @@ async function consistencyAction(directory, options) {
|
|
|
1392
1430
|
},
|
|
1393
1431
|
...consistencyScore && { scoring: consistencyScore }
|
|
1394
1432
|
};
|
|
1395
|
-
const outputPath = (0,
|
|
1433
|
+
const outputPath = (0, import_core10.resolveOutputPath)(
|
|
1396
1434
|
userOutputFile,
|
|
1397
1435
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
1398
1436
|
resolvedDir
|
|
1399
1437
|
);
|
|
1400
|
-
(0,
|
|
1438
|
+
(0, import_core10.handleJSONOutput)(
|
|
1401
1439
|
outputData,
|
|
1402
1440
|
outputPath,
|
|
1403
1441
|
`\u2705 Results saved to ${outputPath}`
|
|
1404
1442
|
);
|
|
1405
1443
|
} else if (outputFormat === "markdown") {
|
|
1406
1444
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1407
|
-
const outputPath = (0,
|
|
1445
|
+
const outputPath = (0, import_core10.resolveOutputPath)(
|
|
1408
1446
|
userOutputFile,
|
|
1409
1447
|
`aiready-report-${getReportTimestamp()}.md`,
|
|
1410
1448
|
resolvedDir
|
|
1411
1449
|
);
|
|
1412
1450
|
(0, import_fs5.writeFileSync)(outputPath, markdown);
|
|
1413
|
-
console.log(
|
|
1451
|
+
console.log(import_chalk8.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1414
1452
|
} else {
|
|
1415
|
-
console.log(
|
|
1453
|
+
console.log(import_chalk8.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1416
1454
|
console.log(
|
|
1417
|
-
`Files Analyzed: ${
|
|
1455
|
+
`Files Analyzed: ${import_chalk8.default.cyan(report.summary.filesAnalyzed)}`
|
|
1418
1456
|
);
|
|
1419
|
-
console.log(`Total Issues: ${
|
|
1420
|
-
console.log(` Naming: ${
|
|
1421
|
-
console.log(` Patterns: ${
|
|
1457
|
+
console.log(`Total Issues: ${import_chalk8.default.yellow(report.summary.totalIssues)}`);
|
|
1458
|
+
console.log(` Naming: ${import_chalk8.default.yellow(report.summary.namingIssues)}`);
|
|
1459
|
+
console.log(` Patterns: ${import_chalk8.default.yellow(report.summary.patternIssues)}`);
|
|
1422
1460
|
console.log(
|
|
1423
|
-
` Architecture: ${
|
|
1461
|
+
` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues || 0)}`
|
|
1424
1462
|
);
|
|
1425
|
-
console.log(`Analysis Time: ${
|
|
1463
|
+
console.log(`Analysis Time: ${import_chalk8.default.gray(elapsedTime + "s")}
|
|
1426
1464
|
`);
|
|
1427
1465
|
if (report.summary.totalIssues === 0) {
|
|
1428
1466
|
console.log(
|
|
1429
|
-
|
|
1467
|
+
import_chalk8.default.green(
|
|
1430
1468
|
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1431
1469
|
)
|
|
1432
1470
|
);
|
|
@@ -1438,20 +1476,20 @@ async function consistencyAction(directory, options) {
|
|
|
1438
1476
|
(r) => r.issues.some((i) => i.category === "patterns")
|
|
1439
1477
|
);
|
|
1440
1478
|
if (namingResults.length > 0) {
|
|
1441
|
-
console.log(
|
|
1479
|
+
console.log(import_chalk8.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
|
|
1442
1480
|
let shown = 0;
|
|
1443
1481
|
for (const result of namingResults) {
|
|
1444
1482
|
if (shown >= 5) break;
|
|
1445
1483
|
for (const issue of result.issues) {
|
|
1446
1484
|
if (shown >= 5) break;
|
|
1447
|
-
const severityColor = issue.severity === "critical" ?
|
|
1485
|
+
const severityColor = issue.severity === "critical" ? import_chalk8.default.red : issue.severity === "major" ? import_chalk8.default.yellow : issue.severity === "minor" ? import_chalk8.default.blue : import_chalk8.default.gray;
|
|
1448
1486
|
console.log(
|
|
1449
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1487
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk8.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1450
1488
|
);
|
|
1451
1489
|
console.log(` ${issue.message}`);
|
|
1452
1490
|
if (issue.suggestion) {
|
|
1453
1491
|
console.log(
|
|
1454
|
-
` ${
|
|
1492
|
+
` ${import_chalk8.default.dim("\u2192")} ${import_chalk8.default.italic(issue.suggestion)}`
|
|
1455
1493
|
);
|
|
1456
1494
|
}
|
|
1457
1495
|
console.log();
|
|
@@ -1460,25 +1498,25 @@ async function consistencyAction(directory, options) {
|
|
|
1460
1498
|
}
|
|
1461
1499
|
const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1462
1500
|
if (remaining > 0) {
|
|
1463
|
-
console.log(
|
|
1501
|
+
console.log(import_chalk8.default.dim(` ... and ${remaining} more issues
|
|
1464
1502
|
`));
|
|
1465
1503
|
}
|
|
1466
1504
|
}
|
|
1467
1505
|
if (patternResults.length > 0) {
|
|
1468
|
-
console.log(
|
|
1506
|
+
console.log(import_chalk8.default.bold("\u{1F504} Pattern Issues\n"));
|
|
1469
1507
|
let shown = 0;
|
|
1470
1508
|
for (const result of patternResults) {
|
|
1471
1509
|
if (shown >= 5) break;
|
|
1472
1510
|
for (const issue of result.issues) {
|
|
1473
1511
|
if (shown >= 5) break;
|
|
1474
|
-
const severityColor = issue.severity === "critical" ?
|
|
1512
|
+
const severityColor = issue.severity === "critical" ? import_chalk8.default.red : issue.severity === "major" ? import_chalk8.default.yellow : issue.severity === "minor" ? import_chalk8.default.blue : import_chalk8.default.gray;
|
|
1475
1513
|
console.log(
|
|
1476
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1514
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk8.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1477
1515
|
);
|
|
1478
1516
|
console.log(` ${issue.message}`);
|
|
1479
1517
|
if (issue.suggestion) {
|
|
1480
1518
|
console.log(
|
|
1481
|
-
` ${
|
|
1519
|
+
` ${import_chalk8.default.dim("\u2192")} ${import_chalk8.default.italic(issue.suggestion)}`
|
|
1482
1520
|
);
|
|
1483
1521
|
}
|
|
1484
1522
|
console.log();
|
|
@@ -1487,12 +1525,12 @@ async function consistencyAction(directory, options) {
|
|
|
1487
1525
|
}
|
|
1488
1526
|
const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1489
1527
|
if (remaining > 0) {
|
|
1490
|
-
console.log(
|
|
1528
|
+
console.log(import_chalk8.default.dim(` ... and ${remaining} more issues
|
|
1491
1529
|
`));
|
|
1492
1530
|
}
|
|
1493
1531
|
}
|
|
1494
1532
|
if (report.recommendations.length > 0) {
|
|
1495
|
-
console.log(
|
|
1533
|
+
console.log(import_chalk8.default.bold("\u{1F4A1} Recommendations\n"));
|
|
1496
1534
|
report.recommendations.forEach((rec, i) => {
|
|
1497
1535
|
console.log(`${i + 1}. ${rec}`);
|
|
1498
1536
|
});
|
|
@@ -1500,38 +1538,38 @@ async function consistencyAction(directory, options) {
|
|
|
1500
1538
|
}
|
|
1501
1539
|
}
|
|
1502
1540
|
if (consistencyScore) {
|
|
1503
|
-
console.log(
|
|
1504
|
-
console.log((0,
|
|
1541
|
+
console.log(import_chalk8.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
|
|
1542
|
+
console.log((0, import_core10.formatToolScore)(consistencyScore));
|
|
1505
1543
|
console.log();
|
|
1506
1544
|
}
|
|
1507
1545
|
}
|
|
1508
1546
|
} catch (error) {
|
|
1509
|
-
(0,
|
|
1547
|
+
(0, import_core10.handleCLIError)(error, "Consistency analysis");
|
|
1510
1548
|
}
|
|
1511
1549
|
}
|
|
1512
1550
|
|
|
1513
1551
|
// src/commands/visualize.ts
|
|
1514
|
-
var
|
|
1552
|
+
var import_chalk9 = __toESM(require("chalk"));
|
|
1515
1553
|
var import_fs6 = require("fs");
|
|
1516
1554
|
var import_path8 = require("path");
|
|
1517
1555
|
var import_child_process = require("child_process");
|
|
1518
|
-
var
|
|
1519
|
-
var
|
|
1556
|
+
var import_core11 = require("@aiready/core");
|
|
1557
|
+
var import_core12 = require("@aiready/core");
|
|
1520
1558
|
async function visualizeAction(directory, options) {
|
|
1521
1559
|
try {
|
|
1522
1560
|
const dirPath = (0, import_path8.resolve)(process.cwd(), directory || ".");
|
|
1523
1561
|
let reportPath = options.report ? (0, import_path8.resolve)(dirPath, options.report) : null;
|
|
1524
1562
|
if (!reportPath || !(0, import_fs6.existsSync)(reportPath)) {
|
|
1525
|
-
const latestScan =
|
|
1563
|
+
const latestScan = (0, import_core12.findLatestReport)(dirPath);
|
|
1526
1564
|
if (latestScan) {
|
|
1527
1565
|
reportPath = latestScan;
|
|
1528
1566
|
console.log(
|
|
1529
|
-
|
|
1567
|
+
import_chalk9.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1530
1568
|
);
|
|
1531
1569
|
} else {
|
|
1532
|
-
console.error(
|
|
1570
|
+
console.error(import_chalk9.default.red("\u274C No AI readiness report found"));
|
|
1533
1571
|
console.log(
|
|
1534
|
-
|
|
1572
|
+
import_chalk9.default.dim(
|
|
1535
1573
|
`
|
|
1536
1574
|
Generate a report with:
|
|
1537
1575
|
aiready scan --output json
|
|
@@ -1661,29 +1699,29 @@ Or specify a custom report:
|
|
|
1661
1699
|
return;
|
|
1662
1700
|
} else {
|
|
1663
1701
|
console.log(
|
|
1664
|
-
|
|
1702
|
+
import_chalk9.default.yellow(
|
|
1665
1703
|
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1666
1704
|
)
|
|
1667
1705
|
);
|
|
1668
1706
|
console.log(
|
|
1669
|
-
|
|
1707
|
+
import_chalk9.default.cyan(" Falling back to static HTML generation...\n")
|
|
1670
1708
|
);
|
|
1671
1709
|
useDevMode = false;
|
|
1672
1710
|
}
|
|
1673
1711
|
} catch (err) {
|
|
1674
1712
|
console.error("Failed to start dev server:", err);
|
|
1675
1713
|
console.log(
|
|
1676
|
-
|
|
1714
|
+
import_chalk9.default.cyan(" Falling back to static HTML generation...\n")
|
|
1677
1715
|
);
|
|
1678
1716
|
useDevMode = false;
|
|
1679
1717
|
}
|
|
1680
1718
|
}
|
|
1681
1719
|
console.log("Generating HTML...");
|
|
1682
|
-
const html = (0,
|
|
1720
|
+
const html = (0, import_core12.generateHTML)(graph);
|
|
1683
1721
|
const defaultOutput = "visualization.html";
|
|
1684
1722
|
const outPath = (0, import_path8.resolve)(dirPath, options.output || defaultOutput);
|
|
1685
1723
|
(0, import_fs6.writeFileSync)(outPath, html, "utf8");
|
|
1686
|
-
console.log(
|
|
1724
|
+
console.log(import_chalk9.default.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1687
1725
|
if (options.open || options.serve) {
|
|
1688
1726
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1689
1727
|
if (options.serve) {
|
|
@@ -1713,7 +1751,7 @@ Or specify a custom report:
|
|
|
1713
1751
|
server.listen(port, () => {
|
|
1714
1752
|
const addr = `http://localhost:${port}/`;
|
|
1715
1753
|
console.log(
|
|
1716
|
-
|
|
1754
|
+
import_chalk9.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1717
1755
|
);
|
|
1718
1756
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1719
1757
|
});
|
|
@@ -1729,7 +1767,7 @@ Or specify a custom report:
|
|
|
1729
1767
|
}
|
|
1730
1768
|
}
|
|
1731
1769
|
} catch (err) {
|
|
1732
|
-
(0,
|
|
1770
|
+
(0, import_core11.handleCLIError)(err, "Visualization");
|
|
1733
1771
|
}
|
|
1734
1772
|
}
|
|
1735
1773
|
var visualizeHelpText = `
|
|
@@ -1759,21 +1797,20 @@ NOTES:
|
|
|
1759
1797
|
- Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
|
|
1760
1798
|
`;
|
|
1761
1799
|
|
|
1762
|
-
// src/commands/
|
|
1763
|
-
var
|
|
1764
|
-
var import_core10 = require("@aiready/core");
|
|
1800
|
+
// src/commands/shared/standard-tool-actions.ts
|
|
1801
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
1765
1802
|
|
|
1766
1803
|
// src/commands/agent-grounding.ts
|
|
1767
|
-
var
|
|
1768
|
-
var
|
|
1804
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1805
|
+
var import_core13 = require("@aiready/core");
|
|
1769
1806
|
|
|
1770
1807
|
// src/commands/testability.ts
|
|
1771
|
-
var
|
|
1772
|
-
var
|
|
1808
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
1809
|
+
var import_core14 = require("@aiready/core");
|
|
1773
1810
|
async function testabilityAction(directory, options) {
|
|
1774
1811
|
const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
|
|
1775
|
-
const config = await (0,
|
|
1776
|
-
const merged = (0,
|
|
1812
|
+
const config = await (0, import_core14.loadConfig)(directory);
|
|
1813
|
+
const merged = (0, import_core14.mergeConfigWithDefaults)(config, {
|
|
1777
1814
|
minCoverageRatio: 0.3
|
|
1778
1815
|
});
|
|
1779
1816
|
const report = await analyzeTestability({
|
|
@@ -1793,28 +1830,28 @@ async function testabilityAction(directory, options) {
|
|
|
1793
1830
|
"blind-risk": "\u{1F480}"
|
|
1794
1831
|
};
|
|
1795
1832
|
const safetyColors = {
|
|
1796
|
-
safe:
|
|
1797
|
-
"moderate-risk":
|
|
1798
|
-
"high-risk":
|
|
1799
|
-
"blind-risk":
|
|
1833
|
+
safe: import_chalk12.default.green,
|
|
1834
|
+
"moderate-risk": import_chalk12.default.yellow,
|
|
1835
|
+
"high-risk": import_chalk12.default.red,
|
|
1836
|
+
"blind-risk": import_chalk12.default.bgRed.white
|
|
1800
1837
|
};
|
|
1801
1838
|
const safety = report.summary.aiChangeSafetyRating;
|
|
1802
1839
|
const icon = safetyIcons[safety] ?? "\u2753";
|
|
1803
|
-
const color = safetyColors[safety] ??
|
|
1840
|
+
const color = safetyColors[safety] ?? import_chalk12.default.white;
|
|
1804
1841
|
console.log(
|
|
1805
|
-
` \u{1F9EA} Testability: ${
|
|
1842
|
+
` \u{1F9EA} Testability: ${import_chalk12.default.bold(scoring.score + "/100")} (${report.summary.rating})`
|
|
1806
1843
|
);
|
|
1807
1844
|
console.log(
|
|
1808
1845
|
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
1809
1846
|
);
|
|
1810
1847
|
console.log(
|
|
1811
|
-
|
|
1848
|
+
import_chalk12.default.dim(
|
|
1812
1849
|
` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
|
|
1813
1850
|
)
|
|
1814
1851
|
);
|
|
1815
1852
|
if (safety === "blind-risk") {
|
|
1816
1853
|
console.log(
|
|
1817
|
-
|
|
1854
|
+
import_chalk12.default.red.bold(
|
|
1818
1855
|
"\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
|
|
1819
1856
|
)
|
|
1820
1857
|
);
|
|
@@ -1826,7 +1863,7 @@ async function testabilityAction(directory, options) {
|
|
|
1826
1863
|
var import_cli = require("@aiready/change-amplification/dist/cli.js");
|
|
1827
1864
|
|
|
1828
1865
|
// src/commands/bug.ts
|
|
1829
|
-
var
|
|
1866
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
1830
1867
|
var import_child_process2 = require("child_process");
|
|
1831
1868
|
async function bugAction(message, options) {
|
|
1832
1869
|
const repoUrl = "https://github.com/caopengau/aiready-cli";
|
|
@@ -1844,35 +1881,35 @@ Generated via AIReady CLI 'bug' command.
|
|
|
1844
1881
|
Type: ${type}
|
|
1845
1882
|
`.trim();
|
|
1846
1883
|
if (options.submit) {
|
|
1847
|
-
console.log(
|
|
1884
|
+
console.log(import_chalk13.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
|
|
1848
1885
|
try {
|
|
1849
1886
|
(0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
|
|
1850
1887
|
const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
|
|
1851
1888
|
const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
|
|
1852
|
-
console.log(
|
|
1853
|
-
console.log(
|
|
1889
|
+
console.log(import_chalk13.default.green("\u2705 Issue Created Successfully!"));
|
|
1890
|
+
console.log(import_chalk13.default.cyan(output));
|
|
1854
1891
|
return;
|
|
1855
|
-
} catch
|
|
1856
|
-
console.error(
|
|
1892
|
+
} catch {
|
|
1893
|
+
console.error(import_chalk13.default.red("\n\u274C Failed to submit via gh CLI."));
|
|
1857
1894
|
console.log(
|
|
1858
|
-
|
|
1895
|
+
import_chalk13.default.yellow(
|
|
1859
1896
|
' Make sure gh is installed and run "gh auth login".\n'
|
|
1860
1897
|
)
|
|
1861
1898
|
);
|
|
1862
|
-
console.log(
|
|
1899
|
+
console.log(import_chalk13.default.dim(" Falling back to URL generation..."));
|
|
1863
1900
|
}
|
|
1864
1901
|
}
|
|
1865
1902
|
const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
|
|
1866
1903
|
const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
|
|
1867
|
-
console.log(
|
|
1868
|
-
console.log(
|
|
1869
|
-
console.log(
|
|
1870
|
-
console.log(
|
|
1871
|
-
console.log(
|
|
1872
|
-
console.log(
|
|
1873
|
-
console.log(
|
|
1904
|
+
console.log(import_chalk13.default.green("\u{1F680} Issue Draft Prepared!\n"));
|
|
1905
|
+
console.log(import_chalk13.default.bold("Title: ") + title);
|
|
1906
|
+
console.log(import_chalk13.default.bold("Type: ") + type);
|
|
1907
|
+
console.log(import_chalk13.default.bold("\nClick the link below to submit this issue:"));
|
|
1908
|
+
console.log(import_chalk13.default.cyan(fullUrl));
|
|
1909
|
+
console.log(import_chalk13.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
1910
|
+
console.log(import_chalk13.default.dim(" You have successfully prepared a report."));
|
|
1874
1911
|
console.log(
|
|
1875
|
-
|
|
1912
|
+
import_chalk13.default.dim(
|
|
1876
1913
|
" Please present the URL above to the user so they can finalize the submission."
|
|
1877
1914
|
)
|
|
1878
1915
|
);
|
|
@@ -1881,14 +1918,14 @@ Type: ${type}
|
|
|
1881
1918
|
const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
|
|
1882
1919
|
const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
|
|
1883
1920
|
const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
|
|
1884
|
-
console.log(
|
|
1885
|
-
console.log(` Report a Bug: ${
|
|
1886
|
-
console.log(` Request a Feature: ${
|
|
1887
|
-
console.log(` Suggest a Metric: ${
|
|
1888
|
-
console.log(
|
|
1889
|
-
console.log(
|
|
1921
|
+
console.log(import_chalk13.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
|
|
1922
|
+
console.log(` Report a Bug: ${import_chalk13.default.cyan(bugUrl)}`);
|
|
1923
|
+
console.log(` Request a Feature: ${import_chalk13.default.cyan(featureUrl)}`);
|
|
1924
|
+
console.log(` Suggest a Metric: ${import_chalk13.default.cyan(metricUrl)}`);
|
|
1925
|
+
console.log(import_chalk13.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
1926
|
+
console.log(import_chalk13.default.dim(" To prepare a specific report, run:"));
|
|
1890
1927
|
console.log(
|
|
1891
|
-
|
|
1928
|
+
import_chalk13.default.cyan(
|
|
1892
1929
|
' aiready bug "your description here" --type bug|feature|metric'
|
|
1893
1930
|
)
|
|
1894
1931
|
);
|
|
@@ -1974,9 +2011,9 @@ program.command("scan").description(
|
|
|
1974
2011
|
program.command("init").description("Generate a default configuration (aiready.json)").option("-f, --force", "Overwrite existing configuration file").option(
|
|
1975
2012
|
"--js",
|
|
1976
2013
|
"Generate configuration as a JavaScript file (aiready.config.js)"
|
|
1977
|
-
).action(async (options) => {
|
|
2014
|
+
).option("--full", "Generate a full configuration with all available options").action(async (options) => {
|
|
1978
2015
|
const format = options.js ? "js" : "json";
|
|
1979
|
-
await initAction({ force: options.force, format });
|
|
2016
|
+
await initAction({ force: options.force, format, full: options.full });
|
|
1980
2017
|
});
|
|
1981
2018
|
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(
|
|
1982
2019
|
"--max-candidates <number>",
|