@aiready/cli 0.9.35 → 0.9.38
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/.turbo/turbo-build.log +18 -7
- package/.turbo/turbo-test.log +5 -5
- package/dist/agent-grounding-DAOSU4MF.mjs +7 -0
- package/dist/chunk-G6SDH7ZS.mjs +126 -0
- package/dist/chunk-JQG7ZATX.mjs +211 -0
- package/dist/chunk-N4SLON5K.mjs +152 -0
- package/dist/chunk-RBWLQRKR.mjs +39 -0
- package/dist/chunk-XAF2EW5H.mjs +46 -0
- package/dist/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/chunk-YIS6WTY5.mjs +35 -0
- package/dist/cli.js +223 -25
- package/dist/cli.mjs +153 -21
- package/dist/deps-health-UWVYJ7FZ.mjs +47 -0
- package/dist/doc-drift-G7MGAZAE.mjs +47 -0
- package/dist/hallucination-risk-XU6E7IGN.mjs +7 -0
- package/dist/index.js +95 -0
- package/dist/index.mjs +1 -1
- package/dist/testability-VDZJZ4MF.mjs +7 -0
- package/package.json +14 -9
- package/src/cli.ts +12 -4
- package/src/commands/agent-grounding.ts +47 -0
- package/src/commands/deps-health.ts +56 -0
- package/src/commands/doc-drift.ts +56 -0
- package/src/commands/hallucination-risk.ts +51 -0
- package/src/commands/index.ts +4 -1
- package/src/commands/scan.ts +161 -27
- package/src/commands/testability.ts +60 -0
- package/src/index.ts +101 -1
package/dist/cli.mjs
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
__require,
|
|
4
4
|
analyzeUnified
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-JQG7ZATX.mjs";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
8
8
|
import { Command } from "commander";
|
|
9
|
-
import { readFileSync as
|
|
10
|
-
import { join } from "path";
|
|
9
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
10
|
+
import { join, dirname } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
11
12
|
|
|
12
13
|
// src/commands/scan.ts
|
|
13
14
|
import chalk2 from "chalk";
|
|
15
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
14
16
|
import { resolve as resolvePath2 } from "path";
|
|
15
17
|
import {
|
|
16
18
|
loadMergedConfig,
|
|
@@ -52,7 +54,7 @@ function findLatestScanReport(dirPath) {
|
|
|
52
54
|
}
|
|
53
55
|
function warnIfGraphCapExceeded(report, dirPath) {
|
|
54
56
|
try {
|
|
55
|
-
const { loadConfig } = __require("@aiready/core");
|
|
57
|
+
const { loadConfig: loadConfig4 } = __require("@aiready/core");
|
|
56
58
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
57
59
|
const configPath = resolvePath(dirPath, "aiready.json");
|
|
58
60
|
if (existsSync(configPath)) {
|
|
@@ -138,7 +140,7 @@ async function scanAction(directory, options) {
|
|
|
138
140
|
const resolvedDir = resolvePath2(process.cwd(), directory || ".");
|
|
139
141
|
try {
|
|
140
142
|
const defaults = {
|
|
141
|
-
tools: ["patterns", "context", "consistency"],
|
|
143
|
+
tools: ["patterns", "context", "consistency", "hallucination", "grounding", "testability", "doc-drift", "deps-health"],
|
|
142
144
|
include: void 0,
|
|
143
145
|
exclude: void 0,
|
|
144
146
|
output: {
|
|
@@ -146,8 +148,28 @@ async function scanAction(directory, options) {
|
|
|
146
148
|
file: void 0
|
|
147
149
|
}
|
|
148
150
|
};
|
|
151
|
+
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
152
|
+
if (options.profile) {
|
|
153
|
+
switch (options.profile.toLowerCase()) {
|
|
154
|
+
case "agentic":
|
|
155
|
+
profileTools = ["hallucination", "grounding", "testability"];
|
|
156
|
+
break;
|
|
157
|
+
case "cost":
|
|
158
|
+
profileTools = ["patterns", "context"];
|
|
159
|
+
break;
|
|
160
|
+
case "security":
|
|
161
|
+
profileTools = ["consistency", "testability"];
|
|
162
|
+
break;
|
|
163
|
+
case "onboarding":
|
|
164
|
+
profileTools = ["context", "consistency", "grounding"];
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
console.log(chalk2.yellow(`
|
|
168
|
+
\u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
149
171
|
const baseOptions = await loadMergedConfig(resolvedDir, defaults, {
|
|
150
|
-
tools:
|
|
172
|
+
tools: profileTools,
|
|
151
173
|
include: options.include?.split(","),
|
|
152
174
|
exclude: options.exclude?.split(",")
|
|
153
175
|
});
|
|
@@ -279,6 +301,20 @@ async function scanAction(directory, options) {
|
|
|
279
301
|
console.log(chalk2.dim(` ... and ${remaining} more files with issues (use --output json for full details)`));
|
|
280
302
|
}
|
|
281
303
|
}
|
|
304
|
+
} else if (event.tool === "doc-drift") {
|
|
305
|
+
const dr = event.data;
|
|
306
|
+
console.log(` Issues found: ${chalk2.bold(String(dr.issues?.length || 0))}`);
|
|
307
|
+
if (dr.rawData) {
|
|
308
|
+
console.log(` Signature Mismatches: ${chalk2.bold(dr.rawData.outdatedComments || 0)}`);
|
|
309
|
+
console.log(` Undocumented Complexity: ${chalk2.bold(dr.rawData.undocumentedComplexity || 0)}`);
|
|
310
|
+
}
|
|
311
|
+
} else if (event.tool === "deps-health") {
|
|
312
|
+
const dr = event.data;
|
|
313
|
+
console.log(` Packages Analyzed: ${chalk2.bold(String(dr.summary?.packagesAnalyzed || 0))}`);
|
|
314
|
+
if (dr.rawData) {
|
|
315
|
+
console.log(` Deprecated Packages: ${chalk2.bold(dr.rawData.deprecatedPackages || 0)}`);
|
|
316
|
+
console.log(` AI Cutoff Skew Score: ${chalk2.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`);
|
|
317
|
+
}
|
|
282
318
|
}
|
|
283
319
|
} catch (err) {
|
|
284
320
|
}
|
|
@@ -324,11 +360,82 @@ async function scanAction(directory, options) {
|
|
|
324
360
|
} catch (err) {
|
|
325
361
|
}
|
|
326
362
|
}
|
|
363
|
+
if (results.hallucination) {
|
|
364
|
+
const { calculateHallucinationScore } = await import("@aiready/hallucination-risk");
|
|
365
|
+
try {
|
|
366
|
+
const hrScore = calculateHallucinationScore(results.hallucination);
|
|
367
|
+
toolScores.set("hallucination-risk", hrScore);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (results.grounding) {
|
|
372
|
+
const { calculateGroundingScore } = await import("@aiready/agent-grounding");
|
|
373
|
+
try {
|
|
374
|
+
const agScore = calculateGroundingScore(results.grounding);
|
|
375
|
+
toolScores.set("agent-grounding", agScore);
|
|
376
|
+
} catch (err) {
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (results.testability) {
|
|
380
|
+
const { calculateTestabilityScore } = await import("@aiready/testability");
|
|
381
|
+
try {
|
|
382
|
+
const tbScore = calculateTestabilityScore(results.testability);
|
|
383
|
+
toolScores.set("testability", tbScore);
|
|
384
|
+
} catch (err) {
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (results.docDrift) {
|
|
388
|
+
toolScores.set("doc-drift", {
|
|
389
|
+
toolName: "doc-drift",
|
|
390
|
+
score: results.docDrift.summary.score,
|
|
391
|
+
rawMetrics: results.docDrift.rawData,
|
|
392
|
+
factors: [],
|
|
393
|
+
recommendations: results.docDrift.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
if (results.deps) {
|
|
397
|
+
toolScores.set("dependency-health", {
|
|
398
|
+
toolName: "dependency-health",
|
|
399
|
+
score: results.deps.summary.score,
|
|
400
|
+
rawMetrics: results.deps.rawData,
|
|
401
|
+
factors: [],
|
|
402
|
+
recommendations: results.deps.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
403
|
+
});
|
|
404
|
+
}
|
|
327
405
|
const cliWeights = parseWeightString(options.weights);
|
|
328
406
|
if (toolScores.size > 0) {
|
|
329
407
|
scoringResult = calculateOverallScore(toolScores, finalOptions, cliWeights.size ? cliWeights : void 0);
|
|
330
408
|
console.log(chalk2.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
331
409
|
console.log(` ${formatScore(scoringResult)}`);
|
|
410
|
+
if (options.compareTo) {
|
|
411
|
+
try {
|
|
412
|
+
const prevReportStr = readFileSync2(resolvePath2(process.cwd(), options.compareTo), "utf8");
|
|
413
|
+
const prevReport = JSON.parse(prevReportStr);
|
|
414
|
+
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
415
|
+
if (typeof prevScore === "number") {
|
|
416
|
+
const diff = scoringResult.overall - prevScore;
|
|
417
|
+
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
418
|
+
console.log();
|
|
419
|
+
if (diff > 0) {
|
|
420
|
+
console.log(chalk2.green(` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
421
|
+
} else if (diff < 0) {
|
|
422
|
+
console.log(chalk2.red(` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
423
|
+
} else {
|
|
424
|
+
console.log(chalk2.blue(` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
425
|
+
}
|
|
426
|
+
scoringResult.trend = {
|
|
427
|
+
previousScore: prevScore,
|
|
428
|
+
difference: diff
|
|
429
|
+
};
|
|
430
|
+
} else {
|
|
431
|
+
console.log(chalk2.yellow(`
|
|
432
|
+
\u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`));
|
|
433
|
+
}
|
|
434
|
+
} catch (e) {
|
|
435
|
+
console.log(chalk2.yellow(`
|
|
436
|
+
\u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
332
439
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
333
440
|
console.log(chalk2.bold("\nTool breakdown:"));
|
|
334
441
|
scoringResult.breakdown.forEach((tool) => {
|
|
@@ -364,17 +471,17 @@ async function scanAction(directory, options) {
|
|
|
364
471
|
if (process.env.GITHUB_ACTIONS === "true") {
|
|
365
472
|
console.log(`
|
|
366
473
|
::group::AI Readiness Score`);
|
|
367
|
-
console.log(`score=${scoringResult.
|
|
474
|
+
console.log(`score=${scoringResult.overall}`);
|
|
368
475
|
if (scoringResult.breakdown) {
|
|
369
476
|
scoringResult.breakdown.forEach((tool) => {
|
|
370
477
|
console.log(`${tool.toolName}=${tool.score}`);
|
|
371
478
|
});
|
|
372
479
|
}
|
|
373
480
|
console.log("::endgroup::");
|
|
374
|
-
if (threshold && scoringResult.
|
|
375
|
-
console.log(`::error::AI Readiness Score ${scoringResult.
|
|
481
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
482
|
+
console.log(`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`);
|
|
376
483
|
} else if (threshold) {
|
|
377
|
-
console.log(`::notice::AI Readiness Score: ${scoringResult.
|
|
484
|
+
console.log(`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`);
|
|
378
485
|
}
|
|
379
486
|
if (results.patterns) {
|
|
380
487
|
const criticalPatterns = results.patterns.flatMap(
|
|
@@ -387,9 +494,9 @@ async function scanAction(directory, options) {
|
|
|
387
494
|
}
|
|
388
495
|
let shouldFail = false;
|
|
389
496
|
let failReason = "";
|
|
390
|
-
if (threshold && scoringResult.
|
|
497
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
391
498
|
shouldFail = true;
|
|
392
|
-
failReason = `AI Readiness Score ${scoringResult.
|
|
499
|
+
failReason = `AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`;
|
|
393
500
|
}
|
|
394
501
|
if (failOnLevel !== "none") {
|
|
395
502
|
const severityLevels = { critical: 4, major: 3, minor: 2, any: 1 };
|
|
@@ -437,7 +544,7 @@ async function scanAction(directory, options) {
|
|
|
437
544
|
} else {
|
|
438
545
|
console.log(chalk2.green("\n\u2705 PR PASSED: AI Readiness Check"));
|
|
439
546
|
if (threshold) {
|
|
440
|
-
console.log(chalk2.green(` Score: ${scoringResult.
|
|
547
|
+
console.log(chalk2.green(` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`));
|
|
441
548
|
}
|
|
442
549
|
console.log(chalk2.dim("\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"));
|
|
443
550
|
}
|
|
@@ -450,11 +557,20 @@ var scanHelpText = `
|
|
|
450
557
|
EXAMPLES:
|
|
451
558
|
$ aiready scan # Analyze all tools
|
|
452
559
|
$ aiready scan --tools patterns,context # Skip consistency
|
|
560
|
+
$ aiready scan --profile agentic # Optimize for AI agent execution
|
|
561
|
+
$ aiready scan --profile security # Optimize for secure coding (testability)
|
|
562
|
+
$ aiready scan --compare-to prev-report.json # Compare trends against previous run
|
|
453
563
|
$ aiready scan --score --threshold 75 # CI/CD with threshold
|
|
454
564
|
$ aiready scan --ci --threshold 70 # GitHub Actions gatekeeper
|
|
455
565
|
$ aiready scan --ci --fail-on major # Fail on major+ issues
|
|
456
566
|
$ aiready scan --output json --output-file report.json
|
|
457
567
|
|
|
568
|
+
PROFILES:
|
|
569
|
+
agentic: hallucination, grounding, testability
|
|
570
|
+
cost: patterns, context
|
|
571
|
+
security: consistency, testability
|
|
572
|
+
onboarding: context, consistency, grounding
|
|
573
|
+
|
|
458
574
|
CI/CD INTEGRATION (Gatekeeper Mode):
|
|
459
575
|
Use --ci for GitHub Actions integration:
|
|
460
576
|
- Outputs GitHub Actions annotations for PR checks
|
|
@@ -741,7 +857,7 @@ async function contextAction(directory, options) {
|
|
|
741
857
|
|
|
742
858
|
// src/commands/consistency.ts
|
|
743
859
|
import chalk5 from "chalk";
|
|
744
|
-
import { writeFileSync } from "fs";
|
|
860
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
745
861
|
import { resolve as resolvePath5 } from "path";
|
|
746
862
|
import {
|
|
747
863
|
loadMergedConfig as loadMergedConfig4,
|
|
@@ -806,7 +922,7 @@ async function consistencyAction(directory, options) {
|
|
|
806
922
|
`aiready-report-${getReportTimestamp()}.md`,
|
|
807
923
|
resolvedDir
|
|
808
924
|
);
|
|
809
|
-
|
|
925
|
+
writeFileSync2(outputPath, markdown);
|
|
810
926
|
console.log(chalk5.green(`\u2705 Report saved to ${outputPath}`));
|
|
811
927
|
} else {
|
|
812
928
|
console.log(chalk5.bold("\n\u{1F4CA} Summary\n"));
|
|
@@ -893,7 +1009,7 @@ async function consistencyAction(directory, options) {
|
|
|
893
1009
|
|
|
894
1010
|
// src/commands/visualize.ts
|
|
895
1011
|
import chalk6 from "chalk";
|
|
896
|
-
import { writeFileSync as
|
|
1012
|
+
import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync as copyFileSync2 } from "fs";
|
|
897
1013
|
import { resolve as resolvePath6 } from "path";
|
|
898
1014
|
import { spawn } from "child_process";
|
|
899
1015
|
import { handleCLIError as handleCLIError5 } from "@aiready/core";
|
|
@@ -918,13 +1034,13 @@ Or specify a custom report:
|
|
|
918
1034
|
return;
|
|
919
1035
|
}
|
|
920
1036
|
}
|
|
921
|
-
const raw =
|
|
1037
|
+
const raw = readFileSync3(reportPath, "utf8");
|
|
922
1038
|
const report = JSON.parse(raw);
|
|
923
1039
|
const configPath = resolvePath6(dirPath, "aiready.json");
|
|
924
1040
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
925
1041
|
if (existsSync2(configPath)) {
|
|
926
1042
|
try {
|
|
927
|
-
const rawConfig = JSON.parse(
|
|
1043
|
+
const rawConfig = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
928
1044
|
if (rawConfig.visualizer?.graph) {
|
|
929
1045
|
graphConfig = {
|
|
930
1046
|
maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
|
|
@@ -1032,7 +1148,7 @@ Or specify a custom report:
|
|
|
1032
1148
|
const html = generateHTML(graph);
|
|
1033
1149
|
const defaultOutput = "visualization.html";
|
|
1034
1150
|
const outPath = resolvePath6(dirPath, options.output || defaultOutput);
|
|
1035
|
-
|
|
1151
|
+
writeFileSync3(outPath, html, "utf8");
|
|
1036
1152
|
console.log(chalk6.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1037
1153
|
if (options.open || options.serve) {
|
|
1038
1154
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -1104,8 +1220,24 @@ NOTES:
|
|
|
1104
1220
|
- Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
|
|
1105
1221
|
`;
|
|
1106
1222
|
|
|
1223
|
+
// src/commands/hallucination-risk.ts
|
|
1224
|
+
import chalk7 from "chalk";
|
|
1225
|
+
import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
|
|
1226
|
+
|
|
1227
|
+
// src/commands/agent-grounding.ts
|
|
1228
|
+
import chalk8 from "chalk";
|
|
1229
|
+
import { loadConfig as loadConfig2, mergeConfigWithDefaults as mergeConfigWithDefaults2 } from "@aiready/core";
|
|
1230
|
+
|
|
1231
|
+
// src/commands/testability.ts
|
|
1232
|
+
import chalk9 from "chalk";
|
|
1233
|
+
import { loadConfig as loadConfig3, mergeConfigWithDefaults as mergeConfigWithDefaults3 } from "@aiready/core";
|
|
1234
|
+
|
|
1107
1235
|
// src/cli.ts
|
|
1108
|
-
var
|
|
1236
|
+
var getDirname = () => {
|
|
1237
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
1238
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
1239
|
+
};
|
|
1240
|
+
var packageJson = JSON.parse(readFileSync4(join(getDirname(), "../package.json"), "utf8"));
|
|
1109
1241
|
var program = new Command();
|
|
1110
1242
|
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText("after", `
|
|
1111
1243
|
AI READINESS SCORING:
|
|
@@ -1143,7 +1275,7 @@ VERSION: ${packageJson.version}
|
|
|
1143
1275
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
1144
1276
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
1145
1277
|
LANDING: https://github.com/caopengau/aiready-landing`);
|
|
1146
|
-
program.command("scan").description("Run comprehensive AI-readiness analysis (patterns + context + consistency)").argument("[directory]", "Directory to analyze", ".").option("-t, --tools <tools>", "Tools to run (comma-separated: patterns,context,consistency)", "
|
|
1278
|
+
program.command("scan").description("Run comprehensive AI-readiness analysis (patterns + context + consistency)").argument("[directory]", "Directory to analyze", ".").option("-t, --tools <tools>", "Tools to run (comma-separated: patterns,context,consistency,hallucination,grounding,testability)").option("--profile <type>", "Scan profile to use (agentic, cost, security, onboarding)").option("--compare-to <path>", "Compare results against a previous AIReady report JSON").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", "json").option("--output-file <path>", "Output file path (for json)").option("--no-score", "Disable calculating AI Readiness Score (enabled by default)").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option("--ci", "CI mode: GitHub Actions annotations, no colors, fail on threshold").option("--fail-on <level>", "Fail on issues: critical, major, any", "critical").addHelpText("after", scanHelpText).action(async (directory, options) => {
|
|
1147
1279
|
await scanAction(directory, options);
|
|
1148
1280
|
});
|
|
1149
1281
|
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("--max-candidates <number>", "Maximum candidates per block (performance tuning)").option("--min-shared-tokens <number>", "Minimum shared tokens for candidates (performance tuning)").option("--full-scan", "Disable smart defaults for comprehensive analysis (slower)").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("--score", "Calculate and display AI Readiness Score for patterns (0-100)").addHelpText("after", patternsHelpText).action(async (directory, options) => {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "./chunk-Y6FXYEAI.mjs";
|
|
2
|
+
|
|
3
|
+
// src/commands/deps-health.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
|
|
6
|
+
async function depsHealthAction(directory, options) {
|
|
7
|
+
const { analyzeDeps } = await import("@aiready/deps");
|
|
8
|
+
const config = await loadConfig(directory);
|
|
9
|
+
const merged = mergeConfigWithDefaults(config, {
|
|
10
|
+
trainingCutoffYear: 2023
|
|
11
|
+
});
|
|
12
|
+
const report = await analyzeDeps({
|
|
13
|
+
rootDir: directory,
|
|
14
|
+
include: options.include,
|
|
15
|
+
exclude: options.exclude,
|
|
16
|
+
trainingCutoffYear: options.trainingCutoffYear ?? merged.trainingCutoffYear ?? 2023
|
|
17
|
+
});
|
|
18
|
+
const scoring = {
|
|
19
|
+
toolName: "dependency-health",
|
|
20
|
+
score: report.summary.score,
|
|
21
|
+
rawMetrics: report.rawData,
|
|
22
|
+
factors: [],
|
|
23
|
+
recommendations: report.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
24
|
+
};
|
|
25
|
+
if (options.output === "json") {
|
|
26
|
+
return scoring;
|
|
27
|
+
}
|
|
28
|
+
const { summary } = report;
|
|
29
|
+
const ratingColors = {
|
|
30
|
+
excellent: chalk.green,
|
|
31
|
+
good: chalk.blueBright,
|
|
32
|
+
moderate: chalk.yellow,
|
|
33
|
+
poor: chalk.red,
|
|
34
|
+
hazardous: chalk.bgRed.white
|
|
35
|
+
};
|
|
36
|
+
const color = ratingColors[summary.rating] ?? chalk.white;
|
|
37
|
+
console.log(` \u{1F4E6} Dependency Health: ${chalk.bold(scoring.score + "/100 health")} (${color(summary.rating)})`);
|
|
38
|
+
if (report.issues.length > 0) {
|
|
39
|
+
console.log(chalk.dim(` Found ${report.issues.length} dependency issues.`));
|
|
40
|
+
} else {
|
|
41
|
+
console.log(chalk.dim(` Dependencies look healthy for AI assistance.`));
|
|
42
|
+
}
|
|
43
|
+
return scoring;
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
depsHealthAction
|
|
47
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import "./chunk-Y6FXYEAI.mjs";
|
|
2
|
+
|
|
3
|
+
// src/commands/doc-drift.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { loadConfig, mergeConfigWithDefaults } from "@aiready/core";
|
|
6
|
+
async function docDriftAction(directory, options) {
|
|
7
|
+
const { analyzeDocDrift } = await import("@aiready/doc-drift");
|
|
8
|
+
const config = await loadConfig(directory);
|
|
9
|
+
const merged = mergeConfigWithDefaults(config, {
|
|
10
|
+
staleMonths: 6
|
|
11
|
+
});
|
|
12
|
+
const report = await analyzeDocDrift({
|
|
13
|
+
rootDir: directory,
|
|
14
|
+
include: options.include,
|
|
15
|
+
exclude: options.exclude,
|
|
16
|
+
staleMonths: options.staleMonths ?? merged.staleMonths ?? 6
|
|
17
|
+
});
|
|
18
|
+
const scoring = {
|
|
19
|
+
toolName: "doc-drift",
|
|
20
|
+
score: report.summary.score,
|
|
21
|
+
rawMetrics: report.rawData,
|
|
22
|
+
factors: [],
|
|
23
|
+
recommendations: report.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
24
|
+
};
|
|
25
|
+
if (options.output === "json") {
|
|
26
|
+
return scoring;
|
|
27
|
+
}
|
|
28
|
+
const { summary } = report;
|
|
29
|
+
const ratingColors = {
|
|
30
|
+
minimal: chalk.green,
|
|
31
|
+
low: chalk.cyan,
|
|
32
|
+
moderate: chalk.yellow,
|
|
33
|
+
high: chalk.red,
|
|
34
|
+
severe: chalk.bgRed.white
|
|
35
|
+
};
|
|
36
|
+
const color = ratingColors[summary.rating] ?? chalk.white;
|
|
37
|
+
console.log(` \u{1F4DD} Documentation Drift: ${chalk.bold(100 - scoring.score + "/100 health")} (${color(summary.rating)} risk)`);
|
|
38
|
+
if (report.issues.length > 0) {
|
|
39
|
+
console.log(chalk.dim(` Found ${report.issues.length} drift issues.`));
|
|
40
|
+
} else {
|
|
41
|
+
console.log(chalk.dim(` No documentation drift detected.`));
|
|
42
|
+
}
|
|
43
|
+
return scoring;
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
docDriftAction
|
|
47
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -105,6 +115,71 @@ async function analyzeUnified(options) {
|
|
|
105
115
|
result.consistency = report;
|
|
106
116
|
result.summary.totalIssues += report.summary.totalIssues;
|
|
107
117
|
}
|
|
118
|
+
if (tools.includes("doc-drift")) {
|
|
119
|
+
const { analyzeDocDrift } = await import("@aiready/doc-drift");
|
|
120
|
+
const report = await analyzeDocDrift({
|
|
121
|
+
rootDir: options.rootDir,
|
|
122
|
+
include: options.include,
|
|
123
|
+
exclude: options.exclude
|
|
124
|
+
});
|
|
125
|
+
if (options.progressCallback) {
|
|
126
|
+
options.progressCallback({ tool: "doc-drift", data: report });
|
|
127
|
+
}
|
|
128
|
+
result.docDrift = report;
|
|
129
|
+
result.summary.totalIssues += report.issues?.length || 0;
|
|
130
|
+
}
|
|
131
|
+
if (tools.includes("deps-health")) {
|
|
132
|
+
const { analyzeDeps } = await import("@aiready/deps");
|
|
133
|
+
const report = await analyzeDeps({
|
|
134
|
+
rootDir: options.rootDir,
|
|
135
|
+
include: options.include,
|
|
136
|
+
exclude: options.exclude
|
|
137
|
+
});
|
|
138
|
+
if (options.progressCallback) {
|
|
139
|
+
options.progressCallback({ tool: "deps-health", data: report });
|
|
140
|
+
}
|
|
141
|
+
result.deps = report;
|
|
142
|
+
result.summary.totalIssues += report.issues?.length || 0;
|
|
143
|
+
}
|
|
144
|
+
if (tools.includes("hallucination")) {
|
|
145
|
+
const { analyzeHallucinationRisk } = await import("@aiready/hallucination-risk");
|
|
146
|
+
const report = await analyzeHallucinationRisk({
|
|
147
|
+
rootDir: options.rootDir,
|
|
148
|
+
include: options.include,
|
|
149
|
+
exclude: options.exclude
|
|
150
|
+
});
|
|
151
|
+
if (options.progressCallback) {
|
|
152
|
+
options.progressCallback({ tool: "hallucination", data: report });
|
|
153
|
+
}
|
|
154
|
+
result.hallucination = report;
|
|
155
|
+
result.summary.totalIssues += report.results?.reduce((sum, r) => sum + (r.issues?.length || 0), 0) || 0;
|
|
156
|
+
}
|
|
157
|
+
if (tools.includes("grounding")) {
|
|
158
|
+
const { analyzeAgentGrounding } = await import("@aiready/agent-grounding");
|
|
159
|
+
const report = await analyzeAgentGrounding({
|
|
160
|
+
rootDir: options.rootDir,
|
|
161
|
+
include: options.include,
|
|
162
|
+
exclude: options.exclude
|
|
163
|
+
});
|
|
164
|
+
if (options.progressCallback) {
|
|
165
|
+
options.progressCallback({ tool: "grounding", data: report });
|
|
166
|
+
}
|
|
167
|
+
result.grounding = report;
|
|
168
|
+
result.summary.totalIssues += report.issues?.length || 0;
|
|
169
|
+
}
|
|
170
|
+
if (tools.includes("testability")) {
|
|
171
|
+
const { analyzeTestability } = await import("@aiready/testability");
|
|
172
|
+
const report = await analyzeTestability({
|
|
173
|
+
rootDir: options.rootDir,
|
|
174
|
+
include: options.include,
|
|
175
|
+
exclude: options.exclude
|
|
176
|
+
});
|
|
177
|
+
if (options.progressCallback) {
|
|
178
|
+
options.progressCallback({ tool: "testability", data: report });
|
|
179
|
+
}
|
|
180
|
+
result.testability = report;
|
|
181
|
+
result.summary.totalIssues += report.issues?.length || 0;
|
|
182
|
+
}
|
|
108
183
|
result.summary.executionTime = Date.now() - startTime;
|
|
109
184
|
return result;
|
|
110
185
|
}
|
|
@@ -132,6 +207,26 @@ function generateUnifiedSummary(result) {
|
|
|
132
207
|
}
|
|
133
208
|
if (result.consistency) {
|
|
134
209
|
output += `\u{1F3F7}\uFE0F Consistency Analysis: ${result.consistency.summary.totalIssues} issues
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
if (result.docDrift) {
|
|
213
|
+
output += `\u{1F4DD} Doc Drift Analysis: ${result.docDrift.issues?.length || 0} issues
|
|
214
|
+
`;
|
|
215
|
+
}
|
|
216
|
+
if (result.deps) {
|
|
217
|
+
output += `\u{1F4E6} Dependency Health: ${result.deps.issues?.length || 0} issues
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
if (result.hallucination) {
|
|
221
|
+
output += `\u{1F9E0} Hallucination Risk: ${result.hallucination.summary?.totalSignals || 0} signals
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
if (result.grounding) {
|
|
225
|
+
output += `\u{1F9ED} Agent Grounding: ${result.grounding.issues?.length || 0} issues
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
if (result.testability) {
|
|
229
|
+
output += `\u{1F9EA} Testability Index: ${result.testability.issues?.length || 0} issues
|
|
135
230
|
`;
|
|
136
231
|
}
|
|
137
232
|
return output;
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.38",
|
|
4
4
|
"description": "Unified CLI for AIReady analysis tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -9,17 +9,22 @@
|
|
|
9
9
|
"aiready": "./dist/cli.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"commander": "^14.0.0",
|
|
13
12
|
"chalk": "^5.3.0",
|
|
14
|
-
"
|
|
15
|
-
"@aiready/
|
|
16
|
-
"@aiready/
|
|
17
|
-
"@aiready/
|
|
18
|
-
"@aiready/
|
|
13
|
+
"commander": "^14.0.0",
|
|
14
|
+
"@aiready/core": "0.9.30",
|
|
15
|
+
"@aiready/context-analyzer": "0.9.33",
|
|
16
|
+
"@aiready/deps": "0.1.3",
|
|
17
|
+
"@aiready/agent-grounding": "0.1.3",
|
|
18
|
+
"@aiready/consistency": "0.8.29",
|
|
19
|
+
"@aiready/visualizer": "0.1.35",
|
|
20
|
+
"@aiready/testability": "0.1.3",
|
|
21
|
+
"@aiready/pattern-detect": "0.11.29",
|
|
22
|
+
"@aiready/hallucination-risk": "0.1.3",
|
|
23
|
+
"@aiready/doc-drift": "0.1.3"
|
|
19
24
|
},
|
|
20
25
|
"devDependencies": {
|
|
21
|
-
"
|
|
22
|
-
"
|
|
26
|
+
"@types/node": "^24.0.0",
|
|
27
|
+
"tsup": "^8.3.5"
|
|
23
28
|
},
|
|
24
29
|
"keywords": [
|
|
25
30
|
"aiready",
|
package/src/cli.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { readFileSync } from 'fs';
|
|
5
|
-
import { join } from 'path';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
6
7
|
|
|
7
8
|
import {
|
|
8
9
|
scanAction,
|
|
@@ -16,7 +17,12 @@ import {
|
|
|
16
17
|
visualiseHelpText,
|
|
17
18
|
} from './commands';
|
|
18
19
|
|
|
19
|
-
const
|
|
20
|
+
const getDirname = () => {
|
|
21
|
+
if (typeof __dirname !== 'undefined') return __dirname;
|
|
22
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const packageJson = JSON.parse(readFileSync(join(getDirname(), '../package.json'), 'utf8'));
|
|
20
26
|
|
|
21
27
|
const program = new Command();
|
|
22
28
|
|
|
@@ -66,13 +72,15 @@ program
|
|
|
66
72
|
.command('scan')
|
|
67
73
|
.description('Run comprehensive AI-readiness analysis (patterns + context + consistency)')
|
|
68
74
|
.argument('[directory]', 'Directory to analyze', '.')
|
|
69
|
-
.option('-t, --tools <tools>', 'Tools to run (comma-separated: patterns,context,consistency
|
|
75
|
+
.option('-t, --tools <tools>', 'Tools to run (comma-separated: patterns,context,consistency,hallucination,grounding,testability)')
|
|
76
|
+
.option('--profile <type>', 'Scan profile to use (agentic, cost, security, onboarding)')
|
|
77
|
+
.option('--compare-to <path>', 'Compare results against a previous AIReady report JSON')
|
|
70
78
|
.option('--include <patterns>', 'File patterns to include (comma-separated)')
|
|
71
79
|
.option('--exclude <patterns>', 'File patterns to exclude (comma-separated)')
|
|
72
80
|
.option('-o, --output <format>', 'Output format: console, json', 'json')
|
|
73
81
|
.option('--output-file <path>', 'Output file path (for json)')
|
|
74
82
|
.option('--no-score', 'Disable calculating AI Readiness Score (enabled by default)')
|
|
75
|
-
.option('--weights <weights>', 'Custom scoring weights
|
|
83
|
+
.option('--weights <weights>', 'Custom scoring weights')
|
|
76
84
|
.option('--threshold <score>', 'Fail CI/CD if score below threshold (0-100)')
|
|
77
85
|
.option('--ci', 'CI mode: GitHub Actions annotations, no colors, fail on threshold')
|
|
78
86
|
.option('--fail-on <level>', 'Fail on issues: critical, major, any', 'critical')
|