@aiready/cli 0.14.14 → 0.14.15

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 (95) hide show
  1. package/CONTRIBUTING.md +86 -1
  2. package/LICENSE +21 -0
  3. package/package.json +33 -12
  4. package/.aiready/aiready-report-20260227-133806.json +0 -7805
  5. package/.aiready/aiready-report-20260227-133938.json +0 -7951
  6. package/.aiready/aiready-report-20260228-003433.json +0 -7939
  7. package/.aiready/aiready-report-20260228-003613.json +0 -771
  8. package/.aiready/aiready-report-20260314-164626.json +0 -59
  9. package/.aiready/aiready-report-20260314-164741.json +0 -59
  10. package/.aiready/aiready-report-20260319-201106.json +0 -5566
  11. package/.aiready/aiready-report-20260319-201511.json +0 -5566
  12. package/.aiready/aiready-report-20260319-202017.json +0 -5708
  13. package/.github/FUNDING.yml +0 -5
  14. package/.turbo/turbo-build.log +0 -29
  15. package/.turbo/turbo-lint.log +0 -0
  16. package/.turbo/turbo-test.log +0 -76
  17. package/aiready-report.json +0 -30703
  18. package/coverage/base.css +0 -224
  19. package/coverage/block-navigation.js +0 -87
  20. package/coverage/clover.xml +0 -865
  21. package/coverage/coverage-final.json +0 -15
  22. package/coverage/favicon.png +0 -0
  23. package/coverage/index.html +0 -146
  24. package/coverage/prettify.css +0 -1
  25. package/coverage/prettify.js +0 -2
  26. package/coverage/sort-arrow-sprite.png +0 -0
  27. package/coverage/sorter.js +0 -210
  28. package/coverage/src/commands/agent-grounding.ts.html +0 -271
  29. package/coverage/src/commands/ai-signal-clarity.ts.html +0 -253
  30. package/coverage/src/commands/change-amplification.ts.html +0 -94
  31. package/coverage/src/commands/consistency.ts.html +0 -781
  32. package/coverage/src/commands/context.ts.html +0 -871
  33. package/coverage/src/commands/deps-health.ts.html +0 -280
  34. package/coverage/src/commands/doc-drift.ts.html +0 -271
  35. package/coverage/src/commands/index.html +0 -281
  36. package/coverage/src/commands/patterns.ts.html +0 -745
  37. package/coverage/src/commands/scan.ts.html +0 -1393
  38. package/coverage/src/commands/testability.ts.html +0 -304
  39. package/coverage/src/commands/upload.ts.html +0 -466
  40. package/coverage/src/commands/visualize.ts.html +0 -1027
  41. package/coverage/src/index.html +0 -116
  42. package/coverage/src/index.ts.html +0 -1372
  43. package/coverage/src/utils/helpers.ts.html +0 -559
  44. package/coverage/src/utils/index.html +0 -116
  45. package/docs/SPOKE_GUIDE.md +0 -184
  46. package/packages/core/src/.aiready/aiready-report-20260314-161145.json +0 -224
  47. package/packages/core/src/.aiready/aiready-report-20260314-161152.json +0 -235
  48. package/packages/pattern-detect/src/.aiready/aiready-report-20260314-161139.json +0 -224
  49. package/src/.aiready/aiready-report-20260312-103623.json +0 -32574
  50. package/src/.aiready/aiready-report-20260312-110843.json +0 -28740
  51. package/src/.aiready/aiready-report-20260312-110955.json +0 -28740
  52. package/src/.aiready/aiready-report-20260314-203209.json +0 -30713
  53. package/src/.aiready/aiready-report-20260314-203736.json +0 -30713
  54. package/src/.aiready/aiready-report-20260314-203857.json +0 -30713
  55. package/src/.aiready/aiready-report-20260314-204047.json +0 -30713
  56. package/src/.aiready/aiready-report-20260318-002110.json +0 -28782
  57. package/src/__tests__/cli.test.ts +0 -85
  58. package/src/__tests__/config-shape.test.ts +0 -105
  59. package/src/__tests__/unified.test.ts +0 -95
  60. package/src/cli.ts +0 -333
  61. package/src/commands/__tests__/agent-grounding.test.ts +0 -24
  62. package/src/commands/__tests__/ai-signal-clarity.test.ts +0 -32
  63. package/src/commands/__tests__/consistency.test.ts +0 -100
  64. package/src/commands/__tests__/deps-health.test.ts +0 -26
  65. package/src/commands/__tests__/doc-drift.test.ts +0 -26
  66. package/src/commands/__tests__/extra-commands.test.ts +0 -168
  67. package/src/commands/__tests__/init.test.ts +0 -51
  68. package/src/commands/__tests__/scan.test.ts +0 -153
  69. package/src/commands/__tests__/testability.test.ts +0 -36
  70. package/src/commands/__tests__/upload.test.ts +0 -50
  71. package/src/commands/__tests__/visualize.test.ts +0 -78
  72. package/src/commands/agent-grounding.ts +0 -62
  73. package/src/commands/ai-signal-clarity.ts +0 -1
  74. package/src/commands/bug.ts +0 -99
  75. package/src/commands/change-amplification.ts +0 -3
  76. package/src/commands/consistency.ts +0 -232
  77. package/src/commands/context.ts +0 -262
  78. package/src/commands/deps-health.ts +0 -1
  79. package/src/commands/doc-drift.ts +0 -1
  80. package/src/commands/index.ts +0 -20
  81. package/src/commands/init.ts +0 -199
  82. package/src/commands/patterns.ts +0 -222
  83. package/src/commands/report-formatter.ts +0 -267
  84. package/src/commands/scan.ts +0 -432
  85. package/src/commands/shared/configured-tool-action.ts +0 -35
  86. package/src/commands/shared/standard-tool-actions.ts +0 -126
  87. package/src/commands/testability.ts +0 -73
  88. package/src/commands/upload.ts +0 -129
  89. package/src/commands/visualize.ts +0 -321
  90. package/src/index.ts +0 -465
  91. package/src/utils/__tests__/helpers.test.ts +0 -35
  92. package/src/utils/helpers.ts +0 -234
  93. package/tsconfig.json +0 -11
  94. package/tsconfig.tsbuildinfo +0 -1
  95. 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
- });