@aiready/cli 0.9.35 → 0.9.36
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 +26 -8
- 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-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 +513 -213
- package/dist/cli.mjs +146 -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 +44 -0
- package/dist/index.mjs +2 -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 +41 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
__require,
|
|
4
3
|
analyzeUnified
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-N4SLON5K.mjs";
|
|
5
|
+
import "./chunk-RBWLQRKR.mjs";
|
|
6
|
+
import "./chunk-YIS6WTY5.mjs";
|
|
7
|
+
import "./chunk-XAF2EW5H.mjs";
|
|
8
|
+
import {
|
|
9
|
+
__require
|
|
10
|
+
} from "./chunk-Y6FXYEAI.mjs";
|
|
6
11
|
|
|
7
12
|
// src/cli.ts
|
|
8
13
|
import { Command } from "commander";
|
|
9
|
-
import { readFileSync as
|
|
10
|
-
import { join } from "path";
|
|
14
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
15
|
+
import { join, dirname } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
11
17
|
|
|
12
18
|
// src/commands/scan.ts
|
|
13
19
|
import chalk2 from "chalk";
|
|
20
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
14
21
|
import { resolve as resolvePath2 } from "path";
|
|
15
22
|
import {
|
|
16
23
|
loadMergedConfig,
|
|
@@ -138,7 +145,7 @@ async function scanAction(directory, options) {
|
|
|
138
145
|
const resolvedDir = resolvePath2(process.cwd(), directory || ".");
|
|
139
146
|
try {
|
|
140
147
|
const defaults = {
|
|
141
|
-
tools: ["patterns", "context", "consistency"],
|
|
148
|
+
tools: ["patterns", "context", "consistency", "hallucination", "grounding", "testability", "doc-drift", "deps-health"],
|
|
142
149
|
include: void 0,
|
|
143
150
|
exclude: void 0,
|
|
144
151
|
output: {
|
|
@@ -146,8 +153,28 @@ async function scanAction(directory, options) {
|
|
|
146
153
|
file: void 0
|
|
147
154
|
}
|
|
148
155
|
};
|
|
156
|
+
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
157
|
+
if (options.profile) {
|
|
158
|
+
switch (options.profile.toLowerCase()) {
|
|
159
|
+
case "agentic":
|
|
160
|
+
profileTools = ["hallucination", "grounding", "testability"];
|
|
161
|
+
break;
|
|
162
|
+
case "cost":
|
|
163
|
+
profileTools = ["patterns", "context"];
|
|
164
|
+
break;
|
|
165
|
+
case "security":
|
|
166
|
+
profileTools = ["consistency", "testability"];
|
|
167
|
+
break;
|
|
168
|
+
case "onboarding":
|
|
169
|
+
profileTools = ["context", "consistency", "grounding"];
|
|
170
|
+
break;
|
|
171
|
+
default:
|
|
172
|
+
console.log(chalk2.yellow(`
|
|
173
|
+
\u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
149
176
|
const baseOptions = await loadMergedConfig(resolvedDir, defaults, {
|
|
150
|
-
tools:
|
|
177
|
+
tools: profileTools,
|
|
151
178
|
include: options.include?.split(","),
|
|
152
179
|
exclude: options.exclude?.split(",")
|
|
153
180
|
});
|
|
@@ -279,6 +306,20 @@ async function scanAction(directory, options) {
|
|
|
279
306
|
console.log(chalk2.dim(` ... and ${remaining} more files with issues (use --output json for full details)`));
|
|
280
307
|
}
|
|
281
308
|
}
|
|
309
|
+
} else if (event.tool === "doc-drift") {
|
|
310
|
+
const dr = event.data;
|
|
311
|
+
console.log(` Issues found: ${chalk2.bold(String(dr.issues?.length || 0))}`);
|
|
312
|
+
if (dr.rawData) {
|
|
313
|
+
console.log(` Signature Mismatches: ${chalk2.bold(dr.rawData.outdatedComments || 0)}`);
|
|
314
|
+
console.log(` Undocumented Complexity: ${chalk2.bold(dr.rawData.undocumentedComplexity || 0)}`);
|
|
315
|
+
}
|
|
316
|
+
} else if (event.tool === "deps-health") {
|
|
317
|
+
const dr = event.data;
|
|
318
|
+
console.log(` Packages Analyzed: ${chalk2.bold(String(dr.summary?.packagesAnalyzed || 0))}`);
|
|
319
|
+
if (dr.rawData) {
|
|
320
|
+
console.log(` Deprecated Packages: ${chalk2.bold(dr.rawData.deprecatedPackages || 0)}`);
|
|
321
|
+
console.log(` AI Cutoff Skew Score: ${chalk2.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`);
|
|
322
|
+
}
|
|
282
323
|
}
|
|
283
324
|
} catch (err) {
|
|
284
325
|
}
|
|
@@ -324,11 +365,82 @@ async function scanAction(directory, options) {
|
|
|
324
365
|
} catch (err) {
|
|
325
366
|
}
|
|
326
367
|
}
|
|
368
|
+
if (finalOptions.tools.includes("hallucination") || finalOptions.tools.includes("hallucination-risk")) {
|
|
369
|
+
try {
|
|
370
|
+
const { hallucinationRiskAction: hallucinationRiskAction2 } = await import("./hallucination-risk-XU6E7IGN.mjs");
|
|
371
|
+
const hrScore = await hallucinationRiskAction2(resolvedDir, { ...finalOptions, output: "json" });
|
|
372
|
+
if (hrScore) toolScores.set("hallucination-risk", hrScore);
|
|
373
|
+
} catch (err) {
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (finalOptions.tools.includes("grounding") || finalOptions.tools.includes("agent-grounding")) {
|
|
377
|
+
try {
|
|
378
|
+
const { agentGroundingAction: agentGroundingAction2 } = await import("./agent-grounding-DAOSU4MF.mjs");
|
|
379
|
+
const agScore = await agentGroundingAction2(resolvedDir, { ...finalOptions, output: "json" });
|
|
380
|
+
if (agScore) toolScores.set("agent-grounding", agScore);
|
|
381
|
+
} catch (err) {
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (finalOptions.tools.includes("testability")) {
|
|
385
|
+
try {
|
|
386
|
+
const { testabilityAction: testabilityAction2 } = await import("./testability-VDZJZ4MF.mjs");
|
|
387
|
+
const tbScore = await testabilityAction2(resolvedDir, { ...finalOptions, output: "json" });
|
|
388
|
+
if (tbScore) toolScores.set("testability", tbScore);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (results.docDrift) {
|
|
393
|
+
toolScores.set("doc-drift", {
|
|
394
|
+
toolName: "doc-drift",
|
|
395
|
+
score: results.docDrift.summary.score,
|
|
396
|
+
rawMetrics: results.docDrift.rawData,
|
|
397
|
+
factors: [],
|
|
398
|
+
recommendations: results.docDrift.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
if (results.deps) {
|
|
402
|
+
toolScores.set("dependency-health", {
|
|
403
|
+
toolName: "dependency-health",
|
|
404
|
+
score: results.deps.summary.score,
|
|
405
|
+
rawMetrics: results.deps.rawData,
|
|
406
|
+
factors: [],
|
|
407
|
+
recommendations: results.deps.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
408
|
+
});
|
|
409
|
+
}
|
|
327
410
|
const cliWeights = parseWeightString(options.weights);
|
|
328
411
|
if (toolScores.size > 0) {
|
|
329
412
|
scoringResult = calculateOverallScore(toolScores, finalOptions, cliWeights.size ? cliWeights : void 0);
|
|
330
413
|
console.log(chalk2.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
331
414
|
console.log(` ${formatScore(scoringResult)}`);
|
|
415
|
+
if (options.compareTo) {
|
|
416
|
+
try {
|
|
417
|
+
const prevReportStr = readFileSync2(resolvePath2(process.cwd(), options.compareTo), "utf8");
|
|
418
|
+
const prevReport = JSON.parse(prevReportStr);
|
|
419
|
+
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
420
|
+
if (typeof prevScore === "number") {
|
|
421
|
+
const diff = scoringResult.overall - prevScore;
|
|
422
|
+
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
423
|
+
console.log();
|
|
424
|
+
if (diff > 0) {
|
|
425
|
+
console.log(chalk2.green(` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
426
|
+
} else if (diff < 0) {
|
|
427
|
+
console.log(chalk2.red(` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
428
|
+
} else {
|
|
429
|
+
console.log(chalk2.blue(` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
430
|
+
}
|
|
431
|
+
scoringResult.trend = {
|
|
432
|
+
previousScore: prevScore,
|
|
433
|
+
difference: diff
|
|
434
|
+
};
|
|
435
|
+
} else {
|
|
436
|
+
console.log(chalk2.yellow(`
|
|
437
|
+
\u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`));
|
|
438
|
+
}
|
|
439
|
+
} catch (e) {
|
|
440
|
+
console.log(chalk2.yellow(`
|
|
441
|
+
\u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
332
444
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
333
445
|
console.log(chalk2.bold("\nTool breakdown:"));
|
|
334
446
|
scoringResult.breakdown.forEach((tool) => {
|
|
@@ -364,17 +476,17 @@ async function scanAction(directory, options) {
|
|
|
364
476
|
if (process.env.GITHUB_ACTIONS === "true") {
|
|
365
477
|
console.log(`
|
|
366
478
|
::group::AI Readiness Score`);
|
|
367
|
-
console.log(`score=${scoringResult.
|
|
479
|
+
console.log(`score=${scoringResult.overall}`);
|
|
368
480
|
if (scoringResult.breakdown) {
|
|
369
481
|
scoringResult.breakdown.forEach((tool) => {
|
|
370
482
|
console.log(`${tool.toolName}=${tool.score}`);
|
|
371
483
|
});
|
|
372
484
|
}
|
|
373
485
|
console.log("::endgroup::");
|
|
374
|
-
if (threshold && scoringResult.
|
|
375
|
-
console.log(`::error::AI Readiness Score ${scoringResult.
|
|
486
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
487
|
+
console.log(`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`);
|
|
376
488
|
} else if (threshold) {
|
|
377
|
-
console.log(`::notice::AI Readiness Score: ${scoringResult.
|
|
489
|
+
console.log(`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`);
|
|
378
490
|
}
|
|
379
491
|
if (results.patterns) {
|
|
380
492
|
const criticalPatterns = results.patterns.flatMap(
|
|
@@ -387,9 +499,9 @@ async function scanAction(directory, options) {
|
|
|
387
499
|
}
|
|
388
500
|
let shouldFail = false;
|
|
389
501
|
let failReason = "";
|
|
390
|
-
if (threshold && scoringResult.
|
|
502
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
391
503
|
shouldFail = true;
|
|
392
|
-
failReason = `AI Readiness Score ${scoringResult.
|
|
504
|
+
failReason = `AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`;
|
|
393
505
|
}
|
|
394
506
|
if (failOnLevel !== "none") {
|
|
395
507
|
const severityLevels = { critical: 4, major: 3, minor: 2, any: 1 };
|
|
@@ -437,7 +549,7 @@ async function scanAction(directory, options) {
|
|
|
437
549
|
} else {
|
|
438
550
|
console.log(chalk2.green("\n\u2705 PR PASSED: AI Readiness Check"));
|
|
439
551
|
if (threshold) {
|
|
440
|
-
console.log(chalk2.green(` Score: ${scoringResult.
|
|
552
|
+
console.log(chalk2.green(` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`));
|
|
441
553
|
}
|
|
442
554
|
console.log(chalk2.dim("\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"));
|
|
443
555
|
}
|
|
@@ -450,11 +562,20 @@ var scanHelpText = `
|
|
|
450
562
|
EXAMPLES:
|
|
451
563
|
$ aiready scan # Analyze all tools
|
|
452
564
|
$ aiready scan --tools patterns,context # Skip consistency
|
|
565
|
+
$ aiready scan --profile agentic # Optimize for AI agent execution
|
|
566
|
+
$ aiready scan --profile security # Optimize for secure coding (testability)
|
|
567
|
+
$ aiready scan --compare-to prev-report.json # Compare trends against previous run
|
|
453
568
|
$ aiready scan --score --threshold 75 # CI/CD with threshold
|
|
454
569
|
$ aiready scan --ci --threshold 70 # GitHub Actions gatekeeper
|
|
455
570
|
$ aiready scan --ci --fail-on major # Fail on major+ issues
|
|
456
571
|
$ aiready scan --output json --output-file report.json
|
|
457
572
|
|
|
573
|
+
PROFILES:
|
|
574
|
+
agentic: hallucination, grounding, testability
|
|
575
|
+
cost: patterns, context
|
|
576
|
+
security: consistency, testability
|
|
577
|
+
onboarding: context, consistency, grounding
|
|
578
|
+
|
|
458
579
|
CI/CD INTEGRATION (Gatekeeper Mode):
|
|
459
580
|
Use --ci for GitHub Actions integration:
|
|
460
581
|
- Outputs GitHub Actions annotations for PR checks
|
|
@@ -741,7 +862,7 @@ async function contextAction(directory, options) {
|
|
|
741
862
|
|
|
742
863
|
// src/commands/consistency.ts
|
|
743
864
|
import chalk5 from "chalk";
|
|
744
|
-
import { writeFileSync } from "fs";
|
|
865
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
745
866
|
import { resolve as resolvePath5 } from "path";
|
|
746
867
|
import {
|
|
747
868
|
loadMergedConfig as loadMergedConfig4,
|
|
@@ -806,7 +927,7 @@ async function consistencyAction(directory, options) {
|
|
|
806
927
|
`aiready-report-${getReportTimestamp()}.md`,
|
|
807
928
|
resolvedDir
|
|
808
929
|
);
|
|
809
|
-
|
|
930
|
+
writeFileSync2(outputPath, markdown);
|
|
810
931
|
console.log(chalk5.green(`\u2705 Report saved to ${outputPath}`));
|
|
811
932
|
} else {
|
|
812
933
|
console.log(chalk5.bold("\n\u{1F4CA} Summary\n"));
|
|
@@ -893,7 +1014,7 @@ async function consistencyAction(directory, options) {
|
|
|
893
1014
|
|
|
894
1015
|
// src/commands/visualize.ts
|
|
895
1016
|
import chalk6 from "chalk";
|
|
896
|
-
import { writeFileSync as
|
|
1017
|
+
import { writeFileSync as writeFileSync3, readFileSync as readFileSync3, existsSync as existsSync2, copyFileSync as copyFileSync2 } from "fs";
|
|
897
1018
|
import { resolve as resolvePath6 } from "path";
|
|
898
1019
|
import { spawn } from "child_process";
|
|
899
1020
|
import { handleCLIError as handleCLIError5 } from "@aiready/core";
|
|
@@ -918,13 +1039,13 @@ Or specify a custom report:
|
|
|
918
1039
|
return;
|
|
919
1040
|
}
|
|
920
1041
|
}
|
|
921
|
-
const raw =
|
|
1042
|
+
const raw = readFileSync3(reportPath, "utf8");
|
|
922
1043
|
const report = JSON.parse(raw);
|
|
923
1044
|
const configPath = resolvePath6(dirPath, "aiready.json");
|
|
924
1045
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
925
1046
|
if (existsSync2(configPath)) {
|
|
926
1047
|
try {
|
|
927
|
-
const rawConfig = JSON.parse(
|
|
1048
|
+
const rawConfig = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
928
1049
|
if (rawConfig.visualizer?.graph) {
|
|
929
1050
|
graphConfig = {
|
|
930
1051
|
maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
|
|
@@ -1032,7 +1153,7 @@ Or specify a custom report:
|
|
|
1032
1153
|
const html = generateHTML(graph);
|
|
1033
1154
|
const defaultOutput = "visualization.html";
|
|
1034
1155
|
const outPath = resolvePath6(dirPath, options.output || defaultOutput);
|
|
1035
|
-
|
|
1156
|
+
writeFileSync3(outPath, html, "utf8");
|
|
1036
1157
|
console.log(chalk6.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1037
1158
|
if (options.open || options.serve) {
|
|
1038
1159
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -1105,7 +1226,11 @@ NOTES:
|
|
|
1105
1226
|
`;
|
|
1106
1227
|
|
|
1107
1228
|
// src/cli.ts
|
|
1108
|
-
var
|
|
1229
|
+
var getDirname = () => {
|
|
1230
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
1231
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
1232
|
+
};
|
|
1233
|
+
var packageJson = JSON.parse(readFileSync4(join(getDirname(), "../package.json"), "utf8"));
|
|
1109
1234
|
var program = new Command();
|
|
1110
1235
|
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText("after", `
|
|
1111
1236
|
AI READINESS SCORING:
|
|
@@ -1143,7 +1268,7 @@ VERSION: ${packageJson.version}
|
|
|
1143
1268
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
1144
1269
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
1145
1270
|
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)", "
|
|
1271
|
+
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
1272
|
await scanAction(directory, options);
|
|
1148
1273
|
});
|
|
1149
1274
|
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,32 @@ 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
|
+
}
|
|
108
144
|
result.summary.executionTime = Date.now() - startTime;
|
|
109
145
|
return result;
|
|
110
146
|
}
|
|
@@ -132,6 +168,14 @@ function generateUnifiedSummary(result) {
|
|
|
132
168
|
}
|
|
133
169
|
if (result.consistency) {
|
|
134
170
|
output += `\u{1F3F7}\uFE0F Consistency Analysis: ${result.consistency.summary.totalIssues} issues
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
if (result.docDrift) {
|
|
174
|
+
output += `\u{1F4DD} Doc Drift Analysis: ${result.docDrift.issues?.length || 0} issues
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
if (result.deps) {
|
|
178
|
+
output += `\u{1F4E6} Dependency Health: ${result.deps.issues?.length || 0} issues
|
|
135
179
|
`;
|
|
136
180
|
}
|
|
137
181
|
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.36",
|
|
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/consistency": "0.8.27",
|
|
15
|
+
"@aiready/context-analyzer": "0.9.31",
|
|
16
|
+
"@aiready/core": "0.9.28",
|
|
17
|
+
"@aiready/deps": "0.1.1",
|
|
18
|
+
"@aiready/agent-grounding": "0.1.1",
|
|
19
|
+
"@aiready/doc-drift": "0.1.1",
|
|
20
|
+
"@aiready/pattern-detect": "0.11.27",
|
|
21
|
+
"@aiready/testability": "0.1.1",
|
|
22
|
+
"@aiready/visualizer": "0.1.33",
|
|
23
|
+
"@aiready/hallucination-risk": "0.1.1"
|
|
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')
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent grounding command for unified CLI
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { loadConfig, mergeConfigWithDefaults } from '@aiready/core';
|
|
7
|
+
import type { ToolScoringOutput } from '@aiready/core';
|
|
8
|
+
|
|
9
|
+
export async function agentGroundingAction(
|
|
10
|
+
directory: string,
|
|
11
|
+
options: any,
|
|
12
|
+
): Promise<ToolScoringOutput | undefined> {
|
|
13
|
+
const { analyzeAgentGrounding, calculateGroundingScore } = await import('@aiready/agent-grounding');
|
|
14
|
+
|
|
15
|
+
const config = await loadConfig(directory);
|
|
16
|
+
const merged = mergeConfigWithDefaults(config, {
|
|
17
|
+
maxRecommendedDepth: 4,
|
|
18
|
+
readmeStaleDays: 90,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const report = await analyzeAgentGrounding({
|
|
22
|
+
rootDir: directory,
|
|
23
|
+
maxRecommendedDepth: options.maxDepth ?? merged.maxRecommendedDepth,
|
|
24
|
+
readmeStaleDays: options.readmeStaleDays ?? merged.readmeStaleDays,
|
|
25
|
+
include: options.include,
|
|
26
|
+
exclude: options.exclude,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const scoring = calculateGroundingScore(report);
|
|
30
|
+
|
|
31
|
+
if (options.output === 'json') {
|
|
32
|
+
return scoring;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const scoreColor = (s: number) =>
|
|
36
|
+
s >= 85 ? chalk.green : s >= 70 ? chalk.cyan : s >= 50 ? chalk.yellow : chalk.red;
|
|
37
|
+
|
|
38
|
+
console.log(` 🧭 Agent Grounding: ${chalk.bold(scoring.score + '/100')} (${report.summary.rating})`);
|
|
39
|
+
const dims = report.summary.dimensions;
|
|
40
|
+
const worstDim = Object.entries(dims).sort(([, a], [, b]) => a - b)[0];
|
|
41
|
+
if (worstDim && worstDim[1] < 70) {
|
|
42
|
+
const name = worstDim[0].replace(/([A-Z])/g, ' $1').replace('Score', '').trim();
|
|
43
|
+
console.log(chalk.dim(` Weakest dimension: ${name} (${worstDim[1]}/100)`));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return scoring;
|
|
47
|
+
}
|