@aiready/cli 0.10.4 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/.turbo/turbo-lint.log +9 -1
- package/.turbo/turbo-test.log +16 -4
- package/dist/chunk-N56YAZVN.mjs +194 -0
- package/dist/chunk-YBZKPKW3.mjs +161 -0
- package/dist/cli.js +198 -892
- package/dist/cli.mjs +87 -582
- package/dist/index.js +116 -353
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/.aiready/aiready-report-20260306-213155.json +24657 -0
- package/src/.aiready/aiready-report-20260306-213925.json +24657 -0
- package/src/.aiready/aiready-report-20260307-092852.json +50609 -0
- package/src/.aiready/aiready-report-20260307-094301.json +50609 -0
- package/src/__tests__/cli.test.ts +55 -29
- package/src/commands/scan.ts +108 -698
- package/src/index.ts +154 -436
- package/dist/chunk-EQ2HQSTJ.mjs +0 -414
- package/dist/chunk-R3O7QPKD.mjs +0 -419
- package/dist/chunk-VUCNUYI7.mjs +0 -417
package/dist/cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
__require,
|
|
4
4
|
analyzeUnified,
|
|
5
5
|
scoreUnified
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-N56YAZVN.mjs";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -19,18 +19,15 @@ import {
|
|
|
19
19
|
loadMergedConfig,
|
|
20
20
|
handleJSONOutput,
|
|
21
21
|
handleCLIError as handleCLIError2,
|
|
22
|
-
getElapsedTime,
|
|
23
22
|
resolveOutputPath,
|
|
24
23
|
formatScore,
|
|
25
|
-
formatToolScore,
|
|
26
24
|
calculateTokenBudget,
|
|
27
25
|
estimateCostFromBudget,
|
|
28
26
|
getModelPreset,
|
|
29
27
|
getRating,
|
|
30
|
-
getRatingDisplay,
|
|
31
28
|
getRepoMetadata,
|
|
32
29
|
Severity,
|
|
33
|
-
|
|
30
|
+
ToolName
|
|
34
31
|
} from "@aiready/core";
|
|
35
32
|
|
|
36
33
|
// src/utils/helpers.ts
|
|
@@ -150,12 +147,6 @@ function generateMarkdownReport(report, elapsedTime) {
|
|
|
150
147
|
}
|
|
151
148
|
return markdown;
|
|
152
149
|
}
|
|
153
|
-
function truncateArray(arr, cap = 8) {
|
|
154
|
-
if (!Array.isArray(arr)) return "";
|
|
155
|
-
const shown = arr.slice(0, cap).map((v) => String(v));
|
|
156
|
-
const more = arr.length - shown.length;
|
|
157
|
-
return shown.join(", ") + (more > 0 ? `, ... (+${more} more)` : "");
|
|
158
|
-
}
|
|
159
150
|
|
|
160
151
|
// src/commands/upload.ts
|
|
161
152
|
import fs from "fs";
|
|
@@ -269,14 +260,14 @@ async function scanAction(directory, options) {
|
|
|
269
260
|
try {
|
|
270
261
|
const defaults = {
|
|
271
262
|
tools: [
|
|
272
|
-
"
|
|
273
|
-
"context",
|
|
274
|
-
"consistency",
|
|
263
|
+
"pattern-detect",
|
|
264
|
+
"context-analyzer",
|
|
265
|
+
"naming-consistency",
|
|
275
266
|
"ai-signal-clarity",
|
|
276
267
|
"agent-grounding",
|
|
277
|
-
"testability",
|
|
268
|
+
"testability-index",
|
|
278
269
|
"doc-drift",
|
|
279
|
-
"
|
|
270
|
+
"dependency-health",
|
|
280
271
|
"change-amplification"
|
|
281
272
|
],
|
|
282
273
|
include: void 0,
|
|
@@ -286,35 +277,37 @@ async function scanAction(directory, options) {
|
|
|
286
277
|
file: void 0
|
|
287
278
|
}
|
|
288
279
|
};
|
|
289
|
-
let profileTools = options.tools ? options.tools.split(",").map((t) =>
|
|
290
|
-
const tool = t.trim();
|
|
291
|
-
if (tool === "hallucination" || tool === "hallucination-risk")
|
|
292
|
-
return "aiSignalClarity";
|
|
293
|
-
return tool;
|
|
294
|
-
}) : void 0;
|
|
280
|
+
let profileTools = options.tools ? options.tools.split(",").map((t) => t.trim()) : void 0;
|
|
295
281
|
if (options.profile) {
|
|
296
282
|
switch (options.profile.toLowerCase()) {
|
|
297
283
|
case "agentic":
|
|
298
284
|
profileTools = [
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
285
|
+
ToolName.AiSignalClarity,
|
|
286
|
+
ToolName.AgentGrounding,
|
|
287
|
+
ToolName.TestabilityIndex
|
|
302
288
|
];
|
|
303
289
|
break;
|
|
304
290
|
case "cost":
|
|
305
|
-
profileTools = [
|
|
291
|
+
profileTools = [ToolName.PatternDetect, ToolName.ContextAnalyzer];
|
|
306
292
|
break;
|
|
307
293
|
case "security":
|
|
308
|
-
profileTools = [
|
|
294
|
+
profileTools = [
|
|
295
|
+
ToolName.NamingConsistency,
|
|
296
|
+
ToolName.TestabilityIndex
|
|
297
|
+
];
|
|
309
298
|
break;
|
|
310
299
|
case "onboarding":
|
|
311
|
-
profileTools = [
|
|
300
|
+
profileTools = [
|
|
301
|
+
ToolName.ContextAnalyzer,
|
|
302
|
+
ToolName.NamingConsistency,
|
|
303
|
+
ToolName.AgentGrounding
|
|
304
|
+
];
|
|
312
305
|
break;
|
|
313
306
|
default:
|
|
314
307
|
console.log(
|
|
315
308
|
chalk3.yellow(
|
|
316
309
|
`
|
|
317
|
-
\u26A0\uFE0F Unknown profile '${options.profile}'. Using
|
|
310
|
+
\u26A0\uFE0F Unknown profile '${options.profile}'. Using defaults.`
|
|
318
311
|
)
|
|
319
312
|
);
|
|
320
313
|
}
|
|
@@ -323,16 +316,14 @@ async function scanAction(directory, options) {
|
|
|
323
316
|
include: options.include?.split(","),
|
|
324
317
|
exclude: options.exclude?.split(",")
|
|
325
318
|
};
|
|
326
|
-
if (profileTools)
|
|
327
|
-
cliOverrides.tools = profileTools;
|
|
328
|
-
}
|
|
319
|
+
if (profileTools) cliOverrides.tools = profileTools;
|
|
329
320
|
const baseOptions = await loadMergedConfig(
|
|
330
321
|
resolvedDir,
|
|
331
322
|
defaults,
|
|
332
323
|
cliOverrides
|
|
333
324
|
);
|
|
334
325
|
let finalOptions = { ...baseOptions };
|
|
335
|
-
if (baseOptions.tools.includes("patterns")) {
|
|
326
|
+
if (baseOptions.tools.includes(ToolName.PatternDetect) || baseOptions.tools.includes("patterns")) {
|
|
336
327
|
const { getSmartDefaults } = await import("@aiready/pattern-detect");
|
|
337
328
|
const patternSmartDefaults = await getSmartDefaults(
|
|
338
329
|
resolvedDir,
|
|
@@ -347,256 +338,21 @@ async function scanAction(directory, options) {
|
|
|
347
338
|
console.log(chalk3.cyan("\n=== AIReady Run Preview ==="));
|
|
348
339
|
console.log(
|
|
349
340
|
chalk3.white("Tools to run:"),
|
|
350
|
-
(finalOptions.tools || [
|
|
341
|
+
(finalOptions.tools || []).join(", ")
|
|
351
342
|
);
|
|
352
|
-
console.log(chalk3.white("Will use settings from config and defaults."));
|
|
353
|
-
console.log(chalk3.white("\nGeneral settings:"));
|
|
354
|
-
if (finalOptions.rootDir)
|
|
355
|
-
console.log(` rootDir: ${chalk3.bold(String(finalOptions.rootDir))}`);
|
|
356
|
-
if (finalOptions.include)
|
|
357
|
-
console.log(
|
|
358
|
-
` include: ${chalk3.bold(truncateArray(finalOptions.include, 6))}`
|
|
359
|
-
);
|
|
360
|
-
if (finalOptions.exclude)
|
|
361
|
-
console.log(
|
|
362
|
-
` exclude: ${chalk3.bold(truncateArray(finalOptions.exclude, 6))}`
|
|
363
|
-
);
|
|
364
|
-
if (finalOptions["pattern-detect"] || finalOptions.minSimilarity) {
|
|
365
|
-
const patternDetectConfig = finalOptions["pattern-detect"] || {
|
|
366
|
-
minSimilarity: finalOptions.minSimilarity,
|
|
367
|
-
minLines: finalOptions.minLines,
|
|
368
|
-
approx: finalOptions.approx,
|
|
369
|
-
minSharedTokens: finalOptions.minSharedTokens,
|
|
370
|
-
maxCandidatesPerBlock: finalOptions.maxCandidatesPerBlock,
|
|
371
|
-
batchSize: finalOptions.batchSize,
|
|
372
|
-
streamResults: finalOptions.streamResults,
|
|
373
|
-
severity: finalOptions.severity,
|
|
374
|
-
includeTests: finalOptions.includeTests
|
|
375
|
-
};
|
|
376
|
-
console.log(chalk3.white("\nPattern-detect settings:"));
|
|
377
|
-
console.log(
|
|
378
|
-
` minSimilarity: ${chalk3.bold(patternDetectConfig.minSimilarity ?? "default")}`
|
|
379
|
-
);
|
|
380
|
-
console.log(
|
|
381
|
-
` minLines: ${chalk3.bold(patternDetectConfig.minLines ?? "default")}`
|
|
382
|
-
);
|
|
383
|
-
if (patternDetectConfig.approx !== void 0)
|
|
384
|
-
console.log(
|
|
385
|
-
` approx: ${chalk3.bold(String(patternDetectConfig.approx))}`
|
|
386
|
-
);
|
|
387
|
-
if (patternDetectConfig.minSharedTokens !== void 0)
|
|
388
|
-
console.log(
|
|
389
|
-
` minSharedTokens: ${chalk3.bold(String(patternDetectConfig.minSharedTokens))}`
|
|
390
|
-
);
|
|
391
|
-
if (patternDetectConfig.maxCandidatesPerBlock !== void 0)
|
|
392
|
-
console.log(
|
|
393
|
-
` maxCandidatesPerBlock: ${chalk3.bold(String(patternDetectConfig.maxCandidatesPerBlock))}`
|
|
394
|
-
);
|
|
395
|
-
if (patternDetectConfig.batchSize !== void 0)
|
|
396
|
-
console.log(
|
|
397
|
-
` batchSize: ${chalk3.bold(String(patternDetectConfig.batchSize))}`
|
|
398
|
-
);
|
|
399
|
-
if (patternDetectConfig.streamResults !== void 0)
|
|
400
|
-
console.log(
|
|
401
|
-
` streamResults: ${chalk3.bold(String(patternDetectConfig.streamResults))}`
|
|
402
|
-
);
|
|
403
|
-
if (patternDetectConfig.severity !== void 0)
|
|
404
|
-
console.log(
|
|
405
|
-
` severity: ${chalk3.bold(String(patternDetectConfig.severity))}`
|
|
406
|
-
);
|
|
407
|
-
if (patternDetectConfig.includeTests !== void 0)
|
|
408
|
-
console.log(
|
|
409
|
-
` includeTests: ${chalk3.bold(String(patternDetectConfig.includeTests))}`
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
if (finalOptions["context-analyzer"] || finalOptions.maxDepth) {
|
|
413
|
-
const ca = finalOptions["context-analyzer"] || {
|
|
414
|
-
maxDepth: finalOptions.maxDepth,
|
|
415
|
-
maxContextBudget: finalOptions.maxContextBudget,
|
|
416
|
-
minCohesion: finalOptions.minCohesion,
|
|
417
|
-
maxFragmentation: finalOptions.maxFragmentation,
|
|
418
|
-
includeNodeModules: finalOptions.includeNodeModules
|
|
419
|
-
};
|
|
420
|
-
console.log(chalk3.white("\nContext-analyzer settings:"));
|
|
421
|
-
console.log(` maxDepth: ${chalk3.bold(ca.maxDepth ?? "default")}`);
|
|
422
|
-
console.log(
|
|
423
|
-
` maxContextBudget: ${chalk3.bold(ca.maxContextBudget ?? "default")}`
|
|
424
|
-
);
|
|
425
|
-
if (ca.minCohesion !== void 0)
|
|
426
|
-
console.log(` minCohesion: ${chalk3.bold(String(ca.minCohesion))}`);
|
|
427
|
-
if (ca.maxFragmentation !== void 0)
|
|
428
|
-
console.log(
|
|
429
|
-
` maxFragmentation: ${chalk3.bold(String(ca.maxFragmentation))}`
|
|
430
|
-
);
|
|
431
|
-
if (ca.includeNodeModules !== void 0)
|
|
432
|
-
console.log(
|
|
433
|
-
` includeNodeModules: ${chalk3.bold(String(ca.includeNodeModules))}`
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
if (finalOptions.consistency) {
|
|
437
|
-
const c = finalOptions.consistency;
|
|
438
|
-
console.log(chalk3.white("\nConsistency settings:"));
|
|
439
|
-
console.log(
|
|
440
|
-
` checkNaming: ${chalk3.bold(String(c.checkNaming ?? true))}`
|
|
441
|
-
);
|
|
442
|
-
console.log(
|
|
443
|
-
` checkPatterns: ${chalk3.bold(String(c.checkPatterns ?? true))}`
|
|
444
|
-
);
|
|
445
|
-
console.log(
|
|
446
|
-
` checkArchitecture: ${chalk3.bold(String(c.checkArchitecture ?? false))}`
|
|
447
|
-
);
|
|
448
|
-
if (c.minSeverity)
|
|
449
|
-
console.log(` minSeverity: ${chalk3.bold(c.minSeverity)}`);
|
|
450
|
-
if (c.acceptedAbbreviations)
|
|
451
|
-
console.log(
|
|
452
|
-
` acceptedAbbreviations: ${chalk3.bold(truncateArray(c.acceptedAbbreviations, 8))}`
|
|
453
|
-
);
|
|
454
|
-
if (c.shortWords)
|
|
455
|
-
console.log(
|
|
456
|
-
` shortWords: ${chalk3.bold(truncateArray(c.shortWords, 8))}`
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
|
-
console.log(chalk3.white("\nStarting analysis..."));
|
|
460
343
|
const progressCallback = (event) => {
|
|
461
344
|
console.log(chalk3.cyan(`
|
|
462
345
|
--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
346
|
+
const res = event.data;
|
|
347
|
+
if (res.summary) {
|
|
348
|
+
if (res.summary.totalIssues !== void 0)
|
|
349
|
+
console.log(` Issues found: ${chalk3.bold(res.summary.totalIssues)}`);
|
|
350
|
+
if (res.summary.score !== void 0)
|
|
351
|
+
console.log(` Tool Score: ${chalk3.bold(res.summary.score)}/100`);
|
|
352
|
+
if (res.summary.totalFiles !== void 0)
|
|
466
353
|
console.log(
|
|
467
|
-
`
|
|
354
|
+
` Files analyzed: ${chalk3.bold(res.summary.totalFiles)}`
|
|
468
355
|
);
|
|
469
|
-
console.log(
|
|
470
|
-
` Files with pattern issues: ${chalk3.bold(String(pr.results?.length || 0))}`
|
|
471
|
-
);
|
|
472
|
-
if (pr.duplicates && pr.duplicates.length > 0) {
|
|
473
|
-
pr.duplicates.slice(0, 5).forEach((d, i) => {
|
|
474
|
-
console.log(
|
|
475
|
-
` ${i + 1}. ${d.file1.split("/").pop()} \u2194 ${d.file2.split("/").pop()} (sim=${(d.similarity * 100).toFixed(1)}%)`
|
|
476
|
-
);
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
if (pr.results && pr.results.length > 0) {
|
|
480
|
-
console.log(` Top files with pattern issues:`);
|
|
481
|
-
const sortedByIssues = [...pr.results].sort(
|
|
482
|
-
(a, b) => (b.issues?.length || 0) - (a.issues?.length || 0)
|
|
483
|
-
);
|
|
484
|
-
sortedByIssues.slice(0, 5).forEach((r, i) => {
|
|
485
|
-
console.log(
|
|
486
|
-
` ${i + 1}. ${r.fileName.split("/").pop()} - ${r.issues.length} issue(s)`
|
|
487
|
-
);
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
if (pr.groups && pr.groups.length >= 0) {
|
|
491
|
-
console.log(
|
|
492
|
-
` \u2705 Grouped ${chalk3.bold(String(pr.duplicates?.length || 0))} duplicates into ${chalk3.bold(String(pr.groups.length))} file pairs`
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
if (pr.clusters && pr.clusters.length >= 0) {
|
|
496
|
-
console.log(
|
|
497
|
-
` \u2705 Created ${chalk3.bold(String(pr.clusters.length))} refactor clusters`
|
|
498
|
-
);
|
|
499
|
-
pr.clusters.slice(0, 3).forEach((cl, idx) => {
|
|
500
|
-
const files = (cl.files || []).map((f) => f.path.split("/").pop()).join(", ");
|
|
501
|
-
console.log(
|
|
502
|
-
` ${idx + 1}. ${files} (${cl.tokenCost || "n/a"} tokens)`
|
|
503
|
-
);
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
} else if (event.tool === "context") {
|
|
507
|
-
const cr = event.data;
|
|
508
|
-
console.log(
|
|
509
|
-
` Context issues found: ${chalk3.bold(String(cr.length || 0))}`
|
|
510
|
-
);
|
|
511
|
-
cr.slice(0, 5).forEach((c, i) => {
|
|
512
|
-
const msg = c.message ? ` - ${c.message}` : "";
|
|
513
|
-
console.log(
|
|
514
|
-
` ${i + 1}. ${c.file} (${c.severity || "n/a"})${msg}`
|
|
515
|
-
);
|
|
516
|
-
});
|
|
517
|
-
} else if (event.tool === "consistency") {
|
|
518
|
-
const rep = event.data;
|
|
519
|
-
console.log(
|
|
520
|
-
` Consistency totalIssues: ${chalk3.bold(String(rep.summary?.totalIssues || 0))}`
|
|
521
|
-
);
|
|
522
|
-
if (rep.results && rep.results.length > 0) {
|
|
523
|
-
const fileMap = /* @__PURE__ */ new Map();
|
|
524
|
-
rep.results.forEach((r) => {
|
|
525
|
-
(r.issues || []).forEach((issue) => {
|
|
526
|
-
const file = issue.location?.file || r.file || "unknown";
|
|
527
|
-
if (!fileMap.has(file)) fileMap.set(file, []);
|
|
528
|
-
fileMap.get(file).push(issue);
|
|
529
|
-
});
|
|
530
|
-
});
|
|
531
|
-
const files = Array.from(fileMap.entries()).sort(
|
|
532
|
-
(a, b) => b[1].length - a[1].length
|
|
533
|
-
);
|
|
534
|
-
const topFiles = files.slice(0, 10);
|
|
535
|
-
topFiles.forEach(([file, issues], idx) => {
|
|
536
|
-
const counts = issues.reduce(
|
|
537
|
-
(acc, it) => {
|
|
538
|
-
const s = (it.severity || Severity.Info).toLowerCase();
|
|
539
|
-
acc[s] = (acc[s] || 0) + 1;
|
|
540
|
-
return acc;
|
|
541
|
-
},
|
|
542
|
-
{}
|
|
543
|
-
);
|
|
544
|
-
const sample = issues.find(
|
|
545
|
-
(it) => it.severity === Severity.Critical || it.severity === Severity.Major
|
|
546
|
-
) || issues[0];
|
|
547
|
-
const sampleMsg = sample ? ` \u2014 ${sample.message}` : "";
|
|
548
|
-
console.log(
|
|
549
|
-
` ${idx + 1}. ${file} \u2014 ${issues.length} issue(s) (critical:${counts[Severity.Critical] || 0} major:${counts[Severity.Major] || 0} minor:${counts[Severity.Minor] || 0} info:${counts[Severity.Info] || 0})${sampleMsg}`
|
|
550
|
-
);
|
|
551
|
-
});
|
|
552
|
-
const remaining = files.length - topFiles.length;
|
|
553
|
-
if (remaining > 0) {
|
|
554
|
-
console.log(
|
|
555
|
-
chalk3.dim(
|
|
556
|
-
` ... and ${remaining} more files with issues (use --output json for full details)`
|
|
557
|
-
)
|
|
558
|
-
);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
} else if (event.tool === "doc-drift") {
|
|
562
|
-
const dr = event.data;
|
|
563
|
-
console.log(
|
|
564
|
-
` Issues found: ${chalk3.bold(String(dr.issues?.length || 0))}`
|
|
565
|
-
);
|
|
566
|
-
if (dr.rawData) {
|
|
567
|
-
console.log(
|
|
568
|
-
` Signature Mismatches: ${chalk3.bold(dr.rawData.outdatedComments || 0)}`
|
|
569
|
-
);
|
|
570
|
-
console.log(
|
|
571
|
-
` Undocumented Complexity: ${chalk3.bold(dr.rawData.undocumentedComplexity || 0)}`
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
} else if (event.tool === "deps-health") {
|
|
575
|
-
const dr = event.data;
|
|
576
|
-
console.log(
|
|
577
|
-
` Packages Analyzed: ${chalk3.bold(String(dr.summary?.packagesAnalyzed || 0))}`
|
|
578
|
-
);
|
|
579
|
-
if (dr.rawData) {
|
|
580
|
-
console.log(
|
|
581
|
-
` Deprecated Packages: ${chalk3.bold(dr.rawData.deprecatedPackages || 0)}`
|
|
582
|
-
);
|
|
583
|
-
console.log(
|
|
584
|
-
` AI Cutoff Skew Score: ${chalk3.bold(dr.rawData.trainingCutoffSkew?.toFixed(1) || 0)}`
|
|
585
|
-
);
|
|
586
|
-
}
|
|
587
|
-
} else if (event.tool === "change-amplification" || event.tool === "changeAmplification") {
|
|
588
|
-
const dr = event.data;
|
|
589
|
-
console.log(
|
|
590
|
-
` Coupling issues: ${chalk3.bold(String(dr.issues?.length || 0))}`
|
|
591
|
-
);
|
|
592
|
-
if (dr.summary) {
|
|
593
|
-
console.log(
|
|
594
|
-
` Complexity Score: ${chalk3.bold(dr.summary.score || 0)}/100`
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
} catch (err) {
|
|
599
|
-
void err;
|
|
600
356
|
}
|
|
601
357
|
};
|
|
602
358
|
const results = await analyzeUnified({
|
|
@@ -606,44 +362,14 @@ async function scanAction(directory, options) {
|
|
|
606
362
|
process.stdout.write(
|
|
607
363
|
`\r\x1B[K [${processed}/${total}] ${message}...`
|
|
608
364
|
);
|
|
609
|
-
if (processed === total)
|
|
610
|
-
process.stdout.write("\n");
|
|
611
|
-
}
|
|
365
|
+
if (processed === total) process.stdout.write("\n");
|
|
612
366
|
},
|
|
613
367
|
suppressToolConfig: true
|
|
614
368
|
});
|
|
615
369
|
console.log(chalk3.cyan("\n=== AIReady Run Summary ==="));
|
|
616
|
-
console.log(
|
|
617
|
-
chalk3.white("Tools run:"),
|
|
618
|
-
(finalOptions.tools || ["patterns", "context", "consistency"]).join(", ")
|
|
619
|
-
);
|
|
620
|
-
console.log(chalk3.cyan("\nResults summary:"));
|
|
621
370
|
console.log(
|
|
622
371
|
` Total issues (all tools): ${chalk3.bold(String(results.summary.totalIssues || 0))}`
|
|
623
372
|
);
|
|
624
|
-
if (results.patternDetect) {
|
|
625
|
-
console.log(
|
|
626
|
-
` Duplicate patterns found: ${chalk3.bold(String(results.patternDetect.duplicates?.length || 0))}`
|
|
627
|
-
);
|
|
628
|
-
console.log(
|
|
629
|
-
` Pattern files with issues: ${chalk3.bold(String(results.patternDetect.results.length || 0))}`
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
if (results.contextAnalyzer)
|
|
633
|
-
console.log(
|
|
634
|
-
` Context issues: ${chalk3.bold(String(results.contextAnalyzer.results.length || 0))}`
|
|
635
|
-
);
|
|
636
|
-
if (results.consistency)
|
|
637
|
-
console.log(
|
|
638
|
-
` Consistency issues: ${chalk3.bold(String(results.consistency.summary?.totalIssues || 0))}`
|
|
639
|
-
);
|
|
640
|
-
if (results.changeAmplification)
|
|
641
|
-
console.log(
|
|
642
|
-
` Change amplification: ${chalk3.bold(String(results.changeAmplification.summary?.score || 0))}/100`
|
|
643
|
-
);
|
|
644
|
-
console.log(chalk3.cyan("===========================\n"));
|
|
645
|
-
const elapsedTime = getElapsedTime(startTime);
|
|
646
|
-
void elapsedTime;
|
|
647
373
|
let scoringResult;
|
|
648
374
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
649
375
|
scoringResult = await scoreUnified(results, finalOptions);
|
|
@@ -651,55 +377,34 @@ async function scanAction(directory, options) {
|
|
|
651
377
|
console.log(` ${formatScore(scoringResult)}`);
|
|
652
378
|
if (options.compareTo) {
|
|
653
379
|
try {
|
|
654
|
-
const
|
|
655
|
-
resolvePath3(process.cwd(), options.compareTo),
|
|
656
|
-
"utf8"
|
|
380
|
+
const prevReport = JSON.parse(
|
|
381
|
+
readFileSync2(resolvePath3(process.cwd(), options.compareTo), "utf8")
|
|
657
382
|
);
|
|
658
|
-
const
|
|
659
|
-
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
383
|
+
const prevScore = prevReport.scoring?.overall || prevReport.scoring?.score;
|
|
660
384
|
if (typeof prevScore === "number") {
|
|
661
385
|
const diff = scoringResult.overall - prevScore;
|
|
662
386
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
663
|
-
|
|
664
|
-
if (diff > 0) {
|
|
387
|
+
if (diff > 0)
|
|
665
388
|
console.log(
|
|
666
389
|
chalk3.green(
|
|
667
390
|
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
668
391
|
)
|
|
669
392
|
);
|
|
670
|
-
|
|
393
|
+
else if (diff < 0)
|
|
671
394
|
console.log(
|
|
672
395
|
chalk3.red(
|
|
673
396
|
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
674
397
|
)
|
|
675
398
|
);
|
|
676
|
-
|
|
399
|
+
else
|
|
677
400
|
console.log(
|
|
678
401
|
chalk3.blue(
|
|
679
|
-
` \u2796 Trend: No change
|
|
402
|
+
` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
|
|
680
403
|
)
|
|
681
404
|
);
|
|
682
|
-
}
|
|
683
|
-
scoringResult.trend = {
|
|
684
|
-
previousScore: prevScore,
|
|
685
|
-
difference: diff
|
|
686
|
-
};
|
|
687
|
-
} else {
|
|
688
|
-
console.log(
|
|
689
|
-
chalk3.yellow(
|
|
690
|
-
`
|
|
691
|
-
\u26A0\uFE0F Previous report at ${options.compareTo} does not contain an overall score.`
|
|
692
|
-
)
|
|
693
|
-
);
|
|
694
405
|
}
|
|
695
406
|
} catch (e) {
|
|
696
407
|
void e;
|
|
697
|
-
console.log(
|
|
698
|
-
chalk3.yellow(
|
|
699
|
-
`
|
|
700
|
-
\u26A0\uFE0F Could not read or parse previous report at ${options.compareTo}.`
|
|
701
|
-
)
|
|
702
|
-
);
|
|
703
408
|
}
|
|
704
409
|
}
|
|
705
410
|
const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
|
|
@@ -713,7 +418,8 @@ async function scanAction(directory, options) {
|
|
|
713
418
|
const totalContext = Math.max(
|
|
714
419
|
...(scoringResult.breakdown || []).map(
|
|
715
420
|
(s) => s.tokenBudget?.totalContextTokens || 0
|
|
716
|
-
)
|
|
421
|
+
),
|
|
422
|
+
0
|
|
717
423
|
);
|
|
718
424
|
if (totalContext > 0) {
|
|
719
425
|
const unifiedBudget = calculateTokenBudget({
|
|
@@ -724,35 +430,17 @@ async function scanAction(directory, options) {
|
|
|
724
430
|
chattiness: 0
|
|
725
431
|
}
|
|
726
432
|
});
|
|
727
|
-
const
|
|
728
|
-
const modelPreset = getModelPreset(targetModel);
|
|
433
|
+
const modelPreset = getModelPreset(options.model || "claude-4.6");
|
|
729
434
|
const costEstimate = estimateCostFromBudget(unifiedBudget, modelPreset);
|
|
730
|
-
|
|
731
|
-
const filled = Math.round(unifiedBudget.efficiencyRatio * barWidth);
|
|
732
|
-
const bar = chalk3.green("\u2588".repeat(filled)) + chalk3.dim("\u2591".repeat(barWidth - filled));
|
|
733
|
-
console.log(chalk3.bold("\n\u{1F4CA} AI Token Budget Analysis (v0.13)"));
|
|
734
|
-
console.log(
|
|
735
|
-
` Efficiency: [${bar}] ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`
|
|
736
|
-
);
|
|
737
|
-
console.log(
|
|
738
|
-
` Total Context: ${chalk3.bold(unifiedBudget.totalContextTokens.toLocaleString())} tokens`
|
|
739
|
-
);
|
|
435
|
+
console.log(chalk3.bold("\n\u{1F4CA} AI Token Budget Analysis"));
|
|
740
436
|
console.log(
|
|
741
|
-
`
|
|
437
|
+
` Efficiency: ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`
|
|
742
438
|
);
|
|
743
|
-
console.log(` Waste Breakdown:`);
|
|
744
439
|
console.log(
|
|
745
|
-
`
|
|
440
|
+
` Wasted Tokens: ${chalk3.red(unifiedBudget.wastedTokens.total.toLocaleString())}`
|
|
746
441
|
);
|
|
747
442
|
console.log(
|
|
748
|
-
`
|
|
749
|
-
);
|
|
750
|
-
console.log(
|
|
751
|
-
` Potential Savings: ${chalk3.green(unifiedBudget.potentialRetrievableTokens.toLocaleString())} tokens retrievable`
|
|
752
|
-
);
|
|
753
|
-
console.log(
|
|
754
|
-
`
|
|
755
|
-
Est. Monthly Cost (${modelPreset.name}): ${chalk3.bold("$" + costEstimate.total)} [range: $${costEstimate.range[0]}-$${costEstimate.range[1]}]`
|
|
443
|
+
` Est. Monthly Cost (${modelPreset.name}): ${chalk3.bold("$" + costEstimate.total)}`
|
|
756
444
|
);
|
|
757
445
|
scoringResult.tokenBudget = unifiedBudget;
|
|
758
446
|
scoringResult.costEstimate = {
|
|
@@ -760,85 +448,31 @@ async function scanAction(directory, options) {
|
|
|
760
448
|
...costEstimate
|
|
761
449
|
};
|
|
762
450
|
}
|
|
763
|
-
if (scoringResult.breakdown
|
|
451
|
+
if (scoringResult.breakdown) {
|
|
764
452
|
console.log(chalk3.bold("\nTool breakdown:"));
|
|
765
453
|
scoringResult.breakdown.forEach((tool) => {
|
|
766
454
|
const rating = getRating(tool.score);
|
|
767
|
-
|
|
768
|
-
console.log(
|
|
769
|
-
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
|
|
770
|
-
);
|
|
455
|
+
console.log(` - ${tool.toolName}: ${tool.score}/100 (${rating})`);
|
|
771
456
|
});
|
|
772
|
-
console.log();
|
|
773
|
-
if (finalOptions.scoring?.showBreakdown) {
|
|
774
|
-
console.log(chalk3.bold("Detailed tool breakdown:"));
|
|
775
|
-
scoringResult.breakdown.forEach((tool) => {
|
|
776
|
-
console.log(formatToolScore(tool));
|
|
777
|
-
});
|
|
778
|
-
console.log();
|
|
779
|
-
}
|
|
780
457
|
}
|
|
781
458
|
}
|
|
782
459
|
const mapToUnifiedReport = (res, scoring) => {
|
|
783
460
|
const allResults = [];
|
|
784
|
-
|
|
461
|
+
const totalFilesSet = /* @__PURE__ */ new Set();
|
|
785
462
|
let criticalCount = 0;
|
|
786
463
|
let majorCount = 0;
|
|
787
|
-
|
|
464
|
+
res.summary.toolsRun.forEach((toolId) => {
|
|
465
|
+
const spokeRes = res[toolId];
|
|
788
466
|
if (!spokeRes || !spokeRes.results) return;
|
|
789
467
|
spokeRes.results.forEach((r) => {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
};
|
|
797
|
-
if (r.issues && Array.isArray(r.issues)) {
|
|
798
|
-
r.issues.forEach((i) => {
|
|
799
|
-
const normalizedIssue = typeof i === "string" ? {
|
|
800
|
-
type: defaultType,
|
|
801
|
-
severity: r.severity || Severity.Info,
|
|
802
|
-
message: i,
|
|
803
|
-
location: { file: fileName, line: 1 }
|
|
804
|
-
} : {
|
|
805
|
-
type: i.type || defaultType,
|
|
806
|
-
severity: i.severity || r.severity || Severity.Info,
|
|
807
|
-
message: i.message || String(i),
|
|
808
|
-
location: i.location || { file: fileName, line: 1 },
|
|
809
|
-
suggestion: i.suggestion
|
|
810
|
-
};
|
|
811
|
-
if (normalizedIssue.severity === Severity.Critical || normalizedIssue.severity === "critical")
|
|
812
|
-
criticalCount++;
|
|
813
|
-
if (normalizedIssue.severity === Severity.Major || normalizedIssue.severity === "major")
|
|
814
|
-
majorCount++;
|
|
815
|
-
normalizedResult.issues.push(normalizedIssue);
|
|
816
|
-
});
|
|
817
|
-
} else if (r.severity) {
|
|
818
|
-
const normalizedIssue = {
|
|
819
|
-
type: defaultType,
|
|
820
|
-
severity: r.severity,
|
|
821
|
-
message: r.message || "General issue",
|
|
822
|
-
location: { file: fileName, line: 1 }
|
|
823
|
-
};
|
|
824
|
-
if (normalizedIssue.severity === Severity.Critical || normalizedIssue.severity === "critical")
|
|
825
|
-
criticalCount++;
|
|
826
|
-
if (normalizedIssue.severity === Severity.Major || normalizedIssue.severity === "major")
|
|
827
|
-
majorCount++;
|
|
828
|
-
normalizedResult.issues.push(normalizedIssue);
|
|
829
|
-
}
|
|
830
|
-
allResults.push(normalizedResult);
|
|
468
|
+
totalFilesSet.add(r.fileName);
|
|
469
|
+
allResults.push(r);
|
|
470
|
+
r.issues?.forEach((i) => {
|
|
471
|
+
if (i.severity === Severity.Critical) criticalCount++;
|
|
472
|
+
if (i.severity === Severity.Major) majorCount++;
|
|
473
|
+
});
|
|
831
474
|
});
|
|
832
|
-
};
|
|
833
|
-
collect(res.patternDetect, IssueType.DuplicatePattern);
|
|
834
|
-
collect(res.contextAnalyzer, IssueType.ContextFragmentation);
|
|
835
|
-
collect(res.consistency, IssueType.NamingInconsistency);
|
|
836
|
-
collect(res.docDrift, IssueType.DocDrift);
|
|
837
|
-
collect(res.dependencyHealth, IssueType.DependencyHealth);
|
|
838
|
-
collect(res.aiSignalClarity, IssueType.AiSignalClarity);
|
|
839
|
-
collect(res.agentGrounding, IssueType.AgentNavigationFailure);
|
|
840
|
-
collect(res.testability, IssueType.LowTestability);
|
|
841
|
-
collect(res.changeAmplification, IssueType.ChangeAmplification);
|
|
475
|
+
});
|
|
842
476
|
return {
|
|
843
477
|
...res,
|
|
844
478
|
results: allResults,
|
|
@@ -851,199 +485,70 @@ async function scanAction(directory, options) {
|
|
|
851
485
|
scoring
|
|
852
486
|
};
|
|
853
487
|
};
|
|
488
|
+
const outputData = {
|
|
489
|
+
...mapToUnifiedReport(results, scoringResult),
|
|
490
|
+
repository: repoMetadata
|
|
491
|
+
};
|
|
854
492
|
const outputFormat = options.output || finalOptions.output?.format || "console";
|
|
855
|
-
const
|
|
493
|
+
const outputPath = resolveOutputPath(
|
|
494
|
+
options.outputFile || finalOptions.output?.file,
|
|
495
|
+
`aiready-report-${getReportTimestamp()}.json`,
|
|
496
|
+
resolvedDir
|
|
497
|
+
);
|
|
856
498
|
if (outputFormat === "json") {
|
|
857
|
-
const timestamp = getReportTimestamp();
|
|
858
|
-
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
859
|
-
const outputPath = resolveOutputPath(
|
|
860
|
-
userOutputFile,
|
|
861
|
-
defaultFilename,
|
|
862
|
-
resolvedDir
|
|
863
|
-
);
|
|
864
|
-
const outputData = {
|
|
865
|
-
...mapToUnifiedReport(results, scoringResult),
|
|
866
|
-
repository: repoMetadata
|
|
867
|
-
};
|
|
868
499
|
handleJSONOutput(
|
|
869
500
|
outputData,
|
|
870
501
|
outputPath,
|
|
871
502
|
`\u2705 Report saved to ${outputPath}`
|
|
872
503
|
);
|
|
873
|
-
if (options.upload) {
|
|
874
|
-
console.log(chalk3.blue("\n\u{1F4E4} Automatic upload triggered..."));
|
|
875
|
-
await uploadAction(outputPath, {
|
|
876
|
-
apiKey: options.apiKey,
|
|
877
|
-
server: options.server
|
|
878
|
-
});
|
|
879
|
-
}
|
|
880
|
-
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
881
504
|
} else {
|
|
882
|
-
const timestamp = getReportTimestamp();
|
|
883
|
-
const defaultFilename = `aiready-report-${timestamp}.json`;
|
|
884
|
-
const outputPath = resolveOutputPath(
|
|
885
|
-
userOutputFile,
|
|
886
|
-
defaultFilename,
|
|
887
|
-
resolvedDir
|
|
888
|
-
);
|
|
889
|
-
const outputData = {
|
|
890
|
-
...mapToUnifiedReport(results, scoringResult),
|
|
891
|
-
repository: repoMetadata
|
|
892
|
-
};
|
|
893
505
|
try {
|
|
894
506
|
writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
|
|
895
507
|
console.log(chalk3.dim(`\u2705 Report auto-persisted to ${outputPath}`));
|
|
896
|
-
if (options.upload) {
|
|
897
|
-
console.log(chalk3.blue("\n\u{1F4E4} Automatic upload triggered..."));
|
|
898
|
-
await uploadAction(outputPath, {
|
|
899
|
-
apiKey: options.apiKey,
|
|
900
|
-
server: options.server
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
904
508
|
} catch (err) {
|
|
905
509
|
void err;
|
|
906
510
|
}
|
|
907
511
|
}
|
|
908
|
-
|
|
512
|
+
if (options.upload) {
|
|
513
|
+
await uploadAction(outputPath, {
|
|
514
|
+
apiKey: options.apiKey,
|
|
515
|
+
server: options.server
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
519
|
+
const isCI = options.ci || process.env.CI === "true";
|
|
909
520
|
if (isCI && scoringResult) {
|
|
910
521
|
const threshold = options.threshold ? parseInt(options.threshold) : void 0;
|
|
911
522
|
const failOnLevel = options.failOn || "critical";
|
|
912
|
-
if (process.env.GITHUB_ACTIONS === "true") {
|
|
913
|
-
console.log(`
|
|
914
|
-
::group::AI Readiness Score`);
|
|
915
|
-
console.log(`score=${scoringResult.overall}`);
|
|
916
|
-
if (scoringResult.breakdown) {
|
|
917
|
-
scoringResult.breakdown.forEach((tool) => {
|
|
918
|
-
console.log(`${tool.toolName}=${tool.score}`);
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
console.log("::endgroup::");
|
|
922
|
-
if (threshold && scoringResult.overall < threshold) {
|
|
923
|
-
console.log(
|
|
924
|
-
`::error::AI Readiness Score ${scoringResult.overall} is below threshold ${threshold}`
|
|
925
|
-
);
|
|
926
|
-
} else if (threshold) {
|
|
927
|
-
console.log(
|
|
928
|
-
`::notice::AI Readiness Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
929
|
-
);
|
|
930
|
-
}
|
|
931
|
-
if (results.patternDetect) {
|
|
932
|
-
const criticalPatterns = results.patternDetect.results.flatMap(
|
|
933
|
-
(p) => p.issues.filter((i) => i.severity === Severity.Critical)
|
|
934
|
-
);
|
|
935
|
-
criticalPatterns.slice(0, 10).forEach((issue) => {
|
|
936
|
-
console.log(
|
|
937
|
-
`::warning file=${issue.location?.file || "unknown"},line=${issue.location?.line || 1}::${issue.message}`
|
|
938
|
-
);
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
523
|
let shouldFail = false;
|
|
943
524
|
let failReason = "";
|
|
944
525
|
if (threshold && scoringResult.overall < threshold) {
|
|
945
526
|
shouldFail = true;
|
|
946
|
-
failReason = `
|
|
527
|
+
failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
|
|
947
528
|
}
|
|
529
|
+
const report = mapToUnifiedReport(results, scoringResult);
|
|
948
530
|
if (failOnLevel !== "none") {
|
|
949
|
-
|
|
950
|
-
const minSeverity = severityLevels[failOnLevel] || 4;
|
|
951
|
-
let criticalCount = 0;
|
|
952
|
-
let majorCount = 0;
|
|
953
|
-
if (results.patternDetect) {
|
|
954
|
-
results.patternDetect.results.forEach((p) => {
|
|
955
|
-
p.issues.forEach((i) => {
|
|
956
|
-
if (i.severity === Severity.Critical) criticalCount++;
|
|
957
|
-
if (i.severity === Severity.Major) majorCount++;
|
|
958
|
-
});
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
if (results.contextAnalyzer) {
|
|
962
|
-
results.contextAnalyzer.results.forEach((c) => {
|
|
963
|
-
if (c.severity === Severity.Critical) criticalCount++;
|
|
964
|
-
if (c.severity === Severity.Major) majorCount++;
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
if (results.consistency) {
|
|
968
|
-
results.consistency.results.forEach((r) => {
|
|
969
|
-
r.issues?.forEach((i) => {
|
|
970
|
-
if (i.severity === Severity.Critical) criticalCount++;
|
|
971
|
-
if (i.severity === Severity.Major) majorCount++;
|
|
972
|
-
});
|
|
973
|
-
});
|
|
974
|
-
}
|
|
975
|
-
if (minSeverity >= 4 && criticalCount > 0) {
|
|
531
|
+
if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
|
|
976
532
|
shouldFail = true;
|
|
977
|
-
failReason = `Found ${
|
|
978
|
-
} else if (
|
|
533
|
+
failReason = `Found ${report.summary.criticalIssues} critical issues`;
|
|
534
|
+
} else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
|
|
979
535
|
shouldFail = true;
|
|
980
|
-
failReason = `Found ${
|
|
536
|
+
failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
|
|
981
537
|
}
|
|
982
538
|
}
|
|
983
539
|
if (shouldFail) {
|
|
984
|
-
console.log(chalk3.red(
|
|
985
|
-
|
|
986
|
-
console.log(chalk3.dim("\n Remediation steps:"));
|
|
987
|
-
console.log(
|
|
988
|
-
chalk3.dim(" 1. Run `aiready scan` locally to see detailed issues")
|
|
989
|
-
);
|
|
990
|
-
console.log(chalk3.dim(" 2. Fix the critical issues before merging"));
|
|
991
|
-
console.log(
|
|
992
|
-
chalk3.dim(
|
|
993
|
-
" 3. Consider upgrading to Team plan for historical tracking: https://getaiready.dev/pricing"
|
|
994
|
-
)
|
|
995
|
-
);
|
|
540
|
+
console.log(chalk3.red(`
|
|
541
|
+
\u{1F6AB} PR BLOCKED: ${failReason}`));
|
|
996
542
|
process.exit(1);
|
|
997
543
|
} else {
|
|
998
|
-
console.log(chalk3.green("\n\u2705 PR PASSED
|
|
999
|
-
if (threshold) {
|
|
1000
|
-
console.log(
|
|
1001
|
-
chalk3.green(
|
|
1002
|
-
` Score: ${scoringResult.overall}/100 (threshold: ${threshold})`
|
|
1003
|
-
)
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
console.log(
|
|
1007
|
-
chalk3.dim(
|
|
1008
|
-
"\n \u{1F4A1} Track historical trends: https://getaiready.dev \u2014 Team plan $99/mo"
|
|
1009
|
-
)
|
|
1010
|
-
);
|
|
544
|
+
console.log(chalk3.green("\n\u2705 PR PASSED"));
|
|
1011
545
|
}
|
|
1012
546
|
}
|
|
1013
547
|
} catch (error) {
|
|
1014
548
|
handleCLIError2(error, "Analysis");
|
|
1015
549
|
}
|
|
1016
550
|
}
|
|
1017
|
-
var scanHelpText =
|
|
1018
|
-
EXAMPLES:
|
|
1019
|
-
$ aiready scan # Analyze all tools
|
|
1020
|
-
$ aiready scan --tools patterns,context # Skip consistency
|
|
1021
|
-
$ aiready scan --profile agentic # Optimize for AI agent execution
|
|
1022
|
-
$ aiready scan --profile security # Optimize for secure coding (testability)
|
|
1023
|
-
$ aiready scan --compare-to prev-report.json # Compare trends against previous run
|
|
1024
|
-
$ aiready scan --score --threshold 75 # CI/CD with threshold
|
|
1025
|
-
$ aiready scan --ci --threshold 70 # GitHub Actions gatekeeper
|
|
1026
|
-
$ aiready scan --ci --fail-on major # Fail on major+ issues
|
|
1027
|
-
$ aiready scan --output json --output-file report.json
|
|
1028
|
-
$ aiready scan --upload --api-key ar_... # Automatic platform upload
|
|
1029
|
-
$ aiready scan --upload --server custom-url.com # Upload to custom platform
|
|
1030
|
-
|
|
1031
|
-
PROFILES:
|
|
1032
|
-
agentic: aiSignalClarity, grounding, testability
|
|
1033
|
-
cost: patterns, context
|
|
1034
|
-
security: consistency, testability
|
|
1035
|
-
onboarding: context, consistency, grounding
|
|
1036
|
-
|
|
1037
|
-
CI/CD INTEGRATION (Gatekeeper Mode):
|
|
1038
|
-
Use --ci for GitHub Actions integration:
|
|
1039
|
-
- Outputs GitHub Actions annotations for PR checks
|
|
1040
|
-
- Fails with exit code 1 if threshold not met
|
|
1041
|
-
- Shows clear "blocked" message with remediation steps
|
|
1042
|
-
|
|
1043
|
-
Example GitHub Actions workflow:
|
|
1044
|
-
- name: AI Readiness Check
|
|
1045
|
-
run: aiready scan --ci --threshold 70
|
|
1046
|
-
`;
|
|
551
|
+
var scanHelpText = `...`;
|
|
1047
552
|
|
|
1048
553
|
// src/commands/patterns.ts
|
|
1049
554
|
import chalk4 from "chalk";
|