@aiready/cli 0.14.14 → 0.14.16

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.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +86 -1
  2. package/LICENSE +21 -0
  3. package/README.md +152 -52
  4. package/dist/cli.js +73 -12
  5. package/dist/cli.mjs +73 -12
  6. package/package.json +44 -14
  7. package/.aiready/aiready-report-20260227-133806.json +0 -7805
  8. package/.aiready/aiready-report-20260227-133938.json +0 -7951
  9. package/.aiready/aiready-report-20260228-003433.json +0 -7939
  10. package/.aiready/aiready-report-20260228-003613.json +0 -771
  11. package/.aiready/aiready-report-20260314-164626.json +0 -59
  12. package/.aiready/aiready-report-20260314-164741.json +0 -59
  13. package/.aiready/aiready-report-20260319-201106.json +0 -5566
  14. package/.aiready/aiready-report-20260319-201511.json +0 -5566
  15. package/.aiready/aiready-report-20260319-202017.json +0 -5708
  16. package/.github/FUNDING.yml +0 -5
  17. package/.turbo/turbo-build.log +0 -29
  18. package/.turbo/turbo-lint.log +0 -0
  19. package/.turbo/turbo-test.log +0 -76
  20. package/aiready-report.json +0 -30703
  21. package/coverage/base.css +0 -224
  22. package/coverage/block-navigation.js +0 -87
  23. package/coverage/clover.xml +0 -865
  24. package/coverage/coverage-final.json +0 -15
  25. package/coverage/favicon.png +0 -0
  26. package/coverage/index.html +0 -146
  27. package/coverage/prettify.css +0 -1
  28. package/coverage/prettify.js +0 -2
  29. package/coverage/sort-arrow-sprite.png +0 -0
  30. package/coverage/sorter.js +0 -210
  31. package/coverage/src/commands/agent-grounding.ts.html +0 -271
  32. package/coverage/src/commands/ai-signal-clarity.ts.html +0 -253
  33. package/coverage/src/commands/change-amplification.ts.html +0 -94
  34. package/coverage/src/commands/consistency.ts.html +0 -781
  35. package/coverage/src/commands/context.ts.html +0 -871
  36. package/coverage/src/commands/deps-health.ts.html +0 -280
  37. package/coverage/src/commands/doc-drift.ts.html +0 -271
  38. package/coverage/src/commands/index.html +0 -281
  39. package/coverage/src/commands/patterns.ts.html +0 -745
  40. package/coverage/src/commands/scan.ts.html +0 -1393
  41. package/coverage/src/commands/testability.ts.html +0 -304
  42. package/coverage/src/commands/upload.ts.html +0 -466
  43. package/coverage/src/commands/visualize.ts.html +0 -1027
  44. package/coverage/src/index.html +0 -116
  45. package/coverage/src/index.ts.html +0 -1372
  46. package/coverage/src/utils/helpers.ts.html +0 -559
  47. package/coverage/src/utils/index.html +0 -116
  48. package/docs/SPOKE_GUIDE.md +0 -184
  49. package/packages/core/src/.aiready/aiready-report-20260314-161145.json +0 -224
  50. package/packages/core/src/.aiready/aiready-report-20260314-161152.json +0 -235
  51. package/packages/pattern-detect/src/.aiready/aiready-report-20260314-161139.json +0 -224
  52. package/src/.aiready/aiready-report-20260312-103623.json +0 -32574
  53. package/src/.aiready/aiready-report-20260312-110843.json +0 -28740
  54. package/src/.aiready/aiready-report-20260312-110955.json +0 -28740
  55. package/src/.aiready/aiready-report-20260314-203209.json +0 -30713
  56. package/src/.aiready/aiready-report-20260314-203736.json +0 -30713
  57. package/src/.aiready/aiready-report-20260314-203857.json +0 -30713
  58. package/src/.aiready/aiready-report-20260314-204047.json +0 -30713
  59. package/src/.aiready/aiready-report-20260318-002110.json +0 -28782
  60. package/src/__tests__/cli.test.ts +0 -85
  61. package/src/__tests__/config-shape.test.ts +0 -105
  62. package/src/__tests__/unified.test.ts +0 -95
  63. package/src/cli.ts +0 -333
  64. package/src/commands/__tests__/agent-grounding.test.ts +0 -24
  65. package/src/commands/__tests__/ai-signal-clarity.test.ts +0 -32
  66. package/src/commands/__tests__/consistency.test.ts +0 -100
  67. package/src/commands/__tests__/deps-health.test.ts +0 -26
  68. package/src/commands/__tests__/doc-drift.test.ts +0 -26
  69. package/src/commands/__tests__/extra-commands.test.ts +0 -168
  70. package/src/commands/__tests__/init.test.ts +0 -51
  71. package/src/commands/__tests__/scan.test.ts +0 -153
  72. package/src/commands/__tests__/testability.test.ts +0 -36
  73. package/src/commands/__tests__/upload.test.ts +0 -50
  74. package/src/commands/__tests__/visualize.test.ts +0 -78
  75. package/src/commands/agent-grounding.ts +0 -62
  76. package/src/commands/ai-signal-clarity.ts +0 -1
  77. package/src/commands/bug.ts +0 -99
  78. package/src/commands/change-amplification.ts +0 -3
  79. package/src/commands/consistency.ts +0 -232
  80. package/src/commands/context.ts +0 -262
  81. package/src/commands/deps-health.ts +0 -1
  82. package/src/commands/doc-drift.ts +0 -1
  83. package/src/commands/index.ts +0 -20
  84. package/src/commands/init.ts +0 -199
  85. package/src/commands/patterns.ts +0 -222
  86. package/src/commands/report-formatter.ts +0 -267
  87. package/src/commands/scan.ts +0 -432
  88. package/src/commands/shared/configured-tool-action.ts +0 -35
  89. package/src/commands/shared/standard-tool-actions.ts +0 -126
  90. package/src/commands/testability.ts +0 -73
  91. package/src/commands/upload.ts +0 -129
  92. package/src/commands/visualize.ts +0 -321
  93. package/src/index.ts +0 -465
  94. package/src/utils/__tests__/helpers.test.ts +0 -35
  95. package/src/utils/helpers.ts +0 -234
  96. package/tsconfig.json +0 -11
  97. package/tsconfig.tsbuildinfo +0 -1
  98. package/vitest.config.ts +0 -13
