@aiready/cli 0.9.40 → 0.9.43
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/.aiready/aiready-report-20260227-133806.json +40 -141
- package/.aiready/aiready-report-20260227-133938.json +40 -141
- package/.aiready/aiready-report-20260228-003433.json +7939 -0
- package/.aiready/aiready-report-20260228-003613.json +771 -0
- package/.github/FUNDING.yml +2 -2
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-lint.log +5 -0
- package/.turbo/turbo-test.log +5 -5
- package/CONTRIBUTING.md +11 -2
- package/dist/chunk-HLBKROD3.mjs +237 -0
- package/dist/chunk-LLJMKNBI.mjs +243 -0
- package/dist/cli.js +708 -184
- package/dist/cli.mjs +687 -178
- package/dist/index.js +24 -9
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/__tests__/cli.test.ts +1 -1
- package/src/cli.ts +114 -28
- package/src/commands/agent-grounding.ts +22 -7
- package/src/commands/ai-signal-clarity.ts +14 -9
- package/src/commands/consistency.ts +70 -30
- package/src/commands/context.ts +109 -39
- package/src/commands/deps-health.ts +15 -6
- package/src/commands/doc-drift.ts +10 -4
- package/src/commands/index.ts +6 -2
- package/src/commands/patterns.ts +67 -26
- package/src/commands/scan.ts +411 -126
- package/src/commands/testability.ts +22 -9
- package/src/commands/visualize.ts +102 -45
- package/src/index.ts +40 -10
- package/src/utils/helpers.ts +57 -32
package/dist/cli.js
CHANGED
|
@@ -54,8 +54,14 @@ function sortBySeverity(results) {
|
|
|
54
54
|
});
|
|
55
55
|
return { ...file, issues: sortedIssues };
|
|
56
56
|
}).sort((a, b) => {
|
|
57
|
-
const aMaxSeverity = Math.max(
|
|
58
|
-
|
|
57
|
+
const aMaxSeverity = Math.max(
|
|
58
|
+
...a.issues.map((i) => severityOrder[i.severity] || 0),
|
|
59
|
+
0
|
|
60
|
+
);
|
|
61
|
+
const bMaxSeverity = Math.max(
|
|
62
|
+
...b.issues.map((i) => severityOrder[i.severity] || 0),
|
|
63
|
+
0
|
|
64
|
+
);
|
|
59
65
|
if (aMaxSeverity !== bMaxSeverity) {
|
|
60
66
|
return bMaxSeverity - aMaxSeverity;
|
|
61
67
|
}
|
|
@@ -122,7 +128,8 @@ async function analyzeUnified(options) {
|
|
|
122
128
|
const report = await analyzeDocDrift({
|
|
123
129
|
rootDir: options.rootDir,
|
|
124
130
|
include: options.include,
|
|
125
|
-
exclude: options.exclude
|
|
131
|
+
exclude: options.exclude,
|
|
132
|
+
onProgress: options.onProgress
|
|
126
133
|
});
|
|
127
134
|
if (options.progressCallback) {
|
|
128
135
|
options.progressCallback({ tool: "doc-drift", data: report });
|
|
@@ -135,7 +142,8 @@ async function analyzeUnified(options) {
|
|
|
135
142
|
const report = await analyzeDeps({
|
|
136
143
|
rootDir: options.rootDir,
|
|
137
144
|
include: options.include,
|
|
138
|
-
exclude: options.exclude
|
|
145
|
+
exclude: options.exclude,
|
|
146
|
+
onProgress: options.onProgress
|
|
139
147
|
});
|
|
140
148
|
if (options.progressCallback) {
|
|
141
149
|
options.progressCallback({ tool: "deps-health", data: report });
|
|
@@ -148,20 +156,25 @@ async function analyzeUnified(options) {
|
|
|
148
156
|
const report = await analyzeAiSignalClarity({
|
|
149
157
|
rootDir: options.rootDir,
|
|
150
158
|
include: options.include,
|
|
151
|
-
exclude: options.exclude
|
|
159
|
+
exclude: options.exclude,
|
|
160
|
+
onProgress: options.onProgress
|
|
152
161
|
});
|
|
153
162
|
if (options.progressCallback) {
|
|
154
163
|
options.progressCallback({ tool: "aiSignalClarity", data: report });
|
|
155
164
|
}
|
|
156
165
|
result.aiSignalClarity = report;
|
|
157
|
-
result.summary.totalIssues += report.results?.reduce(
|
|
166
|
+
result.summary.totalIssues += report.results?.reduce(
|
|
167
|
+
(sum, r) => sum + (r.issues?.length || 0),
|
|
168
|
+
0
|
|
169
|
+
) || 0;
|
|
158
170
|
}
|
|
159
171
|
if (tools.includes("grounding")) {
|
|
160
172
|
const { analyzeAgentGrounding } = await import("@aiready/agent-grounding");
|
|
161
173
|
const report = await analyzeAgentGrounding({
|
|
162
174
|
rootDir: options.rootDir,
|
|
163
175
|
include: options.include,
|
|
164
|
-
exclude: options.exclude
|
|
176
|
+
exclude: options.exclude,
|
|
177
|
+
onProgress: options.onProgress
|
|
165
178
|
});
|
|
166
179
|
if (options.progressCallback) {
|
|
167
180
|
options.progressCallback({ tool: "grounding", data: report });
|
|
@@ -174,7 +187,8 @@ async function analyzeUnified(options) {
|
|
|
174
187
|
const report = await analyzeTestability({
|
|
175
188
|
rootDir: options.rootDir,
|
|
176
189
|
include: options.include,
|
|
177
|
-
exclude: options.exclude
|
|
190
|
+
exclude: options.exclude,
|
|
191
|
+
onProgress: options.onProgress
|
|
178
192
|
});
|
|
179
193
|
if (options.progressCallback) {
|
|
180
194
|
options.progressCallback({ tool: "testability", data: report });
|
|
@@ -187,7 +201,8 @@ async function analyzeUnified(options) {
|
|
|
187
201
|
const report = await analyzeChangeAmplification({
|
|
188
202
|
rootDir: options.rootDir,
|
|
189
203
|
include: options.include,
|
|
190
|
-
exclude: options.exclude
|
|
204
|
+
exclude: options.exclude,
|
|
205
|
+
onProgress: options.onProgress
|
|
191
206
|
});
|
|
192
207
|
if (options.progressCallback) {
|
|
193
208
|
options.progressCallback({ tool: "changeAmplification", data: report });
|
|
@@ -213,19 +228,28 @@ function findLatestScanReport(dirPath) {
|
|
|
213
228
|
if (!(0, import_fs.existsSync)(aireadyDir)) {
|
|
214
229
|
return null;
|
|
215
230
|
}
|
|
216
|
-
let files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
231
|
+
let files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
232
|
+
(f) => f.startsWith("aiready-report-") && f.endsWith(".json")
|
|
233
|
+
);
|
|
217
234
|
if (files.length === 0) {
|
|
218
|
-
files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
235
|
+
files = (0, import_fs.readdirSync)(aireadyDir).filter(
|
|
236
|
+
(f) => f.startsWith("aiready-scan-") && f.endsWith(".json")
|
|
237
|
+
);
|
|
219
238
|
}
|
|
220
239
|
if (files.length === 0) {
|
|
221
240
|
return null;
|
|
222
241
|
}
|
|
223
|
-
const sortedFiles = files.map((f) => ({
|
|
242
|
+
const sortedFiles = files.map((f) => ({
|
|
243
|
+
name: f,
|
|
244
|
+
path: (0, import_path.resolve)(aireadyDir, f),
|
|
245
|
+
mtime: (0, import_fs.statSync)((0, import_path.resolve)(aireadyDir, f)).mtime
|
|
246
|
+
})).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
224
247
|
return sortedFiles[0].path;
|
|
225
248
|
}
|
|
226
|
-
function warnIfGraphCapExceeded(report, dirPath) {
|
|
249
|
+
async function warnIfGraphCapExceeded(report, dirPath) {
|
|
227
250
|
try {
|
|
228
|
-
const { loadConfig: loadConfig4 } =
|
|
251
|
+
const { loadConfig: loadConfig4 } = await import("@aiready/core");
|
|
252
|
+
void loadConfig4;
|
|
229
253
|
let graphConfig = { maxNodes: 400, maxEdges: 600 };
|
|
230
254
|
const configPath = (0, import_path.resolve)(dirPath, "aiready.json");
|
|
231
255
|
if ((0, import_fs.existsSync)(configPath)) {
|
|
@@ -237,7 +261,8 @@ function warnIfGraphCapExceeded(report, dirPath) {
|
|
|
237
261
|
maxEdges: rawConfig.visualizer.graph.maxEdges ?? graphConfig.maxEdges
|
|
238
262
|
};
|
|
239
263
|
}
|
|
240
|
-
} catch (
|
|
264
|
+
} catch (err) {
|
|
265
|
+
void err;
|
|
241
266
|
}
|
|
242
267
|
}
|
|
243
268
|
const nodeCount = (report.context?.length || 0) + (report.patterns?.length || 0);
|
|
@@ -248,21 +273,30 @@ function warnIfGraphCapExceeded(report, dirPath) {
|
|
|
248
273
|
}, 0) || 0;
|
|
249
274
|
if (nodeCount > graphConfig.maxNodes || edgeCount > graphConfig.maxEdges) {
|
|
250
275
|
console.log("");
|
|
251
|
-
console.log(
|
|
276
|
+
console.log(
|
|
277
|
+
import_chalk.default.yellow(`\u26A0\uFE0F Graph may be truncated at visualization time:`)
|
|
278
|
+
);
|
|
252
279
|
if (nodeCount > graphConfig.maxNodes) {
|
|
253
|
-
console.log(
|
|
280
|
+
console.log(
|
|
281
|
+
import_chalk.default.dim(` \u2022 Nodes: ${nodeCount} > limit ${graphConfig.maxNodes}`)
|
|
282
|
+
);
|
|
254
283
|
}
|
|
255
284
|
if (edgeCount > graphConfig.maxEdges) {
|
|
256
|
-
console.log(
|
|
285
|
+
console.log(
|
|
286
|
+
import_chalk.default.dim(` \u2022 Edges: ${edgeCount} > limit ${graphConfig.maxEdges}`)
|
|
287
|
+
);
|
|
257
288
|
}
|
|
258
289
|
console.log(import_chalk.default.dim(` To increase limits, add to aiready.json:`));
|
|
259
290
|
console.log(import_chalk.default.dim(` {`));
|
|
260
291
|
console.log(import_chalk.default.dim(` "visualizer": {`));
|
|
261
|
-
console.log(
|
|
292
|
+
console.log(
|
|
293
|
+
import_chalk.default.dim(` "graph": { "maxNodes": 2000, "maxEdges": 5000 }`)
|
|
294
|
+
);
|
|
262
295
|
console.log(import_chalk.default.dim(` }`));
|
|
263
296
|
console.log(import_chalk.default.dim(` }`));
|
|
264
297
|
}
|
|
265
|
-
} catch (
|
|
298
|
+
} catch (err) {
|
|
299
|
+
void err;
|
|
266
300
|
}
|
|
267
301
|
}
|
|
268
302
|
function generateMarkdownReport(report, elapsedTime) {
|
|
@@ -311,7 +345,17 @@ async function scanAction(directory, options) {
|
|
|
311
345
|
const resolvedDir = (0, import_path2.resolve)(process.cwd(), directory || ".");
|
|
312
346
|
try {
|
|
313
347
|
const defaults = {
|
|
314
|
-
tools: [
|
|
348
|
+
tools: [
|
|
349
|
+
"patterns",
|
|
350
|
+
"context",
|
|
351
|
+
"consistency",
|
|
352
|
+
"aiSignalClarity",
|
|
353
|
+
"grounding",
|
|
354
|
+
"testability",
|
|
355
|
+
"doc-drift",
|
|
356
|
+
"deps-health",
|
|
357
|
+
"changeAmplification"
|
|
358
|
+
],
|
|
315
359
|
include: void 0,
|
|
316
360
|
exclude: void 0,
|
|
317
361
|
output: {
|
|
@@ -321,7 +365,8 @@ async function scanAction(directory, options) {
|
|
|
321
365
|
};
|
|
322
366
|
let profileTools = options.tools ? options.tools.split(",").map((t) => {
|
|
323
367
|
const tool = t.trim();
|
|
324
|
-
if (tool === "hallucination" || tool === "hallucination-risk")
|
|
368
|
+
if (tool === "hallucination" || tool === "hallucination-risk")
|
|
369
|
+
return "aiSignalClarity";
|
|
325
370
|
return tool;
|
|
326
371
|
}) : void 0;
|
|
327
372
|
if (options.profile) {
|
|
@@ -339,8 +384,12 @@ async function scanAction(directory, options) {
|
|
|
339
384
|
profileTools = ["context", "consistency", "grounding"];
|
|
340
385
|
break;
|
|
341
386
|
default:
|
|
342
|
-
console.log(
|
|
343
|
-
|
|
387
|
+
console.log(
|
|
388
|
+
import_chalk2.default.yellow(
|
|
389
|
+
`
|
|
390
|
+
\u26A0\uFE0F Unknown profile '${options.profile}'. Using specified tools or defaults.`
|
|
391
|
+
)
|
|
392
|
+
);
|
|
344
393
|
}
|
|
345
394
|
}
|
|
346
395
|
const cliOverrides = {
|
|
@@ -350,20 +399,41 @@ async function scanAction(directory, options) {
|
|
|
350
399
|
if (profileTools) {
|
|
351
400
|
cliOverrides.tools = profileTools;
|
|
352
401
|
}
|
|
353
|
-
const baseOptions = await (0, import_core.loadMergedConfig)(
|
|
402
|
+
const baseOptions = await (0, import_core.loadMergedConfig)(
|
|
403
|
+
resolvedDir,
|
|
404
|
+
defaults,
|
|
405
|
+
cliOverrides
|
|
406
|
+
);
|
|
354
407
|
let finalOptions = { ...baseOptions };
|
|
355
408
|
if (baseOptions.tools.includes("patterns")) {
|
|
356
409
|
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
357
|
-
const patternSmartDefaults = await getSmartDefaults(
|
|
358
|
-
|
|
410
|
+
const patternSmartDefaults = await getSmartDefaults(
|
|
411
|
+
resolvedDir,
|
|
412
|
+
baseOptions
|
|
413
|
+
);
|
|
414
|
+
finalOptions = {
|
|
415
|
+
...patternSmartDefaults,
|
|
416
|
+
...finalOptions,
|
|
417
|
+
...baseOptions
|
|
418
|
+
};
|
|
359
419
|
}
|
|
360
420
|
console.log(import_chalk2.default.cyan("\n=== AIReady Run Preview ==="));
|
|
361
|
-
console.log(
|
|
421
|
+
console.log(
|
|
422
|
+
import_chalk2.default.white("Tools to run:"),
|
|
423
|
+
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
424
|
+
);
|
|
362
425
|
console.log(import_chalk2.default.white("Will use settings from config and defaults."));
|
|
363
426
|
console.log(import_chalk2.default.white("\nGeneral settings:"));
|
|
364
|
-
if (finalOptions.rootDir)
|
|
365
|
-
|
|
366
|
-
if (finalOptions.
|
|
427
|
+
if (finalOptions.rootDir)
|
|
428
|
+
console.log(` rootDir: ${import_chalk2.default.bold(String(finalOptions.rootDir))}`);
|
|
429
|
+
if (finalOptions.include)
|
|
430
|
+
console.log(
|
|
431
|
+
` include: ${import_chalk2.default.bold(truncateArray(finalOptions.include, 6))}`
|
|
432
|
+
);
|
|
433
|
+
if (finalOptions.exclude)
|
|
434
|
+
console.log(
|
|
435
|
+
` exclude: ${import_chalk2.default.bold(truncateArray(finalOptions.exclude, 6))}`
|
|
436
|
+
);
|
|
367
437
|
if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
|
|
368
438
|
const patternDetectConfig = finalOptions["pattern-detect"] || {
|
|
369
439
|
minSimilarity: finalOptions.minSimilarity,
|
|
@@ -377,15 +447,40 @@ async function scanAction(directory, options) {
|
|
|
377
447
|
includeTests: finalOptions.includeTests
|
|
378
448
|
};
|
|
379
449
|
console.log(import_chalk2.default.white("\nPattern-detect settings:"));
|
|
380
|
-
console.log(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (patternDetectConfig.
|
|
387
|
-
|
|
388
|
-
|
|
450
|
+
console.log(
|
|
451
|
+
` minSimilarity: ${import_chalk2.default.bold(patternDetectConfig.minSimilarity ?? "default")}`
|
|
452
|
+
);
|
|
453
|
+
console.log(
|
|
454
|
+
` minLines: ${import_chalk2.default.bold(patternDetectConfig.minLines ?? "default")}`
|
|
455
|
+
);
|
|
456
|
+
if (patternDetectConfig.approx !== void 0)
|
|
457
|
+
console.log(
|
|
458
|
+
` approx: ${import_chalk2.default.bold(String(patternDetectConfig.approx))}`
|
|
459
|
+
);
|
|
460
|
+
if (patternDetectConfig.minSharedTokens !== void 0)
|
|
461
|
+
console.log(
|
|
462
|
+
` minSharedTokens: ${import_chalk2.default.bold(String(patternDetectConfig.minSharedTokens))}`
|
|
463
|
+
);
|
|
464
|
+
if (patternDetectConfig.maxCandidatesPerBlock !== void 0)
|
|
465
|
+
console.log(
|
|
466
|
+
` maxCandidatesPerBlock: ${import_chalk2.default.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`
|
|
467
|
+
);
|
|
468
|
+
if (patternDetectConfig.batchSize !== void 0)
|
|
469
|
+
console.log(
|
|
470
|
+
` batchSize: ${import_chalk2.default.bold(String(patternDetectConfig.batchSize))}`
|
|
471
|
+
);
|
|
472
|
+
if (patternDetectConfig.streamResults !== void 0)
|
|
473
|
+
console.log(
|
|
474
|
+
` streamResults: ${import_chalk2.default.bold(String(patternDetectConfig.streamResults))}`
|
|
475
|
+
);
|
|
476
|
+
if (patternDetectConfig.severity !== void 0)
|
|
477
|
+
console.log(
|
|
478
|
+
` severity: ${import_chalk2.default.bold(String(patternDetectConfig.severity))}`
|
|
479
|
+
);
|
|
480
|
+
if (patternDetectConfig.includeTests !== void 0)
|
|
481
|
+
console.log(
|
|
482
|
+
` includeTests: ${import_chalk2.default.bold(String(patternDetectConfig.includeTests))}`
|
|
483
|
+
);
|
|
389
484
|
}
|
|
390
485
|
if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
|
|
391
486
|
const ca = finalOptions["context-analyzer"] || {
|
|
@@ -397,20 +492,42 @@ async function scanAction(directory, options) {
|
|
|
397
492
|
};
|
|
398
493
|
console.log(import_chalk2.default.white("\nContext-analyzer settings:"));
|
|
399
494
|
console.log(` maxDepth: ${import_chalk2.default.bold(ca.maxDepth ?? "default")}`);
|
|
400
|
-
console.log(
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (ca.
|
|
495
|
+
console.log(
|
|
496
|
+
` maxContextBudget: ${import_chalk2.default.bold(ca.maxContextBudget ?? "default")}`
|
|
497
|
+
);
|
|
498
|
+
if (ca.minCohesion !== void 0)
|
|
499
|
+
console.log(` minCohesion: ${import_chalk2.default.bold(String(ca.minCohesion))}`);
|
|
500
|
+
if (ca.maxFragmentation !== void 0)
|
|
501
|
+
console.log(
|
|
502
|
+
` maxFragmentation: ${import_chalk2.default.bold(String(ca.maxFragmentation))}`
|
|
503
|
+
);
|
|
504
|
+
if (ca.includeNodeModules !== void 0)
|
|
505
|
+
console.log(
|
|
506
|
+
` includeNodeModules: ${import_chalk2.default.bold(String(ca.includeNodeModules))}`
|
|
507
|
+
);
|
|
404
508
|
}
|
|
405
509
|
if (finalOptions.consistency) {
|
|
406
510
|
const c = finalOptions.consistency;
|
|
407
511
|
console.log(import_chalk2.default.white("\nConsistency settings:"));
|
|
408
|
-
console.log(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
512
|
+
console.log(
|
|
513
|
+
` checkNaming: ${import_chalk2.default.bold(String(c.checkNaming ?? true))}`
|
|
514
|
+
);
|
|
515
|
+
console.log(
|
|
516
|
+
` checkPatterns: ${import_chalk2.default.bold(String(c.checkPatterns ?? true))}`
|
|
517
|
+
);
|
|
518
|
+
console.log(
|
|
519
|
+
` checkArchitecture: ${import_chalk2.default.bold(String(c.checkArchitecture ?? false))}`
|
|
520
|
+
);
|
|
521
|
+
if (c.minSeverity)
|
|
522
|
+
console.log(` minSeverity: ${import_chalk2.default.bold(c.minSeverity)}`);
|
|
523
|
+
if (c.acceptedAbbreviations)
|
|
524
|
+
console.log(
|
|
525
|
+
` acceptedAbbreviations: ${import_chalk2.default.bold(truncateArray(c.acceptedAbbreviations, 8))}`
|
|
526
|
+
);
|
|
527
|
+
if (c.shortWords)
|
|
528
|
+
console.log(
|
|
529
|
+
` shortWords: ${import_chalk2.default.bold(truncateArray(c.shortWords, 8))}`
|
|
530
|
+
);
|
|
414
531
|
}
|
|
415
532
|
console.log(import_chalk2.default.white("\nStarting analysis..."));
|
|
416
533
|
const progressCallback = (event) => {
|
|
@@ -419,40 +536,62 @@ async function scanAction(directory, options) {
|
|
|
419
536
|
try {
|
|
420
537
|
if (event.tool === "patterns") {
|
|
421
538
|
const pr = event.data;
|
|
422
|
-
console.log(
|
|
423
|
-
|
|
539
|
+
console.log(
|
|
540
|
+
` Duplicate patterns: ${import_chalk2.default.bold(String(pr.duplicates?.length || 0))}`
|
|
541
|
+
);
|
|
542
|
+
console.log(
|
|
543
|
+
` Files with pattern issues: ${import_chalk2.default.bold(String(pr.results?.length || 0))}`
|
|
544
|
+
);
|
|
424
545
|
if (pr.duplicates && pr.duplicates.length > 0) {
|
|
425
546
|
pr.duplicates.slice(0, 5).forEach((d, i) => {
|
|
426
|
-
console.log(
|
|
547
|
+
console.log(
|
|
548
|
+
` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`
|
|
549
|
+
);
|
|
427
550
|
});
|
|
428
551
|
}
|
|
429
552
|
if (pr.results && pr.results.length > 0) {
|
|
430
553
|
console.log(` Top files with pattern issues:`);
|
|
431
|
-
const sortedByIssues = [...pr.results].sort(
|
|
554
|
+
const sortedByIssues = [...pr.results].sort(
|
|
555
|
+
(a, b) => (b.issues?.length || 0) - (a.issues?.length || 0)
|
|
556
|
+
);
|
|
432
557
|
sortedByIssues.slice(0, 5).forEach((r, i) => {
|
|
433
|
-
console.log(
|
|
558
|
+
console.log(
|
|
559
|
+
` ${i + 1}. ${r.fileName.split("/").pop()} - ${r.issues.length} issue(s)`
|
|
560
|
+
);
|
|
434
561
|
});
|
|
435
562
|
}
|
|
436
563
|
if (pr.groups && pr.groups.length >= 0) {
|
|
437
|
-
console.log(
|
|
564
|
+
console.log(
|
|
565
|
+
` \u2705 Grouped ${import_chalk2.default.bold(String(pr.duplicates?.length || 0))} duplicates into ${import_chalk2.default.bold(String(pr.groups.length))} file pairs`
|
|
566
|
+
);
|
|
438
567
|
}
|
|
439
568
|
if (pr.clusters && pr.clusters.length >= 0) {
|
|
440
|
-
console.log(
|
|
569
|
+
console.log(
|
|
570
|
+
` \u2705 Created ${import_chalk2.default.bold(String(pr.clusters.length))} refactor clusters`
|
|
571
|
+
);
|
|
441
572
|
pr.clusters.slice(0, 3).forEach((cl, idx) => {
|
|
442
573
|
const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
|
|
443
|
-
console.log(
|
|
574
|
+
console.log(
|
|
575
|
+
` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`
|
|
576
|
+
);
|
|
444
577
|
});
|
|
445
578
|
}
|
|
446
579
|
} else if (event.tool === "context") {
|
|
447
580
|
const cr = event.data;
|
|
448
|
-
console.log(
|
|
581
|
+
console.log(
|
|
582
|
+
` Context issues found: ${import_chalk2.default.bold(String(cr.length || 0))}`
|
|
583
|
+
);
|
|
449
584
|
cr.slice(0, 5).forEach((c, i) => {
|
|
450
585
|
const msg = c.message ? ` - ${c.message}` : "";
|
|
451
|
-
console.log(
|
|
586
|
+
console.log(
|
|
587
|
+
` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`
|
|
588
|
+
);
|
|
452
589
|
});
|
|
453
590
|
} else if (event.tool === "consistency") {
|
|
454
591
|
const rep = event.data;
|
|
455
|
-
console.log(
|
|
592
|
+
console.log(
|
|
593
|
+
` Consistency totalIssues: ${import_chalk2.default.bold(String(rep.summary?.totalIssues || 0))}`
|
|
594
|
+
);
|
|
456
595
|
if (rep.results && rep.results.length > 0) {
|
|
457
596
|
const fileMap = /* @__PURE__ */ new Map();
|
|
458
597
|
rep.results.forEach((r) => {
|
|
@@ -462,68 +601,134 @@ async function scanAction(directory, options) {
|
|
|
462
601
|
fileMap.get(file).push(issue);
|
|
463
602
|
});
|
|
464
603
|
});
|
|
465
|
-
const files = Array.from(fileMap.entries()).sort(
|
|
604
|
+
const files = Array.from(fileMap.entries()).sort(
|
|
605
|
+
(a, b) => b[1].length - a[1].length
|
|
606
|
+
);
|
|
466
607
|
const topFiles = files.slice(0, 10);
|
|
467
608
|
topFiles.forEach(([file, issues], idx) => {
|
|
468
|
-
const counts = issues.reduce(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
609
|
+
const counts = issues.reduce(
|
|
610
|
+
(acc, it) => {
|
|
611
|
+
const s = (it.severity || "info").toLowerCase();
|
|
612
|
+
acc[s] = (acc[s] || 0) + 1;
|
|
613
|
+
return acc;
|
|
614
|
+
},
|
|
615
|
+
{}
|
|
616
|
+
);
|
|
617
|
+
const sample = issues.find(
|
|
618
|
+
(it) => it.severity === "critical" || it.severity === "major"
|
|
619
|
+
) || issues[0];
|
|
474
620
|
const sampleMsg = sample ? ` \u2014 ${sample.message}` : "";
|
|
475
|
-
console.log(
|
|
621
|
+
console.log(
|
|
622
|
+
` ${idx + 1}. ${file} \u2014 ${issues.length} issue(s) (critical:${counts.critical || 0} major:${counts.major || 0} minor:${counts.minor || 0} info:${counts.info || 0})${sampleMsg}`
|
|
623
|
+
);
|
|
476
624
|
});
|
|
477
625
|
const remaining = files.length - topFiles.length;
|
|
478
626
|
if (remaining > 0) {
|
|
479
|
-
console.log(
|
|
627
|
+
console.log(
|
|
628
|
+
import_chalk2.default.dim(
|
|
629
|
+
` ... and ${remaining} more files with issues (use --output json for full details)`
|
|
630
|
+
)
|
|
631
|
+
);
|
|
480
632
|
}
|
|
481
633
|
}
|
|
482
634
|
} else if (event.tool === "doc-drift") {
|
|
483
635
|
const dr = event.data;
|
|
484
|
-
console.log(
|
|
636
|
+
console.log(
|
|
637
|
+
` Issues found: ${import_chalk2.default.bold(String(dr.issues?.length || 0))}`
|
|
638
|
+
);
|
|
485
639
|
if (dr.rawData) {
|
|
486
|
-
console.log(
|
|
487
|
-
|
|
640
|
+
console.log(
|
|
641
|
+
` Signature Mismatches: ${import_chalk2.default.bold(dr.rawData.outdatedComments || 0)}`
|
|
642
|
+
);
|
|
643
|
+
console.log(
|
|
644
|
+
` Undocumented Complexity: ${import_chalk2.default.bold(dr.rawData.undocumentedComplexity || 0)}`
|
|
645
|
+
);
|
|
488
646
|
}
|
|
489
647
|
} else if (event.tool === "deps-health") {
|
|
490
648
|
const dr = event.data;
|
|
491
|
-
console.log(
|
|
649
|
+
console.log(
|
|
650
|
+
` Packages Analyzed: ${import_chalk2.default.bold(String(dr.summary?.packagesAnalyzed || 0))}`
|
|
651
|
+
);
|
|
492
652
|
if (dr.rawData) {
|
|
493
|
-
console.log(
|
|
494
|
-
|
|
653
|
+
console.log(
|
|
654
|
+
` Deprecated Packages: ${import_chalk2.default.bold(dr.rawData.deprecatedPackages || 0)}`
|
|
655
|
+
);
|
|
656
|
+
console.log(
|
|
657
|
+
` AI Cutoff Skew Score: ${import_chalk2.default.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`
|
|
658
|
+
);
|
|
495
659
|
}
|
|
496
660
|
} else if (event.tool === "change-amplification" || event.tool === "changeAmplification") {
|
|
497
661
|
const dr = event.data;
|
|
498
|
-
console.log(
|
|
662
|
+
console.log(
|
|
663
|
+
` Coupling issues: ${import_chalk2.default.bold(String(dr.issues?.length || 0))}`
|
|
664
|
+
);
|
|
499
665
|
if (dr.summary) {
|
|
500
|
-
console.log(
|
|
666
|
+
console.log(
|
|
667
|
+
` Complexity Score: ${import_chalk2.default.bold(dr.summary.score || 0)}/100`
|
|
668
|
+
);
|
|
501
669
|
}
|
|
502
670
|
}
|
|
503
671
|
} catch (err) {
|
|
672
|
+
void err;
|
|
504
673
|
}
|
|
505
674
|
};
|
|
506
|
-
const results = await analyzeUnified({
|
|
675
|
+
const results = await analyzeUnified({
|
|
676
|
+
...finalOptions,
|
|
677
|
+
progressCallback,
|
|
678
|
+
onProgress: (processed, total, message) => {
|
|
679
|
+
process.stdout.write(
|
|
680
|
+
`\r\x1B[K [${processed}/${total}] ${message}...`
|
|
681
|
+
);
|
|
682
|
+
if (processed === total) {
|
|
683
|
+
process.stdout.write("\n");
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
suppressToolConfig: true
|
|
687
|
+
});
|
|
507
688
|
console.log(import_chalk2.default.cyan("\n=== AIReady Run Summary ==="));
|
|
508
|
-
console.log(
|
|
689
|
+
console.log(
|
|
690
|
+
import_chalk2.default.white("Tools run:"),
|
|
691
|
+
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
692
|
+
);
|
|
509
693
|
console.log(import_chalk2.default.cyan("\nResults summary:"));
|
|
510
|
-
console.log(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if (results.
|
|
514
|
-
|
|
515
|
-
|
|
694
|
+
console.log(
|
|
695
|
+
` Total issues (all tools): ${import_chalk2.default.bold(String(results.summary.totalIssues || 0))}`
|
|
696
|
+
);
|
|
697
|
+
if (results.duplicates)
|
|
698
|
+
console.log(
|
|
699
|
+
` Duplicate patterns found: ${import_chalk2.default.bold(String(results.duplicates.length || 0))}`
|
|
700
|
+
);
|
|
701
|
+
if (results.patterns)
|
|
702
|
+
console.log(
|
|
703
|
+
` Pattern files with issues: ${import_chalk2.default.bold(String(results.patterns.length || 0))}`
|
|
704
|
+
);
|
|
705
|
+
if (results.context)
|
|
706
|
+
console.log(
|
|
707
|
+
` Context issues: ${import_chalk2.default.bold(String(results.context.length || 0))}`
|
|
708
|
+
);
|
|
709
|
+
console.log(
|
|
710
|
+
` Consistency issues: ${import_chalk2.default.bold(String(results.consistency?.summary?.totalIssues || 0))}`
|
|
711
|
+
);
|
|
712
|
+
if (results.changeAmplification)
|
|
713
|
+
console.log(
|
|
714
|
+
` Change amplification: ${import_chalk2.default.bold(String(results.changeAmplification.summary?.score || 0))}/100`
|
|
715
|
+
);
|
|
516
716
|
console.log(import_chalk2.default.cyan("===========================\n"));
|
|
517
717
|
const elapsedTime = (0, import_core.getElapsedTime)(startTime);
|
|
718
|
+
void elapsedTime;
|
|
518
719
|
let scoringResult;
|
|
519
720
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
520
721
|
const toolScores = /* @__PURE__ */ new Map();
|
|
521
722
|
if (results.duplicates) {
|
|
522
723
|
const { calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
523
724
|
try {
|
|
524
|
-
const patternScore = calculatePatternScore(
|
|
725
|
+
const patternScore = calculatePatternScore(
|
|
726
|
+
results.duplicates,
|
|
727
|
+
results.patterns?.length || 0
|
|
728
|
+
);
|
|
525
729
|
toolScores.set("pattern-detect", patternScore);
|
|
526
730
|
} catch (err) {
|
|
731
|
+
void err;
|
|
527
732
|
}
|
|
528
733
|
}
|
|
529
734
|
if (results.context) {
|
|
@@ -533,6 +738,7 @@ async function scanAction(directory, options) {
|
|
|
533
738
|
const contextScore = calculateContextScore(ctxSummary);
|
|
534
739
|
toolScores.set("context-analyzer", contextScore);
|
|
535
740
|
} catch (err) {
|
|
741
|
+
void err;
|
|
536
742
|
}
|
|
537
743
|
}
|
|
538
744
|
if (results.consistency) {
|
|
@@ -540,17 +746,24 @@ async function scanAction(directory, options) {
|
|
|
540
746
|
try {
|
|
541
747
|
const issues = results.consistency.results?.flatMap((r) => r.issues) || [];
|
|
542
748
|
const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
|
|
543
|
-
const consistencyScore = calculateConsistencyScore(
|
|
749
|
+
const consistencyScore = calculateConsistencyScore(
|
|
750
|
+
issues,
|
|
751
|
+
totalFiles
|
|
752
|
+
);
|
|
544
753
|
toolScores.set("consistency", consistencyScore);
|
|
545
754
|
} catch (err) {
|
|
755
|
+
void err;
|
|
546
756
|
}
|
|
547
757
|
}
|
|
548
758
|
if (results.aiSignalClarity) {
|
|
549
759
|
const { calculateAiSignalClarityScore } = await import("@aiready/ai-signal-clarity");
|
|
550
760
|
try {
|
|
551
|
-
const hrScore = calculateAiSignalClarityScore(
|
|
761
|
+
const hrScore = calculateAiSignalClarityScore(
|
|
762
|
+
results.aiSignalClarity
|
|
763
|
+
);
|
|
552
764
|
toolScores.set("ai-signal-clarity", hrScore);
|
|
553
765
|
} catch (err) {
|
|
766
|
+
void err;
|
|
554
767
|
}
|
|
555
768
|
}
|
|
556
769
|
if (results.grounding) {
|
|
@@ -559,6 +772,7 @@ async function scanAction(directory, options) {
|
|
|
559
772
|
const agScore = calculateGroundingScore(results.grounding);
|
|
560
773
|
toolScores.set("agent-grounding", agScore);
|
|
561
774
|
} catch (err) {
|
|
775
|
+
void err;
|
|
562
776
|
}
|
|
563
777
|
}
|
|
564
778
|
if (results.testability) {
|
|
@@ -567,6 +781,7 @@ async function scanAction(directory, options) {
|
|
|
567
781
|
const tbScore = calculateTestabilityScore(results.testability);
|
|
568
782
|
toolScores.set("testability", tbScore);
|
|
569
783
|
} catch (err) {
|
|
784
|
+
void err;
|
|
570
785
|
}
|
|
571
786
|
}
|
|
572
787
|
if (results.docDrift) {
|
|
@@ -575,7 +790,13 @@ async function scanAction(directory, options) {
|
|
|
575
790
|
score: results.docDrift.summary.score,
|
|
576
791
|
rawMetrics: results.docDrift.rawData,
|
|
577
792
|
factors: [],
|
|
578
|
-
recommendations: (results.docDrift.recommendations || []).map(
|
|
793
|
+
recommendations: (results.docDrift.recommendations || []).map(
|
|
794
|
+
(action) => ({
|
|
795
|
+
action,
|
|
796
|
+
estimatedImpact: 5,
|
|
797
|
+
priority: "medium"
|
|
798
|
+
})
|
|
799
|
+
)
|
|
579
800
|
});
|
|
580
801
|
}
|
|
581
802
|
if (results.deps) {
|
|
@@ -584,7 +805,13 @@ async function scanAction(directory, options) {
|
|
|
584
805
|
score: results.deps.summary.score,
|
|
585
806
|
rawMetrics: results.deps.rawData,
|
|
586
807
|
factors: [],
|
|
587
|
-
recommendations: (results.deps.recommendations || []).map(
|
|
808
|
+
recommendations: (results.deps.recommendations || []).map(
|
|
809
|
+
(action) => ({
|
|
810
|
+
action,
|
|
811
|
+
estimatedImpact: 5,
|
|
812
|
+
priority: "medium"
|
|
813
|
+
})
|
|
814
|
+
)
|
|
588
815
|
});
|
|
589
816
|
}
|
|
590
817
|
if (results.changeAmplification) {
|
|
@@ -593,17 +820,28 @@ async function scanAction(directory, options) {
|
|
|
593
820
|
score: results.changeAmplification.summary.score,
|
|
594
821
|
rawMetrics: results.changeAmplification.rawData,
|
|
595
822
|
factors: [],
|
|
596
|
-
recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
|
|
823
|
+
recommendations: (results.changeAmplification.recommendations || []).map((action) => ({
|
|
824
|
+
action,
|
|
825
|
+
estimatedImpact: 5,
|
|
826
|
+
priority: "medium"
|
|
827
|
+
}))
|
|
597
828
|
});
|
|
598
829
|
}
|
|
599
830
|
const cliWeights = (0, import_core.parseWeightString)(options.weights);
|
|
600
831
|
if (toolScores.size > 0) {
|
|
601
|
-
scoringResult = (0, import_core.calculateOverallScore)(
|
|
832
|
+
scoringResult = (0, import_core.calculateOverallScore)(
|
|
833
|
+
toolScores,
|
|
834
|
+
finalOptions,
|
|
835
|
+
cliWeights.size ? cliWeights : void 0
|
|
836
|
+
);
|
|
602
837
|
console.log(import_chalk2.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
603
838
|
console.log(` ${(0, import_core.formatScore)(scoringResult)}`);
|
|
604
839
|
if (options.compareTo) {
|
|
605
840
|
try {
|
|
606
|
-
const prevReportStr = (0, import_fs2.readFileSync)(
|
|
841
|
+
const prevReportStr = (0, import_fs2.readFileSync)(
|
|
842
|
+
(0, import_path2.resolve)(process.cwd(), options.compareTo),
|
|
843
|
+
"utf8"
|
|
844
|
+
);
|
|
607
845
|
const prevReport = JSON.parse(prevReportStr);
|
|
608
846
|
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
609
847
|
if (typeof prevScore === "number") {
|
|
@@ -611,23 +849,44 @@ async function scanAction(directory, options) {
|
|
|
611
849
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
612
850
|
console.log();
|
|
613
851
|
if (diff > 0) {
|
|
614
|
-
console.log(
|
|
852
|
+
console.log(
|
|
853
|
+
import_chalk2.default.green(
|
|
854
|
+
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
855
|
+
)
|
|
856
|
+
);
|
|
615
857
|
} else if (diff < 0) {
|
|
616
|
-
console.log(
|
|
858
|
+
console.log(
|
|
859
|
+
import_chalk2.default.red(
|
|
860
|
+
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
861
|
+
)
|
|
862
|
+
);
|
|
617
863
|
} else {
|
|
618
|
-
console.log(
|
|
864
|
+
console.log(
|
|
865
|
+
import_chalk2.default.blue(
|
|
866
|
+
` \u2796 Trend: No change compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
867
|
+
)
|
|
868
|
+
);
|
|
619
869
|
}
|
|
620
870
|
scoringResult.trend = {
|
|
621
871
|
previousScore: prevScore,
|
|
622
872
|
difference: diff
|
|
623
873
|
};
|
|
624
874
|
} else {
|
|
625
|
-
console.log(
|
|
626
|
-
|
|
875
|
+
console.log(
|
|
876
|
+
import_chalk2.default.yellow(
|
|
877
|
+
`
|
|
878
|
+
\u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
|
|
879
|
+
)
|
|
880
|
+
);
|
|
627
881
|
}
|
|
628
882
|
} catch (e) {
|
|
629
|
-
|
|
630
|
-
|
|
883
|
+
void e;
|
|
884
|
+
console.log(
|
|
885
|
+
import_chalk2.default.yellow(
|
|
886
|
+
`
|
|
887
|
+
\u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
|
|
888
|
+
)
|
|
889
|
+
);
|
|
631
890
|
}
|
|
632
891
|
}
|
|
633
892
|
if (scoringResult.breakdown && scoringResult.breakdown.length > 0) {
|
|
@@ -635,7 +894,9 @@ async function scanAction(directory, options) {
|
|
|
635
894
|
scoringResult.breakdown.forEach((tool) => {
|
|
636
895
|
const rating = (0, import_core.getRating)(tool.score);
|
|
637
896
|
const rd = (0, import_core.getRatingDisplay)(rating);
|
|
638
|
-
console.log(
|
|
897
|
+
console.log(
|
|
898
|
+
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
|
|
899
|
+
);
|
|
639
900
|
});
|
|
640
901
|
console.log();
|
|
641
902
|
if (finalOptions.scoring?.showBreakdown) {
|
|
@@ -653,20 +914,33 @@ async function scanAction(directory, options) {
|
|
|
653
914
|
if (outputFormat === "json") {
|
|
654
915
|
const timestamp = getReportTimestamp();
|
|
655
916
|
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
656
|
-
const outputPath = (0, import_core.resolveOutputPath)(
|
|
917
|
+
const outputPath = (0, import_core.resolveOutputPath)(
|
|
918
|
+
userOutputFile,
|
|
919
|
+
defaultFilename,
|
|
920
|
+
resolvedDir
|
|
921
|
+
);
|
|
657
922
|
const outputData = { ...results, scoring: scoringResult };
|
|
658
|
-
(0, import_core.handleJSONOutput)(
|
|
659
|
-
|
|
923
|
+
(0, import_core.handleJSONOutput)(
|
|
924
|
+
outputData,
|
|
925
|
+
outputPath,
|
|
926
|
+
`\u2705 Report saved to ${outputPath}`
|
|
927
|
+
);
|
|
928
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
660
929
|
} else {
|
|
661
930
|
const timestamp = getReportTimestamp();
|
|
662
931
|
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
663
|
-
const outputPath = (0, import_core.resolveOutputPath)(
|
|
932
|
+
const outputPath = (0, import_core.resolveOutputPath)(
|
|
933
|
+
userOutputFile,
|
|
934
|
+
defaultFilename,
|
|
935
|
+
resolvedDir
|
|
936
|
+
);
|
|
664
937
|
const outputData = { ...results, scoring: scoringResult };
|
|
665
938
|
try {
|
|
666
939
|
(0, import_fs2.writeFileSync)(outputPath, JSON.stringify(outputData, null, 2));
|
|
667
940
|
console.log(import_chalk2.default.dim(`\u2705 Report auto-persisted to ${outputPath}`));
|
|
668
|
-
warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
941
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
669
942
|
} catch (err) {
|
|
943
|
+
void err;
|
|
670
944
|
}
|
|
671
945
|
}
|
|
672
946
|
const isCI = options.ci || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
|
|
@@ -684,16 +958,22 @@ async function scanAction(directory, options) {
|
|
|
684
958
|
}
|
|
685
959
|
console.log("::endgroup::");
|
|
686
960
|
if (threshold && scoringResult.overall < threshold) {
|
|
687
|
-
console.log(
|
|
961
|
+
console.log(
|
|
962
|
+
`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`
|
|
963
|
+
);
|
|
688
964
|
} else if (threshold) {
|
|
689
|
-
console.log(
|
|
965
|
+
console.log(
|
|
966
|
+
`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
967
|
+
);
|
|
690
968
|
}
|
|
691
969
|
if (results.patterns) {
|
|
692
970
|
const criticalPatterns = results.patterns.flatMap(
|
|
693
971
|
(p) => p.issues.filter((i) => i.severity === "critical")
|
|
694
972
|
);
|
|
695
973
|
criticalPatterns.slice(0, 10).forEach((issue) => {
|
|
696
|
-
console.log(
|
|
974
|
+
console.log(
|
|
975
|
+
`::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`
|
|
976
|
+
);
|
|
697
977
|
});
|
|
698
978
|
}
|
|
699
979
|
}
|
|
@@ -742,16 +1022,30 @@ async function scanAction(directory, options) {
|
|
|
742
1022
|
console.log(import_chalk2.default.red("\n\u{1F6AB} PR BLOCKED: AI Readiness Check Failed"));
|
|
743
1023
|
console.log(import_chalk2.default.red(` Reason: ${failReason}`));
|
|
744
1024
|
console.log(import_chalk2.default.dim("\n Remediation steps:"));
|
|
745
|
-
console.log(
|
|
1025
|
+
console.log(
|
|
1026
|
+
import_chalk2.default.dim(" 1. Run `aiready scan` locally to see detailed issues")
|
|
1027
|
+
);
|
|
746
1028
|
console.log(import_chalk2.default.dim(" 2. Fix the critical issues before merging"));
|
|
747
|
-
console.log(
|
|
1029
|
+
console.log(
|
|
1030
|
+
import_chalk2.default.dim(
|
|
1031
|
+
" 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"
|
|
1032
|
+
)
|
|
1033
|
+
);
|
|
748
1034
|
process.exit(1);
|
|
749
1035
|
} else {
|
|
750
1036
|
console.log(import_chalk2.default.green("\n\u2705 PR PASSED: AI Readiness Check"));
|
|
751
1037
|
if (threshold) {
|
|
752
|
-
console.log(
|
|
1038
|
+
console.log(
|
|
1039
|
+
import_chalk2.default.green(
|
|
1040
|
+
` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
1041
|
+
)
|
|
1042
|
+
);
|
|
753
1043
|
}
|
|
754
|
-
console.log(
|
|
1044
|
+
console.log(
|
|
1045
|
+
import_chalk2.default.dim(
|
|
1046
|
+
"\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"
|
|
1047
|
+
)
|
|
1048
|
+
);
|
|
755
1049
|
}
|
|
756
1050
|
}
|
|
757
1051
|
} catch (error) {
|
|
@@ -823,7 +1117,11 @@ async function patternsAction(directory, options) {
|
|
|
823
1117
|
if (options.minSharedTokens) {
|
|
824
1118
|
cliOptions.minSharedTokens = parseInt(options.minSharedTokens);
|
|
825
1119
|
}
|
|
826
|
-
const finalOptions = await (0, import_core2.loadMergedConfig)(
|
|
1120
|
+
const finalOptions = await (0, import_core2.loadMergedConfig)(
|
|
1121
|
+
resolvedDir,
|
|
1122
|
+
defaults,
|
|
1123
|
+
cliOptions
|
|
1124
|
+
);
|
|
827
1125
|
const { analyzePatterns: analyzePatterns2, generateSummary, calculatePatternScore } = await import("@aiready/pattern-detect");
|
|
828
1126
|
const { results, duplicates } = await analyzePatterns2(finalOptions);
|
|
829
1127
|
const elapsedTime = (0, import_core2.getElapsedTime)(startTime);
|
|
@@ -845,7 +1143,11 @@ async function patternsAction(directory, options) {
|
|
|
845
1143
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
846
1144
|
resolvedDir
|
|
847
1145
|
);
|
|
848
|
-
(0, import_core2.handleJSONOutput)(
|
|
1146
|
+
(0, import_core2.handleJSONOutput)(
|
|
1147
|
+
outputData,
|
|
1148
|
+
outputPath,
|
|
1149
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1150
|
+
);
|
|
849
1151
|
} else {
|
|
850
1152
|
const terminalWidth = process.stdout.columns || 80;
|
|
851
1153
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
@@ -853,10 +1155,22 @@ async function patternsAction(directory, options) {
|
|
|
853
1155
|
console.log(import_chalk3.default.cyan(divider));
|
|
854
1156
|
console.log(import_chalk3.default.bold.white(" PATTERN ANALYSIS SUMMARY"));
|
|
855
1157
|
console.log(import_chalk3.default.cyan(divider) + "\n");
|
|
856
|
-
console.log(
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
console.log(
|
|
1158
|
+
console.log(
|
|
1159
|
+
import_chalk3.default.white(`\u{1F4C1} Files analyzed: ${import_chalk3.default.bold(results.length)}`)
|
|
1160
|
+
);
|
|
1161
|
+
console.log(
|
|
1162
|
+
import_chalk3.default.yellow(
|
|
1163
|
+
`\u26A0 Duplicate patterns found: ${import_chalk3.default.bold(summary.totalPatterns)}`
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
1166
|
+
console.log(
|
|
1167
|
+
import_chalk3.default.red(
|
|
1168
|
+
`\u{1F4B0} Token cost (wasted): ${import_chalk3.default.bold(summary.totalTokenCost.toLocaleString())}`
|
|
1169
|
+
)
|
|
1170
|
+
);
|
|
1171
|
+
console.log(
|
|
1172
|
+
import_chalk3.default.gray(`\u23F1 Analysis time: ${import_chalk3.default.bold(elapsedTime + "s")}`)
|
|
1173
|
+
);
|
|
860
1174
|
const sortedTypes = Object.entries(summary.patternsByType || {}).filter(([, count]) => count > 0).sort(([, a], [, b]) => b - a);
|
|
861
1175
|
if (sortedTypes.length > 0) {
|
|
862
1176
|
console.log(import_chalk3.default.cyan("\n" + divider));
|
|
@@ -876,13 +1190,21 @@ async function patternsAction(directory, options) {
|
|
|
876
1190
|
const severityIcon = dup.similarity > 0.95 ? "\u{1F534}" : dup.similarity > 0.9 ? "\u{1F7E1}" : "\u{1F535}";
|
|
877
1191
|
const file1Name = dup.file1.split("/").pop() || dup.file1;
|
|
878
1192
|
const file2Name = dup.file2.split("/").pop() || dup.file2;
|
|
879
|
-
console.log(
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1193
|
+
console.log(
|
|
1194
|
+
`${severityIcon} ${severity}: ${import_chalk3.default.bold(file1Name)} \u2194 ${import_chalk3.default.bold(file2Name)}`
|
|
1195
|
+
);
|
|
1196
|
+
console.log(
|
|
1197
|
+
` Similarity: ${import_chalk3.default.bold(Math.round(dup.similarity * 100) + "%")} | Wasted: ${import_chalk3.default.bold(dup.tokenCost.toLocaleString())} tokens each`
|
|
1198
|
+
);
|
|
1199
|
+
console.log(
|
|
1200
|
+
` Lines: ${import_chalk3.default.cyan(dup.line1 + "-" + dup.endLine1)} \u2194 ${import_chalk3.default.cyan(dup.line2 + "-" + dup.endLine2)}
|
|
1201
|
+
`
|
|
1202
|
+
);
|
|
883
1203
|
});
|
|
884
1204
|
} else {
|
|
885
|
-
console.log(
|
|
1205
|
+
console.log(
|
|
1206
|
+
import_chalk3.default.green("\n\u2728 Great! No duplicate patterns detected.\n")
|
|
1207
|
+
);
|
|
886
1208
|
}
|
|
887
1209
|
if (patternScore) {
|
|
888
1210
|
console.log(import_chalk3.default.cyan(divider));
|
|
@@ -922,7 +1244,7 @@ async function contextAction(directory, options) {
|
|
|
922
1244
|
file: void 0
|
|
923
1245
|
}
|
|
924
1246
|
};
|
|
925
|
-
|
|
1247
|
+
const baseOptions = await (0, import_core3.loadMergedConfig)(resolvedDir, defaults, {
|
|
926
1248
|
maxDepth: options.maxDepth ? parseInt(options.maxDepth) : void 0,
|
|
927
1249
|
maxContextBudget: options.maxContext ? parseInt(options.maxContext) : void 0,
|
|
928
1250
|
include: options.include?.split(","),
|
|
@@ -930,13 +1252,20 @@ async function contextAction(directory, options) {
|
|
|
930
1252
|
});
|
|
931
1253
|
let finalOptions = { ...baseOptions };
|
|
932
1254
|
const { getSmartDefaults } = await import("@aiready/context-analyzer");
|
|
933
|
-
const contextSmartDefaults = await getSmartDefaults(
|
|
1255
|
+
const contextSmartDefaults = await getSmartDefaults(
|
|
1256
|
+
resolvedDir,
|
|
1257
|
+
baseOptions
|
|
1258
|
+
);
|
|
934
1259
|
finalOptions = { ...contextSmartDefaults, ...finalOptions };
|
|
935
1260
|
console.log("\u{1F4CB} Configuration:");
|
|
936
1261
|
console.log(` Max depth: ${finalOptions.maxDepth}`);
|
|
937
1262
|
console.log(` Max context budget: ${finalOptions.maxContextBudget}`);
|
|
938
|
-
console.log(
|
|
939
|
-
|
|
1263
|
+
console.log(
|
|
1264
|
+
` Min cohesion: ${(finalOptions.minCohesion * 100).toFixed(1)}%`
|
|
1265
|
+
);
|
|
1266
|
+
console.log(
|
|
1267
|
+
` Max fragmentation: ${(finalOptions.maxFragmentation * 100).toFixed(1)}%`
|
|
1268
|
+
);
|
|
940
1269
|
console.log(` Analysis focus: ${finalOptions.focus}`);
|
|
941
1270
|
console.log("");
|
|
942
1271
|
const { analyzeContext: analyzeContext2, generateSummary, calculateContextScore } = await import("@aiready/context-analyzer");
|
|
@@ -960,7 +1289,11 @@ async function contextAction(directory, options) {
|
|
|
960
1289
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
961
1290
|
resolvedDir
|
|
962
1291
|
);
|
|
963
|
-
(0, import_core3.handleJSONOutput)(
|
|
1292
|
+
(0, import_core3.handleJSONOutput)(
|
|
1293
|
+
outputData,
|
|
1294
|
+
outputPath,
|
|
1295
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1296
|
+
);
|
|
964
1297
|
} else {
|
|
965
1298
|
const terminalWidth = process.stdout.columns || 80;
|
|
966
1299
|
const dividerWidth = Math.min(60, terminalWidth - 2);
|
|
@@ -968,59 +1301,103 @@ async function contextAction(directory, options) {
|
|
|
968
1301
|
console.log(import_chalk4.default.cyan(divider));
|
|
969
1302
|
console.log(import_chalk4.default.bold.white(" CONTEXT ANALYSIS SUMMARY"));
|
|
970
1303
|
console.log(import_chalk4.default.cyan(divider) + "\n");
|
|
971
|
-
console.log(
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
console.log(
|
|
975
|
-
|
|
1304
|
+
console.log(
|
|
1305
|
+
import_chalk4.default.white(`\u{1F4C1} Files analyzed: ${import_chalk4.default.bold(summary.totalFiles)}`)
|
|
1306
|
+
);
|
|
1307
|
+
console.log(
|
|
1308
|
+
import_chalk4.default.white(
|
|
1309
|
+
`\u{1F4CA} Total tokens: ${import_chalk4.default.bold(summary.totalTokens.toLocaleString())}`
|
|
1310
|
+
)
|
|
1311
|
+
);
|
|
1312
|
+
console.log(
|
|
1313
|
+
import_chalk4.default.yellow(
|
|
1314
|
+
`\u{1F4B0} Avg context budget: ${import_chalk4.default.bold(summary.avgContextBudget.toFixed(0))} tokens/file`
|
|
1315
|
+
)
|
|
1316
|
+
);
|
|
1317
|
+
console.log(
|
|
1318
|
+
import_chalk4.default.white(`\u23F1 Analysis time: ${import_chalk4.default.bold(elapsedTime + "s")}
|
|
1319
|
+
`)
|
|
1320
|
+
);
|
|
976
1321
|
const totalIssues = summary.criticalIssues + summary.majorIssues + summary.minorIssues;
|
|
977
1322
|
if (totalIssues > 0) {
|
|
978
1323
|
console.log(import_chalk4.default.bold("\u26A0\uFE0F Issues Found:\n"));
|
|
979
1324
|
if (summary.criticalIssues > 0) {
|
|
980
|
-
console.log(
|
|
1325
|
+
console.log(
|
|
1326
|
+
import_chalk4.default.red(` \u{1F534} Critical: ${import_chalk4.default.bold(summary.criticalIssues)}`)
|
|
1327
|
+
);
|
|
981
1328
|
}
|
|
982
1329
|
if (summary.majorIssues > 0) {
|
|
983
|
-
console.log(
|
|
1330
|
+
console.log(
|
|
1331
|
+
import_chalk4.default.yellow(` \u{1F7E1} Major: ${import_chalk4.default.bold(summary.majorIssues)}`)
|
|
1332
|
+
);
|
|
984
1333
|
}
|
|
985
1334
|
if (summary.minorIssues > 0) {
|
|
986
|
-
console.log(
|
|
1335
|
+
console.log(
|
|
1336
|
+
import_chalk4.default.blue(` \u{1F535} Minor: ${import_chalk4.default.bold(summary.minorIssues)}`)
|
|
1337
|
+
);
|
|
987
1338
|
}
|
|
988
|
-
console.log(
|
|
1339
|
+
console.log(
|
|
1340
|
+
import_chalk4.default.green(
|
|
1341
|
+
`
|
|
989
1342
|
\u{1F4A1} Potential savings: ${import_chalk4.default.bold(summary.totalPotentialSavings.toLocaleString())} tokens
|
|
990
|
-
`
|
|
1343
|
+
`
|
|
1344
|
+
)
|
|
1345
|
+
);
|
|
991
1346
|
} else {
|
|
992
1347
|
console.log(import_chalk4.default.green("\u2705 No significant issues found!\n"));
|
|
993
1348
|
}
|
|
994
1349
|
if (summary.deepFiles.length > 0) {
|
|
995
1350
|
console.log(import_chalk4.default.bold("\u{1F4CF} Deep Import Chains:\n"));
|
|
996
|
-
console.log(
|
|
997
|
-
|
|
998
|
-
|
|
1351
|
+
console.log(
|
|
1352
|
+
import_chalk4.default.gray(` Average depth: ${summary.avgImportDepth.toFixed(1)}`)
|
|
1353
|
+
);
|
|
1354
|
+
console.log(
|
|
1355
|
+
import_chalk4.default.gray(` Maximum depth: ${summary.maxImportDepth}
|
|
1356
|
+
`)
|
|
1357
|
+
);
|
|
999
1358
|
summary.deepFiles.slice(0, 10).forEach((item) => {
|
|
1000
1359
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1001
|
-
console.log(
|
|
1360
|
+
console.log(
|
|
1361
|
+
` ${import_chalk4.default.cyan("\u2192")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(depth: ${item.depth})`)}`
|
|
1362
|
+
);
|
|
1002
1363
|
});
|
|
1003
1364
|
console.log();
|
|
1004
1365
|
}
|
|
1005
1366
|
if (summary.fragmentedModules.length > 0) {
|
|
1006
1367
|
console.log(import_chalk4.default.bold("\u{1F9E9} Fragmented Modules:\n"));
|
|
1007
|
-
console.log(
|
|
1008
|
-
|
|
1368
|
+
console.log(
|
|
1369
|
+
import_chalk4.default.gray(
|
|
1370
|
+
` Average fragmentation: ${(summary.avgFragmentation * 100).toFixed(0)}%
|
|
1371
|
+
`
|
|
1372
|
+
)
|
|
1373
|
+
);
|
|
1009
1374
|
summary.fragmentedModules.slice(0, 10).forEach((module2) => {
|
|
1010
|
-
console.log(
|
|
1011
|
-
|
|
1375
|
+
console.log(
|
|
1376
|
+
` ${import_chalk4.default.yellow("\u25CF")} ${import_chalk4.default.white(module2.domain)} - ${import_chalk4.default.dim(`${module2.files.length} files, ${(module2.fragmentationScore * 100).toFixed(0)}% scattered`)}`
|
|
1377
|
+
);
|
|
1378
|
+
console.log(
|
|
1379
|
+
import_chalk4.default.dim(
|
|
1380
|
+
` Token cost: ${module2.totalTokens.toLocaleString()}, Cohesion: ${(module2.avgCohesion * 100).toFixed(0)}%`
|
|
1381
|
+
)
|
|
1382
|
+
);
|
|
1012
1383
|
});
|
|
1013
1384
|
console.log();
|
|
1014
1385
|
}
|
|
1015
1386
|
if (summary.lowCohesionFiles.length > 0) {
|
|
1016
1387
|
console.log(import_chalk4.default.bold("\u{1F500} Low Cohesion Files:\n"));
|
|
1017
|
-
console.log(
|
|
1018
|
-
|
|
1388
|
+
console.log(
|
|
1389
|
+
import_chalk4.default.gray(
|
|
1390
|
+
` Average cohesion: ${(summary.avgCohesion * 100).toFixed(0)}%
|
|
1391
|
+
`
|
|
1392
|
+
)
|
|
1393
|
+
);
|
|
1019
1394
|
summary.lowCohesionFiles.slice(0, 10).forEach((item) => {
|
|
1020
1395
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1021
1396
|
const scorePercent = (item.score * 100).toFixed(0);
|
|
1022
1397
|
const color = item.score < 0.4 ? import_chalk4.default.red : import_chalk4.default.yellow;
|
|
1023
|
-
console.log(
|
|
1398
|
+
console.log(
|
|
1399
|
+
` ${color("\u25CB")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(${scorePercent}% cohesion)`)}`
|
|
1400
|
+
);
|
|
1024
1401
|
});
|
|
1025
1402
|
console.log();
|
|
1026
1403
|
}
|
|
@@ -1029,7 +1406,9 @@ async function contextAction(directory, options) {
|
|
|
1029
1406
|
summary.topExpensiveFiles.slice(0, 10).forEach((item) => {
|
|
1030
1407
|
const fileName = item.file.split("/").slice(-2).join("/");
|
|
1031
1408
|
const severityColor = item.severity === "critical" ? import_chalk4.default.red : item.severity === "major" ? import_chalk4.default.yellow : import_chalk4.default.blue;
|
|
1032
|
-
console.log(
|
|
1409
|
+
console.log(
|
|
1410
|
+
` ${severityColor("\u25CF")} ${import_chalk4.default.white(fileName)} ${import_chalk4.default.dim(`(${item.contextBudget.toLocaleString()} tokens)`)}`
|
|
1411
|
+
);
|
|
1033
1412
|
});
|
|
1034
1413
|
console.log();
|
|
1035
1414
|
}
|
|
@@ -1080,7 +1459,10 @@ async function consistencyAction(directory, options) {
|
|
|
1080
1459
|
let consistencyScore;
|
|
1081
1460
|
if (options.score) {
|
|
1082
1461
|
const issues = report.results?.flatMap((r) => r.issues) || [];
|
|
1083
|
-
consistencyScore = calculateConsistencyScore(
|
|
1462
|
+
consistencyScore = calculateConsistencyScore(
|
|
1463
|
+
issues,
|
|
1464
|
+
report.summary.filesAnalyzed
|
|
1465
|
+
);
|
|
1084
1466
|
}
|
|
1085
1467
|
const outputFormat = options.output || finalOptions.output?.format || "console";
|
|
1086
1468
|
const userOutputFile = options.outputFile || finalOptions.output?.file;
|
|
@@ -1098,7 +1480,11 @@ async function consistencyAction(directory, options) {
|
|
|
1098
1480
|
`aiready-report-${getReportTimestamp()}.json`,
|
|
1099
1481
|
resolvedDir
|
|
1100
1482
|
);
|
|
1101
|
-
(0, import_core4.handleJSONOutput)(
|
|
1483
|
+
(0, import_core4.handleJSONOutput)(
|
|
1484
|
+
outputData,
|
|
1485
|
+
outputPath,
|
|
1486
|
+
`\u2705 Results saved to ${outputPath}`
|
|
1487
|
+
);
|
|
1102
1488
|
} else if (outputFormat === "markdown") {
|
|
1103
1489
|
const markdown = generateMarkdownReport(report, elapsedTime);
|
|
1104
1490
|
const outputPath = (0, import_core4.resolveOutputPath)(
|
|
@@ -1110,15 +1496,23 @@ async function consistencyAction(directory, options) {
|
|
|
1110
1496
|
console.log(import_chalk5.default.green(`\u2705 Report saved to ${outputPath}`));
|
|
1111
1497
|
} else {
|
|
1112
1498
|
console.log(import_chalk5.default.bold("\n\u{1F4CA} Summary\n"));
|
|
1113
|
-
console.log(
|
|
1499
|
+
console.log(
|
|
1500
|
+
`Files Analyzed: ${import_chalk5.default.cyan(report.summary.filesAnalyzed)}`
|
|
1501
|
+
);
|
|
1114
1502
|
console.log(`Total Issues: ${import_chalk5.default.yellow(report.summary.totalIssues)}`);
|
|
1115
1503
|
console.log(` Naming: ${import_chalk5.default.yellow(report.summary.namingIssues)}`);
|
|
1116
1504
|
console.log(` Patterns: ${import_chalk5.default.yellow(report.summary.patternIssues)}`);
|
|
1117
|
-
console.log(
|
|
1505
|
+
console.log(
|
|
1506
|
+
` Architecture: ${import_chalk5.default.yellow(report.summary.architectureIssues || 0)}`
|
|
1507
|
+
);
|
|
1118
1508
|
console.log(`Analysis Time: ${import_chalk5.default.gray(elapsedTime + "s")}
|
|
1119
1509
|
`);
|
|
1120
1510
|
if (report.summary.totalIssues === 0) {
|
|
1121
|
-
console.log(
|
|
1511
|
+
console.log(
|
|
1512
|
+
import_chalk5.default.green(
|
|
1513
|
+
"\u2728 No consistency issues found! Your codebase is well-maintained.\n"
|
|
1514
|
+
)
|
|
1515
|
+
);
|
|
1122
1516
|
} else {
|
|
1123
1517
|
const namingResults = report.results.filter(
|
|
1124
1518
|
(r) => r.issues.some((i) => i.category === "naming")
|
|
@@ -1134,10 +1528,14 @@ async function consistencyAction(directory, options) {
|
|
|
1134
1528
|
for (const issue of result.issues) {
|
|
1135
1529
|
if (shown >= 5) break;
|
|
1136
1530
|
const severityColor = issue.severity === "critical" ? import_chalk5.default.red : issue.severity === "major" ? import_chalk5.default.yellow : issue.severity === "minor" ? import_chalk5.default.blue : import_chalk5.default.gray;
|
|
1137
|
-
console.log(
|
|
1531
|
+
console.log(
|
|
1532
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk5.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1533
|
+
);
|
|
1138
1534
|
console.log(` ${issue.message}`);
|
|
1139
1535
|
if (issue.suggestion) {
|
|
1140
|
-
console.log(
|
|
1536
|
+
console.log(
|
|
1537
|
+
` ${import_chalk5.default.dim("\u2192")} ${import_chalk5.default.italic(issue.suggestion)}`
|
|
1538
|
+
);
|
|
1141
1539
|
}
|
|
1142
1540
|
console.log();
|
|
1143
1541
|
shown++;
|
|
@@ -1157,10 +1555,14 @@ async function consistencyAction(directory, options) {
|
|
|
1157
1555
|
for (const issue of result.issues) {
|
|
1158
1556
|
if (shown >= 5) break;
|
|
1159
1557
|
const severityColor = issue.severity === "critical" ? import_chalk5.default.red : issue.severity === "major" ? import_chalk5.default.yellow : issue.severity === "minor" ? import_chalk5.default.blue : import_chalk5.default.gray;
|
|
1160
|
-
console.log(
|
|
1558
|
+
console.log(
|
|
1559
|
+
`${severityColor(issue.severity.toUpperCase())} ${import_chalk5.default.dim(`${issue.location.file}:${issue.location.line}`)}`
|
|
1560
|
+
);
|
|
1161
1561
|
console.log(` ${issue.message}`);
|
|
1162
1562
|
if (issue.suggestion) {
|
|
1163
|
-
console.log(
|
|
1563
|
+
console.log(
|
|
1564
|
+
` ${import_chalk5.default.dim("\u2192")} ${import_chalk5.default.italic(issue.suggestion)}`
|
|
1565
|
+
);
|
|
1164
1566
|
}
|
|
1165
1567
|
console.log();
|
|
1166
1568
|
shown++;
|
|
@@ -1206,15 +1608,21 @@ async function visualizeAction(directory, options) {
|
|
|
1206
1608
|
const latestScan = findLatestScanReport(dirPath);
|
|
1207
1609
|
if (latestScan) {
|
|
1208
1610
|
reportPath = latestScan;
|
|
1209
|
-
console.log(
|
|
1611
|
+
console.log(
|
|
1612
|
+
import_chalk6.default.dim(`Found latest report: ${latestScan.split("/").pop()}`)
|
|
1613
|
+
);
|
|
1210
1614
|
} else {
|
|
1211
1615
|
console.error(import_chalk6.default.red("\u274C No AI readiness report found"));
|
|
1212
|
-
console.log(
|
|
1616
|
+
console.log(
|
|
1617
|
+
import_chalk6.default.dim(
|
|
1618
|
+
`
|
|
1213
1619
|
Generate a report with:
|
|
1214
1620
|
aiready scan --output json
|
|
1215
1621
|
|
|
1216
1622
|
Or specify a custom report:
|
|
1217
|
-
aiready visualise --report <path-to-report.json>`
|
|
1623
|
+
aiready visualise --report <path-to-report.json>`
|
|
1624
|
+
)
|
|
1625
|
+
);
|
|
1218
1626
|
return;
|
|
1219
1627
|
}
|
|
1220
1628
|
}
|
|
@@ -1232,6 +1640,7 @@ Or specify a custom report:
|
|
|
1232
1640
|
};
|
|
1233
1641
|
}
|
|
1234
1642
|
} catch (e) {
|
|
1643
|
+
void e;
|
|
1235
1644
|
}
|
|
1236
1645
|
}
|
|
1237
1646
|
const envVisualizerConfig = JSON.stringify(graphConfig);
|
|
@@ -1252,11 +1661,18 @@ Or specify a custom report:
|
|
|
1252
1661
|
} else {
|
|
1253
1662
|
const nodemodulesLocations = [
|
|
1254
1663
|
(0, import_path6.resolve)(dirPath, "node_modules", "@aiready", "visualizer"),
|
|
1255
|
-
(0, import_path6.resolve)(
|
|
1664
|
+
(0, import_path6.resolve)(
|
|
1665
|
+
process.cwd(),
|
|
1666
|
+
"node_modules",
|
|
1667
|
+
"@aiready",
|
|
1668
|
+
"visualizer"
|
|
1669
|
+
)
|
|
1256
1670
|
];
|
|
1257
1671
|
let currentDir = dirPath;
|
|
1258
1672
|
while (currentDir !== "/" && currentDir !== ".") {
|
|
1259
|
-
nodemodulesLocations.push(
|
|
1673
|
+
nodemodulesLocations.push(
|
|
1674
|
+
(0, import_path6.resolve)(currentDir, "node_modules", "@aiready", "visualizer")
|
|
1675
|
+
);
|
|
1260
1676
|
const parent = (0, import_path6.resolve)(currentDir, "..");
|
|
1261
1677
|
if (parent === currentDir) break;
|
|
1262
1678
|
currentDir = parent;
|
|
@@ -1273,7 +1689,8 @@ Or specify a custom report:
|
|
|
1273
1689
|
const vizPkgPath = require.resolve("@aiready/visualizer/package.json");
|
|
1274
1690
|
webDir = (0, import_path6.resolve)(vizPkgPath, "..");
|
|
1275
1691
|
visualizerAvailable = true;
|
|
1276
|
-
} catch (
|
|
1692
|
+
} catch (err) {
|
|
1693
|
+
void err;
|
|
1277
1694
|
}
|
|
1278
1695
|
}
|
|
1279
1696
|
}
|
|
@@ -1301,30 +1718,46 @@ Or specify a custom report:
|
|
|
1301
1718
|
AIREADY_REPORT_PATH: reportPath,
|
|
1302
1719
|
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1303
1720
|
};
|
|
1304
|
-
const vite = (0, import_child_process.spawn)("pnpm", ["run", "dev:web"], {
|
|
1721
|
+
const vite = (0, import_child_process.spawn)("pnpm", ["run", "dev:web"], {
|
|
1722
|
+
cwd: spawnCwd,
|
|
1723
|
+
stdio: "inherit",
|
|
1724
|
+
shell: true,
|
|
1725
|
+
env: envForSpawn
|
|
1726
|
+
});
|
|
1305
1727
|
const onExit = () => {
|
|
1306
1728
|
try {
|
|
1307
1729
|
reportWatcher.close();
|
|
1308
|
-
} catch (
|
|
1730
|
+
} catch (err) {
|
|
1731
|
+
void err;
|
|
1309
1732
|
}
|
|
1310
1733
|
try {
|
|
1311
1734
|
vite.kill();
|
|
1312
|
-
} catch (
|
|
1735
|
+
} catch (err) {
|
|
1736
|
+
void err;
|
|
1313
1737
|
}
|
|
1314
1738
|
process.exit(0);
|
|
1315
1739
|
};
|
|
1316
1740
|
process.on("SIGINT", onExit);
|
|
1317
1741
|
process.on("SIGTERM", onExit);
|
|
1318
1742
|
devServerStarted = true;
|
|
1743
|
+
void devServerStarted;
|
|
1319
1744
|
return;
|
|
1320
1745
|
} else {
|
|
1321
|
-
console.log(
|
|
1322
|
-
|
|
1746
|
+
console.log(
|
|
1747
|
+
import_chalk6.default.yellow(
|
|
1748
|
+
"\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."
|
|
1749
|
+
)
|
|
1750
|
+
);
|
|
1751
|
+
console.log(
|
|
1752
|
+
import_chalk6.default.cyan(" Falling back to static HTML generation...\n")
|
|
1753
|
+
);
|
|
1323
1754
|
useDevMode = false;
|
|
1324
1755
|
}
|
|
1325
1756
|
} catch (err) {
|
|
1326
1757
|
console.error("Failed to start dev server:", err);
|
|
1327
|
-
console.log(
|
|
1758
|
+
console.log(
|
|
1759
|
+
import_chalk6.default.cyan(" Falling back to static HTML generation...\n")
|
|
1760
|
+
);
|
|
1328
1761
|
useDevMode = false;
|
|
1329
1762
|
}
|
|
1330
1763
|
}
|
|
@@ -1346,20 +1779,25 @@ Or specify a custom report:
|
|
|
1346
1779
|
const urlPath = req.url || "/";
|
|
1347
1780
|
if (urlPath === "/" || urlPath === "/index.html") {
|
|
1348
1781
|
const content = await fsp.readFile(outPath, "utf8");
|
|
1349
|
-
res.writeHead(200, {
|
|
1782
|
+
res.writeHead(200, {
|
|
1783
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1784
|
+
});
|
|
1350
1785
|
res.end(content);
|
|
1351
1786
|
return;
|
|
1352
1787
|
}
|
|
1353
1788
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1354
1789
|
res.end("Not found");
|
|
1355
1790
|
} catch (e) {
|
|
1791
|
+
void e;
|
|
1356
1792
|
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1357
1793
|
res.end("Server error");
|
|
1358
1794
|
}
|
|
1359
1795
|
});
|
|
1360
1796
|
server.listen(port, () => {
|
|
1361
1797
|
const addr = `http://localhost:${port}/`;
|
|
1362
|
-
console.log(
|
|
1798
|
+
console.log(
|
|
1799
|
+
import_chalk6.default.cyan(`\u{1F310} Local visualization server running at ${addr}`)
|
|
1800
|
+
);
|
|
1363
1801
|
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1364
1802
|
});
|
|
1365
1803
|
process.on("SIGINT", () => {
|
|
@@ -1425,9 +1863,13 @@ var getDirname = () => {
|
|
|
1425
1863
|
if (typeof __dirname !== "undefined") return __dirname;
|
|
1426
1864
|
return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
|
|
1427
1865
|
};
|
|
1428
|
-
var packageJson = JSON.parse(
|
|
1866
|
+
var packageJson = JSON.parse(
|
|
1867
|
+
(0, import_fs5.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
|
|
1868
|
+
);
|
|
1429
1869
|
var program = new import_commander.Command();
|
|
1430
|
-
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
|
|
1870
|
+
program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
|
|
1871
|
+
"after",
|
|
1872
|
+
`
|
|
1431
1873
|
AI READINESS SCORING:
|
|
1432
1874
|
Get a 0-100 score indicating how AI-ready your codebase is.
|
|
1433
1875
|
Use --score flag with any analysis command for detailed breakdown.
|
|
@@ -1462,23 +1904,105 @@ CONFIGURATION:
|
|
|
1462
1904
|
VERSION: ${packageJson.version}
|
|
1463
1905
|
DOCUMENTATION: https://aiready.dev/docs/cli
|
|
1464
1906
|
GITHUB: https://github.com/caopengau/aiready-cli
|
|
1465
|
-
LANDING: https://github.com/caopengau/aiready-landing`
|
|
1466
|
-
|
|
1907
|
+
LANDING: https://github.com/caopengau/aiready-landing`
|
|
1908
|
+
);
|
|
1909
|
+
program.command("scan").description(
|
|
1910
|
+
"Run comprehensive AI-readiness analysis (patterns + context + consistency)"
|
|
1911
|
+
).argument("[directory]", "Directory to analyze", ".").option(
|
|
1912
|
+
"-t, --tools <tools>",
|
|
1913
|
+
"Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
|
|
1914
|
+
).option(
|
|
1915
|
+
"--profile <type>",
|
|
1916
|
+
"Scan profile to use (agentic, cost, security, onboarding)"
|
|
1917
|
+
).option(
|
|
1918
|
+
"--compare-to <path>",
|
|
1919
|
+
"Compare results against a previous AIReady report JSON"
|
|
1920
|
+
).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(
|
|
1921
|
+
"--no-score",
|
|
1922
|
+
"Disable calculating AI Readiness Score (enabled by default)"
|
|
1923
|
+
).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
|
|
1924
|
+
"--ci",
|
|
1925
|
+
"CI mode: GitHub Actions annotations, no colors, fail on threshold"
|
|
1926
|
+
).option(
|
|
1927
|
+
"--fail-on <level>",
|
|
1928
|
+
"Fail on issues: critical, major, any",
|
|
1929
|
+
"critical"
|
|
1930
|
+
).addHelpText("after", scanHelpText).action(async (directory, options) => {
|
|
1467
1931
|
await scanAction(directory, options);
|
|
1468
1932
|
});
|
|
1469
|
-
program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
|
|
1933
|
+
program.command("patterns").description("Detect duplicate code patterns that confuse AI models").argument("[directory]", "Directory to analyze", ".").option("-s, --similarity <number>", "Minimum similarity score (0-1)", "0.40").option("-l, --min-lines <number>", "Minimum lines to consider", "5").option(
|
|
1934
|
+
"--max-candidates <number>",
|
|
1935
|
+
"Maximum candidates per block (performance tuning)"
|
|
1936
|
+
).option(
|
|
1937
|
+
"--min-shared-tokens <number>",
|
|
1938
|
+
"Minimum shared tokens for candidates (performance tuning)"
|
|
1939
|
+
).option(
|
|
1940
|
+
"--full-scan",
|
|
1941
|
+
"Disable smart defaults for comprehensive analysis (slower)"
|
|
1942
|
+
).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(
|
|
1943
|
+
"--score",
|
|
1944
|
+
"Calculate and display AI Readiness Score for patterns (0-100)"
|
|
1945
|
+
).addHelpText("after", patternsHelpText).action(async (directory, options) => {
|
|
1470
1946
|
await patternsAction(directory, options);
|
|
1471
1947
|
});
|
|
1472
|
-
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(
|
|
1948
|
+
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(
|
|
1949
|
+
"--max-context <number>",
|
|
1950
|
+
"Maximum acceptable context budget (tokens)",
|
|
1951
|
+
"10000"
|
|
1952
|
+
).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(
|
|
1953
|
+
"--score",
|
|
1954
|
+
"Calculate and display AI Readiness Score for context (0-100)"
|
|
1955
|
+
).action(async (directory, options) => {
|
|
1473
1956
|
await contextAction(directory, options);
|
|
1474
1957
|
});
|
|
1475
|
-
program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
|
|
1958
|
+
program.command("consistency").description("Check naming conventions and architectural consistency").argument("[directory]", "Directory to analyze", ".").option("--naming", "Check naming conventions (default: true)").option("--no-naming", "Skip naming analysis").option("--patterns", "Check code patterns (default: true)").option("--no-patterns", "Skip pattern analysis").option(
|
|
1959
|
+
"--min-severity <level>",
|
|
1960
|
+
"Minimum severity: info|minor|major|critical",
|
|
1961
|
+
"info"
|
|
1962
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option(
|
|
1963
|
+
"-o, --output <format>",
|
|
1964
|
+
"Output format: console, json, markdown",
|
|
1965
|
+
"console"
|
|
1966
|
+
).option("--output-file <path>", "Output file path (for json/markdown)").option(
|
|
1967
|
+
"--score",
|
|
1968
|
+
"Calculate and display AI Readiness Score for consistency (0-100)"
|
|
1969
|
+
).action(async (directory, options) => {
|
|
1476
1970
|
await consistencyAction(directory, options);
|
|
1477
1971
|
});
|
|
1478
|
-
program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
|
|
1972
|
+
program.command("visualise").description("Alias for visualize (British spelling)").argument("[directory]", "Directory to analyze", ".").option(
|
|
1973
|
+
"--report <path>",
|
|
1974
|
+
"Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
|
|
1975
|
+
).option(
|
|
1976
|
+
"-o, --output <path>",
|
|
1977
|
+
"Output HTML path (relative to directory)",
|
|
1978
|
+
"packages/visualizer/visualization.html"
|
|
1979
|
+
).option("--open", "Open generated HTML in default browser").option(
|
|
1980
|
+
"--serve [port]",
|
|
1981
|
+
"Start a local static server to serve the visualization (optional port number)",
|
|
1982
|
+
false
|
|
1983
|
+
).option(
|
|
1984
|
+
"--dev",
|
|
1985
|
+
"Start Vite dev server (live reload) for interactive development",
|
|
1986
|
+
true
|
|
1987
|
+
).addHelpText("after", visualiseHelpText).action(async (directory, options) => {
|
|
1479
1988
|
await visualizeAction(directory, options);
|
|
1480
1989
|
});
|
|
1481
|
-
program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
|
|
1990
|
+
program.command("visualize").description("Generate interactive visualization from an AIReady report").argument("[directory]", "Directory to analyze", ".").option(
|
|
1991
|
+
"--report <path>",
|
|
1992
|
+
"Report path (auto-detects latest .aiready/aiready-report-*.json if not provided)"
|
|
1993
|
+
).option(
|
|
1994
|
+
"-o, --output <path>",
|
|
1995
|
+
"Output HTML path (relative to directory)",
|
|
1996
|
+
"packages/visualizer/visualization.html"
|
|
1997
|
+
).option("--open", "Open generated HTML in default browser").option(
|
|
1998
|
+
"--serve [port]",
|
|
1999
|
+
"Start a local static server to serve the visualization (optional port number)",
|
|
2000
|
+
false
|
|
2001
|
+
).option(
|
|
2002
|
+
"--dev",
|
|
2003
|
+
"Start Vite dev server (live reload) for interactive development",
|
|
2004
|
+
false
|
|
2005
|
+
).addHelpText("after", visualizeHelpText).action(async (directory, options) => {
|
|
1482
2006
|
await visualizeAction(directory, options);
|
|
1483
2007
|
});
|
|
1484
2008
|
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) => {
|