@aiready/cli 0.14.10 → 0.14.12

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/dist/cli.mjs CHANGED
@@ -131,13 +131,91 @@ import {
131
131
  getRating,
132
132
  getRatingDisplay
133
133
  } from "@aiready/core";
134
+ function generateProgressBar(score, width = 20) {
135
+ const filled = Math.round(score / 100 * width);
136
+ const empty = width - filled;
137
+ let color = chalk2.red;
138
+ if (score >= 90) color = chalk2.green;
139
+ else if (score >= 75) color = chalk2.cyan;
140
+ else if (score >= 60) color = chalk2.yellow;
141
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
142
+ return color(bar);
143
+ }
144
+ function countIssuesBySeverity(results) {
145
+ let critical = 0;
146
+ let major = 0;
147
+ let minor = 0;
148
+ if (results.summary?.toolsRun) {
149
+ for (const toolId of results.summary.toolsRun) {
150
+ const toolRes = results[toolId];
151
+ if (toolRes?.results) {
152
+ for (const fileRes of toolRes.results) {
153
+ if (fileRes.issues) {
154
+ for (const issue of fileRes.issues) {
155
+ const sev = issue.severity?.toLowerCase();
156
+ if (sev === "critical") critical++;
157
+ else if (sev === "major") major++;
158
+ else minor++;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+ return { critical, major, minor };
166
+ }
167
+ function getTopFilesWithIssues(results, limit = 5) {
168
+ const fileCounts = /* @__PURE__ */ new Map();
169
+ if (results.summary?.toolsRun) {
170
+ for (const toolId of results.summary.toolsRun) {
171
+ const toolRes = results[toolId];
172
+ if (toolRes?.results) {
173
+ for (const fileRes of toolRes.results) {
174
+ if (fileRes.issues?.length > 0) {
175
+ const current = fileCounts.get(fileRes.fileName) || 0;
176
+ fileCounts.set(fileRes.fileName, current + fileRes.issues.length);
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ return Array.from(fileCounts.entries()).map(([file, count]) => ({ file, count })).sort((a, b) => b.count - a.count).slice(0, limit);
183
+ }
134
184
  function printScanSummary(results, startTime) {
185
+ const severity = countIssuesBySeverity(results);
186
+ const totalIssues = severity.critical + severity.major + severity.minor;
187
+ const topFiles = getTopFilesWithIssues(results);
135
188
  console.log(chalk2.cyan("\n=== AIReady Run Summary ==="));
189
+ console.log(` Total issues: ${chalk2.bold(String(totalIssues))}`);
190
+ if (totalIssues > 0) {
191
+ console.log(chalk2.dim(" Severity breakdown:"));
192
+ if (severity.critical > 0) {
193
+ console.log(
194
+ ` ${chalk2.red("\u25CF")} Critical: ${chalk2.bold(severity.critical)}`
195
+ );
196
+ }
197
+ if (severity.major > 0) {
198
+ console.log(
199
+ ` ${chalk2.yellow("\u25CF")} Major: ${chalk2.bold(severity.major)}`
200
+ );
201
+ }
202
+ if (severity.minor > 0) {
203
+ console.log(
204
+ ` ${chalk2.blue("\u25CF")} Minor: ${chalk2.bold(severity.minor)}`
205
+ );
206
+ }
207
+ }
208
+ if (topFiles.length > 0) {
209
+ console.log(chalk2.dim("\n Top files with issues:"));
210
+ topFiles.forEach((item) => {
211
+ console.log(
212
+ ` ${chalk2.yellow("\u2192")} ${item.file}: ${chalk2.bold(item.count)} issues`
213
+ );
214
+ });
215
+ }
136
216
  console.log(
137
- ` Total issues (all tools): ${chalk2.bold(String(results.summary.totalIssues ?? 0))}`
138
- );
139
- console.log(
140
- ` Execution time: ${chalk2.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
217
+ `
218
+ Execution time: ${chalk2.bold(((Date.now() - startTime) / 1e3).toFixed(2) + "s")}`
141
219
  );
142
220
  }
143
221
  function printBusinessImpact(roi, unifiedBudget) {
@@ -164,13 +242,14 @@ function printScoring(scoringResult, scoringProfile) {
164
242
  scoringResult.breakdown.forEach((tool) => {
165
243
  const rating = getRating(tool.score);
166
244
  const emoji = getRatingDisplay(rating).emoji;
245
+ const progressBar = generateProgressBar(tool.score, 15);
167
246
  console.log(
168
- ` - ${tool.toolName}: ${tool.score}/100 (${rating}) ${emoji}`
247
+ ` ${progressBar} ${tool.score}/100 (${rating}) ${emoji} ${tool.toolName}`
169
248
  );
170
249
  });
171
250
  const allRecs = scoringResult.breakdown.flatMap(
172
251
  (t) => (t.recommendations ?? []).map((r) => ({ ...r, tool: t.toolName }))
173
- ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 3);
252
+ ).sort((a, b) => b.estimatedImpact - a.estimatedImpact).slice(0, 5);
174
253
  if (allRecs.length > 0) {
175
254
  console.log(chalk2.bold("\n\u{1F3AF} Top Actionable Recommendations:"));
176
255
  allRecs.forEach((rec, i) => {
@@ -654,6 +733,9 @@ async function initAction(options) {
654
733
  process.exit(1);
655
734
  }
656
735
  const baseConfig = {
736
+ // Target quality score threshold (0-100)
737
+ threshold: 75,
738
+ // Global scan settings
657
739
  scan: {
658
740
  include: [
659
741
  "src/**/*.ts",
@@ -680,80 +762,125 @@ async function initAction(options) {
680
762
  ToolName2.ChangeAmplification
681
763
  ]
682
764
  },
765
+ // Output preferences
766
+ output: {
767
+ format: "console",
768
+ showBreakdown: true,
769
+ saveTo: "aiready-report.json"
770
+ },
771
+ // Scoring profile and weights
772
+ scoring: {
773
+ profile: "balanced"
774
+ },
775
+ // Tool-specific configurations
683
776
  tools: {
684
777
  [ToolName2.PatternDetect]: {
685
778
  minSimilarity: 0.8,
686
779
  minLines: 5,
780
+ minSharedTokens: 10,
781
+ approx: true,
687
782
  ...options.full ? {
688
- batchSize: 50,
689
- approx: true,
690
- minSharedTokens: 10,
691
- maxCandidatesPerBlock: 100
783
+ batchSize: 300,
784
+ maxCandidatesPerBlock: 500,
785
+ minClusterFiles: 3,
786
+ minClusterTokenCost: 1e3
692
787
  } : {}
693
788
  },
694
789
  [ToolName2.ContextAnalyzer]: {
695
790
  maxContextBudget: 128e3,
696
791
  minCohesion: 0.6,
697
- ...options.full ? {
698
- maxDepth: 7,
699
- maxFragmentation: 0.4,
700
- focus: "all",
701
- includeNodeModules: false
702
- } : {}
792
+ maxDepth: 7,
793
+ maxFragmentation: 0.4,
794
+ focus: "all",
795
+ includeNodeModules: false
703
796
  },
704
797
  [ToolName2.NamingConsistency]: {
798
+ checkNaming: true,
799
+ checkPatterns: true,
800
+ checkArchitecture: true,
705
801
  shortWords: ["id", "db", "ui", "ai"],
706
- ...options.full ? { acceptedAbbreviations: [], disableChecks: [] } : {}
802
+ acceptedAbbreviations: [
803
+ "API",
804
+ "JSON",
805
+ "CSV",
806
+ "HTML",
807
+ "CSS",
808
+ "HTTP",
809
+ "URL",
810
+ "SDK",
811
+ "CLI",
812
+ "AI",
813
+ "ML",
814
+ "ID",
815
+ "DB",
816
+ "UI",
817
+ "UX",
818
+ "DOM",
819
+ "UUID",
820
+ "GUID",
821
+ "DEFAULT",
822
+ "MAX",
823
+ "MIN",
824
+ "config",
825
+ "INIT",
826
+ "SKILL",
827
+ "ENV",
828
+ "DEV",
829
+ "PROD",
830
+ "AWS",
831
+ "S3",
832
+ "ARN"
833
+ ],
834
+ ...options.full ? { disableChecks: [] } : {}
707
835
  },
708
836
  [ToolName2.AiSignalClarity]: {
709
837
  checkMagicLiterals: true,
710
838
  checkBooleanTraps: true,
711
839
  checkAmbiguousNames: true,
712
840
  checkUndocumentedExports: true,
713
- ...options.full ? { checkImplicitSideEffects: false, checkDeepCallbacks: false } : {}
841
+ checkImplicitSideEffects: true,
842
+ checkDeepCallbacks: true,
843
+ checkOverloadedSymbols: true,
844
+ checkLargeFiles: true
714
845
  },
715
- ...options.full ? {
716
- [ToolName2.AgentGrounding]: {
717
- maxRecommendedDepth: 5,
718
- readmeStaleDays: 30
719
- },
720
- [ToolName2.TestabilityIndex]: {
721
- minCoverageRatio: 0.7,
722
- testPatterns: ["**/*.test.ts", "**/__tests__/**"]
723
- },
724
- [ToolName2.DocDrift]: {
725
- maxCommits: 50,
726
- staleMonths: 3
727
- },
728
- [ToolName2.DependencyHealth]: {
729
- trainingCutoffYear: 2023
730
- }
731
- } : {}
732
- },
733
- scoring: {
734
- threshold: 70,
735
- showBreakdown: true,
736
- ...options.full ? { profile: "default" } : {}
846
+ [ToolName2.AgentGrounding]: {
847
+ maxRecommendedDepth: 5,
848
+ readmeStaleDays: 30,
849
+ additionalVagueNames: ["stuff", "misc", "temp", "test"]
850
+ },
851
+ [ToolName2.TestabilityIndex]: {
852
+ minCoverageRatio: 0.7,
853
+ testPatterns: ["**/*.test.ts", "**/__tests__/**", "**/*.spec.ts"],
854
+ maxDepth: 10
855
+ },
856
+ [ToolName2.DocDrift]: {
857
+ maxCommits: 50,
858
+ staleMonths: 3
859
+ },
860
+ [ToolName2.DependencyHealth]: {
861
+ trainingCutoffYear: 2023
862
+ },
863
+ [ToolName2.ChangeAmplification]: {
864
+ // Change amplification primarily relies on global scan settings
865
+ }
737
866
  },
738
- ...options.full ? {
739
- visualizer: {
740
- groupingDirs: ["packages", "src", "lib"],
741
- graph: {
742
- maxNodes: 5e3,
743
- maxEdges: 1e4
744
- }
867
+ // Visualizer settings (interactive graph)
868
+ visualizer: {
869
+ groupingDirs: ["packages", "src", "lib"],
870
+ graph: {
871
+ maxNodes: 5e3,
872
+ maxEdges: 1e4
745
873
  }
746
- } : {}
874
+ }
747
875
  };
748
876
  const defaultConfig = baseConfig;
749
877
  let content;
750
878
  if (fileExt === "js") {
751
- content = `/** @type {import('@aiready/core').AIReadyConfig} */
752
- module.exports = ${JSON.stringify(
753
- defaultConfig,
754
- null,
755
- 2
756
- )};
879
+ content = `/**
880
+ * AIReady Configuration
881
+ * @type {import('@aiready/core').AIReadyConfig}
882
+ */
883
+ module.exports = ${JSON.stringify(defaultConfig, null, 2)};
757
884
  `;
758
885
  } else {
759
886
  content = JSON.stringify(defaultConfig, null, 2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/cli",
3
- "version": "0.14.10",
3
+ "version": "0.14.12",
4
4
  "description": "Unified CLI for AIReady analysis tools",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -11,17 +11,17 @@
11
11
  "dependencies": {
12
12
  "chalk": "^5.3.0",
13
13
  "commander": "^14.0.0",
14
- "@aiready/agent-grounding": "0.13.7",
15
- "@aiready/consistency": "0.20.7",
16
- "@aiready/core": "0.23.8",
17
- "@aiready/deps": "0.13.7",
18
- "@aiready/context-analyzer": "0.21.11",
19
- "@aiready/doc-drift": "0.13.7",
20
- "@aiready/change-amplification": "0.13.7",
21
- "@aiready/ai-signal-clarity": "0.13.8",
22
- "@aiready/pattern-detect": "0.16.7",
23
- "@aiready/testability": "0.6.7",
24
- "@aiready/visualizer": "0.6.7"
14
+ "@aiready/consistency": "0.20.9",
15
+ "@aiready/doc-drift": "0.13.9",
16
+ "@aiready/agent-grounding": "0.13.9",
17
+ "@aiready/context-analyzer": "0.21.13",
18
+ "@aiready/change-amplification": "0.13.9",
19
+ "@aiready/core": "0.23.10",
20
+ "@aiready/deps": "0.13.10",
21
+ "@aiready/visualizer": "0.6.9",
22
+ "@aiready/ai-signal-clarity": "0.13.10",
23
+ "@aiready/pattern-detect": "0.16.9",
24
+ "@aiready/testability": "0.6.9"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^24.0.0",
@@ -28,29 +28,24 @@ describe('initAction', () => {
28
28
  }
29
29
  });
30
30
 
31
- it('should generate aiready.json without output field by default', async () => {
31
+ it('should generate aiready.json with output field by default', async () => {
32
32
  await initAction({});
33
33
 
34
34
  expect(existsSync(configPath)).toBe(true);
35
35
  const config = JSON.parse(readFileSync(configPath, 'utf8'));
36
- expect(config).not.toHaveProperty('output');
36
+ expect(config).toHaveProperty('output');
37
+ expect(config.output.format).toBe('console');
37
38
  });
38
39
 
39
- it('should generate aiready.json without output field even with --full flag', async () => {
40
- await initAction({ full: true });
41
-
42
- expect(existsSync(configPath)).toBe(true);
43
- const config = JSON.parse(readFileSync(configPath, 'utf8'));
44
- expect(config).not.toHaveProperty('output');
45
- });
46
-
47
- it('should include scan, tools, and scoring sections', async () => {
40
+ it('should include scan, tools, scoring, and visualizer sections', async () => {
48
41
  await initAction({ full: true });
49
42
 
50
43
  const config = JSON.parse(readFileSync(configPath, 'utf8'));
51
44
  expect(config).toHaveProperty('scan');
52
45
  expect(config).toHaveProperty('tools');
53
46
  expect(config).toHaveProperty('scoring');
47
+ expect(config).toHaveProperty('output');
54
48
  expect(config).toHaveProperty('visualizer');
49
+ expect(config).toHaveProperty('threshold');
55
50
  });
56
51
  });
@@ -20,6 +20,10 @@ export async function initAction(options: {
20
20
  }
21
21
 
22
22
  const baseConfig = {
23
+ // Target quality score threshold (0-100)
24
+ threshold: 75,
25
+
26
+ // Global scan settings
23
27
  scan: {
24
28
  include: [
25
29
  'src/**/*.ts',
@@ -46,93 +50,133 @@ export async function initAction(options: {
46
50
  ToolName.ChangeAmplification,
47
51
  ],
48
52
  },
53
+
54
+ // Output preferences
55
+ output: {
56
+ format: 'console',
57
+ showBreakdown: true,
58
+ saveTo: 'aiready-report.json',
59
+ },
60
+
61
+ // Scoring profile and weights
62
+ scoring: {
63
+ profile: 'balanced',
64
+ },
65
+
66
+ // Tool-specific configurations
49
67
  tools: {
50
68
  [ToolName.PatternDetect]: {
51
69
  minSimilarity: 0.8,
52
70
  minLines: 5,
71
+ minSharedTokens: 10,
72
+ approx: true,
53
73
  ...(options.full
54
74
  ? {
55
- batchSize: 50,
56
- approx: true,
57
- minSharedTokens: 10,
58
- maxCandidatesPerBlock: 100,
75
+ batchSize: 300,
76
+ maxCandidatesPerBlock: 500,
77
+ minClusterFiles: 3,
78
+ minClusterTokenCost: 1000,
59
79
  }
60
80
  : {}),
61
81
  },
62
82
  [ToolName.ContextAnalyzer]: {
63
83
  maxContextBudget: 128000,
64
84
  minCohesion: 0.6,
65
- ...(options.full
66
- ? {
67
- maxDepth: 7,
68
- maxFragmentation: 0.4,
69
- focus: 'all',
70
- includeNodeModules: false,
71
- }
72
- : {}),
85
+ maxDepth: 7,
86
+ maxFragmentation: 0.4,
87
+ focus: 'all',
88
+ includeNodeModules: false,
73
89
  },
74
90
  [ToolName.NamingConsistency]: {
91
+ checkNaming: true,
92
+ checkPatterns: true,
93
+ checkArchitecture: true,
75
94
  shortWords: ['id', 'db', 'ui', 'ai'],
76
- ...(options.full
77
- ? { acceptedAbbreviations: [], disableChecks: [] }
78
- : {}),
95
+ acceptedAbbreviations: [
96
+ 'API',
97
+ 'JSON',
98
+ 'CSV',
99
+ 'HTML',
100
+ 'CSS',
101
+ 'HTTP',
102
+ 'URL',
103
+ 'SDK',
104
+ 'CLI',
105
+ 'AI',
106
+ 'ML',
107
+ 'ID',
108
+ 'DB',
109
+ 'UI',
110
+ 'UX',
111
+ 'DOM',
112
+ 'UUID',
113
+ 'GUID',
114
+ 'DEFAULT',
115
+ 'MAX',
116
+ 'MIN',
117
+ 'config',
118
+ 'INIT',
119
+ 'SKILL',
120
+ 'ENV',
121
+ 'DEV',
122
+ 'PROD',
123
+ 'AWS',
124
+ 'S3',
125
+ 'ARN',
126
+ ],
127
+ ...(options.full ? { disableChecks: [] } : {}),
79
128
  },
80
129
  [ToolName.AiSignalClarity]: {
81
130
  checkMagicLiterals: true,
82
131
  checkBooleanTraps: true,
83
132
  checkAmbiguousNames: true,
84
133
  checkUndocumentedExports: true,
85
- ...(options.full
86
- ? { checkImplicitSideEffects: false, checkDeepCallbacks: false }
87
- : {}),
134
+ checkImplicitSideEffects: true,
135
+ checkDeepCallbacks: true,
136
+ checkOverloadedSymbols: true,
137
+ checkLargeFiles: true,
138
+ },
139
+ [ToolName.AgentGrounding]: {
140
+ maxRecommendedDepth: 5,
141
+ readmeStaleDays: 30,
142
+ additionalVagueNames: ['stuff', 'misc', 'temp', 'test'],
143
+ },
144
+ [ToolName.TestabilityIndex]: {
145
+ minCoverageRatio: 0.7,
146
+ testPatterns: ['**/*.test.ts', '**/__tests__/**', '**/*.spec.ts'],
147
+ maxDepth: 10,
148
+ },
149
+ [ToolName.DocDrift]: {
150
+ maxCommits: 50,
151
+ staleMonths: 3,
152
+ },
153
+ [ToolName.DependencyHealth]: {
154
+ trainingCutoffYear: 2023,
155
+ },
156
+ [ToolName.ChangeAmplification]: {
157
+ // Change amplification primarily relies on global scan settings
88
158
  },
89
- ...(options.full
90
- ? {
91
- [ToolName.AgentGrounding]: {
92
- maxRecommendedDepth: 5,
93
- readmeStaleDays: 30,
94
- },
95
- [ToolName.TestabilityIndex]: {
96
- minCoverageRatio: 0.7,
97
- testPatterns: ['**/*.test.ts', '**/__tests__/**'],
98
- },
99
- [ToolName.DocDrift]: {
100
- maxCommits: 50,
101
- staleMonths: 3,
102
- },
103
- [ToolName.DependencyHealth]: {
104
- trainingCutoffYear: 2023,
105
- },
106
- }
107
- : {}),
108
159
  },
109
- scoring: {
110
- threshold: 70,
111
- showBreakdown: true,
112
- ...(options.full ? { profile: 'default' } : {}),
160
+
161
+ // Visualizer settings (interactive graph)
162
+ visualizer: {
163
+ groupingDirs: ['packages', 'src', 'lib'],
164
+ graph: {
165
+ maxNodes: 5000,
166
+ maxEdges: 10000,
167
+ },
113
168
  },
114
- ...(options.full
115
- ? {
116
- visualizer: {
117
- groupingDirs: ['packages', 'src', 'lib'],
118
- graph: {
119
- maxNodes: 5000,
120
- maxEdges: 10000,
121
- },
122
- },
123
- }
124
- : {}),
125
169
  };
126
170
 
127
171
  const defaultConfig = baseConfig;
128
172
 
129
173
  let content: string;
130
174
  if (fileExt === 'js') {
131
- content = `/** @type {import('@aiready/core').AIReadyConfig} */\nmodule.exports = ${JSON.stringify(
132
- defaultConfig,
133
- null,
134
- 2
135
- )};\n`;
175
+ content = `/**
176
+ * AIReady Configuration
177
+ * @type {import('@aiready/core').AIReadyConfig}
178
+ */
179
+ module.exports = ${JSON.stringify(defaultConfig, null, 2)};\n`;
136
180
  } else {
137
181
  content = JSON.stringify(defaultConfig, null, 2);
138
182
  }