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