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.
Files changed (151) hide show
  1. package/dist/chunks/analysis-tool-handlers-GH5FDEWW.js +817 -0
  2. package/dist/chunks/analysis-tool-handlers-IXP4MWZX.js +817 -0
  3. package/dist/chunks/analysis-tool-handlers-LC2BTQYK.js +13 -0
  4. package/dist/chunks/analysis-tool-handlers-QYFKQPFL.js +817 -0
  5. package/dist/chunks/autodoc-tool-handlers-2HF6ERYN.js +1112 -0
  6. package/dist/chunks/autodoc-tool-handlers-4OGQJ7C3.js +1112 -0
  7. package/dist/chunks/autodoc-tool-handlers-N736CB56.js +138 -0
  8. package/dist/chunks/autodoc-tool-handlers-NQYBY6U4.js +1112 -0
  9. package/dist/chunks/branch-tool-handlers-KW3H4FJK.js +276 -0
  10. package/dist/chunks/branch-tool-handlers-QOUDZKJ2.js +276 -0
  11. package/dist/chunks/branch-tool-handlers-RB2U36KI.js +2 -0
  12. package/dist/chunks/branch-tool-handlers-ZHJM6PDK.js +276 -0
  13. package/dist/chunks/chunk-2Z6OQPYC.js +656 -0
  14. package/dist/chunks/chunk-3MQ7LRPN.js +322 -0
  15. package/dist/chunks/chunk-4W6QYGXZ.js +10 -0
  16. package/dist/chunks/chunk-533NFGUG.js +1 -0
  17. package/dist/chunks/chunk-5NUPOPWM.js +1 -0
  18. package/dist/chunks/chunk-AK4HIPA2.js +322 -0
  19. package/dist/chunks/chunk-B3H5NS3I.js +656 -0
  20. package/dist/chunks/chunk-DPTZHDST.js +4 -0
  21. package/dist/chunks/chunk-E5HQWLU5.js +322 -0
  22. package/dist/chunks/chunk-EOH25B5P.js +572 -0
  23. package/dist/chunks/chunk-ESV6F6E3.js +3179 -0
  24. package/dist/chunks/chunk-FPELPFER.js +924 -0
  25. package/dist/chunks/chunk-G6J42I55.js +161 -0
  26. package/dist/chunks/chunk-GCQE7ZYW.js +1 -0
  27. package/dist/chunks/chunk-GTIF6MOX.js +1 -0
  28. package/dist/chunks/chunk-I6STSSAK.js +2 -0
  29. package/dist/chunks/chunk-J2WBGTK2.js +4697 -0
  30. package/dist/chunks/chunk-KAYOX5EB.js +4697 -0
  31. package/dist/chunks/chunk-KPMTACOT.js +656 -0
  32. package/dist/chunks/chunk-L376GZ44.js +3179 -0
  33. package/dist/chunks/chunk-LCTOTHDA.js +15 -0
  34. package/dist/chunks/chunk-LEDJ7GVQ.js +316 -0
  35. package/dist/chunks/chunk-LH4OUKNZ.js +277 -0
  36. package/dist/chunks/chunk-O6IE2MEZ.js +161 -0
  37. package/dist/chunks/chunk-OEXPCY3F.js +316 -0
  38. package/dist/chunks/chunk-OMXOLFDN.js +924 -0
  39. package/dist/chunks/chunk-PLPBXWOU.js +3179 -0
  40. package/dist/chunks/chunk-PWLE5DN2.js +572 -0
  41. package/dist/chunks/chunk-PY43JPWL.js +447 -0
  42. package/dist/chunks/chunk-Q3B4EB7A.js +15 -0
  43. package/dist/chunks/chunk-Q5LPVLXA.js +337 -0
  44. package/dist/chunks/chunk-QIRZHZK2.js +5 -0
  45. package/dist/chunks/chunk-ROQ27LSL.js +924 -0
  46. package/dist/chunks/chunk-S5Q7BD6J.js +572 -0
  47. package/dist/chunks/chunk-SAMX3HJQ.js +337 -0
  48. package/dist/chunks/chunk-SV3WKUNV.js +1 -0
  49. package/dist/chunks/chunk-TCHCDCDO.js +167 -0
  50. package/dist/chunks/chunk-TR3HS7U6.js +316 -0
  51. package/dist/chunks/chunk-TUWE6FCW.js +167 -0
  52. package/dist/chunks/chunk-TVOTA7EE.js +277 -0
  53. package/dist/chunks/chunk-VS44D772.js +337 -0
  54. package/dist/chunks/chunk-WIE3G5ES.js +167 -0
  55. package/dist/chunks/chunk-XG3ACLWR.js +5 -0
  56. package/dist/chunks/chunk-XJ2Z5QQO.js +1 -0
  57. package/dist/chunks/chunk-XK2NY7RB.js +277 -0
  58. package/dist/chunks/chunk-Y4F7NZFZ.js +4700 -0
  59. package/dist/chunks/chunk-YS75L3ZS.js +161 -0
  60. package/dist/chunks/chunk-ZVG5HHI3.js +15 -0
  61. package/dist/chunks/dev-agent-DDDIVWOF.js +1 -0
  62. package/dist/chunks/dev-agent-E2VCFKXN.js +1624 -0
  63. package/dist/chunks/dev-agent-KJNSU5KQ.js +1624 -0
  64. package/dist/chunks/dev-agent-NDERYIPV.js +1624 -0
  65. package/dist/chunks/faiss-provider-7R4BQDIV.js +12 -0
  66. package/dist/chunks/faiss-provider-7ZFRSDN5.js +12 -0
  67. package/dist/chunks/faiss-provider-SXB7FTLB.js +1 -0
  68. package/dist/chunks/faiss-provider-TKLBEUSH.js +12 -0
  69. package/dist/chunks/file-tool-handlers-5DODQXGF.js +1027 -0
  70. package/dist/chunks/file-tool-handlers-KGHLE4KR.js +1027 -0
  71. package/dist/chunks/file-tool-handlers-KTOQ4NFS.js +12 -0
  72. package/dist/chunks/file-tool-handlers-V4SFUDQB.js +1027 -0
  73. package/dist/chunks/graph-metrics-tool-handlers-3AV4X4ZY.js +65 -0
  74. package/dist/chunks/graph-metrics-tool-handlers-3VMDQHJ6.js +65 -0
  75. package/dist/chunks/graph-metrics-tool-handlers-BZ6E6YHF.js +1 -0
  76. package/dist/chunks/graph-metrics-tool-handlers-IYBGSXL7.js +65 -0
  77. package/dist/chunks/graph-storage-factory-2CQ2RPDV.js +13 -0
  78. package/dist/chunks/graph-storage-factory-C5SMMYL6.js +13 -0
  79. package/dist/chunks/graph-storage-factory-EEO2V3GJ.js +1 -0
  80. package/dist/chunks/graph-storage-factory-WBCTXP34.js +13 -0
  81. package/dist/chunks/history-tool-handlers-AS7OQFZI.js +1 -0
  82. package/dist/chunks/history-tool-handlers-FSNJYXV2.js +208 -0
  83. package/dist/chunks/history-tool-handlers-JZAH4EIQ.js +208 -0
  84. package/dist/chunks/history-tool-handlers-KCSCXZ7T.js +208 -0
  85. package/dist/chunks/incremental-updater-A2EL4QXU.js +14 -0
  86. package/dist/chunks/incremental-updater-EQIKBVY2.js +14 -0
  87. package/dist/chunks/incremental-updater-JFGRPH3B.js +14 -0
  88. package/dist/chunks/incremental-updater-S5BAAGHP.js +1 -0
  89. package/dist/chunks/indexer-agent-ASKY7JPG.js +1 -0
  90. package/dist/chunks/indexer-agent-NKAOF323.js +21 -0
  91. package/dist/chunks/indexer-agent-PJN5IOKQ.js +21 -0
  92. package/dist/chunks/indexer-agent-WRJFWKZX.js +21 -0
  93. package/dist/chunks/indexing-pipeline-D4P2O72Z.js +249 -0
  94. package/dist/chunks/indexing-pipeline-L7C543N4.js +1 -0
  95. package/dist/chunks/indexing-pipeline-NHPRN3AB.js +249 -0
  96. package/dist/chunks/indexing-pipeline-ZAXCZU22.js +249 -0
  97. package/dist/chunks/layered-faiss-provider-62CNW54X.js +1 -0
  98. package/dist/chunks/layered-faiss-provider-O7L77GFX.js +12 -0
  99. package/dist/chunks/layered-faiss-provider-RVHLHLPK.js +12 -0
  100. package/dist/chunks/layered-faiss-provider-YT7EDIJI.js +12 -0
  101. package/dist/chunks/merge-agent-3RF7VFF5.js +2481 -0
  102. package/dist/chunks/merge-agent-JCKTCBCE.js +2481 -0
  103. package/dist/chunks/merge-agent-VCL7OXPN.js +2481 -0
  104. package/dist/chunks/merge-agent-ZGK24WVF.js +11 -0
  105. package/dist/chunks/merge-tool-handlers-GV2LOIKU.js +277 -0
  106. package/dist/chunks/merge-tool-handlers-TYDWU5X2.js +277 -0
  107. package/dist/chunks/merge-tool-handlers-U7X2ZO2M.js +1 -0
  108. package/dist/chunks/merge-tool-handlers-YH62ZLPJ.js +277 -0
  109. package/dist/chunks/pattern-tool-handlers-76NF5JDS.js +13 -0
  110. package/dist/chunks/pattern-tool-handlers-IJAGEIVD.js +1549 -0
  111. package/dist/chunks/pattern-tool-handlers-VA5WYA62.js +1549 -0
  112. package/dist/chunks/pattern-tool-handlers-WQ6UBMJS.js +1549 -0
  113. package/dist/chunks/query-agent-36ADGCFZ.js +1 -0
  114. package/dist/chunks/query-agent-H22CR5N5.js +191 -0
  115. package/dist/chunks/query-agent-K2UGZS4M.js +191 -0
  116. package/dist/chunks/query-agent-YJCEHOXD.js +191 -0
  117. package/dist/chunks/semantic-agent-AC7CBEDE.js +6381 -0
  118. package/dist/chunks/semantic-agent-HK5X6CKU.js +6381 -0
  119. package/dist/chunks/semantic-agent-KONIKEGW.js +6381 -0
  120. package/dist/chunks/semantic-agent-LH6IZ2L7.js +137 -0
  121. package/dist/chunks/semantic-tool-handlers-5LMSH2U7.js +3 -0
  122. package/dist/chunks/semantic-tool-handlers-735UMO7Y.js +817 -0
  123. package/dist/chunks/semantic-tool-handlers-BNUYPP7X.js +817 -0
  124. package/dist/chunks/semantic-tool-handlers-MYZPEUD2.js +817 -0
  125. package/dist/chunks/snapshot-tool-handlers-6SIHZT2F.js +201 -0
  126. package/dist/chunks/snapshot-tool-handlers-DS4P3KOT.js +201 -0
  127. package/dist/chunks/snapshot-tool-handlers-JYHRFPC7.js +201 -0
  128. package/dist/chunks/snapshot-tool-handlers-YEHMAT3L.js +1 -0
  129. package/dist/chunks/storage-paths-A3C7WHHG.js +8 -0
  130. package/dist/chunks/storage-paths-HDYH7WPM.js +1 -0
  131. package/dist/chunks/storage-paths-IMFRHBWF.js +8 -0
  132. package/dist/chunks/storage-paths-P3PUSMUD.js +8 -0
  133. package/dist/chunks/taint-tool-handlers-CWESOOMQ.js +68 -0
  134. package/dist/chunks/taint-tool-handlers-OG3NVVP3.js +1 -0
  135. package/dist/chunks/taint-tool-handlers-ON3G3FA7.js +68 -0
  136. package/dist/chunks/taint-tool-handlers-P4P5J6DB.js +68 -0
  137. package/dist/chunks/tracing-tool-handlers-4BDCXTZZ.js +3935 -0
  138. package/dist/chunks/tracing-tool-handlers-6FPNM7HX.js +3935 -0
  139. package/dist/chunks/tracing-tool-handlers-LQTQ5SKK.js +89 -0
  140. package/dist/chunks/tracing-tool-handlers-XRQX2DTS.js +3935 -0
  141. package/dist/chunks/validation-tool-handlers-DZUG7KYY.js +2 -0
  142. package/dist/chunks/validation-tool-handlers-O6TGFSH5.js +555 -0
  143. package/dist/chunks/validation-tool-handlers-RREUYKIR.js +555 -0
  144. package/dist/chunks/validation-tool-handlers-XPWSMS37.js +555 -0
  145. package/dist/index.js +13 -13
  146. package/dist/roslyn-addon/.build-hash +1 -1
  147. package/dist/roslyn-addon/ILGPU.Algorithms.dll +0 -0
  148. package/dist/roslyn-addon/ILGPU.dll +0 -0
  149. package/dist/roslyn-addon/UltraCode.CSharp.deps.json +35 -0
  150. package/dist/roslyn-addon/UltraCode.CSharp.dll +0 -0
  151. package/package.json +1 -1
