@aiready/agent-grounding 0.1.5 → 0.1.6

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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @aiready/agent-grounding@0.1.5 build /Users/pengcao/projects/aiready/packages/agent-grounding
3
+ > @aiready/agent-grounding@0.1.6 build /Users/pengcao/projects/aiready/packages/agent-grounding
4
4
  > tsup src/index.ts src/cli.ts --format cjs,esm --dts
5
5
 
6
6
  CLI Building entry: src/cli.ts, src/index.ts
@@ -9,15 +9,15 @@
9
9
  CLI Target: es2020
10
10
  CJS Build start
11
11
  ESM Build start
12
+ ESM dist/chunk-NHDH733I.mjs 10.51 KB
12
13
  ESM dist/index.mjs 154.00 B
13
- ESM dist/chunk-OOB3JMXQ.mjs 10.37 KB
14
- ESM dist/cli.mjs 5.04 KB
15
- ESM ⚡️ Build success in 1612ms
16
- CJS dist/index.js 11.62 KB
17
- CJS dist/cli.js 16.99 KB
18
- CJS ⚡️ Build success in 1620ms
14
+ ESM dist/cli.mjs 5.16 KB
15
+ ESM ⚡️ Build success in 39ms
16
+ CJS dist/index.js 11.76 KB
17
+ CJS dist/cli.js 17.24 KB
18
+ CJS ⚡️ Build success in 39ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 69473ms
20
+ DTS ⚡️ Build success in 4273ms
21
21
  DTS dist/cli.d.ts 20.00 B
22
22
  DTS dist/index.d.ts 2.34 KB
23
23
  DTS dist/cli.d.mts 20.00 B
@@ -1,17 +1,16 @@
1
1
 
2
2
  
3
- > @aiready/agent-grounding@0.1.5 test /Users/pengcao/projects/aiready/packages/agent-grounding
3
+ > @aiready/agent-grounding@0.1.6 test /Users/pengcao/projects/aiready/packages/agent-grounding
4
4
  > vitest run
5
5
 
