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