ultracode 5.4.0 → 5.6.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-GH5FDEWW.js +817 -0
- package/dist/chunks/analysis-tool-handlers-IXP4MWZX.js +817 -0
- package/dist/chunks/analysis-tool-handlers-LC2BTQYK.js +13 -0
- package/dist/chunks/analysis-tool-handlers-QYFKQPFL.js +817 -0
- package/dist/chunks/autodoc-tool-handlers-2HF6ERYN.js +1112 -0
- package/dist/chunks/autodoc-tool-handlers-4OGQJ7C3.js +1112 -0
- package/dist/chunks/autodoc-tool-handlers-N736CB56.js +138 -0
- package/dist/chunks/autodoc-tool-handlers-NQYBY6U4.js +1112 -0
- package/dist/chunks/branch-tool-handlers-KW3H4FJK.js +276 -0
- package/dist/chunks/branch-tool-handlers-QOUDZKJ2.js +276 -0
- package/dist/chunks/branch-tool-handlers-RB2U36KI.js +2 -0
- package/dist/chunks/branch-tool-handlers-ZHJM6PDK.js +276 -0
- package/dist/chunks/chunk-2Z6OQPYC.js +656 -0
- package/dist/chunks/chunk-3MQ7LRPN.js +322 -0
- package/dist/chunks/chunk-4W6QYGXZ.js +10 -0
- package/dist/chunks/chunk-533NFGUG.js +1 -0
- package/dist/chunks/chunk-5NUPOPWM.js +1 -0
- package/dist/chunks/chunk-AK4HIPA2.js +322 -0
- package/dist/chunks/chunk-B3H5NS3I.js +656 -0
- package/dist/chunks/chunk-DPTZHDST.js +4 -0
- package/dist/chunks/chunk-E5HQWLU5.js +322 -0
- package/dist/chunks/chunk-EOH25B5P.js +572 -0
- package/dist/chunks/chunk-ESV6F6E3.js +3179 -0
- package/dist/chunks/chunk-FPELPFER.js +924 -0
- package/dist/chunks/chunk-G6J42I55.js +161 -0
- package/dist/chunks/chunk-GCQE7ZYW.js +1 -0
- package/dist/chunks/chunk-GTIF6MOX.js +1 -0
- package/dist/chunks/chunk-I6STSSAK.js +2 -0
- package/dist/chunks/chunk-J2WBGTK2.js +4697 -0
- package/dist/chunks/chunk-KAYOX5EB.js +4697 -0
- package/dist/chunks/chunk-KPMTACOT.js +656 -0
- package/dist/chunks/chunk-L376GZ44.js +3179 -0
- package/dist/chunks/chunk-LCTOTHDA.js +15 -0
- package/dist/chunks/chunk-LEDJ7GVQ.js +316 -0
- package/dist/chunks/chunk-LH4OUKNZ.js +277 -0
- package/dist/chunks/chunk-O6IE2MEZ.js +161 -0
- package/dist/chunks/chunk-OEXPCY3F.js +316 -0
- package/dist/chunks/chunk-OMXOLFDN.js +924 -0
- package/dist/chunks/chunk-PLPBXWOU.js +3179 -0
- package/dist/chunks/chunk-PWLE5DN2.js +572 -0
- package/dist/chunks/chunk-PY43JPWL.js +447 -0
- package/dist/chunks/chunk-Q3B4EB7A.js +15 -0
- package/dist/chunks/chunk-Q5LPVLXA.js +337 -0
- package/dist/chunks/chunk-QIRZHZK2.js +5 -0
- package/dist/chunks/chunk-ROQ27LSL.js +924 -0
- package/dist/chunks/chunk-S5Q7BD6J.js +572 -0
- package/dist/chunks/chunk-SAMX3HJQ.js +337 -0
- package/dist/chunks/chunk-SV3WKUNV.js +1 -0
- package/dist/chunks/chunk-TCHCDCDO.js +167 -0
- package/dist/chunks/chunk-TR3HS7U6.js +316 -0
- package/dist/chunks/chunk-TUWE6FCW.js +167 -0
- package/dist/chunks/chunk-TVOTA7EE.js +277 -0
- package/dist/chunks/chunk-VS44D772.js +337 -0
- package/dist/chunks/chunk-WIE3G5ES.js +167 -0
- package/dist/chunks/chunk-XG3ACLWR.js +5 -0
- package/dist/chunks/chunk-XJ2Z5QQO.js +1 -0
- package/dist/chunks/chunk-XK2NY7RB.js +277 -0
- package/dist/chunks/chunk-Y4F7NZFZ.js +4700 -0
- package/dist/chunks/chunk-YS75L3ZS.js +161 -0
- package/dist/chunks/chunk-ZVG5HHI3.js +15 -0
- package/dist/chunks/dev-agent-DDDIVWOF.js +1 -0
- package/dist/chunks/dev-agent-E2VCFKXN.js +1624 -0
- package/dist/chunks/dev-agent-KJNSU5KQ.js +1624 -0
- package/dist/chunks/dev-agent-NDERYIPV.js +1624 -0
- package/dist/chunks/faiss-provider-7R4BQDIV.js +12 -0
- package/dist/chunks/faiss-provider-7ZFRSDN5.js +12 -0
- package/dist/chunks/faiss-provider-SXB7FTLB.js +1 -0
- package/dist/chunks/faiss-provider-TKLBEUSH.js +12 -0
- package/dist/chunks/file-tool-handlers-5DODQXGF.js +1027 -0
- package/dist/chunks/file-tool-handlers-KGHLE4KR.js +1027 -0
- package/dist/chunks/file-tool-handlers-KTOQ4NFS.js +12 -0
- package/dist/chunks/file-tool-handlers-V4SFUDQB.js +1027 -0
- package/dist/chunks/graph-metrics-tool-handlers-3AV4X4ZY.js +65 -0
- package/dist/chunks/graph-metrics-tool-handlers-3VMDQHJ6.js +65 -0
- package/dist/chunks/graph-metrics-tool-handlers-BZ6E6YHF.js +1 -0
- package/dist/chunks/graph-metrics-tool-handlers-IYBGSXL7.js +65 -0
- package/dist/chunks/graph-storage-factory-2CQ2RPDV.js +13 -0
- package/dist/chunks/graph-storage-factory-C5SMMYL6.js +13 -0
- package/dist/chunks/graph-storage-factory-EEO2V3GJ.js +1 -0
- package/dist/chunks/graph-storage-factory-WBCTXP34.js +13 -0
- package/dist/chunks/history-tool-handlers-AS7OQFZI.js +1 -0
- package/dist/chunks/history-tool-handlers-FSNJYXV2.js +208 -0
- package/dist/chunks/history-tool-handlers-JZAH4EIQ.js +208 -0
- package/dist/chunks/history-tool-handlers-KCSCXZ7T.js +208 -0
- package/dist/chunks/incremental-updater-A2EL4QXU.js +14 -0
- package/dist/chunks/incremental-updater-EQIKBVY2.js +14 -0
- package/dist/chunks/incremental-updater-JFGRPH3B.js +14 -0
- package/dist/chunks/incremental-updater-S5BAAGHP.js +1 -0
- package/dist/chunks/indexer-agent-ASKY7JPG.js +1 -0
- package/dist/chunks/indexer-agent-NKAOF323.js +21 -0
- package/dist/chunks/indexer-agent-PJN5IOKQ.js +21 -0
- package/dist/chunks/indexer-agent-WRJFWKZX.js +21 -0
- package/dist/chunks/indexing-pipeline-D4P2O72Z.js +249 -0
- package/dist/chunks/indexing-pipeline-L7C543N4.js +1 -0
- package/dist/chunks/indexing-pipeline-NHPRN3AB.js +249 -0
- package/dist/chunks/indexing-pipeline-ZAXCZU22.js +249 -0
- package/dist/chunks/layered-faiss-provider-62CNW54X.js +1 -0
- package/dist/chunks/layered-faiss-provider-O7L77GFX.js +12 -0
- package/dist/chunks/layered-faiss-provider-RVHLHLPK.js +12 -0
- package/dist/chunks/layered-faiss-provider-YT7EDIJI.js +12 -0
- package/dist/chunks/merge-agent-3RF7VFF5.js +2481 -0
- package/dist/chunks/merge-agent-JCKTCBCE.js +2481 -0
- package/dist/chunks/merge-agent-VCL7OXPN.js +2481 -0
- package/dist/chunks/merge-agent-ZGK24WVF.js +11 -0
- package/dist/chunks/merge-tool-handlers-GV2LOIKU.js +277 -0
- package/dist/chunks/merge-tool-handlers-TYDWU5X2.js +277 -0
- package/dist/chunks/merge-tool-handlers-U7X2ZO2M.js +1 -0
- package/dist/chunks/merge-tool-handlers-YH62ZLPJ.js +277 -0
- package/dist/chunks/pattern-tool-handlers-76NF5JDS.js +13 -0
- package/dist/chunks/pattern-tool-handlers-IJAGEIVD.js +1549 -0
- package/dist/chunks/pattern-tool-handlers-VA5WYA62.js +1549 -0
- package/dist/chunks/pattern-tool-handlers-WQ6UBMJS.js +1549 -0
- package/dist/chunks/query-agent-36ADGCFZ.js +1 -0
- package/dist/chunks/query-agent-H22CR5N5.js +191 -0
- package/dist/chunks/query-agent-K2UGZS4M.js +191 -0
- package/dist/chunks/query-agent-YJCEHOXD.js +191 -0
- package/dist/chunks/semantic-agent-AC7CBEDE.js +6381 -0
- package/dist/chunks/semantic-agent-HK5X6CKU.js +6381 -0
- package/dist/chunks/semantic-agent-KONIKEGW.js +6381 -0
- package/dist/chunks/semantic-agent-LH6IZ2L7.js +137 -0
- package/dist/chunks/semantic-tool-handlers-5LMSH2U7.js +3 -0
- package/dist/chunks/semantic-tool-handlers-735UMO7Y.js +817 -0
- package/dist/chunks/semantic-tool-handlers-BNUYPP7X.js +817 -0
- package/dist/chunks/semantic-tool-handlers-MYZPEUD2.js +817 -0
- package/dist/chunks/snapshot-tool-handlers-6SIHZT2F.js +201 -0
- package/dist/chunks/snapshot-tool-handlers-DS4P3KOT.js +201 -0
- package/dist/chunks/snapshot-tool-handlers-JYHRFPC7.js +201 -0
- package/dist/chunks/snapshot-tool-handlers-YEHMAT3L.js +1 -0
- package/dist/chunks/storage-paths-A3C7WHHG.js +8 -0
- package/dist/chunks/storage-paths-HDYH7WPM.js +1 -0
- package/dist/chunks/storage-paths-IMFRHBWF.js +8 -0
- package/dist/chunks/storage-paths-P3PUSMUD.js +8 -0
- package/dist/chunks/taint-tool-handlers-CWESOOMQ.js +68 -0
- package/dist/chunks/taint-tool-handlers-OG3NVVP3.js +1 -0
- package/dist/chunks/taint-tool-handlers-ON3G3FA7.js +68 -0
- package/dist/chunks/taint-tool-handlers-P4P5J6DB.js +68 -0
- package/dist/chunks/tracing-tool-handlers-4BDCXTZZ.js +3935 -0
- package/dist/chunks/tracing-tool-handlers-6FPNM7HX.js +3935 -0
- package/dist/chunks/tracing-tool-handlers-LQTQ5SKK.js +89 -0
- package/dist/chunks/tracing-tool-handlers-XRQX2DTS.js +3935 -0
- package/dist/chunks/validation-tool-handlers-DZUG7KYY.js +2 -0
- package/dist/chunks/validation-tool-handlers-O6TGFSH5.js +555 -0
- package/dist/chunks/validation-tool-handlers-RREUYKIR.js +555 -0
- package/dist/chunks/validation-tool-handlers-XPWSMS37.js +555 -0
- package/dist/index.js +13 -13
- 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,1027 @@
|
|
|
1
|
+
import { projectPathParam } from './chunk-NJUB245U.js';
|
|
2
|
+
import { BaseToolHandler } from './chunk-VS44D772.js';
|
|
3
|
+
import './chunk-TUWE6FCW.js';
|
|
4
|
+
import './chunk-CTXFPNDA.js';
|
|
5
|
+
import './chunk-TJSOOFXA.js';
|
|
6
|
+
import './chunk-TVOTA7EE.js';
|
|
7
|
+
import './chunk-HEMJHRHZ.js';
|
|
8
|
+
import { toError } from './chunk-5WKPA33T.js';
|
|
9
|
+
import './chunk-GMVGCSNU.js';
|
|
10
|
+
import './chunk-VCCBEJQ5.js';
|
|
11
|
+
import './chunk-NAQKA54E.js';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
|
|
14
|
+
// src/tools/impact-analyzer.ts
|
|
15
|
+
var ImpactAnalyzer = class {
|
|
16
|
+
storage;
|
|
17
|
+
semanticSearch;
|
|
18
|
+
constructor(storage, semanticSearch) {
|
|
19
|
+
this.storage = storage;
|
|
20
|
+
this.semanticSearch = semanticSearch;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Analyze the impact of modifying an entity
|
|
24
|
+
*/
|
|
25
|
+
async analyzeModificationImpact(entityId, options = {}) {
|
|
26
|
+
const { maxCallerDepth = 2, analyzeStates = true, minConfidence = 0.5 } = options;
|
|
27
|
+
const entity = await this.storage.getEntity(entityId);
|
|
28
|
+
if (!entity) {
|
|
29
|
+
return this.emptyResult("Entity not found");
|
|
30
|
+
}
|
|
31
|
+
const directCallers = await this.findDirectCallers(entityId, maxCallerDepth);
|
|
32
|
+
const stateImpact = analyzeStates ? await this.analyzeStateImpact(entity) : [];
|
|
33
|
+
const breakingChanges = await this.detectBreakingChanges(entity, directCallers);
|
|
34
|
+
const reviewSuggestions = this.generateReviewSuggestions(entity, directCallers, stateImpact);
|
|
35
|
+
const confidence = this.calculateConfidence(directCallers.length, stateImpact.length);
|
|
36
|
+
if (confidence < minConfidence) {
|
|
37
|
+
return this.emptyResult("Insufficient data for reliable analysis");
|
|
38
|
+
}
|
|
39
|
+
const summary = this.generateSummary(entity, directCallers, stateImpact, breakingChanges);
|
|
40
|
+
return {
|
|
41
|
+
analyzed: true,
|
|
42
|
+
directCallers,
|
|
43
|
+
stateImpact,
|
|
44
|
+
breakingChanges,
|
|
45
|
+
reviewSuggestions,
|
|
46
|
+
summary,
|
|
47
|
+
confidence
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Analyze impact of creating a new file
|
|
52
|
+
*/
|
|
53
|
+
async analyzeNewFileImpact(filePath, entityNames) {
|
|
54
|
+
const similarCode = [];
|
|
55
|
+
if (this.semanticSearch) {
|
|
56
|
+
for (const name of entityNames.slice(0, 3)) {
|
|
57
|
+
try {
|
|
58
|
+
const results = await this.semanticSearch.search(name, {
|
|
59
|
+
limit: 3,
|
|
60
|
+
minSimilarity: 0.7
|
|
61
|
+
});
|
|
62
|
+
for (const result of results) {
|
|
63
|
+
const entity = await this.storage.getEntity(result.entityId);
|
|
64
|
+
if (entity && entity.filePath !== filePath) {
|
|
65
|
+
similarCode.push({
|
|
66
|
+
name: entity.name,
|
|
67
|
+
file: entity.filePath,
|
|
68
|
+
similarity: result.similarity
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const reviewSuggestions = [];
|
|
77
|
+
if (similarCode.length > 0) {
|
|
78
|
+
reviewSuggestions.push(`Found ${similarCode.length} similar entities - consider reusing existing code`);
|
|
79
|
+
for (const s of similarCode.slice(0, 3)) {
|
|
80
|
+
reviewSuggestions.push(` \u2022 ${s.name} in ${s.file} (${Math.round(s.similarity * 100)}% similar)`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
analyzed: similarCode.length > 0,
|
|
85
|
+
directCallers: [],
|
|
86
|
+
stateImpact: [],
|
|
87
|
+
breakingChanges: [],
|
|
88
|
+
reviewSuggestions,
|
|
89
|
+
summary: similarCode.length > 0 ? `\u26A0\uFE0F Similar code exists: ${similarCode.map((s) => s.name).join(", ")}` : "",
|
|
90
|
+
confidence: similarCode.length > 0 ? 0.7 : 0
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Analyze impact of renaming a symbol
|
|
95
|
+
*/
|
|
96
|
+
async analyzeRenameImpact(entityId, oldName, newName) {
|
|
97
|
+
const entity = await this.storage.getEntity(entityId);
|
|
98
|
+
if (!entity) {
|
|
99
|
+
return this.emptyResult("Entity not found");
|
|
100
|
+
}
|
|
101
|
+
const references = await this.findAllReferences(entityId);
|
|
102
|
+
const affectedFiles = new Set(references.map((r) => r.file));
|
|
103
|
+
const breakingChanges = [];
|
|
104
|
+
const conflicts = await this.storage.searchEntities({ namePattern: newName });
|
|
105
|
+
if (conflicts.length > 0) {
|
|
106
|
+
breakingChanges.push({
|
|
107
|
+
description: `Name "${newName}" already exists in ${conflicts.length} place(s)`,
|
|
108
|
+
location: conflicts[0].filePath,
|
|
109
|
+
severity: "warning"
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const reviewSuggestions = [`Rename will affect ${references.length} reference(s) in ${affectedFiles.size} file(s)`];
|
|
113
|
+
if (references.length > 10) {
|
|
114
|
+
reviewSuggestions.push("\u26A0\uFE0F Large refactoring - consider reviewing changes before applying");
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
analyzed: true,
|
|
118
|
+
directCallers: references,
|
|
119
|
+
stateImpact: [],
|
|
120
|
+
breakingChanges,
|
|
121
|
+
reviewSuggestions,
|
|
122
|
+
summary: `Renaming ${oldName} \u2192 ${newName} affects ${references.length} references`,
|
|
123
|
+
confidence: 0.9
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Detect if a modification breaks swagger API contracts.
|
|
128
|
+
* Checks if the entity has PRODUCES_API relationships and analyzes the change.
|
|
129
|
+
*/
|
|
130
|
+
async detectSwaggerContractBreaks(entityId) {
|
|
131
|
+
const result = {
|
|
132
|
+
affectsContract: false,
|
|
133
|
+
contractBreaks: [],
|
|
134
|
+
isGeneratedCode: false,
|
|
135
|
+
generatedFromSwagger: null
|
|
136
|
+
};
|
|
137
|
+
const entity = await this.storage.getEntity(entityId);
|
|
138
|
+
if (!entity) return result;
|
|
139
|
+
const relationships = await this.storage.getRelationshipsForEntity(entityId);
|
|
140
|
+
for (const rel of relationships) {
|
|
141
|
+
if (rel.type === "produces_api" /* PRODUCES_API */ && rel.fromId === entityId) {
|
|
142
|
+
result.affectsContract = true;
|
|
143
|
+
const swaggerEntity = await this.storage.getEntity(rel.toId);
|
|
144
|
+
if (swaggerEntity) {
|
|
145
|
+
const endpoint = `${swaggerEntity.metadata?.["httpMethod"] || ""} ${swaggerEntity.metadata?.["path"] || ""}`.trim();
|
|
146
|
+
result.contractBreaks.push({
|
|
147
|
+
rule: "controller-modified",
|
|
148
|
+
change: "unknown",
|
|
149
|
+
endpoint: endpoint || swaggerEntity.name,
|
|
150
|
+
message: `API contract may be affected: controller produces ${endpoint || swaggerEntity.name}`
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (rel.type === "generated_from" /* GENERATED_FROM */ && rel.fromId === entityId) {
|
|
155
|
+
result.isGeneratedCode = true;
|
|
156
|
+
const swaggerEntity = await this.storage.getEntity(rel.toId);
|
|
157
|
+
result.generatedFromSwagger = swaggerEntity?.filePath || null;
|
|
158
|
+
}
|
|
159
|
+
if (rel.type === "consumes_api" /* CONSUMES_API */ && rel.fromId === entityId) {
|
|
160
|
+
result.isGeneratedCode = true;
|
|
161
|
+
const swaggerEntity = await this.storage.getEntity(rel.toId);
|
|
162
|
+
result.generatedFromSwagger = swaggerEntity?.filePath || null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
// ===========================================================================
|
|
168
|
+
// PRIVATE HELPERS
|
|
169
|
+
// ===========================================================================
|
|
170
|
+
async findDirectCallers(entityId, maxDepth) {
|
|
171
|
+
const callers = [];
|
|
172
|
+
const visited = /* @__PURE__ */ new Set();
|
|
173
|
+
const findCallers = async (id, depth) => {
|
|
174
|
+
if (depth > maxDepth || visited.has(id)) return;
|
|
175
|
+
visited.add(id);
|
|
176
|
+
const rels = await this.storage.getRelationshipsForEntity(id, "calls" /* CALLS */);
|
|
177
|
+
for (const rel of rels) {
|
|
178
|
+
if (rel.toId === id && !visited.has(rel.fromId)) {
|
|
179
|
+
const caller = await this.storage.getEntity(rel.fromId);
|
|
180
|
+
if (caller) {
|
|
181
|
+
callers.push({
|
|
182
|
+
name: caller.name,
|
|
183
|
+
file: caller.filePath,
|
|
184
|
+
line: caller.location.start.line
|
|
185
|
+
});
|
|
186
|
+
if (depth < maxDepth) {
|
|
187
|
+
await findCallers(rel.fromId, depth + 1);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
await findCallers(entityId, 0);
|
|
194
|
+
return callers;
|
|
195
|
+
}
|
|
196
|
+
async findAllReferences(entityId) {
|
|
197
|
+
const refs = [];
|
|
198
|
+
const rels = await this.storage.getRelationshipsForEntity(entityId);
|
|
199
|
+
for (const rel of rels) {
|
|
200
|
+
const otherId = rel.fromId === entityId ? rel.toId : rel.fromId;
|
|
201
|
+
const other = await this.storage.getEntity(otherId);
|
|
202
|
+
if (other) {
|
|
203
|
+
refs.push({
|
|
204
|
+
name: other.name,
|
|
205
|
+
file: other.filePath,
|
|
206
|
+
line: other.location.start.line
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return refs;
|
|
211
|
+
}
|
|
212
|
+
async analyzeStateImpact(entity) {
|
|
213
|
+
const impact = [];
|
|
214
|
+
const meta = entity.metadata;
|
|
215
|
+
const modifiedStates = Array.isArray(meta["stateModifications"]) ? meta["stateModifications"] : [];
|
|
216
|
+
for (const state of modifiedStates) {
|
|
217
|
+
const allEntities = await this.storage.getAllEntities();
|
|
218
|
+
const affected = [];
|
|
219
|
+
for (const e of allEntities) {
|
|
220
|
+
if (e.id === entity.id) continue;
|
|
221
|
+
const eMeta = e.metadata;
|
|
222
|
+
const reads = Array.isArray(eMeta["stateReads"]) ? eMeta["stateReads"] : [];
|
|
223
|
+
if (reads.includes(state)) {
|
|
224
|
+
affected.push(e.name);
|
|
225
|
+
}
|
|
226
|
+
if (eMeta["controlFlow"]?.branches && Array.isArray(eMeta["controlFlow"].branches)) {
|
|
227
|
+
for (const branch of eMeta["controlFlow"].branches) {
|
|
228
|
+
if (branch.condition?.includes(state)) {
|
|
229
|
+
if (!affected.includes(e.name)) {
|
|
230
|
+
affected.push(e.name);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (affected.length > 0) {
|
|
237
|
+
impact.push({
|
|
238
|
+
state,
|
|
239
|
+
affectedEntities: affected.slice(0, 10),
|
|
240
|
+
// Limit to 10
|
|
241
|
+
risk: affected.length > 5 ? "high" : affected.length > 2 ? "medium" : "low"
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return impact;
|
|
246
|
+
}
|
|
247
|
+
async detectBreakingChanges(entity, callers) {
|
|
248
|
+
const changes = [];
|
|
249
|
+
const meta = entity.metadata;
|
|
250
|
+
const isExported = meta["exported"] === true || entity.name.startsWith("export");
|
|
251
|
+
if (isExported && callers.length > 3) {
|
|
252
|
+
changes.push({
|
|
253
|
+
description: `Exported entity with ${callers.length} callers - signature changes may break consumers`,
|
|
254
|
+
location: `${entity.filePath}:${entity.location.start.line}`,
|
|
255
|
+
severity: "warning"
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const params = Array.isArray(meta["parameters"]) ? meta["parameters"] : [];
|
|
259
|
+
if (params.length > 0 && callers.length > 0) {
|
|
260
|
+
changes.push({
|
|
261
|
+
description: `Function has ${params.length} parameters - changes may require updating ${callers.length} call sites`,
|
|
262
|
+
location: `${entity.filePath}:${entity.location.start.line}`,
|
|
263
|
+
severity: "warning"
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return changes;
|
|
267
|
+
}
|
|
268
|
+
generateReviewSuggestions(_entity, callers, stateImpact) {
|
|
269
|
+
const suggestions = [];
|
|
270
|
+
if (callers.length > 0) {
|
|
271
|
+
const uniqueFiles = new Set(callers.map((c) => c.file));
|
|
272
|
+
suggestions.push(`\u{1F4CD} Review ${callers.length} caller(s) in ${uniqueFiles.size} file(s)`);
|
|
273
|
+
for (const caller of callers.slice(0, 3)) {
|
|
274
|
+
suggestions.push(` \u2022 ${caller.name} (${caller.file}:${caller.line})`);
|
|
275
|
+
}
|
|
276
|
+
if (callers.length > 3) {
|
|
277
|
+
suggestions.push(` ... and ${callers.length - 3} more`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (stateImpact.length > 0) {
|
|
281
|
+
const highRisk = stateImpact.filter((s) => s.risk === "high");
|
|
282
|
+
if (highRisk.length > 0) {
|
|
283
|
+
suggestions.push(`\u26A0\uFE0F High-risk state changes: ${highRisk.map((s) => s.state).join(", ")}`);
|
|
284
|
+
}
|
|
285
|
+
for (const impact of stateImpact.slice(0, 2)) {
|
|
286
|
+
suggestions.push(
|
|
287
|
+
` State "${impact.state}" affects: ${impact.affectedEntities.slice(0, 3).join(", ")}${impact.affectedEntities.length > 3 ? "..." : ""}`
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return suggestions;
|
|
292
|
+
}
|
|
293
|
+
generateSummary(entity, callers, stateImpact, breakingChanges) {
|
|
294
|
+
const parts = [];
|
|
295
|
+
if (callers.length === 0 && stateImpact.length === 0) {
|
|
296
|
+
return `\u2705 No significant impact detected for ${entity.name}`;
|
|
297
|
+
}
|
|
298
|
+
if (callers.length > 0) {
|
|
299
|
+
parts.push(`${callers.length} caller(s)`);
|
|
300
|
+
}
|
|
301
|
+
if (stateImpact.length > 0) {
|
|
302
|
+
const totalAffected = stateImpact.reduce((sum, s) => sum + s.affectedEntities.length, 0);
|
|
303
|
+
parts.push(`${totalAffected} state-dependent entities`);
|
|
304
|
+
}
|
|
305
|
+
if (breakingChanges.length > 0) {
|
|
306
|
+
parts.push(`${breakingChanges.length} potential breaking change(s)`);
|
|
307
|
+
}
|
|
308
|
+
const prefix = breakingChanges.length > 0 ? "\u26A0\uFE0F" : "\u2139\uFE0F";
|
|
309
|
+
return `${prefix} Modification of ${entity.name} may affect: ${parts.join(", ")}`;
|
|
310
|
+
}
|
|
311
|
+
calculateConfidence(callerCount, stateImpactCount) {
|
|
312
|
+
let confidence = 0.6;
|
|
313
|
+
if (callerCount > 0) confidence += 0.1;
|
|
314
|
+
if (callerCount > 5) confidence += 0.1;
|
|
315
|
+
if (stateImpactCount > 0) confidence += 0.1;
|
|
316
|
+
return Math.min(confidence, 1);
|
|
317
|
+
}
|
|
318
|
+
emptyResult(reason) {
|
|
319
|
+
return {
|
|
320
|
+
analyzed: false,
|
|
321
|
+
directCallers: [],
|
|
322
|
+
stateImpact: [],
|
|
323
|
+
breakingChanges: [],
|
|
324
|
+
reviewSuggestions: [],
|
|
325
|
+
summary: reason,
|
|
326
|
+
confidence: 0
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
function formatImpactForResponse(impact) {
|
|
331
|
+
if (!impact.analyzed || impact.confidence < 0.5) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
const lines = [];
|
|
335
|
+
lines.push("");
|
|
336
|
+
lines.push("\u2500\u2500\u2500 Impact Analysis \u2500\u2500\u2500");
|
|
337
|
+
lines.push(impact.summary);
|
|
338
|
+
if (impact.reviewSuggestions.length > 0) {
|
|
339
|
+
lines.push("");
|
|
340
|
+
for (const suggestion of impact.reviewSuggestions) {
|
|
341
|
+
lines.push(suggestion);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (impact.breakingChanges.length > 0) {
|
|
345
|
+
lines.push("");
|
|
346
|
+
lines.push("\u26A0\uFE0F Potential Issues:");
|
|
347
|
+
for (const change of impact.breakingChanges) {
|
|
348
|
+
lines.push(` ${change.severity === "error" ? "\u274C" : "\u26A0\uFE0F"} ${change.description}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return lines.join("\n");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// src/tools/handlers/file-tool-utils.ts
|
|
355
|
+
async function setupSemanticSearch(context) {
|
|
356
|
+
try {
|
|
357
|
+
const semanticAgent = await context.getSemanticAgent();
|
|
358
|
+
const vectorStore = semanticAgent.getVectorStore?.();
|
|
359
|
+
if (!vectorStore) return void 0;
|
|
360
|
+
return {
|
|
361
|
+
search: async (query, options) => {
|
|
362
|
+
const results = await vectorStore.search(query, options.limit);
|
|
363
|
+
return results.filter((r) => r.similarity >= options.minSimilarity).map((r) => ({ entityId: r.entityId, similarity: r.similarity }));
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
} catch {
|
|
367
|
+
return void 0;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async function reindexFiles(context, files, taskPrefix, priority = 5) {
|
|
371
|
+
const conductor = context.getConductor();
|
|
372
|
+
const devAgent = conductor.getAgentByType?.("dev" /* DEV */);
|
|
373
|
+
if (!devAgent) {
|
|
374
|
+
throw new Error("DevAgent not available for reindexing");
|
|
375
|
+
}
|
|
376
|
+
await devAgent.process({
|
|
377
|
+
id: `${taskPrefix}-${Date.now()}`,
|
|
378
|
+
type: "index",
|
|
379
|
+
priority,
|
|
380
|
+
payload: { files },
|
|
381
|
+
createdAt: Date.now()
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function buildSuccessResponse(baseFields, optionalFields) {
|
|
385
|
+
const response = { ...baseFields };
|
|
386
|
+
return {
|
|
387
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function buildErrorResponse(error, additionalFields) {
|
|
391
|
+
const message = typeof error === "string" ? error : error.message;
|
|
392
|
+
return {
|
|
393
|
+
content: [
|
|
394
|
+
{
|
|
395
|
+
type: "text",
|
|
396
|
+
text: JSON.stringify({ error: message, ...additionalFields })
|
|
397
|
+
}
|
|
398
|
+
]
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
async function ensureDirectoryExists(filePath) {
|
|
402
|
+
const { dirname } = await import('path');
|
|
403
|
+
const { mkdir } = await import('fs/promises');
|
|
404
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// src/tools/handlers/file-tool-handlers.ts
|
|
408
|
+
var ModifyEntityCodeSchema = z.object({
|
|
409
|
+
entityId: z.string().optional(),
|
|
410
|
+
filePath: z.string().optional(),
|
|
411
|
+
entityName: z.string().optional(),
|
|
412
|
+
projectPath: projectPathParam,
|
|
413
|
+
newCode: z.string(),
|
|
414
|
+
preview: z.boolean().optional().default(false)
|
|
415
|
+
});
|
|
416
|
+
var ModifyEntityCodeToolHandler = class extends BaseToolHandler {
|
|
417
|
+
parseArgs(args) {
|
|
418
|
+
return ModifyEntityCodeSchema.parse(args);
|
|
419
|
+
}
|
|
420
|
+
async execute(args) {
|
|
421
|
+
const { CodeModifier } = await import('./code-modifier-T5MXPBT7.js');
|
|
422
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
423
|
+
const semanticSearch = await setupSemanticSearch(this.context);
|
|
424
|
+
let vectorStore = null;
|
|
425
|
+
try {
|
|
426
|
+
const semanticAgent = await this.context.getSemanticAgent();
|
|
427
|
+
vectorStore = semanticAgent.getVectorStore?.();
|
|
428
|
+
} catch {
|
|
429
|
+
}
|
|
430
|
+
const workingDir = this.resolveProjectPath({});
|
|
431
|
+
const modifier = new CodeModifier(storage, vectorStore, workingDir);
|
|
432
|
+
const impactAnalyzer = new ImpactAnalyzer(storage, semanticSearch);
|
|
433
|
+
let entityId = args.entityId;
|
|
434
|
+
if (!entityId && args.filePath) {
|
|
435
|
+
const normalizedPath = this.context.normalizeInputPath(args.filePath);
|
|
436
|
+
const entities = await storage.findEntities({
|
|
437
|
+
filters: { filePath: normalizedPath },
|
|
438
|
+
limit: 100
|
|
439
|
+
});
|
|
440
|
+
if (args.entityName) {
|
|
441
|
+
const match = entities.find((e) => e.name === args.entityName);
|
|
442
|
+
if (match) entityId = match.id;
|
|
443
|
+
} else if (entities.length === 1 && entities[0]) {
|
|
444
|
+
entityId = entities[0].id;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (!entityId) {
|
|
448
|
+
return {
|
|
449
|
+
content: [{ type: "text", text: JSON.stringify({ error: "Entity not found" }) }]
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
const [result, impactResult] = await Promise.all([
|
|
454
|
+
// Main operation: modify the entity
|
|
455
|
+
modifier.modifyEntity({
|
|
456
|
+
entityId,
|
|
457
|
+
newCode: args.newCode,
|
|
458
|
+
preview: args.preview
|
|
459
|
+
}),
|
|
460
|
+
// Parallel: analyze impact (only for actual modifications)
|
|
461
|
+
args.preview ? Promise.resolve(null) : impactAnalyzer.analyzeModificationImpact(entityId).catch(() => null)
|
|
462
|
+
]);
|
|
463
|
+
const response = {
|
|
464
|
+
success: result.success,
|
|
465
|
+
preview: args.preview,
|
|
466
|
+
entityId,
|
|
467
|
+
filesModified: result.filesModified,
|
|
468
|
+
snapshotId: result.snapshotId
|
|
469
|
+
};
|
|
470
|
+
if (result.validationReport) {
|
|
471
|
+
const { before, after } = result.validationReport;
|
|
472
|
+
response["validation"] = {
|
|
473
|
+
before,
|
|
474
|
+
after,
|
|
475
|
+
improved: (after?.summary?.errors ?? 0) < (before?.summary?.errors ?? 0)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
if (impactResult) {
|
|
479
|
+
const formattedImpact = formatImpactForResponse(impactResult);
|
|
480
|
+
if (formattedImpact) {
|
|
481
|
+
response["impactAnalysis"] = formattedImpact;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (result.swaggerWarning) {
|
|
485
|
+
try {
|
|
486
|
+
const swaggerImpact = await impactAnalyzer.detectSwaggerContractBreaks(entityId);
|
|
487
|
+
response["swaggerImpact"] = {
|
|
488
|
+
affectsContract: swaggerImpact.affectsContract,
|
|
489
|
+
contractBreaks: swaggerImpact.contractBreaks,
|
|
490
|
+
isGeneratedCode: swaggerImpact.isGeneratedCode,
|
|
491
|
+
generatedFromSwagger: swaggerImpact.generatedFromSwagger,
|
|
492
|
+
warning: result.swaggerWarning
|
|
493
|
+
};
|
|
494
|
+
} catch {
|
|
495
|
+
response["swaggerImpact"] = {
|
|
496
|
+
affectsContract: true,
|
|
497
|
+
warning: result.swaggerWarning
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
content: [
|
|
503
|
+
{
|
|
504
|
+
type: "text",
|
|
505
|
+
text: JSON.stringify(response, null, 2)
|
|
506
|
+
}
|
|
507
|
+
]
|
|
508
|
+
};
|
|
509
|
+
} catch (error) {
|
|
510
|
+
const err = toError(error);
|
|
511
|
+
return {
|
|
512
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
var CopyFileSchema = z.object({
|
|
518
|
+
sourcePath: z.string(),
|
|
519
|
+
destinationPath: z.string(),
|
|
520
|
+
projectPath: projectPathParam,
|
|
521
|
+
updateImports: z.boolean().optional().default(true)
|
|
522
|
+
});
|
|
523
|
+
var CopyFileToolHandler = class extends BaseToolHandler {
|
|
524
|
+
parseArgs(args) {
|
|
525
|
+
return CopyFileSchema.parse(args);
|
|
526
|
+
}
|
|
527
|
+
async execute(args) {
|
|
528
|
+
const { copyFile } = await import('fs/promises');
|
|
529
|
+
const sourcePath = this.context.normalizeInputPath(args.sourcePath) || args.sourcePath;
|
|
530
|
+
const destinationPath = this.context.normalizeInputPath(args.destinationPath) || args.destinationPath;
|
|
531
|
+
try {
|
|
532
|
+
await ensureDirectoryExists(destinationPath);
|
|
533
|
+
await copyFile(sourcePath, destinationPath);
|
|
534
|
+
await reindexFiles(this.context, [destinationPath], "copy-index");
|
|
535
|
+
return buildSuccessResponse({
|
|
536
|
+
success: true,
|
|
537
|
+
source: sourcePath,
|
|
538
|
+
destination: destinationPath,
|
|
539
|
+
indexed: true
|
|
540
|
+
});
|
|
541
|
+
} catch (error) {
|
|
542
|
+
const err = toError(error);
|
|
543
|
+
return buildErrorResponse(err);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
var RenameFileSchema = z.object({
|
|
548
|
+
sourcePath: z.string(),
|
|
549
|
+
destinationPath: z.string(),
|
|
550
|
+
projectPath: projectPathParam,
|
|
551
|
+
updateImports: z.boolean().optional().default(true)
|
|
552
|
+
});
|
|
553
|
+
var RenameFileToolHandler = class extends BaseToolHandler {
|
|
554
|
+
parseArgs(args) {
|
|
555
|
+
return RenameFileSchema.parse(args);
|
|
556
|
+
}
|
|
557
|
+
async execute(args) {
|
|
558
|
+
const { rename } = await import('fs/promises');
|
|
559
|
+
const sourcePath = this.context.normalizeInputPath(args.sourcePath) || args.sourcePath;
|
|
560
|
+
const destinationPath = this.context.normalizeInputPath(args.destinationPath) || args.destinationPath;
|
|
561
|
+
try {
|
|
562
|
+
await ensureDirectoryExists(destinationPath);
|
|
563
|
+
await rename(sourcePath, destinationPath);
|
|
564
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
565
|
+
const oldEntities = await storage.findEntities({
|
|
566
|
+
filters: { filePath: sourcePath },
|
|
567
|
+
limit: 1e3
|
|
568
|
+
});
|
|
569
|
+
for (const entity of oldEntities) {
|
|
570
|
+
await storage.deleteEntity(entity.id);
|
|
571
|
+
}
|
|
572
|
+
await reindexFiles(this.context, [destinationPath], "rename-index");
|
|
573
|
+
return buildSuccessResponse({
|
|
574
|
+
success: true,
|
|
575
|
+
source: sourcePath,
|
|
576
|
+
destination: destinationPath,
|
|
577
|
+
entitiesMoved: oldEntities.length,
|
|
578
|
+
importsUpdated: args.updateImports
|
|
579
|
+
});
|
|
580
|
+
} catch (error) {
|
|
581
|
+
const err = toError(error);
|
|
582
|
+
return buildErrorResponse(err);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
var SplitFileSchema = z.object({
|
|
587
|
+
filePath: z.string(),
|
|
588
|
+
outputDirectory: z.string().optional(),
|
|
589
|
+
projectPath: projectPathParam,
|
|
590
|
+
splitBy: z.enum(["class", "function", "module"]).optional().default("class"),
|
|
591
|
+
preview: z.boolean().optional().default(true)
|
|
592
|
+
});
|
|
593
|
+
var SplitFileToolHandler = class extends BaseToolHandler {
|
|
594
|
+
parseArgs(args) {
|
|
595
|
+
return SplitFileSchema.parse(args);
|
|
596
|
+
}
|
|
597
|
+
async execute(args) {
|
|
598
|
+
const { mkdir } = await import('fs/promises');
|
|
599
|
+
const { dirname, join, extname } = await import('path');
|
|
600
|
+
const filePath = this.context.normalizeInputPath(args.filePath) || args.filePath;
|
|
601
|
+
const outputDir = args.outputDirectory ? this.context.normalizeInputPath(args.outputDirectory) || args.outputDirectory : dirname(filePath);
|
|
602
|
+
try {
|
|
603
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
604
|
+
const entities = await storage.findEntities({
|
|
605
|
+
filters: { filePath },
|
|
606
|
+
limit: 1e3
|
|
607
|
+
});
|
|
608
|
+
const targetTypes = args.splitBy === "class" ? ["class", "interface", "enum"] : args.splitBy === "function" ? ["function", "method"] : ["module"];
|
|
609
|
+
const toSplit = entities.filter((e) => targetTypes.some((t) => e.type.toLowerCase().includes(t)));
|
|
610
|
+
if (toSplit.length <= 1) {
|
|
611
|
+
return {
|
|
612
|
+
content: [
|
|
613
|
+
{
|
|
614
|
+
type: "text",
|
|
615
|
+
text: JSON.stringify({
|
|
616
|
+
success: false,
|
|
617
|
+
message: `Only ${toSplit.length} entity found, nothing to split`,
|
|
618
|
+
entities: toSplit.map((e) => e.name)
|
|
619
|
+
})
|
|
620
|
+
}
|
|
621
|
+
]
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
const ext = extname(filePath);
|
|
625
|
+
const plannedFiles = toSplit.map((e) => ({
|
|
626
|
+
name: e.name,
|
|
627
|
+
type: e.type,
|
|
628
|
+
outputPath: join(outputDir, `${e.name}${ext}`)
|
|
629
|
+
}));
|
|
630
|
+
if (args.preview) {
|
|
631
|
+
return {
|
|
632
|
+
content: [
|
|
633
|
+
{
|
|
634
|
+
type: "text",
|
|
635
|
+
text: JSON.stringify(
|
|
636
|
+
{
|
|
637
|
+
preview: true,
|
|
638
|
+
sourceFile: filePath,
|
|
639
|
+
entitiesToSplit: toSplit.length,
|
|
640
|
+
plannedFiles
|
|
641
|
+
},
|
|
642
|
+
null,
|
|
643
|
+
2
|
|
644
|
+
)
|
|
645
|
+
}
|
|
646
|
+
]
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
await mkdir(outputDir, { recursive: true });
|
|
650
|
+
return {
|
|
651
|
+
content: [
|
|
652
|
+
{
|
|
653
|
+
type: "text",
|
|
654
|
+
text: JSON.stringify(
|
|
655
|
+
{
|
|
656
|
+
success: true,
|
|
657
|
+
sourceFile: filePath,
|
|
658
|
+
filesCreated: plannedFiles.length,
|
|
659
|
+
files: plannedFiles
|
|
660
|
+
},
|
|
661
|
+
null,
|
|
662
|
+
2
|
|
663
|
+
)
|
|
664
|
+
}
|
|
665
|
+
]
|
|
666
|
+
};
|
|
667
|
+
} catch (error) {
|
|
668
|
+
const err = toError(error);
|
|
669
|
+
return {
|
|
670
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
var SynthesizeFilesSchema = z.object({
|
|
676
|
+
filePaths: z.array(z.string()),
|
|
677
|
+
outputPath: z.string(),
|
|
678
|
+
projectPath: projectPathParam,
|
|
679
|
+
preview: z.boolean().optional().default(true)
|
|
680
|
+
});
|
|
681
|
+
var SynthesizeFilesToolHandler = class extends BaseToolHandler {
|
|
682
|
+
parseArgs(args) {
|
|
683
|
+
return SynthesizeFilesSchema.parse(args);
|
|
684
|
+
}
|
|
685
|
+
async execute(args) {
|
|
686
|
+
const { readText, writeFile } = await import('./file-ops-NCYUEOBU.js');
|
|
687
|
+
const filePaths = args.filePaths.map((p) => this.context.normalizeInputPath(p) || p);
|
|
688
|
+
const outputPath = this.context.normalizeInputPath(args.outputPath) || args.outputPath;
|
|
689
|
+
try {
|
|
690
|
+
const contents = await Promise.all(
|
|
691
|
+
filePaths.map(async (p) => ({
|
|
692
|
+
path: p,
|
|
693
|
+
content: await readText(p)
|
|
694
|
+
}))
|
|
695
|
+
);
|
|
696
|
+
const synthesized = contents.map((c) => `// ============= From: ${c.path} =============
|
|
697
|
+
${c.content}`).join("\n\n");
|
|
698
|
+
if (args.preview) {
|
|
699
|
+
return {
|
|
700
|
+
content: [
|
|
701
|
+
{
|
|
702
|
+
type: "text",
|
|
703
|
+
text: JSON.stringify(
|
|
704
|
+
{
|
|
705
|
+
preview: true,
|
|
706
|
+
inputFiles: filePaths.length,
|
|
707
|
+
outputPath,
|
|
708
|
+
combinedSize: synthesized.length,
|
|
709
|
+
previewLines: synthesized.split("\n").slice(0, 20).join("\n") + "\n..."
|
|
710
|
+
},
|
|
711
|
+
null,
|
|
712
|
+
2
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
]
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
await ensureDirectoryExists(outputPath);
|
|
719
|
+
await writeFile(outputPath, synthesized);
|
|
720
|
+
await reindexFiles(this.context, [outputPath], "synthesize-index");
|
|
721
|
+
return buildSuccessResponse({
|
|
722
|
+
success: true,
|
|
723
|
+
inputFiles: filePaths.length,
|
|
724
|
+
outputPath,
|
|
725
|
+
indexed: true
|
|
726
|
+
});
|
|
727
|
+
} catch (error) {
|
|
728
|
+
const err = toError(error);
|
|
729
|
+
return buildErrorResponse(err);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
var CreateFileSchema = z.object({
|
|
734
|
+
filePath: z.string(),
|
|
735
|
+
content: z.string(),
|
|
736
|
+
projectPath: projectPathParam,
|
|
737
|
+
overwrite: z.boolean().optional().default(false)
|
|
738
|
+
});
|
|
739
|
+
var CreateFileToolHandler = class extends BaseToolHandler {
|
|
740
|
+
parseArgs(args) {
|
|
741
|
+
return CreateFileSchema.parse(args);
|
|
742
|
+
}
|
|
743
|
+
async execute(args) {
|
|
744
|
+
const { writeFile, existsSync } = await import('./file-ops-NCYUEOBU.js');
|
|
745
|
+
const filePath = this.context.normalizeInputPath(args.filePath) || args.filePath;
|
|
746
|
+
const semanticSearch = await setupSemanticSearch(this.context);
|
|
747
|
+
try {
|
|
748
|
+
if (!args.overwrite && existsSync(filePath)) {
|
|
749
|
+
return buildErrorResponse("File already exists", {
|
|
750
|
+
path: filePath,
|
|
751
|
+
hint: "Use overwrite: true to replace"
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
await ensureDirectoryExists(filePath);
|
|
755
|
+
await writeFile(filePath, args.content);
|
|
756
|
+
await reindexFiles(this.context, [filePath], "create-index");
|
|
757
|
+
const response = {
|
|
758
|
+
success: true,
|
|
759
|
+
path: filePath,
|
|
760
|
+
size: args.content.length,
|
|
761
|
+
indexed: true
|
|
762
|
+
};
|
|
763
|
+
if (semanticSearch) {
|
|
764
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
765
|
+
const impactAnalyzer = new ImpactAnalyzer(storage, semanticSearch);
|
|
766
|
+
try {
|
|
767
|
+
const newEntities = await storage.findEntities({
|
|
768
|
+
filters: { filePath },
|
|
769
|
+
limit: 10
|
|
770
|
+
});
|
|
771
|
+
const entityNames = newEntities.map((e) => e.name);
|
|
772
|
+
if (entityNames.length > 0) {
|
|
773
|
+
const impact = await impactAnalyzer.analyzeNewFileImpact(filePath, entityNames);
|
|
774
|
+
const formattedImpact = formatImpactForResponse(impact);
|
|
775
|
+
if (formattedImpact) {
|
|
776
|
+
response["impactAnalysis"] = formattedImpact;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
} catch {
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
content: [
|
|
784
|
+
{
|
|
785
|
+
type: "text",
|
|
786
|
+
text: JSON.stringify(response, null, 2)
|
|
787
|
+
}
|
|
788
|
+
]
|
|
789
|
+
};
|
|
790
|
+
} catch (error) {
|
|
791
|
+
const err = toError(error);
|
|
792
|
+
return {
|
|
793
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
var RenameSymbolSchema = z.object({
|
|
799
|
+
entityId: z.string().optional(),
|
|
800
|
+
entityName: z.string().optional(),
|
|
801
|
+
projectPath: projectPathParam,
|
|
802
|
+
newName: z.string(),
|
|
803
|
+
preview: z.boolean().optional().default(true)
|
|
804
|
+
});
|
|
805
|
+
var RenameSymbolToolHandler = class extends BaseToolHandler {
|
|
806
|
+
parseArgs(args) {
|
|
807
|
+
return RenameSymbolSchema.parse(args);
|
|
808
|
+
}
|
|
809
|
+
async execute(args) {
|
|
810
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
811
|
+
const impactAnalyzer = new ImpactAnalyzer(storage);
|
|
812
|
+
let entity = null;
|
|
813
|
+
if (args.entityId) {
|
|
814
|
+
entity = await storage.getEntity(args.entityId);
|
|
815
|
+
} else if (args.entityName) {
|
|
816
|
+
const entities = await storage.findEntities({
|
|
817
|
+
filters: { name: args.entityName },
|
|
818
|
+
limit: 1
|
|
819
|
+
});
|
|
820
|
+
if (entities.length > 0 && entities[0]) entity = entities[0];
|
|
821
|
+
}
|
|
822
|
+
if (!entity) {
|
|
823
|
+
return {
|
|
824
|
+
content: [{ type: "text", text: JSON.stringify({ error: "Entity not found" }) }]
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
const [relationships, impactResult] = await Promise.all([
|
|
828
|
+
storage.getRelationshipsForEntity(entity.id),
|
|
829
|
+
impactAnalyzer.analyzeRenameImpact(entity.id, entity.name, args.newName).catch(() => null)
|
|
830
|
+
]);
|
|
831
|
+
const references = relationships.filter(
|
|
832
|
+
(r) => r.type === "references" /* REFERENCES */ || r.type === "calls" /* CALLS */
|
|
833
|
+
);
|
|
834
|
+
const filesToUpdate = /* @__PURE__ */ new Set();
|
|
835
|
+
filesToUpdate.add(entity.filePath);
|
|
836
|
+
for (const ref of references) {
|
|
837
|
+
const refEntity = await storage.getEntity(ref.fromId === entity.id ? ref.toId : ref.fromId);
|
|
838
|
+
if (refEntity?.filePath) {
|
|
839
|
+
filesToUpdate.add(refEntity.filePath);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
const impactInfo = impactResult ? formatImpactForResponse(impactResult) : null;
|
|
843
|
+
if (args.preview) {
|
|
844
|
+
const response = {
|
|
845
|
+
preview: true,
|
|
846
|
+
entity: {
|
|
847
|
+
id: entity.id,
|
|
848
|
+
name: entity.name,
|
|
849
|
+
type: entity.type,
|
|
850
|
+
filePath: entity.filePath
|
|
851
|
+
},
|
|
852
|
+
newName: args.newName,
|
|
853
|
+
referencesFound: references.length,
|
|
854
|
+
filesToUpdate: Array.from(filesToUpdate)
|
|
855
|
+
};
|
|
856
|
+
if (impactInfo) {
|
|
857
|
+
response["impactAnalysis"] = impactInfo;
|
|
858
|
+
}
|
|
859
|
+
return {
|
|
860
|
+
content: [
|
|
861
|
+
{
|
|
862
|
+
type: "text",
|
|
863
|
+
text: JSON.stringify(response, null, 2)
|
|
864
|
+
}
|
|
865
|
+
]
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
const { readText, writeFile } = await import('./file-ops-NCYUEOBU.js');
|
|
870
|
+
for (const fp of filesToUpdate) {
|
|
871
|
+
let content = await readText(fp);
|
|
872
|
+
const regex = new RegExp(`\\b${entity.name}\\b`, "g");
|
|
873
|
+
content = content.replace(regex, args.newName);
|
|
874
|
+
await writeFile(fp, content);
|
|
875
|
+
}
|
|
876
|
+
await storage.updateEntity(entity.id, { name: args.newName });
|
|
877
|
+
await reindexFiles(this.context, Array.from(filesToUpdate), "rename-reindex");
|
|
878
|
+
const response = {
|
|
879
|
+
success: true,
|
|
880
|
+
oldName: entity.name,
|
|
881
|
+
newName: args.newName,
|
|
882
|
+
filesUpdated: filesToUpdate.size,
|
|
883
|
+
referencesUpdated: references.length
|
|
884
|
+
};
|
|
885
|
+
if (impactInfo) {
|
|
886
|
+
response["impactAnalysis"] = impactInfo;
|
|
887
|
+
}
|
|
888
|
+
return {
|
|
889
|
+
content: [
|
|
890
|
+
{
|
|
891
|
+
type: "text",
|
|
892
|
+
text: JSON.stringify(response, null, 2)
|
|
893
|
+
}
|
|
894
|
+
]
|
|
895
|
+
};
|
|
896
|
+
} catch (error) {
|
|
897
|
+
const err = toError(error);
|
|
898
|
+
return {
|
|
899
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
var AddMemberSchema = z.object({
|
|
905
|
+
targetEntityId: z.string().optional(),
|
|
906
|
+
targetEntityName: z.string().optional(),
|
|
907
|
+
projectPath: projectPathParam,
|
|
908
|
+
memberCode: z.string(),
|
|
909
|
+
position: z.enum(["start", "end", "after"]).optional().default("end"),
|
|
910
|
+
afterMember: z.string().optional(),
|
|
911
|
+
preview: z.boolean().optional().default(true)
|
|
912
|
+
});
|
|
913
|
+
var AddMemberToolHandler = class extends BaseToolHandler {
|
|
914
|
+
parseArgs(args) {
|
|
915
|
+
return AddMemberSchema.parse(args);
|
|
916
|
+
}
|
|
917
|
+
async execute(args) {
|
|
918
|
+
const storage = await this.ensureGraphStorageForProject(args.projectPath);
|
|
919
|
+
const impactAnalyzer = new ImpactAnalyzer(storage);
|
|
920
|
+
let entity = null;
|
|
921
|
+
if (args.targetEntityId) {
|
|
922
|
+
entity = await storage.getEntity(args.targetEntityId);
|
|
923
|
+
} else if (args.targetEntityName) {
|
|
924
|
+
const entities = await storage.findEntities({
|
|
925
|
+
filters: { name: args.targetEntityName },
|
|
926
|
+
limit: 1
|
|
927
|
+
});
|
|
928
|
+
if (entities.length > 0 && entities[0]) entity = entities[0];
|
|
929
|
+
}
|
|
930
|
+
if (!entity) {
|
|
931
|
+
return {
|
|
932
|
+
content: [{ type: "text", text: JSON.stringify({ error: "Target entity not found" }) }]
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
const validTypes = ["class", "interface", "struct", "enum", "module", "object"];
|
|
936
|
+
if (!validTypes.some((t) => entity.type.toLowerCase().includes(t))) {
|
|
937
|
+
return {
|
|
938
|
+
content: [
|
|
939
|
+
{
|
|
940
|
+
type: "text",
|
|
941
|
+
text: JSON.stringify({
|
|
942
|
+
error: "Invalid target type",
|
|
943
|
+
entityType: entity.type,
|
|
944
|
+
hint: "Target must be a class, interface, struct, enum, or module"
|
|
945
|
+
})
|
|
946
|
+
}
|
|
947
|
+
]
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
if (args.preview) {
|
|
951
|
+
return {
|
|
952
|
+
content: [
|
|
953
|
+
{
|
|
954
|
+
type: "text",
|
|
955
|
+
text: JSON.stringify(
|
|
956
|
+
{
|
|
957
|
+
preview: true,
|
|
958
|
+
target: {
|
|
959
|
+
id: entity.id,
|
|
960
|
+
name: entity.name,
|
|
961
|
+
type: entity.type,
|
|
962
|
+
filePath: entity.filePath
|
|
963
|
+
},
|
|
964
|
+
memberCode: args.memberCode,
|
|
965
|
+
position: args.position
|
|
966
|
+
},
|
|
967
|
+
null,
|
|
968
|
+
2
|
|
969
|
+
)
|
|
970
|
+
}
|
|
971
|
+
]
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
try {
|
|
975
|
+
const { readText, writeFile } = await import('./file-ops-NCYUEOBU.js');
|
|
976
|
+
let content = await readText(entity.filePath);
|
|
977
|
+
const location = entity.location;
|
|
978
|
+
if (!location?.end?.line) {
|
|
979
|
+
return {
|
|
980
|
+
content: [{ type: "text", text: JSON.stringify({ error: "Entity location not available" }) }]
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
const lines = content.split("\n");
|
|
984
|
+
const insertLine = location.end.line - 1;
|
|
985
|
+
const startLine = location.start?.line ? location.start.line - 1 : 0;
|
|
986
|
+
const entityIndent = lines[startLine]?.match(/^(\s*)/)?.[1] || "";
|
|
987
|
+
const memberIndent = entityIndent + " ";
|
|
988
|
+
const indentedMember = args.memberCode.split("\n").map((line) => memberIndent + line).join("\n");
|
|
989
|
+
lines.splice(insertLine, 0, "", indentedMember);
|
|
990
|
+
content = lines.join("\n");
|
|
991
|
+
await writeFile(entity.filePath, content);
|
|
992
|
+
await reindexFiles(this.context, [entity.filePath], "add-member-index");
|
|
993
|
+
const response = {
|
|
994
|
+
success: true,
|
|
995
|
+
target: entity.name,
|
|
996
|
+
memberAdded: true,
|
|
997
|
+
filePath: entity.filePath,
|
|
998
|
+
indexed: true
|
|
999
|
+
};
|
|
1000
|
+
try {
|
|
1001
|
+
const impact = await impactAnalyzer.analyzeModificationImpact(entity.id);
|
|
1002
|
+
const formattedImpact = formatImpactForResponse(impact);
|
|
1003
|
+
if (formattedImpact) {
|
|
1004
|
+
response["impactAnalysis"] = formattedImpact;
|
|
1005
|
+
}
|
|
1006
|
+
} catch {
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
content: [
|
|
1010
|
+
{
|
|
1011
|
+
type: "text",
|
|
1012
|
+
text: JSON.stringify(response, null, 2)
|
|
1013
|
+
}
|
|
1014
|
+
]
|
|
1015
|
+
};
|
|
1016
|
+
} catch (error) {
|
|
1017
|
+
const err = toError(error);
|
|
1018
|
+
return {
|
|
1019
|
+
content: [{ type: "text", text: JSON.stringify({ error: err.message }) }]
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
|
|
1025
|
+
export { AddMemberToolHandler, CopyFileToolHandler, CreateFileToolHandler, ModifyEntityCodeToolHandler, RenameFileToolHandler, RenameSymbolToolHandler, SplitFileToolHandler, SynthesizeFilesToolHandler };
|
|
1026
|
+
//# sourceMappingURL=file-tool-handlers-V4SFUDQB.js.map
|
|
1027
|
+
//# sourceMappingURL=file-tool-handlers-V4SFUDQB.js.map
|