6
6
  [?25l
7
7
   RUN  v4.0.18 /Users/pengcao/projects/aiready/packages/agent-grounding
8
8
 
9
- ✓ src/__tests__/analyzer.test.ts (3 tests) 1215ms
10
- ✓ should detect deep directories and vague file names  954ms
9
+ ✓ src/__tests__/analyzer.test.ts (3 tests) 16ms
11
10
 
12
11
   Test Files  1 passed (1)
13
12
   Tests  3 passed (3)
14
-  Start at  14:38:43
15
-  Duration  21.71s (transform 4.66s, setup 0ms, import 16.23s, tests 1.21s, environment 0ms)
13
+  Start at  22:19:17
14
+  Duration  829ms (transform 144ms, setup 0ms, import 656ms, tests 16ms, environment 0ms)
16
15
 
17
16
  [?25h
@@ -0,0 +1,336 @@
1
+ // src/analyzer.ts
2
+ import { readdirSync, statSync, existsSync, readFileSync } from "fs";
3
+ import { join, extname, basename } from "path";
4
+ import { parse } from "@typescript-eslint/typescript-estree";
5
+ import { calculateAgentGrounding } from "@aiready/core";
6
+ var VAGUE_FILE_NAMES = /* @__PURE__ */ new Set([
7
+ "utils",
8
+ "helpers",
9
+ "helper",
10
+ "misc",
11
+ "common",
12
+ "shared",
13
+ "tools",
14
+ "util",
15
+ "lib",
16
+ "libs",
17
+ "stuff",
18
+ "functions",
19
+ "methods",
20
+ "handlers",
21
+ "data",
22
+ "temp",
23
+ "tmp",
24
+ "test-utils",
25
+ "test-helpers",
26
+ "mocks"
27
+ ]);
28
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
29
+ var DEFAULT_EXCLUDES = [
30
+ "node_modules",
31
+ "dist",
32
+ ".git",
33
+ "coverage",
34
+ ".turbo",
35
+ "build"
36
+ ];
37
+ function collectEntries(dir, options, depth = 0, dirs = [], files = []) {
38
+ if (depth > (options.maxDepth ?? 20)) return { dirs, files };
39
+ const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
40
+ let entries;
41
+ try {
42
+ entries = readdirSync(dir);
43
+ } catch {
44
+ return { dirs, files };
45
+ }
46
+ for (const entry of entries) {
47
+ if (excludes.some((ex) => entry === ex || entry.includes(ex))) continue;
48
+ const full = join(dir, entry);
49
+ let stat;
50
+ try {
51
+ stat = statSync(full);
52
+ } catch {
53
+ continue;
54
+ }
55
+ if (stat.isDirectory()) {
56
+ dirs.push({ path: full, depth });
57
+ collectEntries(full, options, depth + 1, dirs, files);
58
+ } else if (stat.isFile() && SUPPORTED_EXTENSIONS.has(extname(full))) {
59
+ if (!options.include || options.include.some((p) => full.includes(p))) {
60
+ files.push(full);
61
+ }
62
+ }
63
+ }
64
+ return { dirs, files };
65
+ }
66
+ function analyzeFile(filePath) {
67
+ let code;
68
+ try {
69
+ code = readFileSync(filePath, "utf-8");
70
+ } catch {
71
+ return {
72
+ isBarrel: false,
73
+ exportedNames: [],
74
+ untypedExports: 0,
75
+ totalExports: 0,
76
+ domainTerms: []
77
+ };
78
+ }
79
+ let ast;
80
+ try {
81
+ ast = parse(code, {
82
+ jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
83
+ range: false,
84
+ loc: false
85
+ });
86
+ } catch {
87
+ return {
88
+ isBarrel: false,
89
+ exportedNames: [],
90
+ untypedExports: 0,
91
+ totalExports: 0,
92
+ domainTerms: []
93
+ };
94
+ }
95
+ let isBarrel = false;
96
+ const exportedNames = [];
97
+ let untypedExports = 0;
98
+ let totalExports = 0;
99
+ const domainTerms = [];
100
+ for (const node of ast.body) {
101
+ if (node.type === "ExportAllDeclaration") {
102
+ isBarrel = true;
103
+ continue;
104
+ }
105
+ if (node.type === "ExportNamedDeclaration") {
106
+ totalExports++;
107
+ const decl = node.declaration;
108
+ if (decl) {
109
+ const name = decl.id?.name ?? decl.declarations?.[0]?.id?.name;
110
+ if (name) {
111
+ exportedNames.push(name);
112
+ domainTerms.push(
113
+ ...name.replace(/([A-Z])/g, " $1").toLowerCase().split(/\s+/).filter(Boolean)
114
+ );
115
+ const hasType = decl.returnType != null || decl.declarations?.[0]?.id?.typeAnnotation != null || decl.typeParameters != null;
116
+ if (!hasType) untypedExports++;
117
+ }
118
+ } else if (node.specifiers && node.specifiers.length > 0) {
119
+ isBarrel = true;
120
+ }
121
+ }
122
+ if (node.type === "ExportDefaultDeclaration") {
123
+ totalExports++;
124
+ }
125
+ }
126
+ return { isBarrel, exportedNames, untypedExports, totalExports, domainTerms };
127
+ }
128
+ function detectInconsistentTerms(allTerms) {
129
+ const termFreq = /* @__PURE__ */ new Map();
130
+ for (const term of allTerms) {
131
+ if (term.length >= 3) {
132
+ termFreq.set(term, (termFreq.get(term) ?? 0) + 1);
133
+ }
134
+ }
135
+ const orphans = [...termFreq.values()].filter((count) => count === 1).length;
136
+ const common = [...termFreq.values()].filter((count) => count >= 3).length;
137
+ const vocabularySize = termFreq.size;
138
+ const inconsistent = Math.max(0, orphans - common * 2);
139
+ return { inconsistent, vocabularySize };
140
+ }
141
+ async function analyzeAgentGrounding(options) {
142
+ const rootDir = options.rootDir;
143
+ const maxRecommendedDepth = options.maxRecommendedDepth ?? 4;
144
+ const readmeStaleDays = options.readmeStaleDays ?? 90;
145
+ const { dirs, files } = collectEntries(rootDir, options);
146
+ const deepDirectories = dirs.filter(
147
+ (d) => d.depth > maxRecommendedDepth
148
+ ).length;
149
+ const additionalVague = new Set(
150
+ (options.additionalVagueNames ?? []).map((n) => n.toLowerCase())
151
+ );
152
+ let vagueFileNames = 0;
153
+ for (const f of files) {
154
+ const base = basename(f, extname(f)).toLowerCase();
155
+ if (VAGUE_FILE_NAMES.has(base) || additionalVague.has(base)) {
156
+ vagueFileNames++;
157
+ }
158
+ }
159
+ const readmePath = join(rootDir, "README.md");
160
+ const hasRootReadme = existsSync(readmePath);
161
+ let readmeIsFresh = false;
162
+ if (hasRootReadme) {
163
+ try {
164
+ const stat = statSync(readmePath);
165
+ const ageDays = (Date.now() - stat.mtimeMs) / (1e3 * 60 * 60 * 24);
166
+ readmeIsFresh = ageDays < readmeStaleDays;
167
+ } catch {
168
+ }
169
+ }
170
+ const allDomainTerms = [];
171
+ let barrelExports = 0;
172
+ let untypedExports = 0;
173
+ let totalExports = 0;
174
+ for (const f of files) {
175
+ const analysis = analyzeFile(f);
176
+ if (analysis.isBarrel) barrelExports++;
177
+ untypedExports += analysis.untypedExports;
178
+ totalExports += analysis.totalExports;
179
+ allDomainTerms.push(...analysis.domainTerms);
180
+ }
181
+ const {
182
+ inconsistent: inconsistentDomainTerms,
183
+ vocabularySize: domainVocabularySize
184
+ } = detectInconsistentTerms(allDomainTerms);
185
+ const groundingResult = calculateAgentGrounding({
186
+ deepDirectories,
187
+ totalDirectories: dirs.length,
188
+ vagueFileNames,
189
+ totalFiles: files.length,
190
+ hasRootReadme,
191
+ readmeIsFresh,
192
+ barrelExports,
193
+ untypedExports,
194
+ totalExports: Math.max(1, totalExports),
195
+ inconsistentDomainTerms,
196
+ domainVocabularySize: Math.max(1, domainVocabularySize)
197
+ });
198
+ const issues = [];
199
+ if (groundingResult.dimensions.structureClarityScore < 70) {
200
+ issues.push({
201
+ type: "agent-navigation-failure",
202
+ dimension: "structure-clarity",
203
+ severity: "major",
204
+ message: `${deepDirectories} directories exceed recommended depth of ${maxRecommendedDepth} \u2014 agents struggle to navigate deep trees.`,
205
+ location: { file: rootDir, line: 0 },
206
+ suggestion: `Flatten nested directories to ${maxRecommendedDepth} levels or fewer.`
207
+ });
208
+ }
209
+ if (groundingResult.dimensions.selfDocumentationScore < 70) {
210
+ issues.push({
211
+ type: "agent-navigation-failure",
212
+ dimension: "self-documentation",
213
+ severity: "major",
214
+ message: `${vagueFileNames} files use vague names (utils, helpers, misc) \u2014 an agent cannot determine their purpose from the name alone.`,
215
+ location: { file: rootDir, line: 0 },
216
+ suggestion: "Rename to domain-specific names: e.g., userAuthUtils \u2192 tokenValidator."
217
+ });
218
+ }
219
+ if (!hasRootReadme) {
220
+ issues.push({
221
+ type: "agent-navigation-failure",
222
+ dimension: "entry-point",
223
+ severity: "critical",
224
+ message: "No root README.md found \u2014 agents have no orientation document to start from.",
225
+ location: { file: join(rootDir, "README.md"), line: 0 },
226
+ suggestion: "Add a README.md explaining the project structure, entry points, and key conventions."
227
+ });
228
+ } else if (!readmeIsFresh) {
229
+ issues.push({
230
+ type: "agent-navigation-failure",
231
+ dimension: "entry-point",
232
+ severity: "minor",
233
+ message: `README.md is stale (>${readmeStaleDays} days without updates) \u2014 agents may be misled by outdated context.`,
234
+ location: { file: readmePath, line: 0 },
235
+ suggestion: "Update README.md to reflect the current codebase structure."
236
+ });
237
+ }
238
+ if (groundingResult.dimensions.apiClarityScore < 70) {
239
+ issues.push({
240
+ type: "agent-navigation-failure",
241
+ dimension: "api-clarity",
242
+ severity: "major",
243
+ message: `${untypedExports} of ${totalExports} public exports lack TypeScript type annotations \u2014 agents cannot infer the API contract.`,
244
+ location: { file: rootDir, line: 0 },
245
+ suggestion: "Add explicit return type and parameter annotations to all exported functions."
246
+ });
247
+ }
248
+ if (groundingResult.dimensions.domainConsistencyScore < 70) {
249
+ issues.push({
250
+ type: "agent-navigation-failure",
251
+ dimension: "domain-consistency",
252
+ severity: "major",
253
+ message: `${inconsistentDomainTerms} domain terms appear to be used inconsistently \u2014 agents get confused when one concept has multiple names.`,
254
+ location: { file: rootDir, line: 0 },
255
+ suggestion: "Establish a domain glossary and enforce one term per concept across the codebase."
256
+ });
257
+ }
258
+ return {
259
+ summary: {
260
+ filesAnalyzed: files.length,
261
+ directoriesAnalyzed: dirs.length,
262
+ score: groundingResult.score,
263
+ rating: groundingResult.rating,
264
+ dimensions: groundingResult.dimensions
265
+ },
266
+ issues,
267
+ rawData: {
268
+ deepDirectories,
269
+ totalDirectories: dirs.length,
270
+ vagueFileNames,
271
+ totalFiles: files.length,
272
+ hasRootReadme,
273
+ readmeIsFresh,
274
+ barrelExports,
275
+ untypedExports,
276
+ totalExports,
277
+ inconsistentDomainTerms,
278
+ domainVocabularySize
279
+ },
280
+ recommendations: groundingResult.recommendations
281
+ };
282
+ }
283
+
284
+ // src/scoring.ts
285
+ function calculateGroundingScore(report) {
286
+ const { summary, rawData, recommendations } = report;
287
+ const factors = [
288
+ {
289
+ name: "Structure Clarity",
290
+ impact: Math.round(summary.dimensions.structureClarityScore - 50),
291
+ description: `${rawData.deepDirectories} of ${rawData.totalDirectories} dirs exceed recommended depth`
292
+ },
293
+ {
294
+ name: "Self-Documentation",
295
+ impact: Math.round(summary.dimensions.selfDocumentationScore - 50),
296
+ description: `${rawData.vagueFileNames} of ${rawData.totalFiles} files have vague names`
297
+ },
298
+ {
299
+ name: "Entry Points",
300
+ impact: Math.round(summary.dimensions.entryPointScore - 50),
301
+ description: rawData.hasRootReadme ? rawData.readmeIsFresh ? "README present and fresh" : "README present but stale" : "No root README"
302
+ },
303
+ {
304
+ name: "API Clarity",
305
+ impact: Math.round(summary.dimensions.apiClarityScore - 50),
306
+ description: `${rawData.untypedExports} of ${rawData.totalExports} exports lack type annotations`
307
+ },
308
+ {
309
+ name: "Domain Consistency",
310
+ impact: Math.round(summary.dimensions.domainConsistencyScore - 50),
311
+ description: `${rawData.inconsistentDomainTerms} inconsistent domain terms detected`
312
+ }
313
+ ];
314
+ const recs = recommendations.map(
315
+ (action) => ({
316
+ action,
317
+ estimatedImpact: 6,
318
+ priority: summary.score < 50 ? "high" : "medium"
319
+ })
320
+ );
321
+ return {
322
+ toolName: "agent-grounding",
323
+ score: summary.score,
324
+ rawMetrics: {
325
+ ...rawData,
326
+ rating: summary.rating
327
+ },
328
+ factors,
329
+ recommendations: recs
330
+ };
331
+ }
332
+
333
+ export {
334
+ analyzeAgentGrounding,
335
+ calculateGroundingScore
336
+ };
package/dist/cli.js CHANGED
@@ -54,7 +54,14 @@ var VAGUE_FILE_NAMES = /* @__PURE__ */ new Set([
54
54
  "mocks"
55
55
  ]);
56
56
  var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
57
- var DEFAULT_EXCLUDES = ["node_modules", "dist", ".git", "coverage", ".turbo", "build"];
57
+ var DEFAULT_EXCLUDES = [
58
+ "node_modules",
59
+ "dist",
60
+ ".git",
61
+ "coverage",
62
+ ".turbo",
63
+ "build"
64
+ ];
58
65
  function collectEntries(dir, options, depth = 0, dirs = [], files = []) {
59
66
  if (depth > (options.maxDepth ?? 20)) return { dirs, files };
60
67
  const excludes = [...DEFAULT_EXCLUDES, ...options.exclude ?? []];
@@ -89,7 +96,13 @@ function analyzeFile(filePath) {
89
96
  try {
90
97
  code = (0, import_fs.readFileSync)(filePath, "utf-8");
91
98
  } catch {
92
- return { isBarrel: false, exportedNames: [], untypedExports: 0, totalExports: 0, domainTerms: [] };
99
+ return {
100
+ isBarrel: false,
101
+ exportedNames: [],
102
+ untypedExports: 0,
103
+ totalExports: 0,
104
+ domainTerms: []
105
+ };
93
106
  }
94
107
  let ast;
95
108
  try {
@@ -99,10 +112,16 @@ function analyzeFile(filePath) {
99
112
  loc: false
100
113
  });
101
114
  } catch {
102
- return { isBarrel: false, exportedNames: [], untypedExports: 0, totalExports: 0, domainTerms: [] };
115
+ return {
116
+ isBarrel: false,
117
+ exportedNames: [],
118
+ untypedExports: 0,
119
+ totalExports: 0,
120
+ domainTerms: []
121
+ };
103
122
  }
104
123
  let isBarrel = false;
105
- let exportedNames = [];
124
+ const exportedNames = [];
106
125
  let untypedExports = 0;
107
126
  let totalExports = 0;
108
127
  const domainTerms = [];
@@ -118,7 +137,9 @@ function analyzeFile(filePath) {
118
137
  const name = decl.id?.name ?? decl.declarations?.[0]?.id?.name;
119
138
  if (name) {
120
139
  exportedNames.push(name);
121
- domainTerms.push(...name.replace(/([A-Z])/g, " $1").toLowerCase().split(/\s+/).filter(Boolean));
140
+ domainTerms.push(
141
+ ...name.replace(/([A-Z])/g, " $1").toLowerCase().split(/\s+/).filter(Boolean)
142
+ );
122
143
  const hasType = decl.returnType != null || decl.declarations?.[0]?.id?.typeAnnotation != null || decl.typeParameters != null;
123
144
  if (!hasType) untypedExports++;
124
145
  }
@@ -150,8 +171,12 @@ async function analyzeAgentGrounding(options) {
150
171
  const maxRecommendedDepth = options.maxRecommendedDepth ?? 4;
151
172
  const readmeStaleDays = options.readmeStaleDays ?? 90;
152
173
  const { dirs, files } = collectEntries(rootDir, options);
153
- const deepDirectories = dirs.filter((d) => d.depth > maxRecommendedDepth).length;
154
- const additionalVague = new Set((options.additionalVagueNames ?? []).map((n) => n.toLowerCase()));
174
+ const deepDirectories = dirs.filter(
175
+ (d) => d.depth > maxRecommendedDepth
176
+ ).length;
177
+ const additionalVague = new Set(
178
+ (options.additionalVagueNames ?? []).map((n) => n.toLowerCase())
179
+ );
155
180
  let vagueFileNames = 0;
156
181
  for (const f of files) {
157
182
  const base = (0, import_path.basename)(f, (0, import_path.extname)(f)).toLowerCase();
@@ -181,7 +206,10 @@ async function analyzeAgentGrounding(options) {
181
206
  totalExports += analysis.totalExports;
182
207
  allDomainTerms.push(...analysis.domainTerms);
183
208
  }
184
- const { inconsistent: inconsistentDomainTerms, vocabularySize: domainVocabularySize } = detectInconsistentTerms(allDomainTerms);
209
+ const {
210
+ inconsistent: inconsistentDomainTerms,
211
+ vocabularySize: domainVocabularySize
212
+ } = detectInconsistentTerms(allDomainTerms);
185
213
  const groundingResult = (0, import_core.calculateAgentGrounding)({
186
214
  deepDirectories,
187
215
  totalDirectories: dirs.length,
@@ -283,7 +311,7 @@ async function analyzeAgentGrounding(options) {
283
311
 
284
312
  // src/scoring.ts
285
313
  function calculateGroundingScore(report) {
286
- const { summary, rawData, issues, recommendations } = report;
314
+ const { summary, rawData, recommendations } = report;
287
315
  const factors = [
288
316
  {
289
317
  name: "Structure Clarity",
@@ -311,11 +339,13 @@ function calculateGroundingScore(report) {
311
339
  description: `${rawData.inconsistentDomainTerms} inconsistent domain terms detected`
312
340
  }
313
341
  ];
314
- const recs = recommendations.map((action) => ({
315
- action,
316
- estimatedImpact: 6,
317
- priority: summary.score < 50 ? "high" : "medium"
318
- }));
342
+ const recs = recommendations.map(
343
+ (action) => ({
344
+ action,
345
+ estimatedImpact: 6,
346
+ priority: summary.score < 50 ? "high" : "medium"
347
+ })
348
+ );
319
349
  return {
320
350
  toolName: "agent-grounding",
321
351
  score: summary.score,
@@ -334,7 +364,11 @@ var import_fs2 = require("fs");
334
364
  var import_path2 = require("path");
335
365
  var import_core2 = require("@aiready/core");
336
366
  var program = new import_commander.Command();
337
- program.name("aiready-agent-grounding").description("Measure how well an AI agent can navigate your codebase autonomously").version("0.1.0").addHelpText("after", `
367
+ program.name("aiready-agent-grounding").description(
368
+ "Measure how well an AI agent can navigate your codebase autonomously"
369
+ ).version("0.1.0").addHelpText(
370
+ "after",
371
+ `
338
372
  GROUNDING DIMENSIONS:
339
373
  Structure Clarity Deep directory trees slow and confuse agents
340
374
  Self-Documentation Vague file names (utils, helpers) hide intent
@@ -346,7 +380,16 @@ EXAMPLES:
346
380
  aiready-agent-grounding . # Full analysis
347
381
  aiready-agent-grounding src/ --output json # JSON report
348
382
  aiready-agent-grounding . --max-depth 3 # Stricter depth limit
349
- `).argument("<directory>", "Directory to analyze").option("--max-depth <n>", "Max recommended directory depth (default: 4)", "4").option("--readme-stale-days <n>", "Days after which README is considered stale (default: 90)", "90").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console|json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
383
+ `
384
+ ).argument("<directory>", "Directory to analyze").option(
385
+ "--max-depth <n>",
386
+ "Max recommended directory depth (default: 4)",
387
+ "4"
388
+ ).option(
389
+ "--readme-stale-days <n>",
390
+ "Days after which README is considered stale (default: 90)",
391
+ "90"
392
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console|json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
350
393
  console.log(import_chalk.default.blue("\u{1F9ED} Analyzing agent grounding...\n"));
351
394
  const startTime = Date.now();
352
395
  const config = await (0, import_core2.loadConfig)(directory);
@@ -388,10 +431,14 @@ function scoreColor(score) {
388
431
  return import_chalk.default.bgRed.white;
389
432
  }
390
433
  function displayConsoleReport(report, scoring, elapsed) {
391
- const { summary, rawData, issues, recommendations } = report;
434
+ const { summary, issues, recommendations } = report;
392
435
  console.log(import_chalk.default.bold("\n\u{1F9ED} Agent Grounding Analysis\n"));
393
- console.log(`Score: ${scoreColor(summary.score)(summary.score + "/100")} (${summary.rating.toUpperCase()})`);
394
- console.log(`Files: ${import_chalk.default.cyan(summary.filesAnalyzed)} Directories: ${import_chalk.default.cyan(summary.directoriesAnalyzed)}`);
436
+ console.log(
437
+ `Score: ${scoreColor(summary.score)(summary.score + "/100")} (${summary.rating.toUpperCase()})`
438
+ );
439
+ console.log(
440
+ `Files: ${import_chalk.default.cyan(summary.filesAnalyzed)} Directories: ${import_chalk.default.cyan(summary.directoriesAnalyzed)}`
441
+ );
395
442
  console.log(`Analysis: ${import_chalk.default.gray(elapsed + "s")}
396
443
  `);
397
444
  console.log(import_chalk.default.bold("\u{1F4D0} Dimension Scores\n"));
@@ -404,22 +451,33 @@ function displayConsoleReport(report, scoring, elapsed) {
404
451
  ];
405
452
  for (const [name, val] of dims) {
406
453
  const bar = "\u2588".repeat(Math.round(val / 10)).padEnd(10, "\u2591");
407
- console.log(` ${String(name).padEnd(22)} ${scoreColor(val)(bar)} ${val}/100`);
454
+ console.log(
455
+ ` ${String(name).padEnd(22)} ${scoreColor(val)(bar)} ${val}/100`
456
+ );
408
457
  }
409
458
  if (issues.length > 0) {
410
459
  console.log(import_chalk.default.bold("\n\u26A0\uFE0F Issues Found\n"));
411
460
  for (const issue of issues) {
412
461
  const sev = issue.severity === "critical" ? import_chalk.default.red : issue.severity === "major" ? import_chalk.default.yellow : import_chalk.default.blue;
413
462
  console.log(`${sev(issue.severity.toUpperCase())} ${issue.message}`);
414
- if (issue.suggestion) console.log(` ${import_chalk.default.dim("\u2192")} ${import_chalk.default.italic(issue.suggestion)}`);
463
+ if (issue.suggestion)
464
+ console.log(
465
+ ` ${import_chalk.default.dim("\u2192")} ${import_chalk.default.italic(issue.suggestion)}`
466
+ );
415
467
  console.log();
416
468
  }
417
469
  } else {
418
- console.log(import_chalk.default.green("\n\u2728 No grounding issues found \u2014 agents can navigate freely!\n"));
470
+ console.log(
471
+ import_chalk.default.green(
472
+ "\n\u2728 No grounding issues found \u2014 agents can navigate freely!\n"
473
+ )
474
+ );
419
475
  }
420
476
  if (recommendations.length > 0) {
421
477
  console.log(import_chalk.default.bold("\u{1F4A1} Recommendations\n"));
422
- recommendations.forEach((rec, i) => console.log(`${i + 1}. ${rec}`));
478
+ recommendations.forEach(
479
+ (rec, i) => console.log(`${i + 1}. ${rec}`)
480
+ );
423
481
  }
424
482
  console.log();
425
483
  }