@@ -1,100 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { consistencyAction } from '../consistency';
3
- import * as core from '@aiready/core';
4
- import * as fs from 'fs';
5
-
6
- vi.mock('@aiready/core', async () => {
7
- const actual = await vi.importActual('@aiready/core');
8
- return {
9
- ...actual,
10
- loadMergedConfig: vi.fn(),
11
- handleJSONOutput: vi.fn(),
12
- handleCLIError: vi.fn(),
13
- getElapsedTime: vi.fn().mockReturnValue('1.0'),
14
- resolveOutputPath: vi.fn().mockReturnValue('report.json'),
15
- formatToolScore: vi.fn().mockReturnValue('Score: 80'),
16
- };
17
- });
18
-
19
- vi.mock('fs', async () => {
20
- const actual = await vi.importActual('fs');
21
- return {
22
- ...actual,
23
- writeFileSync: vi.fn(),
24
- };
25
- });
26
-
27
- vi.mock('@aiready/consistency', () => ({
28
- analyzeConsistency: vi.fn().mockResolvedValue({
29
- results: [
30
- {
31
- fileName: 'f1.ts',
32
- issues: [
33
- {
34
- category: 'naming',
35
- severity: 'major',
36
- message: 'Bad name',
37
- location: { file: 'f1.ts', line: 1 },
38
- },
39
- ],
40
- },
41
- ],
42
- summary: {
43
- filesAnalyzed: 1,
44
- totalIssues: 1,
45
- namingIssues: 1,
46
- patternIssues: 0,
47
- },
48
- recommendations: ['Fix names'],
49
- }),
50
- calculateConsistencyScore: vi.fn().mockReturnValue({ score: 80 }),
51
- }));
52
-
53
- import { analyzeConsistency } from '@aiready/consistency';
54
-
55
- describe('Consistency CLI Action', () => {
56
- let consoleSpy: any;
57
-
58
- beforeEach(() => {
59
- vi.clearAllMocks();
60
- consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
61
- vi.mocked(core.loadMergedConfig).mockResolvedValue({
62
- output: { format: 'console' },
63
- rootDir: '/test',
64
- });
65
- });
66
-
67
- it('runs consistency analysis and outputs to console', async () => {
68
- await consistencyAction('.', {});
69
- expect(analyzeConsistency).toHaveBeenCalled();
70
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Summary'));
71
- expect(consoleSpy).toHaveBeenCalledWith(
72
- expect.stringContaining('Naming Issues')
73
- );
74
- });
75
-
76
- it('supports JSON output', async () => {
77
- vi.mocked(core.loadMergedConfig).mockResolvedValue({
78
- output: { format: 'json' },
79
- rootDir: '/test',
80
- });
81
- await consistencyAction('.', {});
82
- expect(core.handleJSONOutput).toHaveBeenCalled();
83
- });
84
-
85
- it('supports Markdown output', async () => {
86
- vi.mocked(core.loadMergedConfig).mockResolvedValue({
87
- output: { format: 'markdown' },
88
- rootDir: '/test',
89
- });
90
- await consistencyAction('.', {});
91
- expect(fs.writeFileSync).toHaveBeenCalled();
92
- });
93
-
94
- it('calculates score if requested', async () => {
95
- await consistencyAction('.', { score: true });
96
- expect(consoleSpy).toHaveBeenCalledWith(
97
- expect.stringContaining('AI Readiness Score')
98
- );
99
- });
100
- });
@@ -1,26 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { depsHealthAction } from '../deps-health';
3
-
4
- vi.mock('@aiready/deps', () => ({
5
- analyzeDeps: vi.fn().mockResolvedValue({
6
- summary: { score: 90, rating: 'excellent' },
7
- rawData: {},
8
- recommendations: [],
9
- issues: [],
10
- }),
11
- }));
12
-
13
- vi.mock('@aiready/core', () => ({
14
- loadConfig: vi.fn().mockResolvedValue({}),
15
- mergeConfigWithDefaults: vi
16
- .fn()
17
- .mockImplementation((c, d) => ({ ...d, ...c })),
18
- }));
19
-
20
- describe('Deps Health CLI Action', () => {
21
- it('should run analysis and return scoring', async () => {
22
- const result = await depsHealthAction('.', { output: 'json' });
23
- expect(result?.toolName).toBe('dependency-health');
24
- expect(result?.score).toBe(90);
25
- });
26
- });
@@ -1,26 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { docDriftAction } from '../doc-drift';
3
-
4
- vi.mock('@aiready/doc-drift', () => ({
5
- analyzeDocDrift: vi.fn().mockResolvedValue({
6
- summary: { score: 20, rating: 'low' },
7
- rawData: {},
8
- recommendations: ['Update docs'],
9
- issues: [],
10
- }),
11
- }));
12
-
13
- vi.mock('@aiready/core', () => ({
14
- loadConfig: vi.fn().mockResolvedValue({}),
15
- mergeConfigWithDefaults: vi
16
- .fn()
17
- .mockImplementation((c, d) => ({ ...d, ...c })),
18
- }));
19
-
20
- describe('Doc Drift CLI Action', () => {
21
- it('should run analysis and return scoring', async () => {
22
- const result = await docDriftAction('.', { output: 'json' });
23
- expect(result?.toolName).toBe('doc-drift');
24
- expect(result?.score).toBe(20);
25
- });
26
- });
@@ -1,168 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { changeAmplificationAction } from '../change-amplification';
3
- import { agentGroundingAction } from '../agent-grounding';
4
- import { aiSignalClarityAction } from '../ai-signal-clarity';
5
- import { docDriftAction } from '../doc-drift';
6
- import { testabilityAction } from '../testability';
7
- import { depsHealthAction } from '../deps-health';
8
- import { patternsAction } from '../patterns';
9
- import { contextAction } from '../context';
10
-
11
- vi.mock('@aiready/core', async () => {
12
- const actual = await vi.importActual('@aiready/core');
13
- return {
14
- ...actual,
15
- loadConfig: vi.fn().mockResolvedValue({}),
16
- mergeConfigWithDefaults: vi
17
- .fn()
18
- .mockImplementation((c, d) => ({ ...d, ...c })),
19
- loadMergedConfig: vi.fn().mockResolvedValue({
20
- rootDir: '/test',
21
- output: { format: 'console' },
22
- checkNaming: true,
23
- checkPatterns: true,
24
- }),
25
- handleJSONOutput: vi.fn(),
26
- handleCLIError: vi.fn(),
27
- getElapsedTime: vi.fn().mockReturnValue('1.0'),
28
- resolveOutputPath: vi.fn().mockReturnValue('report.json'),
29
- formatToolScore: vi.fn().mockReturnValue('Score: 80'),
30
- };
31
- });
32
-
33
- // Mock all spokes
34
- vi.mock('@aiready/change-amplification', () => ({
35
- analyzeChangeAmplification: vi.fn().mockResolvedValue({
36
- results: [],
37
- summary: { rating: 'contained' },
38
- recommendations: [],
39
- }),
40
- calculateChangeAmplificationScore: vi.fn().mockReturnValue({ score: 80 }),
41
- }));
42
- vi.mock('@aiready/agent-grounding', () => ({
43
- analyzeAgentGrounding: vi.fn().mockResolvedValue({
44
- results: [],
45
- summary: {
46
- rating: 'grounded',
47
- dimensions: { structure: 80, metadata: 80 },
48
- },
49
- recommendations: [],
50
- }),
51
- calculateGroundingScore: vi.fn().mockReturnValue({ score: 80 }),
52
- }));
53
- vi.mock('@aiready/ai-signal-clarity', () => ({
54
- analyzeAiSignalClarity: vi.fn().mockResolvedValue({
55
- results: [],
56
- summary: { rating: 'clear', topRisk: 'none' },
57
- recommendations: [],
58
- }),
59
- calculateAiSignalClarityScore: vi.fn().mockReturnValue({ score: 80 }),
60
- }));
61
- vi.mock('@aiready/doc-drift', () => ({
62
- analyzeDocDrift: vi.fn().mockResolvedValue({
63
- results: [],
64
- summary: { rating: 'fresh' },
65
- issues: [],
66
- rawData: {},
67
- recommendations: [],
68
- }),
69
- calculateDocDriftScore: vi.fn().mockReturnValue({ score: 80 }),
70
- }));
71
- vi.mock('@aiready/testability', () => ({
72
- analyzeTestability: vi.fn().mockResolvedValue({
73
- results: [],
74
- summary: { rating: 'testable', aiChangeSafetyRating: 'safe' },
75
- rawData: {},
76
- recommendations: [],
77
- }),
78
- calculateTestabilityScore: vi.fn().mockReturnValue({ score: 80 }),
79
- }));
80
- vi.mock('@aiready/deps', () => ({
81
- analyzeDeps: vi.fn().mockResolvedValue({
82
- results: [],
83
- summary: { packagesAnalyzed: 0, filesAnalyzed: 0, rating: 'healthy' },
84
- issues: [],
85
- rawData: {},
86
- recommendations: [],
87
- }),
88
- calculateDepsScore: vi.fn().mockReturnValue({ score: 80 }),
89
- }));
90
- vi.mock('@aiready/pattern-detect', () => ({
91
- analyzePatterns: vi.fn().mockResolvedValue({
92
- results: [],
93
- summary: { totalPatterns: 0 },
94
- config: {},
95
- }),
96
- generateSummary: vi.fn().mockReturnValue({
97
- totalPatterns: 0,
98
- totalTokenCost: 0,
99
- patternsByType: {},
100
- topDuplicates: [],
101
- }),
102
- getSmartDefaults: vi.fn().mockResolvedValue({}),
103
- }));
104
- vi.mock('@aiready/context-analyzer', () => ({
105
- analyzeContext: vi.fn().mockResolvedValue([]),
106
- generateSummary: vi.fn().mockReturnValue({
107
- score: 80,
108
- rating: 'good',
109
- totalFiles: 0,
110
- totalTokens: 0,
111
- avgImportDepth: 0,
112
- maxImportDepth: 0,
113
- avgFragmentation: 0,
114
- criticalIssues: 0,
115
- majorIssues: 0,
116
- totalPotentialSavings: 0,
117
- }),
118
- getSmartDefaults: vi.fn().mockResolvedValue({}),
119
- }));
120
-
121
- describe('Extra CLI Actions', () => {
122
- let consoleSpy: any;
123
-
124
- beforeEach(() => {
125
- vi.clearAllMocks();
126
- consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
127
- });
128
-
129
- it('runs change-amplification', async () => {
130
- await changeAmplificationAction('.', {});
131
- expect(consoleSpy).toHaveBeenCalled();
132
- });
133
-
134
- it('runs agent-grounding', async () => {
135
- await agentGroundingAction('.', {});
136
- expect(consoleSpy).toHaveBeenCalled();
137
- });
138
-
139
- it('runs ai-signal-clarity', async () => {
140
- await aiSignalClarityAction('.', {});
141
- expect(consoleSpy).toHaveBeenCalled();
142
- });
143
-
144
- it('runs doc-drift', async () => {
145
- await docDriftAction('.', {});
146
- expect(consoleSpy).toHaveBeenCalled();
147
- });
148
-
149
- it('runs testability', async () => {
150
- await testabilityAction('.', {});
151
- expect(consoleSpy).toHaveBeenCalled();
152
- });
153
-
154
- it('runs deps-health', async () => {
155
- await depsHealthAction('.', {});
156
- expect(consoleSpy).toHaveBeenCalled();
157
- });
158
-
159
- it('runs patterns', async () => {
160
- await patternsAction('.', {});
161
- expect(consoleSpy).toHaveBeenCalled();
162
- });
163
-
164
- it('runs context', async () => {
165
- await contextAction('.', {});
166
- expect(consoleSpy).toHaveBeenCalled();
167
- });
168
- });
@@ -1,51 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { existsSync, readFileSync, unlinkSync, mkdirSync, rmSync } from 'fs';
3
- import { join } from 'path';
4
- import { initAction } from '../init';
5
-
6
- describe('initAction', () => {
7
- const testDir = join(process.cwd(), 'temp-test-init');
8
- const configPath = join(testDir, 'aiready.json');
9
-
10
- beforeEach(() => {
11
- if (!existsSync(testDir)) {
12
- mkdirSync(testDir, { recursive: true });
13
- }
14
- // Mock process.cwd to use our test directory
15
- vi.spyOn(process, 'cwd').mockReturnValue(testDir);
16
- // Mock console.log to avoid noise
17
- vi.spyOn(console, 'log').mockImplementation(() => {});
18
- vi.spyOn(console, 'error').mockImplementation(() => {});
19
- });
20
-
21
- afterEach(() => {
22
- vi.restoreAllMocks();
23
- if (existsSync(configPath)) {
24
- unlinkSync(configPath);
25
- }
26
- if (existsSync(testDir)) {
27
- rmSync(testDir, { recursive: true, force: true });
28
- }
29
- });
30
-
31
- it('should generate aiready.json with output field by default', async () => {
32
- await initAction({});
33
-
34
- expect(existsSync(configPath)).toBe(true);
35
- const config = JSON.parse(readFileSync(configPath, 'utf8'));
36
- expect(config).toHaveProperty('output');
37
- expect(config.output.format).toBe('console');
38
- });
39
-
40
- it('should include scan, tools, scoring, and visualizer sections', async () => {
41
- await initAction({ full: true });
42
-
43
- const config = JSON.parse(readFileSync(configPath, 'utf8'));
44
- expect(config).toHaveProperty('scan');
45
- expect(config).toHaveProperty('tools');
46
- expect(config).toHaveProperty('scoring');
47
- expect(config).toHaveProperty('output');
48
- expect(config).toHaveProperty('visualizer');
49
- expect(config).toHaveProperty('threshold');
50
- });
51
- });
@@ -1,153 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { scanAction } from '../scan';
3
- import * as core from '@aiready/core';
4
- import * as index from '../../index';
5
- import * as upload from '../upload';
6
- import { readFileSync } from 'fs';
7
- import { Severity } from '@aiready/core';
8
-
9
- vi.mock('../../index', () => ({
10
- analyzeUnified: vi.fn(),
11
- scoreUnified: vi.fn(),
12
- }));
13
-
14
- vi.mock('../upload', () => ({
15
- uploadAction: vi.fn(),
16
- }));
17
-
18
- vi.mock('@aiready/core', async () => {
19
- const actual = await vi.importActual('@aiready/core');
20
- return {
21
- ...actual,
22
- loadMergedConfig: vi.fn(),
23
- loadConfig: vi.fn(),
24
- getRepoMetadata: vi.fn().mockReturnValue({ name: 'test-repo' }),
25
- handleJSONOutput: vi.fn(),
26
- handleCLIError: vi.fn(),
27
- getElapsedTime: vi.fn().mockReturnValue('1.0'),
28
- resolveOutputPath: vi.fn().mockReturnValue('report.json'),
29
- formatScore: vi.fn().mockReturnValue('80/100'),
30
- calculateTokenBudget: vi.fn().mockReturnValue({
31
- efficiencyRatio: 0.8,
32
- wastedTokens: {
33
- total: 100,
34
- bySource: { duplication: 50, fragmentation: 50 },
35
- },
36
- totalContextTokens: 1000,
37
- }),
38
- calculateBusinessROI: vi.fn().mockReturnValue({
39
- monthlySavings: 500,
40
- productivityGainHours: 20,
41
- annualValue: 6000,
42
- }),
43
- };
44
- });
45
-
46
- vi.mock('fs', () => ({
47
- writeFileSync: vi.fn(),
48
- readFileSync: vi.fn(),
49
- existsSync: vi.fn().mockReturnValue(true),
50
- }));
51
-
52
- describe('Scan CLI Action', () => {
53
- let consoleSpy: any;
54
-
55
- beforeEach(() => {
56
- vi.clearAllMocks();
57
- consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
58
- vi.mocked(core.loadMergedConfig).mockResolvedValue({
59
- tools: ['pattern-detect'],
60
- output: { format: 'console' },
61
- rootDir: '/test',
62
- });
63
- vi.mocked(index.analyzeUnified).mockResolvedValue({
64
- summary: {
65
- totalIssues: 5,
66
- toolsRun: ['pattern-detect'],
67
- totalFiles: 10,
68
- executionTime: 1000,
69
- },
70
- 'pattern-detect': {
71
- results: [
72
- {
73
- fileName: 'f1.ts',
74
- issues: [
75
- { severity: Severity.Critical },
76
- { severity: Severity.Major },
77
- ],
78
- },
79
- ],
80
- },
81
- } as any);
82
- vi.mocked(index.scoreUnified).mockResolvedValue({
83
- overall: 80,
84
- breakdown: [
85
- {
86
- toolName: 'pattern-detect',
87
- score: 80,
88
- tokenBudget: {
89
- totalContextTokens: 1000,
90
- wastedTokens: { bySource: { duplication: 50, fragmentation: 50 } },
91
- },
92
- },
93
- ],
94
- } as any);
95
- });
96
-
97
- it('runs standard scan with scoring', async () => {
98
- await scanAction('.', { score: true });
99
- expect(index.analyzeUnified).toHaveBeenCalled();
100
- expect(index.scoreUnified).toHaveBeenCalled();
101
- expect(consoleSpy).toHaveBeenCalledWith(
102
- expect.stringContaining('AI Readiness Overall Score')
103
- );
104
- });
105
-
106
- it('handles profiles correctly', async () => {
107
- await scanAction('.', { profile: 'agentic' });
108
- expect(core.loadMergedConfig).toHaveBeenCalled();
109
- });
110
-
111
- it('compares with previous report', async () => {
112
- vi.mocked(readFileSync).mockReturnValue(
113
- JSON.stringify({ scoring: { overall: 70 } })
114
- );
115
- await scanAction('.', { compareTo: 'prev.json', score: true });
116
- expect(consoleSpy).toHaveBeenCalledWith(
117
- expect.stringContaining('Trend: +10')
118
- );
119
- });
120
-
121
- it('handles CI failure on critical issues', async () => {
122
- const exitSpy = vi
123
- .spyOn(process, 'exit')
124
- .mockImplementation((() => {}) as any);
125
-
126
- await scanAction('.', { ci: true, failOn: 'critical', score: true });
127
-
128
- expect(exitSpy).toHaveBeenCalledWith(1);
129
- expect(consoleSpy).toHaveBeenCalledWith(
130
- expect.stringContaining('SCAN FAILED')
131
- );
132
- // Verify annotations are emitted
133
- expect(consoleSpy).toHaveBeenCalledWith(
134
- expect.stringContaining('Emitting GitHub Action annotations')
135
- );
136
- exitSpy.mockRestore();
137
- });
138
-
139
- it('handles upload flag', async () => {
140
- await scanAction('.', { upload: true, apiKey: 'test-key' });
141
- expect(upload.uploadAction).toHaveBeenCalled();
142
- });
143
-
144
- it('supports JSON output format', async () => {
145
- vi.mocked(core.loadMergedConfig).mockResolvedValue({
146
- tools: ['pattern-detect'],
147
- output: { format: 'json', file: 'out.json' },
148
- rootDir: '/test',
149
- });
150
- await scanAction('.', {});
151
- expect(core.handleJSONOutput).toHaveBeenCalled();
152
- });
153
- });
@@ -1,36 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { testabilityAction } from '../testability';
3
-
4
- vi.mock('@aiready/testability', () => ({
5
- analyzeTestability: vi.fn().mockResolvedValue({
6
- summary: {
7
- score: 80,
8
- rating: 'good',
9
- aiChangeSafetyRating: 'safe',
10
- coverageRatio: 0.5,
11
- },
12
- rawData: { testFiles: 5, sourceFiles: 10 },
13
- }),
14
- calculateTestabilityScore: vi.fn().mockReturnValue({ score: 80 }),
15
- }));
16
-
17
- vi.mock('@aiready/core', () => ({
18
- loadConfig: vi.fn().mockResolvedValue({}),
19
- mergeConfigWithDefaults: vi
20
- .fn()
21
- .mockImplementation((c, d) => ({ ...d, ...c })),
22
- }));
23
-
24
- describe('Testability CLI Action', () => {
25
- it('should run analysis and return scoring in json mode', async () => {
26
- const result = await testabilityAction('.', { output: 'json' });
27
- expect(result?.score).toBe(80);
28
- });
29
-
30
- it('should run analysis and print to console in default mode', async () => {
31
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
32
- await testabilityAction('.', { output: 'console' });
33
- expect(consoleSpy).toHaveBeenCalled();
34
- consoleSpy.mockRestore();
35
- });
36
- });
@@ -1,50 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { uploadAction } from '../upload';
3
-
4
- vi.mock('fs', () => ({
5
- default: {
6
- existsSync: vi.fn().mockReturnValue(true),
7
- readFileSync: vi.fn().mockReturnValue('{"test": true}'),
8
- },
9
- }));
10
-
11
- vi.mock('@aiready/core', () => ({
12
- handleCLIError: vi.fn(),
13
- }));
14
-
15
- describe('Upload CLI Action', () => {
16
- beforeEach(() => {
17
- vi.stubGlobal(
18
- 'fetch',
19
- vi.fn().mockResolvedValue({
20
- ok: true,
21
- headers: { get: () => 'application/json' },
22
- json: () =>
23
- Promise.resolve({
24
- success: true,
25
- analysis: { id: '123', aiScore: 80 },
26
- }),
27
- })
28
- );
29
- vi.stubGlobal('process', {
30
- ...process,
31
- exit: vi.fn(),
32
- });
33
- });
34
-
35
- it('should upload report successfully', async () => {
36
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
37
- await uploadAction('report.json', { apiKey: 'test-key' });
38
- expect(consoleSpy).toHaveBeenCalledWith(
39
- expect.stringContaining('Upload successful')
40
- );
41
- consoleSpy.mockRestore();
42
- });
43
-
44
- it('should fail if API key is missing', async () => {
45
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
46
- await uploadAction('report.json', {});
47
- expect(process.exit).toHaveBeenCalledWith(1);
48
- consoleSpy.mockRestore();
49
- });
50
- });
@@ -1,78 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { visualizeAction } from '../visualize';
3
- import * as fs from 'fs';
4
- import * as core from '@aiready/core';
5
- import { spawn } from 'child_process';
6
-
7
- vi.mock('fs', async () => {
8
- const actual = await vi.importActual('fs');
9
- return {
10
- ...actual,
11
- readFileSync: vi.fn(),
12
- existsSync: vi.fn(),
13
- writeFileSync: vi.fn(),
14
- copyFileSync: vi.fn(),
15
- };
16
- });
17
-
18
- vi.mock('child_process', () => ({
19
- spawn: vi.fn().mockReturnValue({ on: vi.fn(), kill: vi.fn() }),
20
- }));
21
-
22
- vi.mock('@aiready/visualizer/graph', () => ({
23
- GraphBuilder: {
24
- buildFromReport: vi.fn().mockReturnValue({ nodes: [], edges: [] }),
25
- },
26
- }));
27
-
28
- vi.mock('@aiready/core', () => ({
29
- handleCLIError: vi.fn(),
30
- generateHTML: vi.fn().mockReturnValue('<html></html>'),
31
- findLatestReport: vi.fn(),
32
- }));
33
-
34
- describe('Visualize CLI Action', () => {
35
- beforeEach(() => {
36
- vi.clearAllMocks();
37
- vi.spyOn(fs, 'existsSync').mockReturnValue(true);
38
- vi.spyOn(fs, 'readFileSync').mockReturnValue(
39
- JSON.stringify({ scoring: { overall: 80 } })
40
- );
41
- });
42
-
43
- it('should generate HTML from specified report', async () => {
44
- await visualizeAction('.', { report: 'report.json' });
45
- expect(fs.writeFileSync).toHaveBeenCalledWith(
46
- expect.stringContaining('visualization.html'),
47
- '<html></html>',
48
- 'utf8'
49
- );
50
- });
51
-
52
- it('should find latest report if none specified', async () => {
53
- vi.mocked(core.findLatestReport).mockReturnValue('latest.json');
54
- await visualizeAction('.', {});
55
- expect(fs.readFileSync).toHaveBeenCalledWith(
56
- expect.stringContaining('latest.json'),
57
- 'utf8'
58
- );
59
- });
60
-
61
- it('should handle missing reports', async () => {
62
- vi.spyOn(fs, 'existsSync').mockReturnValue(false);
63
- vi.mocked(core.findLatestReport).mockReturnValue(null);
64
- const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
65
-
66
- await visualizeAction('.', { report: 'missing.json' });
67
-
68
- expect(consoleSpy).toHaveBeenCalledWith(
69
- expect.stringContaining('No AI readiness report found')
70
- );
71
- consoleSpy.mockRestore();
72
- });
73
-
74
- it('should attempt to open visualization if requested', async () => {
75
- await visualizeAction('.', { report: 'report.json', open: true });
76
- expect(spawn).toHaveBeenCalled();
77
- });
78
- });