@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.
- package/CONTRIBUTING.md +86 -1
- package/LICENSE +21 -0
- package/README.md +152 -52
- package/dist/cli.js +73 -12
- package/dist/cli.mjs +73 -12
- package/package.json +44 -14
- package/.aiready/aiready-report-20260227-133806.json +0 -7805
- package/.aiready/aiready-report-20260227-133938.json +0 -7951
- package/.aiready/aiready-report-20260228-003433.json +0 -7939
- package/.aiready/aiready-report-20260228-003613.json +0 -771
- package/.aiready/aiready-report-20260314-164626.json +0 -59
- package/.aiready/aiready-report-20260314-164741.json +0 -59
- package/.aiready/aiready-report-20260319-201106.json +0 -5566
- package/.aiready/aiready-report-20260319-201511.json +0 -5566
- package/.aiready/aiready-report-20260319-202017.json +0 -5708
- package/.github/FUNDING.yml +0 -5
- package/.turbo/turbo-build.log +0 -29
- package/.turbo/turbo-lint.log +0 -0
- package/.turbo/turbo-test.log +0 -76
- package/aiready-report.json +0 -30703
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -865
- package/coverage/coverage-final.json +0 -15
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -146
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/commands/agent-grounding.ts.html +0 -271
- package/coverage/src/commands/ai-signal-clarity.ts.html +0 -253
- package/coverage/src/commands/change-amplification.ts.html +0 -94
- package/coverage/src/commands/consistency.ts.html +0 -781
- package/coverage/src/commands/context.ts.html +0 -871
- package/coverage/src/commands/deps-health.ts.html +0 -280
- package/coverage/src/commands/doc-drift.ts.html +0 -271
- package/coverage/src/commands/index.html +0 -281
- package/coverage/src/commands/patterns.ts.html +0 -745
- package/coverage/src/commands/scan.ts.html +0 -1393
- package/coverage/src/commands/testability.ts.html +0 -304
- package/coverage/src/commands/upload.ts.html +0 -466
- package/coverage/src/commands/visualize.ts.html +0 -1027
- package/coverage/src/index.html +0 -116
- package/coverage/src/index.ts.html +0 -1372
- package/coverage/src/utils/helpers.ts.html +0 -559
- package/coverage/src/utils/index.html +0 -116
- package/docs/SPOKE_GUIDE.md +0 -184
- package/packages/core/src/.aiready/aiready-report-20260314-161145.json +0 -224
- package/packages/core/src/.aiready/aiready-report-20260314-161152.json +0 -235
- package/packages/pattern-detect/src/.aiready/aiready-report-20260314-161139.json +0 -224
- package/src/.aiready/aiready-report-20260312-103623.json +0 -32574
- package/src/.aiready/aiready-report-20260312-110843.json +0 -28740
- package/src/.aiready/aiready-report-20260312-110955.json +0 -28740
- package/src/.aiready/aiready-report-20260314-203209.json +0 -30713
- package/src/.aiready/aiready-report-20260314-203736.json +0 -30713
- package/src/.aiready/aiready-report-20260314-203857.json +0 -30713
- package/src/.aiready/aiready-report-20260314-204047.json +0 -30713
- package/src/.aiready/aiready-report-20260318-002110.json +0 -28782
- package/src/__tests__/cli.test.ts +0 -85
- package/src/__tests__/config-shape.test.ts +0 -105
- package/src/__tests__/unified.test.ts +0 -95
- package/src/cli.ts +0 -333
- package/src/commands/__tests__/agent-grounding.test.ts +0 -24
- package/src/commands/__tests__/ai-signal-clarity.test.ts +0 -32
- package/src/commands/__tests__/consistency.test.ts +0 -100
- package/src/commands/__tests__/deps-health.test.ts +0 -26
- package/src/commands/__tests__/doc-drift.test.ts +0 -26
- package/src/commands/__tests__/extra-commands.test.ts +0 -168
- package/src/commands/__tests__/init.test.ts +0 -51
- package/src/commands/__tests__/scan.test.ts +0 -153
- package/src/commands/__tests__/testability.test.ts +0 -36
- package/src/commands/__tests__/upload.test.ts +0 -50
- package/src/commands/__tests__/visualize.test.ts +0 -78
- package/src/commands/agent-grounding.ts +0 -62
- package/src/commands/ai-signal-clarity.ts +0 -1
- package/src/commands/bug.ts +0 -99
- package/src/commands/change-amplification.ts +0 -3
- package/src/commands/consistency.ts +0 -232
- package/src/commands/context.ts +0 -262
- package/src/commands/deps-health.ts +0 -1
- package/src/commands/doc-drift.ts +0 -1
- package/src/commands/index.ts +0 -20
- package/src/commands/init.ts +0 -199
- package/src/commands/patterns.ts +0 -222
- package/src/commands/report-formatter.ts +0 -267
- package/src/commands/scan.ts +0 -432
- package/src/commands/shared/configured-tool-action.ts +0 -35
- package/src/commands/shared/standard-tool-actions.ts +0 -126
- package/src/commands/testability.ts +0 -73
- package/src/commands/upload.ts +0 -129
- package/src/commands/visualize.ts +0 -321
- package/src/index.ts +0 -465
- package/src/utils/__tests__/helpers.test.ts +0 -35
- package/src/utils/helpers.ts +0 -234
- package/tsconfig.json +0 -11
- package/tsconfig.tsbuildinfo +0 -1
- 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
|
-
});
|