@aiready/cli 0.12.12 → 0.12.14
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 +8 -8
- package/.turbo/turbo-test.log +57 -20
- package/dist/chunk-2QOU5KKW.mjs +301 -0
- package/dist/chunk-55ZUD52M.mjs +290 -0
- package/dist/chunk-BD7XZYET.mjs +302 -0
- package/dist/cli.js +39 -15
- package/dist/cli.mjs +4 -1
- package/dist/index.js +36 -15
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/__tests__/config-shape.test.ts +106 -0
- package/src/commands/scan.ts +3 -0
- package/src/index.ts +40 -17
package/dist/index.js
CHANGED
|
@@ -57,16 +57,30 @@ var TOOL_PACKAGE_MAP = {
|
|
|
57
57
|
"deps-health": "@aiready/deps",
|
|
58
58
|
"change-amp": "@aiready/change-amplification"
|
|
59
59
|
};
|
|
60
|
-
function
|
|
61
|
-
if (!
|
|
62
|
-
const sanitized = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
function sanitizeConfigRecursive(obj) {
|
|
61
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj;
|
|
62
|
+
const sanitized = {};
|
|
63
|
+
const infraToStrip = [
|
|
64
|
+
"rootDir",
|
|
65
|
+
"onProgress",
|
|
66
|
+
"progressCallback",
|
|
67
|
+
"streamResults",
|
|
68
|
+
"batchSize",
|
|
69
|
+
"useSmartDefaults"
|
|
70
|
+
];
|
|
71
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
72
|
+
if (infraToStrip.includes(key)) continue;
|
|
73
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
74
|
+
sanitized[key] = sanitizeConfigRecursive(value);
|
|
75
|
+
} else {
|
|
76
|
+
sanitized[key] = value;
|
|
66
77
|
}
|
|
67
|
-
}
|
|
78
|
+
}
|
|
68
79
|
return sanitized;
|
|
69
80
|
}
|
|
81
|
+
function sanitizeToolConfig(config) {
|
|
82
|
+
return sanitizeConfigRecursive(config);
|
|
83
|
+
}
|
|
70
84
|
async function analyzeUnified(options) {
|
|
71
85
|
const startTime = Date.now();
|
|
72
86
|
const requestedTools = options.tools || [
|
|
@@ -118,22 +132,24 @@ async function analyzeUnified(options) {
|
|
|
118
132
|
continue;
|
|
119
133
|
}
|
|
120
134
|
try {
|
|
121
|
-
const
|
|
122
|
-
delete
|
|
123
|
-
delete
|
|
135
|
+
const sanitizedOptions = { ...options };
|
|
136
|
+
delete sanitizedOptions.onProgress;
|
|
137
|
+
delete sanitizedOptions.progressCallback;
|
|
124
138
|
const toolOptions = {
|
|
125
139
|
rootDir: options.rootDir
|
|
126
140
|
// Always include rootDir
|
|
127
141
|
};
|
|
128
142
|
[...import_core.GLOBAL_INFRA_OPTIONS, ...import_core.COMMON_FINE_TUNING_OPTIONS].forEach(
|
|
129
143
|
(key) => {
|
|
130
|
-
if (key in options && key !== "toolConfigs") {
|
|
144
|
+
if (key in options && key !== "toolConfigs" && key !== "tools") {
|
|
131
145
|
toolOptions[key] = options[key];
|
|
132
146
|
}
|
|
133
147
|
}
|
|
134
148
|
);
|
|
135
149
|
if (options.toolConfigs?.[provider.id]) {
|
|
136
150
|
Object.assign(toolOptions, options.toolConfigs[provider.id]);
|
|
151
|
+
} else if (options.tools && !Array.isArray(options.tools) && typeof options.tools === "object" && options.tools[provider.id]) {
|
|
152
|
+
Object.assign(toolOptions, options.tools[provider.id]);
|
|
137
153
|
} else if (options[provider.id]) {
|
|
138
154
|
Object.assign(toolOptions, options[provider.id]);
|
|
139
155
|
}
|
|
@@ -194,10 +210,15 @@ async function analyzeUnified(options) {
|
|
|
194
210
|
console.error(`\u274C Error running tool '${provider.id}':`, err);
|
|
195
211
|
}
|
|
196
212
|
}
|
|
197
|
-
result.summary.config = {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
213
|
+
result.summary.config = sanitizeConfigRecursive({
|
|
214
|
+
scan: {
|
|
215
|
+
tools: requestedTools,
|
|
216
|
+
include: options.include,
|
|
217
|
+
exclude: options.exclude
|
|
218
|
+
},
|
|
219
|
+
// Use 'tools' for tool-specific configurations to match AIReadyConfig
|
|
220
|
+
tools: result.summary.toolConfigs
|
|
221
|
+
});
|
|
201
222
|
result.summary.executionTime = Date.now() - startTime;
|
|
202
223
|
return result;
|
|
203
224
|
}
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.14",
|
|
4
4
|
"description": "Unified CLI for AIReady analysis tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"chalk": "^5.3.0",
|
|
13
13
|
"commander": "^14.0.0",
|
|
14
|
-
"@aiready/agent-grounding": "0.11.
|
|
15
|
-
"@aiready/consistency": "0.18.
|
|
16
|
-
"@aiready/
|
|
17
|
-
"@aiready/deps": "0.11.
|
|
18
|
-
"@aiready/
|
|
19
|
-
"@aiready/
|
|
20
|
-
"@aiready/
|
|
21
|
-
"@aiready/
|
|
22
|
-
"@aiready/
|
|
23
|
-
"@aiready/
|
|
24
|
-
"@aiready/
|
|
14
|
+
"@aiready/agent-grounding": "0.11.13",
|
|
15
|
+
"@aiready/consistency": "0.18.13",
|
|
16
|
+
"@aiready/context-analyzer": "0.19.13",
|
|
17
|
+
"@aiready/deps": "0.11.13",
|
|
18
|
+
"@aiready/core": "0.21.13",
|
|
19
|
+
"@aiready/doc-drift": "0.11.13",
|
|
20
|
+
"@aiready/ai-signal-clarity": "0.11.13",
|
|
21
|
+
"@aiready/visualizer": "0.4.13",
|
|
22
|
+
"@aiready/change-amplification": "0.11.13",
|
|
23
|
+
"@aiready/pattern-detect": "0.14.13",
|
|
24
|
+
"@aiready/testability": "0.4.13"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^24.0.0",
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { analyzeUnified } from '../index';
|
|
3
|
+
import { ToolRegistry, ToolName, SpokeOutputSchema } from '@aiready/core';
|
|
4
|
+
|
|
5
|
+
describe('CLI Configuration Shape', () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
ToolRegistry.clear();
|
|
8
|
+
|
|
9
|
+
// Register a mock provider that returns its input config in metadata
|
|
10
|
+
ToolRegistry.register({
|
|
11
|
+
id: ToolName.PatternDetect,
|
|
12
|
+
alias: ['patterns'],
|
|
13
|
+
analyze: async (options) =>
|
|
14
|
+
SpokeOutputSchema.parse({
|
|
15
|
+
results: [],
|
|
16
|
+
summary: { config: options },
|
|
17
|
+
metadata: {
|
|
18
|
+
toolName: ToolName.PatternDetect,
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
config: options,
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
score: () => ({
|
|
24
|
+
toolName: ToolName.PatternDetect,
|
|
25
|
+
score: 80,
|
|
26
|
+
factors: [],
|
|
27
|
+
recommendations: [],
|
|
28
|
+
rawMetrics: {},
|
|
29
|
+
}),
|
|
30
|
+
defaultWeight: 10,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
ToolRegistry.clear();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should generate a strictly portable AIReadyConfig in summary', async () => {
|
|
39
|
+
const results = await analyzeUnified({
|
|
40
|
+
rootDir: '/tmp/fake-repo',
|
|
41
|
+
tools: [ToolName.PatternDetect],
|
|
42
|
+
exclude: ['**/node_modules/**'],
|
|
43
|
+
// Pass a tool-specific override
|
|
44
|
+
toolConfigs: {
|
|
45
|
+
[ToolName.PatternDetect]: {
|
|
46
|
+
minSimilarity: 0.9,
|
|
47
|
+
// This should be stripped
|
|
48
|
+
rootDir: '/tmp/fake-repo',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const config = results.summary.config;
|
|
54
|
+
|
|
55
|
+
// 1. Check top-level structure
|
|
56
|
+
expect(config).toHaveProperty('scan');
|
|
57
|
+
expect(config).toHaveProperty('tools');
|
|
58
|
+
|
|
59
|
+
// 2. Ensure rootDir is STRIPPED from top level
|
|
60
|
+
expect(config).not.toHaveProperty('rootDir');
|
|
61
|
+
|
|
62
|
+
// 3. Ensure internal keys are stripped from scan section
|
|
63
|
+
expect(config.scan).toHaveProperty('tools');
|
|
64
|
+
expect(config.scan).toHaveProperty('exclude');
|
|
65
|
+
expect(config.scan).not.toHaveProperty('rootDir');
|
|
66
|
+
|
|
67
|
+
// 4. Ensure recursive stripping in tools section
|
|
68
|
+
const patternConfig = config.tools[ToolName.PatternDetect];
|
|
69
|
+
expect(patternConfig).toHaveProperty('minSimilarity', 0.9);
|
|
70
|
+
expect(patternConfig).not.toHaveProperty('rootDir');
|
|
71
|
+
expect(patternConfig).not.toHaveProperty('onProgress');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should strip internal keys like useSmartDefaults and batchSize', async () => {
|
|
75
|
+
const results = await analyzeUnified({
|
|
76
|
+
rootDir: '/test',
|
|
77
|
+
tools: [ToolName.PatternDetect],
|
|
78
|
+
useSmartDefaults: true,
|
|
79
|
+
// @ts-ignore - testing internal key stripping
|
|
80
|
+
batchSize: 50,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const config = results.summary.config;
|
|
84
|
+
|
|
85
|
+
expect(config).not.toHaveProperty('useSmartDefaults');
|
|
86
|
+
expect(config.scan).not.toHaveProperty('useSmartDefaults');
|
|
87
|
+
|
|
88
|
+
// Check tool level too
|
|
89
|
+
const patternConfig = config.tools[ToolName.PatternDetect];
|
|
90
|
+
expect(patternConfig).not.toHaveProperty('useSmartDefaults');
|
|
91
|
+
expect(patternConfig).not.toHaveProperty('batchSize');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should produce a config that is compatible with tool specific collection', async () => {
|
|
95
|
+
// This test ensures that the toolConfigs collected from individual tools
|
|
96
|
+
// are also sanitized before being merged into the final report.
|
|
97
|
+
const results = await analyzeUnified({
|
|
98
|
+
rootDir: '/test',
|
|
99
|
+
tools: [ToolName.PatternDetect],
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const toolConfigs = results.summary.toolConfigs;
|
|
103
|
+
expect(toolConfigs).toBeDefined();
|
|
104
|
+
expect(toolConfigs![ToolName.PatternDetect]).not.toHaveProperty('rootDir');
|
|
105
|
+
});
|
|
106
|
+
});
|
package/src/commands/scan.ts
CHANGED
|
@@ -192,6 +192,9 @@ export async function scanAction(directory: string, options: ScanOptions) {
|
|
|
192
192
|
console.log(
|
|
193
193
|
` Total issues (all tools): ${chalk.bold(String(results.summary.totalIssues || 0))}`
|
|
194
194
|
);
|
|
195
|
+
console.log(
|
|
196
|
+
` Execution time: ${chalk.bold(((Date.now() - startTime) / 1000).toFixed(2) + 's')}`
|
|
197
|
+
);
|
|
195
198
|
|
|
196
199
|
let scoringResult: ScoringResult | undefined;
|
|
197
200
|
if (options.score || finalOptions.scoring?.showBreakdown) {
|
package/src/index.ts
CHANGED
|
@@ -92,19 +92,44 @@ const TOOL_PACKAGE_MAP: Record<string, string> = {
|
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
95
|
+
* Deeply sanitizes a configuration object by removing infrastructure keys like rootDir.
|
|
96
|
+
* Works recursively to clean up nested tool configurations to ensure compatibility
|
|
97
|
+
* with the AIReadyConfig schema for portable configuration files.
|
|
96
98
|
*/
|
|
97
|
-
function
|
|
98
|
-
if (!
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
function sanitizeConfigRecursive(obj: any): any {
|
|
100
|
+
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return obj;
|
|
101
|
+
|
|
102
|
+
const sanitized: any = {};
|
|
103
|
+
const infraToStrip = [
|
|
104
|
+
'rootDir',
|
|
105
|
+
'onProgress',
|
|
106
|
+
'progressCallback',
|
|
107
|
+
'streamResults',
|
|
108
|
+
'batchSize',
|
|
109
|
+
'useSmartDefaults',
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
113
|
+
// Skip infrastructure keys that shouldn't be in a portable config file
|
|
114
|
+
if (infraToStrip.includes(key)) continue;
|
|
115
|
+
|
|
116
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
117
|
+
sanitized[key] = sanitizeConfigRecursive(value);
|
|
118
|
+
} else {
|
|
119
|
+
sanitized[key] = value;
|
|
103
120
|
}
|
|
104
|
-
}
|
|
121
|
+
}
|
|
122
|
+
|
|
105
123
|
return sanitized;
|
|
106
124
|
}
|
|
107
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Sanitize tool configuration by removing global options to match AIReadyConfig schema
|
|
128
|
+
*/
|
|
129
|
+
function sanitizeToolConfig(config: any): any {
|
|
130
|
+
return sanitizeConfigRecursive(config);
|
|
131
|
+
}
|
|
132
|
+
|
|
108
133
|
/**
|
|
109
134
|
* AIReady Unified Analysis
|
|
110
135
|
* Orchestrates all registered tools via the ToolRegistry.
|
|
@@ -169,9 +194,9 @@ export async function analyzeUnified(
|
|
|
169
194
|
|
|
170
195
|
try {
|
|
171
196
|
// Sanitize options for metadata tracking (remove functions/internal keys)
|
|
172
|
-
const
|
|
173
|
-
delete (
|
|
174
|
-
delete (
|
|
197
|
+
const sanitizedOptions = { ...options };
|
|
198
|
+
delete (sanitizedOptions as any).onProgress;
|
|
199
|
+
delete (sanitizedOptions as any).progressCallback;
|
|
175
200
|
|
|
176
201
|
// 1. Start with sanitized global subset
|
|
177
202
|
const toolOptions: any = {
|
|
@@ -286,8 +311,9 @@ export async function analyzeUnified(
|
|
|
286
311
|
}
|
|
287
312
|
}
|
|
288
313
|
|
|
289
|
-
// Finalize configuration for metadata to match AIReadyConfig
|
|
290
|
-
|
|
314
|
+
// Finalize configuration for metadata to match AIReadyConfig schema
|
|
315
|
+
// We use sanitizeConfigRecursive to ensure no internal keys (like rootDir) remain
|
|
316
|
+
result.summary.config = sanitizeConfigRecursive({
|
|
291
317
|
scan: {
|
|
292
318
|
tools: requestedTools,
|
|
293
319
|
include: options.include,
|
|
@@ -295,10 +321,7 @@ export async function analyzeUnified(
|
|
|
295
321
|
},
|
|
296
322
|
// Use 'tools' for tool-specific configurations to match AIReadyConfig
|
|
297
323
|
tools: result.summary.toolConfigs,
|
|
298
|
-
|
|
299
|
-
rootDir: options.rootDir,
|
|
300
|
-
useSmartDefaults: options.useSmartDefaults,
|
|
301
|
-
};
|
|
324
|
+
});
|
|
302
325
|
|
|
303
326
|
result.summary.executionTime = Date.now() - startTime;
|
|
304
327
|
return result;
|