@aiready/cli 0.14.21 → 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 +931 -896
- package/dist/cli.mjs +600 -551
- 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);
|
|
@@ -604,305 +343,595 @@ async function uploadAction(file, options) {
|
|
|
604
343
|
// Might be null, server will handle mapping
|
|
605
344
|
})
|
|
606
345
|
});
|
|
607
|
-
const contentType = response.headers.get("content-type");
|
|
608
|
-
let uploadResult = {};
|
|
609
|
-
if (contentType?.includes("application/json")) {
|
|
610
|
-
uploadResult = await response.json();
|
|
611
|
-
} else {
|
|
612
|
-
const text = await response.text();
|
|
613
|
-
uploadResult = { error: text ?? response.statusText };
|
|
346
|
+
const contentType = response.headers.get("content-type");
|
|
347
|
+
let uploadResult = {};
|
|
348
|
+
if (contentType?.includes("application/json")) {
|
|
349
|
+
uploadResult = await response.json();
|
|
350
|
+
} else {
|
|
351
|
+
const text = await response.text();
|
|
352
|
+
uploadResult = { error: text ?? response.statusText };
|
|
353
|
+
}
|
|
354
|
+
if (!response.ok) {
|
|
355
|
+
console.error(
|
|
356
|
+
import_chalk3.default.red(
|
|
357
|
+
`\u274C Upload failed: ${uploadResult.error ?? response.statusText}`
|
|
358
|
+
)
|
|
359
|
+
);
|
|
360
|
+
if (contentType?.includes("text/html")) {
|
|
361
|
+
console.log(
|
|
362
|
+
import_chalk3.default.yellow(
|
|
363
|
+
" Note: Received an HTML response. This often indicates a redirect (e.g., to a login page) or a server error."
|
|
364
|
+
)
|
|
365
|
+
);
|
|
366
|
+
if (uploadResult.error?.includes("Redirecting")) {
|
|
367
|
+
console.log(
|
|
368
|
+
import_chalk3.default.dim(
|
|
369
|
+
" Detected redirect. Check if the API endpoint requires authentication or has changed."
|
|
370
|
+
)
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (response.status === 401) {
|
|
375
|
+
console.log(
|
|
376
|
+
import_chalk3.default.dim(" Hint: Your API key may be invalid or expired.")
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
382
|
+
console.log(import_chalk3.default.green(`
|
|
383
|
+
\u2705 Upload successful! (${duration}s)`));
|
|
384
|
+
console.log(import_chalk3.default.cyan(` View results: ${serverUrl}/dashboard`));
|
|
385
|
+
if (uploadResult.analysis) {
|
|
386
|
+
console.log(import_chalk3.default.dim(` Analysis ID: ${uploadResult.analysis.id}`));
|
|
387
|
+
console.log(import_chalk3.default.dim(` Score: ${uploadResult.analysis.aiScore}/100`));
|
|
388
|
+
}
|
|
389
|
+
} catch (error) {
|
|
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
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return (0, import_core7.calculateOverallScore)(toolScores, options, void 0);
|
|
783
|
+
}
|
|
784
|
+
|
|
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);
|
|
614
814
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
815
|
+
await handleBusinessImpactMetrics(
|
|
816
|
+
results,
|
|
817
|
+
scoringResult,
|
|
818
|
+
options.model ?? "gpt-5.4-mini"
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
return { results, scoringResult };
|
|
822
|
+
}
|
|
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)
|
|
622
833
|
console.log(
|
|
623
|
-
|
|
624
|
-
|
|
834
|
+
import_chalk5.default.green(
|
|
835
|
+
` \u{1F4C8} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
|
|
625
836
|
)
|
|
626
837
|
);
|
|
627
|
-
|
|
628
|
-
console.log(
|
|
629
|
-
import_chalk3.default.dim(
|
|
630
|
-
" Detected redirect. Check if the API endpoint requires authentication or has changed."
|
|
631
|
-
)
|
|
632
|
-
);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
if (response.status === 401) {
|
|
838
|
+
else if (diff < 0)
|
|
636
839
|
console.log(
|
|
637
|
-
|
|
840
|
+
import_chalk5.default.red(
|
|
841
|
+
` \u{1F4C9} Trend: ${diffStr} compared to ${baselinePath} (${prevScore} \u2192 ${currentScoring.overall})`
|
|
842
|
+
)
|
|
843
|
+
);
|
|
844
|
+
else
|
|
845
|
+
console.log(
|
|
846
|
+
import_chalk5.default.blue(
|
|
847
|
+
` \u2796 Trend: No change (${prevScore} \u2192 ${currentScoring.overall})`
|
|
848
|
+
)
|
|
638
849
|
);
|
|
639
|
-
}
|
|
640
|
-
process.exit(1);
|
|
641
850
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
+
}
|
|
649
889
|
}
|
|
650
|
-
|
|
651
|
-
|
|
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;
|
|
652
904
|
}
|
|
653
905
|
}
|
|
654
|
-
var uploadHelpText = `
|
|
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
906
|
|
|
665
907
|
// src/commands/scan.ts
|
|
666
908
|
async function scanAction(directory, options) {
|
|
667
|
-
console.log(
|
|
909
|
+
console.log(import_chalk6.default.blue("\u{1F680} Starting AIReady unified analysis...\n"));
|
|
668
910
|
const startTime = Date.now();
|
|
669
|
-
const resolvedDir = (0,
|
|
670
|
-
const repoMetadata = (0,
|
|
911
|
+
const resolvedDir = (0, import_path4.resolve)(process.cwd(), directory ?? ".");
|
|
912
|
+
const repoMetadata = (0, import_core9.getRepoMetadata)(resolvedDir);
|
|
671
913
|
try {
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
"pattern-detect",
|
|
675
|
-
"context-analyzer",
|
|
676
|
-
"naming-consistency",
|
|
677
|
-
"ai-signal-clarity",
|
|
678
|
-
"agent-grounding",
|
|
679
|
-
"testability-index",
|
|
680
|
-
"doc-drift",
|
|
681
|
-
"dependency-health",
|
|
682
|
-
"change-amplification"
|
|
683
|
-
],
|
|
684
|
-
include: void 0,
|
|
685
|
-
exclude: void 0,
|
|
686
|
-
output: {
|
|
687
|
-
format: "console",
|
|
688
|
-
file: void 0
|
|
689
|
-
}
|
|
690
|
-
};
|
|
691
|
-
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
692
|
-
if (options.profile) {
|
|
693
|
-
switch (options.profile.toLowerCase()) {
|
|
694
|
-
case "agentic":
|
|
695
|
-
profileTools = [
|
|
696
|
-
import_core6.ToolName.AiSignalClarity,
|
|
697
|
-
import_core6.ToolName.AgentGrounding,
|
|
698
|
-
import_core6.ToolName.TestabilityIndex
|
|
699
|
-
];
|
|
700
|
-
break;
|
|
701
|
-
case "cost":
|
|
702
|
-
profileTools = [import_core6.ToolName.PatternDetect, import_core6.ToolName.ContextAnalyzer];
|
|
703
|
-
break;
|
|
704
|
-
case "logic":
|
|
705
|
-
profileTools = [
|
|
706
|
-
import_core6.ToolName.TestabilityIndex,
|
|
707
|
-
import_core6.ToolName.NamingConsistency,
|
|
708
|
-
import_core6.ToolName.ContextAnalyzer,
|
|
709
|
-
import_core6.ToolName.PatternDetect,
|
|
710
|
-
import_core6.ToolName.ChangeAmplification
|
|
711
|
-
];
|
|
712
|
-
break;
|
|
713
|
-
case "ui":
|
|
714
|
-
profileTools = [
|
|
715
|
-
import_core6.ToolName.NamingConsistency,
|
|
716
|
-
import_core6.ToolName.ContextAnalyzer,
|
|
717
|
-
import_core6.ToolName.PatternDetect,
|
|
718
|
-
import_core6.ToolName.DocDrift,
|
|
719
|
-
import_core6.ToolName.AiSignalClarity
|
|
720
|
-
];
|
|
721
|
-
break;
|
|
722
|
-
case "security":
|
|
723
|
-
profileTools = [
|
|
724
|
-
import_core6.ToolName.NamingConsistency,
|
|
725
|
-
import_core6.ToolName.TestabilityIndex
|
|
726
|
-
];
|
|
727
|
-
break;
|
|
728
|
-
case "onboarding":
|
|
729
|
-
profileTools = [
|
|
730
|
-
import_core6.ToolName.ContextAnalyzer,
|
|
731
|
-
import_core6.ToolName.NamingConsistency,
|
|
732
|
-
import_core6.ToolName.AgentGrounding
|
|
733
|
-
];
|
|
734
|
-
break;
|
|
735
|
-
default:
|
|
736
|
-
console.log(
|
|
737
|
-
import_chalk4.default.yellow(
|
|
738
|
-
`
|
|
739
|
-
\u26A0\uFE0F Unknown profile '${options.profile}'. Using defaults.`
|
|
740
|
-
)
|
|
741
|
-
);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
const cliOverrides = {
|
|
745
|
-
include: options.include?.split(","),
|
|
746
|
-
exclude: options.exclude?.split(",")
|
|
747
|
-
};
|
|
748
|
-
if (profileTools) cliOverrides.tools = profileTools;
|
|
749
|
-
const baseOptions = await (0, import_core6.loadMergedConfig)(
|
|
914
|
+
const finalOptions = await resolveScanConfig(resolvedDir, options);
|
|
915
|
+
const { results, scoringResult } = await runUnifiedScan(
|
|
750
916
|
resolvedDir,
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
const finalOptions = { ...baseOptions };
|
|
755
|
-
if (baseOptions.tools.includes(import_core6.ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
|
|
756
|
-
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
757
|
-
const patternSmartDefaults = await getSmartDefaults(
|
|
758
|
-
resolvedDir,
|
|
759
|
-
finalOptions.toolConfigs?.[import_core6.ToolName.PatternDetect] ?? {}
|
|
760
|
-
);
|
|
761
|
-
if (!finalOptions.toolConfigs) finalOptions.toolConfigs = {};
|
|
762
|
-
finalOptions.toolConfigs[import_core6.ToolName.PatternDetect] = {
|
|
763
|
-
...patternSmartDefaults,
|
|
764
|
-
...finalOptions.toolConfigs[import_core6.ToolName.PatternDetect]
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
console.log(import_chalk4.default.cyan("\n=== AIReady Run Preview ==="));
|
|
768
|
-
console.log(
|
|
769
|
-
import_chalk4.default.white("Tools to run:"),
|
|
770
|
-
(finalOptions.tools ?? []).join(", ")
|
|
917
|
+
finalOptions,
|
|
918
|
+
options,
|
|
919
|
+
startTime
|
|
771
920
|
);
|
|
772
|
-
const progressCallback = (event) => {
|
|
773
|
-
if (event.message) {
|
|
774
|
-
process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
process.stdout.write("\r\x1B[K");
|
|
778
|
-
console.log(import_chalk4.default.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
779
|
-
const res = event.data;
|
|
780
|
-
if (res && res.summary) {
|
|
781
|
-
if (res.summary.totalIssues !== void 0)
|
|
782
|
-
console.log(` Issues found: ${import_chalk4.default.bold(res.summary.totalIssues)}`);
|
|
783
|
-
if (res.summary.score !== void 0)
|
|
784
|
-
console.log(` Tool Score: ${import_chalk4.default.bold(res.summary.score)}/100`);
|
|
785
|
-
if (res.summary.totalFiles !== void 0)
|
|
786
|
-
console.log(
|
|
787
|
-
` Files analyzed: ${import_chalk4.default.bold(res.summary.totalFiles)}`
|
|
788
|
-
);
|
|
789
|
-
}
|
|
790
|
-
};
|
|
791
|
-
const scoringProfile = options.profile ?? baseOptions.scoring?.profile ?? "default";
|
|
792
|
-
const results = await analyzeUnified({
|
|
793
|
-
...finalOptions,
|
|
794
|
-
progressCallback,
|
|
795
|
-
onProgress: () => {
|
|
796
|
-
},
|
|
797
|
-
suppressToolConfig: true
|
|
798
|
-
});
|
|
799
|
-
printScanSummary(results, startTime);
|
|
800
|
-
let scoringResult;
|
|
801
|
-
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
802
|
-
scoringResult = await scoreUnified(results, {
|
|
803
|
-
...finalOptions,
|
|
804
|
-
scoring: {
|
|
805
|
-
...finalOptions.scoring,
|
|
806
|
-
profile: scoringProfile
|
|
807
|
-
}
|
|
808
|
-
});
|
|
809
|
-
printScoring(scoringResult, scoringProfile);
|
|
810
|
-
if (options.compareTo) {
|
|
811
|
-
try {
|
|
812
|
-
const prevReport = JSON.parse(
|
|
813
|
-
(0, import_fs3.readFileSync)((0, import_path3.resolve)(process.cwd(), options.compareTo), "utf8")
|
|
814
|
-
);
|
|
815
|
-
const prevScore = prevReport.scoring?.overall ?? prevReport.scoring?.score;
|
|
816
|
-
if (typeof prevScore === "number") {
|
|
817
|
-
const diff = scoringResult.overall - prevScore;
|
|
818
|
-
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
819
|
-
if (diff > 0)
|
|
820
|
-
console.log(
|
|
821
|
-
import_chalk4.default.green(
|
|
822
|
-
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
823
|
-
)
|
|
824
|
-
);
|
|
825
|
-
else if (diff < 0)
|
|
826
|
-
console.log(
|
|
827
|
-
import_chalk4.default.red(
|
|
828
|
-
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
829
|
-
)
|
|
830
|
-
);
|
|
831
|
-
else
|
|
832
|
-
console.log(
|
|
833
|
-
import_chalk4.default.blue(
|
|
834
|
-
` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
|
|
835
|
-
)
|
|
836
|
-
);
|
|
837
|
-
}
|
|
838
|
-
} catch (e) {
|
|
839
|
-
void e;
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
const totalWastedDuplication = (scoringResult.breakdown ?? []).reduce(
|
|
843
|
-
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.duplication ?? 0),
|
|
844
|
-
0
|
|
845
|
-
);
|
|
846
|
-
const totalWastedFragmentation = (scoringResult.breakdown ?? []).reduce(
|
|
847
|
-
(sum, s) => sum + (s.tokenBudget?.wastedTokens?.bySource?.fragmentation ?? 0),
|
|
848
|
-
0
|
|
849
|
-
);
|
|
850
|
-
const totalContext = Math.max(
|
|
851
|
-
...(scoringResult.breakdown ?? []).map(
|
|
852
|
-
(s) => s.tokenBudget?.totalContextTokens ?? 0
|
|
853
|
-
),
|
|
854
|
-
0
|
|
855
|
-
);
|
|
856
|
-
if (totalContext > 0) {
|
|
857
|
-
const unifiedBudget = (0, import_core6.calculateTokenBudget)({
|
|
858
|
-
totalContextTokens: totalContext,
|
|
859
|
-
wastedTokens: {
|
|
860
|
-
duplication: totalWastedDuplication,
|
|
861
|
-
fragmentation: totalWastedFragmentation,
|
|
862
|
-
chattiness: totalContext * 0.1
|
|
863
|
-
// Default chattiness
|
|
864
|
-
}
|
|
865
|
-
});
|
|
866
|
-
const allIssues = [];
|
|
867
|
-
for (const toolId of results.summary.toolsRun) {
|
|
868
|
-
if (results[toolId]?.results) {
|
|
869
|
-
results[toolId].results.forEach((fileRes) => {
|
|
870
|
-
if (fileRes.issues) {
|
|
871
|
-
allIssues.push(...fileRes.issues);
|
|
872
|
-
}
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
const modelId = options.model ?? "gpt-5.4-mini";
|
|
877
|
-
const roi = (await import("@aiready/core")).calculateBusinessROI({
|
|
878
|
-
tokenWaste: unifiedBudget.wastedTokens.total,
|
|
879
|
-
issues: allIssues,
|
|
880
|
-
modelId
|
|
881
|
-
});
|
|
882
|
-
printBusinessImpact(roi, unifiedBudget);
|
|
883
|
-
results.summary.businessImpact = {
|
|
884
|
-
estimatedMonthlyWaste: roi.monthlySavings,
|
|
885
|
-
potentialSavings: roi.monthlySavings,
|
|
886
|
-
productivityHours: roi.productivityGainHours
|
|
887
|
-
};
|
|
888
|
-
scoringResult.tokenBudget = unifiedBudget;
|
|
889
|
-
scoringResult.businessROI = roi;
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
921
|
console.log(
|
|
893
|
-
|
|
922
|
+
import_chalk6.default.dim(
|
|
894
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"
|
|
895
924
|
)
|
|
896
925
|
);
|
|
897
|
-
console.log(
|
|
898
|
-
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:"));
|
|
899
928
|
console.log(
|
|
900
|
-
|
|
929
|
+
import_chalk6.default.cyan(
|
|
901
930
|
` "Any feedback for the tools? Please use 'aiready bug' to report \u2764\uFE0F"`
|
|
902
931
|
)
|
|
903
932
|
);
|
|
904
933
|
console.log(
|
|
905
|
-
|
|
934
|
+
import_chalk6.default.dim(
|
|
906
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"
|
|
907
936
|
)
|
|
908
937
|
);
|
|
@@ -911,21 +940,21 @@ async function scanAction(directory, options) {
|
|
|
911
940
|
repository: repoMetadata
|
|
912
941
|
};
|
|
913
942
|
const outputFormat = options.output ?? finalOptions.output?.format ?? "console";
|
|
914
|
-
const outputPath = (0,
|
|
943
|
+
const outputPath = (0, import_core9.resolveOutputPath)(
|
|
915
944
|
options.outputFile ?? finalOptions.output?.file,
|
|
916
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
945
|
+
`aiready-report-${(0, import_core2.getReportTimestamp)()}.json`,
|
|
917
946
|
resolvedDir
|
|
918
947
|
);
|
|
919
948
|
if (outputFormat === "json") {
|
|
920
|
-
(0,
|
|
949
|
+
(0, import_core9.handleJSONOutput)(
|
|
921
950
|
outputData,
|
|
922
951
|
outputPath,
|
|
923
952
|
`\u2705 Report saved to ${outputPath}`
|
|
924
953
|
);
|
|
925
954
|
} else {
|
|
926
955
|
try {
|
|
927
|
-
(0,
|
|
928
|
-
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}`));
|
|
929
958
|
} catch (err) {
|
|
930
959
|
void err;
|
|
931
960
|
}
|
|
@@ -937,61 +966,83 @@ async function scanAction(directory, options) {
|
|
|
937
966
|
});
|
|
938
967
|
}
|
|
939
968
|
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
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
|
+
`
|
|
951
986
|
\u{1F4DD} Emitting GitHub Action annotations for ${report.results.length} issues...`
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
if (shouldFail) {
|
|
970
|
-
console.log(import_chalk4.default.red(`
|
|
971
|
-
\u{1F6AB} SCAN FAILED: ${failReason}`));
|
|
972
|
-
process.exit(1);
|
|
973
|
-
} else {
|
|
974
|
-
console.log(import_chalk4.default.green("\n\u2705 SCAN PASSED"));
|
|
975
|
-
}
|
|
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`;
|
|
976
1002
|
}
|
|
977
|
-
}
|
|
978
|
-
|
|
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"));
|
|
979
1010
|
}
|
|
980
1011
|
}
|
|
981
|
-
var
|
|
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
|
+
`;
|
|
982
1033
|
|
|
983
1034
|
// src/commands/init.ts
|
|
984
|
-
var
|
|
985
|
-
var
|
|
986
|
-
var
|
|
987
|
-
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");
|
|
988
1039
|
async function initAction(options) {
|
|
989
1040
|
const fileExt = options.format === "js" ? "js" : "json";
|
|
990
1041
|
const fileName = fileExt === "js" ? "aiready.config.js" : "aiready.json";
|
|
991
|
-
const filePath = (0,
|
|
992
|
-
if ((0,
|
|
1042
|
+
const filePath = (0, import_path5.join)(process.cwd(), fileName);
|
|
1043
|
+
if ((0, import_fs5.existsSync)(filePath) && !options.force) {
|
|
993
1044
|
console.error(
|
|
994
|
-
|
|
1045
|
+
import_chalk7.default.red(`Error: ${fileName} already exists. Use --force to overwrite.`)
|
|
995
1046
|
);
|
|
996
1047
|
process.exit(1);
|
|
997
1048
|
}
|
|
@@ -1015,15 +1066,15 @@ async function initAction(options) {
|
|
|
1015
1066
|
"**/*.spec.ts"
|
|
1016
1067
|
],
|
|
1017
1068
|
tools: [
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
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
|
|
1027
1078
|
]
|
|
1028
1079
|
},
|
|
1029
1080
|
// Output preferences
|
|
@@ -1038,7 +1089,7 @@ async function initAction(options) {
|
|
|
1038
1089
|
},
|
|
1039
1090
|
// Tool-specific configurations
|
|
1040
1091
|
tools: {
|
|
1041
|
-
[
|
|
1092
|
+
[import_core10.ToolName.PatternDetect]: {
|
|
1042
1093
|
// Core detection thresholds
|
|
1043
1094
|
minSimilarity: 0.4,
|
|
1044
1095
|
// Jaccard similarity threshold (0-1)
|
|
@@ -1068,7 +1119,7 @@ async function initAction(options) {
|
|
|
1068
1119
|
// Add any additional advanced options here
|
|
1069
1120
|
} : {}
|
|
1070
1121
|
},
|
|
1071
|
-
[
|
|
1122
|
+
[import_core10.ToolName.ContextAnalyzer]: {
|
|
1072
1123
|
// Smart defaults are generated dynamically based on repository size
|
|
1073
1124
|
// These are fallback values for when smart defaults can't be calculated
|
|
1074
1125
|
maxContextBudget: 25e3,
|
|
@@ -1085,7 +1136,7 @@ async function initAction(options) {
|
|
|
1085
1136
|
includeNodeModules: false
|
|
1086
1137
|
// Whether to include node_modules in analysis
|
|
1087
1138
|
},
|
|
1088
|
-
[
|
|
1139
|
+
[import_core10.ToolName.NamingConsistency]: {
|
|
1089
1140
|
// Core checks
|
|
1090
1141
|
checkNaming: true,
|
|
1091
1142
|
// Check naming conventions and quality
|
|
@@ -1132,7 +1183,7 @@ async function initAction(options) {
|
|
|
1132
1183
|
],
|
|
1133
1184
|
...options.full ? { disableChecks: [] } : {}
|
|
1134
1185
|
},
|
|
1135
|
-
[
|
|
1186
|
+
[import_core10.ToolName.AiSignalClarity]: {
|
|
1136
1187
|
// All signal clarity checks enabled by default
|
|
1137
1188
|
checkMagicLiterals: true,
|
|
1138
1189
|
// Detect magic numbers and strings
|
|
@@ -1151,7 +1202,7 @@ async function initAction(options) {
|
|
|
1151
1202
|
checkLargeFiles: true
|
|
1152
1203
|
// Detect files that are too large
|
|
1153
1204
|
},
|
|
1154
|
-
[
|
|
1205
|
+
[import_core10.ToolName.AgentGrounding]: {
|
|
1155
1206
|
// Structure clarity
|
|
1156
1207
|
maxRecommendedDepth: 4,
|
|
1157
1208
|
// Max directory depth before flagging as "too deep"
|
|
@@ -1162,7 +1213,7 @@ async function initAction(options) {
|
|
|
1162
1213
|
additionalVagueNames: ["stuff", "misc", "temp", "test"]
|
|
1163
1214
|
// Custom vague file names
|
|
1164
1215
|
},
|
|
1165
|
-
[
|
|
1216
|
+
[import_core10.ToolName.TestabilityIndex]: {
|
|
1166
1217
|
// Coverage thresholds
|
|
1167
1218
|
minCoverageRatio: 0.3,
|
|
1168
1219
|
// Minimum acceptable test/source ratio
|
|
@@ -1172,19 +1223,19 @@ async function initAction(options) {
|
|
|
1172
1223
|
maxDepth: 10
|
|
1173
1224
|
// Maximum scan depth
|
|
1174
1225
|
},
|
|
1175
|
-
[
|
|
1226
|
+
[import_core10.ToolName.DocDrift]: {
|
|
1176
1227
|
// Drift detection
|
|
1177
1228
|
maxCommits: 50,
|
|
1178
1229
|
// Maximum commit distance to check for drift
|
|
1179
1230
|
staleMonths: 3
|
|
1180
1231
|
// Consider comments older than this as outdated
|
|
1181
1232
|
},
|
|
1182
|
-
[
|
|
1233
|
+
[import_core10.ToolName.DependencyHealth]: {
|
|
1183
1234
|
// Training cutoff for AI knowledge assessment
|
|
1184
1235
|
trainingCutoffYear: 2023
|
|
1185
1236
|
// Year cutoff for AI training data
|
|
1186
1237
|
},
|
|
1187
|
-
[
|
|
1238
|
+
[import_core10.ToolName.ChangeAmplification]: {
|
|
1188
1239
|
// Change amplification primarily relies on global scan settings
|
|
1189
1240
|
// No additional tool-specific configuration required
|
|
1190
1241
|
}
|
|
@@ -1211,30 +1262,28 @@ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
|
|
|
1211
1262
|
content = JSON.stringify(defaultConfig, null, 2);
|
|
1212
1263
|
}
|
|
1213
1264
|
try {
|
|
1214
|
-
(0,
|
|
1265
|
+
(0, import_fs5.writeFileSync)(filePath, content, "utf8");
|
|
1215
1266
|
console.log(
|
|
1216
|
-
|
|
1217
|
-
\u2705 Created default configuration: ${
|
|
1267
|
+
import_chalk7.default.green(`
|
|
1268
|
+
\u2705 Created default configuration: ${import_chalk7.default.bold(fileName)}`)
|
|
1218
1269
|
);
|
|
1219
1270
|
console.log(
|
|
1220
|
-
|
|
1271
|
+
import_chalk7.default.cyan("You can now fine-tune your settings and run AIReady with:")
|
|
1221
1272
|
);
|
|
1222
|
-
console.log(
|
|
1273
|
+
console.log(import_chalk7.default.white(` $ aiready scan
|
|
1223
1274
|
`));
|
|
1224
1275
|
} catch (error) {
|
|
1225
|
-
console.error(
|
|
1276
|
+
console.error(import_chalk7.default.red(`Failed to write configuration file: ${error}`));
|
|
1226
1277
|
process.exit(1);
|
|
1227
1278
|
}
|
|
1228
1279
|
}
|
|
1229
1280
|
|
|
1230
1281
|
// src/commands/patterns.ts
|
|
1231
|
-
var
|
|
1232
|
-
var
|
|
1233
|
-
var import_core8 = require("@aiready/core");
|
|
1282
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
1283
|
+
var import_core11 = require("@aiready/core");
|
|
1234
1284
|
async function patternsAction(directory, options) {
|
|
1235
|
-
console.log(
|
|
1285
|
+
console.log(import_chalk8.default.blue("\u{1F50D} Analyzing patterns...\n"));
|
|
1236
1286
|
const startTime = Date.now();
|
|
1237
|
-
const resolvedDir = (0, import_path5.resolve)(process.cwd(), directory ?? ".");
|
|
1238
1287
|
try {
|
|
1239
1288
|
const useSmartDefaults = !options.fullScan;
|
|
1240
1289
|
const defaults = {
|
|
@@ -1263,8 +1312,8 @@ async function patternsAction(directory, options) {
|
|
|
1263
1312
|
if (options.minSharedTokens) {
|
|
1264
1313
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
1265
1314
|
}
|
|
1266
|
-
const finalOptions = await (0,
|
|
1267
|
-
|
|
1315
|
+
const { resolvedDir, finalOptions } = await (0, import_core11.prepareActionConfig)(
|
|
1316
|
+
directory,
|
|
1268
1317
|
defaults,
|
|
1269
1318
|
cliOptions
|
|
1270
1319
|
);
|
|
@@ -1272,66 +1321,59 @@ async function patternsAction(directory, options) {
|
|
|
1272
1321
|
const { results, duplicates } = await analyzePatterns(
|
|
1273
1322
|
finalOptions
|
|
1274
1323
|
);
|
|
1275
|
-
const elapsedTime = (0,
|
|
1324
|
+
const elapsedTime = (0, import_core11.getElapsedTime)(startTime);
|
|
1276
1325
|
const summary = generateSummary(results);
|
|
1277
1326
|
let patternScore;
|
|
1278
1327
|
if (options.score) {
|
|
1279
1328
|
patternScore = calculatePatternScore(duplicates, results.length);
|
|
1280
1329
|
}
|
|
1281
|
-
const outputFormat
|
|
1282
|
-
|
|
1330
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core11.resolveOutputFormat)(
|
|
1331
|
+
options,
|
|
1332
|
+
finalOptions
|
|
1333
|
+
);
|
|
1283
1334
|
if (outputFormat === "json") {
|
|
1284
|
-
const outputData = {
|
|
1335
|
+
const outputData = (0, import_core11.formatStandardReport)({
|
|
1285
1336
|
results,
|
|
1286
|
-
summary
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
1292
|
-
resolvedDir
|
|
1293
|
-
);
|
|
1294
|
-
(0, import_core8.handleJSONOutput)(
|
|
1337
|
+
summary,
|
|
1338
|
+
elapsedTime,
|
|
1339
|
+
score: patternScore
|
|
1340
|
+
});
|
|
1341
|
+
(0, import_core11.handleStandardJSONOutput)({
|
|
1295
1342
|
outputData,
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
);
|
|
1343
|
+
outputFile: userOutputFile,
|
|
1344
|
+
resolvedDir
|
|
1345
|
+
});
|
|
1299
1346
|
} else {
|
|
1300
|
-
|
|
1301
|
-
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1302
|
-
const divider = "\u2501".repeat(dividerWidth);
|
|
1303
|
-
console.log(import_chalk6.default.cyan(divider));
|
|
1304
|
-
console.log(import_chalk6.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
1305
|
-
console.log(import_chalk6.default.cyan(divider) + "\n");
|
|
1347
|
+
(0, import_core11.printTerminalHeader)("PATTERN ANALYSIS SUMMARY");
|
|
1306
1348
|
console.log(
|
|
1307
|
-
|
|
1349
|
+
import_chalk8.default.white(`\u{1F4C1} Files analyzed: ${import_chalk8.default.bold(results.length)}`)
|
|
1308
1350
|
);
|
|
1309
1351
|
console.log(
|
|
1310
|
-
|
|
1311
|
-
`\u26A0 Duplicate patterns found: ${
|
|
1352
|
+
import_chalk8.default.yellow(
|
|
1353
|
+
`\u26A0 Duplicate patterns found: ${import_chalk8.default.bold(summary.totalPatterns)}`
|
|
1312
1354
|
)
|
|
1313
1355
|
);
|
|
1314
1356
|
console.log(
|
|
1315
|
-
|
|
1316
|
-
`\u{1F4B0} Token cost (wasted): ${
|
|
1357
|
+
import_chalk8.default.red(
|
|
1358
|
+
`\u{1F4B0} Token cost (wasted): ${import_chalk8.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1317
1359
|
)
|
|
1318
1360
|
);
|
|
1319
1361
|
console.log(
|
|
1320
|
-
|
|
1362
|
+
import_chalk8.default.gray(`\u23F1 Analysis time: ${import_chalk8.default.bold(elapsedTime + "s")}`)
|
|
1321
1363
|
);
|
|
1322
1364
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
1323
1365
|
if (sortedTypes.length > 0) {
|
|
1324
|
-
console.log(
|
|
1325
|
-
console.log(
|
|
1326
|
-
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");
|
|
1327
1369
|
sortedTypes.forEach(([type, count]) => {
|
|
1328
|
-
console.log(` ${
|
|
1370
|
+
console.log(` ${import_chalk8.default.white(type.padEnd(15))} ${import_chalk8.default.bold(count)}`);
|
|
1329
1371
|
});
|
|
1330
1372
|
}
|
|
1331
1373
|
if (summary.totalPatterns > 0 && duplicates.length > 0) {
|
|
1332
|
-
console.log(
|
|
1333
|
-
console.log(
|
|
1334
|
-
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");
|
|
1335
1377
|
const topDuplicates = [...duplicates].sort((a, b) => b.similarity - a.similarity).slice(0, 10);
|
|
1336
1378
|
topDuplicates.forEach((dup) => {
|
|
1337
1379
|
const severity = dup.similarity > 0.95 ? "CRITICAL" : dup.similarity > 0.9 ? "HIGH" : "MEDIUM";
|
|
@@ -1339,34 +1381,34 @@ async function patternsAction(directory, options) {
|
|
|
1339
1381
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
1340
1382
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
1341
1383
|
console.log(
|
|
1342
|
-
`${severityIcon} ${severity}: ${
|
|
1384
|
+
`${severityIcon} ${severity}: ${import_chalk8.default.bold(file1Name)} \u2194 ${import_chalk8.default.bold(file2Name)}`
|
|
1343
1385
|
);
|
|
1344
1386
|
console.log(
|
|
1345
|
-
` Similarity: ${
|
|
1387
|
+
` Similarity: ${import_chalk8.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk8.default.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1346
1388
|
);
|
|
1347
1389
|
console.log(
|
|
1348
|
-
` Lines: ${
|
|
1390
|
+
` Lines: ${import_chalk8.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk8.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1349
1391
|
`
|
|
1350
1392
|
);
|
|
1351
1393
|
});
|
|
1352
1394
|
} else {
|
|
1353
1395
|
console.log(
|
|
1354
|
-
|
|
1396
|
+
import_chalk8.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1355
1397
|
);
|
|
1356
1398
|
}
|
|
1357
1399
|
if (patternScore) {
|
|
1358
|
-
console.log(
|
|
1359
|
-
console.log(
|
|
1360
|
-
console.log(
|
|
1361
|
-
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));
|
|
1362
1404
|
console.log();
|
|
1363
1405
|
}
|
|
1364
1406
|
}
|
|
1365
1407
|
} catch (error) {
|
|
1366
|
-
(0,
|
|
1408
|
+
(0, import_core11.handleCLIError)(error, "Pattern analysis");
|
|
1367
1409
|
}
|
|
1368
1410
|
}
|
|
1369
|
-
var
|
|
1411
|
+
var PATTERNS_HELP_TEXT = `
|
|
1370
1412
|
EXAMPLES:
|
|
1371
1413
|
$ aiready patterns # Default analysis
|
|
1372
1414
|
$ aiready patterns --similarity 0.6 # Stricter matching
|
|
@@ -1374,13 +1416,11 @@ EXAMPLES:
|
|
|
1374
1416
|
`;
|
|
1375
1417
|
|
|
1376
1418
|
// src/commands/context.ts
|
|
1377
|
-
var
|
|
1378
|
-
var
|
|
1379
|
-
var import_core9 = require("@aiready/core");
|
|
1419
|
+
var import_chalk9 = __toESM(require("chalk"));
|
|
1420
|
+
var import_core12 = require("@aiready/core");
|
|
1380
1421
|
async function contextAction(directory, options) {
|
|
1381
|
-
console.log(
|
|
1422
|
+
console.log(import_chalk9.default.blue("\u{1F9E0} Analyzing context costs...\n"));
|
|
1382
1423
|
const startTime = Date.now();
|
|
1383
|
-
const resolvedDir = (0, import_path6.resolve)(process.cwd(), directory ?? ".");
|
|
1384
1424
|
try {
|
|
1385
1425
|
const defaults = {
|
|
1386
1426
|
maxDepth: 5,
|
|
@@ -1392,7 +1432,7 @@ async function contextAction(directory, options) {
|
|
|
1392
1432
|
file: void 0
|
|
1393
1433
|
}
|
|
1394
1434
|
};
|
|
1395
|
-
const baseOptions = await (0,
|
|
1435
|
+
const { resolvedDir, finalOptions: baseOptions } = await (0, import_core12.prepareActionConfig)(directory, defaults, {
|
|
1396
1436
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
1397
1437
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
1398
1438
|
include: options.include?.split(","),
|
|
@@ -1418,113 +1458,111 @@ async function contextAction(directory, options) {
|
|
|
1418
1458
|
console.log("");
|
|
1419
1459
|
const { analyzeContext, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
1420
1460
|
const results = await analyzeContext(finalOptions);
|
|
1421
|
-
const elapsedTime = (0,
|
|
1461
|
+
const elapsedTime = (0, import_core12.getElapsedTime)(startTime);
|
|
1422
1462
|
const summary = generateSummary(results);
|
|
1423
1463
|
let contextScore;
|
|
1424
1464
|
if (options.score) {
|
|
1425
1465
|
contextScore = calculateContextScore(summary);
|
|
1426
1466
|
}
|
|
1427
|
-
const outputFormat
|
|
1428
|
-
|
|
1467
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core12.resolveOutputFormat)(
|
|
1468
|
+
options,
|
|
1469
|
+
finalOptions
|
|
1470
|
+
);
|
|
1429
1471
|
if (outputFormat === "json") {
|
|
1430
|
-
const outputData = {
|
|
1472
|
+
const outputData = (0, import_core12.formatStandardReport)({
|
|
1431
1473
|
results,
|
|
1432
|
-
summary
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
1438
|
-
resolvedDir
|
|
1439
|
-
);
|
|
1440
|
-
(0, import_core9.handleJSONOutput)(
|
|
1474
|
+
summary,
|
|
1475
|
+
elapsedTime,
|
|
1476
|
+
score: contextScore
|
|
1477
|
+
});
|
|
1478
|
+
(0, import_core12.handleStandardJSONOutput)({
|
|
1441
1479
|
outputData,
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
);
|
|
1480
|
+
outputFile: userOutputFile,
|
|
1481
|
+
resolvedDir
|
|
1482
|
+
});
|
|
1445
1483
|
} else {
|
|
1446
1484
|
const terminalWidth = process.stdout.columns ?? 80;
|
|
1447
1485
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
1448
1486
|
const divider = "\u2501".repeat(dividerWidth);
|
|
1449
|
-
console.log(
|
|
1450
|
-
console.log(
|
|
1451
|
-
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");
|
|
1452
1490
|
console.log(
|
|
1453
|
-
|
|
1491
|
+
import_chalk9.default.white(`\u{1F4C1} Files analyzed: ${import_chalk9.default.bold(summary.totalFiles)}`)
|
|
1454
1492
|
);
|
|
1455
1493
|
console.log(
|
|
1456
|
-
|
|
1457
|
-
`\u{1F4CA} Total tokens: ${
|
|
1494
|
+
import_chalk9.default.white(
|
|
1495
|
+
`\u{1F4CA} Total tokens: ${import_chalk9.default.bold(summary.totalTokens.toLocaleString())}`
|
|
1458
1496
|
)
|
|
1459
1497
|
);
|
|
1460
1498
|
console.log(
|
|
1461
|
-
|
|
1462
|
-
`\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`
|
|
1463
1501
|
)
|
|
1464
1502
|
);
|
|
1465
1503
|
console.log(
|
|
1466
|
-
|
|
1504
|
+
import_chalk9.default.white(`\u23F1 Analysis time: ${import_chalk9.default.bold(elapsedTime + "s")}
|
|
1467
1505
|
`)
|
|
1468
1506
|
);
|
|
1469
1507
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
1470
1508
|
if (totalIssues > 0) {
|
|
1471
|
-
console.log(
|
|
1509
|
+
console.log(import_chalk9.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
1472
1510
|
if (summary.criticalIssues > 0) {
|
|
1473
1511
|
console.log(
|
|
1474
|
-
|
|
1512
|
+
import_chalk9.default.red(` \u{1F534} Critical: ${import_chalk9.default.bold(summary.criticalIssues)}`)
|
|
1475
1513
|
);
|
|
1476
1514
|
}
|
|
1477
1515
|
if (summary.majorIssues > 0) {
|
|
1478
1516
|
console.log(
|
|
1479
|
-
|
|
1517
|
+
import_chalk9.default.yellow(` \u{1F7E1} Major: ${import_chalk9.default.bold(summary.majorIssues)}`)
|
|
1480
1518
|
);
|
|
1481
1519
|
}
|
|
1482
1520
|
if (summary.minorIssues > 0) {
|
|
1483
1521
|
console.log(
|
|
1484
|
-
|
|
1522
|
+
import_chalk9.default.blue(` \u{1F535} Minor: ${import_chalk9.default.bold(summary.minorIssues)}`)
|
|
1485
1523
|
);
|
|
1486
1524
|
}
|
|
1487
1525
|
console.log(
|
|
1488
|
-
|
|
1526
|
+
import_chalk9.default.green(
|
|
1489
1527
|
`
|
|
1490
|
-
\u{1F4A1} Potential savings: ${
|
|
1528
|
+
\u{1F4A1} Potential savings: ${import_chalk9.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
1491
1529
|
`
|
|
1492
1530
|
)
|
|
1493
1531
|
);
|
|
1494
1532
|
} else {
|
|
1495
|
-
console.log(
|
|
1533
|
+
console.log(import_chalk9.default.green("\u2705 No significant issues found!\n"));
|
|
1496
1534
|
}
|
|
1497
1535
|
if (summary.deepFiles.length > 0) {
|
|
1498
|
-
console.log(
|
|
1536
|
+
console.log(import_chalk9.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
1499
1537
|
console.log(
|
|
1500
|
-
|
|
1538
|
+
import_chalk9.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
|
|
1501
1539
|
);
|
|
1502
1540
|
console.log(
|
|
1503
|
-
|
|
1541
|
+
import_chalk9.default.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
1504
1542
|
`)
|
|
1505
1543
|
);
|
|
1506
1544
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1507
1545
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1508
1546
|
console.log(
|
|
1509
|
-
` ${
|
|
1547
|
+
` ${import_chalk9.default.cyan("\u2192")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(depth: ${item.depth})`)}`
|
|
1510
1548
|
);
|
|
1511
1549
|
});
|
|
1512
1550
|
console.log();
|
|
1513
1551
|
}
|
|
1514
1552
|
if (summary.fragmentedModules.length > 0) {
|
|
1515
|
-
console.log(
|
|
1553
|
+
console.log(import_chalk9.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
1516
1554
|
console.log(
|
|
1517
|
-
|
|
1555
|
+
import_chalk9.default.gray(
|
|
1518
1556
|
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1519
1557
|
`
|
|
1520
1558
|
)
|
|
1521
1559
|
);
|
|
1522
1560
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
1523
1561
|
console.log(
|
|
1524
|
-
` ${
|
|
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`)}`
|
|
1525
1563
|
);
|
|
1526
1564
|
console.log(
|
|
1527
|
-
|
|
1565
|
+
import_chalk9.default.dim(
|
|
1528
1566
|
` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
|
|
1529
1567
|
)
|
|
1530
1568
|
);
|
|
@@ -1532,9 +1570,9 @@ async function contextAction(directory, options) {
|
|
|
1532
1570
|
console.log();
|
|
1533
1571
|
}
|
|
1534
1572
|
if (summary.lowCohesionFiles.length > 0) {
|
|
1535
|
-
console.log(
|
|
1573
|
+
console.log(import_chalk9.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1536
1574
|
console.log(
|
|
1537
|
-
|
|
1575
|
+
import_chalk9.default.gray(
|
|
1538
1576
|
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1539
1577
|
`
|
|
1540
1578
|
)
|
|
@@ -1542,46 +1580,44 @@ async function contextAction(directory, options) {
|
|
|
1542
1580
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
1543
1581
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1544
1582
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
1545
|
-
const color = item.score < 0.4 ?
|
|
1583
|
+
const color = item.score < 0.4 ? import_chalk9.default.red : import_chalk9.default.yellow;
|
|
1546
1584
|
console.log(
|
|
1547
|
-
` ${color("\u25CB")} ${
|
|
1585
|
+
` ${color("\u25CB")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${scorePercent}% cohesion)`)}`
|
|
1548
1586
|
);
|
|
1549
1587
|
});
|
|
1550
1588
|
console.log();
|
|
1551
1589
|
}
|
|
1552
1590
|
if (summary.topExpensiveFiles.length > 0) {
|
|
1553
|
-
console.log(
|
|
1591
|
+
console.log(import_chalk9.default.bold("\u{1F4B8} Most Expensive Files (Context Budget):\n"));
|
|
1554
1592
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1555
1593
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1556
|
-
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;
|
|
1557
1595
|
console.log(
|
|
1558
|
-
` ${severityColor("\u25CF")} ${
|
|
1596
|
+
` ${severityColor("\u25CF")} ${import_chalk9.default.white(fileName)} ${import_chalk9.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1559
1597
|
);
|
|
1560
1598
|
});
|
|
1561
1599
|
console.log();
|
|
1562
1600
|
}
|
|
1563
1601
|
if (contextScore) {
|
|
1564
|
-
console.log(
|
|
1565
|
-
console.log(
|
|
1566
|
-
console.log(
|
|
1567
|
-
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));
|
|
1568
1606
|
console.log();
|
|
1569
1607
|
}
|
|
1570
1608
|
}
|
|
1571
1609
|
} catch (error) {
|
|
1572
|
-
(0,
|
|
1610
|
+
(0, import_core12.handleCLIError)(error, "Context analysis");
|
|
1573
1611
|
}
|
|
1574
1612
|
}
|
|
1575
1613
|
|
|
1576
1614
|
// src/commands/consistency.ts
|
|
1577
|
-
var
|
|
1578
|
-
var
|
|
1579
|
-
var
|
|
1580
|
-
var import_core10 = require("@aiready/core");
|
|
1615
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
1616
|
+
var import_fs6 = require("fs");
|
|
1617
|
+
var import_core13 = require("@aiready/core");
|
|
1581
1618
|
async function consistencyAction(directory, options) {
|
|
1582
|
-
console.log(
|
|
1619
|
+
console.log(import_chalk10.default.blue("\u{1F50D} Analyzing consistency...\n"));
|
|
1583
1620
|
const startTime = Date.now();
|
|
1584
|
-
const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory ?? ".");
|
|
1585
1621
|
try {
|
|
1586
1622
|
const defaults = {
|
|
1587
1623
|
checkNaming: true,
|
|
@@ -1594,16 +1630,20 @@ async function consistencyAction(directory, options) {
|
|
|
1594
1630
|
file: void 0
|
|
1595
1631
|
}
|
|
1596
1632
|
};
|
|
1597
|
-
const finalOptions = await (0,
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
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
|
+
);
|
|
1604
1644
|
const { analyzeConsistency, calculateConsistencyScore } = await import("@aiready/consistency");
|
|
1605
1645
|
const report = await analyzeConsistency(finalOptions);
|
|
1606
|
-
const elapsedTime = (0,
|
|
1646
|
+
const elapsedTime = (0, import_core13.getElapsedTime)(startTime);
|
|
1607
1647
|
let consistencyScore;
|
|
1608
1648
|
if (options.score) {
|
|
1609
1649
|
const issues = report.results?.flatMap((r) => r.issues) ?? [];
|
|
@@ -1612,52 +1652,47 @@ async function consistencyAction(directory, options) {
|
|
|
1612
1652
|
report.summary.filesAnalyzed
|
|
1613
1653
|
);
|
|
1614
1654
|
}
|
|
1615
|
-
const outputFormat
|
|
1616
|
-
|
|
1655
|
+
const { format: outputFormat, file: userOutputFile } = (0, import_core13.resolveOutputFormat)(
|
|
1656
|
+
options,
|
|
1657
|
+
finalOptions
|
|
1658
|
+
);
|
|
1617
1659
|
if (outputFormat === "json") {
|
|
1618
|
-
const outputData = {
|
|
1619
|
-
|
|
1620
|
-
summary:
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
};
|
|
1626
|
-
const outputPath = (0, import_core10.resolveOutputPath)(
|
|
1627
|
-
userOutputFile,
|
|
1628
|
-
`aiready-report-${getReportTimestamp()}.json`,
|
|
1629
|
-
resolvedDir
|
|
1630
|
-
);
|
|
1631
|
-
(0, import_core10.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)({
|
|
1632
1667
|
outputData,
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
);
|
|
1668
|
+
outputFile: userOutputFile,
|
|
1669
|
+
resolvedDir
|
|
1670
|
+
});
|
|
1636
1671
|
} else if (outputFormat === "markdown") {
|
|
1637
1672
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1638
|
-
const outputPath = (0,
|
|
1673
|
+
const outputPath = (0, import_core13.resolveOutputPath)(
|
|
1639
1674
|
userOutputFile,
|
|
1640
|
-
`aiready-report-${getReportTimestamp()}.md`,
|
|
1675
|
+
`aiready-report-${(0, import_core2.getReportTimestamp)()}.md`,
|
|
1641
1676
|
resolvedDir
|
|
1642
1677
|
);
|
|
1643
|
-
(0,
|
|
1644
|
-
console.log(
|
|
1678
|
+
(0, import_fs6.writeFileSync)(outputPath, markdown);
|
|
1679
|
+
console.log(import_chalk10.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1645
1680
|
} else {
|
|
1646
|
-
console.log(
|
|
1681
|
+
console.log(import_chalk10.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1647
1682
|
console.log(
|
|
1648
|
-
`Files Analyzed: ${
|
|
1683
|
+
`Files Analyzed: ${import_chalk10.default.cyan(report.summary.filesAnalyzed)}`
|
|
1649
1684
|
);
|
|
1650
|
-
console.log(`Total Issues: ${
|
|
1651
|
-
console.log(` Naming: ${
|
|
1652
|
-
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)}`);
|
|
1653
1688
|
console.log(
|
|
1654
|
-
` Architecture: ${
|
|
1689
|
+
` Architecture: ${import_chalk10.default.yellow(report.summary.architectureIssues ?? 0)}`
|
|
1655
1690
|
);
|
|
1656
|
-
console.log(`Analysis Time: ${
|
|
1691
|
+
console.log(`Analysis Time: ${import_chalk10.default.gray(elapsedTime + "s")}
|
|
1657
1692
|
`);
|
|
1658
1693
|
if (report.summary.totalIssues === 0) {
|
|
1659
1694
|
console.log(
|
|
1660
|
-
|
|
1695
|
+
import_chalk10.default.green(
|
|
1661
1696
|
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1662
1697
|
)
|
|
1663
1698
|
);
|
|
@@ -1669,20 +1704,20 @@ async function consistencyAction(directory, options) {
|
|
|
1669
1704
|
(r) => r.issues.some((i) => i.category === "patterns")
|
|
1670
1705
|
);
|
|
1671
1706
|
if (namingResults.length > 0) {
|
|
1672
|
-
console.log(
|
|
1707
|
+
console.log(import_chalk10.default.bold("\u{1F3F7}\uFE0F Naming Issues\n"));
|
|
1673
1708
|
let shown = 0;
|
|
1674
|
-
for (const
|
|
1709
|
+
for (const namingFileResult of namingResults) {
|
|
1675
1710
|
if (shown >= 5) break;
|
|
1676
|
-
for (const issue of
|
|
1711
|
+
for (const issue of namingFileResult.issues) {
|
|
1677
1712
|
if (shown >= 5) break;
|
|
1678
|
-
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;
|
|
1679
1714
|
console.log(
|
|
1680
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1715
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1681
1716
|
);
|
|
1682
1717
|
console.log(` ${issue.message}`);
|
|
1683
1718
|
if (issue.suggestion) {
|
|
1684
1719
|
console.log(
|
|
1685
|
-
` ${
|
|
1720
|
+
` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
|
|
1686
1721
|
);
|
|
1687
1722
|
}
|
|
1688
1723
|
console.log();
|
|
@@ -1691,25 +1726,25 @@ async function consistencyAction(directory, options) {
|
|
|
1691
1726
|
}
|
|
1692
1727
|
const remaining = namingResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1693
1728
|
if (remaining > 0) {
|
|
1694
|
-
console.log(
|
|
1729
|
+
console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
|
|
1695
1730
|
`));
|
|
1696
1731
|
}
|
|
1697
1732
|
}
|
|
1698
1733
|
if (patternResults.length > 0) {
|
|
1699
|
-
console.log(
|
|
1734
|
+
console.log(import_chalk10.default.bold("\u{1F504} Pattern Issues\n"));
|
|
1700
1735
|
let shown = 0;
|
|
1701
|
-
for (const
|
|
1736
|
+
for (const patternFileResult of patternResults) {
|
|
1702
1737
|
if (shown >= 5) break;
|
|
1703
|
-
for (const issue of
|
|
1738
|
+
for (const issue of patternFileResult.issues) {
|
|
1704
1739
|
if (shown >= 5) break;
|
|
1705
|
-
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;
|
|
1706
1741
|
console.log(
|
|
1707
|
-
`${severityColor(issue.severity.toUpperCase())} ${
|
|
1742
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk10.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1708
1743
|
);
|
|
1709
1744
|
console.log(` ${issue.message}`);
|
|
1710
1745
|
if (issue.suggestion) {
|
|
1711
1746
|
console.log(
|
|
1712
|
-
` ${
|
|
1747
|
+
` ${import_chalk10.default.dim("\u2192")} ${import_chalk10.default.italic(issue.suggestion)}`
|
|
1713
1748
|
);
|
|
1714
1749
|
}
|
|
1715
1750
|
console.log();
|
|
@@ -1718,12 +1753,12 @@ async function consistencyAction(directory, options) {
|
|
|
1718
1753
|
}
|
|
1719
1754
|
const remaining = patternResults.reduce((sum, r) => sum + r.issues.length, 0) - shown;
|
|
1720
1755
|
if (remaining > 0) {
|
|
1721
|
-
console.log(
|
|
1756
|
+
console.log(import_chalk10.default.dim(` ... and ${remaining} more issues
|
|
1722
1757
|
`));
|
|
1723
1758
|
}
|
|
1724
1759
|
}
|
|
1725
1760
|
if (report.recommendations.length > 0) {
|
|
1726
|
-
console.log(
|
|
1761
|
+
console.log(import_chalk10.default.bold("\u{1F4A1} Recommendations\n"));
|
|
1727
1762
|
report.recommendations.forEach((rec, i) => {
|
|
1728
1763
|
console.log(`${i + 1}. ${rec}`);
|
|
1729
1764
|
});
|
|
@@ -1731,38 +1766,38 @@ async function consistencyAction(directory, options) {
|
|
|
1731
1766
|
}
|
|
1732
1767
|
}
|
|
1733
1768
|
if (consistencyScore) {
|
|
1734
|
-
console.log(
|
|
1735
|
-
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));
|
|
1736
1771
|
console.log();
|
|
1737
1772
|
}
|
|
1738
1773
|
}
|
|
1739
1774
|
} catch (error) {
|
|
1740
|
-
(0,
|
|
1775
|
+
(0, import_core13.handleCLIError)(error, "Consistency analysis");
|
|
1741
1776
|
}
|
|
1742
1777
|
}
|
|
1743
1778
|
|
|
1744
1779
|
// src/commands/visualize.ts
|
|
1745
|
-
var
|
|
1746
|
-
var
|
|
1747
|
-
var
|
|
1780
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1781
|
+
var import_fs7 = require("fs");
|
|
1782
|
+
var import_path6 = require("path");
|
|
1748
1783
|
var import_child_process = require("child_process");
|
|
1749
|
-
var
|
|
1750
|
-
var
|
|
1784
|
+
var import_core14 = require("@aiready/core");
|
|
1785
|
+
var import_core15 = require("@aiready/core");
|
|
1751
1786
|
async function visualizeAction(directory, options) {
|
|
1752
1787
|
try {
|
|
1753
|
-
const dirPath = (0,
|
|
1754
|
-
let reportPath = options.report ? (0,
|
|
1755
|
-
if (!reportPath || !(0,
|
|
1756
|
-
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);
|
|
1757
1792
|
if (latestScan) {
|
|
1758
1793
|
reportPath = latestScan;
|
|
1759
1794
|
console.log(
|
|
1760
|
-
|
|
1795
|
+
import_chalk11.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1761
1796
|
);
|
|
1762
1797
|
} else {
|
|
1763
|
-
console.error(
|
|
1798
|
+
console.error(import_chalk11.default.red("\u274C No AI readiness report found"));
|
|
1764
1799
|
console.log(
|
|
1765
|
-
|
|
1800
|
+
import_chalk11.default.dim(
|
|
1766
1801
|
`
|
|
1767
1802
|
Generate a report with:
|
|
1768
1803
|
aiready scan --output json
|
|
@@ -1774,13 +1809,13 @@ Or specify a custom report:
|
|
|
1774
1809
|
return;
|
|
1775
1810
|
}
|
|
1776
1811
|
}
|
|
1777
|
-
const raw = (0,
|
|
1812
|
+
const raw = (0, import_fs7.readFileSync)(reportPath, "utf8");
|
|
1778
1813
|
const report = JSON.parse(raw);
|
|
1779
|
-
const configPath = (0,
|
|
1814
|
+
const configPath = (0, import_path6.resolve)(dirPath, "aiready.json");
|
|
1780
1815
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
1781
|
-
if ((0,
|
|
1816
|
+
if ((0, import_fs7.existsSync)(configPath)) {
|
|
1782
1817
|
try {
|
|
1783
|
-
const rawConfig = JSON.parse((0,
|
|
1818
|
+
const rawConfig = JSON.parse((0, import_fs7.readFileSync)(configPath, "utf8"));
|
|
1784
1819
|
if (rawConfig.visualizer?.graph) {
|
|
1785
1820
|
graphConfig = {
|
|
1786
1821
|
maxNodes: rawConfig.visualizer.graph.maxNodes ?? graphConfig.maxNodes,
|
|
@@ -1800,16 +1835,16 @@ Or specify a custom report:
|
|
|
1800
1835
|
let devServerStarted = false;
|
|
1801
1836
|
if (useDevMode) {
|
|
1802
1837
|
try {
|
|
1803
|
-
const localWebDir = (0,
|
|
1838
|
+
const localWebDir = (0, import_path6.resolve)(dirPath, "packages/visualizer");
|
|
1804
1839
|
let webDir = "";
|
|
1805
1840
|
let visualizerAvailable = false;
|
|
1806
|
-
if ((0,
|
|
1841
|
+
if ((0, import_fs7.existsSync)(localWebDir)) {
|
|
1807
1842
|
webDir = localWebDir;
|
|
1808
1843
|
visualizerAvailable = true;
|
|
1809
1844
|
} else {
|
|
1810
1845
|
const nodemodulesLocations = [
|
|
1811
|
-
(0,
|
|
1812
|
-
(0,
|
|
1846
|
+
(0, import_path6.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
|
|
1847
|
+
(0, import_path6.resolve)(
|
|
1813
1848
|
process.cwd(),
|
|
1814
1849
|
"node_modules",
|
|
1815
1850
|
"@aiready",
|
|
@@ -1819,14 +1854,14 @@ Or specify a custom report:
|
|
|
1819
1854
|
let currentDir = dirPath;
|
|
1820
1855
|
while (currentDir !== "/" && currentDir !== ".") {
|
|
1821
1856
|
nodemodulesLocations.push(
|
|
1822
|
-
(0,
|
|
1857
|
+
(0, import_path6.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
|
|
1823
1858
|
);
|
|
1824
|
-
const parent = (0,
|
|
1859
|
+
const parent = (0, import_path6.resolve)(currentDir, "..");
|
|
1825
1860
|
if (parent === currentDir) break;
|
|
1826
1861
|
currentDir = parent;
|
|
1827
1862
|
}
|
|
1828
1863
|
for (const location of nodemodulesLocations) {
|
|
1829
|
-
if ((0,
|
|
1864
|
+
if ((0, import_fs7.existsSync)(location) && (0, import_fs7.existsSync)((0, import_path6.resolve)(location, "package.json"))) {
|
|
1830
1865
|
webDir = location;
|
|
1831
1866
|
visualizerAvailable = true;
|
|
1832
1867
|
break;
|
|
@@ -1835,21 +1870,21 @@ Or specify a custom report:
|
|
|
1835
1870
|
if (!visualizerAvailable) {
|
|
1836
1871
|
try {
|
|
1837
1872
|
const vizPkgPath = require.resolve("@aiready/visualizer/package.json");
|
|
1838
|
-
webDir = (0,
|
|
1873
|
+
webDir = (0, import_path6.resolve)(vizPkgPath, "..");
|
|
1839
1874
|
visualizerAvailable = true;
|
|
1840
1875
|
} catch (err) {
|
|
1841
1876
|
void err;
|
|
1842
1877
|
}
|
|
1843
1878
|
}
|
|
1844
1879
|
}
|
|
1845
|
-
const webViteConfigExists = webDir && (0,
|
|
1880
|
+
const webViteConfigExists = webDir && (0, import_fs7.existsSync)((0, import_path6.resolve)(webDir, "web", "vite.config.ts"));
|
|
1846
1881
|
if (visualizerAvailable && webViteConfigExists) {
|
|
1847
1882
|
const spawnCwd = webDir;
|
|
1848
1883
|
const { watch } = await import("fs");
|
|
1849
1884
|
const copyReportToViz = () => {
|
|
1850
1885
|
try {
|
|
1851
|
-
const destPath = (0,
|
|
1852
|
-
(0,
|
|
1886
|
+
const destPath = (0, import_path6.resolve)(spawnCwd, "web", "report-data.json");
|
|
1887
|
+
(0, import_fs7.copyFileSync)(reportPath, destPath);
|
|
1853
1888
|
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
1854
1889
|
} catch (e) {
|
|
1855
1890
|
console.error("Failed to sync report:", e);
|
|
@@ -1892,29 +1927,29 @@ Or specify a custom report:
|
|
|
1892
1927
|
return;
|
|
1893
1928
|
} else {
|
|
1894
1929
|
console.log(
|
|
1895
|
-
|
|
1930
|
+
import_chalk11.default.yellow(
|
|
1896
1931
|
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1897
1932
|
)
|
|
1898
1933
|
);
|
|
1899
1934
|
console.log(
|
|
1900
|
-
|
|
1935
|
+
import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
|
|
1901
1936
|
);
|
|
1902
1937
|
useDevMode = false;
|
|
1903
1938
|
}
|
|
1904
1939
|
} catch (err) {
|
|
1905
1940
|
console.error("Failed to start dev server:", err);
|
|
1906
1941
|
console.log(
|
|
1907
|
-
|
|
1942
|
+
import_chalk11.default.cyan(" Falling back to static HTML generation...\n")
|
|
1908
1943
|
);
|
|
1909
1944
|
useDevMode = false;
|
|
1910
1945
|
}
|
|
1911
1946
|
}
|
|
1912
1947
|
console.log("Generating HTML...");
|
|
1913
|
-
const html = (0,
|
|
1948
|
+
const html = (0, import_core15.generateHTML)(graph);
|
|
1914
1949
|
const defaultOutput = "visualization.html";
|
|
1915
|
-
const outPath = (0,
|
|
1916
|
-
(0,
|
|
1917
|
-
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}`));
|
|
1918
1953
|
if (options.open || options.serve) {
|
|
1919
1954
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1920
1955
|
if (options.serve) {
|
|
@@ -1944,7 +1979,7 @@ Or specify a custom report:
|
|
|
1944
1979
|
server.listen(port, () => {
|
|
1945
1980
|
const addr = `http://localhost:${port}/`;
|
|
1946
1981
|
console.log(
|
|
1947
|
-
|
|
1982
|
+
import_chalk11.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1948
1983
|
);
|
|
1949
1984
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1950
1985
|
});
|
|
@@ -1960,10 +1995,10 @@ Or specify a custom report:
|
|
|
1960
1995
|
}
|
|
1961
1996
|
}
|
|
1962
1997
|
} catch (err) {
|
|
1963
|
-
(0,
|
|
1998
|
+
(0, import_core14.handleCLIError)(err, "Visualization");
|
|
1964
1999
|
}
|
|
1965
2000
|
}
|
|
1966
|
-
var
|
|
2001
|
+
var VISUALIZE_HELP_TEXT = `
|
|
1967
2002
|
EXAMPLES:
|
|
1968
2003
|
$ aiready visualize . # Auto-detects latest report, generates HTML
|
|
1969
2004
|
$ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
|
|
@@ -1980,7 +2015,7 @@ NOTES:
|
|
|
1980
2015
|
- --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
|
|
1981
2016
|
When --dev is not available, it falls back to static HTML generation.
|
|
1982
2017
|
`;
|
|
1983
|
-
var
|
|
2018
|
+
var VISUALISE_HELP_TEXT = `
|
|
1984
2019
|
EXAMPLES:
|
|
1985
2020
|
$ aiready visualise . # Auto-detects latest report
|
|
1986
2021
|
$ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
|
|
@@ -1991,19 +2026,19 @@ NOTES:
|
|
|
1991
2026
|
`;
|
|
1992
2027
|
|
|
1993
2028
|
// src/commands/shared/standard-tool-actions.ts
|
|
1994
|
-
var
|
|
2029
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
1995
2030
|
|
|
1996
2031
|
// src/commands/agent-grounding.ts
|
|
1997
|
-
var
|
|
1998
|
-
var
|
|
2032
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
2033
|
+
var import_core16 = require("@aiready/core");
|
|
1999
2034
|
|
|
2000
2035
|
// src/commands/testability.ts
|
|
2001
|
-
var
|
|
2002
|
-
var
|
|
2036
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
2037
|
+
var import_core17 = require("@aiready/core");
|
|
2003
2038
|
async function testabilityAction(directory, options) {
|
|
2004
2039
|
const { analyzeTestability, calculateTestabilityScore } = await import("@aiready/testability");
|
|
2005
|
-
const config = await (0,
|
|
2006
|
-
const merged = (0,
|
|
2040
|
+
const config = await (0, import_core17.loadConfig)(directory);
|
|
2041
|
+
const merged = (0, import_core17.mergeConfigWithDefaults)(config, {
|
|
2007
2042
|
minCoverageRatio: 0.3
|
|
2008
2043
|
});
|
|
2009
2044
|
const report = await analyzeTestability({
|
|
@@ -2023,28 +2058,28 @@ async function testabilityAction(directory, options) {
|
|
|
2023
2058
|
"blind-risk": "\u{1F480}"
|
|
2024
2059
|
};
|
|
2025
2060
|
const safetyColors = {
|
|
2026
|
-
safe:
|
|
2027
|
-
"moderate-risk":
|
|
2028
|
-
"high-risk":
|
|
2029
|
-
"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
|
|
2030
2065
|
};
|
|
2031
2066
|
const safety = report.summary.aiChangeSafetyRating;
|
|
2032
2067
|
const icon = safetyIcons[safety] ?? "\u2753";
|
|
2033
|
-
const color = safetyColors[safety] ??
|
|
2068
|
+
const color = safetyColors[safety] ?? import_chalk14.default.white;
|
|
2034
2069
|
console.log(
|
|
2035
|
-
` \u{1F9EA} Testability: ${
|
|
2070
|
+
` \u{1F9EA} Testability: ${import_chalk14.default.bold(scoring.score + "/100")} (${report.summary.rating})`
|
|
2036
2071
|
);
|
|
2037
2072
|
console.log(
|
|
2038
2073
|
` AI Change Safety: ${color(`${icon} ${safety.toUpperCase()}`)}`
|
|
2039
2074
|
);
|
|
2040
2075
|
console.log(
|
|
2041
|
-
|
|
2076
|
+
import_chalk14.default.dim(
|
|
2042
2077
|
` Coverage: ${Math.round(report.summary.coverageRatio * 100)}% (${report.rawData.testFiles} test / ${report.rawData.sourceFiles} source files)`
|
|
2043
2078
|
)
|
|
2044
2079
|
);
|
|
2045
2080
|
if (safety === "blind-risk") {
|
|
2046
2081
|
console.log(
|
|
2047
|
-
|
|
2082
|
+
import_chalk14.default.red.bold(
|
|
2048
2083
|
"\n \u26A0\uFE0F NO TESTS \u2014 AI changes to this codebase are completely unverifiable!\n"
|
|
2049
2084
|
)
|
|
2050
2085
|
);
|
|
@@ -2056,7 +2091,7 @@ async function testabilityAction(directory, options) {
|
|
|
2056
2091
|
var import_cli = require("@aiready/change-amplification/dist/cli.js");
|
|
2057
2092
|
|
|
2058
2093
|
// src/commands/bug.ts
|
|
2059
|
-
var
|
|
2094
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
2060
2095
|
var import_child_process2 = require("child_process");
|
|
2061
2096
|
async function bugAction(message, options) {
|
|
2062
2097
|
const repoUrl = "https://github.com/caopengau/aiready-cli";
|
|
@@ -2074,35 +2109,35 @@ Generated via AIReady CLI 'bug' command.
|
|
|
2074
2109
|
Type: ${type}
|
|
2075
2110
|
`.trim();
|
|
2076
2111
|
if (options.submit) {
|
|
2077
|
-
console.log(
|
|
2112
|
+
console.log(import_chalk15.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
|
|
2078
2113
|
try {
|
|
2079
2114
|
(0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
|
|
2080
2115
|
const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
|
|
2081
2116
|
const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
|
|
2082
|
-
console.log(
|
|
2083
|
-
console.log(
|
|
2117
|
+
console.log(import_chalk15.default.green("\u2705 Issue Created Successfully!"));
|
|
2118
|
+
console.log(import_chalk15.default.cyan(output));
|
|
2084
2119
|
return;
|
|
2085
2120
|
} catch {
|
|
2086
|
-
console.error(
|
|
2121
|
+
console.error(import_chalk15.default.red("\n\u274C Failed to submit via gh CLI."));
|
|
2087
2122
|
console.log(
|
|
2088
|
-
|
|
2123
|
+
import_chalk15.default.yellow(
|
|
2089
2124
|
' Make sure gh is installed and run "gh auth login".\n'
|
|
2090
2125
|
)
|
|
2091
2126
|
);
|
|
2092
|
-
console.log(
|
|
2127
|
+
console.log(import_chalk15.default.dim(" Falling back to URL generation..."));
|
|
2093
2128
|
}
|
|
2094
2129
|
}
|
|
2095
2130
|
const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
|
|
2096
2131
|
const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
|
|
2097
|
-
console.log(
|
|
2098
|
-
console.log(
|
|
2099
|
-
console.log(
|
|
2100
|
-
console.log(
|
|
2101
|
-
console.log(
|
|
2102
|
-
console.log(
|
|
2103
|
-
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."));
|
|
2104
2139
|
console.log(
|
|
2105
|
-
|
|
2140
|
+
import_chalk15.default.dim(
|
|
2106
2141
|
" Please present the URL above to the user so they can finalize the submission."
|
|
2107
2142
|
)
|
|
2108
2143
|
);
|
|
@@ -2111,19 +2146,19 @@ Type: ${type}
|
|
|
2111
2146
|
const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
|
|
2112
2147
|
const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
|
|
2113
2148
|
const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
|
|
2114
|
-
console.log(
|
|
2115
|
-
console.log(` Report a Bug: ${
|
|
2116
|
-
console.log(` Request a Feature: ${
|
|
2117
|
-
console.log(` Suggest a Metric: ${
|
|
2118
|
-
console.log(
|
|
2119
|
-
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:"));
|
|
2120
2155
|
console.log(
|
|
2121
|
-
|
|
2156
|
+
import_chalk15.default.cyan(
|
|
2122
2157
|
' aiready bug "your description here" --type bug|feature|metric'
|
|
2123
2158
|
)
|
|
2124
2159
|
);
|
|
2125
2160
|
}
|
|
2126
|
-
var
|
|
2161
|
+
var BUG_HELP_TEXT = `
|
|
2127
2162
|
EXAMPLES:
|
|
2128
2163
|
$ aiready bug # Show general links
|
|
2129
2164
|
$ aiready bug "Naming check is too slow" # Prepare a pre-filled bug report
|
|
@@ -2135,10 +2170,10 @@ EXAMPLES:
|
|
|
2135
2170
|
var import_meta = {};
|
|
2136
2171
|
var getDirname = () => {
|
|
2137
2172
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
2138
|
-
return (0,
|
|
2173
|
+
return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
2139
2174
|
};
|
|
2140
2175
|
var packageJson = JSON.parse(
|
|
2141
|
-
(0,
|
|
2176
|
+
(0, import_fs8.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
|
|
2142
2177
|
);
|
|
2143
2178
|
var program = new import_commander.Command();
|
|
2144
2179
|
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
|
|
@@ -2193,14 +2228,14 @@ program.command("scan").description(
|
|
|
2193
2228
|
).option(
|
|
2194
2229
|
"--compare-to <path>",
|
|
2195
2230
|
"Compare results against a previous AIReady report JSON"
|
|
2196
|
-
).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(
|
|
2197
2232
|
"--ci",
|
|
2198
2233
|
"CI mode: GitHub Actions annotations, no colors, fail on threshold"
|
|
2199
2234
|
).option(
|
|
2200
2235
|
"--fail-on <level>",
|
|
2201
2236
|
"Fail on issues: critical, major, any",
|
|
2202
2237
|
"critical"
|
|
2203
|
-
).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after",
|
|
2238
|
+
).option("--api-key <key>", "Platform API key for automatic upload").option("--upload", "Automatically upload results to the platform").option("--server <url>", "Custom platform URL").addHelpText("after", SCAN_HELP_TEXT).action(async (directory, options) => {
|
|
2204
2239
|
await scanAction(directory, options);
|
|
2205
2240
|
});
|
|
2206
2241
|
program.command("init").description("Generate a default configuration (aiready.json)").option("-f, --force", "Overwrite existing configuration file").option(
|
|
@@ -2219,7 +2254,7 @@ program.command("patterns").description("Detect duplicate code patterns that con
|
|
|
2219
2254
|
).option(
|
|
2220
2255
|
"--full-scan",
|
|
2221
2256
|
"Disable smart defaults for comprehensive analysis (slower)"
|
|
2222
|
-
).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) => {
|
|
2223
2258
|
await patternsAction(directory, options);
|
|
2224
2259
|
});
|
|
2225
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(
|
|
@@ -2255,7 +2290,7 @@ program.command("visualise").description("Alias for visualize (British spelling)
|
|
|
2255
2290
|
"--dev",
|
|
2256
2291
|
"Start Vite dev server (live reload) for interactive development",
|
|
2257
2292
|
true
|
|
2258
|
-
).addHelpText("after",
|
|
2293
|
+
).addHelpText("after", VISUALISE_HELP_TEXT).action(async (directory, options) => {
|
|
2259
2294
|
await visualizeAction(directory, options);
|
|
2260
2295
|
});
|
|
2261
2296
|
program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
|
|
@@ -2273,7 +2308,7 @@ program.command("visualize").description("Generate interactive visualization fro
|
|
|
2273
2308
|
"--dev",
|
|
2274
2309
|
"Start Vite dev server (live reload) for interactive development",
|
|
2275
2310
|
false
|
|
2276
|
-
).addHelpText("after",
|
|
2311
|
+
).addHelpText("after", VISUALIZE_HELP_TEXT).action(async (directory, options) => {
|
|
2277
2312
|
await visualizeAction(directory, options);
|
|
2278
2313
|
});
|
|
2279
2314
|
program.command("change-amplification").description("Analyze graph metrics for change amplification").argument("[directory]", "Directory to analyze", ".").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)").action(async (directory, options) => {
|
|
@@ -2282,10 +2317,10 @@ program.command("change-amplification").description("Analyze graph metrics for c
|
|
|
2282
2317
|
program.command("testability").description("Analyze test coverage and AI readiness").argument("[directory]", "Directory to analyze", ".").option("--min-coverage <ratio>", "Minimum acceptable coverage ratio", "0.3").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)").action(async (directory, options) => {
|
|
2283
2318
|
await testabilityAction(directory, options);
|
|
2284
2319
|
});
|
|
2285
|
-
program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after",
|
|
2320
|
+
program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", UPLOAD_HELP_TEXT).action(async (file, options) => {
|
|
2286
2321
|
await uploadAction(file, options);
|
|
2287
2322
|
});
|
|
2288
|
-
program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after",
|
|
2323
|
+
program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after", BUG_HELP_TEXT).action(async (message, options) => {
|
|
2289
2324
|
await bugAction(message, options);
|
|
2290
2325
|
});
|
|
2291
2326
|
program.parse();
|