@aiready/cli 0.9.33 → 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.js
CHANGED
|
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
9
16
|
var __copyProps = (to, from, except, desc) => {
|
|
10
17
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
18
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,15 +30,158 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
30
|
mod
|
|
24
31
|
));
|
|
25
32
|
|
|
33
|
+
// src/commands/hallucination-risk.ts
|
|
34
|
+
var hallucination_risk_exports = {};
|
|
35
|
+
__export(hallucination_risk_exports, {
|
|
36
|
+
hallucinationRiskAction: () => hallucinationRiskAction
|
|
37
|
+
});
|
|
38
|
+
async function hallucinationRiskAction(directory, options) {
|
|
39
|
+
const { analyzeHallucinationRisk, calculateHallucinationScore } = await import("@aiready/hallucination-risk");
|
|
40
|
+
const config = await (0, import_core.loadConfig)(directory);
|
|
41
|
+
const merged = (0, import_core.mergeConfigWithDefaults)(config, {
|
|
42
|
+
minSeverity: "info"
|
|
43
|
+
});
|
|
44
|
+
const report = await analyzeHallucinationRisk({
|
|
45
|
+
rootDir: directory,
|
|
46
|
+
minSeverity: options.minSeverity ?? merged.minSeverity ?? "info",
|
|
47
|
+
include: options.include,
|
|
48
|
+
exclude: options.exclude
|
|
49
|
+
});
|
|
50
|
+
const scoring = calculateHallucinationScore(report);
|
|
51
|
+
if (options.output === "json") {
|
|
52
|
+
return scoring;
|
|
53
|
+
}
|
|
54
|
+
const { summary } = report;
|
|
55
|
+
const ratingColors = {
|
|
56
|
+
minimal: import_chalk2.default.green,
|
|
57
|
+
low: import_chalk2.default.cyan,
|
|
58
|
+
moderate: import_chalk2.default.yellow,
|
|
59
|
+
high: import_chalk2.default.red,
|
|
60
|
+
severe: import_chalk2.default.bgRed.white
|
|
61
|
+
};
|
|
62
|
+
const color = ratingColors[summary.rating] ?? import_chalk2.default.white;
|
|
63
|
+
console.log(` \u{1F9E0} Hallucination Risk: ${import_chalk2.default.bold(scoring.score + "/100")} (${color(summary.rating)})`);
|
|
64
|
+
console.log(` Top Risk: ${import_chalk2.default.italic(summary.topRisk)}`);
|
|
65
|
+
if (summary.totalSignals > 0) {
|
|
66
|
+
console.log(import_chalk2.default.dim(` ${summary.criticalSignals} critical ${summary.majorSignals} major ${summary.minorSignals} minor signals`));
|
|
67
|
+
}
|
|
68
|
+
return scoring;
|
|
69
|
+
}
|
|
70
|
+
var import_chalk2, import_core;
|
|
71
|
+
var init_hallucination_risk = __esm({
|
|
72
|
+
"src/commands/hallucination-risk.ts"() {
|
|
73
|
+
"use strict";
|
|
74
|
+
import_chalk2 = __toESM(require("chalk"));
|
|
75
|
+
import_core = require("@aiready/core");
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// src/commands/agent-grounding.ts
|
|
80
|
+
var agent_grounding_exports = {};
|
|
81
|
+
__export(agent_grounding_exports, {
|
|
82
|
+
agentGroundingAction: () => agentGroundingAction
|
|
83
|
+
});
|
|
84
|
+
async function agentGroundingAction(directory, options) {
|
|
85
|
+
const { analyzeAgentGrounding, calculateGroundingScore } = await import("@aiready/agent-grounding");
|
|
86
|
+
const config = await (0, import_core2.loadConfig)(directory);
|
|
87
|
+
const merged = (0, import_core2.mergeConfigWithDefaults)(config, {
|
|
88
|
+
maxRecommendedDepth: 4,
|
|
89
|
+
readmeStaleDays: 90
|
|
90
|
+
});
|
|
91
|
+
const report = await analyzeAgentGrounding({
|
|
92
|
+
rootDir: directory,
|
|
93
|
+
maxRecommendedDepth: options.maxDepth ?? merged.maxRecommendedDepth,
|
|
94
|
+
readmeStaleDays: options.readmeStaleDays ?? merged.readmeStaleDays,
|
|
95
|
+
include: options.include,
|
|
96
|
+
exclude: options.exclude
|
|
97
|
+
});
|
|
98
|
+
const scoring = calculateGroundingScore(report);
|
|
99
|
+
if (options.output === "json") {
|
|
100
|
+
return scoring;
|
|
101
|
+
}
|
|
102
|
+
const scoreColor = (s) => s >= 85 ? import_chalk3.default.green : s >= 70 ? import_chalk3.default.cyan : s >= 50 ? import_chalk3.default.yellow : import_chalk3.default.red;
|
|
103
|
+
console.log(` \u{1F9ED} Agent Grounding: ${import_chalk3.default.bold(scoring.score + "/100")} (${report.summary.rating})`);
|
|
104
|
+
const dims = report.summary.dimensions;
|
|
105
|
+
const worstDim = Object.entries(dims).sort(([, a], [, b]) => a - b)[0];
|
|
106
|
+
if (worstDim && worstDim[1] < 70) {
|
|
107
|
+
const name = worstDim[0].replace(/([A-Z])/g, " $1").replace("Score", "").trim();
|
|
108
|
+
console.log(import_chalk3.default.dim(` Weakest dimension: ${name} (${worstDim[1]}/100)`));
|
|
109
|
+
}
|
|
110
|
+
return scoring;
|
|
111
|
+
}
|
|
112
|
+
var import_chalk3, import_core2;
|
|
113
|
+
var init_agent_grounding = __esm({
|
|
114
|
+
"src/commands/agent-grounding.ts"() {
|
|
115
|
+
"use strict";
|
|
116
|
+
import_chalk3 = __toESM(require("chalk"));
|
|
117
|
+
import_core2 = require("@aiready/core");
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// src/commands/testability.ts
|
|
122
|
+
var testability_exports = {};
|
|
123
|
+
__export(testability_exports, {
|
|
124
|
+
testabilityAction: () => testabilityAction
|
|
125
|
+
});
|
|
126
|
+
async function testabilityAction(directory, options) {
|
|
127
|
+
const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
|
|
128
|
+
const config = await (0, import_core3.loadConfig)(directory);
|
|
129
|
+
const merged = (0, import_core3.mergeConfigWithDefaults)(config, {
|
|
130
|
+
minCoverageRatio: 0.3
|
|
131
|
+
});
|
|
132
|
+
const report = await analyzeTestability({
|
|
133
|
+
rootDir: directory,
|
|
134
|
+
minCoverageRatio: options.minCoverageRatio ?? merged.minCoverageRatio,
|
|
135
|
+
include: options.include,
|
|
136
|
+
exclude: options.exclude
|
|
137
|
+
});
|
|
138
|
+
const scoring = calculateTestabilityScore(report);
|
|
139
|
+
if (options.output === "json") {
|
|
140
|
+
return scoring;
|
|
141
|
+
}
|
|
142
|
+
const safetyIcons = {
|
|
143
|
+
"safe": "\u2705",
|
|
144
|
+
"moderate-risk": "\u26A0\uFE0F ",
|
|
145
|
+
"high-risk": "\u{1F534}",
|
|
146
|
+
"blind-risk": "\u{1F480}"
|
|
147
|
+
};
|
|
148
|
+
const safetyColors = {
|
|
149
|
+
"safe": import_chalk4.default.green,
|
|
150
|
+
"moderate-risk": import_chalk4.default.yellow,
|
|
151
|
+
"high-risk": import_chalk4.default.red,
|
|
152
|
+
"blind-risk": import_chalk4.default.bgRed.white
|
|
153
|
+
};
|
|
154
|
+
const safety = report.summary.aiChangeSafetyRating;
|
|
155
|
+
const icon = safetyIcons[safety] ?? "\u2753";
|
|
156
|
+
const color = safetyColors[safety] ?? import_chalk4.default.white;
|
|
157
|
+
console.log(` \u{1F9EA} Testability: ${import_chalk4.default.bold(scoring.score + "/100")} (${report.summary.rating})`);
|
|
158
|
+
console.log(` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`);
|
|
159
|
+
console.log(import_chalk4.default.dim(` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`));
|
|
160
|
+
if (safety === "blind-risk") {
|
|
161
|
+
console.log(import_chalk4.default.red.bold("\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"));
|
|
162
|
+
}
|
|
163
|
+
return scoring;
|
|
164
|
+
}
|
|
165
|
+
var import_chalk4, import_core3;
|
|
166
|
+
var init_testability = __esm({
|
|
167
|
+
"src/commands/testability.ts"() {
|
|
168
|
+
"use strict";
|
|
169
|
+
import_chalk4 = __toESM(require("chalk"));
|
|
170
|
+
import_core3 = require("@aiready/core");
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
26
174
|
// src/cli.ts
|
|
27
175
|
var import_commander = require("commander");
|
|
28
|
-
var
|
|
176
|
+
var import_fs5 = require("fs");
|
|
29
177
|
var import_path7 = require("path");
|
|
178
|
+
var import_url = require("url");
|
|
30
179
|
|
|
31
180
|
// src/commands/scan.ts
|
|
32
|
-
var
|
|
181
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
182
|
+
var import_fs2 = require("fs");
|
|
33
183
|
var import_path2 = require("path");
|
|
34
|
-
var
|
|
184
|
+
var import_core4 = require("@aiready/core");
|
|
35
185
|
|
|
36
186
|
// src/index.ts
|
|
37
187
|
var import_pattern_detect = require("@aiready/pattern-detect");
|
|
@@ -115,6 +265,32 @@ async function analyzeUnified(options) {
|
|
|
115
265
|
result.consistency = report;
|
|
116
266
|
result.summary.totalIssues += report.summary.totalIssues;
|
|
117
267
|
}
|
|
268
|
+
if (tools.includes("doc-drift")) {
|
|
269
|
+
const { analyzeDocDrift } = await import("@aiready/doc-drift");
|
|
270
|
+
const report = await analyzeDocDrift({
|
|
271
|
+
rootDir: options.rootDir,
|
|
272
|
+
include: options.include,
|
|
273
|
+
exclude: options.exclude
|
|
274
|
+
});
|
|
275
|
+
if (options.progressCallback) {
|
|
276
|
+
options.progressCallback({ tool: "doc-drift", data: report });
|
|
277
|
+
}
|
|
278
|
+
result.docDrift = report;
|
|
279
|
+
result.summary.totalIssues += report.issues?.length || 0;
|
|
280
|
+
}
|
|
281
|
+
if (tools.includes("deps-health")) {
|
|
282
|
+
const { analyzeDeps } = await import("@aiready/deps");
|
|
283
|
+
const report = await analyzeDeps({
|
|
284
|
+
rootDir: options.rootDir,
|
|
285
|
+
include: options.include,
|
|
286
|
+
exclude: options.exclude
|
|
287
|
+
});
|
|
288
|
+
if (options.progressCallback) {
|
|
289
|
+
options.progressCallback({ tool: "deps-health", data: report });
|
|
290
|
+
}
|
|
291
|
+
result.deps = report;
|
|
292
|
+
result.summary.totalIssues += report.issues?.length || 0;
|
|
293
|
+
}
|
|
118
294
|
result.summary.executionTime = Date.now() - startTime;
|
|
119
295
|
return result;
|
|
120
296
|
}
|
|
@@ -145,7 +321,7 @@ function findLatestScanReport(dirPath) {
|
|
|
145
321
|
}
|
|
146
322
|
function warnIfGraphCapExceeded(report, dirPath) {
|
|
147
323
|
try {
|
|
148
|
-
const { loadConfig } = require("@aiready/core");
|
|
324
|
+
const { loadConfig: loadConfig4 } = require("@aiready/core");
|
|
149
325
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
150
326
|
const configPath = (0, import_path.resolve)(dirPath, "aiready.json");
|
|
151
327
|
if ((0, import_fs.existsSync)(configPath)) {
|
|
@@ -226,12 +402,12 @@ function truncateArray(arr, cap = 8) {
|
|
|
226
402
|
|
|
227
403
|
// src/commands/scan.ts
|
|
228
404
|
async function scanAction(directory, options) {
|
|
229
|
-
console.log(
|
|
405
|
+
console.log(import_chalk5.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
230
406
|
const startTime = Date.now();
|
|
231
407
|
const resolvedDir = (0, import_path2.resolve)(process.cwd(), directory || ".");
|
|
232
408
|
try {
|
|
233
409
|
const defaults = {
|
|
234
|
-
tools: ["patterns", "context", "consistency"],
|
|
410
|
+
tools: ["patterns", "context", "consistency", "hallucination", "grounding", "testability", "doc-drift", "deps-health"],
|
|
235
411
|
include: void 0,
|
|
236
412
|
exclude: void 0,
|
|
237
413
|
output: {
|
|
@@ -239,8 +415,28 @@ async function scanAction(directory, options) {
|
|
|
239
415
|
file: void 0
|
|
240
416
|
}
|
|
241
417
|
};
|
|
242
|
-
|
|
243
|
-
|
|
418
|
+
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
419
|
+
if (options.profile) {
|
|
420
|
+
switch (options.profile.toLowerCase()) {
|
|
421
|
+
case "agentic":
|
|
422
|
+
profileTools = ["hallucination", "grounding", "testability"];
|
|
423
|
+
break;
|
|
424
|
+
case "cost":
|
|
425
|
+
profileTools = ["patterns", "context"];
|
|
426
|
+
break;
|
|
427
|
+
case "security":
|
|
428
|
+
profileTools = ["consistency", "testability"];
|
|
429
|
+
break;
|
|
430
|
+
case "onboarding":
|
|
431
|
+
profileTools = ["context", "consistency", "grounding"];
|
|
432
|
+
break;
|
|
433
|
+
default:
|
|
434
|
+
console.log(import_chalk5.default.yellow(`
|
|
435
|
+
\u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const baseOptions = await (0, import_core4.loadMergedConfig)(resolvedDir, defaults, {
|
|
439
|
+
tools: profileTools,
|
|
244
440
|
include: options.include?.split(","),
|
|
245
441
|
exclude: options.exclude?.split(",")
|
|
246
442
|
});
|
|
@@ -250,13 +446,13 @@ async function scanAction(directory, options) {
|
|
|
250
446
|
const patternSmartDefaults = await getSmartDefaults(resolvedDir, baseOptions);
|
|
251
447
|
finalOptions = { ...patternSmartDefaults, ...finalOptions, ...baseOptions };
|
|
252
448
|
}
|
|
253
|
-
console.log(
|
|
254
|
-
console.log(
|
|
255
|
-
console.log(
|
|
256
|
-
console.log(
|
|
257
|
-
if (finalOptions.rootDir) console.log(` rootDir: ${
|
|
258
|
-
if (finalOptions.include) console.log(` include: ${
|
|
259
|
-
if (finalOptions.exclude) console.log(` exclude: ${
|
|
449
|
+
console.log(import_chalk5.default.cyan("\n=== AIReady Run Preview ==="));
|
|
450
|
+
console.log(import_chalk5.default.white("Tools to run:"), (finalOptions.tools || ["patterns", "context", "consistency"]).join(", "));
|
|
451
|
+
console.log(import_chalk5.default.white("Will use settings from config and defaults."));
|
|
452
|
+
console.log(import_chalk5.default.white("\nGeneral settings:"));
|
|
453
|
+
if (finalOptions.rootDir) console.log(` rootDir: ${import_chalk5.default.bold(String(finalOptions.rootDir))}`);
|
|
454
|
+
if (finalOptions.include) console.log(` include: ${import_chalk5.default.bold(truncateArray(finalOptions.include, 6))}`);
|
|
455
|
+
if (finalOptions.exclude) console.log(` exclude: ${import_chalk5.default.bold(truncateArray(finalOptions.exclude, 6))}`);
|
|
260
456
|
if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
|
|
261
457
|
const patternDetectConfig = finalOptions["pattern-detect"] || {
|
|
262
458
|
minSimilarity: finalOptions.minSimilarity,
|
|
@@ -269,16 +465,16 @@ async function scanAction(directory, options) {
|
|
|
269
465
|
severity: finalOptions.severity,
|
|
270
466
|
includeTests: finalOptions.includeTests
|
|
271
467
|
};
|
|
272
|
-
console.log(
|
|
273
|
-
console.log(` minSimilarity: ${
|
|
274
|
-
console.log(` minLines: ${
|
|
275
|
-
if (patternDetectConfig.approx !== void 0) console.log(` approx: ${
|
|
276
|
-
if (patternDetectConfig.minSharedTokens !== void 0) console.log(` minSharedTokens: ${
|
|
277
|
-
if (patternDetectConfig.maxCandidatesPerBlock !== void 0) console.log(` maxCandidatesPerBlock: ${
|
|
278
|
-
if (patternDetectConfig.batchSize !== void 0) console.log(` batchSize: ${
|
|
279
|
-
if (patternDetectConfig.streamResults !== void 0) console.log(` streamResults: ${
|
|
280
|
-
if (patternDetectConfig.severity !== void 0) console.log(` severity: ${
|
|
281
|
-
if (patternDetectConfig.includeTests !== void 0) console.log(` includeTests: ${
|
|
468
|
+
console.log(import_chalk5.default.white("\nPattern-detect settings:"));
|
|
469
|
+
console.log(` minSimilarity: ${import_chalk5.default.bold(patternDetectConfig.minSimilarity ?? "default")}`);
|
|
470
|
+
console.log(` minLines: ${import_chalk5.default.bold(patternDetectConfig.minLines ?? "default")}`);
|
|
471
|
+
if (patternDetectConfig.approx !== void 0) console.log(` approx: ${import_chalk5.default.bold(String(patternDetectConfig.approx))}`);
|
|
472
|
+
if (patternDetectConfig.minSharedTokens !== void 0) console.log(` minSharedTokens: ${import_chalk5.default.bold(String(patternDetectConfig.minSharedTokens))}`);
|
|
473
|
+
if (patternDetectConfig.maxCandidatesPerBlock !== void 0) console.log(` maxCandidatesPerBlock: ${import_chalk5.default.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`);
|
|
474
|
+
if (patternDetectConfig.batchSize !== void 0) console.log(` batchSize: ${import_chalk5.default.bold(String(patternDetectConfig.batchSize))}`);
|
|
475
|
+
if (patternDetectConfig.streamResults !== void 0) console.log(` streamResults: ${import_chalk5.default.bold(String(patternDetectConfig.streamResults))}`);
|
|
476
|
+
if (patternDetectConfig.severity !== void 0) console.log(` severity: ${import_chalk5.default.bold(String(patternDetectConfig.severity))}`);
|
|
477
|
+
if (patternDetectConfig.includeTests !== void 0) console.log(` includeTests: ${import_chalk5.default.bold(String(patternDetectConfig.includeTests))}`);
|
|
282
478
|
}
|
|
283
479
|
if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
|
|
284
480
|
const ca = finalOptions["context-analyzer"] || {
|
|
@@ -288,32 +484,32 @@ async function scanAction(directory, options) {
|
|
|
288
484
|
maxFragmentation: finalOptions.maxFragmentation,
|
|
289
485
|
includeNodeModules: finalOptions.includeNodeModules
|
|
290
486
|
};
|
|
291
|
-
console.log(
|
|
292
|
-
console.log(` maxDepth: ${
|
|
293
|
-
console.log(` maxContextBudget: ${
|
|
294
|
-
if (ca.minCohesion !== void 0) console.log(` minCohesion: ${
|
|
295
|
-
if (ca.maxFragmentation !== void 0) console.log(` maxFragmentation: ${
|
|
296
|
-
if (ca.includeNodeModules !== void 0) console.log(` includeNodeModules: ${
|
|
487
|
+
console.log(import_chalk5.default.white("\nContext-analyzer settings:"));
|
|
488
|
+
console.log(` maxDepth: ${import_chalk5.default.bold(ca.maxDepth ?? "default")}`);
|
|
489
|
+
console.log(` maxContextBudget: ${import_chalk5.default.bold(ca.maxContextBudget ?? "default")}`);
|
|
490
|
+
if (ca.minCohesion !== void 0) console.log(` minCohesion: ${import_chalk5.default.bold(String(ca.minCohesion))}`);
|
|
491
|
+
if (ca.maxFragmentation !== void 0) console.log(` maxFragmentation: ${import_chalk5.default.bold(String(ca.maxFragmentation))}`);
|
|
492
|
+
if (ca.includeNodeModules !== void 0) console.log(` includeNodeModules: ${import_chalk5.default.bold(String(ca.includeNodeModules))}`);
|
|
297
493
|
}
|
|
298
494
|
if (finalOptions.consistency) {
|
|
299
495
|
const c = finalOptions.consistency;
|
|
300
|
-
console.log(
|
|
301
|
-
console.log(` checkNaming: ${
|
|
302
|
-
console.log(` checkPatterns: ${
|
|
303
|
-
console.log(` checkArchitecture: ${
|
|
304
|
-
if (c.minSeverity) console.log(` minSeverity: ${
|
|
305
|
-
if (c.acceptedAbbreviations) console.log(` acceptedAbbreviations: ${
|
|
306
|
-
if (c.shortWords) console.log(` shortWords: ${
|
|
496
|
+
console.log(import_chalk5.default.white("\nConsistency settings:"));
|
|
497
|
+
console.log(` checkNaming: ${import_chalk5.default.bold(String(c.checkNaming ?? true))}`);
|
|
498
|
+
console.log(` checkPatterns: ${import_chalk5.default.bold(String(c.checkPatterns ?? true))}`);
|
|
499
|
+
console.log(` checkArchitecture: ${import_chalk5.default.bold(String(c.checkArchitecture ?? false))}`);
|
|
500
|
+
if (c.minSeverity) console.log(` minSeverity: ${import_chalk5.default.bold(c.minSeverity)}`);
|
|
501
|
+
if (c.acceptedAbbreviations) console.log(` acceptedAbbreviations: ${import_chalk5.default.bold(truncateArray(c.acceptedAbbreviations, 8))}`);
|
|
502
|
+
if (c.shortWords) console.log(` shortWords: ${import_chalk5.default.bold(truncateArray(c.shortWords, 8))}`);
|
|
307
503
|
}
|
|
308
|
-
console.log(
|
|
504
|
+
console.log(import_chalk5.default.white("\nStarting analysis..."));
|
|
309
505
|
const progressCallback = (event) => {
|
|
310
|
-
console.log(
|
|
506
|
+
console.log(import_chalk5.default.cyan(`
|
|
311
507
|
--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
312
508
|
try {
|
|
313
509
|
if (event.tool === "patterns") {
|
|
314
510
|
const pr = event.data;
|
|
315
|
-
console.log(` Duplicate patterns: ${
|
|
316
|
-
console.log(` Files with pattern issues: ${
|
|
511
|
+
console.log(` Duplicate patterns: ${import_chalk5.default.bold(String(pr.duplicates?.length || 0))}`);
|
|
512
|
+
console.log(` Files with pattern issues: ${import_chalk5.default.bold(String(pr.results?.length || 0))}`);
|
|
317
513
|
if (pr.duplicates && pr.duplicates.length > 0) {
|
|
318
514
|
pr.duplicates.slice(0, 5).forEach((d, i) => {
|
|
319
515
|
console.log(` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`);
|
|
@@ -327,10 +523,10 @@ async function scanAction(directory, options) {
|
|
|
327
523
|
});
|
|
328
524
|
}
|
|
329
525
|
if (pr.groups && pr.groups.length >= 0) {
|
|
330
|
-
console.log(` \u2705 Grouped ${
|
|
526
|
+
console.log(` \u2705 Grouped ${import_chalk5.default.bold(String(pr.duplicates?.length || 0))} duplicates into ${import_chalk5.default.bold(String(pr.groups.length))} file pairs`);
|
|
331
527
|
}
|
|
332
528
|
if (pr.clusters && pr.clusters.length >= 0) {
|
|
333
|
-
console.log(` \u2705 Created ${
|
|
529
|
+
console.log(` \u2705 Created ${import_chalk5.default.bold(String(pr.clusters.length))} refactor clusters`);
|
|
334
530
|
pr.clusters.slice(0, 3).forEach((cl, idx) => {
|
|
335
531
|
const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
|
|
336
532
|
console.log(` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`);
|
|
@@ -338,14 +534,14 @@ async function scanAction(directory, options) {
|
|
|
338
534
|
}
|
|
339
535
|
} else if (event.tool === "context") {
|
|
340
536
|
const cr = event.data;
|
|
341
|
-
console.log(` Context issues found: ${
|
|
537
|
+
console.log(` Context issues found: ${import_chalk5.default.bold(String(cr.length || 0))}`);
|
|
342
538
|
cr.slice(0, 5).forEach((c, i) => {
|
|
343
539
|
const msg = c.message ? ` - ${c.message}` : "";
|
|
344
540
|
console.log(` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`);
|
|
345
541
|
});
|
|
346
542
|
} else if (event.tool === "consistency") {
|
|
347
543
|
const rep = event.data;
|
|
348
|
-
console.log(` Consistency totalIssues: ${
|
|
544
|
+
console.log(` Consistency totalIssues: ${import_chalk5.default.bold(String(rep.summary?.totalIssues || 0))}`);
|
|
349
545
|
if (rep.results && rep.results.length > 0) {
|
|
350
546
|
const fileMap = /* @__PURE__ */ new Map();
|
|
351
547
|
rep.results.forEach((r) => {
|
|
@@ -369,24 +565,38 @@ async function scanAction(directory, options) {
|
|
|
369
565
|
});
|
|
370
566
|
const remaining = files.length - topFiles.length;
|
|
371
567
|
if (remaining > 0) {
|
|
372
|
-
console.log(
|
|
568
|
+
console.log(import_chalk5.default.dim(` ... and ${remaining} more files with issues (use --output json for full details)`));
|
|
373
569
|
}
|
|
374
570
|
}
|
|
571
|
+
} else if (event.tool === "doc-drift") {
|
|
572
|
+
const dr = event.data;
|
|
573
|
+
console.log(` Issues found: ${import_chalk5.default.bold(String(dr.issues?.length || 0))}`);
|
|
574
|
+
if (dr.rawData) {
|
|
575
|
+
console.log(` Signature Mismatches: ${import_chalk5.default.bold(dr.rawData.outdatedComments || 0)}`);
|
|
576
|
+
console.log(` Undocumented Complexity: ${import_chalk5.default.bold(dr.rawData.undocumentedComplexity || 0)}`);
|
|
577
|
+
}
|
|
578
|
+
} else if (event.tool === "deps-health") {
|
|
579
|
+
const dr = event.data;
|
|
580
|
+
console.log(` Packages Analyzed: ${import_chalk5.default.bold(String(dr.summary?.packagesAnalyzed || 0))}`);
|
|
581
|
+
if (dr.rawData) {
|
|
582
|
+
console.log(` Deprecated Packages: ${import_chalk5.default.bold(dr.rawData.deprecatedPackages || 0)}`);
|
|
583
|
+
console.log(` AI Cutoff Skew Score: ${import_chalk5.default.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`);
|
|
584
|
+
}
|
|
375
585
|
}
|
|
376
586
|
} catch (err) {
|
|
377
587
|
}
|
|
378
588
|
};
|
|
379
589
|
const results = await analyzeUnified({ ...finalOptions, progressCallback, suppressToolConfig: true });
|
|
380
|
-
console.log(
|
|
381
|
-
console.log(
|
|
382
|
-
console.log(
|
|
383
|
-
console.log(` Total issues (all tools): ${
|
|
384
|
-
if (results.duplicates) console.log(` Duplicate patterns found: ${
|
|
385
|
-
if (results.patterns) console.log(` Pattern files with issues: ${
|
|
386
|
-
if (results.context) console.log(` Context issues: ${
|
|
387
|
-
if (results.consistency) console.log(` Consistency issues: ${
|
|
388
|
-
console.log(
|
|
389
|
-
const elapsedTime = (0,
|
|
590
|
+
console.log(import_chalk5.default.cyan("\n=== AIReady Run Summary ==="));
|
|
591
|
+
console.log(import_chalk5.default.white("Tools run:"), (finalOptions.tools || ["patterns", "context", "consistency"]).join(", "));
|
|
592
|
+
console.log(import_chalk5.default.cyan("\nResults summary:"));
|
|
593
|
+
console.log(` Total issues (all tools): ${import_chalk5.default.bold(String(results.summary.totalIssues || 0))}`);
|
|
594
|
+
if (results.duplicates) console.log(` Duplicate patterns found: ${import_chalk5.default.bold(String(results.duplicates.length || 0))}`);
|
|
595
|
+
if (results.patterns) console.log(` Pattern files with issues: ${import_chalk5.default.bold(String(results.patterns.length || 0))}`);
|
|
596
|
+
if (results.context) console.log(` Context issues: ${import_chalk5.default.bold(String(results.context.length || 0))}`);
|
|
597
|
+
if (results.consistency) console.log(` Consistency issues: ${import_chalk5.default.bold(String(results.consistency.summary.totalIssues || 0))}`);
|
|
598
|
+
console.log(import_chalk5.default.cyan("===========================\n"));
|
|
599
|
+
const elapsedTime = (0, import_core4.getElapsedTime)(startTime);
|
|
390
600
|
let scoringResult;
|
|
391
601
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
392
602
|
const toolScores = /* @__PURE__ */ new Map();
|
|
@@ -417,23 +627,94 @@ async function scanAction(directory, options) {
|
|
|
417
627
|
} catch (err) {
|
|
418
628
|
}
|
|
419
629
|
}
|
|
420
|
-
|
|
630
|
+
if (finalOptions.tools.includes("hallucination") || finalOptions.tools.includes("hallucination-risk")) {
|
|
631
|
+
try {
|
|
632
|
+
const { hallucinationRiskAction: hallucinationRiskAction2 } = await Promise.resolve().then(() => (init_hallucination_risk(), hallucination_risk_exports));
|
|
633
|
+
const hrScore = await hallucinationRiskAction2(resolvedDir, { ...finalOptions, output: "json" });
|
|
634
|
+
if (hrScore) toolScores.set("hallucination-risk", hrScore);
|
|
635
|
+
} catch (err) {
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (finalOptions.tools.includes("grounding") || finalOptions.tools.includes("agent-grounding")) {
|
|
639
|
+
try {
|
|
640
|
+
const { agentGroundingAction: agentGroundingAction2 } = await Promise.resolve().then(() => (init_agent_grounding(), agent_grounding_exports));
|
|
641
|
+
const agScore = await agentGroundingAction2(resolvedDir, { ...finalOptions, output: "json" });
|
|
642
|
+
if (agScore) toolScores.set("agent-grounding", agScore);
|
|
643
|
+
} catch (err) {
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (finalOptions.tools.includes("testability")) {
|
|
647
|
+
try {
|
|
648
|
+
const { testabilityAction: testabilityAction2 } = await Promise.resolve().then(() => (init_testability(), testability_exports));
|
|
649
|
+
const tbScore = await testabilityAction2(resolvedDir, { ...finalOptions, output: "json" });
|
|
650
|
+
if (tbScore) toolScores.set("testability", tbScore);
|
|
651
|
+
} catch (err) {
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (results.docDrift) {
|
|
655
|
+
toolScores.set("doc-drift", {
|
|
656
|
+
toolName: "doc-drift",
|
|
657
|
+
score: results.docDrift.summary.score,
|
|
658
|
+
rawMetrics: results.docDrift.rawData,
|
|
659
|
+
factors: [],
|
|
660
|
+
recommendations: results.docDrift.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
if (results.deps) {
|
|
664
|
+
toolScores.set("dependency-health", {
|
|
665
|
+
toolName: "dependency-health",
|
|
666
|
+
score: results.deps.summary.score,
|
|
667
|
+
rawMetrics: results.deps.rawData,
|
|
668
|
+
factors: [],
|
|
669
|
+
recommendations: results.deps.recommendations.map((action) => ({ action, estimatedImpact: 5, priority: "medium" }))
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
const cliWeights = (0, import_core4.parseWeightString)(options.weights);
|
|
421
673
|
if (toolScores.size > 0) {
|
|
422
|
-
scoringResult = (0,
|
|
423
|
-
console.log(
|
|
424
|
-
console.log(` ${(0,
|
|
674
|
+
scoringResult = (0, import_core4.calculateOverallScore)(toolScores, finalOptions, cliWeights.size ? cliWeights : void 0);
|
|
675
|
+
console.log(import_chalk5.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
676
|
+
console.log(` ${(0, import_core4.formatScore)(scoringResult)}`);
|
|
677
|
+
if (options.compareTo) {
|
|
678
|
+
try {
|
|
679
|
+
const prevReportStr = (0, import_fs2.readFileSync)((0, import_path2.resolve)(process.cwd(), options.compareTo), "utf8");
|
|
680
|
+
const prevReport = JSON.parse(prevReportStr);
|
|
681
|
+
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
682
|
+
if (typeof prevScore === "number") {
|
|
683
|
+
const diff = scoringResult.overall - prevScore;
|
|
684
|
+
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
685
|
+
console.log();
|
|
686
|
+
if (diff > 0) {
|
|
687
|
+
console.log(import_chalk5.default.green(` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
688
|
+
} else if (diff < 0) {
|
|
689
|
+
console.log(import_chalk5.default.red(` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
690
|
+
} else {
|
|
691
|
+
console.log(import_chalk5.default.blue(` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`));
|
|
692
|
+
}
|
|
693
|
+
scoringResult.trend = {
|
|
694
|
+
previousScore: prevScore,
|
|
695
|
+
difference: diff
|
|
696
|
+
};
|
|
697
|
+
} else {
|
|
698
|
+
console.log(import_chalk5.default.yellow(`
|
|
699
|
+
\u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`));
|
|
700
|
+
}
|
|
701
|
+
} catch (e) {
|
|
702
|
+
console.log(import_chalk5.default.yellow(`
|
|
703
|
+
\u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`));
|
|
704
|
+
}
|
|
705
|
+
}
|
|
425
706
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
426
|
-
console.log(
|
|
707
|
+
console.log(import_chalk5.default.bold("\nTool breakdown:"));
|
|
427
708
|
scoringResult.breakdown.forEach((tool) => {
|
|
428
|
-
const rating = (0,
|
|
429
|
-
const rd = (0,
|
|
709
|
+
const rating = (0, import_core4.getRating)(tool.score);
|
|
710
|
+
const rd = (0, import_core4.getRatingDisplay)(rating);
|
|
430
711
|
console.log(` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`);
|
|
431
712
|
});
|
|
432
713
|
console.log();
|
|
433
714
|
if (finalOptions.scoring?.showBreakdown) {
|
|
434
|
-
console.log(
|
|
715
|
+
console.log(import_chalk5.default.bold("Detailed tool breakdown:"));
|
|
435
716
|
scoringResult.breakdown.forEach((tool) => {
|
|
436
|
-
console.log((0,
|
|
717
|
+
console.log((0, import_core4.formatToolScore)(tool));
|
|
437
718
|
});
|
|
438
719
|
console.log();
|
|
439
720
|
}
|
|
@@ -445,9 +726,9 @@ async function scanAction(directory, options) {
|
|
|
445
726
|
if (outputFormat === "json") {
|
|
446
727
|
const timestamp = getReportTimestamp();
|
|
447
728
|
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
448
|
-
const outputPath = (0,
|
|
729
|
+
const outputPath = (0, import_core4.resolveOutputPath)(userOutputFile, defaultFilename, resolvedDir);
|
|
449
730
|
const outputData = { ...results, scoring: scoringResult };
|
|
450
|
-
(0,
|
|
731
|
+
(0, import_core4.handleJSONOutput)(outputData, outputPath, `\u2705 Report saved to ${outputPath}`);
|
|
451
732
|
warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
452
733
|
}
|
|
453
734
|
const isCI = options.ci || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
|
|
@@ -457,17 +738,17 @@ async function scanAction(directory, options) {
|
|
|
457
738
|
if (process.env.GITHUB_ACTIONS === "true") {
|
|
458
739
|
console.log(`
|
|
459
740
|
::group::AI Readiness Score`);
|
|
460
|
-
console.log(`score=${scoringResult.
|
|
741
|
+
console.log(`score=${scoringResult.overall}`);
|
|
461
742
|
if (scoringResult.breakdown) {
|
|
462
743
|
scoringResult.breakdown.forEach((tool) => {
|
|
463
744
|
console.log(`${tool.toolName}=${tool.score}`);
|
|
464
745
|
});
|
|
465
746
|
}
|
|
466
747
|
console.log("::endgroup::");
|
|
467
|
-
if (threshold && scoringResult.
|
|
468
|
-
console.log(`::error::AI Readiness Score ${scoringResult.
|
|
748
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
749
|
+
console.log(`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`);
|
|
469
750
|
} else if (threshold) {
|
|
470
|
-
console.log(`::notice::AI Readiness Score: ${scoringResult.
|
|
751
|
+
console.log(`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`);
|
|
471
752
|
}
|
|
472
753
|
if (results.patterns) {
|
|
473
754
|
const criticalPatterns = results.patterns.flatMap(
|
|
@@ -480,9 +761,9 @@ async function scanAction(directory, options) {
|
|
|
480
761
|
}
|
|
481
762
|
let shouldFail = false;
|
|
482
763
|
let failReason = "";
|
|
483
|
-
if (threshold && scoringResult.
|
|
764
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
484
765
|
shouldFail = true;
|
|
485
|
-
failReason = `AI Readiness Score ${scoringResult.
|
|
766
|
+
failReason = `AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`;
|
|
486
767
|
}
|
|
487
768
|
if (failOnLevel !== "none") {
|
|
488
769
|
const severityLevels = { critical: 4, major: 3, minor: 2, any: 1 };
|
|
@@ -520,34 +801,43 @@ async function scanAction(directory, options) {
|
|
|
520
801
|
}
|
|
521
802
|
}
|
|
522
803
|
if (shouldFail) {
|
|
523
|
-
console.log(
|
|
524
|
-
console.log(
|
|
525
|
-
console.log(
|
|
526
|
-
console.log(
|
|
527
|
-
console.log(
|
|
528
|
-
console.log(
|
|
804
|
+
console.log(import_chalk5.default.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
|
|
805
|
+
console.log(import_chalk5.default.red(` Reason: ${failReason}`));
|
|
806
|
+
console.log(import_chalk5.default.dim("\n Remediation steps:"));
|
|
807
|
+
console.log(import_chalk5.default.dim(" 1. Run `aiready scan` locally to see detailed issues"));
|
|
808
|
+
console.log(import_chalk5.default.dim(" 2. Fix the critical issues before merging"));
|
|
809
|
+
console.log(import_chalk5.default.dim(" 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"));
|
|
529
810
|
process.exit(1);
|
|
530
811
|
} else {
|
|
531
|
-
console.log(
|
|
812
|
+
console.log(import_chalk5.default.green("\n\u2705 PR PASSED: AI Readiness Check"));
|
|
532
813
|
if (threshold) {
|
|
533
|
-
console.log(
|
|
814
|
+
console.log(import_chalk5.default.green(` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`));
|
|
534
815
|
}
|
|
535
|
-
console.log(
|
|
816
|
+
console.log(import_chalk5.default.dim("\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"));
|
|
536
817
|
}
|
|
537
818
|
}
|
|
538
819
|
} catch (error) {
|
|
539
|
-
(0,
|
|
820
|
+
(0, import_core4.handleCLIError)(error, "Analysis");
|
|
540
821
|
}
|
|
541
822
|
}
|
|
542
823
|
var scanHelpText = `
|
|
543
824
|
EXAMPLES:
|
|
544
825
|
$ aiready scan # Analyze all tools
|
|
545
826
|
$ aiready scan --tools patterns,context # Skip consistency
|
|
827
|
+
$ aiready scan --profile agentic # Optimize for AI agent execution
|
|
828
|
+
$ aiready scan --profile security # Optimize for secure coding (testability)
|
|
829
|
+
$ aiready scan --compare-to prev-report.json # Compare trends against previous run
|
|
546
830
|
$ aiready scan --score --threshold 75 # CI/CD with threshold
|
|
547
831
|
$ aiready scan --ci --threshold 70 # GitHub Actions gatekeeper
|
|
548
832
|
$ aiready scan --ci --fail-on major # Fail on major+ issues
|
|
549
833
|
$ aiready scan --output json --output-file report.json
|
|
550
834
|
|
|
835
|
+
PROFILES:
|
|
836
|
+
agentic: hallucination, grounding, testability
|
|
837
|
+
cost: patterns, context
|
|
838
|
+
security: consistency, testability
|
|
839
|
+
onboarding: context, consistency, grounding
|
|
840
|
+
|
|
551
841
|
CI/CD INTEGRATION (Gatekeeper Mode):
|
|
552
842
|
Use --ci for GitHub Actions integration:
|
|
553
843
|
- Outputs GitHub Actions annotations for PR checks
|
|
@@ -560,11 +850,11 @@ CI/CD INTEGRATION (Gatekeeper Mode):
|
|
|
560
850
|
`;
|
|
561
851
|
|
|
562
852
|
// src/commands/patterns.ts
|
|
563
|
-
var
|
|
853
|
+
var import_chalk6 = __toESM(require("chalk"));
|
|
564
854
|
var import_path3 = require("path");
|
|
565
|
-
var
|
|
855
|
+
var import_core5 = require("@aiready/core");
|
|
566
856
|
async function patternsAction(directory, options) {
|
|
567
|
-
console.log(
|
|
857
|
+
console.log(import_chalk6.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
568
858
|
const startTime = Date.now();
|
|
569
859
|
const resolvedDir = (0, import_path3.resolve)(process.cwd(), directory || ".");
|
|
570
860
|
try {
|
|
@@ -595,10 +885,10 @@ async function patternsAction(directory, options) {
|
|
|
595
885
|
if (options.minSharedTokens) {
|
|
596
886
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
597
887
|
}
|
|
598
|
-
const finalOptions = await (0,
|
|
888
|
+
const finalOptions = await (0, import_core5.loadMergedConfig)(resolvedDir, defaults, cliOptions);
|
|
599
889
|
const { analyzePatterns: analyzePatterns2, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
600
890
|
const { results, duplicates } = await analyzePatterns2(finalOptions);
|
|
601
|
-
const elapsedTime = (0,
|
|
891
|
+
const elapsedTime = (0, import_core5.getElapsedTime)(startTime);
|
|
602
892
|
const summary = generateSummary(results);
|
|
603
893
|
let patternScore;
|
|
604
894
|
if (options.score) {
|
|
@@ -612,60 +902,60 @@ async function patternsAction(directory, options) {
|
|
|
612
902
|
summary: { ...summary, executionTime: parseFloat(elapsedTime) },
|
|
613
903
|
...patternScore && { scoring: patternScore }
|
|
614
904
|
};
|
|
615
|
-
const outputPath = (0,
|
|
905
|
+
const outputPath = (0, import_core5.resolveOutputPath)(
|
|
616
906
|
userOutputFile,
|
|
617
907
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
618
908
|
resolvedDir
|
|
619
909
|
);
|
|
620
|
-
(0,
|
|
910
|
+
(0, import_core5.handleJSONOutput)(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
|
|
621
911
|
} else {
|
|
622
912
|
const terminalWidth = process.stdout.columns || 80;
|
|
623
913
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
624
914
|
const divider = "\u2501".repeat(dividerWidth);
|
|
625
|
-
console.log(
|
|
626
|
-
console.log(
|
|
627
|
-
console.log(
|
|
628
|
-
console.log(
|
|
629
|
-
console.log(
|
|
630
|
-
console.log(
|
|
631
|
-
console.log(
|
|
915
|
+
console.log(import_chalk6.default.cyan(divider));
|
|
916
|
+
console.log(import_chalk6.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
917
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
918
|
+
console.log(import_chalk6.default.white(`\u{1F4C1} Files analyzed: ${import_chalk6.default.bold(results.length)}`));
|
|
919
|
+
console.log(import_chalk6.default.yellow(`\u26A0 Duplicate patterns found: ${import_chalk6.default.bold(summary.totalPatterns)}`));
|
|
920
|
+
console.log(import_chalk6.default.red(`\u{1F4B0} Token cost (wasted): ${import_chalk6.default.bold(summary.totalTokenCost.toLocaleString())}`));
|
|
921
|
+
console.log(import_chalk6.default.gray(`\u23F1 Analysis time: ${import_chalk6.default.bold(elapsedTime + "s")}`));
|
|
632
922
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
633
923
|
if (sortedTypes.length > 0) {
|
|
634
|
-
console.log(
|
|
635
|
-
console.log(
|
|
636
|
-
console.log(
|
|
924
|
+
console.log(import_chalk6.default.cyan("\n" + divider));
|
|
925
|
+
console.log(import_chalk6.default.bold.white(" PATTERNS BY TYPE"));
|
|
926
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
637
927
|
sortedTypes.forEach(([type, count]) => {
|
|
638
|
-
console.log(` ${
|
|
928
|
+
console.log(` ${import_chalk6.default.white(type.padEnd(15))} ${import_chalk6.default.bold(count)}`);
|
|
639
929
|
});
|
|
640
930
|
}
|
|
641
931
|
if (summary.totalPatterns > 0 && duplicates.length > 0) {
|
|
642
|
-
console.log(
|
|
643
|
-
console.log(
|
|
644
|
-
console.log(
|
|
932
|
+
console.log(import_chalk6.default.cyan("\n" + divider));
|
|
933
|
+
console.log(import_chalk6.default.bold.white(" TOP DUPLICATE PATTERNS"));
|
|
934
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
645
935
|
const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
|
|
646
936
|
topDuplicates.forEach((dup) => {
|
|
647
937
|
const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
|
|
648
938
|
const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
|
|
649
939
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
650
940
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
651
|
-
console.log(`${severityIcon} ${severity}: ${
|
|
652
|
-
console.log(` Similarity: ${
|
|
653
|
-
console.log(` Lines: ${
|
|
941
|
+
console.log(`${severityIcon} ${severity}: ${import_chalk6.default.bold(file1Name)} \u2194 ${import_chalk6.default.bold(file2Name)}`);
|
|
942
|
+
console.log(` Similarity: ${import_chalk6.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk6.default.bold(dup.tokenCost.toLocaleString())} tokens each`);
|
|
943
|
+
console.log(` Lines: ${import_chalk6.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk6.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
654
944
|
`);
|
|
655
945
|
});
|
|
656
946
|
} else {
|
|
657
|
-
console.log(
|
|
947
|
+
console.log(import_chalk6.default.green("\n\u2728 Great! No duplicate patterns detected.\n"));
|
|
658
948
|
}
|
|
659
949
|
if (patternScore) {
|
|
660
|
-
console.log(
|
|
661
|
-
console.log(
|
|
662
|
-
console.log(
|
|
663
|
-
console.log((0,
|
|
950
|
+
console.log(import_chalk6.default.cyan(divider));
|
|
951
|
+
console.log(import_chalk6.default.bold.white(" AI READINESS SCORE (Patterns)"));
|
|
952
|
+
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
953
|
+
console.log((0, import_core5.formatToolScore)(patternScore));
|
|
664
954
|
console.log();
|
|
665
955
|
}
|
|
666
956
|
}
|
|
667
957
|
} catch (error) {
|
|
668
|
-
(0,
|
|
958
|
+
(0, import_core5.handleCLIError)(error, "Pattern analysis");
|
|
669
959
|
}
|
|
670
960
|
}
|
|
671
961
|
var patternsHelpText = `
|
|
@@ -676,11 +966,11 @@ EXAMPLES:
|
|
|
676
966
|
`;
|
|
677
967
|
|
|
678
968
|
// src/commands/context.ts
|
|
679
|
-
var
|
|
969
|
+
var import_chalk7 = __toESM(require("chalk"));
|
|
680
970
|
var import_path4 = require("path");
|
|
681
|
-
var
|
|
971
|
+
var import_core6 = require("@aiready/core");
|
|
682
972
|
async function contextAction(directory, options) {
|
|
683
|
-
console.log(
|
|
973
|
+
console.log(import_chalk7.default.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
684
974
|
const startTime = Date.now();
|
|
685
975
|
const resolvedDir = (0, import_path4.resolve)(process.cwd(), directory || ".");
|
|
686
976
|
try {
|
|
@@ -694,7 +984,7 @@ async function contextAction(directory, options) {
|
|
|
694
984
|
file: void 0
|
|
695
985
|
}
|
|
696
986
|
};
|
|
697
|
-
let baseOptions = await (0,
|
|
987
|
+
let baseOptions = await (0, import_core6.loadMergedConfig)(resolvedDir, defaults, {
|
|
698
988
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
699
989
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
700
990
|
include: options.include?.split(","),
|
|
@@ -713,7 +1003,7 @@ async function contextAction(directory, options) {
|
|
|
713
1003
|
console.log("");
|
|
714
1004
|
const { analyzeContext: analyzeContext2, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
715
1005
|
const results = await analyzeContext2(finalOptions);
|
|
716
|
-
const elapsedTime = (0,
|
|
1006
|
+
const elapsedTime = (0, import_core6.getElapsedTime)(startTime);
|
|
717
1007
|
const summary = generateSummary(results);
|
|
718
1008
|
let contextScore;
|
|
719
1009
|
if (options.score) {
|
|
@@ -727,104 +1017,104 @@ async function contextAction(directory, options) {
|
|
|
727
1017
|
summary: { ...summary, executionTime: parseFloat(elapsedTime) },
|
|
728
1018
|
...contextScore && { scoring: contextScore }
|
|
729
1019
|
};
|
|
730
|
-
const outputPath = (0,
|
|
1020
|
+
const outputPath = (0, import_core6.resolveOutputPath)(
|
|
731
1021
|
userOutputFile,
|
|
732
1022
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
733
1023
|
resolvedDir
|
|
734
1024
|
);
|
|
735
|
-
(0,
|
|
1025
|
+
(0, import_core6.handleJSONOutput)(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
|
|
736
1026
|
} else {
|
|
737
1027
|
const terminalWidth = process.stdout.columns || 80;
|
|
738
1028
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
739
1029
|
const divider = "\u2501".repeat(dividerWidth);
|
|
740
|
-
console.log(
|
|
741
|
-
console.log(
|
|
742
|
-
console.log(
|
|
743
|
-
console.log(
|
|
744
|
-
console.log(
|
|
745
|
-
console.log(
|
|
746
|
-
console.log(
|
|
1030
|
+
console.log(import_chalk7.default.cyan(divider));
|
|
1031
|
+
console.log(import_chalk7.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
1032
|
+
console.log(import_chalk7.default.cyan(divider) + "\n");
|
|
1033
|
+
console.log(import_chalk7.default.white(`\u{1F4C1} Files analyzed: ${import_chalk7.default.bold(summary.totalFiles)}`));
|
|
1034
|
+
console.log(import_chalk7.default.white(`\u{1F4CA} Total tokens: ${import_chalk7.default.bold(summary.totalTokens.toLocaleString())}`));
|
|
1035
|
+
console.log(import_chalk7.default.yellow(`\u{1F4B0} Avg context budget: ${import_chalk7.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`));
|
|
1036
|
+
console.log(import_chalk7.default.white(`\u23F1 Analysis time: ${import_chalk7.default.bold(elapsedTime + "s")}
|
|
747
1037
|
`));
|
|
748
1038
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
749
1039
|
if (totalIssues > 0) {
|
|
750
|
-
console.log(
|
|
1040
|
+
console.log(import_chalk7.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
751
1041
|
if (summary.criticalIssues > 0) {
|
|
752
|
-
console.log(
|
|
1042
|
+
console.log(import_chalk7.default.red(` \u{1F534} Critical: ${import_chalk7.default.bold(summary.criticalIssues)}`));
|
|
753
1043
|
}
|
|
754
1044
|
if (summary.majorIssues > 0) {
|
|
755
|
-
console.log(
|
|
1045
|
+
console.log(import_chalk7.default.yellow(` \u{1F7E1} Major: ${import_chalk7.default.bold(summary.majorIssues)}`));
|
|
756
1046
|
}
|
|
757
1047
|
if (summary.minorIssues > 0) {
|
|
758
|
-
console.log(
|
|
1048
|
+
console.log(import_chalk7.default.blue(` \u{1F535} Minor: ${import_chalk7.default.bold(summary.minorIssues)}`));
|
|
759
1049
|
}
|
|
760
|
-
console.log(
|
|
761
|
-
\u{1F4A1} Potential savings: ${
|
|
1050
|
+
console.log(import_chalk7.default.green(`
|
|
1051
|
+
\u{1F4A1} Potential savings: ${import_chalk7.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
762
1052
|
`));
|
|
763
1053
|
} else {
|
|
764
|
-
console.log(
|
|
1054
|
+
console.log(import_chalk7.default.green("\u2705 No significant issues found!\n"));
|
|
765
1055
|
}
|
|
766
1056
|
if (summary.deepFiles.length > 0) {
|
|
767
|
-
console.log(
|
|
768
|
-
console.log(
|
|
769
|
-
console.log(
|
|
1057
|
+
console.log(import_chalk7.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
1058
|
+
console.log(import_chalk7.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`));
|
|
1059
|
+
console.log(import_chalk7.default.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
770
1060
|
`));
|
|
771
1061
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
772
1062
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
773
|
-
console.log(` ${
|
|
1063
|
+
console.log(` ${import_chalk7.default.cyan("\u2192")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(depth: ${item.depth})`)}`);
|
|
774
1064
|
});
|
|
775
1065
|
console.log();
|
|
776
1066
|
}
|
|
777
1067
|
if (summary.fragmentedModules.length > 0) {
|
|
778
|
-
console.log(
|
|
779
|
-
console.log(
|
|
1068
|
+
console.log(import_chalk7.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
1069
|
+
console.log(import_chalk7.default.gray(` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
780
1070
|
`));
|
|
781
1071
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
782
|
-
console.log(` ${
|
|
783
|
-
console.log(
|
|
1072
|
+
console.log(` ${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`)}`);
|
|
1073
|
+
console.log(import_chalk7.default.dim(` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`));
|
|
784
1074
|
});
|
|
785
1075
|
console.log();
|
|
786
1076
|
}
|
|
787
1077
|
if (summary.lowCohesionFiles.length > 0) {
|
|
788
|
-
console.log(
|
|
789
|
-
console.log(
|
|
1078
|
+
console.log(import_chalk7.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1079
|
+
console.log(import_chalk7.default.gray(` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
790
1080
|
`));
|
|
791
1081
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
792
1082
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
793
1083
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
794
|
-
const color = item.score < 0.4 ?
|
|
795
|
-
console.log(` ${color("\u25CB")} ${
|
|
1084
|
+
const color = item.score < 0.4 ? import_chalk7.default.red : import_chalk7.default.yellow;
|
|
1085
|
+
console.log(` ${color("\u25CB")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(${scorePercent}% cohesion)`)}`);
|
|
796
1086
|
});
|
|
797
1087
|
console.log();
|
|
798
1088
|
}
|
|
799
1089
|
if (summary.topExpensiveFiles.length > 0) {
|
|
800
|
-
console.log(
|
|
1090
|
+
console.log(import_chalk7.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
|
|
801
1091
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
802
1092
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
803
|
-
const severityColor = item.severity === "critical" ?
|
|
804
|
-
console.log(` ${severityColor("\u25CF")} ${
|
|
1093
|
+
const severityColor = item.severity === "critical" ? import_chalk7.default.red : item.severity === "major" ? import_chalk7.default.yellow : import_chalk7.default.blue;
|
|
1094
|
+
console.log(` ${severityColor("\u25CF")} ${import_chalk7.default.white(fileName)} ${import_chalk7.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`);
|
|
805
1095
|
});
|
|
806
1096
|
console.log();
|
|
807
1097
|
}
|
|
808
1098
|
if (contextScore) {
|
|
809
|
-
console.log(
|
|
810
|
-
console.log(
|
|
811
|
-
console.log(
|
|
812
|
-
console.log((0,
|
|
1099
|
+
console.log(import_chalk7.default.cyan(divider));
|
|
1100
|
+
console.log(import_chalk7.default.bold.white(" AI READINESS SCORE (Context)"));
|
|
1101
|
+
console.log(import_chalk7.default.cyan(divider) + "\n");
|
|
1102
|
+
console.log((0, import_core6.formatToolScore)(contextScore));
|
|
813
1103
|
console.log();
|
|
814
1104
|
}
|
|
815
1105
|
}
|
|
816
1106
|
} catch (error) {
|
|
817
|
-
(0,
|
|
1107
|
+
(0, import_core6.handleCLIError)(error, "Context analysis");
|
|
818
1108
|
}
|
|
819
1109
|
}
|
|
820
1110
|
|
|
821
1111
|
// src/commands/consistency.ts
|
|
822
|
-
var
|
|
823
|
-
var
|
|
1112
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
1113
|
+
var import_fs3 = require("fs");
|
|
824
1114
|
var import_path5 = require("path");
|
|
825
|
-
var
|
|
1115
|
+
var import_core7 = require("@aiready/core");
|
|
826
1116
|
async function consistencyAction(directory, options) {
|
|
827
|
-
console.log(
|
|
1117
|
+
console.log(import_chalk8.default.blue("\u{1F50D} Analyzing consistency...\n"));
|
|
828
1118
|
const startTime = Date.now();
|
|
829
1119
|
const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory || ".");
|
|
830
1120
|
try {
|
|
@@ -839,7 +1129,7 @@ async function consistencyAction(directory, options) {
|
|
|
839
1129
|
file: void 0
|
|
840
1130
|
}
|
|
841
1131
|
};
|
|
842
|
-
const finalOptions = await (0,
|
|
1132
|
+
const finalOptions = await (0, import_core7.loadMergedConfig)(resolvedDir, defaults, {
|
|
843
1133
|
checkNaming: options.naming !== false,
|
|
844
1134
|
checkPatterns: options.patterns !== false,
|
|
845
1135
|
minSeverity: options.minSeverity,
|
|
@@ -848,7 +1138,7 @@ async function consistencyAction(directory, options) {
|
|
|
848
1138
|
});
|
|
849
1139
|
const { analyzeConsistency: analyzeConsistency2, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
850
1140
|
const report = await analyzeConsistency2(finalOptions);
|
|
851
|
-
const elapsedTime = (0,
|
|
1141
|
+
const elapsedTime = (0, import_core7.getElapsedTime)(startTime);
|
|
852
1142
|
let consistencyScore;
|
|
853
1143
|
if (options.score) {
|
|
854
1144
|
const issues = report.results?.flatMap((r) => r.issues) || [];
|
|
@@ -865,32 +1155,32 @@ async function consistencyAction(directory, options) {
|
|
|
865
1155
|
},
|
|
866
1156
|
...consistencyScore && { scoring: consistencyScore }
|
|
867
1157
|
};
|
|
868
|
-
const outputPath = (0,
|
|
1158
|
+
const outputPath = (0, import_core7.resolveOutputPath)(
|
|
869
1159
|
userOutputFile,
|
|
870
1160
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
871
1161
|
resolvedDir
|
|
872
1162
|
);
|
|
873
|
-
(0,
|
|
1163
|
+
(0, import_core7.handleJSONOutput)(outputData, outputPath, `\u2705 Results saved to ${outputPath}`);
|
|
874
1164
|
} else if (outputFormat === "markdown") {
|
|
875
1165
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
876
|
-
const outputPath = (0,
|
|
1166
|
+
const outputPath = (0, import_core7.resolveOutputPath)(
|
|
877
1167
|
userOutputFile,
|
|
878
1168
|
`aiready-report-${getReportTimestamp()}.md`,
|
|
879
1169
|
resolvedDir
|
|
880
1170
|
);
|
|
881
|
-
(0,
|
|
882
|
-
console.log(
|
|
1171
|
+
(0, import_fs3.writeFileSync)(outputPath, markdown);
|
|
1172
|
+
console.log(import_chalk8.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
883
1173
|
} else {
|
|
884
|
-
console.log(
|
|
885
|
-
console.log(`Files Analyzed: ${
|
|
886
|
-
console.log(`Total Issues: ${
|
|
887
|
-
console.log(` Naming: ${
|
|
888
|
-
console.log(` Patterns: ${
|
|
889
|
-
console.log(` Architecture: ${
|
|
890
|
-
console.log(`Analysis Time: ${
|
|
1174
|
+
console.log(import_chalk8.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1175
|
+
console.log(`Files Analyzed: ${import_chalk8.default.cyan(report.summary.filesAnalyzed)}`);
|
|
1176
|
+
console.log(`Total Issues: ${import_chalk8.default.yellow(report.summary.totalIssues)}`);
|
|
1177
|
+
console.log(` Naming: ${import_chalk8.default.yellow(report.summary.namingIssues)}`);
|
|
1178
|
+
console.log(` Patterns: ${import_chalk8.default.yellow(report.summary.patternIssues)}`);
|
|
1179
|
+
console.log(` Architecture: ${import_chalk8.default.yellow(report.summary.architectureIssues || 0)}`);
|
|
1180
|
+
console.log(`Analysis Time: ${import_chalk8.default.gray(elapsedTime + "s")}
|
|
891
1181
|
`);
|
|
892
1182
|
if (report.summary.totalIssues === 0) {
|
|
893
|
-
console.log(
|
|
1183
|
+
console.log(import_chalk8.default.green("\u2728 No consistency issues found! Your codebase is well-maintained.\n"));
|
|
894
1184
|
} else {
|
|
895
1185
|
const namingResults = report.results.filter(
|
|
896
1186
|
(r) => r.issues.some((i) => i.category === "naming")
|
|
@@ -899,17 +1189,17 @@ async function consistencyAction(directory, options) {
|
|
|
899
1189
|
(r) => r.issues.some((i) => i.category === "patterns")
|
|
900
1190
|
);
|
|
901
1191
|
if (namingResults.length > 0) {
|
|
902
|
-
console.log(
|
|
1192
|
+
console.log(import_chalk8.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
|
|
903
1193
|
let shown = 0;
|
|
904
1194
|
for (const result of namingResults) {
|
|
905
1195
|
if (shown >= 5) break;
|
|
906
1196
|
for (const issue of result.issues) {
|
|
907
1197
|
if (shown >= 5) break;
|
|
908
|
-
const severityColor = issue.severity === "critical" ?
|
|
909
|
-
console.log(`${severityColor(issue.severity.toUpperCase())} ${
|
|
1198
|
+
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;
|
|
1199
|
+
console.log(`${severityColor(issue.severity.toUpperCase())} ${import_chalk8.default.dim(`${issue.location.file}:${issue.location.line}`)}`);
|
|
910
1200
|
console.log(` ${issue.message}`);
|
|
911
1201
|
if (issue.suggestion) {
|
|
912
|
-
console.log(` ${
|
|
1202
|
+
console.log(` ${import_chalk8.default.dim("\u2192")} ${import_chalk8.default.italic(issue.suggestion)}`);
|
|
913
1203
|
}
|
|
914
1204
|
console.log();
|
|
915
1205
|
shown++;
|
|
@@ -917,22 +1207,22 @@ async function consistencyAction(directory, options) {
|
|
|
917
1207
|
}
|
|
918
1208
|
const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
919
1209
|
if (remaining > 0) {
|
|
920
|
-
console.log(
|
|
1210
|
+
console.log(import_chalk8.default.dim(` ... and ${remaining} more issues
|
|
921
1211
|
`));
|
|
922
1212
|
}
|
|
923
1213
|
}
|
|
924
1214
|
if (patternResults.length > 0) {
|
|
925
|
-
console.log(
|
|
1215
|
+
console.log(import_chalk8.default.bold("\u{1F504} Pattern Issues\n"));
|
|
926
1216
|
let shown = 0;
|
|
927
1217
|
for (const result of patternResults) {
|
|
928
1218
|
if (shown >= 5) break;
|
|
929
1219
|
for (const issue of result.issues) {
|
|
930
1220
|
if (shown >= 5) break;
|
|
931
|
-
const severityColor = issue.severity === "critical" ?
|
|
932
|
-
console.log(`${severityColor(issue.severity.toUpperCase())} ${
|
|
1221
|
+
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;
|
|
1222
|
+
console.log(`${severityColor(issue.severity.toUpperCase())} ${import_chalk8.default.dim(`${issue.location.file}:${issue.location.line}`)}`);
|
|
933
1223
|
console.log(` ${issue.message}`);
|
|
934
1224
|
if (issue.suggestion) {
|
|
935
|
-
console.log(` ${
|
|
1225
|
+
console.log(` ${import_chalk8.default.dim("\u2192")} ${import_chalk8.default.italic(issue.suggestion)}`);
|
|
936
1226
|
}
|
|
937
1227
|
console.log();
|
|
938
1228
|
shown++;
|
|
@@ -940,12 +1230,12 @@ async function consistencyAction(directory, options) {
|
|
|
940
1230
|
}
|
|
941
1231
|
const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
942
1232
|
if (remaining > 0) {
|
|
943
|
-
console.log(
|
|
1233
|
+
console.log(import_chalk8.default.dim(` ... and ${remaining} more issues
|
|
944
1234
|
`));
|
|
945
1235
|
}
|
|
946
1236
|
}
|
|
947
1237
|
if (report.recommendations.length > 0) {
|
|
948
|
-
console.log(
|
|
1238
|
+
console.log(import_chalk8.default.bold("\u{1F4A1} Recommendations\n"));
|
|
949
1239
|
report.recommendations.forEach((rec, i) => {
|
|
950
1240
|
console.log(`${i + 1}. ${rec}`);
|
|
951
1241
|
});
|
|
@@ -953,35 +1243,35 @@ async function consistencyAction(directory, options) {
|
|
|
953
1243
|
}
|
|
954
1244
|
}
|
|
955
1245
|
if (consistencyScore) {
|
|
956
|
-
console.log(
|
|
957
|
-
console.log((0,
|
|
1246
|
+
console.log(import_chalk8.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
|
|
1247
|
+
console.log((0, import_core7.formatToolScore)(consistencyScore));
|
|
958
1248
|
console.log();
|
|
959
1249
|
}
|
|
960
1250
|
}
|
|
961
1251
|
} catch (error) {
|
|
962
|
-
(0,
|
|
1252
|
+
(0, import_core7.handleCLIError)(error, "Consistency analysis");
|
|
963
1253
|
}
|
|
964
1254
|
}
|
|
965
1255
|
|
|
966
1256
|
// src/commands/visualize.ts
|
|
967
|
-
var
|
|
968
|
-
var
|
|
1257
|
+
var import_chalk9 = __toESM(require("chalk"));
|
|
1258
|
+
var import_fs4 = require("fs");
|
|
969
1259
|
var import_path6 = require("path");
|
|
970
1260
|
var import_child_process = require("child_process");
|
|
971
|
-
var
|
|
972
|
-
var
|
|
1261
|
+
var import_core8 = require("@aiready/core");
|
|
1262
|
+
var import_core9 = require("@aiready/core");
|
|
973
1263
|
async function visualizeAction(directory, options) {
|
|
974
1264
|
try {
|
|
975
1265
|
const dirPath = (0, import_path6.resolve)(process.cwd(), directory || ".");
|
|
976
1266
|
let reportPath = options.report ? (0, import_path6.resolve)(dirPath, options.report) : null;
|
|
977
|
-
if (!reportPath || !(0,
|
|
1267
|
+
if (!reportPath || !(0, import_fs4.existsSync)(reportPath)) {
|
|
978
1268
|
const latestScan = findLatestScanReport(dirPath);
|
|
979
1269
|
if (latestScan) {
|
|
980
1270
|
reportPath = latestScan;
|
|
981
|
-
console.log(
|
|
1271
|
+
console.log(import_chalk9.default.dim(`Found latest report: ${latestScan.split("/").pop()}`));
|
|
982
1272
|
} else {
|
|
983
|
-
console.error(
|
|
984
|
-
console.log(
|
|
1273
|
+
console.error(import_chalk9.default.red("\u274C No AI readiness report found"));
|
|
1274
|
+
console.log(import_chalk9.default.dim(`
|
|
985
1275
|
Generate a report with:
|
|
986
1276
|
aiready scan --output json
|
|
987
1277
|
|
|
@@ -990,13 +1280,13 @@ Or specify a custom report:
|
|
|
990
1280
|
return;
|
|
991
1281
|
}
|
|
992
1282
|
}
|
|
993
|
-
const raw = (0,
|
|
1283
|
+
const raw = (0, import_fs4.readFileSync)(reportPath, "utf8");
|
|
994
1284
|
const report = JSON.parse(raw);
|
|
995
1285
|
const configPath = (0, import_path6.resolve)(dirPath, "aiready.json");
|
|
996
1286
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
997
|
-
if ((0,
|
|
1287
|
+
if ((0, import_fs4.existsSync)(configPath)) {
|
|
998
1288
|
try {
|
|
999
|
-
const rawConfig = JSON.parse((0,
|
|
1289
|
+
const rawConfig = JSON.parse((0, import_fs4.readFileSync)(configPath, "utf8"));
|
|
1000
1290
|
if (rawConfig.visualizer?.graph) {
|
|
1001
1291
|
graphConfig = {
|
|
1002
1292
|
maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
|
|
@@ -1018,7 +1308,7 @@ Or specify a custom report:
|
|
|
1018
1308
|
const monorepoWebDir = (0, import_path6.resolve)(dirPath, "packages/visualizer");
|
|
1019
1309
|
let webDir = "";
|
|
1020
1310
|
let visualizerAvailable = false;
|
|
1021
|
-
if ((0,
|
|
1311
|
+
if ((0, import_fs4.existsSync)(monorepoWebDir)) {
|
|
1022
1312
|
webDir = monorepoWebDir;
|
|
1023
1313
|
visualizerAvailable = true;
|
|
1024
1314
|
} else {
|
|
@@ -1034,7 +1324,7 @@ Or specify a custom report:
|
|
|
1034
1324
|
currentDir = parent;
|
|
1035
1325
|
}
|
|
1036
1326
|
for (const location of nodemodulesLocations) {
|
|
1037
|
-
if ((0,
|
|
1327
|
+
if ((0, import_fs4.existsSync)(location) && (0, import_fs4.existsSync)((0, import_path6.resolve)(location, "package.json"))) {
|
|
1038
1328
|
webDir = location;
|
|
1039
1329
|
visualizerAvailable = true;
|
|
1040
1330
|
break;
|
|
@@ -1049,14 +1339,14 @@ Or specify a custom report:
|
|
|
1049
1339
|
}
|
|
1050
1340
|
}
|
|
1051
1341
|
}
|
|
1052
|
-
const webViteConfigExists = webDir && (0,
|
|
1342
|
+
const webViteConfigExists = webDir && (0, import_fs4.existsSync)((0, import_path6.resolve)(webDir, "web", "vite.config.ts"));
|
|
1053
1343
|
if (visualizerAvailable && webViteConfigExists) {
|
|
1054
1344
|
const spawnCwd = webDir;
|
|
1055
1345
|
const { watch } = await import("fs");
|
|
1056
1346
|
const copyReportToViz = () => {
|
|
1057
1347
|
try {
|
|
1058
1348
|
const destPath = (0, import_path6.resolve)(spawnCwd, "web", "report-data.json");
|
|
1059
|
-
(0,
|
|
1349
|
+
(0, import_fs4.copyFileSync)(reportPath, destPath);
|
|
1060
1350
|
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
1061
1351
|
} catch (e) {
|
|
1062
1352
|
console.error("Failed to sync report:", e);
|
|
@@ -1090,22 +1380,22 @@ Or specify a custom report:
|
|
|
1090
1380
|
devServerStarted = true;
|
|
1091
1381
|
return;
|
|
1092
1382
|
} else {
|
|
1093
|
-
console.log(
|
|
1094
|
-
console.log(
|
|
1383
|
+
console.log(import_chalk9.default.yellow("\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."));
|
|
1384
|
+
console.log(import_chalk9.default.cyan(" Falling back to static HTML generation...\n"));
|
|
1095
1385
|
useDevMode = false;
|
|
1096
1386
|
}
|
|
1097
1387
|
} catch (err) {
|
|
1098
1388
|
console.error("Failed to start dev server:", err);
|
|
1099
|
-
console.log(
|
|
1389
|
+
console.log(import_chalk9.default.cyan(" Falling back to static HTML generation...\n"));
|
|
1100
1390
|
useDevMode = false;
|
|
1101
1391
|
}
|
|
1102
1392
|
}
|
|
1103
1393
|
console.log("Generating HTML...");
|
|
1104
|
-
const html = (0,
|
|
1394
|
+
const html = (0, import_core9.generateHTML)(graph);
|
|
1105
1395
|
const defaultOutput = "visualization.html";
|
|
1106
1396
|
const outPath = (0, import_path6.resolve)(dirPath, options.output || defaultOutput);
|
|
1107
|
-
(0,
|
|
1108
|
-
console.log(
|
|
1397
|
+
(0, import_fs4.writeFileSync)(outPath, html, "utf8");
|
|
1398
|
+
console.log(import_chalk9.default.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1109
1399
|
if (options.open || options.serve) {
|
|
1110
1400
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1111
1401
|
if (options.serve) {
|
|
@@ -1131,7 +1421,7 @@ Or specify a custom report:
|
|
|
1131
1421
|
});
|
|
1132
1422
|
server.listen(port, () => {
|
|
1133
1423
|
const addr = `http://localhost:${port}/`;
|
|
1134
|
-
console.log(
|
|
1424
|
+
console.log(import_chalk9.default.cyan(`\u{1F310} Local visualization server running at ${addr}`));
|
|
1135
1425
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1136
1426
|
});
|
|
1137
1427
|
process.on("SIGINT", () => {
|
|
@@ -1146,7 +1436,7 @@ Or specify a custom report:
|
|
|
1146
1436
|
}
|
|
1147
1437
|
}
|
|
1148
1438
|
} catch (err) {
|
|
1149
|
-
(0,
|
|
1439
|
+
(0, import_core8.handleCLIError)(err, "Visualization");
|
|
1150
1440
|
}
|
|
1151
1441
|
}
|
|
1152
1442
|
var visualizeHelpText = `
|
|
@@ -1176,8 +1466,18 @@ NOTES:
|
|
|
1176
1466
|
- Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
|
|
1177
1467
|
`;
|
|
1178
1468
|
|
|
1469
|
+
// src/commands/index.ts
|
|
1470
|
+
init_hallucination_risk();
|
|
1471
|
+
init_agent_grounding();
|
|
1472
|
+
init_testability();
|
|
1473
|
+
|
|
1179
1474
|
// src/cli.ts
|
|
1180
|
-
var
|
|
1475
|
+
var import_meta = {};
|
|
1476
|
+
var getDirname = () => {
|
|
1477
|
+
if (typeof __dirname !== "undefined") return __dirname;
|
|
1478
|
+
return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
1479
|
+
};
|
|
1480
|
+
var packageJson = JSON.parse((0, import_fs5.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8"));
|
|
1181
1481
|
var program = new import_commander.Command();
|
|
1182
1482
|
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText("after", `
|
|
1183
1483
|
AI READINESS SCORING:
|
|
@@ -1215,7 +1515,7 @@ VERSION: ${packageJson.version}
|
|
|
1215
1515
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
1216
1516
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
1217
1517
|
LANDING: https://github.com/caopengau/aiready-landing`);
|
|
1218
|
-
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)", "
|
|
1518
|
+
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) => {
|
|
1219
1519
|
await scanAction(directory, options);
|
|
1220
1520
|
});
|
|
1221
1521
|
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) => {
|