@@ -0,0 +1,817 @@
1
+ import { DetectCodeClonesSchema } from './chunk-RAGUL4TA.js';
2
+ import { projectPathParam } from './chunk-NJUB245U.js';
3
+ import { SAFE_LIMITS, BaseToolHandler, MAX_PAGE_SIZE, paginate } from './chunk-Q5LPVLXA.js';
4
+ import './chunk-TCHCDCDO.js';
5
+ import './chunk-LH4OUKNZ.js';
6
+ import './chunk-HEMJHRHZ.js';
7
+ import { toError } from './chunk-5WKPA33T.js';
8
+ import { init_logging, log } from './chunk-VCCBEJQ5.js';
9
+ import './chunk-NAQKA54E.js';
10
+ import { readFileSync } from 'fs';
11
+ import { z } from 'zod';
12
+
13
+ // src/tools/handlers/semantic-tool-handlers.ts
14
+ init_logging();
15
+ var CONTENT_TOKEN_LIMIT = 8e3;
16
+ var CHARS_PER_TOKEN = 4;
17
+ function loadSourceCode(filePath, startLine, endLine) {
18
+ if (!filePath || !startLine || !endLine) return void 0;
19
+ try {
20
+ const content = readFileSync(filePath, "utf-8");
21
+ const lines = content.split("\n");
22
+ const start = Math.max(0, startLine - 1);
23
+ const end = Math.min(lines.length, endLine);
24
+ return lines.slice(start, end).join("\n");
25
+ } catch {
26
+ return void 0;
27
+ }
28
+ }
29
+ function estimateTokens(text) {
30
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
31
+ }
32
+ function applyContentPagination(results, includeContent) {
33
+ if (!includeContent || results.length === 0) {
34
+ return { results };
35
+ }
36
+ let tokensUsed = 0;
37
+ let includedCount = 0;
38
+ const paginatedResults = [];
39
+ for (const result of results) {
40
+ const content = result.content;
41
+ if (content) {
42
+ const contentTokens = estimateTokens(content);
43
+ if (tokensUsed + contentTokens > CONTENT_TOKEN_LIMIT && includedCount > 0) {
44
+ paginatedResults.push({ ...result, content: void 0 });
45
+ } else {
46
+ tokensUsed += contentTokens;
47
+ includedCount++;
48
+ paginatedResults.push(result);
49
+ }
50
+ } else {
51
+ paginatedResults.push(result);
52
+ }
53
+ }
54
+ const hasMore = includedCount < results.filter((r) => r.content).length;
55
+ return {
56
+ results: paginatedResults,
57
+ ...hasMore ? {
58
+ contentPagination: {
59
+ includedCount,
60
+ totalCount: results.length,
61
+ tokensUsed,
62
+ tokenLimit: CONTENT_TOKEN_LIMIT,
63
+ hasMore,
64
+ message: `Content included for ${includedCount} of ${results.length} results (~${tokensUsed} tokens). Use offset to see more.`
65
+ }
66
+ } : {}
67
+ };
68
+ }
69
+ var SemanticSearchSchema = z.object({
70
+ query: z.string().describe("Natural language search query"),
71
+ projectPath: projectPathParam,
72
+ offset: z.number().optional().default(0),
73
+ limit: z.number().optional().default(SAFE_LIMITS.searchResults),
74
+ entityTypes: z.array(z.string()).optional().describe("Filter by entity types (function, class, interface, etc.)"),
75
+ minSimilarity: z.number().optional().default(0.7).describe("Minimum similarity threshold (0.0-1.0)"),
76
+ includeContent: z.boolean().optional().default(false).describe("Include full source code (startLine to endLine) in results"),
77
+ expandRelated: z.boolean().optional().default(false).describe("Expand results with graph neighbors (callers, dependencies, inheritors)"),
78
+ expansionDepth: z.number().optional().default(1).describe("Graph traversal depth for expansion (1 or 2 hops)"),
79
+ // Two-stage retrieval with reranking
80
+ rerank: z.boolean().optional().default(false).describe(
81
+ "Enable two-stage retrieval: rerank top results with cross-encoder for better precision (requires vLLM or TEI provider)"
82
+ ),
83
+ rerankTopK: z.number().optional().default(50).describe("Number of top embedding results to rerank (default: 50)"),
84
+ // New filters based on parser-extracted data
85
+ minCyclomatic: z.number().optional().describe("Filter: minimum cyclomatic complexity"),
86
+ maxCyclomatic: z.number().optional().describe("Filter: maximum cyclomatic complexity"),
87
+ hasExceptions: z.boolean().optional().describe("Filter: must have try-catch blocks"),
88
+ hasLoops: z.boolean().optional().describe("Filter: must have loops"),
89
+ hasAwaits: z.boolean().optional().describe("Filter: must have await expressions (async code)"),
90
+ hasDocumentation: z.boolean().optional().describe("Filter: must have documentation/docstrings"),
91
+ isDeprecated: z.boolean().optional().describe("Filter: deprecated entities only"),
92
+ minCallCount: z.number().optional().describe("Filter: minimum number of function calls"),
93
+ // History filters (Prolly Tree)
94
+ changedInLastCommits: z.number().optional().describe("Filter: only entities changed in last N graph commits (Prolly Tree)"),
95
+ changedSinceMs: z.number().optional().describe("Filter: only entities changed since this Unix timestamp (ms)")
96
+ });
97
+ var SemanticSearchToolHandler = class extends BaseToolHandler {
98
+ parseArgs(args) {
99
+ return SemanticSearchSchema.parse(args);
100
+ }
101
+ async execute(args) {
102
+ const resolvedPath = this.resolveProjectPath(args);
103
+ const currentProject = this.getProjectContext().getCurrentProject();
104
+ log.d("SEMSEARCH", "proj_paths", { arg: args.projectPath, resolved: resolvedPath, current: currentProject });
105
+ if (args.projectPath && resolvedPath !== currentProject) {
106
+ if (!this.isProjectIndexed(resolvedPath)) {
107
+ return {
108
+ content: [
109
+ {
110
+ type: "text",
111
+ text: JSON.stringify(
112
+ {
113
+ success: false,
114
+ error: `Project not indexed: ${resolvedPath}`,
115
+ hint: "Run 'index' tool on the target directory first",
116
+ currentProject,
117
+ requestedProject: resolvedPath
118
+ },
119
+ null,
120
+ 2
121
+ )
122
+ }
123
+ ]
124
+ };
125
+ }
126
+ log.w("SEMSEARCH", "cross_proj", { current: currentProject, requested: resolvedPath });
127
+ }
128
+ const semanticAgent = await this.ensureSemanticAgentForProject(resolvedPath);
129
+ const initError = semanticAgent.getEmbeddingInitError();
130
+ if (initError) {
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: JSON.stringify(
136
+ {
137
+ success: false,
138
+ error: `Embedding provider initialization failed: ${initError.message}`,
139
+ hint: "Check if the configured embedding provider is available (Docker, Ollama, etc.)"
140
+ },
141
+ null,
142
+ 2
143
+ )
144
+ }
145
+ ]
146
+ };
147
+ }
148
+ await this.ensureGraphStorageForProject(resolvedPath);
149
+ const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
150
+ const searchResult = await semanticAgent.semanticSearch(args.query, 1e3);
151
+ let allResults = searchResult.results || [];
152
+ let rerankStats = { reranked: false, provider: "" };
153
+ if (args.rerank && allResults.length > 0) {
154
+ const provider = semanticAgent.getEmbeddingProvider?.();
155
+ const capabilities = provider?.getCapabilities?.();
156
+ if (capabilities?.rerank && provider?.rerank) {
157
+ try {
158
+ const topK = Math.min(args.rerankTopK, allResults.length);
159
+ const toRerank = allResults.slice(0, topK);
160
+ const documents = toRerank.map((r, idx) => ({
161
+ text: r.content || r.metadata?.content || r.name || "",
162
+ id: r.id || String(idx)
163
+ }));
164
+ const reranked = await provider.rerank(args.query, documents, {
165
+ topK,
166
+ threshold: args.minSimilarity
167
+ });
168
+ const rerankedMap = new Map(reranked.map((r) => [r.id, r.score]));
169
+ for (const result of toRerank) {
170
+ const newScore = rerankedMap.get(result.id);
171
+ if (newScore !== void 0) {
172
+ result.similarity = newScore;
173
+ result.reranked = true;
174
+ }
175
+ }
176
+ allResults = [...toRerank, ...allResults.slice(topK)];
177
+ allResults.sort(
178
+ (a, b) => (b.similarity || 0) - (a.similarity || 0)
179
+ );
180
+ rerankStats = { reranked: true, provider: provider.info?.name || "unknown" };
181
+ } catch (error) {
182
+ const err = toError(error);
183
+ log.w("SEMSEARCH", "rerank_fail", { err: err.message });
184
+ }
185
+ }
186
+ }
187
+ let filteredResults = allResults;
188
+ const hasFilters = args.minCyclomatic !== void 0 || args.maxCyclomatic !== void 0 || args.hasExceptions !== void 0 || args.hasLoops !== void 0 || args.hasAwaits !== void 0 || args.hasDocumentation !== void 0 || args.isDeprecated !== void 0 || args.minCallCount !== void 0;
189
+ if (hasFilters) {
190
+ filteredResults = allResults.filter((r) => {
191
+ const meta = r.metadata || {};
192
+ if (args.minCyclomatic !== void 0 && (meta.cyclomatic || 0) < args.minCyclomatic) return false;
193
+ if (args.maxCyclomatic !== void 0 && (meta.cyclomatic || Infinity) > args.maxCyclomatic) return false;
194
+ if (args.hasExceptions !== void 0 && meta.hasExceptions !== args.hasExceptions) return false;
195
+ if (args.hasLoops !== void 0 && meta.hasLoops !== args.hasLoops) return false;
196
+ if (args.hasAwaits !== void 0 && meta.hasAwaits !== args.hasAwaits) return false;
197
+ if (args.hasDocumentation !== void 0 && meta.hasDocumentation !== args.hasDocumentation) return false;
198
+ if (args.isDeprecated !== void 0 && meta.isDeprecated !== args.isDeprecated) return false;
199
+ if (args.minCallCount !== void 0 && (meta.callCount || 0) < args.minCallCount) return false;
200
+ return true;
201
+ });
202
+ }
203
+ if (args.changedInLastCommits !== void 0 || args.changedSinceMs !== void 0) {
204
+ const { getRecentlyChangedEntities } = await import('./recently-changed-FX5QR4Z2.js');
205
+ const storage = await this.context.getGraphStorage();
206
+ const adapter = storage.getLibSQLAdapter?.();
207
+ if (adapter) {
208
+ const recentlyChanged = await getRecentlyChangedEntities(adapter, {
209
+ lastCommits: args.changedInLastCommits,
210
+ sinceTimestamp: args.changedSinceMs
211
+ });
212
+ if (recentlyChanged) {
213
+ filteredResults = filteredResults.filter((r) => {
214
+ const entityId = r.metadata?.entityId || r.id?.replace(/^ent:/, "");
215
+ return entityId ? recentlyChanged.changedIds.has(entityId) : false;
216
+ });
217
+ }
218
+ }
219
+ }
220
+ let expandedResults = filteredResults;
221
+ let expansionStats = { expanded: false, neighborsAdded: 0 };
222
+ if (args.expandRelated && filteredResults.length > 0) {
223
+ const expansion = await this.expandWithGraphNeighbors(filteredResults, args.expansionDepth, args.minSimilarity);
224
+ expandedResults = expansion.results;
225
+ expansionStats = { expanded: true, neighborsAdded: expansion.neighborsAdded };
226
+ }
227
+ const paginatedResult = paginate(expandedResults, args.offset, safeLimit);
228
+ const queryExpansion = searchResult.expandedQuery ? {
229
+ expandedQuery: searchResult.expandedQuery,
230
+ ...searchResult.expansionInfo ? {
231
+ coocTerms: searchResult.expansionInfo.coocTerms?.length || 0,
232
+ prfTerms: searchResult.expansionInfo.prfTerms?.length || 0
233
+ } : {}
234
+ } : null;
235
+ const mappedResults = paginatedResult.data.map((r) => {
236
+ const meta = r.metadata || {};
237
+ const filePath = r.filePath || meta.filePath || meta.path;
238
+ const startLine = meta.startLine;
239
+ const endLine = meta.endLine;
240
+ const content = args.includeContent ? loadSourceCode(filePath, startLine, endLine) : void 0;
241
+ return {
242
+ id: r.id,
243
+ name: r.name || meta.name,
244
+ type: r.type || meta.entityType || meta.type,
245
+ similarity: r.similarity,
246
+ ...r.reranked ? { reranked: true } : {},
247
+ filePath,
248
+ startLine,
249
+ endLine,
250
+ language: meta.language,
251
+ // Complexity metrics (if available)
252
+ ...meta.cyclomatic ? {
253
+ complexity: {
254
+ cyclomatic: meta.cyclomatic,
255
+ cognitive: meta.cognitive,
256
+ linesOfCode: meta.linesOfCode,
257
+ nestingDepth: meta.nestingDepth
258
+ }
259
+ } : {},
260
+ // Control flow info (if available)
261
+ ...meta.hasBranches !== void 0 ? {
262
+ controlFlow: {
263
+ hasBranches: meta.hasBranches,
264
+ hasLoops: meta.hasLoops,
265
+ hasExceptions: meta.hasExceptions,
266
+ hasAwaits: meta.hasAwaits,
267
+ branchCount: meta.branchCount,
268
+ loopCount: meta.loopCount,
269
+ returnCount: meta.returnCount
270
+ }
271
+ } : {},
272
+ // Call info (if available)
273
+ ...meta.callCount ? {
274
+ calls: {
275
+ count: meta.callCount,
276
+ hasAsync: meta.hasAsyncCalls
277
+ }
278
+ } : {},
279
+ // Documentation info (if available)
280
+ ...meta.hasDocumentation ? {
281
+ documentation: {
282
+ hasDocumentation: true,
283
+ hasParams: meta.hasParams,
284
+ hasExamples: meta.hasExamples,
285
+ isDeprecated: meta.isDeprecated
286
+ }
287
+ } : {},
288
+ // Type info
289
+ ...meta.returnType ? { returnType: meta.returnType } : {},
290
+ ...meta.paramCount ? { paramCount: meta.paramCount } : {},
291
+ // Expansion info
292
+ ...r.isExpanded ? { isExpanded: true, relationshipType: r.relationshipType } : {},
293
+ // Content (loaded from file)
294
+ ...content ? { content } : {}
295
+ };
296
+ });
297
+ const { results: finalResults, contentPagination } = applyContentPagination(mappedResults, args.includeContent);
298
+ return {
299
+ content: [
300
+ {
301
+ type: "text",
302
+ text: JSON.stringify(
303
+ {
304
+ query: args.query,
305
+ count: finalResults.length,
306
+ pagination: paginatedResult.pagination,
307
+ ...queryExpansion ? { queryExpansion } : {},
308
+ ...rerankStats.reranked ? { rerank: rerankStats } : {},
309
+ ...expansionStats.expanded ? { expansion: expansionStats } : {},
310
+ ...contentPagination ? { contentPagination } : {},
311
+ results: finalResults
312
+ },
313
+ null,
314
+ 2
315
+ )
316
+ }
317
+ ]
318
+ };
319
+ }
320
+ /**
321
+ * Expand search results with graph neighbors (callers, dependencies, inheritors)
322
+ */
323
+ async expandWithGraphNeighbors(results, depth, minSimilarity) {
324
+ const storage = await this.context.getGraphStorage();
325
+ const seen = new Set(results.map((r) => r.id));
326
+ const neighbors = [];
327
+ for (const result of results.slice(0, 20)) {
328
+ let entityId = result.metadata?.entityId;
329
+ if (!entityId && result.metadata?.name && result.metadata?.path) {
330
+ try {
331
+ const found = await storage.findEntities({
332
+ filters: {
333
+ name: result.metadata.name,
334
+ filePath: result.metadata.path
335
+ },
336
+ limit: 1
337
+ });
338
+ if (found.length > 0) {
339
+ entityId = found[0]?.id;
340
+ }
341
+ } catch {
342
+ }
343
+ }
344
+ if (!entityId) continue;
345
+ try {
346
+ const relationships = await storage.getRelationshipsForEntity(entityId);
347
+ for (const rel of relationships) {
348
+ const relatedId = rel.fromId === entityId ? rel.toId : rel.fromId;
349
+ if (seen.has(relatedId) || seen.has(`ent:${relatedId}`)) continue;
350
+ seen.add(relatedId);
351
+ const relatedEntity = await storage.getEntity(relatedId);
352
+ if (!relatedEntity) continue;
353
+ const neighborSimilarity = result.similarity * 0.7;
354
+ if (neighborSimilarity < minSimilarity) continue;
355
+ neighbors.push({
356
+ id: `ent:${relatedId}`,
357
+ name: relatedEntity.name,
358
+ type: relatedEntity.type,
359
+ similarity: neighborSimilarity,
360
+ filePath: relatedEntity.filePath,
361
+ content: relatedEntity.metadata?.["content"],
362
+ isExpanded: true,
363
+ relationshipType: rel.type,
364
+ metadata: { entityId: relatedId }
365
+ });
366
+ }
367
+ if (depth >= 2 && neighbors.length < 50) {
368
+ for (const neighbor of neighbors.slice(-10)) {
369
+ const neighborEntityId = neighbor.id?.replace(/^ent:/, "");
370
+ if (!neighborEntityId) continue;
371
+ try {
372
+ const hop2Rels = await storage.getRelationshipsForEntity(neighborEntityId);
373
+ for (const rel of hop2Rels.slice(0, 5)) {
374
+ const hop2Id = rel.fromId === neighborEntityId ? rel.toId : rel.fromId;
375
+ if (seen.has(hop2Id) || seen.has(`ent:${hop2Id}`)) continue;
376
+ seen.add(hop2Id);
377
+ const hop2Entity = await storage.getEntity(hop2Id);
378
+ if (!hop2Entity) continue;
379
+ const hop2Similarity = neighbor.similarity * 0.7;
380
+ if (hop2Similarity < minSimilarity) continue;
381
+ neighbors.push({
382
+ id: `ent:${hop2Id}`,
383
+ name: hop2Entity.name,
384
+ type: hop2Entity.type,
385
+ similarity: hop2Similarity,
386
+ filePath: hop2Entity.filePath,
387
+ content: hop2Entity.metadata?.["content"],
388
+ isExpanded: true,
389
+ relationshipType: `${rel.type} (2-hop)`,
390
+ metadata: { entityId: hop2Id }
391
+ });
392
+ }
393
+ } catch {
394
+ }
395
+ }
396
+ }
397
+ } catch {
398
+ }
399
+ }
400
+ const combined = [...results, ...neighbors];
401
+ combined.sort((a, b) => (b.similarity || 0) - (a.similarity || 0));
402
+ return {
403
+ results: combined,
404
+ neighborsAdded: neighbors.length
405
+ };
406
+ }
407
+ };
408
+ var FindSimilarCodeSchema = z.object({
409
+ code: z.string().describe("Code snippet to find similar code for"),
410
+ projectPath: projectPathParam,
411
+ offset: z.number().optional().default(0),
412
+ limit: z.number().optional().default(SAFE_LIMITS.searchResults),
413
+ minSimilarity: z.number().optional().default(0.7).describe("Minimum similarity threshold (0.0-1.0)"),
414
+ includeContent: z.boolean().optional().default(false).describe("Include full source code (startLine to endLine) in results")
415
+ });
416
+ var FindSimilarCodeToolHandler = class extends BaseToolHandler {
417
+ parseArgs(args) {
418
+ return FindSimilarCodeSchema.parse(args);
419
+ }
420
+ async execute(args) {
421
+ const resolvedPath = this.resolveProjectPath(args);
422
+ const semanticAgent = await this.ensureSemanticAgentForProject(resolvedPath);
423
+ const initError = semanticAgent.getEmbeddingInitError();
424
+ if (initError) {
425
+ return {
426
+ content: [
427
+ {
428
+ type: "text",
429
+ text: JSON.stringify(
430
+ {
431
+ success: false,
432
+ error: `Embedding provider initialization failed: ${initError.message}`,
433
+ hint: "Check if the configured embedding provider is available (Docker, Ollama, etc.)"
434
+ },
435
+ null,
436
+ 2
437
+ )
438
+ }
439
+ ]
440
+ };
441
+ }
442
+ const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
443
+ const allResults = await semanticAgent.findSimilarCode(args.code, args.minSimilarity);
444
+ const paginatedResult = paginate(allResults, args.offset, safeLimit);
445
+ const mappedResults = paginatedResult.data.map((r) => {
446
+ const filePath = r.filePath || r.metadata?.path;
447
+ const startLine = r.metadata?.startLine;
448
+ const endLine = r.metadata?.endLine;
449
+ const content = args.includeContent ? loadSourceCode(filePath, startLine, endLine) : void 0;
450
+ return {
451
+ id: r.id,
452
+ name: r.name,
453
+ type: r.type,
454
+ similarity: r.similarity,
455
+ filePath,
456
+ startLine,
457
+ endLine,
458
+ ...content ? { content } : {}
459
+ };
460
+ });
461
+ const { results: finalResults, contentPagination } = applyContentPagination(mappedResults, args.includeContent);
462
+ return {
463
+ content: [
464
+ {
465
+ type: "text",
466
+ text: JSON.stringify(
467
+ {
468
+ count: finalResults.length,
469
+ pagination: paginatedResult.pagination,
470
+ ...contentPagination ? { contentPagination } : {},
471
+ results: finalResults
472
+ },
473
+ null,
474
+ 2
475
+ )
476
+ }
477
+ ]
478
+ };
479
+ }
480
+ };
481
+ var DetectCodeClonesToolHandler = class extends BaseToolHandler {
482
+ parseArgs(args) {
483
+ return DetectCodeClonesSchema.parse(args);
484
+ }
485
+ async execute(args) {
486
+ try {
487
+ const semanticAgent = await this.ensureSemanticAgentForProject();
488
+ const initError = semanticAgent.getEmbeddingInitError();
489
+ if (initError) {
490
+ return {
491
+ content: [
492
+ {
493
+ type: "text",
494
+ text: JSON.stringify(
495
+ {
496
+ success: false,
497
+ error: `Embedding provider initialization failed: ${initError.message}`,
498
+ hint: "Check if the configured embedding provider is available (Docker, Ollama, etc.)"
499
+ },
500
+ null,
501
+ 2
502
+ )
503
+ }
504
+ ]
505
+ };
506
+ }
507
+ const minSimilarity = args.minSimilarity ?? 0.8;
508
+ const allClones = await semanticAgent.detectClones(minSimilarity);
509
+ if (!allClones || !Array.isArray(allClones)) {
510
+ return {
511
+ content: [
512
+ {
513
+ type: "text",
514
+ text: JSON.stringify(
515
+ {
516
+ groupsFound: 0,
517
+ clones: [],
518
+ warning: "Clone detection unavailable - vector store may not be initialized"
519
+ },
520
+ null,
521
+ 2
522
+ )
523
+ }
524
+ ]
525
+ };
526
+ }
527
+ return {
528
+ content: [
529
+ {
530
+ type: "text",
531
+ text: JSON.stringify(
532
+ {
533
+ groupsFound: allClones.length,
534
+ scope: args.scope ?? "all",
535
+ minSimilarity,
536
+ clones: allClones.map((group) => ({
537
+ similarity: group.avgSimilarity,
538
+ cloneType: group.cloneType,
539
+ members: (group.members || []).map((m) => ({
540
+ id: m.id,
541
+ name: m.name,
542
+ filePath: m.path,
543
+ startLine: m.startLine,
544
+ endLine: m.endLine
545
+ }))
546
+ }))
547
+ },
548
+ null,
549
+ 2
550
+ )
551
+ }
552
+ ]
553
+ };
554
+ } catch (error) {
555
+ const err = toError(error);
556
+ log.e("CLONES", "detectClones failed", { error: err.message, stack: err.stack });
557
+ return {
558
+ content: [
559
+ {
560
+ type: "text",
561
+ text: JSON.stringify(
562
+ {
563
+ groupsFound: 0,
564
+ clones: [],
565
+ error: err.message
566
+ },
567
+ null,
568
+ 2
569
+ )
570
+ }
571
+ ]
572
+ };
573
+ }
574
+ }
575
+ };
576
+ var JscpdDetectClonesSchema = z.object({
577
+ directory: z.string().optional(),
578
+ minLines: z.number().optional().default(5),
579
+ minTokens: z.number().optional().default(50),
580
+ threshold: z.number().optional().default(0),
581
+ format: z.array(z.string()).optional(),
582
+ offset: z.number().optional().default(0),
583
+ limit: z.number().optional().default(SAFE_LIMITS.clones)
584
+ });
585
+ var JscpdDetectClonesToolHandler = class extends BaseToolHandler {
586
+ parseArgs(args) {
587
+ return JscpdDetectClonesSchema.parse(args);
588
+ }
589
+ async execute(args) {
590
+ const targetDir = args.directory ? this.context.normalizeInputPath(args.directory) ?? this.resolveProjectPath({}) : this.resolveProjectPath({});
591
+ try {
592
+ const { runJscpdCloneDetection } = await import('./jscpd-ZS3WMD6W.js');
593
+ const result = await runJscpdCloneDetection({
594
+ paths: [targetDir],
595
+ formats: args.format || ["javascript", "typescript", "python"],
596
+ minLines: args.minLines,
597
+ minTokens: args.minTokens
598
+ });
599
+ const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
600
+ const paginatedResult = paginate(result.clones, args.offset, safeLimit);
601
+ return {
602
+ content: [
603
+ {
604
+ type: "text",
605
+ text: JSON.stringify(
606
+ {
607
+ duplicatesFound: paginatedResult.data.length,
608
+ pagination: paginatedResult.pagination,
609
+ statistics: {
610
+ total: result.statistic.total,
611
+ detectionDate: result.statistic.detectionDate
612
+ },
613
+ duplicates: paginatedResult.data.map((c) => ({
614
+ format: c.format,
615
+ foundDate: c.foundDate,
616
+ duplicationA: {
617
+ sourceId: c.duplicationA.sourceId,
618
+ start: c.duplicationA.start,
619
+ end: c.duplicationA.end
620
+ },
621
+ duplicationB: {
622
+ sourceId: c.duplicationB.sourceId,
623
+ start: c.duplicationB.start,
624
+ end: c.duplicationB.end
625
+ }
626
+ }))
627
+ },
628
+ null,
629
+ 2
630
+ )
631
+ }
632
+ ]
633
+ };
634
+ } catch (error) {
635
+ const err = toError(error);
636
+ return {
637
+ content: [
638
+ {
639
+ type: "text",
640
+ text: JSON.stringify({ error: err.message })
641
+ }
642
+ ]
643
+ };
644
+ }
645
+ }
646
+ };
647
+ var CrossLanguageSearchSchema = z.object({
648
+ query: z.string().describe("Search query"),
649
+ projectPath: projectPathParam,
650
+ languages: z.array(z.string()).optional().describe("Languages to search in"),
651
+ offset: z.number().optional().default(0),
652
+ limit: z.number().optional().default(SAFE_LIMITS.searchResults),
653
+ includeContent: z.boolean().optional().default(false).describe("Include full source code (startLine to endLine) in results")
654
+ });
655
+ var CrossLanguageSearchToolHandler = class extends BaseToolHandler {
656
+ parseArgs(args) {
657
+ return CrossLanguageSearchSchema.parse(args);
658
+ }
659
+ async execute(args) {
660
+ const resolvedPath = this.resolveProjectPath(args);
661
+ const semanticAgent = await this.ensureSemanticAgentForProject(resolvedPath);
662
+ const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
663
+ const languages = args.languages || [
664
+ "typescript",
665
+ "javascript",
666
+ "python",
667
+ "go",
668
+ "rust",
669
+ "java",
670
+ "cpp",
671
+ "swift",
672
+ "kotlin",
673
+ "csharp"
674
+ ];
675
+ const allResults = await semanticAgent.crossLanguageSearch(args.query, languages);
676
+ const paginatedResult = paginate(allResults, args.offset, safeLimit);
677
+ const mappedResults = paginatedResult.data.map((r) => {
678
+ const filePath = r.filePath || r.metadata?.path;
679
+ const startLine = r.metadata?.startLine;
680
+ const endLine = r.metadata?.endLine;
681
+ const content = args.includeContent ? loadSourceCode(filePath, startLine, endLine) : void 0;
682
+ return {
683
+ id: r.id,
684
+ name: r.name,
685
+ language: r.metadata?.language,
686
+ filePath,
687
+ startLine,
688
+ endLine,
689
+ similarity: r.similarity,
690
+ ...content ? { content } : {}
691
+ };
692
+ });
693
+ const { results: finalResults, contentPagination } = applyContentPagination(mappedResults, args.includeContent);
694
+ return {
695
+ content: [
696
+ {
697
+ type: "text",
698
+ text: JSON.stringify(
699
+ {
700
+ query: args.query,
701
+ languages,
702
+ count: finalResults.length,
703
+ pagination: paginatedResult.pagination,
704
+ ...contentPagination ? { contentPagination } : {},
705
+ results: finalResults
706
+ },
707
+ null,
708
+ 2
709
+ )
710
+ }
711
+ ]
712
+ };
713
+ }
714
+ };
715
+ var PatternSearchSchema = z.object({
716
+ pattern: z.string(),
717
+ projectPath: projectPathParam,
718
+ mode: z.enum(["entity", "content", "semantic", "hybrid"]).optional().default("hybrid"),
719
+ entityTypes: z.array(z.string()).optional(),
720
+ offset: z.number().optional().default(0),
721
+ limit: z.number().optional().default(SAFE_LIMITS.searchResults),
722
+ minSimilarity: z.number().optional().default(0.7),
723
+ // History filters (Prolly Tree)
724
+ changedInLastCommits: z.number().optional().describe("Filter: only entities changed in last N graph commits (Prolly Tree)"),
725
+ changedSinceMs: z.number().optional().describe("Filter: only entities changed since this Unix timestamp (ms)")
726
+ });
727
+ var PatternSearchToolHandler = class extends BaseToolHandler {
728
+ parseArgs(args) {
729
+ return PatternSearchSchema.parse(args);
730
+ }
731
+ async execute(args) {
732
+ const { PatternSearch } = await import('./pattern-search-WRBKEWYE.js');
733
+ const resolvedPath = this.resolveProjectPath(args);
734
+ const storage = await this.ensureGraphStorageForProject(resolvedPath);
735
+ const safeLimit = Math.min(args.limit, MAX_PAGE_SIZE);
736
+ let vectorStore = null;
737
+ let embeddingError = null;
738
+ try {
739
+ const semanticAgent = await this.ensureSemanticAgentForProject(resolvedPath);
740
+ embeddingError = semanticAgent.getEmbeddingInitError();
741
+ vectorStore = semanticAgent.getVectorStore?.();
742
+ } catch {
743
+ }
744
+ if ((args.mode === "semantic" || args.mode === "hybrid") && embeddingError) {
745
+ return {
746
+ content: [
747
+ {
748
+ type: "text",
749
+ text: JSON.stringify(
750
+ {
751
+ success: false,
752
+ error: `Embedding provider initialization failed: ${embeddingError.message}`,
753
+ hint: "Check if the configured embedding provider is available. Use mode='entity' or 'content' for text-based search."
754
+ },
755
+ null,
756
+ 2
757
+ )
758
+ }
759
+ ]
760
+ };
761
+ }
762
+ const patternSearch = new PatternSearch(storage, vectorStore, null);
763
+ await patternSearch.initialize();
764
+ let allResults = await patternSearch.search({
765
+ pattern: args.pattern,
766
+ mode: args.mode,
767
+ scope: { entityTypes: args.entityTypes },
768
+ limit: 500
769
+ });
770
+ if (args.changedInLastCommits !== void 0 || args.changedSinceMs !== void 0) {
771
+ const { getRecentlyChangedEntities } = await import('./recently-changed-FX5QR4Z2.js');
772
+ const adapter = storage.getLibSQLAdapter?.();
773
+ if (adapter) {
774
+ const recentlyChanged = await getRecentlyChangedEntities(adapter, {
775
+ lastCommits: args.changedInLastCommits,
776
+ sinceTimestamp: args.changedSinceMs
777
+ });
778
+ if (recentlyChanged) {
779
+ allResults = allResults.filter((r) => recentlyChanged.changedIds.has(r.entity.id));
780
+ }
781
+ }
782
+ }
783
+ const paginatedResult = paginate(allResults, args.offset, safeLimit);
784
+ return {
785
+ content: [
786
+ {
787
+ type: "text",
788
+ text: JSON.stringify(
789
+ {
790
+ pattern: args.pattern,
791
+ mode: args.mode,
792
+ count: paginatedResult.data.length,
793
+ pagination: paginatedResult.pagination,
794
+ results: paginatedResult.data.map((r) => ({
795
+ id: r.entity.id,
796
+ name: r.entity.name,
797
+ type: r.entity.type,
798
+ matchType: r.matchType,
799
+ score: r.score,
800
+ filePath: r.entity.filePath,
801
+ startLine: r.entity.location?.start?.line,
802
+ endLine: r.entity.location?.end?.line,
803
+ snippet: r.snippet
804
+ }))
805
+ },
806
+ null,
807
+ 2
808
+ )
809
+ }
810
+ ]
811
+ };
812
+ }
813
+ };
814
+
815
+ export { CrossLanguageSearchToolHandler, DetectCodeClonesToolHandler, FindSimilarCodeToolHandler, JscpdDetectClonesToolHandler, PatternSearchToolHandler, SemanticSearchToolHandler };
816
+ //# sourceMappingURL=semantic-tool-handlers-735UMO7Y.js.map
817
+ //# sourceMappingURL=semantic-tool-handlers-735UMO7Y.js.map