@aiready/core 0.7.9 → 0.7.11
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/dist/index.d.mts +129 -1
- package/dist/index.d.ts +129 -1
- package/dist/index.js +195 -19
- package/dist/index.mjs +177 -11
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -34,9 +34,12 @@ interface AIReadyConfig {
|
|
|
34
34
|
scan?: {
|
|
35
35
|
include?: string[];
|
|
36
36
|
exclude?: string[];
|
|
37
|
+
tools?: string[];
|
|
37
38
|
};
|
|
38
39
|
tools?: {
|
|
39
40
|
'pattern-detect'?: {
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
scoreWeight?: number;
|
|
40
43
|
minSimilarity?: number;
|
|
41
44
|
minLines?: number;
|
|
42
45
|
batchSize?: number;
|
|
@@ -47,6 +50,8 @@ interface AIReadyConfig {
|
|
|
47
50
|
maxResults?: number;
|
|
48
51
|
};
|
|
49
52
|
'context-analyzer'?: {
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
scoreWeight?: number;
|
|
50
55
|
maxDepth?: number;
|
|
51
56
|
maxContextBudget?: number;
|
|
52
57
|
minCohesion?: number;
|
|
@@ -59,10 +64,23 @@ interface AIReadyConfig {
|
|
|
59
64
|
pathDomainMap?: Record<string, string>;
|
|
60
65
|
};
|
|
61
66
|
'consistency'?: {
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
scoreWeight?: number;
|
|
62
69
|
acceptedAbbreviations?: string[];
|
|
63
70
|
shortWords?: string[];
|
|
64
71
|
disableChecks?: ('single-letter' | 'abbreviation' | 'convention-mix' | 'unclear' | 'poor-naming')[];
|
|
65
72
|
};
|
|
73
|
+
[toolName: string]: {
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
scoreWeight?: number;
|
|
76
|
+
[key: string]: any;
|
|
77
|
+
} | undefined;
|
|
78
|
+
};
|
|
79
|
+
scoring?: {
|
|
80
|
+
threshold?: number;
|
|
81
|
+
showBreakdown?: boolean;
|
|
82
|
+
compareBaseline?: string;
|
|
83
|
+
saveTo?: string;
|
|
66
84
|
};
|
|
67
85
|
output?: {
|
|
68
86
|
format?: 'console' | 'json' | 'html';
|
|
@@ -196,4 +214,114 @@ declare function handleCLIError(error: unknown, commandName: string): never;
|
|
|
196
214
|
*/
|
|
197
215
|
declare function getElapsedTime(startTime: number): string;
|
|
198
216
|
|
|
199
|
-
|
|
217
|
+
/**
|
|
218
|
+
* AI Readiness Scoring System
|
|
219
|
+
*
|
|
220
|
+
* Provides dynamic, composable scoring across multiple analysis tools.
|
|
221
|
+
* Each tool contributes a 0-100 score with configurable weights.
|
|
222
|
+
*/
|
|
223
|
+
interface ToolScoringOutput {
|
|
224
|
+
/** Unique tool identifier (e.g., "pattern-detect") */
|
|
225
|
+
toolName: string;
|
|
226
|
+
/** Normalized 0-100 score for this tool */
|
|
227
|
+
score: number;
|
|
228
|
+
/** Raw metrics used to calculate the score */
|
|
229
|
+
rawMetrics: Record<string, any>;
|
|
230
|
+
/** Factors that influenced the score */
|
|
231
|
+
factors: Array<{
|
|
232
|
+
name: string;
|
|
233
|
+
impact: number;
|
|
234
|
+
description: string;
|
|
235
|
+
}>;
|
|
236
|
+
/** Actionable recommendations with estimated impact */
|
|
237
|
+
recommendations: Array<{
|
|
238
|
+
action: string;
|
|
239
|
+
estimatedImpact: number;
|
|
240
|
+
priority: 'high' | 'medium' | 'low';
|
|
241
|
+
}>;
|
|
242
|
+
}
|
|
243
|
+
interface ScoringResult {
|
|
244
|
+
/** Overall AI Readiness Score (0-100) */
|
|
245
|
+
overall: number;
|
|
246
|
+
/** Rating category */
|
|
247
|
+
rating: 'Excellent' | 'Good' | 'Fair' | 'Needs Work' | 'Critical';
|
|
248
|
+
/** Timestamp of score calculation */
|
|
249
|
+
timestamp: string;
|
|
250
|
+
/** Tools that contributed to this score */
|
|
251
|
+
toolsUsed: string[];
|
|
252
|
+
/** Breakdown by tool */
|
|
253
|
+
breakdown: ToolScoringOutput[];
|
|
254
|
+
/** Calculation details */
|
|
255
|
+
calculation: {
|
|
256
|
+
formula: string;
|
|
257
|
+
weights: Record<string, number>;
|
|
258
|
+
normalized: string;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
interface ScoringConfig {
|
|
262
|
+
/** Minimum passing score (exit code 1 if below) */
|
|
263
|
+
threshold?: number;
|
|
264
|
+
/** Show detailed breakdown in output */
|
|
265
|
+
showBreakdown?: boolean;
|
|
266
|
+
/** Path to baseline JSON for comparison */
|
|
267
|
+
compareBaseline?: string;
|
|
268
|
+
/** Auto-save score to this path */
|
|
269
|
+
saveTo?: string;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Default weights for known tools.
|
|
273
|
+
* New tools get weight of 10 if not specified.
|
|
274
|
+
*/
|
|
275
|
+
declare const DEFAULT_TOOL_WEIGHTS: Record<string, number>;
|
|
276
|
+
/**
|
|
277
|
+
* Tool name normalization map (shorthand -> full name)
|
|
278
|
+
*/
|
|
279
|
+
declare const TOOL_NAME_MAP: Record<string, string>;
|
|
280
|
+
/**
|
|
281
|
+
* Normalize tool name from shorthand to full name
|
|
282
|
+
*/
|
|
283
|
+
declare function normalizeToolName(shortName: string): string;
|
|
284
|
+
/**
|
|
285
|
+
* Get tool weight with fallback priority:
|
|
286
|
+
* 1. CLI override
|
|
287
|
+
* 2. Tool config scoreWeight
|
|
288
|
+
* 3. Default weight
|
|
289
|
+
* 4. 10 (for unknown tools)
|
|
290
|
+
*/
|
|
291
|
+
declare function getToolWeight(toolName: string, toolConfig?: {
|
|
292
|
+
scoreWeight?: number;
|
|
293
|
+
}, cliOverride?: number): number;
|
|
294
|
+
/**
|
|
295
|
+
* Parse weight string from CLI (e.g., "patterns:50,context:30")
|
|
296
|
+
*/
|
|
297
|
+
declare function parseWeightString(weightStr?: string): Map<string, number>;
|
|
298
|
+
/**
|
|
299
|
+
* Calculate overall AI Readiness Score from multiple tool scores.
|
|
300
|
+
*
|
|
301
|
+
* Formula: Σ(tool_score × tool_weight) / Σ(active_tool_weights)
|
|
302
|
+
*
|
|
303
|
+
* This allows dynamic composition - score adjusts automatically
|
|
304
|
+
* based on which tools actually ran.
|
|
305
|
+
*/
|
|
306
|
+
declare function calculateOverallScore(toolOutputs: Map<string, ToolScoringOutput>, config?: any, cliWeights?: Map<string, number>): ScoringResult;
|
|
307
|
+
/**
|
|
308
|
+
* Convert numeric score to rating category
|
|
309
|
+
*/
|
|
310
|
+
declare function getRating(score: number): ScoringResult['rating'];
|
|
311
|
+
/**
|
|
312
|
+
* Get rating emoji and color for display
|
|
313
|
+
*/
|
|
314
|
+
declare function getRatingDisplay(rating: ScoringResult['rating']): {
|
|
315
|
+
emoji: string;
|
|
316
|
+
color: string;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* Format score for display with rating
|
|
320
|
+
*/
|
|
321
|
+
declare function formatScore(result: ScoringResult): string;
|
|
322
|
+
/**
|
|
323
|
+
* Format individual tool score for display
|
|
324
|
+
*/
|
|
325
|
+
declare function formatToolScore(output: ToolScoringOutput): string;
|
|
326
|
+
|
|
327
|
+
export { type AIReadyConfig, type ASTNode, type AnalysisResult, type CLIOptions, DEFAULT_EXCLUDE, DEFAULT_TOOL_WEIGHTS, type ExportWithImports, type FileImport, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, type ScoringConfig, type ScoringResult, TOOL_NAME_MAP, type ToolScoringOutput, calculateImportSimilarity, calculateOverallScore, estimateTokens, extractFunctions, extractImports, formatScore, formatToolScore, getElapsedTime, getFileExtension, getRating, getRatingDisplay, getToolWeight, handleCLIError, handleJSONOutput, isSourceFile, loadConfig, loadMergedConfig, mergeConfigWithDefaults, normalizeToolName, parseCode, parseFileExports, parseWeightString, readFileContent, resolveOutputPath, scanFiles };
|
package/dist/index.d.ts
CHANGED
|
@@ -34,9 +34,12 @@ interface AIReadyConfig {
|
|
|
34
34
|
scan?: {
|
|
35
35
|
include?: string[];
|
|
36
36
|
exclude?: string[];
|
|
37
|
+
tools?: string[];
|
|
37
38
|
};
|
|
38
39
|
tools?: {
|
|
39
40
|
'pattern-detect'?: {
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
scoreWeight?: number;
|
|
40
43
|
minSimilarity?: number;
|
|
41
44
|
minLines?: number;
|
|
42
45
|
batchSize?: number;
|
|
@@ -47,6 +50,8 @@ interface AIReadyConfig {
|
|
|
47
50
|
maxResults?: number;
|
|
48
51
|
};
|
|
49
52
|
'context-analyzer'?: {
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
scoreWeight?: number;
|
|
50
55
|
maxDepth?: number;
|
|
51
56
|
maxContextBudget?: number;
|
|
52
57
|
minCohesion?: number;
|
|
@@ -59,10 +64,23 @@ interface AIReadyConfig {
|
|
|
59
64
|
pathDomainMap?: Record<string, string>;
|
|
60
65
|
};
|
|
61
66
|
'consistency'?: {
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
scoreWeight?: number;
|
|
62
69
|
acceptedAbbreviations?: string[];
|
|
63
70
|
shortWords?: string[];
|
|
64
71
|
disableChecks?: ('single-letter' | 'abbreviation' | 'convention-mix' | 'unclear' | 'poor-naming')[];
|
|
65
72
|
};
|
|
73
|
+
[toolName: string]: {
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
scoreWeight?: number;
|
|
76
|
+
[key: string]: any;
|
|
77
|
+
} | undefined;
|
|
78
|
+
};
|
|
79
|
+
scoring?: {
|
|
80
|
+
threshold?: number;
|
|
81
|
+
showBreakdown?: boolean;
|
|
82
|
+
compareBaseline?: string;
|
|
83
|
+
saveTo?: string;
|
|
66
84
|
};
|
|
67
85
|
output?: {
|
|
68
86
|
format?: 'console' | 'json' | 'html';
|
|
@@ -196,4 +214,114 @@ declare function handleCLIError(error: unknown, commandName: string): never;
|
|
|
196
214
|
*/
|
|
197
215
|
declare function getElapsedTime(startTime: number): string;
|
|
198
216
|
|
|
199
|
-
|
|
217
|
+
/**
|
|
218
|
+
* AI Readiness Scoring System
|
|
219
|
+
*
|
|
220
|
+
* Provides dynamic, composable scoring across multiple analysis tools.
|
|
221
|
+
* Each tool contributes a 0-100 score with configurable weights.
|
|
222
|
+
*/
|
|
223
|
+
interface ToolScoringOutput {
|
|
224
|
+
/** Unique tool identifier (e.g., "pattern-detect") */
|
|
225
|
+
toolName: string;
|
|
226
|
+
/** Normalized 0-100 score for this tool */
|
|
227
|
+
score: number;
|
|
228
|
+
/** Raw metrics used to calculate the score */
|
|
229
|
+
rawMetrics: Record<string, any>;
|
|
230
|
+
/** Factors that influenced the score */
|
|
231
|
+
factors: Array<{
|
|
232
|
+
name: string;
|
|
233
|
+
impact: number;
|
|
234
|
+
description: string;
|
|
235
|
+
}>;
|
|
236
|
+
/** Actionable recommendations with estimated impact */
|
|
237
|
+
recommendations: Array<{
|
|
238
|
+
action: string;
|
|
239
|
+
estimatedImpact: number;
|
|
240
|
+
priority: 'high' | 'medium' | 'low';
|
|
241
|
+
}>;
|
|
242
|
+
}
|
|
243
|
+
interface ScoringResult {
|
|
244
|
+
/** Overall AI Readiness Score (0-100) */
|
|
245
|
+
overall: number;
|
|
246
|
+
/** Rating category */
|
|
247
|
+
rating: 'Excellent' | 'Good' | 'Fair' | 'Needs Work' | 'Critical';
|
|
248
|
+
/** Timestamp of score calculation */
|
|
249
|
+
timestamp: string;
|
|
250
|
+
/** Tools that contributed to this score */
|
|
251
|
+
toolsUsed: string[];
|
|
252
|
+
/** Breakdown by tool */
|
|
253
|
+
breakdown: ToolScoringOutput[];
|
|
254
|
+
/** Calculation details */
|
|
255
|
+
calculation: {
|
|
256
|
+
formula: string;
|
|
257
|
+
weights: Record<string, number>;
|
|
258
|
+
normalized: string;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
interface ScoringConfig {
|
|
262
|
+
/** Minimum passing score (exit code 1 if below) */
|
|
263
|
+
threshold?: number;
|
|
264
|
+
/** Show detailed breakdown in output */
|
|
265
|
+
showBreakdown?: boolean;
|
|
266
|
+
/** Path to baseline JSON for comparison */
|
|
267
|
+
compareBaseline?: string;
|
|
268
|
+
/** Auto-save score to this path */
|
|
269
|
+
saveTo?: string;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Default weights for known tools.
|
|
273
|
+
* New tools get weight of 10 if not specified.
|
|
274
|
+
*/
|
|
275
|
+
declare const DEFAULT_TOOL_WEIGHTS: Record<string, number>;
|
|
276
|
+
/**
|
|
277
|
+
* Tool name normalization map (shorthand -> full name)
|
|
278
|
+
*/
|
|
279
|
+
declare const TOOL_NAME_MAP: Record<string, string>;
|
|
280
|
+
/**
|
|
281
|
+
* Normalize tool name from shorthand to full name
|
|
282
|
+
*/
|
|
283
|
+
declare function normalizeToolName(shortName: string): string;
|
|
284
|
+
/**
|
|
285
|
+
* Get tool weight with fallback priority:
|
|
286
|
+
* 1. CLI override
|
|
287
|
+
* 2. Tool config scoreWeight
|
|
288
|
+
* 3. Default weight
|
|
289
|
+
* 4. 10 (for unknown tools)
|
|
290
|
+
*/
|
|
291
|
+
declare function getToolWeight(toolName: string, toolConfig?: {
|
|
292
|
+
scoreWeight?: number;
|
|
293
|
+
}, cliOverride?: number): number;
|
|
294
|
+
/**
|
|
295
|
+
* Parse weight string from CLI (e.g., "patterns:50,context:30")
|
|
296
|
+
*/
|
|
297
|
+
declare function parseWeightString(weightStr?: string): Map<string, number>;
|
|
298
|
+
/**
|
|
299
|
+
* Calculate overall AI Readiness Score from multiple tool scores.
|
|
300
|
+
*
|
|
301
|
+
* Formula: Σ(tool_score × tool_weight) / Σ(active_tool_weights)
|
|
302
|
+
*
|
|
303
|
+
* This allows dynamic composition - score adjusts automatically
|
|
304
|
+
* based on which tools actually ran.
|
|
305
|
+
*/
|
|
306
|
+
declare function calculateOverallScore(toolOutputs: Map<string, ToolScoringOutput>, config?: any, cliWeights?: Map<string, number>): ScoringResult;
|
|
307
|
+
/**
|
|
308
|
+
* Convert numeric score to rating category
|
|
309
|
+
*/
|
|
310
|
+
declare function getRating(score: number): ScoringResult['rating'];
|
|
311
|
+
/**
|
|
312
|
+
* Get rating emoji and color for display
|
|
313
|
+
*/
|
|
314
|
+
declare function getRatingDisplay(rating: ScoringResult['rating']): {
|
|
315
|
+
emoji: string;
|
|
316
|
+
color: string;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* Format score for display with rating
|
|
320
|
+
*/
|
|
321
|
+
declare function formatScore(result: ScoringResult): string;
|
|
322
|
+
/**
|
|
323
|
+
* Format individual tool score for display
|
|
324
|
+
*/
|
|
325
|
+
declare function formatToolScore(output: ToolScoringOutput): string;
|
|
326
|
+
|
|
327
|
+
export { type AIReadyConfig, type ASTNode, type AnalysisResult, type CLIOptions, DEFAULT_EXCLUDE, DEFAULT_TOOL_WEIGHTS, type ExportWithImports, type FileImport, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, type ScoringConfig, type ScoringResult, TOOL_NAME_MAP, type ToolScoringOutput, calculateImportSimilarity, calculateOverallScore, estimateTokens, extractFunctions, extractImports, formatScore, formatToolScore, getElapsedTime, getFileExtension, getRating, getRatingDisplay, getToolWeight, handleCLIError, handleJSONOutput, isSourceFile, loadConfig, loadMergedConfig, mergeConfigWithDefaults, normalizeToolName, parseCode, parseFileExports, parseWeightString, readFileContent, resolveOutputPath, scanFiles };
|
package/dist/index.js
CHANGED
|
@@ -21,20 +21,30 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
DEFAULT_EXCLUDE: () => DEFAULT_EXCLUDE,
|
|
24
|
+
DEFAULT_TOOL_WEIGHTS: () => DEFAULT_TOOL_WEIGHTS,
|
|
25
|
+
TOOL_NAME_MAP: () => TOOL_NAME_MAP,
|
|
24
26
|
calculateImportSimilarity: () => calculateImportSimilarity,
|
|
27
|
+
calculateOverallScore: () => calculateOverallScore,
|
|
25
28
|
estimateTokens: () => estimateTokens,
|
|
26
29
|
extractFunctions: () => extractFunctions,
|
|
27
30
|
extractImports: () => extractImports,
|
|
31
|
+
formatScore: () => formatScore,
|
|
32
|
+
formatToolScore: () => formatToolScore,
|
|
28
33
|
getElapsedTime: () => getElapsedTime,
|
|
29
34
|
getFileExtension: () => getFileExtension,
|
|
35
|
+
getRating: () => getRating,
|
|
36
|
+
getRatingDisplay: () => getRatingDisplay,
|
|
37
|
+
getToolWeight: () => getToolWeight,
|
|
30
38
|
handleCLIError: () => handleCLIError,
|
|
31
39
|
handleJSONOutput: () => handleJSONOutput,
|
|
32
40
|
isSourceFile: () => isSourceFile,
|
|
33
41
|
loadConfig: () => loadConfig,
|
|
34
42
|
loadMergedConfig: () => loadMergedConfig,
|
|
35
43
|
mergeConfigWithDefaults: () => mergeConfigWithDefaults,
|
|
44
|
+
normalizeToolName: () => normalizeToolName,
|
|
36
45
|
parseCode: () => parseCode,
|
|
37
46
|
parseFileExports: () => parseFileExports,
|
|
47
|
+
parseWeightString: () => parseWeightString,
|
|
38
48
|
readFileContent: () => readFileContent,
|
|
39
49
|
resolveOutputPath: () => resolveOutputPath,
|
|
40
50
|
scanFiles: () => scanFiles
|
|
@@ -44,6 +54,8 @@ module.exports = __toCommonJS(index_exports);
|
|
|
44
54
|
// src/utils/file-scanner.ts
|
|
45
55
|
var import_glob = require("glob");
|
|
46
56
|
var import_promises = require("fs/promises");
|
|
57
|
+
var import_fs = require("fs");
|
|
58
|
+
var import_path = require("path");
|
|
47
59
|
var DEFAULT_EXCLUDE = [
|
|
48
60
|
// Dependencies
|
|
49
61
|
"**/node_modules/**",
|
|
@@ -96,7 +108,17 @@ async function scanFiles(options) {
|
|
|
96
108
|
// Broad default - tools should filter further
|
|
97
109
|
exclude
|
|
98
110
|
} = options;
|
|
99
|
-
const
|
|
111
|
+
const ignoreFilePath = (0, import_path.join)(rootDir || ".", ".aireadyignore");
|
|
112
|
+
let ignoreFromFile = [];
|
|
113
|
+
if ((0, import_fs.existsSync)(ignoreFilePath)) {
|
|
114
|
+
try {
|
|
115
|
+
const txt = await (0, import_promises.readFile)(ignoreFilePath, "utf-8");
|
|
116
|
+
ignoreFromFile = txt.split(/\r?\n/).map((s) => s.trim()).filter(Boolean).filter((l) => !l.startsWith("#")).filter((l) => !l.startsWith("!"));
|
|
117
|
+
} catch (e) {
|
|
118
|
+
ignoreFromFile = [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const finalExclude = [.../* @__PURE__ */ new Set([...exclude || [], ...ignoreFromFile, ...DEFAULT_EXCLUDE])];
|
|
100
122
|
const files = await (0, import_glob.glob)(include, {
|
|
101
123
|
cwd: rootDir,
|
|
102
124
|
ignore: finalExclude,
|
|
@@ -295,8 +317,8 @@ function estimateTokens(text) {
|
|
|
295
317
|
}
|
|
296
318
|
|
|
297
319
|
// src/utils/config.ts
|
|
298
|
-
var
|
|
299
|
-
var
|
|
320
|
+
var import_fs2 = require("fs");
|
|
321
|
+
var import_path2 = require("path");
|
|
300
322
|
var import_url = require("url");
|
|
301
323
|
var CONFIG_FILES = [
|
|
302
324
|
"aiready.json",
|
|
@@ -307,11 +329,11 @@ var CONFIG_FILES = [
|
|
|
307
329
|
".aireadyrc.js"
|
|
308
330
|
];
|
|
309
331
|
async function loadConfig(rootDir) {
|
|
310
|
-
let currentDir = (0,
|
|
332
|
+
let currentDir = (0, import_path2.resolve)(rootDir);
|
|
311
333
|
while (true) {
|
|
312
334
|
for (const configFile of CONFIG_FILES) {
|
|
313
|
-
const configPath = (0,
|
|
314
|
-
if ((0,
|
|
335
|
+
const configPath = (0, import_path2.join)(currentDir, configFile);
|
|
336
|
+
if ((0, import_fs2.existsSync)(configPath)) {
|
|
315
337
|
try {
|
|
316
338
|
let config;
|
|
317
339
|
if (configFile.endsWith(".js")) {
|
|
@@ -319,7 +341,7 @@ async function loadConfig(rootDir) {
|
|
|
319
341
|
const module2 = await import(`${fileUrl}?t=${Date.now()}`);
|
|
320
342
|
config = module2.default || module2;
|
|
321
343
|
} else {
|
|
322
|
-
const content = (0,
|
|
344
|
+
const content = (0, import_fs2.readFileSync)(configPath, "utf-8");
|
|
323
345
|
config = JSON.parse(content);
|
|
324
346
|
}
|
|
325
347
|
if (typeof config !== "object" || config === null) {
|
|
@@ -332,7 +354,7 @@ async function loadConfig(rootDir) {
|
|
|
332
354
|
}
|
|
333
355
|
}
|
|
334
356
|
}
|
|
335
|
-
const parent = (0,
|
|
357
|
+
const parent = (0, import_path2.dirname)(currentDir);
|
|
336
358
|
if (parent === currentDir) {
|
|
337
359
|
break;
|
|
338
360
|
}
|
|
@@ -364,19 +386,19 @@ function mergeConfigWithDefaults(userConfig, defaults) {
|
|
|
364
386
|
}
|
|
365
387
|
|
|
366
388
|
// src/utils/cli-helpers.ts
|
|
367
|
-
var
|
|
368
|
-
var
|
|
389
|
+
var import_fs3 = require("fs");
|
|
390
|
+
var import_path3 = require("path");
|
|
369
391
|
function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()) {
|
|
370
392
|
let outputPath;
|
|
371
393
|
if (userPath) {
|
|
372
394
|
outputPath = userPath;
|
|
373
395
|
} else {
|
|
374
|
-
const aireadyDir = (0,
|
|
375
|
-
outputPath = (0,
|
|
396
|
+
const aireadyDir = (0, import_path3.join)(workingDir, ".aiready");
|
|
397
|
+
outputPath = (0, import_path3.join)(aireadyDir, defaultFilename);
|
|
376
398
|
}
|
|
377
|
-
const parentDir = (0,
|
|
378
|
-
if (!(0,
|
|
379
|
-
(0,
|
|
399
|
+
const parentDir = (0, import_path3.dirname)(outputPath);
|
|
400
|
+
if (!(0, import_fs3.existsSync)(parentDir)) {
|
|
401
|
+
(0, import_fs3.mkdirSync)(parentDir, { recursive: true });
|
|
380
402
|
}
|
|
381
403
|
return outputPath;
|
|
382
404
|
}
|
|
@@ -392,11 +414,11 @@ async function loadMergedConfig(directory, defaults, cliOptions) {
|
|
|
392
414
|
}
|
|
393
415
|
function handleJSONOutput(data, outputFile, successMessage) {
|
|
394
416
|
if (outputFile) {
|
|
395
|
-
const dir = (0,
|
|
396
|
-
if (!(0,
|
|
397
|
-
(0,
|
|
417
|
+
const dir = (0, import_path3.dirname)(outputFile);
|
|
418
|
+
if (!(0, import_fs3.existsSync)(dir)) {
|
|
419
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true });
|
|
398
420
|
}
|
|
399
|
-
(0,
|
|
421
|
+
(0, import_fs3.writeFileSync)(outputFile, JSON.stringify(data, null, 2));
|
|
400
422
|
console.log(successMessage || `\u2705 Results saved to ${outputFile}`);
|
|
401
423
|
} else {
|
|
402
424
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -409,23 +431,177 @@ function handleCLIError(error, commandName) {
|
|
|
409
431
|
function getElapsedTime(startTime) {
|
|
410
432
|
return ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
411
433
|
}
|
|
434
|
+
|
|
435
|
+
// src/scoring.ts
|
|
436
|
+
var DEFAULT_TOOL_WEIGHTS = {
|
|
437
|
+
"pattern-detect": 40,
|
|
438
|
+
"context-analyzer": 35,
|
|
439
|
+
"consistency": 25,
|
|
440
|
+
"doc-drift": 20,
|
|
441
|
+
"deps": 15
|
|
442
|
+
};
|
|
443
|
+
var TOOL_NAME_MAP = {
|
|
444
|
+
"patterns": "pattern-detect",
|
|
445
|
+
"context": "context-analyzer",
|
|
446
|
+
"consistency": "consistency",
|
|
447
|
+
"doc-drift": "doc-drift",
|
|
448
|
+
"deps": "deps"
|
|
449
|
+
};
|
|
450
|
+
function normalizeToolName(shortName) {
|
|
451
|
+
return TOOL_NAME_MAP[shortName] || shortName;
|
|
452
|
+
}
|
|
453
|
+
function getToolWeight(toolName, toolConfig, cliOverride) {
|
|
454
|
+
if (cliOverride !== void 0) {
|
|
455
|
+
return cliOverride;
|
|
456
|
+
}
|
|
457
|
+
if (toolConfig?.scoreWeight !== void 0) {
|
|
458
|
+
return toolConfig.scoreWeight;
|
|
459
|
+
}
|
|
460
|
+
return DEFAULT_TOOL_WEIGHTS[toolName] || 10;
|
|
461
|
+
}
|
|
462
|
+
function parseWeightString(weightStr) {
|
|
463
|
+
const weights = /* @__PURE__ */ new Map();
|
|
464
|
+
if (!weightStr) {
|
|
465
|
+
return weights;
|
|
466
|
+
}
|
|
467
|
+
const pairs = weightStr.split(",");
|
|
468
|
+
for (const pair of pairs) {
|
|
469
|
+
const [toolShortName, weightStr2] = pair.split(":");
|
|
470
|
+
if (toolShortName && weightStr2) {
|
|
471
|
+
const toolName = normalizeToolName(toolShortName.trim());
|
|
472
|
+
const weight = parseInt(weightStr2.trim(), 10);
|
|
473
|
+
if (!isNaN(weight) && weight > 0) {
|
|
474
|
+
weights.set(toolName, weight);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return weights;
|
|
479
|
+
}
|
|
480
|
+
function calculateOverallScore(toolOutputs, config, cliWeights) {
|
|
481
|
+
if (toolOutputs.size === 0) {
|
|
482
|
+
throw new Error("No tool outputs provided for scoring");
|
|
483
|
+
}
|
|
484
|
+
const weights = /* @__PURE__ */ new Map();
|
|
485
|
+
for (const [toolName] of toolOutputs.entries()) {
|
|
486
|
+
const cliWeight = cliWeights?.get(toolName);
|
|
487
|
+
const configWeight = config?.tools?.[toolName]?.scoreWeight;
|
|
488
|
+
const weight = cliWeight ?? configWeight ?? DEFAULT_TOOL_WEIGHTS[toolName] ?? 10;
|
|
489
|
+
weights.set(toolName, weight);
|
|
490
|
+
}
|
|
491
|
+
let weightedSum = 0;
|
|
492
|
+
let totalWeight = 0;
|
|
493
|
+
const breakdown = [];
|
|
494
|
+
const toolsUsed = [];
|
|
495
|
+
const calculationWeights = {};
|
|
496
|
+
for (const [toolName, output] of toolOutputs.entries()) {
|
|
497
|
+
const weight = weights.get(toolName) || 10;
|
|
498
|
+
const weightedScore = output.score * weight;
|
|
499
|
+
weightedSum += weightedScore;
|
|
500
|
+
totalWeight += weight;
|
|
501
|
+
toolsUsed.push(toolName);
|
|
502
|
+
calculationWeights[toolName] = weight;
|
|
503
|
+
breakdown.push(output);
|
|
504
|
+
}
|
|
505
|
+
const overall = Math.round(weightedSum / totalWeight);
|
|
506
|
+
const rating = getRating(overall);
|
|
507
|
+
const formulaParts = Array.from(toolOutputs.entries()).map(([name, output]) => {
|
|
508
|
+
const w = weights.get(name) || 10;
|
|
509
|
+
return `(${output.score} \xD7 ${w})`;
|
|
510
|
+
});
|
|
511
|
+
const formulaStr = `[${formulaParts.join(" + ")}] / ${totalWeight} = ${overall}`;
|
|
512
|
+
return {
|
|
513
|
+
overall,
|
|
514
|
+
rating,
|
|
515
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
516
|
+
toolsUsed,
|
|
517
|
+
breakdown,
|
|
518
|
+
calculation: {
|
|
519
|
+
formula: formulaStr,
|
|
520
|
+
weights: calculationWeights,
|
|
521
|
+
normalized: formulaStr
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function getRating(score) {
|
|
526
|
+
if (score >= 90) return "Excellent";
|
|
527
|
+
if (score >= 75) return "Good";
|
|
528
|
+
if (score >= 60) return "Fair";
|
|
529
|
+
if (score >= 40) return "Needs Work";
|
|
530
|
+
return "Critical";
|
|
531
|
+
}
|
|
532
|
+
function getRatingDisplay(rating) {
|
|
533
|
+
switch (rating) {
|
|
534
|
+
case "Excellent":
|
|
535
|
+
return { emoji: "\u2705", color: "green" };
|
|
536
|
+
case "Good":
|
|
537
|
+
return { emoji: "\u{1F44D}", color: "blue" };
|
|
538
|
+
case "Fair":
|
|
539
|
+
return { emoji: "\u26A0\uFE0F", color: "yellow" };
|
|
540
|
+
case "Needs Work":
|
|
541
|
+
return { emoji: "\u{1F528}", color: "orange" };
|
|
542
|
+
case "Critical":
|
|
543
|
+
return { emoji: "\u274C", color: "red" };
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function formatScore(result) {
|
|
547
|
+
const { emoji, color } = getRatingDisplay(result.rating);
|
|
548
|
+
return `${result.overall}/100 (${result.rating}) ${emoji}`;
|
|
549
|
+
}
|
|
550
|
+
function formatToolScore(output) {
|
|
551
|
+
let result = ` Score: ${output.score}/100
|
|
552
|
+
|
|
553
|
+
`;
|
|
554
|
+
if (output.factors && output.factors.length > 0) {
|
|
555
|
+
result += ` Factors:
|
|
556
|
+
`;
|
|
557
|
+
output.factors.forEach((factor) => {
|
|
558
|
+
const impactSign = factor.impact > 0 ? "+" : "";
|
|
559
|
+
result += ` \u2022 ${factor.name}: ${impactSign}${factor.impact} - ${factor.description}
|
|
560
|
+
`;
|
|
561
|
+
});
|
|
562
|
+
result += "\n";
|
|
563
|
+
}
|
|
564
|
+
if (output.recommendations && output.recommendations.length > 0) {
|
|
565
|
+
result += ` Recommendations:
|
|
566
|
+
`;
|
|
567
|
+
output.recommendations.forEach((rec, i) => {
|
|
568
|
+
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
569
|
+
result += ` ${i + 1}. ${priorityIcon} ${rec.action}
|
|
570
|
+
`;
|
|
571
|
+
result += ` Impact: +${rec.estimatedImpact} points
|
|
572
|
+
|
|
573
|
+
`;
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
return result;
|
|
577
|
+
}
|
|
412
578
|
// Annotate the CommonJS export names for ESM import in node:
|
|
413
579
|
0 && (module.exports = {
|
|
414
580
|
DEFAULT_EXCLUDE,
|
|
581
|
+
DEFAULT_TOOL_WEIGHTS,
|
|
582
|
+
TOOL_NAME_MAP,
|
|
415
583
|
calculateImportSimilarity,
|
|
584
|
+
calculateOverallScore,
|
|
416
585
|
estimateTokens,
|
|
417
586
|
extractFunctions,
|
|
418
587
|
extractImports,
|
|
588
|
+
formatScore,
|
|
589
|
+
formatToolScore,
|
|
419
590
|
getElapsedTime,
|
|
420
591
|
getFileExtension,
|
|
592
|
+
getRating,
|
|
593
|
+
getRatingDisplay,
|
|
594
|
+
getToolWeight,
|
|
421
595
|
handleCLIError,
|
|
422
596
|
handleJSONOutput,
|
|
423
597
|
isSourceFile,
|
|
424
598
|
loadConfig,
|
|
425
599
|
loadMergedConfig,
|
|
426
600
|
mergeConfigWithDefaults,
|
|
601
|
+
normalizeToolName,
|
|
427
602
|
parseCode,
|
|
428
603
|
parseFileExports,
|
|
604
|
+
parseWeightString,
|
|
429
605
|
readFileContent,
|
|
430
606
|
resolveOutputPath,
|
|
431
607
|
scanFiles
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/utils/file-scanner.ts
|
|
2
2
|
import { glob } from "glob";
|
|
3
3
|
import { readFile } from "fs/promises";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
4
6
|
var DEFAULT_EXCLUDE = [
|
|
5
7
|
// Dependencies
|
|
6
8
|
"**/node_modules/**",
|
|
@@ -53,7 +55,17 @@ async function scanFiles(options) {
|
|
|
53
55
|
// Broad default - tools should filter further
|
|
54
56
|
exclude
|
|
55
57
|
} = options;
|
|
56
|
-
const
|
|
58
|
+
const ignoreFilePath = join(rootDir || ".", ".aireadyignore");
|
|
59
|
+
let ignoreFromFile = [];
|
|
60
|
+
if (existsSync(ignoreFilePath)) {
|
|
61
|
+
try {
|
|
62
|
+
const txt = await readFile(ignoreFilePath, "utf-8");
|
|
63
|
+
ignoreFromFile = txt.split(/\r?\n/).map((s) => s.trim()).filter(Boolean).filter((l) => !l.startsWith("#")).filter((l) => !l.startsWith("!"));
|
|
64
|
+
} catch (e) {
|
|
65
|
+
ignoreFromFile = [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const finalExclude = [.../* @__PURE__ */ new Set([...exclude || [], ...ignoreFromFile, ...DEFAULT_EXCLUDE])];
|
|
57
69
|
const files = await glob(include, {
|
|
58
70
|
cwd: rootDir,
|
|
59
71
|
ignore: finalExclude,
|
|
@@ -252,8 +264,8 @@ function estimateTokens(text) {
|
|
|
252
264
|
}
|
|
253
265
|
|
|
254
266
|
// src/utils/config.ts
|
|
255
|
-
import { readFileSync, existsSync } from "fs";
|
|
256
|
-
import { join, resolve, dirname } from "path";
|
|
267
|
+
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
268
|
+
import { join as join2, resolve, dirname } from "path";
|
|
257
269
|
import { pathToFileURL } from "url";
|
|
258
270
|
var CONFIG_FILES = [
|
|
259
271
|
"aiready.json",
|
|
@@ -267,8 +279,8 @@ async function loadConfig(rootDir) {
|
|
|
267
279
|
let currentDir = resolve(rootDir);
|
|
268
280
|
while (true) {
|
|
269
281
|
for (const configFile of CONFIG_FILES) {
|
|
270
|
-
const configPath =
|
|
271
|
-
if (
|
|
282
|
+
const configPath = join2(currentDir, configFile);
|
|
283
|
+
if (existsSync2(configPath)) {
|
|
272
284
|
try {
|
|
273
285
|
let config;
|
|
274
286
|
if (configFile.endsWith(".js")) {
|
|
@@ -321,18 +333,18 @@ function mergeConfigWithDefaults(userConfig, defaults) {
|
|
|
321
333
|
}
|
|
322
334
|
|
|
323
335
|
// src/utils/cli-helpers.ts
|
|
324
|
-
import { writeFileSync, mkdirSync, existsSync as
|
|
325
|
-
import { join as
|
|
336
|
+
import { writeFileSync, mkdirSync, existsSync as existsSync3 } from "fs";
|
|
337
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
326
338
|
function resolveOutputPath(userPath, defaultFilename, workingDir = process.cwd()) {
|
|
327
339
|
let outputPath;
|
|
328
340
|
if (userPath) {
|
|
329
341
|
outputPath = userPath;
|
|
330
342
|
} else {
|
|
331
|
-
const aireadyDir =
|
|
332
|
-
outputPath =
|
|
343
|
+
const aireadyDir = join3(workingDir, ".aiready");
|
|
344
|
+
outputPath = join3(aireadyDir, defaultFilename);
|
|
333
345
|
}
|
|
334
346
|
const parentDir = dirname2(outputPath);
|
|
335
|
-
if (!
|
|
347
|
+
if (!existsSync3(parentDir)) {
|
|
336
348
|
mkdirSync(parentDir, { recursive: true });
|
|
337
349
|
}
|
|
338
350
|
return outputPath;
|
|
@@ -350,7 +362,7 @@ async function loadMergedConfig(directory, defaults, cliOptions) {
|
|
|
350
362
|
function handleJSONOutput(data, outputFile, successMessage) {
|
|
351
363
|
if (outputFile) {
|
|
352
364
|
const dir = dirname2(outputFile);
|
|
353
|
-
if (!
|
|
365
|
+
if (!existsSync3(dir)) {
|
|
354
366
|
mkdirSync(dir, { recursive: true });
|
|
355
367
|
}
|
|
356
368
|
writeFileSync(outputFile, JSON.stringify(data, null, 2));
|
|
@@ -366,22 +378,176 @@ function handleCLIError(error, commandName) {
|
|
|
366
378
|
function getElapsedTime(startTime) {
|
|
367
379
|
return ((Date.now() - startTime) / 1e3).toFixed(2);
|
|
368
380
|
}
|
|
381
|
+
|
|
382
|
+
// src/scoring.ts
|
|
383
|
+
var DEFAULT_TOOL_WEIGHTS = {
|
|
384
|
+
"pattern-detect": 40,
|
|
385
|
+
"context-analyzer": 35,
|
|
386
|
+
"consistency": 25,
|
|
387
|
+
"doc-drift": 20,
|
|
388
|
+
"deps": 15
|
|
389
|
+
};
|
|
390
|
+
var TOOL_NAME_MAP = {
|
|
391
|
+
"patterns": "pattern-detect",
|
|
392
|
+
"context": "context-analyzer",
|
|
393
|
+
"consistency": "consistency",
|
|
394
|
+
"doc-drift": "doc-drift",
|
|
395
|
+
"deps": "deps"
|
|
396
|
+
};
|
|
397
|
+
function normalizeToolName(shortName) {
|
|
398
|
+
return TOOL_NAME_MAP[shortName] || shortName;
|
|
399
|
+
}
|
|
400
|
+
function getToolWeight(toolName, toolConfig, cliOverride) {
|
|
401
|
+
if (cliOverride !== void 0) {
|
|
402
|
+
return cliOverride;
|
|
403
|
+
}
|
|
404
|
+
if (toolConfig?.scoreWeight !== void 0) {
|
|
405
|
+
return toolConfig.scoreWeight;
|
|
406
|
+
}
|
|
407
|
+
return DEFAULT_TOOL_WEIGHTS[toolName] || 10;
|
|
408
|
+
}
|
|
409
|
+
function parseWeightString(weightStr) {
|
|
410
|
+
const weights = /* @__PURE__ */ new Map();
|
|
411
|
+
if (!weightStr) {
|
|
412
|
+
return weights;
|
|
413
|
+
}
|
|
414
|
+
const pairs = weightStr.split(",");
|
|
415
|
+
for (const pair of pairs) {
|
|
416
|
+
const [toolShortName, weightStr2] = pair.split(":");
|
|
417
|
+
if (toolShortName && weightStr2) {
|
|
418
|
+
const toolName = normalizeToolName(toolShortName.trim());
|
|
419
|
+
const weight = parseInt(weightStr2.trim(), 10);
|
|
420
|
+
if (!isNaN(weight) && weight > 0) {
|
|
421
|
+
weights.set(toolName, weight);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return weights;
|
|
426
|
+
}
|
|
427
|
+
function calculateOverallScore(toolOutputs, config, cliWeights) {
|
|
428
|
+
if (toolOutputs.size === 0) {
|
|
429
|
+
throw new Error("No tool outputs provided for scoring");
|
|
430
|
+
}
|
|
431
|
+
const weights = /* @__PURE__ */ new Map();
|
|
432
|
+
for (const [toolName] of toolOutputs.entries()) {
|
|
433
|
+
const cliWeight = cliWeights?.get(toolName);
|
|
434
|
+
const configWeight = config?.tools?.[toolName]?.scoreWeight;
|
|
435
|
+
const weight = cliWeight ?? configWeight ?? DEFAULT_TOOL_WEIGHTS[toolName] ?? 10;
|
|
436
|
+
weights.set(toolName, weight);
|
|
437
|
+
}
|
|
438
|
+
let weightedSum = 0;
|
|
439
|
+
let totalWeight = 0;
|
|
440
|
+
const breakdown = [];
|
|
441
|
+
const toolsUsed = [];
|
|
442
|
+
const calculationWeights = {};
|
|
443
|
+
for (const [toolName, output] of toolOutputs.entries()) {
|
|
444
|
+
const weight = weights.get(toolName) || 10;
|
|
445
|
+
const weightedScore = output.score * weight;
|
|
446
|
+
weightedSum += weightedScore;
|
|
447
|
+
totalWeight += weight;
|
|
448
|
+
toolsUsed.push(toolName);
|
|
449
|
+
calculationWeights[toolName] = weight;
|
|
450
|
+
breakdown.push(output);
|
|
451
|
+
}
|
|
452
|
+
const overall = Math.round(weightedSum / totalWeight);
|
|
453
|
+
const rating = getRating(overall);
|
|
454
|
+
const formulaParts = Array.from(toolOutputs.entries()).map(([name, output]) => {
|
|
455
|
+
const w = weights.get(name) || 10;
|
|
456
|
+
return `(${output.score} \xD7 ${w})`;
|
|
457
|
+
});
|
|
458
|
+
const formulaStr = `[${formulaParts.join(" + ")}] / ${totalWeight} = ${overall}`;
|
|
459
|
+
return {
|
|
460
|
+
overall,
|
|
461
|
+
rating,
|
|
462
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
463
|
+
toolsUsed,
|
|
464
|
+
breakdown,
|
|
465
|
+
calculation: {
|
|
466
|
+
formula: formulaStr,
|
|
467
|
+
weights: calculationWeights,
|
|
468
|
+
normalized: formulaStr
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
function getRating(score) {
|
|
473
|
+
if (score >= 90) return "Excellent";
|
|
474
|
+
if (score >= 75) return "Good";
|
|
475
|
+
if (score >= 60) return "Fair";
|
|
476
|
+
if (score >= 40) return "Needs Work";
|
|
477
|
+
return "Critical";
|
|
478
|
+
}
|
|
479
|
+
function getRatingDisplay(rating) {
|
|
480
|
+
switch (rating) {
|
|
481
|
+
case "Excellent":
|
|
482
|
+
return { emoji: "\u2705", color: "green" };
|
|
483
|
+
case "Good":
|
|
484
|
+
return { emoji: "\u{1F44D}", color: "blue" };
|
|
485
|
+
case "Fair":
|
|
486
|
+
return { emoji: "\u26A0\uFE0F", color: "yellow" };
|
|
487
|
+
case "Needs Work":
|
|
488
|
+
return { emoji: "\u{1F528}", color: "orange" };
|
|
489
|
+
case "Critical":
|
|
490
|
+
return { emoji: "\u274C", color: "red" };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
function formatScore(result) {
|
|
494
|
+
const { emoji, color } = getRatingDisplay(result.rating);
|
|
495
|
+
return `${result.overall}/100 (${result.rating}) ${emoji}`;
|
|
496
|
+
}
|
|
497
|
+
function formatToolScore(output) {
|
|
498
|
+
let result = ` Score: ${output.score}/100
|
|
499
|
+
|
|
500
|
+
`;
|
|
501
|
+
if (output.factors && output.factors.length > 0) {
|
|
502
|
+
result += ` Factors:
|
|
503
|
+
`;
|
|
504
|
+
output.factors.forEach((factor) => {
|
|
505
|
+
const impactSign = factor.impact > 0 ? "+" : "";
|
|
506
|
+
result += ` \u2022 ${factor.name}: ${impactSign}${factor.impact} - ${factor.description}
|
|
507
|
+
`;
|
|
508
|
+
});
|
|
509
|
+
result += "\n";
|
|
510
|
+
}
|
|
511
|
+
if (output.recommendations && output.recommendations.length > 0) {
|
|
512
|
+
result += ` Recommendations:
|
|
513
|
+
`;
|
|
514
|
+
output.recommendations.forEach((rec, i) => {
|
|
515
|
+
const priorityIcon = rec.priority === "high" ? "\u{1F534}" : rec.priority === "medium" ? "\u{1F7E1}" : "\u{1F535}";
|
|
516
|
+
result += ` ${i + 1}. ${priorityIcon} ${rec.action}
|
|
517
|
+
`;
|
|
518
|
+
result += ` Impact: +${rec.estimatedImpact} points
|
|
519
|
+
|
|
520
|
+
`;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
369
525
|
export {
|
|
370
526
|
DEFAULT_EXCLUDE,
|
|
527
|
+
DEFAULT_TOOL_WEIGHTS,
|
|
528
|
+
TOOL_NAME_MAP,
|
|
371
529
|
calculateImportSimilarity,
|
|
530
|
+
calculateOverallScore,
|
|
372
531
|
estimateTokens,
|
|
373
532
|
extractFunctions,
|
|
374
533
|
extractImports,
|
|
534
|
+
formatScore,
|
|
535
|
+
formatToolScore,
|
|
375
536
|
getElapsedTime,
|
|
376
537
|
getFileExtension,
|
|
538
|
+
getRating,
|
|
539
|
+
getRatingDisplay,
|
|
540
|
+
getToolWeight,
|
|
377
541
|
handleCLIError,
|
|
378
542
|
handleJSONOutput,
|
|
379
543
|
isSourceFile,
|
|
380
544
|
loadConfig,
|
|
381
545
|
loadMergedConfig,
|
|
382
546
|
mergeConfigWithDefaults,
|
|
547
|
+
normalizeToolName,
|
|
383
548
|
parseCode,
|
|
384
549
|
parseFileExports,
|
|
550
|
+
parseWeightString,
|
|
385
551
|
readFileContent,
|
|
386
552
|
resolveOutputPath,
|
|
387
553
|
scanFiles
|