@aiready/agent-grounding 0.11.4 → 0.11.8
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 +12 -12
- package/.turbo/turbo-test.log +4 -4
- package/dist/chunk-7DOMO6A5.mjs +300 -0
- package/dist/cli.js +4 -2
- package/dist/cli.mjs +1 -1
- package/dist/index.js +4 -2
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/src/analyzer.ts +5 -2
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/agent-grounding@0.11.
|
|
3
|
+
> @aiready/agent-grounding@0.11.7 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
|
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
[34mCLI[39m Target: es2020
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
11
|
[34mESM[39m Build start
|
|
12
|
+
[32mCJS[39m [1mdist/index.js [22m[32m12.31 KB[39m
|
|
13
|
+
[32mCJS[39m [1mdist/cli.js [22m[32m16.54 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 67ms
|
|
12
15
|
[32mESM[39m [1mdist/index.mjs [22m[32m1.30 KB[39m
|
|
13
|
-
[32mESM[39m [1mdist/chunk-T5YTLYD6.mjs [22m[32m9.69 KB[39m
|
|
14
16
|
[32mESM[39m [1mdist/cli.mjs [22m[32m5.16 KB[39m
|
|
15
|
-
[32mESM[39m
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
DTS dist/cli.d.mts 20.00 B
|
|
24
|
-
DTS dist/index.d.mts 2.49 KB
|
|
17
|
+
[32mESM[39m [1mdist/chunk-7DOMO6A5.mjs [22m[32m9.73 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 68ms
|
|
19
|
+
[34mDTS[39m Build start
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 1572ms
|
|
21
|
+
[32mDTS[39m [1mdist/cli.d.ts [22m[32m20.00 B[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m2.49 KB[39m
|
|
23
|
+
[32mDTS[39m [1mdist/cli.d.mts [22m[32m20.00 B[39m
|
|
24
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m2.49 KB[39m
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @aiready/agent-grounding@0.11.
|
|
3
|
+
> @aiready/agent-grounding@0.11.7 test /Users/pengcao/projects/aiready/packages/agent-grounding
|
|
4
4
|
> vitest run
|
|
5
5
|
|
|
6
6
|
[?25l
|
|
7
7
|
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/Users/pengcao/projects/aiready/packages/agent-grounding[39m
|
|
8
8
|
|
|
9
|
-
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m3 tests[22m[2m)[22m[
|
|
9
|
+
[32m✓[39m src/__tests__/analyzer.test.ts [2m([22m[2m3 tests[22m[2m)[22m[33m 339[2mms[22m[39m
|
|
10
10
|
|
|
11
11
|
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
12
12
|
[2m Tests [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
13
|
-
[2m Start at [22m
|
|
14
|
-
[2m Duration [22m
|
|
13
|
+
[2m Start at [22m 13:15:42
|
|
14
|
+
[2m Duration [22m 1.98s[2m (transform 240ms, setup 0ms, import 1.09s, tests 339ms, environment 0ms)[22m
|
|
15
15
|
|
|
16
16
|
[?25h
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// src/analyzer.ts
|
|
2
|
+
import {
|
|
3
|
+
scanEntries,
|
|
4
|
+
calculateAgentGrounding,
|
|
5
|
+
VAGUE_FILE_NAMES,
|
|
6
|
+
Severity,
|
|
7
|
+
IssueType,
|
|
8
|
+
emitProgress
|
|
9
|
+
} from "@aiready/core";
|
|
10
|
+
import { readFileSync, existsSync, statSync } from "fs";
|
|
11
|
+
import { join, extname, basename, relative } from "path";
|
|
12
|
+
import { parse } from "@typescript-eslint/typescript-estree";
|
|
13
|
+
function analyzeFile(filePath) {
|
|
14
|
+
let code;
|
|
15
|
+
try {
|
|
16
|
+
code = readFileSync(filePath, "utf-8");
|
|
17
|
+
} catch {
|
|
18
|
+
return {
|
|
19
|
+
isBarrel: false,
|
|
20
|
+
exportedNames: [],
|
|
21
|
+
untypedExports: 0,
|
|
22
|
+
totalExports: 0,
|
|
23
|
+
domainTerms: []
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
let ast;
|
|
27
|
+
try {
|
|
28
|
+
ast = parse(code, {
|
|
29
|
+
jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
|
|
30
|
+
range: false,
|
|
31
|
+
loc: false
|
|
32
|
+
});
|
|
33
|
+
} catch {
|
|
34
|
+
return {
|
|
35
|
+
isBarrel: false,
|
|
36
|
+
exportedNames: [],
|
|
37
|
+
untypedExports: 0,
|
|
38
|
+
totalExports: 0,
|
|
39
|
+
domainTerms: []
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
let isBarrel = false;
|
|
43
|
+
const exportedNames = [];
|
|
44
|
+
let untypedExports = 0;
|
|
45
|
+
let totalExports = 0;
|
|
46
|
+
const domainTerms = [];
|
|
47
|
+
for (const node of ast.body) {
|
|
48
|
+
if (node.type === "ExportAllDeclaration") {
|
|
49
|
+
isBarrel = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (node.type === "ExportNamedDeclaration") {
|
|
53
|
+
totalExports++;
|
|
54
|
+
const decl = node.declaration;
|
|
55
|
+
if (decl) {
|
|
56
|
+
const name = decl.id?.name ?? decl.declarations?.[0]?.id?.name;
|
|
57
|
+
if (name) {
|
|
58
|
+
exportedNames.push(name);
|
|
59
|
+
domainTerms.push(
|
|
60
|
+
...name.replace(/([A-Z])/g, " $1").toLowerCase().split(/\s+/).filter(Boolean)
|
|
61
|
+
);
|
|
62
|
+
const hasType = decl.returnType != null || decl.declarations?.[0]?.id?.typeAnnotation != null || decl.typeParameters != null;
|
|
63
|
+
if (!hasType) untypedExports++;
|
|
64
|
+
}
|
|
65
|
+
} else if (node.specifiers && node.specifiers.length > 0) {
|
|
66
|
+
isBarrel = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (node.type === "ExportDefaultDeclaration") {
|
|
70
|
+
totalExports++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { isBarrel, exportedNames, untypedExports, totalExports, domainTerms };
|
|
74
|
+
}
|
|
75
|
+
function detectInconsistentTerms(allTerms) {
|
|
76
|
+
const termFreq = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const term of allTerms) {
|
|
78
|
+
if (term.length >= 3) {
|
|
79
|
+
termFreq.set(term, (termFreq.get(term) ?? 0) + 1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const orphans = [...termFreq.values()].filter((count) => count === 1).length;
|
|
83
|
+
const common = [...termFreq.values()].filter((count) => count >= 3).length;
|
|
84
|
+
const vocabularySize = termFreq.size;
|
|
85
|
+
const inconsistent = Math.max(0, orphans - common * 2);
|
|
86
|
+
return { inconsistent, vocabularySize };
|
|
87
|
+
}
|
|
88
|
+
async function analyzeAgentGrounding(options) {
|
|
89
|
+
const rootDir = options.rootDir;
|
|
90
|
+
const maxRecommendedDepth = options.maxRecommendedDepth ?? 4;
|
|
91
|
+
const readmeStaleDays = options.readmeStaleDays ?? 90;
|
|
92
|
+
const { files, dirs: rawDirs } = await scanEntries({
|
|
93
|
+
...options,
|
|
94
|
+
include: options.include || ["**/*.{ts,tsx,js,jsx}"]
|
|
95
|
+
});
|
|
96
|
+
const dirs = rawDirs.map((d) => ({
|
|
97
|
+
path: d,
|
|
98
|
+
depth: relative(rootDir, d).split(/[/\\]/).filter(Boolean).length
|
|
99
|
+
}));
|
|
100
|
+
const deepDirectories = dirs.filter(
|
|
101
|
+
(d) => d.depth > maxRecommendedDepth
|
|
102
|
+
).length;
|
|
103
|
+
const additionalVague = new Set(
|
|
104
|
+
(options.additionalVagueNames ?? []).map((n) => n.toLowerCase())
|
|
105
|
+
);
|
|
106
|
+
let vagueFileNames = 0;
|
|
107
|
+
for (const f of files) {
|
|
108
|
+
const base = basename(f, extname(f)).toLowerCase();
|
|
109
|
+
if (VAGUE_FILE_NAMES.has(base) || additionalVague.has(base)) {
|
|
110
|
+
vagueFileNames++;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const readmePath = join(rootDir, "README.md");
|
|
114
|
+
const hasRootReadme = existsSync(readmePath);
|
|
115
|
+
let readmeIsFresh = false;
|
|
116
|
+
if (hasRootReadme) {
|
|
117
|
+
try {
|
|
118
|
+
const stat = statSync(readmePath);
|
|
119
|
+
const ageDays = (Date.now() - stat.mtimeMs) / (1e3 * 60 * 60 * 24);
|
|
120
|
+
readmeIsFresh = ageDays < readmeStaleDays;
|
|
121
|
+
} catch {
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const allDomainTerms = [];
|
|
125
|
+
let barrelExports = 0;
|
|
126
|
+
let untypedExports = 0;
|
|
127
|
+
let totalExports = 0;
|
|
128
|
+
let processed = 0;
|
|
129
|
+
for (const f of files) {
|
|
130
|
+
processed++;
|
|
131
|
+
emitProgress(
|
|
132
|
+
processed,
|
|
133
|
+
files.length,
|
|
134
|
+
"agent-grounding",
|
|
135
|
+
"analyzing files",
|
|
136
|
+
options.onProgress
|
|
137
|
+
);
|
|
138
|
+
const analysis = analyzeFile(f);
|
|
139
|
+
if (analysis.isBarrel) barrelExports++;
|
|
140
|
+
untypedExports += analysis.untypedExports;
|
|
141
|
+
totalExports += analysis.totalExports;
|
|
142
|
+
allDomainTerms.push(...analysis.domainTerms);
|
|
143
|
+
}
|
|
144
|
+
const {
|
|
145
|
+
inconsistent: inconsistentDomainTerms,
|
|
146
|
+
vocabularySize: domainVocabularySize
|
|
147
|
+
} = detectInconsistentTerms(allDomainTerms);
|
|
148
|
+
const groundingResult = calculateAgentGrounding({
|
|
149
|
+
deepDirectories,
|
|
150
|
+
totalDirectories: dirs.length,
|
|
151
|
+
vagueFileNames,
|
|
152
|
+
totalFiles: files.length,
|
|
153
|
+
hasRootReadme,
|
|
154
|
+
readmeIsFresh,
|
|
155
|
+
barrelExports,
|
|
156
|
+
untypedExports,
|
|
157
|
+
totalExports: Math.max(1, totalExports),
|
|
158
|
+
inconsistentDomainTerms,
|
|
159
|
+
domainVocabularySize: Math.max(1, domainVocabularySize)
|
|
160
|
+
});
|
|
161
|
+
const issues = [];
|
|
162
|
+
if (groundingResult.dimensions.structureClarityScore < 70) {
|
|
163
|
+
issues.push({
|
|
164
|
+
type: IssueType.AgentNavigationFailure,
|
|
165
|
+
dimension: "structure-clarity",
|
|
166
|
+
severity: Severity.Major,
|
|
167
|
+
message: `${deepDirectories} directories exceed recommended depth of ${maxRecommendedDepth} \u2014 agents struggle to navigate deep trees.`,
|
|
168
|
+
location: { file: rootDir, line: 0 },
|
|
169
|
+
suggestion: `Flatten nested directories to ${maxRecommendedDepth} levels or fewer.`
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (groundingResult.dimensions.selfDocumentationScore < 70) {
|
|
173
|
+
issues.push({
|
|
174
|
+
type: IssueType.AgentNavigationFailure,
|
|
175
|
+
dimension: "self-documentation",
|
|
176
|
+
severity: Severity.Major,
|
|
177
|
+
message: `${vagueFileNames} files use vague names (utils, helpers, misc) \u2014 an agent cannot determine their purpose from the name alone.`,
|
|
178
|
+
location: { file: rootDir, line: 0 },
|
|
179
|
+
suggestion: "Rename to domain-specific names: e.g., userAuthUtils \u2192 tokenValidator."
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (!hasRootReadme) {
|
|
183
|
+
issues.push({
|
|
184
|
+
type: IssueType.AgentNavigationFailure,
|
|
185
|
+
dimension: "entry-point",
|
|
186
|
+
severity: Severity.Critical,
|
|
187
|
+
message: "No root README.md found \u2014 agents have no orientation document to start from.",
|
|
188
|
+
location: { file: join(rootDir, "README.md"), line: 0 },
|
|
189
|
+
suggestion: "Add a README.md explaining the project structure, entry points, and key conventions."
|
|
190
|
+
});
|
|
191
|
+
} else if (!readmeIsFresh) {
|
|
192
|
+
issues.push({
|
|
193
|
+
type: IssueType.AgentNavigationFailure,
|
|
194
|
+
dimension: "entry-point",
|
|
195
|
+
severity: Severity.Minor,
|
|
196
|
+
message: `README.md is stale (>${readmeStaleDays} days without updates) \u2014 agents may be misled by outdated context.`,
|
|
197
|
+
location: { file: readmePath, line: 0 },
|
|
198
|
+
suggestion: "Update README.md to reflect the current codebase structure."
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (groundingResult.dimensions.apiClarityScore < 70) {
|
|
202
|
+
issues.push({
|
|
203
|
+
type: IssueType.AgentNavigationFailure,
|
|
204
|
+
dimension: "api-clarity",
|
|
205
|
+
severity: Severity.Major,
|
|
206
|
+
message: `${untypedExports} of ${totalExports} public exports lack TypeScript type annotations \u2014 agents cannot infer the API contract.`,
|
|
207
|
+
location: { file: rootDir, line: 0 },
|
|
208
|
+
suggestion: "Add explicit return type and parameter annotations to all exported functions."
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (groundingResult.dimensions.domainConsistencyScore < 70) {
|
|
212
|
+
issues.push({
|
|
213
|
+
type: IssueType.AgentNavigationFailure,
|
|
214
|
+
dimension: "domain-consistency",
|
|
215
|
+
severity: Severity.Major,
|
|
216
|
+
message: `${inconsistentDomainTerms} domain terms appear to be used inconsistently \u2014 agents get confused when one concept has multiple names.`,
|
|
217
|
+
location: { file: rootDir, line: 0 },
|
|
218
|
+
suggestion: "Establish a domain glossary and enforce one term per concept across the codebase."
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
summary: {
|
|
223
|
+
filesAnalyzed: files.length,
|
|
224
|
+
directoriesAnalyzed: dirs.length,
|
|
225
|
+
score: groundingResult.score,
|
|
226
|
+
rating: groundingResult.rating,
|
|
227
|
+
dimensions: groundingResult.dimensions
|
|
228
|
+
},
|
|
229
|
+
issues,
|
|
230
|
+
rawData: {
|
|
231
|
+
deepDirectories,
|
|
232
|
+
totalDirectories: dirs.length,
|
|
233
|
+
vagueFileNames,
|
|
234
|
+
totalFiles: files.length,
|
|
235
|
+
hasRootReadme,
|
|
236
|
+
readmeIsFresh,
|
|
237
|
+
barrelExports,
|
|
238
|
+
untypedExports,
|
|
239
|
+
totalExports,
|
|
240
|
+
inconsistentDomainTerms,
|
|
241
|
+
domainVocabularySize
|
|
242
|
+
},
|
|
243
|
+
recommendations: groundingResult.recommendations
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/scoring.ts
|
|
248
|
+
import { ToolName } from "@aiready/core";
|
|
249
|
+
function calculateGroundingScore(report) {
|
|
250
|
+
const { summary, rawData, recommendations } = report;
|
|
251
|
+
const factors = [
|
|
252
|
+
{
|
|
253
|
+
name: "Structure Clarity",
|
|
254
|
+
impact: Math.round(summary.dimensions.structureClarityScore - 50),
|
|
255
|
+
description: `${rawData.deepDirectories} of ${rawData.totalDirectories} dirs exceed recommended depth`
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "Self-Documentation",
|
|
259
|
+
impact: Math.round(summary.dimensions.selfDocumentationScore - 50),
|
|
260
|
+
description: `${rawData.vagueFileNames} of ${rawData.totalFiles} files have vague names`
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: "Entry Points",
|
|
264
|
+
impact: Math.round(summary.dimensions.entryPointScore - 50),
|
|
265
|
+
description: rawData.hasRootReadme ? rawData.readmeIsFresh ? "README present and fresh" : "README present but stale" : "No root README"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "API Clarity",
|
|
269
|
+
impact: Math.round(summary.dimensions.apiClarityScore - 50),
|
|
270
|
+
description: `${rawData.untypedExports} of ${rawData.totalExports} exports lack type annotations`
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: "Domain Consistency",
|
|
274
|
+
impact: Math.round(summary.dimensions.domainConsistencyScore - 50),
|
|
275
|
+
description: `${rawData.inconsistentDomainTerms} inconsistent domain terms detected`
|
|
276
|
+
}
|
|
277
|
+
];
|
|
278
|
+
const recs = recommendations.map(
|
|
279
|
+
(action) => ({
|
|
280
|
+
action,
|
|
281
|
+
estimatedImpact: 6,
|
|
282
|
+
priority: summary.score < 50 ? "high" : "medium"
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
return {
|
|
286
|
+
toolName: ToolName.AgentGrounding,
|
|
287
|
+
score: summary.score,
|
|
288
|
+
rawMetrics: {
|
|
289
|
+
...rawData,
|
|
290
|
+
rating: summary.rating
|
|
291
|
+
},
|
|
292
|
+
factors,
|
|
293
|
+
recommendations: recs
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export {
|
|
298
|
+
analyzeAgentGrounding,
|
|
299
|
+
calculateGroundingScore
|
|
300
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -149,10 +149,12 @@ async function analyzeAgentGrounding(options) {
|
|
|
149
149
|
let processed = 0;
|
|
150
150
|
for (const f of files) {
|
|
151
151
|
processed++;
|
|
152
|
-
|
|
152
|
+
(0, import_core.emitProgress)(
|
|
153
153
|
processed,
|
|
154
154
|
files.length,
|
|
155
|
-
|
|
155
|
+
"agent-grounding",
|
|
156
|
+
"analyzing files",
|
|
157
|
+
options.onProgress
|
|
156
158
|
);
|
|
157
159
|
const analysis = analyzeFile(f);
|
|
158
160
|
if (analysis.isBarrel) barrelExports++;
|
package/dist/cli.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -153,10 +153,12 @@ async function analyzeAgentGrounding(options) {
|
|
|
153
153
|
let processed = 0;
|
|
154
154
|
for (const f of files) {
|
|
155
155
|
processed++;
|
|
156
|
-
|
|
156
|
+
(0, import_core.emitProgress)(
|
|
157
157
|
processed,
|
|
158
158
|
files.length,
|
|
159
|
-
|
|
159
|
+
"agent-grounding",
|
|
160
|
+
"analyzing files",
|
|
161
|
+
options.onProgress
|
|
160
162
|
);
|
|
161
163
|
const analysis = analyzeFile(f);
|
|
162
164
|
if (analysis.isBarrel) barrelExports++;
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/agent-grounding",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.8",
|
|
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.21.
|
|
43
|
+
"@aiready/core": "0.21.8"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^24.0.0",
|
package/src/analyzer.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
VAGUE_FILE_NAMES,
|
|
16
16
|
Severity,
|
|
17
17
|
IssueType,
|
|
18
|
+
emitProgress,
|
|
18
19
|
} from '@aiready/core';
|
|
19
20
|
import { readFileSync, existsSync, statSync } from 'fs';
|
|
20
21
|
import { join, extname, basename, relative } from 'path';
|
|
@@ -204,10 +205,12 @@ export async function analyzeAgentGrounding(
|
|
|
204
205
|
let processed = 0;
|
|
205
206
|
for (const f of files) {
|
|
206
207
|
processed++;
|
|
207
|
-
|
|
208
|
+
emitProgress(
|
|
208
209
|
processed,
|
|
209
210
|
files.length,
|
|
210
|
-
|
|
211
|
+
'agent-grounding',
|
|
212
|
+
'analyzing files',
|
|
213
|
+
options.onProgress
|
|
211
214
|
);
|
|
212
215
|
|
|
213
216
|
const analysis = analyzeFile(f);
|