@aiready/cli 0.10.6 → 0.12.1
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 +43 -4
- package/dist/chunk-LTUQDJPO.mjs +229 -0
- package/dist/chunk-N56YAZVN.mjs +194 -0
- package/dist/chunk-YBZKPKW3.mjs +161 -0
- package/dist/cli.js +237 -910
- package/dist/cli.mjs +92 -584
- package/dist/index.js +149 -369
- 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/.aiready/aiready-report-20260307-094831.json +50609 -0
- package/src/.aiready/aiready-report-20260307-100539.json +50609 -0
- package/src/.aiready/aiready-report-20260307-103508.json +51329 -0
- package/src/__tests__/cli.test.ts +55 -29
- package/src/commands/scan.ts +116 -700
- package/src/index.ts +191 -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-LTUQDJPO.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,25 @@ 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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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;
|
|
344
|
+
if (event.message) {
|
|
345
|
+
process.stdout.write(`\r\x1B[K [${event.tool}] ${event.message}`);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
process.stdout.write("\n");
|
|
349
|
+
console.log(chalk3.cyan(`--- ${event.tool.toUpperCase()} RESULTS ---`));
|
|
350
|
+
const res = event.data;
|
|
351
|
+
if (res && res.summary) {
|
|
352
|
+
if (res.summary.totalIssues !== void 0)
|
|
353
|
+
console.log(` Issues found: ${chalk3.bold(res.summary.totalIssues)}`);
|
|
354
|
+
if (res.summary.score !== void 0)
|
|
355
|
+
console.log(` Tool Score: ${chalk3.bold(res.summary.score)}/100`);
|
|
356
|
+
if (res.summary.totalFiles !== void 0)
|
|
590
357
|
console.log(
|
|
591
|
-
`
|
|
358
|
+
` Files analyzed: ${chalk3.bold(res.summary.totalFiles)}`
|
|
592
359
|
);
|
|
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
360
|
}
|
|
602
361
|
};
|
|
603
362
|
const results = await analyzeUnified({
|
|
@@ -607,44 +366,14 @@ async function scanAction(directory, options) {
|
|
|
607
366
|
process.stdout.write(
|
|
608
367
|
`\r\x1B[K [${processed}/${total}] ${message}...`
|
|
609
368
|
);
|
|
610
|
-
if (processed === total)
|
|
611
|
-
process.stdout.write("\n");
|
|
612
|
-
}
|
|
369
|
+
if (processed === total) process.stdout.write("\n");
|
|
613
370
|
},
|
|
614
371
|
suppressToolConfig: true
|
|
615
372
|
});
|
|
616
373
|
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
374
|
console.log(
|
|
623
375
|
` Total issues (all tools): ${chalk3.bold(String(results.summary.totalIssues || 0))}`
|
|
624
376
|
);
|
|
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
377
|
let scoringResult;
|
|
649
378
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
650
379
|
scoringResult = await scoreUnified(results, finalOptions);
|
|
@@ -652,55 +381,34 @@ async function scanAction(directory, options) {
|
|
|
652
381
|
console.log(` ${formatScore(scoringResult)}`);
|
|
653
382
|
if (options.compareTo) {
|
|
654
383
|
try {
|
|
655
|
-
const
|
|
656
|
-
resolvePath3(process.cwd(), options.compareTo),
|
|
657
|
-
"utf8"
|
|
384
|
+
const prevReport = JSON.parse(
|
|
385
|
+
readFileSync2(resolvePath3(process.cwd(), options.compareTo), "utf8")
|
|
658
386
|
);
|
|
659
|
-
const
|
|
660
|
-
const prevScore = prevReport.scoring?.score || prevReport.scoring?.overallScore;
|
|
387
|
+
const prevScore = prevReport.scoring?.overall || prevReport.scoring?.score;
|
|
661
388
|
if (typeof prevScore === "number") {
|
|
662
389
|
const diff = scoringResult.overall - prevScore;
|
|
663
390
|
const diffStr = diff > 0 ? `+${diff}` : String(diff);
|
|
664
|
-
|
|
665
|
-
if (diff > 0) {
|
|
391
|
+
if (diff > 0)
|
|
666
392
|
console.log(
|
|
667
393
|
chalk3.green(
|
|
668
394
|
` \u{1F4C8} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
669
395
|
)
|
|
670
396
|
);
|
|
671
|
-
|
|
397
|
+
else if (diff < 0)
|
|
672
398
|
console.log(
|
|
673
399
|
chalk3.red(
|
|
674
400
|
` \u{1F4C9} Trend: ${diffStr} compared to ${options.compareTo} (${prevScore} \u2192 ${scoringResult.overall})`
|
|
675
401
|
)
|
|
676
402
|
);
|
|
677
|
-
|
|
403
|
+
else
|
|
678
404
|
console.log(
|
|
679
405
|
chalk3.blue(
|
|
680
|
-
` \u2796 Trend: No change
|
|
406
|
+
` \u2796 Trend: No change (${prevScore} \u2192 ${scoringResult.overall})`
|
|
681
407
|
)
|
|
682
408
|
);
|
|
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
409
|
}
|
|
696
410
|
} catch (e) {
|
|
697
411
|
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
412
|
}
|
|
705
413
|
}
|
|
706
414
|
const totalWastedDuplication = (scoringResult.breakdown || []).reduce(
|
|
@@ -714,7 +422,8 @@ async function scanAction(directory, options) {
|
|
|
714
422
|
const totalContext = Math.max(
|
|
715
423
|
...(scoringResult.breakdown || []).map(
|
|
716
424
|
(s) => s.tokenBudget?.totalContextTokens || 0
|
|
717
|
-
)
|
|
425
|
+
),
|
|
426
|
+
0
|
|
718
427
|
);
|
|
719
428
|
if (totalContext > 0) {
|
|
720
429
|
const unifiedBudget = calculateTokenBudget({
|
|
@@ -725,35 +434,17 @@ async function scanAction(directory, options) {
|
|
|
725
434
|
chattiness: 0
|
|
726
435
|
}
|
|
727
436
|
});
|
|
728
|
-
const
|
|
729
|
-
const modelPreset = getModelPreset(targetModel);
|
|
437
|
+
const modelPreset = getModelPreset(options.model || "claude-4.6");
|
|
730
438
|
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
|
-
);
|
|
439
|
+
console.log(chalk3.bold("\n\u{1F4CA} AI Token Budget Analysis"));
|
|
741
440
|
console.log(
|
|
742
|
-
`
|
|
441
|
+
` Efficiency: ${(unifiedBudget.efficiencyRatio * 100).toFixed(0)}%`
|
|
743
442
|
);
|
|
744
|
-
console.log(` Waste Breakdown:`);
|
|
745
443
|
console.log(
|
|
746
|
-
`
|
|
444
|
+
` Wasted Tokens: ${chalk3.red(unifiedBudget.wastedTokens.total.toLocaleString())}`
|
|
747
445
|
);
|
|
748
446
|
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]}]`
|
|
447
|
+
` Est. Monthly Cost (${modelPreset.name}): ${chalk3.bold("$" + costEstimate.total)}`
|
|
757
448
|
);
|
|
758
449
|
scoringResult.tokenBudget = unifiedBudget;
|
|
759
450
|
scoringResult.costEstimate = {
|
|
@@ -761,85 +452,31 @@ async function scanAction(directory, options) {
|
|
|
761
452
|
...costEstimate
|
|
762
453
|
};
|
|
763
454
|
}
|
|
764
|
-
if (scoringResult.breakdown
|
|
455
|
+
if (scoringResult.breakdown) {
|
|
765
456
|
console.log(chalk3.bold("\nTool breakdown:"));
|
|
766
457
|
scoringResult.breakdown.forEach((tool) => {
|
|
767
458
|
const rating = getRating(tool.score);
|
|
768
|
-
|
|
769
|
-
console.log(
|
|
770
|
-
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${rd.emoji}`
|
|
771
|
-
);
|
|
459
|
+
console.log(` - ${tool.toolName}: ${tool.score}/100 (${rating})`);
|
|
772
460
|
});
|
|
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
461
|
}
|
|
782
462
|
}
|
|
783
463
|
const mapToUnifiedReport = (res, scoring) => {
|
|
784
464
|
const allResults = [];
|
|
785
|
-
|
|
465
|
+
const totalFilesSet = /* @__PURE__ */ new Set();
|
|
786
466
|
let criticalCount = 0;
|
|
787
467
|
let majorCount = 0;
|
|
788
|
-
|
|
468
|
+
res.summary.toolsRun.forEach((toolId) => {
|
|
469
|
+
const spokeRes = res[toolId];
|
|
789
470
|
if (!spokeRes || !spokeRes.results) return;
|
|
790
471
|
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);
|
|
472
|
+
totalFilesSet.add(r.fileName);
|
|
473
|
+
allResults.push(r);
|
|
474
|
+
r.issues?.forEach((i) => {
|
|
475
|
+
if (i.severity === Severity.Critical) criticalCount++;
|
|
476
|
+
if (i.severity === Severity.Major) majorCount++;
|
|
477
|
+
});
|
|
832
478
|
});
|
|
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);
|
|
479
|
+
});
|
|
843
480
|
return {
|
|
844
481
|
...res,
|
|
845
482
|
results: allResults,
|
|
@@ -852,199 +489,70 @@ async function scanAction(directory, options) {
|
|
|
852
489
|
scoring
|
|
853
490
|
};
|
|
854
491
|
};
|
|
492
|
+
const outputData = {
|
|
493
|
+
...mapToUnifiedReport(results, scoringResult),
|
|
494
|
+
repository: repoMetadata
|
|
495
|
+
};
|
|
855
496
|
const outputFormat = options.output || finalOptions.output?.format || "console";
|
|
856
|
-
const
|
|
497
|
+
const outputPath = resolveOutputPath(
|
|
498
|
+
options.outputFile || finalOptions.output?.file,
|
|
499
|
+
`aiready-report-${getReportTimestamp()}.json`,
|
|
500
|
+
resolvedDir
|
|
501
|
+
);
|
|
857
502
|
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
503
|
handleJSONOutput(
|
|
870
504
|
outputData,
|
|
871
505
|
outputPath,
|
|
872
506
|
`\u2705 Report saved to ${outputPath}`
|
|
873
507
|
);
|
|
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
508
|
} 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
509
|
try {
|
|
895
510
|
writeFileSync(outputPath, JSON.stringify(outputData, null, 2));
|
|
896
511
|
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
512
|
} catch (err) {
|
|
906
513
|
void err;
|
|
907
514
|
}
|
|
908
515
|
}
|
|
909
|
-
|
|
516
|
+
if (options.upload) {
|
|
517
|
+
await uploadAction(outputPath, {
|
|
518
|
+
apiKey: options.apiKey,
|
|
519
|
+
server: options.server
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
await warnIfGraphCapExceeded(outputData, resolvedDir);
|
|
523
|
+
const isCI = options.ci || process.env.CI === "true";
|
|
910
524
|
if (isCI && scoringResult) {
|
|
911
525
|
const threshold = options.threshold ? parseInt(options.threshold) : void 0;
|
|
912
526
|
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
527
|
let shouldFail = false;
|
|
944
528
|
let failReason = "";
|
|
945
529
|
if (threshold && scoringResult.overall < threshold) {
|
|
946
530
|
shouldFail = true;
|
|
947
|
-
failReason = `
|
|
531
|
+
failReason = `Score ${scoringResult.overall} < threshold ${threshold}`;
|
|
948
532
|
}
|
|
533
|
+
const report = mapToUnifiedReport(results, scoringResult);
|
|
949
534
|
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) {
|
|
535
|
+
if (failOnLevel === "critical" && report.summary.criticalIssues > 0) {
|
|
977
536
|
shouldFail = true;
|
|
978
|
-
failReason = `Found ${
|
|
979
|
-
} else if (
|
|
537
|
+
failReason = `Found ${report.summary.criticalIssues} critical issues`;
|
|
538
|
+
} else if (failOnLevel === "major" && report.summary.criticalIssues + report.summary.majorIssues > 0) {
|
|
980
539
|
shouldFail = true;
|
|
981
|
-
failReason = `Found ${
|
|
540
|
+
failReason = `Found ${report.summary.criticalIssues} critical and ${report.summary.majorIssues} major issues`;
|
|
982
541
|
}
|
|
983
542
|
}
|
|
984
543
|
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
|
-
);
|
|
544
|
+
console.log(chalk3.red(`
|
|
545
|
+
\u{1F6AB} PR BLOCKED: ${failReason}`));
|
|
997
546
|
process.exit(1);
|
|
998
547
|
} 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
|
-
);
|
|
548
|
+
console.log(chalk3.green("\n\u2705 PR PASSED"));
|
|
1012
549
|
}
|
|
1013
550
|
}
|
|
1014
551
|
} catch (error) {
|
|
1015
552
|
handleCLIError2(error, "Analysis");
|
|
1016
553
|
}
|
|
1017
554
|
}
|
|
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
|
-
`;
|
|
555
|
+
var scanHelpText = `...`;
|
|
1048
556
|
|
|
1049
557
|
// src/commands/patterns.ts
|
|
1050
558
|
import chalk4 from "chalk";
|