@aiready/cli 0.12.19 → 0.12.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/.turbo/turbo-lint.log +24 -5
- package/.turbo/turbo-test.log +66 -121
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +865 -0
- package/coverage/coverage-final.json +15 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +146 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/commands/agent-grounding.ts.html +271 -0
- package/coverage/src/commands/ai-signal-clarity.ts.html +253 -0
- package/coverage/src/commands/change-amplification.ts.html +94 -0
- package/coverage/src/commands/consistency.ts.html +781 -0
- package/coverage/src/commands/context.ts.html +871 -0
- package/coverage/src/commands/deps-health.ts.html +280 -0
- package/coverage/src/commands/doc-drift.ts.html +271 -0
- package/coverage/src/commands/index.html +281 -0
- package/coverage/src/commands/patterns.ts.html +745 -0
- package/coverage/src/commands/scan.ts.html +1393 -0
- package/coverage/src/commands/testability.ts.html +304 -0
- package/coverage/src/commands/upload.ts.html +466 -0
- package/coverage/src/commands/visualize.ts.html +1027 -0
- package/coverage/src/index.html +116 -0
- package/coverage/src/index.ts.html +1372 -0
- package/coverage/src/utils/helpers.ts.html +559 -0
- package/coverage/src/utils/index.html +116 -0
- package/dist/cli.js +249 -15
- package/dist/cli.mjs +247 -13
- package/package.json +13 -12
- package/src/.aiready/aiready-report-20260308-174006.json +29526 -0
- package/src/__tests__/unified.test.ts +95 -0
- package/src/cli.ts +86 -0
- package/src/commands/__tests__/agent-grounding.test.ts +24 -0
- package/src/commands/__tests__/ai-signal-clarity.test.ts +32 -0
- package/src/commands/__tests__/consistency.test.ts +97 -0
- package/src/commands/__tests__/deps-health.test.ts +26 -0
- package/src/commands/__tests__/doc-drift.test.ts +26 -0
- package/src/commands/__tests__/extra-commands.test.ts +177 -0
- package/src/commands/__tests__/scan.test.ts +147 -0
- package/src/commands/__tests__/testability.test.ts +36 -0
- package/src/commands/__tests__/upload.test.ts +51 -0
- package/src/commands/__tests__/visualize.test.ts +82 -0
- package/src/commands/clawmart.ts +162 -0
- package/src/commands/index.ts +8 -0
- package/src/commands/scan.ts +33 -11
- package/src/utils/__tests__/helpers.test.ts +35 -0
- package/vitest.config.ts +20 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { analyzeUnified, scoreUnified, generateUnifiedSummary } from '../index';
|
|
3
|
+
import { ToolRegistry, ToolName } from '@aiready/core';
|
|
4
|
+
|
|
5
|
+
vi.mock('@aiready/core', async () => {
|
|
6
|
+
const actual = await vi.importActual('@aiready/core');
|
|
7
|
+
return {
|
|
8
|
+
...actual,
|
|
9
|
+
initializeParsers: vi.fn().mockResolvedValue(undefined),
|
|
10
|
+
calculateOverallScore: vi
|
|
11
|
+
.fn()
|
|
12
|
+
.mockReturnValue({ overall: 85, breakdown: [] }),
|
|
13
|
+
calculateTokenBudget: vi.fn().mockReturnValue({}),
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('Unified CLI logic', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('analyzeUnified', () => {
|
|
23
|
+
it('should run multiple tools and aggregate results', async () => {
|
|
24
|
+
const mockProvider1 = {
|
|
25
|
+
id: 'tool1',
|
|
26
|
+
analyze: vi.fn().mockResolvedValue({
|
|
27
|
+
results: [{ fileName: 'f1.ts', issues: [{}, {}] }],
|
|
28
|
+
summary: { totalFiles: 1 },
|
|
29
|
+
}),
|
|
30
|
+
score: vi.fn(),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
vi.spyOn(ToolRegistry, 'find').mockImplementation((id) => {
|
|
34
|
+
if (id === 'tool1') return mockProvider1 as any;
|
|
35
|
+
return null;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const options = {
|
|
39
|
+
rootDir: '.',
|
|
40
|
+
tools: ['tool1'],
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const result = await analyzeUnified(options as any);
|
|
44
|
+
expect(result.summary.totalIssues).toBe(2);
|
|
45
|
+
expect(result.summary.toolsRun).toContain('tool1');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('scoreUnified', () => {
|
|
50
|
+
it('should score results from multiple tools', async () => {
|
|
51
|
+
const mockProvider = {
|
|
52
|
+
id: 'tool1',
|
|
53
|
+
score: vi.fn().mockReturnValue({ score: 80 }),
|
|
54
|
+
};
|
|
55
|
+
vi.spyOn(ToolRegistry, 'get').mockReturnValue(mockProvider as any);
|
|
56
|
+
|
|
57
|
+
const results = {
|
|
58
|
+
summary: { toolsRun: ['tool1'] },
|
|
59
|
+
tool1: { results: [] },
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const score = await scoreUnified(results as any, { rootDir: '.' } as any);
|
|
63
|
+
expect(score.overall).toBe(85); // From mocked calculateOverallScore
|
|
64
|
+
expect(mockProvider.score).toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should handle empty tools', async () => {
|
|
68
|
+
const results = { summary: { toolsRun: [] } };
|
|
69
|
+
const score = await scoreUnified(results as any, { rootDir: '.' } as any);
|
|
70
|
+
expect(score.overall).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('generateUnifiedSummary', () => {
|
|
75
|
+
it('should generate human-readable summary', () => {
|
|
76
|
+
const result = {
|
|
77
|
+
summary: {
|
|
78
|
+
toolsRun: ['tool1'],
|
|
79
|
+
totalIssues: 5,
|
|
80
|
+
executionTime: 1200,
|
|
81
|
+
},
|
|
82
|
+
tool1: { results: [{ issues: [{}, {}] }] },
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
vi.spyOn(ToolRegistry, 'getAll').mockReturnValue([
|
|
86
|
+
{ id: 'tool1' },
|
|
87
|
+
] as any);
|
|
88
|
+
|
|
89
|
+
const summary = generateUnifiedSummary(result as any);
|
|
90
|
+
expect(summary).toContain('AIReady Analysis Complete');
|
|
91
|
+
expect(summary).toContain('Total issues found: 5');
|
|
92
|
+
expect(summary).toContain('1.20s');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
});
|
package/src/cli.ts
CHANGED
|
@@ -16,8 +16,15 @@ import {
|
|
|
16
16
|
visualizeHelpText,
|
|
17
17
|
visualiseHelpText,
|
|
18
18
|
changeAmplificationAction,
|
|
19
|
+
testabilityAction,
|
|
19
20
|
uploadAction,
|
|
20
21
|
uploadHelpText,
|
|
22
|
+
clawmartMeAction,
|
|
23
|
+
clawmartListingsAction,
|
|
24
|
+
clawmartCreateAction,
|
|
25
|
+
clawmartUploadAction,
|
|
26
|
+
clawmartDownloadAction,
|
|
27
|
+
clawmartHelpText,
|
|
21
28
|
} from './commands';
|
|
22
29
|
|
|
23
30
|
const getDirname = () => {
|
|
@@ -279,6 +286,20 @@ program
|
|
|
279
286
|
await changeAmplificationAction(directory, options);
|
|
280
287
|
});
|
|
281
288
|
|
|
289
|
+
// Testability command
|
|
290
|
+
program
|
|
291
|
+
.command('testability')
|
|
292
|
+
.description('Analyze test coverage and AI readiness')
|
|
293
|
+
.argument('[directory]', 'Directory to analyze', '.')
|
|
294
|
+
.option('--min-coverage <ratio>', 'Minimum acceptable coverage ratio', '0.3')
|
|
295
|
+
.option('--include <patterns>', 'File patterns to include (comma-separated)')
|
|
296
|
+
.option('--exclude <patterns>', 'File patterns to exclude (comma-separated)')
|
|
297
|
+
.option('-o, --output <format>', 'Output format: console, json', 'console')
|
|
298
|
+
.option('--output-file <path>', 'Output file path (for json)')
|
|
299
|
+
.action(async (directory, options) => {
|
|
300
|
+
await testabilityAction(directory, options);
|
|
301
|
+
});
|
|
302
|
+
|
|
282
303
|
// Upload command - Upload report JSON to platform
|
|
283
304
|
program
|
|
284
305
|
.command('upload')
|
|
@@ -292,4 +313,69 @@ program
|
|
|
292
313
|
await uploadAction(file, options);
|
|
293
314
|
});
|
|
294
315
|
|
|
316
|
+
// ClawMart commands
|
|
317
|
+
const clawmart = program
|
|
318
|
+
.command('clawmart')
|
|
319
|
+
.description('Manage ClawMart personas and skills')
|
|
320
|
+
.addHelpText('after', clawmartHelpText);
|
|
321
|
+
|
|
322
|
+
clawmart
|
|
323
|
+
.command('me')
|
|
324
|
+
.description('Show my ClawMart creator profile')
|
|
325
|
+
.option('--api-key <key>', 'ClawMart API key')
|
|
326
|
+
.option('--server <url>', 'Custom ClawMart API server')
|
|
327
|
+
.action(async (options) => {
|
|
328
|
+
await clawmartMeAction(options);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
clawmart
|
|
332
|
+
.command('listings')
|
|
333
|
+
.description('Show my ClawMart listings')
|
|
334
|
+
.option('-q, --query <string>', 'Search query')
|
|
335
|
+
.option('-t, --type <type>', 'Filter by type: skill, persona')
|
|
336
|
+
.option('-l, --limit <number>', 'Limit results', '10')
|
|
337
|
+
.option('--api-key <key>', 'ClawMart API key')
|
|
338
|
+
.option('--server <url>', 'Custom ClawMart API server')
|
|
339
|
+
.action(async (options) => {
|
|
340
|
+
await clawmartListingsAction(options);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
clawmart
|
|
344
|
+
.command('create')
|
|
345
|
+
.description('Create a new listing on ClawMart')
|
|
346
|
+
.requiredOption('--name <string>', 'Listing name')
|
|
347
|
+
.requiredOption('--tagline <string>', 'Short tagline')
|
|
348
|
+
.option('--about <string>', 'Full description')
|
|
349
|
+
.option('--category <string>', 'Category', 'Utility')
|
|
350
|
+
.option('--capabilities <string>', 'Comma-separated list of capabilities')
|
|
351
|
+
.option('--price <number>', 'Price in USD', '0')
|
|
352
|
+
.option('--type <type>', 'Product type: skill, persona', 'skill')
|
|
353
|
+
.option('--api-key <key>', 'ClawMart API key')
|
|
354
|
+
.option('--server <url>', 'Custom ClawMart API server')
|
|
355
|
+
.action(async (options) => {
|
|
356
|
+
await clawmartCreateAction(options);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
clawmart
|
|
360
|
+
.command('upload')
|
|
361
|
+
.description('Upload content to a listing')
|
|
362
|
+
.argument('<id>', 'Listing ID')
|
|
363
|
+
.argument('<files...>', 'Files or directories to upload')
|
|
364
|
+
.option('--api-key <key>', 'ClawMart API key')
|
|
365
|
+
.option('--server <url>', 'Custom ClawMart API server')
|
|
366
|
+
.action(async (id, files, options) => {
|
|
367
|
+
await clawmartUploadAction(id, files as string[], options);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
clawmart
|
|
371
|
+
.command('download')
|
|
372
|
+
.description('Download a package from ClawMart')
|
|
373
|
+
.argument('<idOrSlug>', 'Listing ID or Slug')
|
|
374
|
+
.option('--outDir <path>', 'Output directory')
|
|
375
|
+
.option('--api-key <key>', 'ClawMart API key')
|
|
376
|
+
.option('--server <url>', 'Custom ClawMart API server')
|
|
377
|
+
.action(async (idOrSlug, options) => {
|
|
378
|
+
await clawmartDownloadAction(idOrSlug, options);
|
|
379
|
+
});
|
|
380
|
+
|
|
295
381
|
program.parse();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { agentGroundingAction } from '../agent-grounding';
|
|
3
|
+
|
|
4
|
+
vi.mock('@aiready/agent-grounding', () => ({
|
|
5
|
+
analyzeAgentGrounding: vi.fn().mockResolvedValue({
|
|
6
|
+
summary: { score: 75, rating: 'good', dimensions: { apiClarityScore: 60 } },
|
|
7
|
+
results: [],
|
|
8
|
+
}),
|
|
9
|
+
calculateGroundingScore: vi.fn().mockReturnValue({ score: 75 }),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock('@aiready/core', () => ({
|
|
13
|
+
loadConfig: vi.fn().mockResolvedValue({}),
|
|
14
|
+
mergeConfigWithDefaults: vi
|
|
15
|
+
.fn()
|
|
16
|
+
.mockImplementation((c, d) => ({ ...d, ...c })),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
describe('Agent Grounding CLI Action', () => {
|
|
20
|
+
it('should run analysis and return scoring', async () => {
|
|
21
|
+
const result = await agentGroundingAction('.', { output: 'json' });
|
|
22
|
+
expect(result?.score).toBe(75);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { aiSignalClarityAction } from '../ai-signal-clarity';
|
|
3
|
+
|
|
4
|
+
vi.mock('@aiready/ai-signal-clarity', () => ({
|
|
5
|
+
analyzeAiSignalClarity: vi.fn().mockResolvedValue({
|
|
6
|
+
summary: {
|
|
7
|
+
score: 85,
|
|
8
|
+
rating: 'low',
|
|
9
|
+
topRisk: 'none',
|
|
10
|
+
totalSignals: 0,
|
|
11
|
+
criticalSignals: 0,
|
|
12
|
+
majorSignals: 0,
|
|
13
|
+
minorSignals: 0,
|
|
14
|
+
},
|
|
15
|
+
results: [],
|
|
16
|
+
}),
|
|
17
|
+
calculateAiSignalClarityScore: vi.fn().mockReturnValue({ score: 85 }),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
vi.mock('@aiready/core', () => ({
|
|
21
|
+
loadConfig: vi.fn().mockResolvedValue({}),
|
|
22
|
+
mergeConfigWithDefaults: vi
|
|
23
|
+
.fn()
|
|
24
|
+
.mockImplementation((c, d) => ({ ...d, ...c })),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
describe('AI Signal Clarity CLI Action', () => {
|
|
28
|
+
it('should run analysis and return scoring', async () => {
|
|
29
|
+
const result = await aiSignalClarityAction('.', { output: 'json' });
|
|
30
|
+
expect(result?.score).toBe(85);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('runs consistency analysis and outputs to console', async () => {
|
|
67
|
+
await consistencyAction('.', {});
|
|
68
|
+
expect(analyzeConsistency).toHaveBeenCalled();
|
|
69
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Summary'));
|
|
70
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
71
|
+
expect.stringContaining('Naming Issues')
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('supports JSON output', async () => {
|
|
76
|
+
vi.mocked(core.loadMergedConfig).mockResolvedValue({
|
|
77
|
+
output: { format: 'json' },
|
|
78
|
+
});
|
|
79
|
+
await consistencyAction('.', {});
|
|
80
|
+
expect(core.handleJSONOutput).toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('supports Markdown output', async () => {
|
|
84
|
+
vi.mocked(core.loadMergedConfig).mockResolvedValue({
|
|
85
|
+
output: { format: 'markdown' },
|
|
86
|
+
});
|
|
87
|
+
await consistencyAction('.', {});
|
|
88
|
+
expect(fs.writeFileSync).toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('calculates score if requested', async () => {
|
|
92
|
+
await consistencyAction('.', { score: true });
|
|
93
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
94
|
+
expect.stringContaining('AI Readiness Score')
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
import * as core from '@aiready/core';
|
|
11
|
+
|
|
12
|
+
vi.mock('@aiready/core', async () => {
|
|
13
|
+
const actual = await vi.importActual('@aiready/core');
|
|
14
|
+
return {
|
|
15
|
+
...actual,
|
|
16
|
+
loadConfig: vi.fn().mockResolvedValue({}),
|
|
17
|
+
mergeConfigWithDefaults: vi
|
|
18
|
+
.fn()
|
|
19
|
+
.mockImplementation((c, d) => ({ ...d, ...c })),
|
|
20
|
+
loadMergedConfig: vi.fn().mockResolvedValue({
|
|
21
|
+
rootDir: '.',
|
|
22
|
+
output: { format: 'console' },
|
|
23
|
+
checkNaming: true,
|
|
24
|
+
checkPatterns: true,
|
|
25
|
+
}),
|
|
26
|
+
handleJSONOutput: vi.fn(),
|
|
27
|
+
handleCLIError: vi.fn(),
|
|
28
|
+
getElapsedTime: vi.fn().mockReturnValue('1.0'),
|
|
29
|
+
resolveOutputPath: vi.fn().mockReturnValue('report.json'),
|
|
30
|
+
formatToolScore: vi.fn().mockReturnValue('Score: 80'),
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Mock all spokes
|
|
35
|
+
vi.mock('@aiready/change-amplification', () => ({
|
|
36
|
+
analyzeChangeAmplification: vi
|
|
37
|
+
.fn()
|
|
38
|
+
.mockResolvedValue({
|
|
39
|
+
results: [],
|
|
40
|
+
summary: { rating: 'contained' },
|
|
41
|
+
recommendations: [],
|
|
42
|
+
}),
|
|
43
|
+
calculateChangeAmplificationScore: vi.fn().mockReturnValue({ score: 80 }),
|
|
44
|
+
}));
|
|
45
|
+
vi.mock('@aiready/agent-grounding', () => ({
|
|
46
|
+
analyzeAgentGrounding: vi.fn().mockResolvedValue({
|
|
47
|
+
results: [],
|
|
48
|
+
summary: {
|
|
49
|
+
rating: 'grounded',
|
|
50
|
+
dimensions: { structure: 80, metadata: 80 },
|
|
51
|
+
},
|
|
52
|
+
recommendations: [],
|
|
53
|
+
}),
|
|
54
|
+
calculateGroundingScore: vi.fn().mockReturnValue({ score: 80 }),
|
|
55
|
+
}));
|
|
56
|
+
vi.mock('@aiready/ai-signal-clarity', () => ({
|
|
57
|
+
analyzeAiSignalClarity: vi.fn().mockResolvedValue({
|
|
58
|
+
results: [],
|
|
59
|
+
summary: { rating: 'clear', topRisk: 'none' },
|
|
60
|
+
recommendations: [],
|
|
61
|
+
}),
|
|
62
|
+
calculateAiSignalClarityScore: vi.fn().mockReturnValue({ score: 80 }),
|
|
63
|
+
}));
|
|
64
|
+
vi.mock('@aiready/doc-drift', () => ({
|
|
65
|
+
analyzeDocDrift: vi.fn().mockResolvedValue({
|
|
66
|
+
results: [],
|
|
67
|
+
summary: { rating: 'fresh' },
|
|
68
|
+
issues: [],
|
|
69
|
+
rawData: {},
|
|
70
|
+
recommendations: [],
|
|
71
|
+
}),
|
|
72
|
+
calculateDocDriftScore: vi.fn().mockReturnValue({ score: 80 }),
|
|
73
|
+
}));
|
|
74
|
+
vi.mock('@aiready/testability', () => ({
|
|
75
|
+
analyzeTestability: vi.fn().mockResolvedValue({
|
|
76
|
+
results: [],
|
|
77
|
+
summary: { rating: 'testable', aiChangeSafetyRating: 'safe' },
|
|
78
|
+
rawData: {},
|
|
79
|
+
recommendations: [],
|
|
80
|
+
}),
|
|
81
|
+
calculateTestabilityScore: vi.fn().mockReturnValue({ score: 80 }),
|
|
82
|
+
}));
|
|
83
|
+
vi.mock('@aiready/deps', () => ({
|
|
84
|
+
analyzeDeps: vi.fn().mockResolvedValue({
|
|
85
|
+
results: [],
|
|
86
|
+
summary: { packagesAnalyzed: 0, filesAnalyzed: 0, rating: 'healthy' },
|
|
87
|
+
issues: [],
|
|
88
|
+
rawData: {},
|
|
89
|
+
recommendations: [],
|
|
90
|
+
}),
|
|
91
|
+
calculateDepsScore: vi.fn().mockReturnValue({ score: 80 }),
|
|
92
|
+
}));
|
|
93
|
+
vi.mock('@aiready/pattern-detect', () => ({
|
|
94
|
+
analyzePatterns: vi
|
|
95
|
+
.fn()
|
|
96
|
+
.mockResolvedValue({
|
|
97
|
+
results: [],
|
|
98
|
+
summary: { totalPatterns: 0 },
|
|
99
|
+
config: {},
|
|
100
|
+
}),
|
|
101
|
+
generateSummary: vi
|
|
102
|
+
.fn()
|
|
103
|
+
.mockReturnValue({
|
|
104
|
+
totalPatterns: 0,
|
|
105
|
+
totalTokenCost: 0,
|
|
106
|
+
patternsByType: {},
|
|
107
|
+
topDuplicates: [],
|
|
108
|
+
}),
|
|
109
|
+
getSmartDefaults: vi.fn().mockResolvedValue({}),
|
|
110
|
+
}));
|
|
111
|
+
vi.mock('@aiready/context-analyzer', () => ({
|
|
112
|
+
analyzeContext: vi.fn().mockResolvedValue([]),
|
|
113
|
+
generateSummary: vi
|
|
114
|
+
.fn()
|
|
115
|
+
.mockReturnValue({
|
|
116
|
+
score: 80,
|
|
117
|
+
rating: 'good',
|
|
118
|
+
totalFiles: 0,
|
|
119
|
+
totalTokens: 0,
|
|
120
|
+
avgImportDepth: 0,
|
|
121
|
+
maxImportDepth: 0,
|
|
122
|
+
avgFragmentation: 0,
|
|
123
|
+
criticalIssues: 0,
|
|
124
|
+
majorIssues: 0,
|
|
125
|
+
totalPotentialSavings: 0,
|
|
126
|
+
}),
|
|
127
|
+
getSmartDefaults: vi.fn().mockResolvedValue({}),
|
|
128
|
+
}));
|
|
129
|
+
|
|
130
|
+
describe('Extra CLI Actions', () => {
|
|
131
|
+
let consoleSpy: any;
|
|
132
|
+
|
|
133
|
+
beforeEach(() => {
|
|
134
|
+
vi.clearAllMocks();
|
|
135
|
+
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('runs change-amplification', async () => {
|
|
139
|
+
await changeAmplificationAction('.', {});
|
|
140
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('runs agent-grounding', async () => {
|
|
144
|
+
await agentGroundingAction('.', {});
|
|
145
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('runs ai-signal-clarity', async () => {
|
|
149
|
+
await aiSignalClarityAction('.', {});
|
|
150
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('runs doc-drift', async () => {
|
|
154
|
+
await docDriftAction('.', {});
|
|
155
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('runs testability', async () => {
|
|
159
|
+
await testabilityAction('.', {});
|
|
160
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('runs deps-health', async () => {
|
|
164
|
+
await depsHealthAction('.', {});
|
|
165
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('runs patterns', async () => {
|
|
169
|
+
await patternsAction('.', {});
|
|
170
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('runs context', async () => {
|
|
174
|
+
await contextAction('.', {});
|
|
175
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
176
|
+
});
|
|
177
|
+
});
|