@aiready/cli 0.14.22 → 0.14.24
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/dist/chunk-HUSUJEQJ.mjs +298 -0
- package/dist/cli.js +873 -840
- package/dist/cli.mjs +500 -453
- package/dist/index.js +0 -9
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
package/dist/cli.js
CHANGED
|
@@ -25,286 +25,24 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
|
-
var
|
|
29
|
-
var
|
|
28
|
+
var import_fs8 = require("fs");
|
|
29
|
+
var import_path7 = require("path");
|
|
30
30
|
var import_url = require("url");
|
|
31
31
|
|
|
32
32
|
// src/commands/scan.ts
|
|
33
|
-
var
|
|
34
|
-
var
|
|
35
|
-
var
|
|
36
|
-
var
|
|
33
|
+
var import_chalk6 = __toESM(require("chalk"));
|
|
34
|
+
var import_fs4 = require("fs");
|
|
35
|
+
var import_path4 = require("path");
|
|
36
|
+
var import_core9 = require("@aiready/core");
|
|
37
37
|
|
|
38
|
-
// src/index.ts
|
|
39
|
-
var
|
|
40
|
-
var import_pattern_detect = require("@aiready/pattern-detect");
|
|
41
|
-
var import_context_analyzer = require("@aiready/context-analyzer");
|
|
42
|
-
var import_consistency = require("@aiready/consistency");
|
|
43
|
-
var import_ai_signal_clarity = require("@aiready/ai-signal-clarity");
|
|
44
|
-
var import_agent_grounding = require("@aiready/agent-grounding");
|
|
45
|
-
var import_testability = require("@aiready/testability");
|
|
46
|
-
var import_doc_drift = require("@aiready/doc-drift");
|
|
47
|
-
var import_deps = require("@aiready/deps");
|
|
48
|
-
var import_change_amplification = require("@aiready/change-amplification");
|
|
49
|
-
var TOOL_PACKAGE_MAP = {
|
|
50
|
-
[import_core.ToolName.PatternDetect]: "@aiready/pattern-detect",
|
|
51
|
-
[import_core.ToolName.ContextAnalyzer]: "@aiready/context-analyzer",
|
|
52
|
-
[import_core.ToolName.NamingConsistency]: "@aiready/consistency",
|
|
53
|
-
[import_core.ToolName.AiSignalClarity]: "@aiready/ai-signal-clarity",
|
|
54
|
-
[import_core.ToolName.AgentGrounding]: "@aiready/agent-grounding",
|
|
55
|
-
[import_core.ToolName.TestabilityIndex]: "@aiready/testability",
|
|
56
|
-
[import_core.ToolName.DocDrift]: "@aiready/doc-drift",
|
|
57
|
-
[import_core.ToolName.DependencyHealth]: "@aiready/deps",
|
|
58
|
-
[import_core.ToolName.ChangeAmplification]: "@aiready/change-amplification",
|
|
59
|
-
// Aliases handled by registry
|
|
60
|
-
patterns: "@aiready/pattern-detect",
|
|
61
|
-
duplicates: "@aiready/pattern-detect",
|
|
62
|
-
context: "@aiready/context-analyzer",
|
|
63
|
-
fragmentation: "@aiready/context-analyzer",
|
|
64
|
-
consistency: "@aiready/consistency",
|
|
65
|
-
"ai-signal": "@aiready/ai-signal-clarity",
|
|
66
|
-
grounding: "@aiready/agent-grounding",
|
|
67
|
-
testability: "@aiready/testability",
|
|
68
|
-
"deps-health": "@aiready/deps",
|
|
69
|
-
"change-amp": "@aiready/change-amplification"
|
|
70
|
-
};
|
|
71
|
-
function sanitizeConfigRecursive(obj) {
|
|
72
|
-
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
|
|
73
|
-
const sanitized = {};
|
|
74
|
-
const infraToStrip = [
|
|
75
|
-
"rootDir",
|
|
76
|
-
"onProgress",
|
|
77
|
-
"progressCallback",
|
|
78
|
-
"streamResults",
|
|
79
|
-
"batchSize",
|
|
80
|
-
"useSmartDefaults"
|
|
81
|
-
];
|
|
82
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
83
|
-
if (infraToStrip.includes(key)) continue;
|
|
84
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
85
|
-
sanitized[key] = sanitizeConfigRecursive(value);
|
|
86
|
-
} else {
|
|
87
|
-
sanitized[key] = value;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return sanitized;
|
|
91
|
-
}
|
|
92
|
-
function sanitizeToolConfig(config) {
|
|
93
|
-
return sanitizeConfigRecursive(config);
|
|
94
|
-
}
|
|
95
|
-
async function analyzeUnified(options) {
|
|
96
|
-
await (0, import_core.initializeParsers)();
|
|
97
|
-
const startTime = Date.now();
|
|
98
|
-
const requestedTools = options.tools ?? [
|
|
99
|
-
"patterns",
|
|
100
|
-
"context",
|
|
101
|
-
"consistency"
|
|
102
|
-
];
|
|
103
|
-
const result = {
|
|
104
|
-
summary: {
|
|
105
|
-
totalIssues: 0,
|
|
106
|
-
criticalIssues: 0,
|
|
107
|
-
// Added as per instruction
|
|
108
|
-
majorIssues: 0,
|
|
109
|
-
// Added as per instruction
|
|
110
|
-
totalFiles: 0,
|
|
111
|
-
toolsRun: [],
|
|
112
|
-
executionTime: 0,
|
|
113
|
-
config: options,
|
|
114
|
-
toolConfigs: {}
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
for (const toolName of requestedTools) {
|
|
118
|
-
let provider = import_core.ToolRegistry.find(toolName);
|
|
119
|
-
if (!provider) {
|
|
120
|
-
const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
|
|
121
|
-
try {
|
|
122
|
-
await import(packageName);
|
|
123
|
-
provider = import_core.ToolRegistry.find(toolName);
|
|
124
|
-
if (provider) {
|
|
125
|
-
console.log(
|
|
126
|
-
`\u2705 Successfully loaded tool provider: ${toolName} from ${packageName}`
|
|
127
|
-
);
|
|
128
|
-
} else {
|
|
129
|
-
console.log(
|
|
130
|
-
`\u26A0\uFE0F Loaded ${packageName} but provider ${toolName} still not found in registry.`
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
} catch (err) {
|
|
134
|
-
console.log(
|
|
135
|
-
`\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
|
|
136
|
-
err.message
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (!provider) {
|
|
141
|
-
console.warn(
|
|
142
|
-
`\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
|
|
143
|
-
);
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
try {
|
|
147
|
-
const sanitizedOptions = { ...options };
|
|
148
|
-
delete sanitizedOptions.onProgress;
|
|
149
|
-
delete sanitizedOptions.progressCallback;
|
|
150
|
-
const toolOptions = {
|
|
151
|
-
rootDir: options.rootDir
|
|
152
|
-
// Always include rootDir
|
|
153
|
-
};
|
|
154
|
-
[...import_core.GLOBAL_INFRA_OPTIONS, ...import_core.COMMON_FINE_TUNING_OPTIONS].forEach(
|
|
155
|
-
(key) => {
|
|
156
|
-
if (key in options && key !== "toolConfigs" && key !== "tools") {
|
|
157
|
-
toolOptions[key] = options[key];
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
);
|
|
161
|
-
if (options.toolConfigs?.[provider.id]) {
|
|
162
|
-
Object.assign(toolOptions, options.toolConfigs[provider.id]);
|
|
163
|
-
} else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
|
|
164
|
-
Object.assign(toolOptions, options.tools[provider.id]);
|
|
165
|
-
} else if (options[provider.id]) {
|
|
166
|
-
Object.assign(toolOptions, options[provider.id]);
|
|
167
|
-
}
|
|
168
|
-
toolOptions.onProgress = (processed, total, message) => {
|
|
169
|
-
if (options.progressCallback) {
|
|
170
|
-
options.progressCallback({
|
|
171
|
-
tool: provider.id,
|
|
172
|
-
processed,
|
|
173
|
-
total,
|
|
174
|
-
message
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
const output = await provider.analyze(toolOptions);
|
|
179
|
-
if (output.metadata) {
|
|
180
|
-
output.metadata.config = sanitizeToolConfig(toolOptions);
|
|
181
|
-
}
|
|
182
|
-
if (options.progressCallback) {
|
|
183
|
-
options.progressCallback({ tool: provider.id, data: output });
|
|
184
|
-
}
|
|
185
|
-
result[provider.id] = output;
|
|
186
|
-
result.summary.toolsRun.push(provider.id);
|
|
187
|
-
if (output.summary?.config) {
|
|
188
|
-
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
|
|
189
|
-
output.summary.config
|
|
190
|
-
);
|
|
191
|
-
} else if (output.metadata?.config) {
|
|
192
|
-
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
|
|
193
|
-
output.metadata.config
|
|
194
|
-
);
|
|
195
|
-
} else {
|
|
196
|
-
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
|
|
197
|
-
}
|
|
198
|
-
const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
|
|
199
|
-
if (toolFiles > result.summary.totalFiles) {
|
|
200
|
-
result.summary.totalFiles = toolFiles;
|
|
201
|
-
}
|
|
202
|
-
const issueCount = output.results.reduce(
|
|
203
|
-
(sum, file) => sum + (file.issues?.length ?? 0),
|
|
204
|
-
0
|
|
205
|
-
);
|
|
206
|
-
result.summary.totalIssues += issueCount;
|
|
207
|
-
} catch (err) {
|
|
208
|
-
console.error(`\u274C Error running tool '${provider.id}':`, err);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
result.summary.config = sanitizeConfigRecursive({
|
|
212
|
-
scan: {
|
|
213
|
-
tools: requestedTools,
|
|
214
|
-
include: options.include,
|
|
215
|
-
exclude: options.exclude
|
|
216
|
-
},
|
|
217
|
-
// Use 'tools' for tool-specific configurations to match AIReadyConfig
|
|
218
|
-
tools: result.summary.toolConfigs
|
|
219
|
-
});
|
|
220
|
-
result.summary.executionTime = Date.now() - startTime;
|
|
221
|
-
const keyMappings = {
|
|
222
|
-
"pattern-detect": ["patternDetect", "patterns"],
|
|
223
|
-
"context-analyzer": ["contextAnalyzer", "context"],
|
|
224
|
-
"naming-consistency": ["namingConsistency", "consistency"],
|
|
225
|
-
"ai-signal-clarity": ["aiSignalClarity"],
|
|
226
|
-
"agent-grounding": ["agentGrounding"],
|
|
227
|
-
"testability-index": ["testabilityIndex", "testability"],
|
|
228
|
-
"doc-drift": ["docDrift"],
|
|
229
|
-
"dependency-health": ["dependencyHealth", "deps"],
|
|
230
|
-
"change-amplification": ["changeAmplification"]
|
|
231
|
-
};
|
|
232
|
-
for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
|
|
233
|
-
if (result[kebabKey]) {
|
|
234
|
-
for (const alias of aliases) {
|
|
235
|
-
result[alias] = result[kebabKey];
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
return result;
|
|
240
|
-
}
|
|
241
|
-
async function scoreUnified(results, options) {
|
|
242
|
-
const toolScores = /* @__PURE__ */ new Map();
|
|
243
|
-
for (const toolId of results.summary.toolsRun) {
|
|
244
|
-
const provider = import_core.ToolRegistry.get(toolId);
|
|
245
|
-
if (!provider) continue;
|
|
246
|
-
const output = results[toolId];
|
|
247
|
-
if (!output) continue;
|
|
248
|
-
try {
|
|
249
|
-
const toolScore = provider.score(output, options);
|
|
250
|
-
if (!toolScore.tokenBudget) {
|
|
251
|
-
if (toolId === import_core.ToolName.PatternDetect && output.duplicates) {
|
|
252
|
-
const wastedTokens = output.duplicates.reduce(
|
|
253
|
-
(sum, d) => sum + (d.tokenCost ?? 0),
|
|
254
|
-
0
|
|
255
|
-
);
|
|
256
|
-
toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
|
|
257
|
-
totalContextTokens: wastedTokens * 2,
|
|
258
|
-
wastedTokens: {
|
|
259
|
-
duplication: wastedTokens,
|
|
260
|
-
fragmentation: 0,
|
|
261
|
-
chattiness: 0
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
} else if (toolId === import_core.ToolName.ContextAnalyzer && output.summary) {
|
|
265
|
-
toolScore.tokenBudget = (0, import_core.calculateTokenBudget)({
|
|
266
|
-
totalContextTokens: output.summary.totalTokens,
|
|
267
|
-
wastedTokens: {
|
|
268
|
-
duplication: 0,
|
|
269
|
-
fragmentation: output.summary.totalPotentialSavings ?? 0,
|
|
270
|
-
chattiness: 0
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
toolScores.set(toolId, toolScore);
|
|
276
|
-
} catch (err) {
|
|
277
|
-
console.error(`\u274C Error scoring tool '${toolId}':`, err);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
if (toolScores.size === 0) {
|
|
281
|
-
return {
|
|
282
|
-
overall: 0,
|
|
283
|
-
rating: "Critical",
|
|
284
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
285
|
-
toolsUsed: [],
|
|
286
|
-
breakdown: [],
|
|
287
|
-
calculation: {
|
|
288
|
-
formula: "0 / 0 = 0",
|
|
289
|
-
weights: {},
|
|
290
|
-
normalized: "0 / 0 = 0"
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
return (0, import_core.calculateOverallScore)(toolScores, options, void 0);
|
|
295
|
-
}
|
|
38
|
+
// src/utils/index.ts
|
|
39
|
+
var import_core2 = require("@aiready/core");
|
|
296
40
|
|
|
297
41
|
// src/utils/helpers.ts
|
|
298
42
|
var import_path = require("path");
|
|
299
43
|
var import_fs = require("fs");
|
|
300
44
|
var import_chalk = __toESM(require("chalk"));
|
|
301
|
-
var
|
|
302
|
-
var import_core3 = require("@aiready/core");
|
|
303
|
-
function getReportTimestamp() {
|
|
304
|
-
const now = /* @__PURE__ */ new Date();
|
|
305
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
306
|
-
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
307
|
-
}
|
|
45
|
+
var import_core = require("@aiready/core");
|
|
308
46
|
async function warnIfGraphCapExceeded(report, dirPath) {
|
|
309
47
|
try {
|
|
310
48
|
const { loadConfig: loadConfig4 } = await import("@aiready/core");
|
|
@@ -393,7 +131,7 @@ function generateMarkdownReport(report, elapsedTime) {
|
|
|
393
131
|
|
|
394
132
|
// src/commands/report-formatter.ts
|
|
395
133
|
var import_chalk2 = __toESM(require("chalk"));
|
|
396
|
-
var
|
|
134
|
+
var import_core3 = require("@aiready/core");
|
|
397
135
|
function generateProgressBar(score, width = 20) {
|
|
398
136
|
const filled = Math.round(score / 100 * width);
|
|
399
137
|
const empty = width - filled;
|
|
@@ -498,31 +236,34 @@ function printBusinessImpact(roi, unifiedBudget) {
|
|
|
498
236
|
}
|
|
499
237
|
function printScoring(scoringResult, scoringProfile) {
|
|
500
238
|
console.log(import_chalk2.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
501
|
-
console.log(` ${(0,
|
|
239
|
+
console.log(` ${(0, import_core3.formatScore)(scoringResult)}`);
|
|
502
240
|
console.log(import_chalk2.default.dim(` (Scoring Profile: ${scoringProfile})`));
|
|
503
241
|
if (scoringResult.breakdown) {
|
|
504
242
|
console.log(import_chalk2.default.bold("\nTool breakdown:"));
|
|
505
243
|
scoringResult.breakdown.forEach((tool) => {
|
|
506
|
-
const rating = (0,
|
|
507
|
-
const emoji = (0,
|
|
244
|
+
const rating = (0, import_core3.getRating)(tool.score);
|
|
245
|
+
const emoji = (0, import_core3.getRatingDisplay)(rating).emoji;
|
|
508
246
|
const progressBar = generateProgressBar(tool.score, 15);
|
|
509
247
|
console.log(
|
|
510
248
|
` ${progressBar} ${tool.score}/100 (${rating}) ${emoji} ${tool.toolName}`
|
|
511
249
|
);
|
|
512
250
|
});
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
});
|
|
525
|
-
|
|
251
|
+
printTopRecommendations(scoringResult.breakdown);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function printTopRecommendations(breakdown) {
|
|
255
|
+
const allRecs = breakdown.flatMap(
|
|
256
|
+
(t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
|
|
257
|
+
).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
|
|
258
|
+
if (allRecs.length > 0) {
|
|
259
|
+
console.log(import_chalk2.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
|
|
260
|
+
allRecs.forEach((rec, i) => {
|
|
261
|
+
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
262
|
+
console.log(` ${i + 1}. ${priorityIcon} ${import_chalk2.default.bold(rec.action)}`);
|
|
263
|
+
console.log(
|
|
264
|
+
` Impact: ${import_chalk2.default.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
|
|
265
|
+
);
|
|
266
|
+
});
|
|
526
267
|
}
|
|
527
268
|
}
|
|
528
269
|
function mapToUnifiedReport(res, scoring) {
|
|
@@ -537,9 +278,9 @@ function mapToUnifiedReport(res, scoring) {
|
|
|
537
278
|
totalFilesSet.add(r.fileName);
|
|
538
279
|
allResults.push(r);
|
|
539
280
|
r.issues?.forEach((i) => {
|
|
540
|
-
if (i.severity ===
|
|
281
|
+
if (i.severity === import_core3.Severity.Critical || i.severity === "critical")
|
|
541
282
|
criticalCount++;
|
|
542
|
-
if (i.severity ===
|
|
283
|
+
if (i.severity === import_core3.Severity.Major || i.severity === "major")
|
|
543
284
|
majorCount++;
|
|
544
285
|
});
|
|
545
286
|
});
|
|
@@ -561,7 +302,7 @@ function mapToUnifiedReport(res, scoring) {
|
|
|
561
302
|
var import_fs2 = __toESM(require("fs"));
|
|
562
303
|
var import_path2 = require("path");
|
|
563
304
|
var import_chalk3 = __toESM(require("chalk"));
|
|
564
|
-
var
|
|
305
|
+
var import_core4 = require("@aiready/core");
|
|
565
306
|
async function uploadAction(file, options) {
|
|
566
307
|
const startTime = Date.now();
|
|
567
308
|
const filePath = (0, import_path2.resolve)(process.cwd(), file);
|
|
@@ -648,265 +389,551 @@ async function uploadAction(file, options) {
|
|
|
648
389
|
console.log(import_chalk3.default.dim(` Score: ${uploadResult.analysis.aiScore}/100`));
|
|
649
390
|
}
|
|
650
391
|
} catch (error) {
|
|
651
|
-
(0,
|
|
392
|
+
(0, import_core4.handleCLIError)(error, "Upload");
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
var UPLOAD_HELP_TEXT = `
|
|
396
|
+
EXAMPLES:
|
|
397
|
+
$ aiready upload report.json --api-key ar_...
|
|
398
|
+
$ aiready upload .aiready/latest.json
|
|
399
|
+
$ AIREADY_API_KEY=ar_... aiready upload report.json
|
|
400
|
+
|
|
401
|
+
ENVIRONMENT VARIABLES:
|
|
402
|
+
AIREADY_API_KEY Your platform API key
|
|
403
|
+
AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
|
|
404
|
+
`;
|
|
405
|
+
|
|
406
|
+
// src/commands/scan-config.ts
|
|
407
|
+
var import_core6 = require("@aiready/core");
|
|
408
|
+
|
|
409
|
+
// src/commands/scan-helpers.ts
|
|
410
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
411
|
+
var import_core5 = require("@aiready/core");
|
|
412
|
+
function getProfileTools(profile) {
|
|
413
|
+
switch (profile.toLowerCase()) {
|
|
414
|
+
case "agentic":
|
|
415
|
+
return [
|
|
416
|
+
import_core5.ToolName.AiSignalClarity,
|
|
417
|
+
import_core5.ToolName.AgentGrounding,
|
|
418
|
+
import_core5.ToolName.TestabilityIndex
|
|
419
|
+
];
|
|
420
|
+
case "cost":
|
|
421
|
+
return [import_core5.ToolName.PatternDetect, import_core5.ToolName.ContextAnalyzer];
|
|
422
|
+
case "logic":
|
|
423
|
+
return [
|
|
424
|
+
import_core5.ToolName.TestabilityIndex,
|
|
425
|
+
import_core5.ToolName.NamingConsistency,
|
|
426
|
+
import_core5.ToolName.ContextAnalyzer,
|
|
427
|
+
import_core5.ToolName.PatternDetect,
|
|
428
|
+
import_core5.ToolName.ChangeAmplification
|
|
429
|
+
];
|
|
430
|
+
case "ui":
|
|
431
|
+
return [
|
|
432
|
+
import_core5.ToolName.NamingConsistency,
|
|
433
|
+
import_core5.ToolName.ContextAnalyzer,
|
|
434
|
+
import_core5.ToolName.PatternDetect,
|
|
435
|
+
import_core5.ToolName.DocDrift,
|
|
436
|
+
import_core5.ToolName.AiSignalClarity
|
|
437
|
+
];
|
|
438
|
+
case "security":
|
|
439
|
+
return [import_core5.ToolName.NamingConsistency, import_core5.ToolName.TestabilityIndex];
|
|
440
|
+
case "onboarding":
|
|
441
|
+
return [
|
|
442
|
+
import_core5.ToolName.ContextAnalyzer,
|
|
443
|
+
import_core5.ToolName.NamingConsistency,
|
|
444
|
+
import_core5.ToolName.AgentGrounding
|
|
445
|
+
];
|
|
446
|
+
default:
|
|
447
|
+
console.log(
|
|
448
|
+
import_chalk4.default.yellow(`
|
|
449
|
+
\u26A0\uFE0F Unknown profile '${profile}'. Using defaults.`)
|
|
450
|
+
);
|
|
451
|
+
return void 0;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function createProgressCallback() {
|
|
455
|
+
return (event) => {
|
|
456
|
+
if (event.message) {
|
|
457
|
+
process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
process.stdout.write("\r\x1B[K");
|
|
461
|
+
console.log(import_chalk4.default.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
462
|
+
const toolResult = event.data;
|
|
463
|
+
if (toolResult && toolResult.summary) {
|
|
464
|
+
if (toolResult.summary.totalIssues !== void 0)
|
|
465
|
+
console.log(
|
|
466
|
+
` Issues found: ${import_chalk4.default.bold(toolResult.summary.totalIssues)}`
|
|
467
|
+
);
|
|
468
|
+
if (toolResult.summary.score !== void 0)
|
|
469
|
+
console.log(
|
|
470
|
+
` Tool Score: ${import_chalk4.default.bold(toolResult.summary.score)}/100`
|
|
471
|
+
);
|
|
472
|
+
if (toolResult.summary.totalFiles !== void 0)
|
|
473
|
+
console.log(
|
|
474
|
+
` Files analyzed: ${import_chalk4.default.bold(toolResult.summary.totalFiles)}`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/commands/scan-config.ts
|
|
481
|
+
var SCAN_DEFAULTS = {
|
|
482
|
+
tools: [
|
|
483
|
+
"pattern-detect",
|
|
484
|
+
"context-analyzer",
|
|
485
|
+
"naming-consistency",
|
|
486
|
+
"ai-signal-clarity",
|
|
487
|
+
"agent-grounding",
|
|
488
|
+
"testability-index",
|
|
489
|
+
"doc-drift",
|
|
490
|
+
"dependency-health",
|
|
491
|
+
"change-amplification"
|
|
492
|
+
],
|
|
493
|
+
include: void 0,
|
|
494
|
+
exclude: void 0,
|
|
495
|
+
output: {
|
|
496
|
+
format: "console",
|
|
497
|
+
file: void 0
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
async function resolveScanConfig(resolvedDir, options) {
|
|
501
|
+
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
502
|
+
if (options.profile) {
|
|
503
|
+
profileTools = getProfileTools(options.profile);
|
|
504
|
+
}
|
|
505
|
+
const cliOverrides = {
|
|
506
|
+
include: options.include?.split(","),
|
|
507
|
+
exclude: options.exclude?.split(",")
|
|
508
|
+
};
|
|
509
|
+
if (profileTools) cliOverrides.tools = profileTools;
|
|
510
|
+
const baseOptions = await (0, import_core6.loadMergedConfig)(
|
|
511
|
+
resolvedDir,
|
|
512
|
+
SCAN_DEFAULTS,
|
|
513
|
+
cliOverrides
|
|
514
|
+
);
|
|
515
|
+
const finalOptions = { ...baseOptions };
|
|
516
|
+
if (baseOptions.tools.includes(import_core6.ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
|
|
517
|
+
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
518
|
+
const patternSmartDefaults = await getSmartDefaults(
|
|
519
|
+
resolvedDir,
|
|
520
|
+
finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] ?? {}
|
|
521
|
+
);
|
|
522
|
+
if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
|
|
523
|
+
finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
|
|
524
|
+
...patternSmartDefaults,
|
|
525
|
+
...finalOptions.toolConfigs[import_core6.ToolName.PatternDetect]
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
return finalOptions;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/commands/scan-orchestrator.ts
|
|
532
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
533
|
+
var import_fs3 = require("fs");
|
|
534
|
+
var import_path3 = require("path");
|
|
535
|
+
var import_core8 = require("@aiready/core");
|
|
536
|
+
|
|
537
|
+
// src/index.ts
|
|
538
|
+
var import_core7 = require("@aiready/core");
|
|
539
|
+
var TOOL_PACKAGE_MAP = {
|
|
540
|
+
[import_core7.ToolName.PatternDetect]: "@aiready/pattern-detect",
|
|
541
|
+
[import_core7.ToolName.ContextAnalyzer]: "@aiready/context-analyzer",
|
|
542
|
+
[import_core7.ToolName.NamingConsistency]: "@aiready/consistency",
|
|
543
|
+
[import_core7.ToolName.AiSignalClarity]: "@aiready/ai-signal-clarity",
|
|
544
|
+
[import_core7.ToolName.AgentGrounding]: "@aiready/agent-grounding",
|
|
545
|
+
[import_core7.ToolName.TestabilityIndex]: "@aiready/testability",
|
|
546
|
+
[import_core7.ToolName.DocDrift]: "@aiready/doc-drift",
|
|
547
|
+
[import_core7.ToolName.DependencyHealth]: "@aiready/deps",
|
|
548
|
+
[import_core7.ToolName.ChangeAmplification]: "@aiready/change-amplification",
|
|
549
|
+
// Aliases handled by registry
|
|
550
|
+
patterns: "@aiready/pattern-detect",
|
|
551
|
+
duplicates: "@aiready/pattern-detect",
|
|
552
|
+
context: "@aiready/context-analyzer",
|
|
553
|
+
fragmentation: "@aiready/context-analyzer",
|
|
554
|
+
consistency: "@aiready/consistency",
|
|
555
|
+
"ai-signal": "@aiready/ai-signal-clarity",
|
|
556
|
+
grounding: "@aiready/agent-grounding",
|
|
557
|
+
testability: "@aiready/testability",
|
|
558
|
+
"deps-health": "@aiready/deps",
|
|
559
|
+
"change-amp": "@aiready/change-amplification"
|
|
560
|
+
};
|
|
561
|
+
function sanitizeConfigRecursive(obj) {
|
|
562
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
|
|
563
|
+
const sanitized = {};
|
|
564
|
+
const infraToStrip = [
|
|
565
|
+
"rootDir",
|
|
566
|
+
"onProgress",
|
|
567
|
+
"progressCallback",
|
|
568
|
+
"streamResults",
|
|
569
|
+
"batchSize",
|
|
570
|
+
"useSmartDefaults"
|
|
571
|
+
];
|
|
572
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
573
|
+
if (infraToStrip.includes(key)) continue;
|
|
574
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
575
|
+
sanitized[key] = sanitizeConfigRecursive(value);
|
|
576
|
+
} else {
|
|
577
|
+
sanitized[key] = value;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return sanitized;
|
|
581
|
+
}
|
|
582
|
+
function sanitizeToolConfig(config) {
|
|
583
|
+
return sanitizeConfigRecursive(config);
|
|
584
|
+
}
|
|
585
|
+
async function analyzeUnified(options) {
|
|
586
|
+
await (0, import_core7.initializeParsers)();
|
|
587
|
+
const startTime = Date.now();
|
|
588
|
+
const requestedTools = options.tools ?? [
|
|
589
|
+
"patterns",
|
|
590
|
+
"context",
|
|
591
|
+
"consistency"
|
|
592
|
+
];
|
|
593
|
+
const result = {
|
|
594
|
+
summary: {
|
|
595
|
+
totalIssues: 0,
|
|
596
|
+
criticalIssues: 0,
|
|
597
|
+
// Added as per instruction
|
|
598
|
+
majorIssues: 0,
|
|
599
|
+
// Added as per instruction
|
|
600
|
+
totalFiles: 0,
|
|
601
|
+
toolsRun: [],
|
|
602
|
+
executionTime: 0,
|
|
603
|
+
config: options,
|
|
604
|
+
toolConfigs: {}
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
for (const toolName of requestedTools) {
|
|
608
|
+
let provider = import_core7.ToolRegistry.find(toolName);
|
|
609
|
+
if (!provider) {
|
|
610
|
+
const packageName = TOOL_PACKAGE_MAP[toolName] ?? (toolName.startsWith("@aiready/") ? toolName : `@aiready/${toolName}`);
|
|
611
|
+
try {
|
|
612
|
+
await import(packageName);
|
|
613
|
+
provider = import_core7.ToolRegistry.find(toolName);
|
|
614
|
+
if (provider) {
|
|
615
|
+
console.log(
|
|
616
|
+
`\u2705 Successfully loaded tool provider: ${toolName} from ${packageName}`
|
|
617
|
+
);
|
|
618
|
+
} else {
|
|
619
|
+
console.log(
|
|
620
|
+
`\u26A0\uFE0F Loaded ${packageName} but provider ${toolName} still not found in registry.`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
} catch (err) {
|
|
624
|
+
console.log(
|
|
625
|
+
`\u274C Failed to dynamically load tool ${toolName} (${packageName}):`,
|
|
626
|
+
err.message
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (!provider) {
|
|
631
|
+
console.warn(
|
|
632
|
+
`\u26A0\uFE0F Warning: Tool provider for '${toolName}' not found. Skipping.`
|
|
633
|
+
);
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
try {
|
|
637
|
+
const sanitizedOptions = { ...options };
|
|
638
|
+
delete sanitizedOptions.onProgress;
|
|
639
|
+
delete sanitizedOptions.progressCallback;
|
|
640
|
+
const toolOptions = {
|
|
641
|
+
rootDir: options.rootDir
|
|
642
|
+
// Always include rootDir
|
|
643
|
+
};
|
|
644
|
+
[...import_core7.GLOBAL_INFRA_OPTIONS, ...import_core7.COMMON_FINE_TUNING_OPTIONS].forEach(
|
|
645
|
+
(key) => {
|
|
646
|
+
if (key in options && key !== "toolConfigs" && key !== "tools") {
|
|
647
|
+
toolOptions[key] = options[key];
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
);
|
|
651
|
+
if (options.toolConfigs?.[provider.id]) {
|
|
652
|
+
Object.assign(toolOptions, options.toolConfigs[provider.id]);
|
|
653
|
+
} else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
|
|
654
|
+
Object.assign(toolOptions, options.tools[provider.id]);
|
|
655
|
+
} else if (options[provider.id]) {
|
|
656
|
+
Object.assign(toolOptions, options[provider.id]);
|
|
657
|
+
}
|
|
658
|
+
toolOptions.onProgress = (processed, total, message) => {
|
|
659
|
+
if (options.progressCallback) {
|
|
660
|
+
options.progressCallback({
|
|
661
|
+
tool: provider.id,
|
|
662
|
+
processed,
|
|
663
|
+
total,
|
|
664
|
+
message
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
const output = await provider.analyze(toolOptions);
|
|
669
|
+
if (output.metadata) {
|
|
670
|
+
output.metadata.config = sanitizeToolConfig(toolOptions);
|
|
671
|
+
}
|
|
672
|
+
if (options.progressCallback) {
|
|
673
|
+
options.progressCallback({ tool: provider.id, data: output });
|
|
674
|
+
}
|
|
675
|
+
result[provider.id] = output;
|
|
676
|
+
result.summary.toolsRun.push(provider.id);
|
|
677
|
+
if (output.summary?.config) {
|
|
678
|
+
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
|
|
679
|
+
output.summary.config
|
|
680
|
+
);
|
|
681
|
+
} else if (output.metadata?.config) {
|
|
682
|
+
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(
|
|
683
|
+
output.metadata.config
|
|
684
|
+
);
|
|
685
|
+
} else {
|
|
686
|
+
result.summary.toolConfigs[provider.id] = sanitizeToolConfig(toolOptions);
|
|
687
|
+
}
|
|
688
|
+
const toolFiles = output.summary?.totalFiles ?? output.summary?.filesAnalyzed ?? 0;
|
|
689
|
+
if (toolFiles > result.summary.totalFiles) {
|
|
690
|
+
result.summary.totalFiles = toolFiles;
|
|
691
|
+
}
|
|
692
|
+
const issueCount = output.results.reduce(
|
|
693
|
+
(sum, file) => sum + (file.issues?.length ?? 0),
|
|
694
|
+
0
|
|
695
|
+
);
|
|
696
|
+
result.summary.totalIssues += issueCount;
|
|
697
|
+
} catch (err) {
|
|
698
|
+
console.error(`\u274C Error running tool '${provider.id}':`, err);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
result.summary.config = sanitizeConfigRecursive({
|
|
702
|
+
scan: {
|
|
703
|
+
tools: requestedTools,
|
|
704
|
+
include: options.include,
|
|
705
|
+
exclude: options.exclude
|
|
706
|
+
},
|
|
707
|
+
// Use 'tools' for tool-specific configurations to match AIReadyConfig
|
|
708
|
+
tools: result.summary.toolConfigs
|
|
709
|
+
});
|
|
710
|
+
result.summary.executionTime = Date.now() - startTime;
|
|
711
|
+
const keyMappings = {
|
|
712
|
+
"pattern-detect": ["patternDetect", "patterns"],
|
|
713
|
+
"context-analyzer": ["contextAnalyzer", "context"],
|
|
714
|
+
"naming-consistency": ["namingConsistency", "consistency"],
|
|
715
|
+
"ai-signal-clarity": ["aiSignalClarity"],
|
|
716
|
+
"agent-grounding": ["agentGrounding"],
|
|
717
|
+
"testability-index": ["testabilityIndex", "testability"],
|
|
718
|
+
"doc-drift": ["docDrift"],
|
|
719
|
+
"dependency-health": ["dependencyHealth", "deps"],
|
|
720
|
+
"change-amplification": ["changeAmplification"]
|
|
721
|
+
};
|
|
722
|
+
for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
|
|
723
|
+
if (result[kebabKey]) {
|
|
724
|
+
for (const alias of aliases) {
|
|
725
|
+
result[alias] = result[kebabKey];
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
731
|
+
async function scoreUnified(results, options) {
|
|
732
|
+
const toolScores = /* @__PURE__ */ new Map();
|
|
733
|
+
for (const toolId of results.summary.toolsRun) {
|
|
734
|
+
const provider = import_core7.ToolRegistry.get(toolId);
|
|
735
|
+
if (!provider) continue;
|
|
736
|
+
const output = results[toolId];
|
|
737
|
+
if (!output) continue;
|
|
738
|
+
try {
|
|
739
|
+
const toolScore = provider.score(output, options);
|
|
740
|
+
if (!toolScore.tokenBudget) {
|
|
741
|
+
if (toolId === import_core7.ToolName.PatternDetect && output.duplicates) {
|
|
742
|
+
const wastedTokens = output.duplicates.reduce(
|
|
743
|
+
(sum, d) => sum + (d.tokenCost ?? 0),
|
|
744
|
+
0
|
|
745
|
+
);
|
|
746
|
+
toolScore.tokenBudget = (0, import_core7.calculateTokenBudget)({
|
|
747
|
+
totalContextTokens: wastedTokens * 2,
|
|
748
|
+
wastedTokens: {
|
|
749
|
+
duplication: wastedTokens,
|
|
750
|
+
fragmentation: 0,
|
|
751
|
+
chattiness: 0
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
} else if (toolId === import_core7.ToolName.ContextAnalyzer && output.summary) {
|
|
755
|
+
toolScore.tokenBudget = (0, import_core7.calculateTokenBudget)({
|
|
756
|
+
totalContextTokens: output.summary.totalTokens,
|
|
757
|
+
wastedTokens: {
|
|
758
|
+
duplication: 0,
|
|
759
|
+
fragmentation: output.summary.totalPotentialSavings ?? 0,
|
|
760
|
+
chattiness: 0
|
|
761
|
+
}
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
toolScores.set(toolId, toolScore);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
console.error(`\u274C Error scoring tool '${toolId}':`, err);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (toolScores.size === 0) {
|
|
771
|
+
return {
|
|
772
|
+
overall: 0,
|
|
773
|
+
rating: "Critical",
|
|
774
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
775
|
+
toolsUsed: [],
|
|
776
|
+
breakdown: [],
|
|
777
|
+
calculation: {
|
|
778
|
+
formula: "0 / 0 = 0",
|
|
779
|
+
weights: {},
|
|
780
|
+
normalized: "0 / 0 = 0"
|
|
781
|
+
}
|
|
782
|
+
};
|
|
652
783
|
}
|
|
784
|
+
return (0, import_core7.calculateOverallScore)(toolScores, options, void 0);
|
|
653
785
|
}
|
|
654
|
-
var UPLOAD_HELP_TEXT = `
|
|
655
|
-
EXAMPLES:
|
|
656
|
-
$ aiready upload report.json --api-key ar_...
|
|
657
|
-
$ aiready upload .aiready/latest.json
|
|
658
|
-
$ AIREADY_API_KEY=ar_... aiready upload report.json
|
|
659
|
-
|
|
660
|
-
ENVIRONMENT VARIABLES:
|
|
661
|
-
AIREADY_API_KEY Your platform API key
|
|
662
|
-
AIREADY_SERVER Custom platform URL (default: https://dev.platform.getaiready.dev)
|
|
663
|
-
`;
|
|
664
786
|
|
|
665
|
-
// src/commands/scan-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
import_core6.ToolName.AgentGrounding
|
|
701
|
-
];
|
|
702
|
-
default:
|
|
703
|
-
console.log(
|
|
704
|
-
import_chalk4.default.yellow(`
|
|
705
|
-
\u26A0\uFE0F Unknown profile '${profile}'. Using defaults.`)
|
|
706
|
-
);
|
|
707
|
-
return void 0;
|
|
787
|
+
// src/commands/scan-orchestrator.ts
|
|
788
|
+
async function runUnifiedScan(resolvedDir, finalOptions, options, startTime) {
|
|
789
|
+
console.log(import_chalk5.default.cyan("\n=== AIReady Run Preview ==="));
|
|
790
|
+
console.log(
|
|
791
|
+
import_chalk5.default.white("Tools to run:"),
|
|
792
|
+
(finalOptions.tools ?? []).join(", ")
|
|
793
|
+
);
|
|
794
|
+
const progressCallback = createProgressCallback();
|
|
795
|
+
const scoringProfile = options.profile ?? finalOptions.scoring?.profile ?? "default";
|
|
796
|
+
const results = await analyzeUnified({
|
|
797
|
+
...finalOptions,
|
|
798
|
+
progressCallback,
|
|
799
|
+
onProgress: () => {
|
|
800
|
+
},
|
|
801
|
+
suppressToolConfig: true
|
|
802
|
+
});
|
|
803
|
+
printScanSummary(results, startTime);
|
|
804
|
+
let scoringResult;
|
|
805
|
+
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
806
|
+
scoringResult = await scoreUnified(results, {
|
|
807
|
+
...finalOptions,
|
|
808
|
+
scoring: {
|
|
809
|
+
...finalOptions.scoring,
|
|
810
|
+
profile: scoringProfile
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
printScoring(scoringResult, scoringProfile);
|
|
814
|
+
if (options.compareTo) {
|
|
815
|
+
handleTrendComparison(options.compareTo, scoringResult);
|
|
816
|
+
}
|
|
817
|
+
await handleBusinessImpactMetrics(
|
|
818
|
+
results,
|
|
819
|
+
scoringResult,
|
|
820
|
+
options.model ?? "gpt-5.4-mini"
|
|
821
|
+
);
|
|
708
822
|
}
|
|
823
|
+
return { results, scoringResult };
|
|
709
824
|
}
|
|
710
|
-
function
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
if (toolResult.summary.totalIssues !== void 0)
|
|
825
|
+
function handleTrendComparison(baselinePath, currentScoring) {
|
|
826
|
+
try {
|
|
827
|
+
const prevReport = JSON.parse(
|
|
828
|
+
(0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), baselinePath), "utf8")
|
|
829
|
+
);
|
|
830
|
+
const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
|
|
831
|
+
if (typeof prevScore === "number") {
|
|
832
|
+
const diff = currentScoring.overall - prevScore;
|
|
833
|
+
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
834
|
+
if (diff > 0)
|
|
721
835
|
console.log(
|
|
722
|
-
|
|
836
|
+
import_chalk5.default.green(
|
|
837
|
+
` \u{1F4C8} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
|
|
838
|
+
)
|
|
723
839
|
);
|
|
724
|
-
if (
|
|
840
|
+
else if (diff < 0)
|
|
725
841
|
console.log(
|
|
726
|
-
|
|
842
|
+
import_chalk5.default.red(
|
|
843
|
+
` \u{1F4C9} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
|
|
844
|
+
)
|
|
727
845
|
);
|
|
728
|
-
|
|
846
|
+
else
|
|
729
847
|
console.log(
|
|
730
|
-
|
|
848
|
+
import_chalk5.default.blue(
|
|
849
|
+
` \u2796 Trend: No change (${prevScore} \u2192 ${currentScoring.overall})`
|
|
850
|
+
)
|
|
731
851
|
);
|
|
732
852
|
}
|
|
733
|
-
}
|
|
853
|
+
} catch (e) {
|
|
854
|
+
void e;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
async function handleBusinessImpactMetrics(results, scoringResult, modelId) {
|
|
858
|
+
const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
|
|
859
|
+
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
|
|
860
|
+
0
|
|
861
|
+
);
|
|
862
|
+
const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
|
|
863
|
+
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
|
|
864
|
+
0
|
|
865
|
+
);
|
|
866
|
+
const totalContext = Math.max(
|
|
867
|
+
...(scoringResult.breakdown ?? []).map(
|
|
868
|
+
(s) => s.tokenBudget?.totalContextTokens ?? 0
|
|
869
|
+
),
|
|
870
|
+
0
|
|
871
|
+
);
|
|
872
|
+
if (totalContext > 0) {
|
|
873
|
+
const unifiedBudget = (0, import_core8.calculateTokenBudget)({
|
|
874
|
+
totalContextTokens: totalContext,
|
|
875
|
+
wastedTokens: {
|
|
876
|
+
duplication: totalWastedDuplication,
|
|
877
|
+
fragmentation: totalWastedFragmentation,
|
|
878
|
+
chattiness: totalContext * 0.1
|
|
879
|
+
// Default chattiness
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
const allIssues = [];
|
|
883
|
+
for (const toolId of results.summary.toolsRun) {
|
|
884
|
+
if (results[toolId]?.results) {
|
|
885
|
+
results[toolId].results.forEach((fileRes) => {
|
|
886
|
+
if (fileRes.issues) {
|
|
887
|
+
allIssues.push(...fileRes.issues);
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const { calculateBusinessROI } = await import("@aiready/core");
|
|
893
|
+
const roi = calculateBusinessROI({
|
|
894
|
+
tokenWaste: unifiedBudget.wastedTokens.total,
|
|
895
|
+
issues: allIssues,
|
|
896
|
+
modelId
|
|
897
|
+
});
|
|
898
|
+
printBusinessImpact(roi, unifiedBudget);
|
|
899
|
+
results.summary.businessImpact = {
|
|
900
|
+
estimatedMonthlyWaste: roi.monthlySavings,
|
|
901
|
+
potentialSavings: roi.monthlySavings,
|
|
902
|
+
productivityHours: roi.productivityGainHours
|
|
903
|
+
};
|
|
904
|
+
scoringResult.tokenBudget = unifiedBudget;
|
|
905
|
+
scoringResult.businessROI = roi;
|
|
906
|
+
}
|
|
734
907
|
}
|
|
735
908
|
|
|
736
909
|
// src/commands/scan.ts
|
|
737
910
|
async function scanAction(directory, options) {
|
|
738
|
-
console.log(
|
|
911
|
+
console.log(import_chalk6.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
739
912
|
const startTime = Date.now();
|
|
740
|
-
const resolvedDir = (0,
|
|
741
|
-
const repoMetadata = (0,
|
|
913
|
+
const resolvedDir = (0, import_path4.resolve)(process.cwd(), directory ?? ".");
|
|
914
|
+
const repoMetadata = (0, import_core9.getRepoMetadata)(resolvedDir);
|
|
742
915
|
try {
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
"pattern-detect",
|
|
746
|
-
"context-analyzer",
|
|
747
|
-
"naming-consistency",
|
|
748
|
-
"ai-signal-clarity",
|
|
749
|
-
"agent-grounding",
|
|
750
|
-
"testability-index",
|
|
751
|
-
"doc-drift",
|
|
752
|
-
"dependency-health",
|
|
753
|
-
"change-amplification"
|
|
754
|
-
],
|
|
755
|
-
include: void 0,
|
|
756
|
-
exclude: void 0,
|
|
757
|
-
output: {
|
|
758
|
-
format: "console",
|
|
759
|
-
file: void 0
|
|
760
|
-
}
|
|
761
|
-
};
|
|
762
|
-
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
763
|
-
if (options.profile) {
|
|
764
|
-
profileTools = getProfileTools(options.profile);
|
|
765
|
-
}
|
|
766
|
-
const cliOverrides = {
|
|
767
|
-
include: options.include?.split(","),
|
|
768
|
-
exclude: options.exclude?.split(",")
|
|
769
|
-
};
|
|
770
|
-
if (profileTools) cliOverrides.tools = profileTools;
|
|
771
|
-
const baseOptions = await (0, import_core7.loadMergedConfig)(
|
|
916
|
+
const finalOptions = await resolveScanConfig(resolvedDir, options);
|
|
917
|
+
const { results, scoringResult } = await runUnifiedScan(
|
|
772
918
|
resolvedDir,
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
const finalOptions = { ...baseOptions };
|
|
777
|
-
if (baseOptions.tools.includes(import_core7.ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
|
|
778
|
-
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
779
|
-
const patternSmartDefaults = await getSmartDefaults(
|
|
780
|
-
resolvedDir,
|
|
781
|
-
finalOptions.toolConfigs?.[import_core7.ToolName.PatternDetect] ?? {}
|
|
782
|
-
);
|
|
783
|
-
if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
|
|
784
|
-
finalOptions.toolConfigs[import_core7.ToolName.PatternDetect] = {
|
|
785
|
-
...patternSmartDefaults,
|
|
786
|
-
...finalOptions.toolConfigs[import_core7.ToolName.PatternDetect]
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
console.log(import_chalk5.default.cyan("\n=== AIReady Run Preview ==="));
|
|
790
|
-
console.log(
|
|
791
|
-
import_chalk5.default.white("Tools to run:"),
|
|
792
|
-
(finalOptions.tools ?? []).join(", ")
|
|
919
|
+
finalOptions,
|
|
920
|
+
options,
|
|
921
|
+
startTime
|
|
793
922
|
);
|
|
794
|
-
const progressCallback = createProgressCallback();
|
|
795
|
-
const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
|
|
796
|
-
const results = await analyzeUnified({
|
|
797
|
-
...finalOptions,
|
|
798
|
-
progressCallback,
|
|
799
|
-
onProgress: () => {
|
|
800
|
-
},
|
|
801
|
-
suppressToolConfig: true
|
|
802
|
-
});
|
|
803
|
-
printScanSummary(results, startTime);
|
|
804
|
-
let scoringResult;
|
|
805
|
-
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
806
|
-
scoringResult = await scoreUnified(results, {
|
|
807
|
-
...finalOptions,
|
|
808
|
-
scoring: {
|
|
809
|
-
...finalOptions.scoring,
|
|
810
|
-
profile: scoringProfile
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
printScoring(scoringResult, scoringProfile);
|
|
814
|
-
if (options.compareTo) {
|
|
815
|
-
try {
|
|
816
|
-
const prevReport = JSON.parse(
|
|
817
|
-
(0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), options.compareTo), "utf8")
|
|
818
|
-
);
|
|
819
|
-
const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
|
|
820
|
-
if (typeof prevScore === "number") {
|
|
821
|
-
const diff = scoringResult.overall - prevScore;
|
|
822
|
-
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
823
|
-
if (diff > 0)
|
|
824
|
-
console.log(
|
|
825
|
-
import_chalk5.default.green(
|
|
826
|
-
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
827
|
-
)
|
|
828
|
-
);
|
|
829
|
-
else if (diff < 0)
|
|
830
|
-
console.log(
|
|
831
|
-
import_chalk5.default.red(
|
|
832
|
-
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
833
|
-
)
|
|
834
|
-
);
|
|
835
|
-
else
|
|
836
|
-
console.log(
|
|
837
|
-
import_chalk5.default.blue(
|
|
838
|
-
` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
|
|
839
|
-
)
|
|
840
|
-
);
|
|
841
|
-
}
|
|
842
|
-
} catch (e) {
|
|
843
|
-
void e;
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
|
|
847
|
-
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
|
|
848
|
-
0
|
|
849
|
-
);
|
|
850
|
-
const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
|
|
851
|
-
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
|
|
852
|
-
0
|
|
853
|
-
);
|
|
854
|
-
const totalContext = Math.max(
|
|
855
|
-
...(scoringResult.breakdown ?? []).map(
|
|
856
|
-
(s) => s.tokenBudget?.totalContextTokens ?? 0
|
|
857
|
-
),
|
|
858
|
-
0
|
|
859
|
-
);
|
|
860
|
-
if (totalContext > 0) {
|
|
861
|
-
const unifiedBudget = (0, import_core7.calculateTokenBudget)({
|
|
862
|
-
totalContextTokens: totalContext,
|
|
863
|
-
wastedTokens: {
|
|
864
|
-
duplication: totalWastedDuplication,
|
|
865
|
-
fragmentation: totalWastedFragmentation,
|
|
866
|
-
chattiness: totalContext * 0.1
|
|
867
|
-
// Default chattiness
|
|
868
|
-
}
|
|
869
|
-
});
|
|
870
|
-
const allIssues = [];
|
|
871
|
-
for (const toolId of results.summary.toolsRun) {
|
|
872
|
-
if (results[toolId]?.results) {
|
|
873
|
-
results[toolId].results.forEach((fileRes) => {
|
|
874
|
-
if (fileRes.issues) {
|
|
875
|
-
allIssues.push(...fileRes.issues);
|
|
876
|
-
}
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
const modelId = options.model ?? "gpt-5.4-mini";
|
|
881
|
-
const roi = (await import("@aiready/core")).calculateBusinessROI({
|
|
882
|
-
tokenWaste: unifiedBudget.wastedTokens.total,
|
|
883
|
-
issues: allIssues,
|
|
884
|
-
modelId
|
|
885
|
-
});
|
|
886
|
-
printBusinessImpact(roi, unifiedBudget);
|
|
887
|
-
results.summary.businessImpact = {
|
|
888
|
-
estimatedMonthlyWaste: roi.monthlySavings,
|
|
889
|
-
potentialSavings: roi.monthlySavings,
|
|
890
|
-
productivityHours: roi.productivityGainHours
|
|
891
|
-
};
|
|
892
|
-
scoringResult.tokenBudget = unifiedBudget;
|
|
893
|
-
scoringResult.businessROI = roi;
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
923
|
console.log(
|
|
897
|
-
|
|
924
|
+
import_chalk6.default.dim(
|
|
898
925
|
"\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
899
926
|
)
|
|
900
927
|
);
|
|
901
|
-
console.log(
|
|
902
|
-
console.log(
|
|
928
|
+
console.log(import_chalk6.default.dim("\u{1F4AC} Found a bug or have a metric idea?"));
|
|
929
|
+
console.log(import_chalk6.default.dim("\u{1F449} Copy/paste this to your AI agent:"));
|
|
903
930
|
console.log(
|
|
904
|
-
|
|
931
|
+
import_chalk6.default.cyan(
|
|
905
932
|
` "Any feedback for the tools? Please use 'aiready bug' to report \u2764\uFE0F"`
|
|
906
933
|
)
|
|
907
934
|
);
|
|
908
935
|
console.log(
|
|
909
|
-
|
|
936
|
+
import_chalk6.default.dim(
|
|
910
937
|
"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
911
938
|
)
|
|
912
939
|
);
|
|
@@ -915,21 +942,21 @@ async function scanAction(directory, options) {
|
|
|
915
942
|
repository: repoMetadata
|
|
916
943
|
};
|
|
917
944
|
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
918
|
-
const outputPath = (0,
|
|
945
|
+
const outputPath = (0, import_core9.resolveOutputPath)(
|
|
919
946
|
options.outputFile ?? finalOptions.output?.file,
|
|
920
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
947
|
+
`aiready-report-${(0, import_core2.getReportTimestamp)()}.json`,
|
|
921
948
|
resolvedDir
|
|
922
949
|
);
|
|
923
950
|
if (outputFormat === "json") {
|
|
924
|
-
(0,
|
|
951
|
+
(0, import_core9.handleJSONOutput)(
|
|
925
952
|
outputData,
|
|
926
953
|
outputPath,
|
|
927
954
|
`\u2705 Report saved to ${outputPath}`
|
|
928
955
|
);
|
|
929
956
|
} else {
|
|
930
957
|
try {
|
|
931
|
-
(0,
|
|
932
|
-
console.log(
|
|
958
|
+
(0, import_fs4.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
|
|
959
|
+
console.log(import_chalk6.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
|
|
933
960
|
} catch (err) {
|
|
934
961
|
void err;
|
|
935
962
|
}
|
|
@@ -941,61 +968,83 @@ async function scanAction(directory, options) {
|
|
|
941
968
|
});
|
|
942
969
|
}
|
|
943
970
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
971
|
+
await handleGatekeeper(outputData, scoringResult, options, results);
|
|
972
|
+
} catch (error) {
|
|
973
|
+
(0, import_core9.handleCLIError)(error, "Analysis");
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
async function handleGatekeeper(outputData, scoringResult, options, results) {
|
|
977
|
+
if (!scoringResult) return;
|
|
978
|
+
const threshold = options.threshold ? parseInt(options.threshold) : void 0;
|
|
979
|
+
const failOnLevel = options.failOn ?? "critical";
|
|
980
|
+
const isCI = options.ci ?? process.env.CI === "true";
|
|
981
|
+
let shouldFail = false;
|
|
982
|
+
let failReason = "";
|
|
983
|
+
const report = mapToUnifiedReport(results, scoringResult);
|
|
984
|
+
if (isCI && report.results && report.results.length > 0) {
|
|
985
|
+
console.log(
|
|
986
|
+
import_chalk6.default.cyan(
|
|
987
|
+
`
|
|
955
988
|
\u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
if (shouldFail) {
|
|
974
|
-
console.log(import_chalk5.default.red(`
|
|
975
|
-
\u{1F6AB} SCAN FAILED: ${failReason}`));
|
|
976
|
-
process.exit(1);
|
|
977
|
-
} else {
|
|
978
|
-
console.log(import_chalk5.default.green("\n\u2705 SCAN PASSED"));
|
|
979
|
-
}
|
|
989
|
+
)
|
|
990
|
+
);
|
|
991
|
+
(0, import_core9.emitIssuesAsAnnotations)(report.results);
|
|
992
|
+
}
|
|
993
|
+
if (threshold && scoringResult.overall < threshold) {
|
|
994
|
+
shouldFail = true;
|
|
995
|
+
failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
|
|
996
|
+
}
|
|
997
|
+
if (failOnLevel !== "none") {
|
|
998
|
+
if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
|
|
999
|
+
shouldFail = true;
|
|
1000
|
+
failReason = `Found ${report.summary.criticalIssues} critical issues`;
|
|
1001
|
+
} else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
|
|
1002
|
+
shouldFail = true;
|
|
1003
|
+
failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
|
|
980
1004
|
}
|
|
981
|
-
}
|
|
982
|
-
|
|
1005
|
+
}
|
|
1006
|
+
if (shouldFail) {
|
|
1007
|
+
console.log(import_chalk6.default.red(`
|
|
1008
|
+
\u{1F6AB} SCAN FAILED: ${failReason}`));
|
|
1009
|
+
process.exit(1);
|
|
1010
|
+
} else {
|
|
1011
|
+
console.log(import_chalk6.default.green("\n\u2705 SCAN PASSED"));
|
|
983
1012
|
}
|
|
984
1013
|
}
|
|
985
|
-
var SCAN_HELP_TEXT =
|
|
1014
|
+
var SCAN_HELP_TEXT = `
|
|
1015
|
+
Run a comprehensive AI-readiness scan of your codebase.
|
|
1016
|
+
|
|
1017
|
+
${import_chalk6.default.bold("Examples:")}
|
|
1018
|
+
$ aiready scan .
|
|
1019
|
+
$ aiready scan src --profile agentic
|
|
1020
|
+
$ aiready scan . --threshold 80 --fail-on critical
|
|
1021
|
+
$ aiready scan . --output json --output-file report.json
|
|
1022
|
+
|
|
1023
|
+
${import_chalk6.default.bold("Profiles:")}
|
|
1024
|
+
agentic - Focus on AI signal clarity and agent grounding
|
|
1025
|
+
cost - Focus on token budget and pattern reuse
|
|
1026
|
+
logic - Focus on testability and naming consistency
|
|
1027
|
+
ui - Focus on component naming and documentation
|
|
1028
|
+
security - Focus on naming and testability
|
|
1029
|
+
onboarding - Focus on context and grounding
|
|
1030
|
+
|
|
1031
|
+
${import_chalk6.default.bold("CI/CD Integration:")}
|
|
1032
|
+
Use --threshold and --fail-on to use AIReady as a quality gate in your CI pipelines.
|
|
1033
|
+
When running in GitHub Actions, it will automatically emit annotations for found issues.
|
|
1034
|
+
`;
|
|
986
1035
|
|
|
987
1036
|
// src/commands/init.ts
|
|
988
|
-
var
|
|
989
|
-
var
|
|
990
|
-
var
|
|
991
|
-
var
|
|
1037
|
+
var import_fs5 = require("fs");
|
|
1038
|
+
var import_path5 = require("path");
|
|
1039
|
+
var import_chalk7 = __toESM(require("chalk"));
|
|
1040
|
+
var import_core10 = require("@aiready/core");
|
|
992
1041
|
async function initAction(options) {
|
|
993
1042
|
const fileExt = options.format === "js" ? "js" : "json";
|
|
994
1043
|
const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
|
|
995
|
-
const filePath = (0,
|
|
996
|
-
if ((0,
|
|
1044
|
+
const filePath = (0, import_path5.join)(process.cwd(), fileName);
|
|
1045
|
+
if ((0, import_fs5.existsSync)(filePath) && !options.force) {
|
|
997
1046
|
console.error(
|
|
998
|
-
|
|
1047
|
+
import_chalk7.default.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
|
|
999
1048
|
);
|
|
1000
1049
|
process.exit(1);
|
|
1001
1050
|
}
|
|
@@ -1019,15 +1068,15 @@ async function initAction(options) {
|
|
|
1019
1068
|
"**/*.spec.ts"
|
|
1020
1069
|
],
|
|
1021
1070
|
tools: [
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1071
|
+
import_core10.ToolName.PatternDetect,
|
|
1072
|
+
import_core10.ToolName.ContextAnalyzer,
|
|
1073
|
+
import_core10.ToolName.NamingConsistency,
|
|
1074
|
+
import_core10.ToolName.AiSignalClarity,
|
|
1075
|
+
import_core10.ToolName.AgentGrounding,
|
|
1076
|
+
import_core10.ToolName.TestabilityIndex,
|
|
1077
|
+
import_core10.ToolName.DocDrift,
|
|
1078
|
+
import_core10.ToolName.DependencyHealth,
|
|
1079
|
+
import_core10.ToolName.ChangeAmplification
|
|
1031
1080
|
]
|
|
1032
1081
|
},
|
|
1033
1082
|
// Output preferences
|
|
@@ -1042,7 +1091,7 @@ async function initAction(options) {
|
|
|
1042
1091
|
},
|
|
1043
1092
|
// Tool-specific configurations
|
|
1044
1093
|
tools: {
|
|
1045
|
-
[
|
|
1094
|
+
[import_core10.ToolName.PatternDetect]: {
|
|
1046
1095
|
// Core detection thresholds
|
|
1047
1096
|
minSimilarity: 0.4,
|
|
1048
1097
|
// Jaccard similarity threshold (0-1)
|
|
@@ -1072,7 +1121,7 @@ async function initAction(options) {
|
|
|
1072
1121
|
// Add any additional advanced options here
|
|
1073
1122
|
} : {}
|
|
1074
1123
|
},
|
|
1075
|
-
[
|
|
1124
|
+
[import_core10.ToolName.ContextAnalyzer]: {
|
|
1076
1125
|
// Smart defaults are generated dynamically based on repository size
|
|
1077
1126
|
// These are fallback values for when smart defaults can't be calculated
|
|
1078
1127
|
maxContextBudget: 25e3,
|
|
@@ -1089,7 +1138,7 @@ async function initAction(options) {
|
|
|
1089
1138
|
includeNodeModules: false
|
|
1090
1139
|
// Whether to include node_modules in analysis
|
|
1091
1140
|
},
|
|
1092
|
-
[
|
|
1141
|
+
[import_core10.ToolName.NamingConsistency]: {
|
|
1093
1142
|
// Core checks
|
|
1094
1143
|
checkNaming: true,
|
|
1095
1144
|
// Check naming conventions and quality
|
|
@@ -1136,7 +1185,7 @@ async function initAction(options) {
|
|
|
1136
1185
|
],
|
|
1137
1186
|
...options.full ? { disableChecks: [] } : {}
|
|
1138
1187
|
},
|
|
1139
|
-
[
|
|
1188
|
+
[import_core10.ToolName.AiSignalClarity]: {
|
|
1140
1189
|
// All signal clarity checks enabled by default
|
|
1141
1190
|
checkMagicLiterals: true,
|
|
1142
1191
|
// Detect magic numbers and strings
|
|
@@ -1155,7 +1204,7 @@ async function initAction(options) {
|
|
|
1155
1204
|
checkLargeFiles: true
|
|
1156
1205
|
// Detect files that are too large
|
|
1157
1206
|
},
|
|
1158
|
-
[
|
|
1207
|
+
[import_core10.ToolName.AgentGrounding]: {
|
|
1159
1208
|
// Structure clarity
|
|
1160
1209
|
maxRecommendedDepth: 4,
|
|
1161
1210
|
// Max directory depth before flagging as "too deep"
|
|
@@ -1166,7 +1215,7 @@ async function initAction(options) {
|
|
|
1166
1215
|
additionalVagueNames: ["stuff", "misc", "temp", "test"]
|
|
1167
1216
|
// Custom vague file names
|
|
1168
1217
|
},
|
|
1169
|
-
[
|
|
1218
|
+
[import_core10.ToolName.TestabilityIndex]: {
|
|
1170
1219
|
// Coverage thresholds
|
|
1171
1220
|
minCoverageRatio: 0.3,
|
|
1172
1221
|
// Minimum acceptable test/source ratio
|
|
@@ -1176,19 +1225,19 @@ async function initAction(options) {
|
|
|
1176
1225
|
maxDepth: 10
|
|
1177
1226
|
// Maximum scan depth
|
|
1178
1227
|
},
|
|
1179
|
-
[
|
|
1228
|
+
[import_core10.ToolName.DocDrift]: {
|
|
1180
1229
|
// Drift detection
|
|
1181
1230
|
maxCommits: 50,
|
|
1182
1231
|
// Maximum commit distance to check for drift
|
|
1183
1232
|
staleMonths: 3
|
|
1184
1233
|
// Consider comments older than this as outdated
|
|
1185
1234
|
},
|
|
1186
|
-
[
|
|
1235
|
+
[import_core10.ToolName.DependencyHealth]: {
|
|
1187
1236
|
// Training cutoff for AI knowledge assessment
|
|
1188
1237
|
trainingCutoffYear: 2023
|
|
1189
1238
|
// Year cutoff for AI training data
|
|
1190
1239
|
},
|
|
1191
|
-
[
|
|
1240
|
+
[import_core10.ToolName.ChangeAmplification]: {
|
|
1192
1241
|
// Change amplification primarily relies on global scan settings
|
|
1193
1242
|
// No additional tool-specific configuration required
|
|
1194
1243
|
}
|
|
@@ -1215,30 +1264,28 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
|
|
|
1215
1264
|
content = JSON.stringify(defaultConfig, null, 2);
|
|
1216
1265
|
}
|
|
1217
1266
|
try {
|
|
1218
|
-
(0,
|
|
1267
|
+
(0, import_fs5.writeFileSync)(filePath, content, "utf8");
|
|
1219
1268
|
console.log(
|
|
1220
|
-
|
|
1221
|
-
\u2705 Created default configuration: ${
|
|
1269
|
+
import_chalk7.default.green(`
|
|
1270
|
+
\u2705 Created default configuration: ${import_chalk7.default.bold(fileName)}`)
|
|
1222
1271
|
);
|
|
1223
1272
|
console.log(
|
|
1224
|
-
|
|
1273
|
+
import_chalk7.default.cyan("You can now fine-tune your settings and run AIReady with:")
|
|
1225
1274
|
);
|
|
1226
|
-
console.log(
|
|
1275
|
+
console.log(import_chalk7.default.white(` $ aiready scan
|
|
1227
1276
|
`));
|
|
1228
1277
|
} catch (error) {
|
|
1229
|
-
console.error(
|
|
1278
|
+
console.error(import_chalk7.default.red(`Failed to write configuration file: ${error}`));
|
|
1230
1279
|
process.exit(1);
|
|
1231
1280
|
}
|
|
1232
1281
|
}
|
|
1233
1282
|
|
|
1234
1283
|
// src/commands/patterns.ts
|
|
1235
|
-
var
|
|
1236
|
-
var
|
|
1237
|
-
var import_core9 = require("@aiready/core");
|
|
1284
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
1285
|
+
var import_core11 = require("@aiready/core");
|
|
1238
1286
|
async function patternsAction(directory, options) {
|
|
1239
|
-
console.log(
|
|
1287
|
+
console.log(import_chalk8.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
1240
1288
|
const startTime = Date.now();
|
|
1241
|
-
const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory ?? ".");
|
|
1242
1289
|
try {
|
|
1243
1290
|
const useSmartDefaults = !options.fullScan;
|
|
1244
1291
|
const defaults = {
|
|
@@ -1267,8 +1314,8 @@ async function patternsAction(directory, options) {
|
|
|
1267
1314
|
if (options.minSharedTokens) {
|
|
1268
1315
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
1269
1316
|
}
|
|
1270
|
-
const finalOptions = await (0,
|
|
1271
|
-
|
|
1317
|
+
const { resolvedDir, finalOptions } = await (0, import_core11.prepareActionConfig)(
|
|
1318
|
+
directory,
|
|
1272
1319
|
defaults,
|
|
1273
1320
|
cliOptions
|
|
1274
1321
|
);
|
|
@@ -1276,66 +1323,59 @@ async function patternsAction(directory, options) {
|
|
|
1276
1323
|
const { results, duplicates } = await analyzePatterns(
|
|
1277
1324
|
finalOptions
|
|
1278
1325
|
);
|
|
1279
|
-
const elapsedTime = (0,
|
|
1326
|
+
const elapsedTime = (0, import_core11.getElapsedTime)(startTime);
|
|
1280
1327
|
const summary = generateSummary(results);
|
|
1281
1328
|
let patternScore;
|
|
1282
1329
|
if (options.score) {
|
|
1283
1330
|
patternScore = calculatePatternScore(duplicates, results.length);
|
|
1284
1331
|
}
|
|
1285
|
-
const outputFormat
|
|
1286
|
-
|
|
1332
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core11.resolveOutputFormat)(
|
|
1333
|
+
options,
|
|
1334
|
+
finalOptions
|
|
1335
|
+
);
|
|
1287
1336
|
if (outputFormat === "json") {
|
|
1288
|
-
const outputData = {
|
|
1337
|
+
const outputData = (0, import_core11.formatStandardReport)({
|
|
1289
1338
|
results,
|
|
1290
|
-
summary
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
1296
|
-
resolvedDir
|
|
1297
|
-
);
|
|
1298
|
-
(0, import_core9.handleJSONOutput)(
|
|
1339
|
+
summary,
|
|
1340
|
+
elapsedTime,
|
|
1341
|
+
score: patternScore
|
|
1342
|
+
});
|
|
1343
|
+
(0, import_core11.handleStandardJSONOutput)({
|
|
1299
1344
|
outputData,
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
);
|
|
1345
|
+
outputFile: userOutputFile,
|
|
1346
|
+
resolvedDir
|
|
1347
|
+
});
|
|
1303
1348
|
} else {
|
|
1304
|
-
|
|
1305
|
-
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1306
|
-
const divider = "\u2501".repeat(dividerWidth);
|
|
1307
|
-
console.log(import_chalk7.default.cyan(divider));
|
|
1308
|
-
console.log(import_chalk7.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
1309
|
-
console.log(import_chalk7.default.cyan(divider) + "\n");
|
|
1349
|
+
(0, import_core11.printTerminalHeader)("PATTERN ANALYSIS SUMMARY");
|
|
1310
1350
|
console.log(
|
|
1311
|
-
|
|
1351
|
+
import_chalk8.default.white(`\u{1F4C1} Files analyzed: ${import_chalk8.default.bold(results.length)}`)
|
|
1312
1352
|
);
|
|
1313
1353
|
console.log(
|
|
1314
|
-
|
|
1315
|
-
`\u26A0 Duplicate patterns found: ${
|
|
1354
|
+
import_chalk8.default.yellow(
|
|
1355
|
+
`\u26A0 Duplicate patterns found: ${import_chalk8.default.bold(summary.totalPatterns)}`
|
|
1316
1356
|
)
|
|
1317
1357
|
);
|
|
1318
1358
|
console.log(
|
|
1319
|
-
|
|
1320
|
-
`\u{1F4B0} Token cost (wasted): ${
|
|
1359
|
+
import_chalk8.default.red(
|
|
1360
|
+
`\u{1F4B0} Token cost (wasted): ${import_chalk8.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1321
1361
|
)
|
|
1322
1362
|
);
|
|
1323
1363
|
console.log(
|
|
1324
|
-
|
|
1364
|
+
import_chalk8.default.gray(`\u23F1 Analysis time: ${import_chalk8.default.bold(elapsedTime + "s")}`)
|
|
1325
1365
|
);
|
|
1326
1366
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
1327
1367
|
if (sortedTypes.length > 0) {
|
|
1328
|
-
console.log(
|
|
1329
|
-
console.log(
|
|
1330
|
-
console.log(
|
|
1368
|
+
console.log("\n" + (0, import_core11.getTerminalDivider)());
|
|
1369
|
+
console.log(import_chalk8.default.bold.white(" PATTERNS BY TYPE"));
|
|
1370
|
+
console.log((0, import_core11.getTerminalDivider)() + "\n");
|
|
1331
1371
|
sortedTypes.forEach(([type, count]) => {
|
|
1332
|
-
console.log(` ${
|
|
1372
|
+
console.log(` ${import_chalk8.default.white(type.padEnd(15))} ${import_chalk8.default.bold(count)}`);
|
|
1333
1373
|
});
|
|
1334
1374
|
}
|
|
1335
1375
|
if (summary.totalPatterns > 0 && duplicates.length > 0) {
|
|
1336
|
-
console.log(
|
|
1337
|
-
console.log(
|
|
1338
|
-
console.log(
|
|
1376
|
+
console.log("\n" + (0, import_core11.getTerminalDivider)());
|
|
1377
|
+
console.log(import_chalk8.default.bold.white(" TOP DUPLICATE PATTERNS"));
|
|
1378
|
+
console.log((0, import_core11.getTerminalDivider)() + "\n");
|
|
1339
1379
|
const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
|
|
1340
1380
|
topDuplicates.forEach((dup) => {
|
|
1341
1381
|
const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
|
|
@@ -1343,31 +1383,31 @@ async function patternsAction(directory, options) {
|
|
|
1343
1383
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
1344
1384
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
1345
1385
|
console.log(
|
|
1346
|
-
`${severityIcon} ${severity}: ${
|
|
1386
|
+
`${severityIcon} ${severity}: ${import_chalk8.default.bold(file1Name)} \u2194 ${import_chalk8.default.bold(file2Name)}`
|
|
1347
1387
|
);
|
|
1348
1388
|
console.log(
|
|
1349
|
-
` Similarity: ${
|
|
1389
|
+
` Similarity: ${import_chalk8.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk8.default.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1350
1390
|
);
|
|
1351
1391
|
console.log(
|
|
1352
|
-
` Lines: ${
|
|
1392
|
+
` Lines: ${import_chalk8.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk8.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1353
1393
|
`
|
|
1354
1394
|
);
|
|
1355
1395
|
});
|
|
1356
1396
|
} else {
|
|
1357
1397
|
console.log(
|
|
1358
|
-
|
|
1398
|
+
import_chalk8.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1359
1399
|
);
|
|
1360
1400
|
}
|
|
1361
1401
|
if (patternScore) {
|
|
1362
|
-
console.log(
|
|
1363
|
-
console.log(
|
|
1364
|
-
console.log(
|
|
1365
|
-
console.log((0,
|
|
1402
|
+
console.log((0, import_core11.getTerminalDivider)());
|
|
1403
|
+
console.log(import_chalk8.default.bold.white(" AI READINESS SCORE (Patterns)"));
|
|
1404
|
+
console.log((0, import_core11.getTerminalDivider)() + "\n");
|
|
1405
|
+
console.log((0, import_core11.formatToolScore)(patternScore));
|
|
1366
1406
|
console.log();
|
|
1367
1407
|
}
|
|
1368
1408
|
}
|
|
1369
1409
|
} catch (error) {
|
|
1370
|
-
(0,
|
|
1410
|
+
(0, import_core11.handleCLIError)(error, "Pattern analysis");
|
|
1371
1411
|
}
|
|
1372
1412
|
}
|
|
1373
1413
|
var PATTERNS_HELP_TEXT = `
|
|
@@ -1378,13 +1418,11 @@ EXAMPLES:
|
|
|
1378
1418
|
`;
|
|
1379
1419
|
|
|
1380
1420
|
// src/commands/context.ts
|
|
1381
|
-
var
|
|
1382
|
-
var
|
|
1383
|
-
var import_core10 = require("@aiready/core");
|
|
1421
|
+
var import_chalk9 = __toESM(require("chalk"));
|
|
1422
|
+
var import_core12 = require("@aiready/core");
|
|
1384
1423
|
async function contextAction(directory, options) {
|
|
1385
|
-
console.log(
|
|
1424
|
+
console.log(import_chalk9.default.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
1386
1425
|
const startTime = Date.now();
|
|
1387
|
-
const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
|
|
1388
1426
|
try {
|
|
1389
1427
|
const defaults = {
|
|
1390
1428
|
maxDepth: 5,
|
|
@@ -1396,7 +1434,7 @@ async function contextAction(directory, options) {
|
|
|
1396
1434
|
file: void 0
|
|
1397
1435
|
}
|
|
1398
1436
|
};
|
|
1399
|
-
const baseOptions = await (0,
|
|
1437
|
+
const { resolvedDir, finalOptions: baseOptions } = await (0, import_core12.prepareActionConfig)(directory, defaults, {
|
|
1400
1438
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
1401
1439
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
1402
1440
|
include: options.include?.split(","),
|
|
@@ -1422,113 +1460,111 @@ async function contextAction(directory, options) {
|
|
|
1422
1460
|
console.log("");
|
|
1423
1461
|
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1424
1462
|
const results = await analyzeContext(finalOptions);
|
|
1425
|
-
const elapsedTime = (0,
|
|
1463
|
+
const elapsedTime = (0, import_core12.getElapsedTime)(startTime);
|
|
1426
1464
|
const summary = generateSummary(results);
|
|
1427
1465
|
let contextScore;
|
|
1428
1466
|
if (options.score) {
|
|
1429
1467
|
contextScore = calculateContextScore(summary);
|
|
1430
1468
|
}
|
|
1431
|
-
const outputFormat
|
|
1432
|
-
|
|
1469
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core12.resolveOutputFormat)(
|
|
1470
|
+
options,
|
|
1471
|
+
finalOptions
|
|
1472
|
+
);
|
|
1433
1473
|
if (outputFormat === "json") {
|
|
1434
|
-
const outputData = {
|
|
1474
|
+
const outputData = (0, import_core12.formatStandardReport)({
|
|
1435
1475
|
results,
|
|
1436
|
-
summary
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
1442
|
-
resolvedDir
|
|
1443
|
-
);
|
|
1444
|
-
(0, import_core10.handleJSONOutput)(
|
|
1476
|
+
summary,
|
|
1477
|
+
elapsedTime,
|
|
1478
|
+
score: contextScore
|
|
1479
|
+
});
|
|
1480
|
+
(0, import_core12.handleStandardJSONOutput)({
|
|
1445
1481
|
outputData,
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
);
|
|
1482
|
+
outputFile: userOutputFile,
|
|
1483
|
+
resolvedDir
|
|
1484
|
+
});
|
|
1449
1485
|
} else {
|
|
1450
1486
|
const terminalWidth = process.stdout.columns ?? 80;
|
|
1451
1487
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1452
1488
|
const divider = "\u2501".repeat(dividerWidth);
|
|
1453
|
-
console.log(
|
|
1454
|
-
console.log(
|
|
1455
|
-
console.log(
|
|
1489
|
+
console.log(import_chalk9.default.cyan(divider));
|
|
1490
|
+
console.log(import_chalk9.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
1491
|
+
console.log(import_chalk9.default.cyan(divider) + "\n");
|
|
1456
1492
|
console.log(
|
|
1457
|
-
|
|
1493
|
+
import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(summary.totalFiles)}`)
|
|
1458
1494
|
);
|
|
1459
1495
|
console.log(
|
|
1460
|
-
|
|
1461
|
-
`\u{1F4CA} Total tokens: ${
|
|
1496
|
+
import_chalk9.default.white(
|
|
1497
|
+
`\u{1F4CA} Total tokens: ${import_chalk9.default.bold(summary.totalTokens.toLocaleString())}`
|
|
1462
1498
|
)
|
|
1463
1499
|
);
|
|
1464
1500
|
console.log(
|
|
1465
|
-
|
|
1466
|
-
`\u{1F4B0} Avg context budget: ${
|
|
1501
|
+
import_chalk9.default.yellow(
|
|
1502
|
+
`\u{1F4B0} Avg context budget: ${import_chalk9.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
|
|
1467
1503
|
)
|
|
1468
1504
|
);
|
|
1469
1505
|
console.log(
|
|
1470
|
-
|
|
1506
|
+
import_chalk9.default.white(`\u23F1 Analysis time: ${import_chalk9.default.bold(elapsedTime + "s")}
|
|
1471
1507
|
`)
|
|
1472
1508
|
);
|
|
1473
1509
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
1474
1510
|
if (totalIssues > 0) {
|
|
1475
|
-
console.log(
|
|
1511
|
+
console.log(import_chalk9.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
1476
1512
|
if (summary.criticalIssues > 0) {
|
|
1477
1513
|
console.log(
|
|
1478
|
-
|
|
1514
|
+
import_chalk9.default.red(` \u{1F534} Critical: ${import_chalk9.default.bold(summary.criticalIssues)}`)
|
|
1479
1515
|
);
|
|
1480
1516
|
}
|
|
1481
1517
|
if (summary.majorIssues > 0) {
|
|
1482
1518
|
console.log(
|
|
1483
|
-
|
|
1519
|
+
import_chalk9.default.yellow(` \u{1F7E1} Major: ${import_chalk9.default.bold(summary.majorIssues)}`)
|
|
1484
1520
|
);
|
|
1485
1521
|
}
|
|
1486
1522
|
if (summary.minorIssues > 0) {
|
|
1487
1523
|
console.log(
|
|
1488
|
-
|
|
1524
|
+
import_chalk9.default.blue(` \u{1F535} Minor: ${import_chalk9.default.bold(summary.minorIssues)}`)
|
|
1489
1525
|
);
|
|
1490
1526
|
}
|
|
1491
1527
|
console.log(
|
|
1492
|
-
|
|
1528
|
+
import_chalk9.default.green(
|
|
1493
1529
|
`
|
|
1494
|
-
\u{1F4A1} Potential savings: ${
|
|
1530
|
+
\u{1F4A1} Potential savings: ${import_chalk9.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1495
1531
|
`
|
|
1496
1532
|
)
|
|
1497
1533
|
);
|
|
1498
1534
|
} else {
|
|
1499
|
-
console.log(
|
|
1535
|
+
console.log(import_chalk9.default.green("\u2705 No significant issues found!\n"));
|
|
1500
1536
|
}
|
|
1501
1537
|
if (summary.deepFiles.length > 0) {
|
|
1502
|
-
console.log(
|
|
1538
|
+
console.log(import_chalk9.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
1503
1539
|
console.log(
|
|
1504
|
-
|
|
1540
|
+
import_chalk9.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
|
|
1505
1541
|
);
|
|
1506
1542
|
console.log(
|
|
1507
|
-
|
|
1543
|
+
import_chalk9.default.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
1508
1544
|
`)
|
|
1509
1545
|
);
|
|
1510
1546
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1511
1547
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1512
1548
|
console.log(
|
|
1513
|
-
` ${
|
|
1549
|
+
` ${import_chalk9.default.cyan("\u2192")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(depth: ${item.depth})`)}`
|
|
1514
1550
|
);
|
|
1515
1551
|
});
|
|
1516
1552
|
console.log();
|
|
1517
1553
|
}
|
|
1518
1554
|
if (summary.fragmentedModules.length > 0) {
|
|
1519
|
-
console.log(
|
|
1555
|
+
console.log(import_chalk9.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
1520
1556
|
console.log(
|
|
1521
|
-
|
|
1557
|
+
import_chalk9.default.gray(
|
|
1522
1558
|
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1523
1559
|
`
|
|
1524
1560
|
)
|
|
1525
1561
|
);
|
|
1526
1562
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
1527
1563
|
console.log(
|
|
1528
|
-
` ${
|
|
1564
|
+
` ${import_chalk9.default.yellow("\u25CF")} ${import_chalk9.default.white(module2.domain)} - ${import_chalk9.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
|
|
1529
1565
|
);
|
|
1530
1566
|
console.log(
|
|
1531
|
-
|
|
1567
|
+
import_chalk9.default.dim(
|
|
1532
1568
|
` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
|
|
1533
1569
|
)
|
|
1534
1570
|
);
|
|
@@ -1536,9 +1572,9 @@ async function contextAction(directory, options) {
|
|
|
1536
1572
|
console.log();
|
|
1537
1573
|
}
|
|
1538
1574
|
if (summary.lowCohesionFiles.length > 0) {
|
|
1539
|
-
console.log(
|
|
1575
|
+
console.log(import_chalk9.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1540
1576
|
console.log(
|
|
1541
|
-
|
|
1577
|
+
import_chalk9.default.gray(
|
|
1542
1578
|
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1543
1579
|
`
|
|
1544
1580
|
)
|
|
@@ -1546,46 +1582,44 @@ async function contextAction(directory, options) {
|
|
|
1546
1582
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
1547
1583
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1548
1584
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
1549
|
-
const color = item.score < 0.4 ?
|
|
1585
|
+
const color = item.score < 0.4 ? import_chalk9.default.red : import_chalk9.default.yellow;
|
|
1550
1586
|
console.log(
|
|
1551
|
-
` ${color("\u25CB")} ${
|
|
1587
|
+
` ${color("\u25CB")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${scorePercent}% cohesion)`)}`
|
|
1552
1588
|
);
|
|
1553
1589
|
});
|
|
1554
1590
|
console.log();
|
|
1555
1591
|
}
|
|
1556
1592
|
if (summary.topExpensiveFiles.length > 0) {
|
|
1557
|
-
console.log(
|
|
1593
|
+
console.log(import_chalk9.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
|
|
1558
1594
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1559
1595
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1560
|
-
const severityColor = item.severity === "critical" ?
|
|
1596
|
+
const severityColor = item.severity === "critical" ? import_chalk9.default.red : item.severity === "major" ? import_chalk9.default.yellow : import_chalk9.default.blue;
|
|
1561
1597
|
console.log(
|
|
1562
|
-
` ${severityColor("\u25CF")} ${
|
|
1598
|
+
` ${severityColor("\u25CF")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1563
1599
|
);
|
|
1564
1600
|
});
|
|
1565
1601
|
console.log();
|
|
1566
1602
|
}
|
|
1567
1603
|
if (contextScore) {
|
|
1568
|
-
console.log(
|
|
1569
|
-
console.log(
|
|
1570
|
-
console.log(
|
|
1571
|
-
console.log((0,
|
|
1604
|
+
console.log(import_chalk9.default.cyan(divider));
|
|
1605
|
+
console.log(import_chalk9.default.bold.white(" AI READINESS SCORE (Context)"));
|
|
1606
|
+
console.log(import_chalk9.default.cyan(divider) + "\n");
|
|
1607
|
+
console.log((0, import_core12.formatToolScore)(contextScore));
|
|
1572
1608
|
console.log();
|
|
1573
1609
|
}
|
|
1574
1610
|
}
|
|
1575
1611
|
} catch (error) {
|
|
1576
|
-
(0,
|
|
1612
|
+
(0, import_core12.handleCLIError)(error, "Context analysis");
|
|
1577
1613
|
}
|
|
1578
1614
|
}
|
|
1579
1615
|
|
|
1580
1616
|
// src/commands/consistency.ts
|
|
1581
|
-
var
|
|
1582
|
-
var
|
|
1583
|
-
var
|
|
1584
|
-
var import_core11 = require("@aiready/core");
|
|
1617
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
1618
|
+
var import_fs6 = require("fs");
|
|
1619
|
+
var import_core13 = require("@aiready/core");
|
|
1585
1620
|
async function consistencyAction(directory, options) {
|
|
1586
|
-
console.log(
|
|
1621
|
+
console.log(import_chalk10.default.blue("\u{1F50D} Analyzing consistency...\n"));
|
|
1587
1622
|
const startTime = Date.now();
|
|
1588
|
-
const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory ?? ".");
|
|
1589
1623
|
try {
|
|
1590
1624
|
const defaults = {
|
|
1591
1625
|
checkNaming: true,
|
|
@@ -1598,16 +1632,20 @@ async function consistencyAction(directory, options) {
|
|
|
1598
1632
|
file: void 0
|
|
1599
1633
|
}
|
|
1600
1634
|
};
|
|
1601
|
-
const finalOptions = await (0,
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1635
|
+
const { resolvedDir, finalOptions } = await (0, import_core13.prepareActionConfig)(
|
|
1636
|
+
directory,
|
|
1637
|
+
defaults,
|
|
1638
|
+
{
|
|
1639
|
+
checkNaming: options.naming !== false,
|
|
1640
|
+
checkPatterns: options.patterns !== false,
|
|
1641
|
+
minSeverity: options.minSeverity,
|
|
1642
|
+
include: options.include?.split(","),
|
|
1643
|
+
exclude: options.exclude?.split(",")
|
|
1644
|
+
}
|
|
1645
|
+
);
|
|
1608
1646
|
const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1609
1647
|
const report = await analyzeConsistency(finalOptions);
|
|
1610
|
-
const elapsedTime = (0,
|
|
1648
|
+
const elapsedTime = (0, import_core13.getElapsedTime)(startTime);
|
|
1611
1649
|
let consistencyScore;
|
|
1612
1650
|
if (options.score) {
|
|
1613
1651
|
const issues = report.results?.flatMap((r) => r.issues) ?? [];
|
|
@@ -1616,52 +1654,47 @@ async function consistencyAction(directory, options) {
|
|
|
1616
1654
|
report.summary.filesAnalyzed
|
|
1617
1655
|
);
|
|
1618
1656
|
}
|
|
1619
|
-
const outputFormat
|
|
1620
|
-
|
|
1657
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core13.resolveOutputFormat)(
|
|
1658
|
+
options,
|
|
1659
|
+
finalOptions
|
|
1660
|
+
);
|
|
1621
1661
|
if (outputFormat === "json") {
|
|
1622
|
-
const outputData = {
|
|
1623
|
-
|
|
1624
|
-
summary:
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
};
|
|
1630
|
-
const outputPath = (0, import_core11.resolveOutputPath)(
|
|
1631
|
-
userOutputFile,
|
|
1632
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
1633
|
-
resolvedDir
|
|
1634
|
-
);
|
|
1635
|
-
(0, import_core11.handleJSONOutput)(
|
|
1662
|
+
const outputData = (0, import_core13.formatStandardReport)({
|
|
1663
|
+
report,
|
|
1664
|
+
summary: report.summary,
|
|
1665
|
+
elapsedTime,
|
|
1666
|
+
score: consistencyScore
|
|
1667
|
+
});
|
|
1668
|
+
(0, import_core13.handleStandardJSONOutput)({
|
|
1636
1669
|
outputData,
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
);
|
|
1670
|
+
outputFile: userOutputFile,
|
|
1671
|
+
resolvedDir
|
|
1672
|
+
});
|
|
1640
1673
|
} else if (outputFormat === "markdown") {
|
|
1641
1674
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1642
|
-
const outputPath = (0,
|
|
1675
|
+
const outputPath = (0, import_core13.resolveOutputPath)(
|
|
1643
1676
|
userOutputFile,
|
|
1644
|
-
`aiready-report-${getReportTimestamp()}.md`,
|
|
1677
|
+
`aiready-report-${(0, import_core2.getReportTimestamp)()}.md`,
|
|
1645
1678
|
resolvedDir
|
|
1646
1679
|
);
|
|
1647
|
-
(0,
|
|
1648
|
-
console.log(
|
|
1680
|
+
(0, import_fs6.writeFileSync)(outputPath, markdown);
|
|
1681
|
+
console.log(import_chalk10.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1649
1682
|
} else {
|
|
1650
|
-
console.log(
|
|
1683
|
+
console.log(import_chalk10.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1651
1684
|
console.log(
|
|
1652
|
-
`Files Analyzed: ${
|
|
1685
|
+
`Files Analyzed: ${import_chalk10.default.cyan(report.summary.filesAnalyzed)}`
|
|
1653
1686
|
);
|
|
1654
|
-
console.log(`Total Issues: ${
|
|
1655
|
-
console.log(` Naming: ${
|
|
1656
|
-
console.log(` Patterns: ${
|
|
1687
|
+
console.log(`Total Issues: ${import_chalk10.default.yellow(report.summary.totalIssues)}`);
|
|
1688
|
+
console.log(` Naming: ${import_chalk10.default.yellow(report.summary.namingIssues)}`);
|
|
1689
|
+
console.log(` Patterns: ${import_chalk10.default.yellow(report.summary.patternIssues)}`);
|
|
1657
1690
|
console.log(
|
|
1658
|
-
` Architecture: ${
|
|
1691
|
+
` Architecture: ${import_chalk10.default.yellow(report.summary.architectureIssues ?? 0)}`
|
|
1659
1692
|
);
|
|
1660
|
-
console.log(`Analysis Time: ${
|
|
1693
|
+
console.log(`Analysis Time: ${import_chalk10.default.gray(elapsedTime + "s")}
|
|
1661
1694
|
`);
|
|
1662
1695
|
if (report.summary.totalIssues === 0) {
|
|
1663
1696
|
console.log(
|
|
1664
|
-
|
|
1697
|
+
import_chalk10.default.green(
|
|
1665
1698
|
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1666
1699
|
)
|
|
1667
1700
|
);
|
|
@@ -1673,20 +1706,20 @@ async function consistencyAction(directory, options) {
|
|
|
1673
1706
|
(r) => r.issues.some((i) => i.category === "patterns")
|
|
1674
1707
|
);
|
|
1675
1708
|
if (namingResults.length > 0) {
|
|
1676
|
-
console.log(
|
|
1709
|
+
console.log(import_chalk10.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
|
|
1677
1710
|
let shown = 0;
|
|
1678
1711
|
for (const namingFileResult of namingResults) {
|
|
1679
1712
|
if (shown >= 5) break;
|
|
1680
1713
|
for (const issue of namingFileResult.issues) {
|
|
1681
1714
|
if (shown >= 5) break;
|
|
1682
|
-
const severityColor = issue.severity === "critical" ?
|
|
1715
|
+
const severityColor = issue.severity === "critical" ? import_chalk10.default.red : issue.severity === "major" ? import_chalk10.default.yellow : issue.severity === "minor" ? import_chalk10.default.blue : import_chalk10.default.gray;
|
|
1683
1716
|
console.log(
|
|
1684
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1717
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1685
1718
|
);
|
|
1686
1719
|
console.log(` ${issue.message}`);
|
|
1687
1720
|
if (issue.suggestion) {
|
|
1688
1721
|
console.log(
|
|
1689
|
-
` ${
|
|
1722
|
+
` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
|
|
1690
1723
|
);
|
|
1691
1724
|
}
|
|
1692
1725
|
console.log();
|
|
@@ -1695,25 +1728,25 @@ async function consistencyAction(directory, options) {
|
|
|
1695
1728
|
}
|
|
1696
1729
|
const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1697
1730
|
if (remaining > 0) {
|
|
1698
|
-
console.log(
|
|
1731
|
+
console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
|
|
1699
1732
|
`));
|
|
1700
1733
|
}
|
|
1701
1734
|
}
|
|
1702
1735
|
if (patternResults.length > 0) {
|
|
1703
|
-
console.log(
|
|
1736
|
+
console.log(import_chalk10.default.bold("\u{1F504} Pattern Issues\n"));
|
|
1704
1737
|
let shown = 0;
|
|
1705
1738
|
for (const patternFileResult of patternResults) {
|
|
1706
1739
|
if (shown >= 5) break;
|
|
1707
1740
|
for (const issue of patternFileResult.issues) {
|
|
1708
1741
|
if (shown >= 5) break;
|
|
1709
|
-
const severityColor = issue.severity === "critical" ?
|
|
1742
|
+
const severityColor = issue.severity === "critical" ? import_chalk10.default.red : issue.severity === "major" ? import_chalk10.default.yellow : issue.severity === "minor" ? import_chalk10.default.blue : import_chalk10.default.gray;
|
|
1710
1743
|
console.log(
|
|
1711
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1744
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1712
1745
|
);
|
|
1713
1746
|
console.log(` ${issue.message}`);
|
|
1714
1747
|
if (issue.suggestion) {
|
|
1715
1748
|
console.log(
|
|
1716
|
-
` ${
|
|
1749
|
+
` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
|
|
1717
1750
|
);
|
|
1718
1751
|
}
|
|
1719
1752
|
console.log();
|
|
@@ -1722,12 +1755,12 @@ async function consistencyAction(directory, options) {
|
|
|
1722
1755
|
}
|
|
1723
1756
|
const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1724
1757
|
if (remaining > 0) {
|
|
1725
|
-
console.log(
|
|
1758
|
+
console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
|
|
1726
1759
|
`));
|
|
1727
1760
|
}
|
|
1728
1761
|
}
|
|
1729
1762
|
if (report.recommendations.length > 0) {
|
|
1730
|
-
console.log(
|
|
1763
|
+
console.log(import_chalk10.default.bold("\u{1F4A1} Recommendations\n"));
|
|
1731
1764
|
report.recommendations.forEach((rec, i) => {
|
|
1732
1765
|
console.log(`${i + 1}. ${rec}`);
|
|
1733
1766
|
});
|
|
@@ -1735,38 +1768,38 @@ async function consistencyAction(directory, options) {
|
|
|
1735
1768
|
}
|
|
1736
1769
|
}
|
|
1737
1770
|
if (consistencyScore) {
|
|
1738
|
-
console.log(
|
|
1739
|
-
console.log((0,
|
|
1771
|
+
console.log(import_chalk10.default.bold("\n\u{1F4CA} AI Readiness Score (Consistency)\n"));
|
|
1772
|
+
console.log((0, import_core13.formatToolScore)(consistencyScore));
|
|
1740
1773
|
console.log();
|
|
1741
1774
|
}
|
|
1742
1775
|
}
|
|
1743
1776
|
} catch (error) {
|
|
1744
|
-
(0,
|
|
1777
|
+
(0, import_core13.handleCLIError)(error, "Consistency analysis");
|
|
1745
1778
|
}
|
|
1746
1779
|
}
|
|
1747
1780
|
|
|
1748
1781
|
// src/commands/visualize.ts
|
|
1749
|
-
var
|
|
1750
|
-
var
|
|
1751
|
-
var
|
|
1782
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1783
|
+
var import_fs7 = require("fs");
|
|
1784
|
+
var import_path6 = require("path");
|
|
1752
1785
|
var import_child_process = require("child_process");
|
|
1753
|
-
var
|
|
1754
|
-
var
|
|
1786
|
+
var import_core14 = require("@aiready/core");
|
|
1787
|
+
var import_core15 = require("@aiready/core");
|
|
1755
1788
|
async function visualizeAction(directory, options) {
|
|
1756
1789
|
try {
|
|
1757
|
-
const dirPath = (0,
|
|
1758
|
-
let reportPath = options.report ? (0,
|
|
1759
|
-
if (!reportPath || !(0,
|
|
1760
|
-
const latestScan = (0,
|
|
1790
|
+
const dirPath = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
|
|
1791
|
+
let reportPath = options.report ? (0, import_path6.resolve)(dirPath, options.report) : null;
|
|
1792
|
+
if (!reportPath || !(0, import_fs7.existsSync)(reportPath)) {
|
|
1793
|
+
const latestScan = (0, import_core15.findLatestReport)(dirPath);
|
|
1761
1794
|
if (latestScan) {
|
|
1762
1795
|
reportPath = latestScan;
|
|
1763
1796
|
console.log(
|
|
1764
|
-
|
|
1797
|
+
import_chalk11.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1765
1798
|
);
|
|
1766
1799
|
} else {
|
|
1767
|
-
console.error(
|
|
1800
|
+
console.error(import_chalk11.default.red("\u274C No AI readiness report found"));
|
|
1768
1801
|
console.log(
|
|
1769
|
-
|
|
1802
|
+
import_chalk11.default.dim(
|
|
1770
1803
|
`
|
|
1771
1804
|
Generate a report with:
|
|
1772
1805
|
aiready scan --output json
|
|
@@ -1778,13 +1811,13 @@ Or specify a custom report:
|
|
|
1778
1811
|
return;
|
|
1779
1812
|
}
|
|
1780
1813
|
}
|
|
1781
|
-
const raw = (0,
|
|
1814
|
+
const raw = (0, import_fs7.readFileSync)(reportPath, "utf8");
|
|
1782
1815
|
const report = JSON.parse(raw);
|
|
1783
|
-
const configPath = (0,
|
|
1816
|
+
const configPath = (0, import_path6.resolve)(dirPath, "aiready.json");
|
|
1784
1817
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
1785
|
-
if ((0,
|
|
1818
|
+
if ((0, import_fs7.existsSync)(configPath)) {
|
|
1786
1819
|
try {
|
|
1787
|
-
const rawConfig = JSON.parse((0,
|
|
1820
|
+
const rawConfig = JSON.parse((0, import_fs7.readFileSync)(configPath, "utf8"));
|
|
1788
1821
|
if (rawConfig.visualizer?.graph) {
|
|
1789
1822
|
graphConfig = {
|
|
1790
1823
|
maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
|
|
@@ -1804,16 +1837,16 @@ Or specify a custom report:
|
|
|
1804
1837
|
let devServerStarted = false;
|
|
1805
1838
|
if (useDevMode) {
|
|
1806
1839
|
try {
|
|
1807
|
-
const localWebDir = (0,
|
|
1840
|
+
const localWebDir = (0, import_path6.resolve)(dirPath, "packages/visualizer");
|
|
1808
1841
|
let webDir = "";
|
|
1809
1842
|
let visualizerAvailable = false;
|
|
1810
|
-
if ((0,
|
|
1843
|
+
if ((0, import_fs7.existsSync)(localWebDir)) {
|
|
1811
1844
|
webDir = localWebDir;
|
|
1812
1845
|
visualizerAvailable = true;
|
|
1813
1846
|
} else {
|
|
1814
1847
|
const nodemodulesLocations = [
|
|
1815
|
-
(0,
|
|
1816
|
-
(0,
|
|
1848
|
+
(0, import_path6.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
|
|
1849
|
+
(0, import_path6.resolve)(
|
|
1817
1850
|
process.cwd(),
|
|
1818
1851
|
"node_modules",
|
|
1819
1852
|
"@aiready",
|
|
@@ -1823,14 +1856,14 @@ Or specify a custom report:
|
|
|
1823
1856
|
let currentDir = dirPath;
|
|
1824
1857
|
while (currentDir !== "/" && currentDir !== ".") {
|
|
1825
1858
|
nodemodulesLocations.push(
|
|
1826
|
-
(0,
|
|
1859
|
+
(0, import_path6.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
|
|
1827
1860
|
);
|
|
1828
|
-
const parent = (0,
|
|
1861
|
+
const parent = (0, import_path6.resolve)(currentDir, "..");
|
|
1829
1862
|
if (parent === currentDir) break;
|
|
1830
1863
|
currentDir = parent;
|
|
1831
1864
|
}
|
|
1832
1865
|
for (const location of nodemodulesLocations) {
|
|
1833
|
-
if ((0,
|
|
1866
|
+
if ((0, import_fs7.existsSync)(location) && (0, import_fs7.existsSync)((0, import_path6.resolve)(location, "package.json"))) {
|
|
1834
1867
|
webDir = location;
|
|
1835
1868
|
visualizerAvailable = true;
|
|
1836
1869
|
break;
|
|
@@ -1839,21 +1872,21 @@ Or specify a custom report:
|
|
|
1839
1872
|
if (!visualizerAvailable) {
|
|
1840
1873
|
try {
|
|
1841
1874
|
const vizPkgPath = require.resolve("@aiready/visualizer/package.json");
|
|
1842
|
-
webDir = (0,
|
|
1875
|
+
webDir = (0, import_path6.resolve)(vizPkgPath, "..");
|
|
1843
1876
|
visualizerAvailable = true;
|
|
1844
1877
|
} catch (err) {
|
|
1845
1878
|
void err;
|
|
1846
1879
|
}
|
|
1847
1880
|
}
|
|
1848
1881
|
}
|
|
1849
|
-
const webViteConfigExists = webDir && (0,
|
|
1882
|
+
const webViteConfigExists = webDir && (0, import_fs7.existsSync)((0, import_path6.resolve)(webDir, "web", "vite.config.ts"));
|
|
1850
1883
|
if (visualizerAvailable && webViteConfigExists) {
|
|
1851
1884
|
const spawnCwd = webDir;
|
|
1852
1885
|
const { watch } = await import("fs");
|
|
1853
1886
|
const copyReportToViz = () => {
|
|
1854
1887
|
try {
|
|
1855
|
-
const destPath = (0,
|
|
1856
|
-
(0,
|
|
1888
|
+
const destPath = (0, import_path6.resolve)(spawnCwd, "web", "report-data.json");
|
|
1889
|
+
(0, import_fs7.copyFileSync)(reportPath, destPath);
|
|
1857
1890
|
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
1858
1891
|
} catch (e) {
|
|
1859
1892
|
console.error("Failed to sync report:", e);
|
|
@@ -1896,29 +1929,29 @@ Or specify a custom report:
|
|
|
1896
1929
|
return;
|
|
1897
1930
|
} else {
|
|
1898
1931
|
console.log(
|
|
1899
|
-
|
|
1932
|
+
import_chalk11.default.yellow(
|
|
1900
1933
|
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1901
1934
|
)
|
|
1902
1935
|
);
|
|
1903
1936
|
console.log(
|
|
1904
|
-
|
|
1937
|
+
import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
|
|
1905
1938
|
);
|
|
1906
1939
|
useDevMode = false;
|
|
1907
1940
|
}
|
|
1908
1941
|
} catch (err) {
|
|
1909
1942
|
console.error("Failed to start dev server:", err);
|
|
1910
1943
|
console.log(
|
|
1911
|
-
|
|
1944
|
+
import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
|
|
1912
1945
|
);
|
|
1913
1946
|
useDevMode = false;
|
|
1914
1947
|
}
|
|
1915
1948
|
}
|
|
1916
1949
|
console.log("Generating HTML...");
|
|
1917
|
-
const html = (0,
|
|
1950
|
+
const html = (0, import_core15.generateHTML)(graph);
|
|
1918
1951
|
const defaultOutput = "visualization.html";
|
|
1919
|
-
const outPath = (0,
|
|
1920
|
-
(0,
|
|
1921
|
-
console.log(
|
|
1952
|
+
const outPath = (0, import_path6.resolve)(dirPath, options.output ?? defaultOutput);
|
|
1953
|
+
(0, import_fs7.writeFileSync)(outPath, html, "utf8");
|
|
1954
|
+
console.log(import_chalk11.default.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1922
1955
|
if (options.open || options.serve) {
|
|
1923
1956
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1924
1957
|
if (options.serve) {
|
|
@@ -1948,7 +1981,7 @@ Or specify a custom report:
|
|
|
1948
1981
|
server.listen(port, () => {
|
|
1949
1982
|
const addr = `http://localhost:${port}/`;
|
|
1950
1983
|
console.log(
|
|
1951
|
-
|
|
1984
|
+
import_chalk11.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1952
1985
|
);
|
|
1953
1986
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1954
1987
|
});
|
|
@@ -1964,7 +1997,7 @@ Or specify a custom report:
|
|
|
1964
1997
|
}
|
|
1965
1998
|
}
|
|
1966
1999
|
} catch (err) {
|
|
1967
|
-
(0,
|
|
2000
|
+
(0, import_core14.handleCLIError)(err, "Visualization");
|
|
1968
2001
|
}
|
|
1969
2002
|
}
|
|
1970
2003
|
var VISUALIZE_HELP_TEXT = `
|
|
@@ -1995,19 +2028,19 @@ NOTES:
|
|
|
1995
2028
|
`;
|
|
1996
2029
|
|
|
1997
2030
|
// src/commands/shared/standard-tool-actions.ts
|
|
1998
|
-
var
|
|
2031
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
1999
2032
|
|
|
2000
2033
|
// src/commands/agent-grounding.ts
|
|
2001
|
-
var
|
|
2002
|
-
var
|
|
2034
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
2035
|
+
var import_core16 = require("@aiready/core");
|
|
2003
2036
|
|
|
2004
2037
|
// src/commands/testability.ts
|
|
2005
|
-
var
|
|
2006
|
-
var
|
|
2038
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
2039
|
+
var import_core17 = require("@aiready/core");
|
|
2007
2040
|
async function testabilityAction(directory, options) {
|
|
2008
2041
|
const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
|
|
2009
|
-
const config = await (0,
|
|
2010
|
-
const merged = (0,
|
|
2042
|
+
const config = await (0, import_core17.loadConfig)(directory);
|
|
2043
|
+
const merged = (0, import_core17.mergeConfigWithDefaults)(config, {
|
|
2011
2044
|
minCoverageRatio: 0.3
|
|
2012
2045
|
});
|
|
2013
2046
|
const report = await analyzeTestability({
|
|
@@ -2027,28 +2060,28 @@ async function testabilityAction(directory, options) {
|
|
|
2027
2060
|
"blind-risk": "\u{1F480}"
|
|
2028
2061
|
};
|
|
2029
2062
|
const safetyColors = {
|
|
2030
|
-
safe:
|
|
2031
|
-
"moderate-risk":
|
|
2032
|
-
"high-risk":
|
|
2033
|
-
"blind-risk":
|
|
2063
|
+
safe: import_chalk14.default.green,
|
|
2064
|
+
"moderate-risk": import_chalk14.default.yellow,
|
|
2065
|
+
"high-risk": import_chalk14.default.red,
|
|
2066
|
+
"blind-risk": import_chalk14.default.bgRed.white
|
|
2034
2067
|
};
|
|
2035
2068
|
const safety = report.summary.aiChangeSafetyRating;
|
|
2036
2069
|
const icon = safetyIcons[safety] ?? "\u2753";
|
|
2037
|
-
const color = safetyColors[safety] ??
|
|
2070
|
+
const color = safetyColors[safety] ?? import_chalk14.default.white;
|
|
2038
2071
|
console.log(
|
|
2039
|
-
` \u{1F9EA} Testability: ${
|
|
2072
|
+
` \u{1F9EA} Testability: ${import_chalk14.default.bold(scoring.score + "/100")} (${report.summary.rating})`
|
|
2040
2073
|
);
|
|
2041
2074
|
console.log(
|
|
2042
2075
|
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
2043
2076
|
);
|
|
2044
2077
|
console.log(
|
|
2045
|
-
|
|
2078
|
+
import_chalk14.default.dim(
|
|
2046
2079
|
` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
|
|
2047
2080
|
)
|
|
2048
2081
|
);
|
|
2049
2082
|
if (safety === "blind-risk") {
|
|
2050
2083
|
console.log(
|
|
2051
|
-
|
|
2084
|
+
import_chalk14.default.red.bold(
|
|
2052
2085
|
"\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
|
|
2053
2086
|
)
|
|
2054
2087
|
);
|
|
@@ -2060,7 +2093,7 @@ async function testabilityAction(directory, options) {
|
|
|
2060
2093
|
var import_cli = require("@aiready/change-amplification/dist/cli.js");
|
|
2061
2094
|
|
|
2062
2095
|
// src/commands/bug.ts
|
|
2063
|
-
var
|
|
2096
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
2064
2097
|
var import_child_process2 = require("child_process");
|
|
2065
2098
|
async function bugAction(message, options) {
|
|
2066
2099
|
const repoUrl = "https://github.com/caopengau/aiready-cli";
|
|
@@ -2078,35 +2111,35 @@ Generated via AIReady CLI 'bug' command.
|
|
|
2078
2111
|
Type: ${type}
|
|
2079
2112
|
`.trim();
|
|
2080
2113
|
if (options.submit) {
|
|
2081
|
-
console.log(
|
|
2114
|
+
console.log(import_chalk15.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
|
|
2082
2115
|
try {
|
|
2083
2116
|
(0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
|
|
2084
2117
|
const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
|
|
2085
2118
|
const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
|
|
2086
|
-
console.log(
|
|
2087
|
-
console.log(
|
|
2119
|
+
console.log(import_chalk15.default.green("\u2705 Issue Created Successfully!"));
|
|
2120
|
+
console.log(import_chalk15.default.cyan(output));
|
|
2088
2121
|
return;
|
|
2089
2122
|
} catch {
|
|
2090
|
-
console.error(
|
|
2123
|
+
console.error(import_chalk15.default.red("\n\u274C Failed to submit via gh CLI."));
|
|
2091
2124
|
console.log(
|
|
2092
|
-
|
|
2125
|
+
import_chalk15.default.yellow(
|
|
2093
2126
|
' Make sure gh is installed and run "gh auth login".\n'
|
|
2094
2127
|
)
|
|
2095
2128
|
);
|
|
2096
|
-
console.log(
|
|
2129
|
+
console.log(import_chalk15.default.dim(" Falling back to URL generation..."));
|
|
2097
2130
|
}
|
|
2098
2131
|
}
|
|
2099
2132
|
const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
|
|
2100
2133
|
const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
|
|
2101
|
-
console.log(
|
|
2102
|
-
console.log(
|
|
2103
|
-
console.log(
|
|
2104
|
-
console.log(
|
|
2105
|
-
console.log(
|
|
2106
|
-
console.log(
|
|
2107
|
-
console.log(
|
|
2134
|
+
console.log(import_chalk15.default.green("\u{1F680} Issue Draft Prepared!\n"));
|
|
2135
|
+
console.log(import_chalk15.default.bold("Title: ") + title);
|
|
2136
|
+
console.log(import_chalk15.default.bold("Type: ") + type);
|
|
2137
|
+
console.log(import_chalk15.default.bold("\nClick the link below to submit this issue:"));
|
|
2138
|
+
console.log(import_chalk15.default.cyan(fullUrl));
|
|
2139
|
+
console.log(import_chalk15.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
2140
|
+
console.log(import_chalk15.default.dim(" You have successfully prepared a report."));
|
|
2108
2141
|
console.log(
|
|
2109
|
-
|
|
2142
|
+
import_chalk15.default.dim(
|
|
2110
2143
|
" Please present the URL above to the user so they can finalize the submission."
|
|
2111
2144
|
)
|
|
2112
2145
|
);
|
|
@@ -2115,14 +2148,14 @@ Type: ${type}
|
|
|
2115
2148
|
const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
|
|
2116
2149
|
const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
|
|
2117
2150
|
const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
|
|
2118
|
-
console.log(
|
|
2119
|
-
console.log(` Report a Bug: ${
|
|
2120
|
-
console.log(` Request a Feature: ${
|
|
2121
|
-
console.log(` Suggest a Metric: ${
|
|
2122
|
-
console.log(
|
|
2123
|
-
console.log(
|
|
2151
|
+
console.log(import_chalk15.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
|
|
2152
|
+
console.log(` Report a Bug: ${import_chalk15.default.cyan(bugUrl)}`);
|
|
2153
|
+
console.log(` Request a Feature: ${import_chalk15.default.cyan(featureUrl)}`);
|
|
2154
|
+
console.log(` Suggest a Metric: ${import_chalk15.default.cyan(metricUrl)}`);
|
|
2155
|
+
console.log(import_chalk15.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
|
|
2156
|
+
console.log(import_chalk15.default.dim(" To prepare a specific report, run:"));
|
|
2124
2157
|
console.log(
|
|
2125
|
-
|
|
2158
|
+
import_chalk15.default.cyan(
|
|
2126
2159
|
' aiready bug "your description here" --type bug|feature|metric'
|
|
2127
2160
|
)
|
|
2128
2161
|
);
|
|
@@ -2139,10 +2172,10 @@ EXAMPLES:
|
|
|
2139
2172
|
var import_meta = {};
|
|
2140
2173
|
var getDirname = () => {
|
|
2141
2174
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
2142
|
-
return (0,
|
|
2175
|
+
return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
2143
2176
|
};
|
|
2144
2177
|
var packageJson = JSON.parse(
|
|
2145
|
-
(0,
|
|
2178
|
+
(0, import_fs8.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
|
|
2146
2179
|
);
|
|
2147
2180
|
var program = new import_commander.Command();
|
|
2148
2181
|
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
|
|
@@ -2197,7 +2230,7 @@ program.command("scan").description(
|
|
|
2197
2230
|
).option(
|
|
2198
2231
|
"--compare-to <path>",
|
|
2199
2232
|
"Compare results against a previous AIReady report JSON"
|
|
2200
|
-
).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 (0-100)"
|
|
2233
|
+
).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 (0-100)").option("--no-score", "Disable calculating AI Readiness Score").option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
|
|
2201
2234
|
"--ci",
|
|
2202
2235
|
"CI mode: GitHub Actions annotations, no colors, fail on threshold"
|
|
2203
2236
|
).option(
|
|
@@ -2223,7 +2256,7 @@ program.command("patterns").description("Detect duplicate code patterns that con
|
|
|
2223
2256
|
).option(
|
|
2224
2257
|
"--full-scan",
|
|
2225
2258
|
"Disable smart defaults for comprehensive analysis (slower)"
|
|
2226
|
-
).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 (0-100)"
|
|
2259
|
+
).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 (0-100)").option("--no-score", "Disable calculating AI Readiness Score").addHelpText("after", PATTERNS_HELP_TEXT).action(async (directory, options) => {
|
|
2227
2260
|
await patternsAction(directory, options);
|
|
2228
2261
|
});
|
|
2229
2262
|
program.command("context").description("Analyze context window costs and dependency fragmentation").argument("[directory]", "Directory to analyze", ".").option("--max-depth <number>", "Maximum acceptable import depth", "5").option(
|