ultracode 5.3.0 → 5.5.0
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/chunks/analysis-tool-handlers-H2RXLDPX.js +817 -0
- package/dist/chunks/analysis-tool-handlers-RJZAR6VT.js +817 -0
- package/dist/chunks/analysis-tool-handlers-Z2RF24T7.js +13 -0
- package/dist/chunks/autodoc-tool-handlers-CV5JEQUA.js +1112 -0
- package/dist/chunks/autodoc-tool-handlers-EHTNCH6I.js +1112 -0
- package/dist/chunks/autodoc-tool-handlers-MECXQJ2K.js +138 -0
- package/dist/chunks/chaos-CO7TOBOJ.js +18 -0
- package/dist/chunks/chaos-VM2PXERO.js +1573 -0
- package/dist/chunks/chaos-W3XRVJ7K.js +1564 -0
- package/dist/chunks/chunk-6K37BWK5.js +439 -0
- package/dist/chunks/chunk-EALTCYHZ.js +10 -0
- package/dist/chunks/chunk-FTBE7VMY.js +316 -0
- package/dist/chunks/chunk-KBW6LRQP.js +322 -0
- package/dist/chunks/chunk-NKUHX4CU.js +5 -0
- package/dist/chunks/chunk-NZFF4DQ4.js +3179 -0
- package/dist/chunks/chunk-RGP5UVQ7.js +3179 -0
- package/dist/chunks/chunk-RMZXFGQZ.js +322 -0
- package/dist/chunks/chunk-UG44F23Y.js +316 -0
- package/dist/chunks/chunk-V2SCB5H5.js +4403 -0
- package/dist/chunks/chunk-V6JAQNM3.js +1 -0
- package/dist/chunks/chunk-XFGXM4CR.js +4403 -0
- package/dist/chunks/dev-agent-JVIGBMHQ.js +1 -0
- package/dist/chunks/dev-agent-TRVP5U6N.js +1624 -0
- package/dist/chunks/dev-agent-Y5G5WKQ4.js +1624 -0
- package/dist/chunks/graph-storage-factory-AYZ57YSL.js +13 -0
- package/dist/chunks/graph-storage-factory-GTAIJEI5.js +1 -0
- package/dist/chunks/graph-storage-factory-T2WO5QVG.js +13 -0
- package/dist/chunks/incremental-updater-KDIQGAUU.js +14 -0
- package/dist/chunks/incremental-updater-OJRSTO3Q.js +1 -0
- package/dist/chunks/incremental-updater-SBEBH7KF.js +14 -0
- package/dist/chunks/indexer-agent-H3QIEL3Z.js +21 -0
- package/dist/chunks/indexer-agent-KHF5JMV7.js +21 -0
- package/dist/chunks/indexer-agent-SHJD6Z77.js +1 -0
- package/dist/chunks/indexing-pipeline-J6Z4BHKF.js +1 -0
- package/dist/chunks/indexing-pipeline-OY3337QN.js +249 -0
- package/dist/chunks/indexing-pipeline-WCXIDMAP.js +249 -0
- package/dist/chunks/merge-agent-LSUBDJB2.js +2481 -0
- package/dist/chunks/merge-agent-MJEW3HWU.js +2481 -0
- package/dist/chunks/merge-agent-O45OXF33.js +11 -0
- package/dist/chunks/merge-tool-handlers-BDSVNQVZ.js +277 -0
- package/dist/chunks/merge-tool-handlers-HP7DRBXJ.js +1 -0
- package/dist/chunks/merge-tool-handlers-RUJAKE3D.js +277 -0
- package/dist/chunks/pattern-tool-handlers-L62W3CXR.js +1549 -0
- package/dist/chunks/pattern-tool-handlers-SAHX2CVW.js +13 -0
- package/dist/chunks/query-agent-3TWDFIMT.js +191 -0
- package/dist/chunks/query-agent-HXQ3BMMF.js +191 -0
- package/dist/chunks/query-agent-USMC2GNG.js +1 -0
- package/dist/chunks/semantic-agent-MQCAWIAB.js +6381 -0
- package/dist/chunks/semantic-agent-NDGR3NAK.js +6381 -0
- package/dist/chunks/semantic-agent-S4ZL6GZC.js +137 -0
- package/dist/index.js +17 -17
- package/dist/roslyn-addon/.build-hash +1 -1
- package/dist/roslyn-addon/ILGPU.Algorithms.dll +0 -0
- package/dist/roslyn-addon/ILGPU.dll +0 -0
- package/dist/roslyn-addon/UltraCode.CSharp.deps.json +35 -0
- package/dist/roslyn-addon/UltraCode.CSharp.dll +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
import { projectPathParam } from './chunk-NJUB245U.js';
|
|
2
|
+
import { SAFE_LIMITS, BaseToolHandler, MAX_PAGE_SIZE, paginate } from './chunk-WLKASYMP.js';
|
|
3
|
+
import './chunk-KMXE2SJJ.js';
|
|
4
|
+
import './chunk-HNDYLCWI.js';
|
|
5
|
+
import { TimeTravelManager } from './chunk-AIZUHUK6.js';
|
|
6
|
+
import './chunk-ZD54CMKT.js';
|
|
7
|
+
import './chunk-HEMJHRHZ.js';
|
|
8
|
+
import { toError } from './chunk-5WKPA33T.js';
|
|
9
|
+
import { init_logging, log } from './chunk-VCCBEJQ5.js';
|
|
10
|
+
import './chunk-NAQKA54E.js';
|
|
11
|
+
import { execSync } from 'child_process';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
|
|
14
|
+
// src/tools/handlers/analysis-tool-handlers.ts
|
|
15
|
+
init_logging();
|
|
16
|
+
var SuggestRefactoringSchema = z.object({
|
|
17
|
+
entityId: z.string().optional(),
|
|
18
|
+
filePath: z.string().optional(),
|
|
19
|
+
projectPath: projectPathParam,
|
|
20
|
+
type: z.enum(["extract_method", "rename", "move", "simplify", "all"]).optional().default("all"),
|
|
21
|
+
offset: z.number().optional().default(0),
|
|
22
|
+
limit: z.number().optional().default(SAFE_LIMITS.searchResults)
|
|
23
|
+
});
|
|
24
|
+
var SuggestRefactoringToolHandler = class extends BaseToolHandler {
|
|
25
|
+
parseArgs(args) {
|
|
26
|
+
return SuggestRefactoringSchema.parse(args);
|
|
27
|
+
}
|
|
28
|
+
async execute(args) {
|
|
29
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
30
|
+
const semanticAgent = await this.context.getSemanticAgent();
|
|
31
|
+
const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
|
|
32
|
+
let code;
|
|
33
|
+
const targetEntityId = args.entityId;
|
|
34
|
+
let targetFilePath = args.filePath ? this.context.normalizeInputPath(args.filePath) : void 0;
|
|
35
|
+
if (args.entityId) {
|
|
36
|
+
const entity = await storage.getEntity(args.entityId);
|
|
37
|
+
if (entity?.filePath) {
|
|
38
|
+
targetFilePath = entity.filePath;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!code && targetFilePath) {
|
|
42
|
+
try {
|
|
43
|
+
const { readFile } = await import('fs/promises');
|
|
44
|
+
code = await readFile(targetFilePath, "utf-8");
|
|
45
|
+
} catch {
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: JSON.stringify({ error: `Cannot read file: ${targetFilePath}` }) }]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!code) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: JSON.stringify({ error: "No code found. Provide entityId or filePath." }) }]
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const allSuggestions = await semanticAgent.suggestRefactoring(code);
|
|
57
|
+
const paginatedResult = paginate(allSuggestions, args.offset, safeLimit);
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: "text",
|
|
62
|
+
text: JSON.stringify(
|
|
63
|
+
{
|
|
64
|
+
entityId: targetEntityId,
|
|
65
|
+
filePath: targetFilePath,
|
|
66
|
+
suggestionsFound: paginatedResult.data.length,
|
|
67
|
+
pagination: paginatedResult.pagination,
|
|
68
|
+
suggestions: paginatedResult.data.map(
|
|
69
|
+
(s) => ({
|
|
70
|
+
type: s.type,
|
|
71
|
+
impact: s.impact,
|
|
72
|
+
confidence: s.confidence,
|
|
73
|
+
description: s.description,
|
|
74
|
+
entityId: targetEntityId,
|
|
75
|
+
filePath: targetFilePath,
|
|
76
|
+
suggestedCode: s.code
|
|
77
|
+
})
|
|
78
|
+
)
|
|
79
|
+
},
|
|
80
|
+
null,
|
|
81
|
+
2
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var AnalyzeHotspotsSchema = z.object({
|
|
89
|
+
projectPath: projectPathParam,
|
|
90
|
+
metric: z.enum(["complexity", "changes", "coupling", "all"]).optional().default("complexity"),
|
|
91
|
+
offset: z.number().optional().default(0),
|
|
92
|
+
limit: z.number().optional().default(SAFE_LIMITS.hotspots),
|
|
93
|
+
includeHistoricalMetrics: z.boolean().optional().default(true).describe("Use Prolly Tree history for changeFrequency calculation"),
|
|
94
|
+
lookbackDays: z.number().optional().default(30).describe("Number of days to look back for change frequency")
|
|
95
|
+
});
|
|
96
|
+
var AnalyzeHotspotsToolHandler = class extends BaseToolHandler {
|
|
97
|
+
// Cache for change frequency to avoid redundant calculations within same execution
|
|
98
|
+
changeFrequencyCache = /* @__PURE__ */ new Map();
|
|
99
|
+
parseArgs(args) {
|
|
100
|
+
return AnalyzeHotspotsSchema.parse(args);
|
|
101
|
+
}
|
|
102
|
+
async execute(args) {
|
|
103
|
+
this.changeFrequencyCache.clear();
|
|
104
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
105
|
+
const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
|
|
106
|
+
const entities = await storage.findEntities({ filters: {}, limit: 5e3 });
|
|
107
|
+
const needsHistory = args.includeHistoricalMetrics && (args.metric === "changes" || args.metric === "all");
|
|
108
|
+
if (needsHistory) {
|
|
109
|
+
await this.preloadChangeFrequencies(entities, storage, args.lookbackDays);
|
|
110
|
+
}
|
|
111
|
+
const hotspots = [];
|
|
112
|
+
for (const entity of entities) {
|
|
113
|
+
const { score, changeMetrics } = this.calculateHotspotScore(entity, args.metric, args.includeHistoricalMetrics);
|
|
114
|
+
if (score > 0) {
|
|
115
|
+
const storedMetrics = entity.metadata?.["metrics"] ?? {};
|
|
116
|
+
const storedLinesOfCode = storedMetrics.linesOfCode;
|
|
117
|
+
const linesOfCode = storedLinesOfCode ?? (entity.location?.end?.line && entity.location?.start?.line ? entity.location.end.line - entity.location.start.line + 1 : void 0);
|
|
118
|
+
hotspots.push({
|
|
119
|
+
id: entity.id,
|
|
120
|
+
name: entity.name,
|
|
121
|
+
type: entity.type,
|
|
122
|
+
filePath: entity.filePath,
|
|
123
|
+
score: Math.round(score * 100) / 100,
|
|
124
|
+
metrics: {
|
|
125
|
+
...storedMetrics,
|
|
126
|
+
...linesOfCode !== void 0 && storedLinesOfCode === void 0 ? { linesOfCode } : {},
|
|
127
|
+
...changeMetrics
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
hotspots.sort((a, b) => b.score - a.score);
|
|
133
|
+
const paginatedResult = paginate(hotspots, args.offset, safeLimit);
|
|
134
|
+
return {
|
|
135
|
+
content: [
|
|
136
|
+
{
|
|
137
|
+
type: "text",
|
|
138
|
+
text: JSON.stringify(
|
|
139
|
+
{
|
|
140
|
+
metric: args.metric,
|
|
141
|
+
includeHistoricalMetrics: args.includeHistoricalMetrics,
|
|
142
|
+
lookbackDays: args.lookbackDays,
|
|
143
|
+
hotspotsFound: paginatedResult.data.length,
|
|
144
|
+
pagination: paginatedResult.pagination,
|
|
145
|
+
hotspots: paginatedResult.data,
|
|
146
|
+
nextSteps: [
|
|
147
|
+
"graph_metrics({metric:'pagerank'}) \u2014 rank hotspots by architectural importance",
|
|
148
|
+
"taint_analysis() \u2014 check if hotspots contain security vulnerabilities"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
null,
|
|
152
|
+
2
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Pre-load change frequencies for all entities in a batch to minimize diff operations.
|
|
160
|
+
* Uses Prolly Tree history first, falls back to Git for entities without Prolly data.
|
|
161
|
+
*/
|
|
162
|
+
async preloadChangeFrequencies(entities, storage, lookbackDays) {
|
|
163
|
+
const adapter = storage.getLibSQLAdapter?.();
|
|
164
|
+
const commitManager = adapter?.getCommitManager?.();
|
|
165
|
+
const nodeStore = adapter?.getProllyNodeStore?.();
|
|
166
|
+
const entityChangeCount = /* @__PURE__ */ new Map();
|
|
167
|
+
let prollyDataAvailable = false;
|
|
168
|
+
for (const entity of entities) {
|
|
169
|
+
entityChangeCount.set(entity.id, { count: 0, source: "none" });
|
|
170
|
+
}
|
|
171
|
+
if (commitManager && nodeStore) {
|
|
172
|
+
const sinceTimestamp = Date.now() - lookbackDays * 24 * 60 * 60 * 1e3;
|
|
173
|
+
const recentCommits = await commitManager.getCommitsSince(sinceTimestamp);
|
|
174
|
+
if (recentCommits.length >= 2) {
|
|
175
|
+
prollyDataAvailable = true;
|
|
176
|
+
const timeTravel = new TimeTravelManager(nodeStore, commitManager);
|
|
177
|
+
for (let i = 0; i < recentCommits.length - 1; i++) {
|
|
178
|
+
const current = recentCommits[i];
|
|
179
|
+
const parent = recentCommits[i + 1];
|
|
180
|
+
if (!current || !parent) continue;
|
|
181
|
+
try {
|
|
182
|
+
const diff = await timeTravel.diffCommits(parent.commitHash, current.commitHash);
|
|
183
|
+
if (!diff) continue;
|
|
184
|
+
for (const entry of [...diff.treeDiff.added, ...diff.treeDiff.modified, ...diff.treeDiff.deleted]) {
|
|
185
|
+
const existing = entityChangeCount.get(entry.key);
|
|
186
|
+
if (existing) {
|
|
187
|
+
entityChangeCount.set(entry.key, { count: existing.count + 1, source: "prolly" });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
log.w("HOTSPOTS", "diff_failed", { error: error.message });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
log.d("HOTSPOTS", "prolly_preload_complete", {
|
|
195
|
+
commits: recentCommits.length,
|
|
196
|
+
withChanges: [...entityChangeCount.values()].filter((v) => v.count > 0).length
|
|
197
|
+
});
|
|
198
|
+
} else {
|
|
199
|
+
log.d("HOTSPOTS", "insufficient_commits", { count: recentCommits.length });
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
log.d("HOTSPOTS", "prolly_not_available", { reason: "missing components" });
|
|
203
|
+
}
|
|
204
|
+
const gitChangeCache = /* @__PURE__ */ new Map();
|
|
205
|
+
let gitFallbackCount = 0;
|
|
206
|
+
for (const entity of entities) {
|
|
207
|
+
const current = entityChangeCount.get(entity.id);
|
|
208
|
+
if (!current || current.count > 0 || !entity.filePath) continue;
|
|
209
|
+
let gitCount = gitChangeCache.get(entity.filePath);
|
|
210
|
+
if (gitCount === void 0) {
|
|
211
|
+
gitCount = this.getChangeFrequencyFromGit(entity.filePath, lookbackDays);
|
|
212
|
+
gitChangeCache.set(entity.filePath, gitCount);
|
|
213
|
+
}
|
|
214
|
+
if (gitCount > 0) {
|
|
215
|
+
entityChangeCount.set(entity.id, { count: gitCount, source: "git" });
|
|
216
|
+
gitFallbackCount++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (gitFallbackCount > 0) {
|
|
220
|
+
log.d("HOTSPOTS", "git_fallback_complete", {
|
|
221
|
+
filesChecked: gitChangeCache.size,
|
|
222
|
+
entitiesUpdated: gitFallbackCount
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
for (const [entityId, data] of entityChangeCount) {
|
|
226
|
+
this.changeFrequencyCache.set(entityId, { changeCount: data.count, source: data.source });
|
|
227
|
+
}
|
|
228
|
+
log.d("HOTSPOTS", "preloaded_change_frequencies", {
|
|
229
|
+
entities: entities.length,
|
|
230
|
+
prollyAvailable: prollyDataAvailable,
|
|
231
|
+
withChanges: [...entityChangeCount.values()].filter((v) => v.count > 0).length
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get change frequency from Git log (fallback when Prolly data unavailable).
|
|
236
|
+
*/
|
|
237
|
+
getChangeFrequencyFromGit(filePath, lookbackDays) {
|
|
238
|
+
try {
|
|
239
|
+
const since = new Date(Date.now() - lookbackDays * 24 * 60 * 60 * 1e3).toISOString().split("T")[0];
|
|
240
|
+
const output = execSync(`git log --oneline --since="${since}" -- "${filePath}"`, {
|
|
241
|
+
encoding: "utf-8",
|
|
242
|
+
timeout: 5e3,
|
|
243
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
244
|
+
});
|
|
245
|
+
const lines = output.trim().split("\n").filter(Boolean);
|
|
246
|
+
return lines.length;
|
|
247
|
+
} catch {
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
calculateHotspotScore(entity, metric, includeHistoricalMetrics) {
|
|
252
|
+
const metrics = entity.metadata?.["metrics"] || {};
|
|
253
|
+
let score = 0;
|
|
254
|
+
let changeMetrics;
|
|
255
|
+
const linesOfCode = metrics.linesOfCode || (entity.location?.end?.line && entity.location?.start?.line ? entity.location.end.line - entity.location.start.line + 1 : 0);
|
|
256
|
+
if (metric === "complexity" || metric === "all") {
|
|
257
|
+
score += (metrics.cyclomaticComplexity || 0) * 2;
|
|
258
|
+
score += (metrics.cognitiveComplexity || 0) * 1.5;
|
|
259
|
+
score += (metrics.nestingDepth || 0) * 3;
|
|
260
|
+
score += linesOfCode / 50;
|
|
261
|
+
const paramCount = metrics.parameterCount || 0;
|
|
262
|
+
score += paramCount > 4 ? (paramCount - 4) * 2 : 0;
|
|
263
|
+
}
|
|
264
|
+
if (metric === "changes" || metric === "all") {
|
|
265
|
+
if (includeHistoricalMetrics) {
|
|
266
|
+
const cached = this.changeFrequencyCache.get(entity.id);
|
|
267
|
+
if (cached && cached.changeCount > 0) {
|
|
268
|
+
const changeScore = Math.log(cached.changeCount + 1) * 10;
|
|
269
|
+
score += changeScore;
|
|
270
|
+
changeMetrics = {
|
|
271
|
+
changeFrequency: cached.changeCount,
|
|
272
|
+
changeFrequencyScore: Math.round(changeScore * 100) / 100,
|
|
273
|
+
changeSource: cached.source
|
|
274
|
+
};
|
|
275
|
+
} else {
|
|
276
|
+
changeMetrics = {
|
|
277
|
+
changeFrequency: 0,
|
|
278
|
+
changeFrequencyScore: 0,
|
|
279
|
+
changeSource: "none"
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
score += (metrics.changeFrequency || 0) * 10;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (metric === "coupling" || metric === "all") {
|
|
287
|
+
score += metrics.couplingScore || 0;
|
|
288
|
+
score += (metrics.dependencyCount || 0) / 5;
|
|
289
|
+
}
|
|
290
|
+
return { score, changeMetrics };
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
var FindRelatedConceptsSchema = z.object({
|
|
294
|
+
entityId: z.string().describe("Entity ID to find related concepts for"),
|
|
295
|
+
projectPath: projectPathParam,
|
|
296
|
+
offset: z.number().optional().default(0),
|
|
297
|
+
limit: z.number().optional().default(SAFE_LIMITS.searchResults)
|
|
298
|
+
});
|
|
299
|
+
var FindRelatedConceptsToolHandler = class extends BaseToolHandler {
|
|
300
|
+
parseArgs(args) {
|
|
301
|
+
return FindRelatedConceptsSchema.parse(args);
|
|
302
|
+
}
|
|
303
|
+
async execute(args) {
|
|
304
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
305
|
+
const semanticAgent = await this.context.getSemanticAgent();
|
|
306
|
+
const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
|
|
307
|
+
const entity = await storage.getEntity(args.entityId);
|
|
308
|
+
if (!entity) {
|
|
309
|
+
return {
|
|
310
|
+
content: [{ type: "text", text: JSON.stringify({ error: `Entity not found: ${args.entityId}` }) }]
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const concept = entity.name;
|
|
314
|
+
const searchResult = await semanticAgent.semanticSearch(concept, 500);
|
|
315
|
+
const allRelated = searchResult.results || [];
|
|
316
|
+
const paginatedResult = paginate(allRelated, args.offset, safeLimit);
|
|
317
|
+
const enrichedRelated = await Promise.all(
|
|
318
|
+
paginatedResult.data.map(async (r) => {
|
|
319
|
+
try {
|
|
320
|
+
let ent = null;
|
|
321
|
+
const meta = r.metadata;
|
|
322
|
+
const metaEntityId = meta?.["entityId"];
|
|
323
|
+
if (metaEntityId && /^[0-9a-f]{12}$/.test(metaEntityId)) {
|
|
324
|
+
ent = await storage.getEntity(metaEntityId);
|
|
325
|
+
}
|
|
326
|
+
if (!ent && typeof r.id === "string" && r.id.startsWith("ent:")) {
|
|
327
|
+
const idPart = r.id.slice(4);
|
|
328
|
+
if (/^[0-9a-f]{12}$/.test(idPart)) {
|
|
329
|
+
ent = await storage.getEntity(idPart);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!ent) {
|
|
333
|
+
const compositeId = metaEntityId ?? (typeof r.id === "string" && r.id.startsWith("ent:") ? r.id.slice(4) : void 0);
|
|
334
|
+
if (compositeId && compositeId.includes(":")) {
|
|
335
|
+
const lastColon = compositeId.lastIndexOf(":");
|
|
336
|
+
const entityName = compositeId.slice(lastColon + 1);
|
|
337
|
+
if (entityName) {
|
|
338
|
+
const found = await storage.searchEntities({ namePattern: entityName });
|
|
339
|
+
ent = found.find((e) => e.metadata?.["communityId"] != null || e.metadata?.["pageRank"] != null) ?? found[0] ?? null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (!ent) return r;
|
|
344
|
+
const entMeta = ent.metadata ?? {};
|
|
345
|
+
const communityId = entMeta["communityId"];
|
|
346
|
+
const pageRank = entMeta["pageRank"];
|
|
347
|
+
if (communityId != null || pageRank != null) {
|
|
348
|
+
return {
|
|
349
|
+
...r,
|
|
350
|
+
...communityId != null ? { communityId } : {},
|
|
351
|
+
...typeof pageRank === "number" ? { pageRank: Math.round(pageRank * 1e4) / 1e4 } : {}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
} catch {
|
|
355
|
+
}
|
|
356
|
+
return r;
|
|
357
|
+
})
|
|
358
|
+
);
|
|
359
|
+
return {
|
|
360
|
+
content: [
|
|
361
|
+
{
|
|
362
|
+
type: "text",
|
|
363
|
+
text: JSON.stringify(
|
|
364
|
+
{
|
|
365
|
+
entityId: args.entityId,
|
|
366
|
+
concept,
|
|
367
|
+
relatedCount: enrichedRelated.length,
|
|
368
|
+
pagination: paginatedResult.pagination,
|
|
369
|
+
related: enrichedRelated
|
|
370
|
+
},
|
|
371
|
+
null,
|
|
372
|
+
2
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
]
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
var AnalyzeStateChaosSchema = z.object({
|
|
380
|
+
projectPath: projectPathParam,
|
|
381
|
+
scope: z.enum(["file", "module", "project"]).optional().default("project"),
|
|
382
|
+
stateIdentifiers: z.array(z.string()).optional(),
|
|
383
|
+
autoDetect: z.boolean().optional().default(true),
|
|
384
|
+
maxDepth: z.number().optional(),
|
|
385
|
+
excludePatterns: z.array(z.string()).optional(),
|
|
386
|
+
format: z.enum(["summary", "detailed", "json"]).optional().default("summary")
|
|
387
|
+
});
|
|
388
|
+
var AnalyzeStateChaosToolHandler = class extends BaseToolHandler {
|
|
389
|
+
parseArgs(args) {
|
|
390
|
+
return AnalyzeStateChaosSchema.parse(args);
|
|
391
|
+
}
|
|
392
|
+
async execute(args) {
|
|
393
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
394
|
+
const { ChaosAnalyzer } = await import('./chaos-VM2PXERO.js');
|
|
395
|
+
const analyzer = new ChaosAnalyzer(storage);
|
|
396
|
+
const results = await analyzer.analyze({
|
|
397
|
+
scope: args.scope || "project",
|
|
398
|
+
stateIdentifiers: args.stateIdentifiers,
|
|
399
|
+
autoDetect: args.autoDetect ?? true,
|
|
400
|
+
maxDepth: args.maxDepth,
|
|
401
|
+
excludePatterns: args.excludePatterns
|
|
402
|
+
});
|
|
403
|
+
const graphContext = [];
|
|
404
|
+
for (const r of results) {
|
|
405
|
+
const identifier = r.statePattern.identifier;
|
|
406
|
+
if (!identifier) continue;
|
|
407
|
+
try {
|
|
408
|
+
const entities = await storage.searchEntities({ namePattern: identifier });
|
|
409
|
+
let pr = null;
|
|
410
|
+
let cid = null;
|
|
411
|
+
for (const ent of entities) {
|
|
412
|
+
const meta = ent.metadata ?? {};
|
|
413
|
+
if (meta["communityId"] != null || meta["pageRank"] != null) {
|
|
414
|
+
pr = meta["pageRank"];
|
|
415
|
+
cid = meta["communityId"];
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (entities.length > 0) {
|
|
420
|
+
graphContext.push({
|
|
421
|
+
stateIdentifier: identifier,
|
|
422
|
+
pageRank: typeof pr === "number" ? pr : null,
|
|
423
|
+
communityId: typeof cid === "number" ? cid : null,
|
|
424
|
+
communityRisk: typeof pr === "number" && pr > 0.7 ? "high" : typeof pr === "number" && pr > 0.4 ? "medium" : "low"
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
} catch {
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const chaosNextSteps = [
|
|
431
|
+
"graph_metrics({metric:'louvain'}) \u2014 cluster chaotic modules by community",
|
|
432
|
+
"graph_metrics({metric:'pagerank'}) \u2014 assess architectural importance of chaotic entities"
|
|
433
|
+
];
|
|
434
|
+
if (args.format === "json") {
|
|
435
|
+
return {
|
|
436
|
+
content: [
|
|
437
|
+
{
|
|
438
|
+
type: "text",
|
|
439
|
+
text: JSON.stringify(
|
|
440
|
+
{
|
|
441
|
+
statePatterns: results,
|
|
442
|
+
csharpPatterns: analyzer.csharpPatterns,
|
|
443
|
+
graphContext,
|
|
444
|
+
nextSteps: chaosNextSteps
|
|
445
|
+
},
|
|
446
|
+
null,
|
|
447
|
+
2
|
|
448
|
+
)
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
if (args.format === "detailed" && (results.length > 0 || analyzer.csharpPatterns.length > 0)) {
|
|
454
|
+
const parts = [];
|
|
455
|
+
if (results.length > 0) {
|
|
456
|
+
parts.push(results.map((r) => analyzer.formatDetailed(r)).join("\n\n---\n\n"));
|
|
457
|
+
}
|
|
458
|
+
if (analyzer.csharpPatterns.length > 0 && results.length === 0) {
|
|
459
|
+
parts.push(analyzer.formatForAI(results));
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
content: [{ type: "text", text: parts.join("\n\n") }]
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
const text = analyzer.formatForAI(results);
|
|
466
|
+
const nextStepsText = `
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
Next steps:
|
|
470
|
+
${chaosNextSteps.map((s) => `- ${s}`).join("\n")}`;
|
|
471
|
+
return {
|
|
472
|
+
content: [{ type: "text", text: text + nextStepsText }]
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
var AnalyzeCodeImpactSchema = z.object({
|
|
477
|
+
entityId: z.string().optional(),
|
|
478
|
+
filePath: z.string().optional(),
|
|
479
|
+
projectPath: projectPathParam,
|
|
480
|
+
depth: z.number().optional().default(3),
|
|
481
|
+
highlightRecentChanges: z.boolean().optional().default(false).describe("Annotate impacted entities with recently-changed status (Prolly Tree)"),
|
|
482
|
+
recentCommitsCount: z.number().optional().default(10).describe("Number of recent commits to consider for highlighting")
|
|
483
|
+
});
|
|
484
|
+
var AnalyzeCodeImpactToolHandler = class extends BaseToolHandler {
|
|
485
|
+
parseArgs(args) {
|
|
486
|
+
return AnalyzeCodeImpactSchema.parse(args);
|
|
487
|
+
}
|
|
488
|
+
async execute(args) {
|
|
489
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
490
|
+
let entityId = args.entityId;
|
|
491
|
+
if (entityId) {
|
|
492
|
+
const directEntity = await storage.getEntity(entityId);
|
|
493
|
+
if (!directEntity) {
|
|
494
|
+
const byName = await storage.searchEntities({ namePattern: entityId });
|
|
495
|
+
if (byName.length > 0) {
|
|
496
|
+
if (args.filePath) {
|
|
497
|
+
const normalizedPath = this.context.normalizeInputPath(args.filePath);
|
|
498
|
+
const normalizedFilter = (normalizedPath || "").replace(/\\/g, "/").toLowerCase();
|
|
499
|
+
const inFile = byName.find((e) => {
|
|
500
|
+
const ep = (e.filePath || "").replace(/\\/g, "/").toLowerCase();
|
|
501
|
+
return ep.includes(normalizedFilter) || ep.endsWith(normalizedFilter);
|
|
502
|
+
});
|
|
503
|
+
if (inFile) entityId = inFile.id;
|
|
504
|
+
else entityId = byName[0].id;
|
|
505
|
+
} else {
|
|
506
|
+
entityId = byName[0].id;
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
entityId = void 0;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (!entityId && args.filePath) {
|
|
514
|
+
const normalizedPath = this.context.normalizeInputPath(args.filePath);
|
|
515
|
+
const entities = await storage.findEntities({
|
|
516
|
+
filters: { filePath: normalizedPath },
|
|
517
|
+
limit: 1
|
|
518
|
+
});
|
|
519
|
+
if (entities.length > 0 && entities[0]) {
|
|
520
|
+
entityId = entities[0].id;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (!entityId) {
|
|
524
|
+
return {
|
|
525
|
+
content: [{ type: "text", text: JSON.stringify({ error: "Entity not found" }) }]
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
const entity = await storage.getEntity(entityId);
|
|
529
|
+
const relationships = await storage.getRelationshipsForEntity(entityId);
|
|
530
|
+
const impactedEntities = /* @__PURE__ */ new Set();
|
|
531
|
+
let frontier = [entityId];
|
|
532
|
+
let currentDepth = 0;
|
|
533
|
+
while (frontier.length > 0 && currentDepth < args.depth) {
|
|
534
|
+
const nextFrontier = [];
|
|
535
|
+
for (const current of frontier) {
|
|
536
|
+
const rels = await storage.getRelationshipsForEntity(current);
|
|
537
|
+
for (const rel of rels) {
|
|
538
|
+
const targetId = rel.fromId === current ? rel.toId : rel.fromId;
|
|
539
|
+
if (!impactedEntities.has(targetId) && targetId !== entityId) {
|
|
540
|
+
impactedEntities.add(targetId);
|
|
541
|
+
nextFrontier.push(targetId);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
frontier = nextFrontier;
|
|
546
|
+
currentDepth++;
|
|
547
|
+
}
|
|
548
|
+
let contractImpact;
|
|
549
|
+
{
|
|
550
|
+
const impactedIds = Array.from(impactedEntities);
|
|
551
|
+
const impactedBatch = await storage.getEntitiesBatch(impactedIds);
|
|
552
|
+
const affectedEndpoints = [];
|
|
553
|
+
const affectedSchemas = [];
|
|
554
|
+
const consumers = [];
|
|
555
|
+
for (const [, impEntity] of impactedBatch) {
|
|
556
|
+
if (impEntity.metadata?.["isApiContract"]) {
|
|
557
|
+
const swaggerType = impEntity.metadata["swaggerType"];
|
|
558
|
+
if (swaggerType === "endpoint") {
|
|
559
|
+
const sig = `${impEntity.metadata["httpMethod"] || ""} ${impEntity.metadata["path"] || ""}`.trim();
|
|
560
|
+
affectedEndpoints.push(sig || impEntity.name);
|
|
561
|
+
} else if (swaggerType === "schema") {
|
|
562
|
+
affectedSchemas.push(impEntity.name);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (entity?.metadata?.["isApiContract"]) {
|
|
567
|
+
const swaggerType = entity.metadata["swaggerType"];
|
|
568
|
+
if (swaggerType === "endpoint") {
|
|
569
|
+
const sig = `${entity.metadata["httpMethod"] || ""} ${entity.metadata["path"] || ""}`.trim();
|
|
570
|
+
affectedEndpoints.push(sig || entity.name);
|
|
571
|
+
} else if (swaggerType === "schema") {
|
|
572
|
+
affectedSchemas.push(entity.name);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
for (const rel of relationships) {
|
|
576
|
+
if (rel.type === "consumes_api" || rel.metadata?.context?.includes("consumes")) {
|
|
577
|
+
const consumerId = rel.fromId === entityId ? rel.toId : rel.fromId;
|
|
578
|
+
const consumer = impactedBatch.get(consumerId);
|
|
579
|
+
if (consumer) {
|
|
580
|
+
consumers.push(consumer.name);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (affectedEndpoints.length > 0 || affectedSchemas.length > 0) {
|
|
585
|
+
const risk = affectedEndpoints.length > 3 || affectedSchemas.length > 5 ? "high" : affectedEndpoints.length > 0 ? "medium" : "low";
|
|
586
|
+
contractImpact = {
|
|
587
|
+
affectsApiContract: true,
|
|
588
|
+
affectedEndpoints: [...new Set(affectedEndpoints)],
|
|
589
|
+
affectedSchemas: [...new Set(affectedSchemas)],
|
|
590
|
+
breakingChangeRisk: risk,
|
|
591
|
+
consumers: [...new Set(consumers)],
|
|
592
|
+
warning: "Changes affect external API contract \u2014 consumers may break"
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
let recentlyChangedImpact;
|
|
597
|
+
if (args.highlightRecentChanges) {
|
|
598
|
+
const { getRecentlyChangedEntities } = await import('./recently-changed-FX5QR4Z2.js');
|
|
599
|
+
const adapter = storage.getLibSQLAdapter?.();
|
|
600
|
+
if (adapter) {
|
|
601
|
+
const recentlyChanged = await getRecentlyChangedEntities(adapter, {
|
|
602
|
+
lastCommits: args.recentCommitsCount
|
|
603
|
+
});
|
|
604
|
+
if (recentlyChanged) {
|
|
605
|
+
let recentlyAddedCount = 0;
|
|
606
|
+
let recentlyModifiedCount = 0;
|
|
607
|
+
for (const id of impactedEntities) {
|
|
608
|
+
if (recentlyChanged.addedIds.has(id)) recentlyAddedCount++;
|
|
609
|
+
else if (recentlyChanged.modifiedIds.has(id)) recentlyModifiedCount++;
|
|
610
|
+
}
|
|
611
|
+
const totalRecent = recentlyAddedCount + recentlyModifiedCount;
|
|
612
|
+
recentlyChangedImpact = {
|
|
613
|
+
recentlyAddedCount,
|
|
614
|
+
recentlyModifiedCount,
|
|
615
|
+
volatileRatio: impactedEntities.size > 0 ? Math.round(totalRecent / impactedEntities.size * 100) / 100 : 0,
|
|
616
|
+
commitsAnalyzed: recentlyChanged.commitsAnalyzed
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return {
|
|
622
|
+
content: [
|
|
623
|
+
{
|
|
624
|
+
type: "text",
|
|
625
|
+
text: JSON.stringify(
|
|
626
|
+
{
|
|
627
|
+
entity: entity ? { id: entity.id, name: entity.name, type: entity.type } : null,
|
|
628
|
+
directRelationships: relationships.length,
|
|
629
|
+
totalImpactedEntities: impactedEntities.size,
|
|
630
|
+
impactDepth: args.depth,
|
|
631
|
+
riskLevel: impactedEntities.size > 50 ? "high" : impactedEntities.size > 20 ? "medium" : "low",
|
|
632
|
+
...contractImpact ? { contractImpact } : {},
|
|
633
|
+
...recentlyChangedImpact ? { recentlyChangedImpact } : {},
|
|
634
|
+
nextSteps: [
|
|
635
|
+
"graph_metrics({metric:'pagerank'}) \u2014 assess importance of impacted entities",
|
|
636
|
+
"taint_analysis() \u2014 check if impacted code has security vulnerabilities"
|
|
637
|
+
]
|
|
638
|
+
},
|
|
639
|
+
null,
|
|
640
|
+
2
|
|
641
|
+
)
|
|
642
|
+
}
|
|
643
|
+
]
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
var AnalyzeSwaggerImpactSchema = z.object({
|
|
648
|
+
projectPath: projectPathParam,
|
|
649
|
+
swaggerFile: z.string().optional().describe("Path to swagger file (auto-detected if omitted)"),
|
|
650
|
+
schemaName: z.string().optional().describe("Specific schema name to analyze"),
|
|
651
|
+
endpointPath: z.string().optional().describe("Specific endpoint like 'GET /api/users'")
|
|
652
|
+
});
|
|
653
|
+
var AnalyzeSwaggerImpactToolHandler = class extends BaseToolHandler {
|
|
654
|
+
parseArgs(args) {
|
|
655
|
+
return AnalyzeSwaggerImpactSchema.parse(args);
|
|
656
|
+
}
|
|
657
|
+
async execute(args) {
|
|
658
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
659
|
+
const allEntities = await storage.getAllEntities();
|
|
660
|
+
const allRelationships = await storage.getAllRelationships();
|
|
661
|
+
let swaggerEntities = allEntities.filter((e) => e.metadata?.["isApiContract"]);
|
|
662
|
+
if (swaggerEntities.length === 0) {
|
|
663
|
+
return {
|
|
664
|
+
content: [
|
|
665
|
+
{
|
|
666
|
+
type: "text",
|
|
667
|
+
text: JSON.stringify({
|
|
668
|
+
error: "No swagger/OpenAPI specifications found in the project graph. Index a project with swagger files first."
|
|
669
|
+
})
|
|
670
|
+
}
|
|
671
|
+
]
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
if (args.swaggerFile) {
|
|
675
|
+
const normalizedPath = this.context.normalizeInputPath(args.swaggerFile);
|
|
676
|
+
swaggerEntities = swaggerEntities.filter(
|
|
677
|
+
(e) => e.filePath.replace(/\\/g, "/").toLowerCase().includes((normalizedPath || "").replace(/\\/g, "/").toLowerCase())
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
if (args.schemaName) {
|
|
681
|
+
swaggerEntities = swaggerEntities.filter(
|
|
682
|
+
(e) => e.metadata?.["swaggerType"] === "schema" && e.name === args.schemaName
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
if (args.endpointPath) {
|
|
686
|
+
const [method, ...pathParts] = args.endpointPath.split(" ");
|
|
687
|
+
const path = pathParts.join(" ");
|
|
688
|
+
swaggerEntities = swaggerEntities.filter((e) => {
|
|
689
|
+
if (e.metadata?.["swaggerType"] !== "endpoint") return false;
|
|
690
|
+
const entityMethod = (e.metadata["httpMethod"] || "").toUpperCase();
|
|
691
|
+
const entityPath = e.metadata["path"] || "";
|
|
692
|
+
return (!method || entityMethod === method.toUpperCase()) && (!path || entityPath === path);
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
const producers = [];
|
|
696
|
+
const consumers = [];
|
|
697
|
+
const generatedTypes = [];
|
|
698
|
+
const swaggerEntityIds = new Set(swaggerEntities.map((e) => e.id));
|
|
699
|
+
const entityMap = new Map(allEntities.map((e) => [e.id, e]));
|
|
700
|
+
for (const rel of allRelationships) {
|
|
701
|
+
if (rel.type === "produces_api") {
|
|
702
|
+
const from = entityMap.get(rel.fromId);
|
|
703
|
+
const to = entityMap.get(rel.toId);
|
|
704
|
+
if (from && to && (swaggerEntityIds.has(rel.toId) || swaggerEntityIds.has(rel.fromId))) {
|
|
705
|
+
producers.push({ name: from.name, file: from.filePath, type: from.type });
|
|
706
|
+
}
|
|
707
|
+
} else if (rel.type === "consumes_api") {
|
|
708
|
+
const from = entityMap.get(rel.fromId);
|
|
709
|
+
const to = entityMap.get(rel.toId);
|
|
710
|
+
if (from && to && (swaggerEntityIds.has(rel.toId) || swaggerEntityIds.has(rel.fromId))) {
|
|
711
|
+
consumers.push({ name: from.name, file: from.filePath, type: from.type });
|
|
712
|
+
}
|
|
713
|
+
} else if (rel.type === "generated_from") {
|
|
714
|
+
const from = entityMap.get(rel.fromId);
|
|
715
|
+
const to = entityMap.get(rel.toId);
|
|
716
|
+
if (from && to && (swaggerEntityIds.has(rel.toId) || swaggerEntityIds.has(rel.fromId))) {
|
|
717
|
+
generatedTypes.push({
|
|
718
|
+
name: from.name,
|
|
719
|
+
file: from.filePath,
|
|
720
|
+
schemaName: to.name
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
const totalAffected = producers.length + consumers.length + generatedTypes.length;
|
|
726
|
+
const breakingChangeRisk = totalAffected > 10 ? "high" : totalAffected > 3 ? "medium" : "low";
|
|
727
|
+
const recommendations = [];
|
|
728
|
+
if (consumers.length > 0) {
|
|
729
|
+
recommendations.push(`${consumers.length} generated client(s) may need regeneration after swagger changes`);
|
|
730
|
+
}
|
|
731
|
+
if (generatedTypes.length > 0) {
|
|
732
|
+
recommendations.push(
|
|
733
|
+
`${generatedTypes.length} generated type(s) are linked to swagger schemas \u2014 regenerate after schema changes`
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
if (producers.length > 0) {
|
|
737
|
+
recommendations.push(
|
|
738
|
+
`${producers.length} controller(s) produce this API \u2014 update swagger spec after changing these`
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
const endpoints = swaggerEntities.filter((e) => e.metadata?.["swaggerType"] === "endpoint").map((e) => ({
|
|
742
|
+
name: e.name,
|
|
743
|
+
method: e.metadata?.["httpMethod"],
|
|
744
|
+
path: e.metadata?.["path"]
|
|
745
|
+
}));
|
|
746
|
+
const schemas = swaggerEntities.filter((e) => e.metadata?.["swaggerType"] === "schema").map((e) => e.name);
|
|
747
|
+
return {
|
|
748
|
+
content: [
|
|
749
|
+
{
|
|
750
|
+
type: "text",
|
|
751
|
+
text: JSON.stringify(
|
|
752
|
+
{
|
|
753
|
+
swaggerFiles: [...new Set(swaggerEntities.map((e) => e.filePath))],
|
|
754
|
+
endpoints,
|
|
755
|
+
schemas,
|
|
756
|
+
producers,
|
|
757
|
+
consumers,
|
|
758
|
+
generatedTypes,
|
|
759
|
+
breakingChangeRisk,
|
|
760
|
+
totalAffectedEntities: totalAffected,
|
|
761
|
+
recommendations
|
|
762
|
+
},
|
|
763
|
+
null,
|
|
764
|
+
2
|
|
765
|
+
)
|
|
766
|
+
}
|
|
767
|
+
]
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
var DetectTechnologyStackSchema = z.object({
|
|
772
|
+
directory: z.string().optional(),
|
|
773
|
+
projectPath: projectPathParam
|
|
774
|
+
});
|
|
775
|
+
var DetectTechnologyStackToolHandler = class extends BaseToolHandler {
|
|
776
|
+
parseArgs(args) {
|
|
777
|
+
return DetectTechnologyStackSchema.parse(args);
|
|
778
|
+
}
|
|
779
|
+
async execute(args) {
|
|
780
|
+
const targetDir = args.directory ? this.context.normalizeInputPath(args.directory) ?? this.resolveProjectPath({}) : this.resolveProjectPath({ projectPath: args.projectPath });
|
|
781
|
+
try {
|
|
782
|
+
const { TechnologyDetector } = await import('./technology-detector-ACNN7RLQ.js');
|
|
783
|
+
const graphStorage = await this.context.getGraphStorage();
|
|
784
|
+
graphStorage.setProject(targetDir);
|
|
785
|
+
const detector = new TechnologyDetector(graphStorage, targetDir);
|
|
786
|
+
const stack = await detector.detectStack();
|
|
787
|
+
return {
|
|
788
|
+
content: [
|
|
789
|
+
{
|
|
790
|
+
type: "text",
|
|
791
|
+
text: JSON.stringify(
|
|
792
|
+
{
|
|
793
|
+
directory: targetDir,
|
|
794
|
+
languages: stack.languages,
|
|
795
|
+
frameworks: stack.frameworks,
|
|
796
|
+
buildTools: stack.buildTools,
|
|
797
|
+
dependencies: stack.dependencies,
|
|
798
|
+
confidence: stack.confidence
|
|
799
|
+
},
|
|
800
|
+
null,
|
|
801
|
+
2
|
|
802
|
+
)
|
|
803
|
+
}
|
|
804
|
+
]
|
|
805
|
+
};
|
|
806
|
+
} catch (error) {
|
|
807
|
+
const err = toError(error);
|
|
808
|
+
return {
|
|
809
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
export { AnalyzeCodeImpactToolHandler, AnalyzeHotspotsToolHandler, AnalyzeStateChaosToolHandler, AnalyzeSwaggerImpactToolHandler, DetectTechnologyStackToolHandler, FindRelatedConceptsToolHandler, SuggestRefactoringToolHandler };
|
|
816
|
+
//# sourceMappingURL=analysis-tool-handlers-H2RXLDPX.js.map
|
|
817
|
+
//# sourceMappingURL=analysis-tool-handlers-H2RXLDPX.js.map
|