@aiready/agent-grounding 0.13.19 ā 0.13.21
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 +23 -24
- package/.turbo/turbo-lint.log +4 -5
- package/.turbo/turbo-test.log +16 -18
- package/dist/chunk-ER6KHJNN.mjs +251 -0
- package/dist/chunk-OFAWUHBZ.mjs +260 -0
- package/dist/chunk-SS3ETQAF.mjs +276 -0
- package/dist/cli.js +84 -153
- package/dist/cli.mjs +38 -61
- package/dist/index.d.mts +2 -6
- package/dist/index.d.ts +2 -6
- package/dist/index.js +49 -94
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/__tests__/scoring.test.ts +1 -1
- package/src/analyzer.ts +45 -64
- package/src/cli.ts +37 -69
- package/src/scoring.ts +21 -55
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _aiready_core from '@aiready/core';
|
|
2
|
-
import { Issue, IssueType, ScanOptions
|
|
2
|
+
import { Issue, IssueType, ScanOptions } from '@aiready/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Agent Grounding Tool Provider
|
|
@@ -67,11 +67,7 @@ declare function analyzeAgentGrounding(options: AgentGroundingOptions): Promise<
|
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Convert agent grounding report into a ToolScoringOutput.
|
|
70
|
-
*
|
|
71
|
-
* @param report - The detailed agent grounding report.
|
|
72
|
-
* @returns Standardized scoring and risk factor breakdown.
|
|
73
|
-
* @lastUpdated 2026-03-18
|
|
74
70
|
*/
|
|
75
|
-
declare function calculateGroundingScore(report: AgentGroundingReport):
|
|
71
|
+
declare function calculateGroundingScore(report: AgentGroundingReport): any;
|
|
76
72
|
|
|
77
73
|
export { type AgentGroundingIssue, type AgentGroundingOptions, AgentGroundingProvider, type AgentGroundingReport, analyzeAgentGrounding, calculateGroundingScore };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _aiready_core from '@aiready/core';
|
|
2
|
-
import { Issue, IssueType, ScanOptions
|
|
2
|
+
import { Issue, IssueType, ScanOptions } from '@aiready/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Agent Grounding Tool Provider
|
|
@@ -67,11 +67,7 @@ declare function analyzeAgentGrounding(options: AgentGroundingOptions): Promise<
|
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Convert agent grounding report into a ToolScoringOutput.
|
|
70
|
-
*
|
|
71
|
-
* @param report - The detailed agent grounding report.
|
|
72
|
-
* @returns Standardized scoring and risk factor breakdown.
|
|
73
|
-
* @lastUpdated 2026-03-18
|
|
74
70
|
*/
|
|
75
|
-
declare function calculateGroundingScore(report: AgentGroundingReport):
|
|
71
|
+
declare function calculateGroundingScore(report: AgentGroundingReport): any;
|
|
76
72
|
|
|
77
73
|
export { type AgentGroundingIssue, type AgentGroundingOptions, AgentGroundingProvider, type AgentGroundingReport, analyzeAgentGrounding, calculateGroundingScore };
|
package/dist/index.js
CHANGED
|
@@ -34,68 +34,45 @@ var import_core3 = require("@aiready/core");
|
|
|
34
34
|
var import_core = require("@aiready/core");
|
|
35
35
|
var import_fs = require("fs");
|
|
36
36
|
var import_path = require("path");
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
async function analyzeFile(filePath) {
|
|
38
|
+
const result = {
|
|
39
|
+
isBarrel: false,
|
|
40
|
+
exportedNames: [],
|
|
41
|
+
untypedExports: 0,
|
|
42
|
+
totalExports: 0,
|
|
43
|
+
domainTerms: []
|
|
44
|
+
};
|
|
45
|
+
const parser = await (0, import_core.getParser)(filePath);
|
|
46
|
+
if (!parser) return result;
|
|
39
47
|
let code;
|
|
40
48
|
try {
|
|
41
49
|
code = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
42
50
|
} catch {
|
|
43
|
-
return
|
|
44
|
-
isBarrel: false,
|
|
45
|
-
exportedNames: [],
|
|
46
|
-
untypedExports: 0,
|
|
47
|
-
totalExports: 0,
|
|
48
|
-
domainTerms: []
|
|
49
|
-
};
|
|
51
|
+
return result;
|
|
50
52
|
}
|
|
51
|
-
let ast;
|
|
52
53
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
untypedExports: 0,
|
|
63
|
-
totalExports: 0,
|
|
64
|
-
domainTerms: []
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
let isBarrel = false;
|
|
68
|
-
const exportedNames = [];
|
|
69
|
-
let untypedExports = 0;
|
|
70
|
-
let totalExports = 0;
|
|
71
|
-
const domainTerms = [];
|
|
72
|
-
for (const node of ast.body) {
|
|
73
|
-
if (node.type === "ExportAllDeclaration") {
|
|
74
|
-
isBarrel = true;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (node.type === "ExportNamedDeclaration") {
|
|
78
|
-
totalExports++;
|
|
79
|
-
const decl = node.declaration;
|
|
80
|
-
if (decl) {
|
|
81
|
-
const name = decl.id?.name ?? decl.declarations?.[0]?.id?.name;
|
|
82
|
-
if (name) {
|
|
83
|
-
exportedNames.push(name);
|
|
84
|
-
domainTerms.push(
|
|
54
|
+
await parser.initialize();
|
|
55
|
+
const parseResult = parser.parse(code, filePath);
|
|
56
|
+
for (const exp of parseResult.exports) {
|
|
57
|
+
if (exp.type === "function" || exp.type === "class" || exp.type === "const") {
|
|
58
|
+
result.totalExports++;
|
|
59
|
+
const name = exp.name;
|
|
60
|
+
if (name && name !== "default") {
|
|
61
|
+
result.exportedNames.push(name);
|
|
62
|
+
result.domainTerms.push(
|
|
85
63
|
...name.replace(/([A-Z])/g, " $1").toLowerCase().split(/\s+/).filter(Boolean)
|
|
86
64
|
);
|
|
87
|
-
|
|
88
|
-
|
|
65
|
+
if (exp.isTyped === false) {
|
|
66
|
+
result.untypedExports++;
|
|
67
|
+
}
|
|
89
68
|
}
|
|
90
|
-
} else if (node.specifiers && node.specifiers.length > 0) {
|
|
91
|
-
isBarrel = true;
|
|
92
69
|
}
|
|
70
|
+
if (parseResult.exports.length > 5) result.isBarrel = true;
|
|
93
71
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.warn(`Agent Grounding: Failed to parse ${filePath}: ${error}`);
|
|
97
74
|
}
|
|
98
|
-
return
|
|
75
|
+
return result;
|
|
99
76
|
}
|
|
100
77
|
function detectInconsistentTerms(allTerms) {
|
|
101
78
|
const termFreq = /* @__PURE__ */ new Map();
|
|
@@ -164,7 +141,7 @@ async function analyzeAgentGrounding(options) {
|
|
|
164
141
|
"analyzing files",
|
|
165
142
|
options.onProgress
|
|
166
143
|
);
|
|
167
|
-
const analysis = analyzeFile(f);
|
|
144
|
+
const analysis = await analyzeFile(f);
|
|
168
145
|
if (analysis.isBarrel) barrelExports++;
|
|
169
146
|
untypedExports += analysis.untypedExports;
|
|
170
147
|
totalExports += analysis.totalExports;
|
|
@@ -227,11 +204,11 @@ async function analyzeAgentGrounding(options) {
|
|
|
227
204
|
suggestion: "Update README.md to reflect the current codebase structure."
|
|
228
205
|
});
|
|
229
206
|
}
|
|
230
|
-
if (
|
|
207
|
+
if (untypedExports > 0) {
|
|
231
208
|
issues.push({
|
|
232
209
|
type: import_core.IssueType.AgentNavigationFailure,
|
|
233
210
|
dimension: "api-clarity",
|
|
234
|
-
severity: import_core.Severity.Major,
|
|
211
|
+
severity: groundingResult.dimensions.apiClarityScore < 70 ? import_core.Severity.Major : import_core.Severity.Minor,
|
|
235
212
|
message: `${untypedExports} of ${totalExports} public exports lack TypeScript type annotations \u2014 agents cannot infer the API contract.`,
|
|
236
213
|
location: { file: rootDir, line: 0 },
|
|
237
214
|
suggestion: "Add explicit return type and parameter annotations to all exported functions."
|
|
@@ -277,50 +254,28 @@ async function analyzeAgentGrounding(options) {
|
|
|
277
254
|
var import_core2 = require("@aiready/core");
|
|
278
255
|
function calculateGroundingScore(report) {
|
|
279
256
|
const { summary, rawData, recommendations } = report;
|
|
280
|
-
|
|
281
|
-
{
|
|
282
|
-
name: "Structure Clarity",
|
|
283
|
-
impact: Math.round(summary.dimensions.structureClarityScore - 50),
|
|
284
|
-
description: `${rawData.deepDirectories} of ${rawData.totalDirectories} dirs exceed recommended depth`
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
name: "Self-Documentation",
|
|
288
|
-
impact: Math.round(summary.dimensions.selfDocumentationScore - 50),
|
|
289
|
-
description: `${rawData.vagueFileNames} of ${rawData.totalFiles} files have vague names`
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
name: "Entry Points",
|
|
293
|
-
impact: Math.round(summary.dimensions.entryPointScore - 50),
|
|
294
|
-
description: rawData.hasRootReadme ? rawData.readmeIsFresh ? "README present and fresh" : "README present but stale" : "No root README"
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
name: "API Clarity",
|
|
298
|
-
impact: Math.round(summary.dimensions.apiClarityScore - 50),
|
|
299
|
-
description: `${rawData.untypedExports} of ${rawData.totalExports} exports lack type annotations`
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
name: "Domain Consistency",
|
|
303
|
-
impact: Math.round(summary.dimensions.domainConsistencyScore - 50),
|
|
304
|
-
description: `${rawData.inconsistentDomainTerms} inconsistent domain terms detected`
|
|
305
|
-
}
|
|
306
|
-
];
|
|
307
|
-
const recs = recommendations.map(
|
|
308
|
-
(action) => ({
|
|
309
|
-
action,
|
|
310
|
-
estimatedImpact: 6,
|
|
311
|
-
priority: summary.score < 50 ? "high" : "medium"
|
|
312
|
-
})
|
|
313
|
-
);
|
|
314
|
-
return {
|
|
257
|
+
return (0, import_core2.buildStandardToolScore)({
|
|
315
258
|
toolName: import_core2.ToolName.AgentGrounding,
|
|
316
259
|
score: summary.score,
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
260
|
+
rawData,
|
|
261
|
+
dimensions: {
|
|
262
|
+
structureClarityScore: summary.dimensions.structureClarityScore,
|
|
263
|
+
selfDocumentationScore: summary.dimensions.selfDocumentationScore,
|
|
264
|
+
entryPointScore: summary.dimensions.entryPointScore,
|
|
265
|
+
apiClarityScore: summary.dimensions.apiClarityScore,
|
|
266
|
+
domainConsistencyScore: summary.dimensions.domainConsistencyScore
|
|
320
267
|
},
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
268
|
+
dimensionNames: {
|
|
269
|
+
structureClarityScore: "Structure Clarity",
|
|
270
|
+
selfDocumentationScore: "Self-Documentation",
|
|
271
|
+
entryPointScore: "Entry Points",
|
|
272
|
+
apiClarityScore: "API Clarity",
|
|
273
|
+
domainConsistencyScore: "Domain Consistency"
|
|
274
|
+
},
|
|
275
|
+
recommendations,
|
|
276
|
+
recommendationImpact: 6,
|
|
277
|
+
rating: summary.rating
|
|
278
|
+
});
|
|
324
279
|
}
|
|
325
280
|
|
|
326
281
|
// src/provider.ts
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/agent-grounding",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.21",
|
|
4
4
|
"description": "Measures how well an AI agent can navigate a codebase autonomously without human assistance",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
41
|
"commander": "^14.0.0",
|
|
42
42
|
"glob": "^13.0.0",
|
|
43
|
-
"@aiready/core": "0.23.
|
|
43
|
+
"@aiready/core": "0.23.22"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^24.0.0",
|
|
@@ -43,7 +43,7 @@ describe('Agent Grounding Scoring', () => {
|
|
|
43
43
|
expect(scoring.factors.length).toBe(5);
|
|
44
44
|
|
|
45
45
|
const apiClarityFactor = scoring.factors.find(
|
|
46
|
-
(f) => f.name === 'API Clarity'
|
|
46
|
+
(f: any) => f.name === 'API Clarity'
|
|
47
47
|
);
|
|
48
48
|
expect(apiClarityFactor?.impact).toBe(0); // 50 - 50
|
|
49
49
|
expect(apiClarityFactor?.description).toContain(
|
package/src/analyzer.ts
CHANGED
|
@@ -16,11 +16,10 @@ import {
|
|
|
16
16
|
Severity,
|
|
17
17
|
IssueType,
|
|
18
18
|
emitProgress,
|
|
19
|
+
getParser,
|
|
19
20
|
} from '@aiready/core';
|
|
20
21
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
21
22
|
import { join, extname, basename, relative } from 'path';
|
|
22
|
-
import { parse } from '@typescript-eslint/typescript-estree';
|
|
23
|
-
import type { TSESTree } from '@typescript-eslint/types';
|
|
24
23
|
import type {
|
|
25
24
|
AgentGroundingOptions,
|
|
26
25
|
AgentGroundingIssue,
|
|
@@ -39,59 +38,41 @@ interface FileAnalysis {
|
|
|
39
38
|
domainTerms: string[];
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
function analyzeFile(filePath: string): FileAnalysis {
|
|
41
|
+
async function analyzeFile(filePath: string): Promise<FileAnalysis> {
|
|
42
|
+
const result: FileAnalysis = {
|
|
43
|
+
isBarrel: false,
|
|
44
|
+
exportedNames: [],
|
|
45
|
+
untypedExports: 0,
|
|
46
|
+
totalExports: 0,
|
|
47
|
+
domainTerms: [],
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const parser = await getParser(filePath);
|
|
51
|
+
if (!parser) return result;
|
|
52
|
+
|
|
43
53
|
let code: string;
|
|
44
54
|
try {
|
|
45
55
|
code = readFileSync(filePath, 'utf-8');
|
|
46
56
|
} catch {
|
|
47
|
-
return
|
|
48
|
-
isBarrel: false,
|
|
49
|
-
exportedNames: [],
|
|
50
|
-
untypedExports: 0,
|
|
51
|
-
totalExports: 0,
|
|
52
|
-
domainTerms: [],
|
|
53
|
-
};
|
|
57
|
+
return result;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
let ast: TSESTree.Program;
|
|
57
60
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
let isBarrel = false;
|
|
74
|
-
const exportedNames: string[] = [];
|
|
75
|
-
let untypedExports = 0;
|
|
76
|
-
let totalExports = 0;
|
|
77
|
-
|
|
78
|
-
// Extract "domain terms" from exported identifier names (camelCase split)
|
|
79
|
-
const domainTerms: string[] = [];
|
|
80
|
-
|
|
81
|
-
for (const node of ast.body) {
|
|
82
|
-
if (node.type === 'ExportAllDeclaration') {
|
|
83
|
-
isBarrel = true;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
if (node.type === 'ExportNamedDeclaration') {
|
|
87
|
-
totalExports++;
|
|
88
|
-
const decl = (node as any).declaration;
|
|
89
|
-
if (decl) {
|
|
90
|
-
const name = decl.id?.name ?? decl.declarations?.[0]?.id?.name;
|
|
91
|
-
if (name) {
|
|
92
|
-
exportedNames.push(name);
|
|
93
|
-
// Split camelCase into terms
|
|
94
|
-
domainTerms.push(
|
|
61
|
+
await parser.initialize();
|
|
62
|
+
const parseResult = parser.parse(code, filePath);
|
|
63
|
+
|
|
64
|
+
for (const exp of parseResult.exports) {
|
|
65
|
+
if (
|
|
66
|
+
exp.type === 'function' ||
|
|
67
|
+
exp.type === 'class' ||
|
|
68
|
+
exp.type === 'const'
|
|
69
|
+
) {
|
|
70
|
+
result.totalExports++;
|
|
71
|
+
const name = exp.name;
|
|
72
|
+
if (name && name !== 'default') {
|
|
73
|
+
result.exportedNames.push(name);
|
|
74
|
+
// Domain consistency terms
|
|
75
|
+
result.domainTerms.push(
|
|
95
76
|
...name
|
|
96
77
|
.replace(/([A-Z])/g, ' $1')
|
|
97
78
|
.toLowerCase()
|
|
@@ -99,24 +80,21 @@ function analyzeFile(filePath: string): FileAnalysis {
|
|
|
99
80
|
.filter(Boolean)
|
|
100
81
|
);
|
|
101
82
|
|
|
102
|
-
// Check if it's
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
decl.typeParameters != null;
|
|
107
|
-
if (!hasType) untypedExports++;
|
|
83
|
+
// Check if it's untyped
|
|
84
|
+
if (exp.isTyped === false) {
|
|
85
|
+
result.untypedExports++;
|
|
86
|
+
}
|
|
108
87
|
}
|
|
109
|
-
} else if (node.specifiers && node.specifiers.length > 0) {
|
|
110
|
-
// Named re-exports from another module ā this is barrel-like
|
|
111
|
-
isBarrel = true;
|
|
112
88
|
}
|
|
89
|
+
|
|
90
|
+
// Barrel detection heuristic: if it has many exports
|
|
91
|
+
if (parseResult.exports.length > 5) result.isBarrel = true;
|
|
113
92
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.warn(`Agent Grounding: Failed to parse ${filePath}: ${error}`);
|
|
117
95
|
}
|
|
118
96
|
|
|
119
|
-
return
|
|
97
|
+
return result;
|
|
120
98
|
}
|
|
121
99
|
|
|
122
100
|
// ---------------------------------------------------------------------------
|
|
@@ -220,7 +198,7 @@ export async function analyzeAgentGrounding(
|
|
|
220
198
|
options.onProgress
|
|
221
199
|
);
|
|
222
200
|
|
|
223
|
-
const analysis = analyzeFile(f);
|
|
201
|
+
const analysis = await analyzeFile(f);
|
|
224
202
|
if (analysis.isBarrel) barrelExports++;
|
|
225
203
|
untypedExports += analysis.untypedExports;
|
|
226
204
|
totalExports += analysis.totalExports;
|
|
@@ -296,11 +274,14 @@ export async function analyzeAgentGrounding(
|
|
|
296
274
|
});
|
|
297
275
|
}
|
|
298
276
|
|
|
299
|
-
if (
|
|
277
|
+
if (untypedExports > 0) {
|
|
300
278
|
issues.push({
|
|
301
279
|
type: IssueType.AgentNavigationFailure,
|
|
302
280
|
dimension: 'api-clarity',
|
|
303
|
-
severity:
|
|
281
|
+
severity:
|
|
282
|
+
groundingResult.dimensions.apiClarityScore < 70
|
|
283
|
+
? Severity.Major
|
|
284
|
+
: Severity.Minor,
|
|
304
285
|
message: `${untypedExports} of ${totalExports} public exports lack TypeScript type annotations ā agents cannot infer the API contract.`,
|
|
305
286
|
location: { file: rootDir, line: 0 },
|
|
306
287
|
suggestion:
|
package/src/cli.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
loadConfig,
|
|
12
12
|
mergeConfigWithDefaults,
|
|
13
13
|
resolveOutputPath,
|
|
14
|
+
displayStandardConsoleReport,
|
|
14
15
|
} from '@aiready/core';
|
|
15
16
|
|
|
16
17
|
const program = new Command();
|
|
@@ -90,76 +91,43 @@ EXAMPLES:
|
|
|
90
91
|
writeFileSync(outputPath, JSON.stringify(payload, null, 2));
|
|
91
92
|
console.log(chalk.green(`ā Report saved to ${outputPath}`));
|
|
92
93
|
} else {
|
|
93
|
-
|
|
94
|
+
displayStandardConsoleReport({
|
|
95
|
+
title: 'š§ Agent Grounding Analysis',
|
|
96
|
+
score: scoring.summary.score,
|
|
97
|
+
rating: scoring.summary.rating,
|
|
98
|
+
dimensions: [
|
|
99
|
+
{
|
|
100
|
+
name: 'Structure Clarity',
|
|
101
|
+
value: scoring.summary.dimensions.structureClarityScore,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'Self-Documentation',
|
|
105
|
+
value: scoring.summary.dimensions.selfDocumentationScore,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'Entry Points',
|
|
109
|
+
value: scoring.summary.dimensions.entryPointScore,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'API Clarity',
|
|
113
|
+
value: scoring.summary.dimensions.apiClarityScore,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'Domain Consistency',
|
|
117
|
+
value: scoring.summary.dimensions.domainConsistencyScore,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
stats: [
|
|
121
|
+
{ label: 'Files', value: scoring.summary.filesAnalyzed },
|
|
122
|
+
{ label: 'Directories', value: scoring.summary.directoriesAnalyzed },
|
|
123
|
+
],
|
|
124
|
+
issues: report.issues,
|
|
125
|
+
recommendations: report.recommendations,
|
|
126
|
+
elapsedTime: elapsed,
|
|
127
|
+
noIssuesMessage:
|
|
128
|
+
'⨠No grounding issues found ā agents can navigate freely!',
|
|
129
|
+
});
|
|
94
130
|
}
|
|
95
131
|
});
|
|
96
132
|
|
|
97
133
|
program.parse();
|
|
98
|
-
|
|
99
|
-
function scoreColor(score: number) {
|
|
100
|
-
if (score >= 85) return chalk.green;
|
|
101
|
-
if (score >= 70) return chalk.cyan;
|
|
102
|
-
if (score >= 50) return chalk.yellow;
|
|
103
|
-
if (score >= 30) return chalk.red;
|
|
104
|
-
return chalk.bgRed.white;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function displayConsoleReport(report: any, scoring: any, elapsed: string) {
|
|
108
|
-
const { summary, issues, recommendations } = report;
|
|
109
|
-
|
|
110
|
-
console.log(chalk.bold('\nš§ Agent Grounding Analysis\n'));
|
|
111
|
-
console.log(
|
|
112
|
-
`Score: ${scoreColor(summary.score)(summary.score + '/100')} (${summary.rating.toUpperCase()})`
|
|
113
|
-
);
|
|
114
|
-
console.log(
|
|
115
|
-
`Files: ${chalk.cyan(summary.filesAnalyzed)} Directories: ${chalk.cyan(summary.directoriesAnalyzed)}`
|
|
116
|
-
);
|
|
117
|
-
console.log(`Analysis: ${chalk.gray(elapsed + 's')}\n`);
|
|
118
|
-
|
|
119
|
-
console.log(chalk.bold('š Dimension Scores\n'));
|
|
120
|
-
const dims = [
|
|
121
|
-
['Structure Clarity', summary.dimensions.structureClarityScore],
|
|
122
|
-
['Self-Documentation', summary.dimensions.selfDocumentationScore],
|
|
123
|
-
['Entry Points', summary.dimensions.entryPointScore],
|
|
124
|
-
['API Clarity', summary.dimensions.apiClarityScore],
|
|
125
|
-
['Domain Consistency', summary.dimensions.domainConsistencyScore],
|
|
126
|
-
];
|
|
127
|
-
for (const [name, val] of dims) {
|
|
128
|
-
const bar = 'ā'.repeat(Math.round((val as number) / 10)).padEnd(10, 'ā');
|
|
129
|
-
console.log(
|
|
130
|
-
` ${String(name).padEnd(22)} ${scoreColor(val as number)(bar)} ${val}/100`
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (issues.length > 0) {
|
|
135
|
-
console.log(chalk.bold('\nā ļø Issues Found\n'));
|
|
136
|
-
for (const issue of issues) {
|
|
137
|
-
const sev =
|
|
138
|
-
issue.severity === 'critical'
|
|
139
|
-
? chalk.red
|
|
140
|
-
: issue.severity === 'major'
|
|
141
|
-
? chalk.yellow
|
|
142
|
-
: chalk.blue;
|
|
143
|
-
console.log(`${sev(issue.severity.toUpperCase())} ${issue.message}`);
|
|
144
|
-
if (issue.suggestion)
|
|
145
|
-
console.log(
|
|
146
|
-
` ${chalk.dim('ā')} ${chalk.italic(issue.suggestion)}`
|
|
147
|
-
);
|
|
148
|
-
console.log();
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
console.log(
|
|
152
|
-
chalk.green(
|
|
153
|
-
'\n⨠No grounding issues found ā agents can navigate freely!\n'
|
|
154
|
-
)
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (recommendations.length > 0) {
|
|
159
|
-
console.log(chalk.bold('š” Recommendations\n'));
|
|
160
|
-
recommendations.forEach((rec: string, i: number) =>
|
|
161
|
-
console.log(`${i + 1}. ${rec}`)
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
console.log();
|
|
165
|
-
}
|
package/src/scoring.ts
CHANGED
|
@@ -1,66 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ToolName, buildStandardToolScore } from '@aiready/core';
|
|
2
2
|
import type { AgentGroundingReport } from './types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Convert agent grounding report into a ToolScoringOutput.
|
|
6
|
-
*
|
|
7
|
-
* @param report - The detailed agent grounding report.
|
|
8
|
-
* @returns Standardized scoring and risk factor breakdown.
|
|
9
|
-
* @lastUpdated 2026-03-18
|
|
10
6
|
*/
|
|
11
|
-
export function calculateGroundingScore(
|
|
12
|
-
report: AgentGroundingReport
|
|
13
|
-
): ToolScoringOutput {
|
|
7
|
+
export function calculateGroundingScore(report: AgentGroundingReport): any {
|
|
14
8
|
const { summary, rawData, recommendations } = report;
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
name: 'Structure Clarity',
|
|
19
|
-
impact: Math.round(summary.dimensions.structureClarityScore - 50),
|
|
20
|
-
description: `${rawData.deepDirectories} of ${rawData.totalDirectories} dirs exceed recommended depth`,
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: 'Self-Documentation',
|
|
24
|
-
impact: Math.round(summary.dimensions.selfDocumentationScore - 50),
|
|
25
|
-
description: `${rawData.vagueFileNames} of ${rawData.totalFiles} files have vague names`,
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: 'Entry Points',
|
|
29
|
-
impact: Math.round(summary.dimensions.entryPointScore - 50),
|
|
30
|
-
description: rawData.hasRootReadme
|
|
31
|
-
? rawData.readmeIsFresh
|
|
32
|
-
? 'README present and fresh'
|
|
33
|
-
: 'README present but stale'
|
|
34
|
-
: 'No root README',
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: 'API Clarity',
|
|
38
|
-
impact: Math.round(summary.dimensions.apiClarityScore - 50),
|
|
39
|
-
description: `${rawData.untypedExports} of ${rawData.totalExports} exports lack type annotations`,
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: 'Domain Consistency',
|
|
43
|
-
impact: Math.round(summary.dimensions.domainConsistencyScore - 50),
|
|
44
|
-
description: `${rawData.inconsistentDomainTerms} inconsistent domain terms detected`,
|
|
45
|
-
},
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
const recs: ToolScoringOutput['recommendations'] = recommendations.map(
|
|
49
|
-
(action) => ({
|
|
50
|
-
action,
|
|
51
|
-
estimatedImpact: 6,
|
|
52
|
-
priority: summary.score < 50 ? 'high' : 'medium',
|
|
53
|
-
})
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return {
|
|
10
|
+
return buildStandardToolScore({
|
|
57
11
|
toolName: ToolName.AgentGrounding,
|
|
58
12
|
score: summary.score,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
13
|
+
rawData,
|
|
14
|
+
dimensions: {
|
|
15
|
+
structureClarityScore: summary.dimensions.structureClarityScore,
|
|
16
|
+
selfDocumentationScore: summary.dimensions.selfDocumentationScore,
|
|
17
|
+
entryPointScore: summary.dimensions.entryPointScore,
|
|
18
|
+
apiClarityScore: summary.dimensions.apiClarityScore,
|
|
19
|
+
domainConsistencyScore: summary.dimensions.domainConsistencyScore,
|
|
20
|
+
},
|
|
21
|
+
dimensionNames: {
|
|
22
|
+
structureClarityScore: 'Structure Clarity',
|
|
23
|
+
selfDocumentationScore: 'Self-Documentation',
|
|
24
|
+
entryPointScore: 'Entry Points',
|
|
25
|
+
apiClarityScore: 'API Clarity',
|
|
26
|
+
domainConsistencyScore: 'Domain Consistency',
|
|
62
27
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
28
|
+
recommendations,
|
|
29
|
+
recommendationImpact: 6,
|
|
30
|
+
rating: summary.rating,
|
|
31
|
+
});
|
|
66
32
|
}
|