@aiready/cli 0.13.0 → 0.13.2
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-test.log +17 -17
- package/CONTRIBUTING.md +1 -1
- package/README.md +7 -1
- package/dist/cli.js +48 -4
- package/dist/cli.mjs +49 -4
- package/docs/SPOKE_GUIDE.md +184 -0
- package/package.json +6 -6
- package/src/.aiready/aiready-report-20260311-010454.json +34448 -0
- package/src/.aiready/aiready-report-20260311-193858.json +34448 -0
- package/src/cli.ts +2 -1
- package/src/commands/scan.ts +61 -2
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/cli@0.
|
|
3
|
+
> @aiready/cli@0.13.2 build /Users/pengcao/projects/aiready/packages/cli
|
|
4
4
|
> tsup src/index.ts src/cli.ts --format cjs,esm
|
|
5
5
|
|
|
6
6
|
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
|
|
13
|
-
[43m[30m WARN [39m[49m [33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m"import.meta" is not available with the "cjs" output format and will be empty[0m [empty-import-meta]
|
|
13
|
+
[43m[30m WARN [39m[49m [33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m"import.meta" is not available with the "cjs" output format and will be empty[0m [empty-import-meta] [90m7:51:15 pm[39m
|
|
14
14
|
|
|
15
15
|
src/cli.ts:32:31:
|
|
16
16
|
[37m 32 │ return dirname(fileURLToPath([32mimport.meta[37m.url));
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
[32mCJS[39m [1mdist/index.js [22m[32m10.62 KB[39m
|
|
24
|
-
[32mCJS[39m [1mdist/cli.js [22m[32m80.29 KB[39m
|
|
25
|
-
[32mCJS[39m ⚡️ Build success in 34ms
|
|
26
|
-
[32mESM[39m [1mdist/cli.mjs [22m[32m66.94 KB[39m
|
|
27
|
-
[32mESM[39m [1mdist/chunk-VOKP7FGM.mjs [22m[32m9.52 KB[39m
|
|
28
23
|
[32mESM[39m [1mdist/index.mjs [22m[32m170.00 B[39m
|
|
29
|
-
[32mESM[39m
|
|
24
|
+
[32mESM[39m [1mdist/chunk-VOKP7FGM.mjs [22m[32m9.52 KB[39m
|
|
25
|
+
[32mESM[39m [1mdist/cli.mjs [22m[32m68.68 KB[39m
|
|
26
|
+
[32mESM[39m ⚡️ Build success in 30ms
|
|
27
|
+
[32mCJS[39m [1mdist/index.js [22m[32m10.62 KB[39m
|
|
28
|
+
[32mCJS[39m [1mdist/cli.js [22m[32m82.21 KB[39m
|
|
29
|
+
[32mCJS[39m ⚡️ Build success in 30ms
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/cli@0.
|
|
3
|
+
> @aiready/cli@0.13.0 test /Users/pengcao/projects/aiready/packages/cli
|
|
4
4
|
> vitest run
|
|
5
5
|
|
|
6
6
|
[?25l
|
|
7
7
|
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/Users/pengcao/projects/aiready/packages/cli[39m
|
|
8
8
|
|
|
9
|
-
[32m✓[39m src/
|
|
10
|
-
[32m✓[39m src/commands/__tests__/deps-health.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 16[2mms[22m[39m
|
|
11
|
-
[32m✓[39m src/commands/__tests__/doc-drift.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
12
|
-
[32m✓[39m src/commands/__tests__/agent-grounding.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
13
|
-
[32m✓[39m src/commands/__tests__/ai-signal-clarity.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
9
|
+
[32m✓[39m src/utils/__tests__/helpers.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
14
10
|
[90mstdout[2m | src/commands/__tests__/visualize.test.ts[2m > [22m[2mVisualize CLI Action[2m > [22m[2mshould generate HTML from specified report
|
|
15
11
|
[22m[39mBuilding graph from report...
|
|
16
12
|
|
|
13
|
+
[32m✓[39m src/commands/__tests__/testability.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
14
|
+
[32m✓[39m src/commands/__tests__/ai-signal-clarity.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
15
|
+
[32m✓[39m src/commands/__tests__/deps-health.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
16
|
+
[32m✓[39m src/commands/__tests__/doc-drift.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
17
|
+
[32m✓[39m src/commands/__tests__/agent-grounding.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
17
18
|
[90mstdout[2m | src/commands/__tests__/visualize.test.ts[2m > [22m[2mVisualize CLI Action[2m > [22m[2mshould generate HTML from specified report
|
|
18
19
|
[22m[39mGenerating HTML...
|
|
19
20
|
✅ Visualization written to: /Users/pengcao/projects/aiready/packages/cli/visualization.html
|
|
@@ -41,8 +42,7 @@ Or specify a custom report:
|
|
|
41
42
|
[22m[39mGenerating HTML...
|
|
42
43
|
✅ Visualization written to: /Users/pengcao/projects/aiready/packages/cli/visualization.html
|
|
43
44
|
|
|
44
|
-
[32m✓[39m src/commands/__tests__/visualize.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
45
|
-
[32m✓[39m src/utils/__tests__/helpers.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
45
|
+
[32m✓[39m src/commands/__tests__/visualize.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
46
46
|
[90mstdout[2m | src/commands/__tests__/upload.test.ts[2m > [22m[2mUpload CLI Action[2m > [22m[2mshould fail if API key is missing
|
|
47
47
|
[22m[39m Set AIREADY_API_KEY environment variable or use --api-key flag.
|
|
48
48
|
Get an API key from https://platform.getaiready.dev/dashboard
|
|
@@ -58,18 +58,18 @@ Or specify a custom report:
|
|
|
58
58
|
Score: 80/100
|
|
59
59
|
|
|
60
60
|
[32m✓[39m src/commands/__tests__/upload.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
61
|
-
[32m✓[39m src/commands/__tests__/consistency.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
62
|
-
[32m✓[39m src/commands/__tests__/scan.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
63
|
-
[32m✓[39m src/commands/__tests__/extra-commands.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 122[2mms[22m[39m
|
|
61
|
+
[32m✓[39m src/commands/__tests__/consistency.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
62
|
+
[32m✓[39m src/commands/__tests__/scan.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 77[2mms[22m[39m
|
|
64
63
|
[32m✓[39m src/__tests__/unified.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
65
|
-
[32m✓[39m src/__tests__/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
[32m✓[39m src/commands/__tests__/extra-commands.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 93[2mms[22m[39m
|
|
65
|
+
[32m✓[39m src/__tests__/cli.test.ts [2m([22m[2m3 tests[22m[2m)[22m[33m 3317[2mms[22m[39m
|
|
66
|
+
[33m[2m✓[22m[39m should run unified analysis with both tools [33m 3316[2mms[22m[39m
|
|
67
|
+
[32m✓[39m src/__tests__/config-shape.test.ts [2m([22m[2m3 tests[22m[2m)[22m[33m 3318[2mms[22m[39m
|
|
68
|
+
[33m[2m✓[22m[39m should generate a strictly portable AIReadyConfig in summary [33m 3316[2mms[22m[39m
|
|
69
69
|
|
|
70
70
|
[2m Test Files [22m [1m[32m14 passed[39m[22m[90m (14)[39m
|
|
71
71
|
[2m Tests [22m [1m[32m43 passed[39m[22m[90m (43)[39m
|
|
72
|
-
[2m Start at [22m
|
|
73
|
-
[2m Duration [22m 4.
|
|
72
|
+
[2m Start at [22m 00:58:55
|
|
73
|
+
[2m Duration [22m 4.20s[2m (transform 1.99s, setup 0ms, import 4.11s, tests 6.94s, environment 1ms)[22m
|
|
74
74
|
|
|
75
75
|
[?25h
|
package/CONTRIBUTING.md
CHANGED
|
@@ -196,7 +196,7 @@ src/
|
|
|
196
196
|
Great places to start:
|
|
197
197
|
|
|
198
198
|
- **New commands**: Add new CLI commands
|
|
199
|
-
- **Tool integration**: Integrate new analysis tools
|
|
199
|
+
- **Tool integration**: Integrate new analysis tools. Follow the [Spoke Development Guide](./docs/SPOKE_GUIDE.md) for more details.
|
|
200
200
|
- **Output formats**: Add new output options (XML, CSV, HTML)
|
|
201
201
|
- **Configuration**: Improve config file handling
|
|
202
202
|
- **Performance**: Optimize for large codebases
|
package/README.md
CHANGED
|
@@ -50,10 +50,15 @@ aiready scan .
|
|
|
50
50
|
|
|
51
51
|
# Run a specific tool
|
|
52
52
|
aiready patterns . --similarity 0.6
|
|
53
|
-
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 🛠️ Building Your Own Tool (Spokes)
|
|
56
|
+
|
|
57
|
+
Want to build your own analysis tool that integrates with the AIReady ecosystem? Check out our [Spoke Development Guide](./docs/SPOKE_GUIDE.md).
|
|
54
58
|
|
|
55
59
|
## 🌐 Platform Integration
|
|
56
60
|
|
|
61
|
+
|
|
57
62
|
Connect your local scans to the [AIReady Dashboard](https://platform.getaiready.dev/dashboard).
|
|
58
63
|
|
|
59
64
|
### Automatic Upload
|
|
@@ -85,3 +90,4 @@ MIT
|
|
|
85
90
|
```
|
|
86
91
|
|
|
87
92
|
```
|
|
93
|
+
````
|
package/dist/cli.js
CHANGED
|
@@ -550,6 +550,24 @@ async function scanAction(directory, options) {
|
|
|
550
550
|
case "cost":
|
|
551
551
|
profileTools = [import_core3.ToolName.PatternDetect, import_core3.ToolName.ContextAnalyzer];
|
|
552
552
|
break;
|
|
553
|
+
case "logic":
|
|
554
|
+
profileTools = [
|
|
555
|
+
import_core3.ToolName.TestabilityIndex,
|
|
556
|
+
import_core3.ToolName.NamingConsistency,
|
|
557
|
+
import_core3.ToolName.ContextAnalyzer,
|
|
558
|
+
import_core3.ToolName.PatternDetect,
|
|
559
|
+
import_core3.ToolName.ChangeAmplification
|
|
560
|
+
];
|
|
561
|
+
break;
|
|
562
|
+
case "ui":
|
|
563
|
+
profileTools = [
|
|
564
|
+
import_core3.ToolName.NamingConsistency,
|
|
565
|
+
import_core3.ToolName.ContextAnalyzer,
|
|
566
|
+
import_core3.ToolName.PatternDetect,
|
|
567
|
+
import_core3.ToolName.DocDrift,
|
|
568
|
+
import_core3.ToolName.AiSignalClarity
|
|
569
|
+
];
|
|
570
|
+
break;
|
|
553
571
|
case "security":
|
|
554
572
|
profileTools = [
|
|
555
573
|
import_core3.ToolName.NamingConsistency,
|
|
@@ -619,6 +637,7 @@ async function scanAction(directory, options) {
|
|
|
619
637
|
);
|
|
620
638
|
}
|
|
621
639
|
};
|
|
640
|
+
const scoringProfile = options.profile || baseOptions.scoring?.profile || "default";
|
|
622
641
|
const results = await analyzeUnified({
|
|
623
642
|
...finalOptions,
|
|
624
643
|
progressCallback,
|
|
@@ -635,9 +654,16 @@ async function scanAction(directory, options) {
|
|
|
635
654
|
);
|
|
636
655
|
let scoringResult;
|
|
637
656
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
638
|
-
scoringResult = await scoreUnified(results,
|
|
657
|
+
scoringResult = await scoreUnified(results, {
|
|
658
|
+
...finalOptions,
|
|
659
|
+
scoring: {
|
|
660
|
+
...finalOptions.scoring,
|
|
661
|
+
profile: scoringProfile
|
|
662
|
+
}
|
|
663
|
+
});
|
|
639
664
|
console.log(import_chalk3.default.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
640
665
|
console.log(` ${(0, import_core3.formatScore)(scoringResult)}`);
|
|
666
|
+
console.log(import_chalk3.default.dim(` (Scoring Profile: ${scoringProfile})`));
|
|
641
667
|
if (options.compareTo) {
|
|
642
668
|
try {
|
|
643
669
|
const prevReport = JSON.parse(
|
|
@@ -735,8 +761,26 @@ async function scanAction(directory, options) {
|
|
|
735
761
|
console.log(import_chalk3.default.bold("\nTool breakdown:"));
|
|
736
762
|
scoringResult.breakdown.forEach((tool) => {
|
|
737
763
|
const rating = (0, import_core3.getRating)(tool.score);
|
|
738
|
-
|
|
764
|
+
const emoji = (0, import_core3.getRatingDisplay)(rating).emoji;
|
|
765
|
+
console.log(
|
|
766
|
+
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
|
|
767
|
+
);
|
|
739
768
|
});
|
|
769
|
+
const allRecs = scoringResult.breakdown.flatMap(
|
|
770
|
+
(t) => (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
|
|
771
|
+
).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
|
|
772
|
+
if (allRecs.length > 0) {
|
|
773
|
+
console.log(import_chalk3.default.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
|
|
774
|
+
allRecs.forEach((rec, i) => {
|
|
775
|
+
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
776
|
+
console.log(
|
|
777
|
+
` ${i + 1}. ${priorityIcon} ${import_chalk3.default.bold(rec.action)}`
|
|
778
|
+
);
|
|
779
|
+
console.log(
|
|
780
|
+
` Impact: ${import_chalk3.default.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
|
|
781
|
+
);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
740
784
|
}
|
|
741
785
|
}
|
|
742
786
|
const mapToUnifiedReport = (res, scoring) => {
|
|
@@ -1869,11 +1913,11 @@ program.command("scan").description(
|
|
|
1869
1913
|
"Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
|
|
1870
1914
|
).option(
|
|
1871
1915
|
"--profile <type>",
|
|
1872
|
-
"Scan profile to use (agentic, cost, security, onboarding)"
|
|
1916
|
+
"Scan profile to use (agentic, cost, logic, ui, security, onboarding)"
|
|
1873
1917
|
).option(
|
|
1874
1918
|
"--compare-to <path>",
|
|
1875
1919
|
"Compare results against a previous AIReady report JSON"
|
|
1876
|
-
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
|
|
1920
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option(
|
|
1877
1921
|
"--no-score",
|
|
1878
1922
|
"Disable calculating AI Readiness Score (enabled by default)"
|
|
1879
1923
|
).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
|
package/dist/cli.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
formatScore,
|
|
24
24
|
calculateTokenBudget,
|
|
25
25
|
getRating,
|
|
26
|
+
getRatingDisplay,
|
|
26
27
|
getRepoMetadata,
|
|
27
28
|
Severity,
|
|
28
29
|
ToolName,
|
|
@@ -289,6 +290,24 @@ async function scanAction(directory, options) {
|
|
|
289
290
|
case "cost":
|
|
290
291
|
profileTools = [ToolName.PatternDetect, ToolName.ContextAnalyzer];
|
|
291
292
|
break;
|
|
293
|
+
case "logic":
|
|
294
|
+
profileTools = [
|
|
295
|
+
ToolName.TestabilityIndex,
|
|
296
|
+
ToolName.NamingConsistency,
|
|
297
|
+
ToolName.ContextAnalyzer,
|
|
298
|
+
ToolName.PatternDetect,
|
|
299
|
+
ToolName.ChangeAmplification
|
|
300
|
+
];
|
|
301
|
+
break;
|
|
302
|
+
case "ui":
|
|
303
|
+
profileTools = [
|
|
304
|
+
ToolName.NamingConsistency,
|
|
305
|
+
ToolName.ContextAnalyzer,
|
|
306
|
+
ToolName.PatternDetect,
|
|
307
|
+
ToolName.DocDrift,
|
|
308
|
+
ToolName.AiSignalClarity
|
|
309
|
+
];
|
|
310
|
+
break;
|
|
292
311
|
case "security":
|
|
293
312
|
profileTools = [
|
|
294
313
|
ToolName.NamingConsistency,
|
|
@@ -358,6 +377,7 @@ async function scanAction(directory, options) {
|
|
|
358
377
|
);
|
|
359
378
|
}
|
|
360
379
|
};
|
|
380
|
+
const scoringProfile = options.profile || baseOptions.scoring?.profile || "default";
|
|
361
381
|
const results = await analyzeUnified({
|
|
362
382
|
...finalOptions,
|
|
363
383
|
progressCallback,
|
|
@@ -374,9 +394,16 @@ async function scanAction(directory, options) {
|
|
|
374
394
|
);
|
|
375
395
|
let scoringResult;
|
|
376
396
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
|
377
|
-
scoringResult = await scoreUnified(results,
|
|
397
|
+
scoringResult = await scoreUnified(results, {
|
|
398
|
+
...finalOptions,
|
|
399
|
+
scoring: {
|
|
400
|
+
...finalOptions.scoring,
|
|
401
|
+
profile: scoringProfile
|
|
402
|
+
}
|
|
403
|
+
});
|
|
378
404
|
console.log(chalk3.bold("\n\u{1F4CA} AI Readiness Overall Score"));
|
|
379
405
|
console.log(` ${formatScore(scoringResult)}`);
|
|
406
|
+
console.log(chalk3.dim(` (Scoring Profile: ${scoringProfile})`));
|
|
380
407
|
if (options.compareTo) {
|
|
381
408
|
try {
|
|
382
409
|
const prevReport = JSON.parse(
|
|
@@ -474,8 +501,26 @@ async function scanAction(directory, options) {
|
|
|
474
501
|
console.log(chalk3.bold("\nTool breakdown:"));
|
|
475
502
|
scoringResult.breakdown.forEach((tool) => {
|
|
476
503
|
const rating = getRating(tool.score);
|
|
477
|
-
|
|
504
|
+
const emoji = getRatingDisplay(rating).emoji;
|
|
505
|
+
console.log(
|
|
506
|
+
` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
|
|
507
|
+
);
|
|
478
508
|
});
|
|
509
|
+
const allRecs = scoringResult.breakdown.flatMap(
|
|
510
|
+
(t) => (t.recommendations || []).map((r) => ({ ...r, tool: t.toolName }))
|
|
511
|
+
).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
|
|
512
|
+
if (allRecs.length > 0) {
|
|
513
|
+
console.log(chalk3.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
|
|
514
|
+
allRecs.forEach((rec, i) => {
|
|
515
|
+
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
516
|
+
console.log(
|
|
517
|
+
` ${i + 1}. ${priorityIcon} ${chalk3.bold(rec.action)}`
|
|
518
|
+
);
|
|
519
|
+
console.log(
|
|
520
|
+
` Impact: ${chalk3.green(`+${rec.estimatedImpact} points`)} to ${rec.tool}`
|
|
521
|
+
);
|
|
522
|
+
});
|
|
523
|
+
}
|
|
479
524
|
}
|
|
480
525
|
}
|
|
481
526
|
const mapToUnifiedReport = (res, scoring) => {
|
|
@@ -1630,11 +1675,11 @@ program.command("scan").description(
|
|
|
1630
1675
|
"Tools to run (comma-separated: patterns,context,consistency,doc-drift,deps-health,aiSignalClarity,grounding,testability,changeAmplification)"
|
|
1631
1676
|
).option(
|
|
1632
1677
|
"--profile <type>",
|
|
1633
|
-
"Scan profile to use (agentic, cost, security, onboarding)"
|
|
1678
|
+
"Scan profile to use (agentic, cost, logic, ui, security, onboarding)"
|
|
1634
1679
|
).option(
|
|
1635
1680
|
"--compare-to <path>",
|
|
1636
1681
|
"Compare results against a previous AIReady report JSON"
|
|
1637
|
-
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option(
|
|
1682
|
+
).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").option("--score", "Calculate and display AI Readiness Score (0-100)").option(
|
|
1638
1683
|
"--no-score",
|
|
1639
1684
|
"Disable calculating AI Readiness Score (enabled by default)"
|
|
1640
1685
|
).option("--weights <weights>", "Custom scoring weights").option("--threshold <score>", "Fail CI/CD if score below threshold (0-100)").option(
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Building a New AIReady Spoke
|
|
2
|
+
|
|
3
|
+
This guide explains how to build a new analysis tool ("spoke") and integrate it into the AIReady ecosystem. AIReady uses a hub-and-spoke architecture where independent tools are coordinated by a central CLI and Hub (@aiready/core).
|
|
4
|
+
|
|
5
|
+
## 🚀 Getting Started
|
|
6
|
+
|
|
7
|
+
### 1. Create Package Structure
|
|
8
|
+
|
|
9
|
+
If you are contributing to the monorepo:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mkdir -p packages/your-tool/src
|
|
13
|
+
cd packages/your-tool
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### 2. Create `package.json`
|
|
17
|
+
|
|
18
|
+
Your tool should depend on `@aiready/core` for shared types and utilities.
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"name": "@aiready/your-tool",
|
|
23
|
+
"version": "0.1.0",
|
|
24
|
+
"description": "Brief description of what this tool does",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.mjs",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"bin": {
|
|
29
|
+
"aiready-yourtool": "./dist/cli.js"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts",
|
|
33
|
+
"dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"lint": "eslint src",
|
|
36
|
+
"clean": "rm -rf dist"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@aiready/core": "workspace:*",
|
|
40
|
+
"commander": "^12.1.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"tsup": "^8.3.5"
|
|
44
|
+
},
|
|
45
|
+
"keywords": ["aiready", "your-keywords"],
|
|
46
|
+
"license": "MIT"
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Implement the Analysis Logic
|
|
51
|
+
|
|
52
|
+
Create `src/analyzer.ts` to contain your core logic.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { scanFiles, readFileContent } from '@aiready/core';
|
|
56
|
+
import type {
|
|
57
|
+
AnalysisResult,
|
|
58
|
+
Issue,
|
|
59
|
+
ScanOptions,
|
|
60
|
+
SpokeOutput,
|
|
61
|
+
} from '@aiready/core';
|
|
62
|
+
|
|
63
|
+
export async function analyzeYourTool(
|
|
64
|
+
options: ScanOptions
|
|
65
|
+
): Promise<SpokeOutput> {
|
|
66
|
+
const files = await scanFiles(options);
|
|
67
|
+
const results: AnalysisResult[] = [];
|
|
68
|
+
|
|
69
|
+
// Your analysis logic here
|
|
70
|
+
// 1. Iterate through files
|
|
71
|
+
// 2. Detect issues
|
|
72
|
+
// 3. Return standardized AnalysisResult[]
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
results,
|
|
76
|
+
summary: {
|
|
77
|
+
totalFiles: files.length,
|
|
78
|
+
totalIssues: results.reduce((acc, r) => acc + r.issues.length, 0),
|
|
79
|
+
// ... other summary stats
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 4. Implement ToolProvider and Register
|
|
86
|
+
|
|
87
|
+
Every spoke must implement the `ToolProvider` interface and register with the global `ToolRegistry` so that it is automatically discovered by the unified CLI.
|
|
88
|
+
|
|
89
|
+
1. **Create `src/provider.ts`**:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import {
|
|
93
|
+
ToolProvider,
|
|
94
|
+
ToolName,
|
|
95
|
+
SpokeOutput,
|
|
96
|
+
ScanOptions,
|
|
97
|
+
ToolScoringOutput,
|
|
98
|
+
} from '@aiready/core';
|
|
99
|
+
import { analyzeYourTool } from './analyzer';
|
|
100
|
+
|
|
101
|
+
export const YourToolProvider: ToolProvider = {
|
|
102
|
+
id: ToolName.YourToolID, // Use an existing ToolName or request a new one
|
|
103
|
+
alias: ['your-alias'],
|
|
104
|
+
|
|
105
|
+
async analyze(options: ScanOptions): Promise<SpokeOutput> {
|
|
106
|
+
const output = await analyzeYourTool(options);
|
|
107
|
+
return {
|
|
108
|
+
...output,
|
|
109
|
+
metadata: { toolName: ToolName.YourToolID, version: '0.1.0' },
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
score(output: SpokeOutput, options: ScanOptions): ToolScoringOutput {
|
|
114
|
+
// Implement scoring logic (0-100)
|
|
115
|
+
return {
|
|
116
|
+
score: 100, // Example
|
|
117
|
+
metrics: output.summary,
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
defaultWeight: 10,
|
|
122
|
+
};
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
2. **Register in `src/index.ts`**:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { ToolRegistry } from '@aiready/core';
|
|
129
|
+
import { YourToolProvider } from './provider';
|
|
130
|
+
|
|
131
|
+
// Register with global registry for automatic CLI discovery
|
|
132
|
+
ToolRegistry.register(YourToolProvider);
|
|
133
|
+
|
|
134
|
+
export { YourToolProvider };
|
|
135
|
+
export * from './analyzer';
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 5. Create Standalone CLI (`src/cli.ts`)
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
#!/usr/bin/env node
|
|
142
|
+
import { Command } from 'commander';
|
|
143
|
+
import { analyzeYourTool } from './analyzer';
|
|
144
|
+
import chalk from 'chalk';
|
|
145
|
+
|
|
146
|
+
const program = new Command();
|
|
147
|
+
|
|
148
|
+
program
|
|
149
|
+
.name('aiready-yourtool')
|
|
150
|
+
.description('Description of your tool')
|
|
151
|
+
.version('0.1.0')
|
|
152
|
+
.argument('<directory>', 'Directory to analyze')
|
|
153
|
+
.action(async (directory, options) => {
|
|
154
|
+
console.log(chalk.blue('🔍 Analyzing...\n'));
|
|
155
|
+
const output = await analyzeYourTool({ rootDir: directory });
|
|
156
|
+
console.log(JSON.stringify(output, null, 2));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
program.parse();
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 📋 Standard Specs to Follow
|
|
163
|
+
|
|
164
|
+
To ensure your tool integrates perfectly with the AIReady ecosystem, it must follow these rules:
|
|
165
|
+
|
|
166
|
+
1. **Standard Options**: Support `--include`, `--exclude`, and `--output` (standardized via `ScanOptions`).
|
|
167
|
+
2. **No Direct Dependencies**: Spokes should never depend on other spokes. Only depend on `@aiready/core`.
|
|
168
|
+
3. **Standard Issue Types**: Use `IssueType` from `@aiready/core` whenever possible.
|
|
169
|
+
4. **Severity Levels**: Use `critical`, `major`, `minor`, and `info`.
|
|
170
|
+
5. **Non-Blocking**: The `analyze` function should be asynchronous and handle large codebases efficiently.
|
|
171
|
+
|
|
172
|
+
## 🧪 Testing
|
|
173
|
+
|
|
174
|
+
Use `vitest` for unit and integration tests. Ensure you test your `ToolProvider` implementation using the `validateSpokeOutput` utility from `@aiready/core`.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { validateSpokeOutput } from '@aiready/core/types/contract';
|
|
178
|
+
|
|
179
|
+
test('output matches AIReady contract', async () => {
|
|
180
|
+
const output = await analyzeYourTool({ rootDir: './test' });
|
|
181
|
+
const validation = validateSpokeOutput('your-tool', output);
|
|
182
|
+
expect(validation.valid).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "Unified CLI for AIReady analysis tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -11,18 +11,18 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"chalk": "^5.3.0",
|
|
13
13
|
"commander": "^14.0.0",
|
|
14
|
+
"@aiready/consistency": "0.19.0",
|
|
14
15
|
"@aiready/clawmart": "0.1.2",
|
|
15
16
|
"@aiready/context-analyzer": "0.20.0",
|
|
16
17
|
"@aiready/agent-grounding": "0.12.0",
|
|
17
|
-
"@aiready/
|
|
18
|
-
"@aiready/core": "0.22.0",
|
|
19
|
-
"@aiready/deps": "0.12.0",
|
|
18
|
+
"@aiready/core": "0.22.1",
|
|
20
19
|
"@aiready/doc-drift": "0.12.0",
|
|
21
20
|
"@aiready/change-amplification": "0.12.0",
|
|
21
|
+
"@aiready/deps": "0.12.0",
|
|
22
22
|
"@aiready/ai-signal-clarity": "0.12.0",
|
|
23
|
-
"@aiready/pattern-detect": "0.15.0",
|
|
24
23
|
"@aiready/visualizer": "0.5.0",
|
|
25
|
-
"@aiready/testability": "0.5.0"
|
|
24
|
+
"@aiready/testability": "0.5.0",
|
|
25
|
+
"@aiready/pattern-detect": "0.15.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^24.0.0",
|