wave-agent-sdk 0.0.7 → 0.0.10

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 (240) hide show
  1. package/dist/agent.d.ts +105 -24
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +438 -53
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -0
  7. package/dist/managers/aiManager.d.ts +18 -7
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +254 -142
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +11 -9
  12. package/dist/managers/hookManager.d.ts +6 -6
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +81 -39
  15. package/dist/managers/liveConfigManager.d.ts +95 -0
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -0
  17. package/dist/managers/liveConfigManager.js +442 -0
  18. package/dist/managers/lspManager.d.ts +43 -0
  19. package/dist/managers/lspManager.d.ts.map +1 -0
  20. package/dist/managers/lspManager.js +326 -0
  21. package/dist/managers/messageManager.d.ts +41 -24
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +184 -73
  24. package/dist/managers/permissionManager.d.ts +66 -0
  25. package/dist/managers/permissionManager.d.ts.map +1 -0
  26. package/dist/managers/permissionManager.js +208 -0
  27. package/dist/managers/skillManager.d.ts +1 -0
  28. package/dist/managers/skillManager.d.ts.map +1 -1
  29. package/dist/managers/skillManager.js +2 -1
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +4 -2
  32. package/dist/managers/subagentManager.d.ts +42 -6
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +213 -62
  35. package/dist/managers/toolManager.d.ts +38 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +66 -2
  38. package/dist/services/aiService.d.ts +15 -5
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +446 -77
  41. package/dist/services/configurationService.d.ts +116 -0
  42. package/dist/services/configurationService.d.ts.map +1 -0
  43. package/dist/services/configurationService.js +585 -0
  44. package/dist/services/fileWatcher.d.ts +69 -0
  45. package/dist/services/fileWatcher.d.ts.map +1 -0
  46. package/dist/services/fileWatcher.js +212 -0
  47. package/dist/services/hook.d.ts +5 -40
  48. package/dist/services/hook.d.ts.map +1 -1
  49. package/dist/services/hook.js +47 -109
  50. package/dist/services/jsonlHandler.d.ts +71 -0
  51. package/dist/services/jsonlHandler.d.ts.map +1 -0
  52. package/dist/services/jsonlHandler.js +236 -0
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +33 -11
  55. package/dist/services/session.d.ts +116 -52
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +415 -143
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +77 -17
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +27 -1
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +33 -8
  64. package/dist/tools/lspTool.d.ts +6 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -0
  66. package/dist/tools/lspTool.js +589 -0
  67. package/dist/tools/multiEditTool.d.ts.map +1 -1
  68. package/dist/tools/multiEditTool.js +30 -10
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +113 -3
  71. package/dist/tools/skillTool.js +2 -2
  72. package/dist/tools/todoWriteTool.d.ts.map +1 -1
  73. package/dist/tools/todoWriteTool.js +23 -0
  74. package/dist/tools/types.d.ts +11 -8
  75. package/dist/tools/types.d.ts.map +1 -1
  76. package/dist/tools/writeTool.d.ts.map +1 -1
  77. package/dist/tools/writeTool.js +30 -15
  78. package/dist/types/commands.d.ts +4 -1
  79. package/dist/types/commands.d.ts.map +1 -1
  80. package/dist/types/config.d.ts +4 -0
  81. package/dist/types/config.d.ts.map +1 -1
  82. package/dist/types/configuration.d.ts +69 -0
  83. package/dist/types/configuration.d.ts.map +1 -0
  84. package/dist/types/configuration.js +8 -0
  85. package/dist/types/core.d.ts +45 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +83 -0
  88. package/dist/types/environment.d.ts.map +1 -0
  89. package/dist/types/environment.js +21 -0
  90. package/dist/types/fileSearch.d.ts +5 -0
  91. package/dist/types/fileSearch.d.ts.map +1 -0
  92. package/dist/types/fileSearch.js +1 -0
  93. package/dist/types/hooks.d.ts +18 -3
  94. package/dist/types/hooks.d.ts.map +1 -1
  95. package/dist/types/hooks.js +8 -8
  96. package/dist/types/index.d.ts +7 -0
  97. package/dist/types/index.d.ts.map +1 -1
  98. package/dist/types/index.js +7 -0
  99. package/dist/types/lsp.d.ts +90 -0
  100. package/dist/types/lsp.d.ts.map +1 -0
  101. package/dist/types/lsp.js +4 -0
  102. package/dist/types/messaging.d.ts +19 -12
  103. package/dist/types/messaging.d.ts.map +1 -1
  104. package/dist/types/permissions.d.ts +35 -0
  105. package/dist/types/permissions.d.ts.map +1 -0
  106. package/dist/types/permissions.js +12 -0
  107. package/dist/types/session.d.ts +15 -0
  108. package/dist/types/session.d.ts.map +1 -0
  109. package/dist/types/session.js +7 -0
  110. package/dist/types/skills.d.ts +1 -0
  111. package/dist/types/skills.d.ts.map +1 -1
  112. package/dist/types/tools.d.ts +35 -0
  113. package/dist/types/tools.d.ts.map +1 -0
  114. package/dist/types/tools.js +4 -0
  115. package/dist/utils/abortUtils.d.ts +34 -0
  116. package/dist/utils/abortUtils.d.ts.map +1 -0
  117. package/dist/utils/abortUtils.js +92 -0
  118. package/dist/utils/bashHistory.d.ts +4 -0
  119. package/dist/utils/bashHistory.d.ts.map +1 -1
  120. package/dist/utils/bashHistory.js +48 -30
  121. package/dist/utils/builtinSubagents.d.ts +7 -0
  122. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  123. package/dist/utils/builtinSubagents.js +65 -0
  124. package/dist/utils/cacheControlUtils.d.ts +96 -0
  125. package/dist/utils/cacheControlUtils.d.ts.map +1 -0
  126. package/dist/utils/cacheControlUtils.js +324 -0
  127. package/dist/utils/commandPathResolver.d.ts +52 -0
  128. package/dist/utils/commandPathResolver.d.ts.map +1 -0
  129. package/dist/utils/commandPathResolver.js +145 -0
  130. package/dist/utils/configPaths.d.ts +85 -0
  131. package/dist/utils/configPaths.d.ts.map +1 -0
  132. package/dist/utils/configPaths.js +121 -0
  133. package/dist/utils/constants.d.ts +1 -13
  134. package/dist/utils/constants.d.ts.map +1 -1
  135. package/dist/utils/constants.js +2 -14
  136. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  137. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  138. package/dist/utils/convertMessagesForAPI.js +39 -18
  139. package/dist/utils/customCommands.d.ts.map +1 -1
  140. package/dist/utils/customCommands.js +66 -21
  141. package/dist/utils/fileSearch.d.ts +14 -0
  142. package/dist/utils/fileSearch.d.ts.map +1 -0
  143. package/dist/utils/fileSearch.js +88 -0
  144. package/dist/utils/fileUtils.d.ts +27 -0
  145. package/dist/utils/fileUtils.d.ts.map +1 -0
  146. package/dist/utils/fileUtils.js +145 -0
  147. package/dist/utils/globalLogger.d.ts +88 -0
  148. package/dist/utils/globalLogger.d.ts.map +1 -0
  149. package/dist/utils/globalLogger.js +120 -0
  150. package/dist/utils/largeOutputHandler.d.ts +15 -0
  151. package/dist/utils/largeOutputHandler.d.ts.map +1 -0
  152. package/dist/utils/largeOutputHandler.js +40 -0
  153. package/dist/utils/markdownParser.d.ts.map +1 -1
  154. package/dist/utils/markdownParser.js +1 -17
  155. package/dist/utils/mcpUtils.d.ts.map +1 -1
  156. package/dist/utils/mcpUtils.js +25 -3
  157. package/dist/utils/messageOperations.d.ts +20 -18
  158. package/dist/utils/messageOperations.d.ts.map +1 -1
  159. package/dist/utils/messageOperations.js +30 -38
  160. package/dist/utils/pathEncoder.d.ts +108 -0
  161. package/dist/utils/pathEncoder.d.ts.map +1 -0
  162. package/dist/utils/pathEncoder.js +279 -0
  163. package/dist/utils/subagentParser.d.ts +2 -2
  164. package/dist/utils/subagentParser.d.ts.map +1 -1
  165. package/dist/utils/subagentParser.js +12 -8
  166. package/dist/utils/tokenCalculation.d.ts +26 -0
  167. package/dist/utils/tokenCalculation.d.ts.map +1 -0
  168. package/dist/utils/tokenCalculation.js +36 -0
  169. package/dist/utils/tokenEstimator.d.ts +39 -0
  170. package/dist/utils/tokenEstimator.d.ts.map +1 -0
  171. package/dist/utils/tokenEstimator.js +55 -0
  172. package/package.json +6 -6
  173. package/src/agent.ts +586 -78
  174. package/src/index.ts +4 -0
  175. package/src/managers/aiManager.ts +341 -192
  176. package/src/managers/backgroundBashManager.ts +11 -9
  177. package/src/managers/hookManager.ts +102 -54
  178. package/src/managers/liveConfigManager.ts +634 -0
  179. package/src/managers/lspManager.ts +434 -0
  180. package/src/managers/messageManager.ts +258 -121
  181. package/src/managers/permissionManager.ts +276 -0
  182. package/src/managers/skillManager.ts +3 -1
  183. package/src/managers/slashCommandManager.ts +5 -3
  184. package/src/managers/subagentManager.ts +295 -76
  185. package/src/managers/toolManager.ts +95 -3
  186. package/src/services/aiService.ts +656 -84
  187. package/src/services/configurationService.ts +762 -0
  188. package/src/services/fileWatcher.ts +300 -0
  189. package/src/services/hook.ts +54 -144
  190. package/src/services/jsonlHandler.ts +303 -0
  191. package/src/services/memory.ts +34 -11
  192. package/src/services/session.ts +522 -173
  193. package/src/tools/bashTool.ts +94 -20
  194. package/src/tools/deleteFileTool.ts +38 -1
  195. package/src/tools/editTool.ts +44 -9
  196. package/src/tools/lspTool.ts +760 -0
  197. package/src/tools/multiEditTool.ts +41 -11
  198. package/src/tools/readTool.ts +127 -3
  199. package/src/tools/skillTool.ts +2 -2
  200. package/src/tools/todoWriteTool.ts +33 -1
  201. package/src/tools/types.ts +15 -9
  202. package/src/tools/writeTool.ts +43 -16
  203. package/src/types/commands.ts +6 -1
  204. package/src/types/config.ts +5 -0
  205. package/src/types/configuration.ts +73 -0
  206. package/src/types/core.ts +55 -0
  207. package/src/types/environment.ts +104 -0
  208. package/src/types/fileSearch.ts +4 -0
  209. package/src/types/hooks.ts +32 -16
  210. package/src/types/index.ts +7 -0
  211. package/src/types/lsp.ts +96 -0
  212. package/src/types/messaging.ts +21 -14
  213. package/src/types/permissions.ts +48 -0
  214. package/src/types/session.ts +20 -0
  215. package/src/types/skills.ts +1 -0
  216. package/src/types/tools.ts +38 -0
  217. package/src/utils/abortUtils.ts +118 -0
  218. package/src/utils/bashHistory.ts +55 -31
  219. package/src/utils/builtinSubagents.ts +71 -0
  220. package/src/utils/cacheControlUtils.ts +475 -0
  221. package/src/utils/commandPathResolver.ts +189 -0
  222. package/src/utils/configPaths.ts +163 -0
  223. package/src/utils/constants.ts +2 -17
  224. package/src/utils/convertMessagesForAPI.ts +44 -18
  225. package/src/utils/customCommands.ts +90 -22
  226. package/src/utils/fileSearch.ts +107 -0
  227. package/src/utils/fileUtils.ts +160 -0
  228. package/src/utils/globalLogger.ts +128 -0
  229. package/src/utils/largeOutputHandler.ts +55 -0
  230. package/src/utils/markdownParser.ts +1 -19
  231. package/src/utils/mcpUtils.ts +34 -3
  232. package/src/utils/messageOperations.ts +47 -53
  233. package/src/utils/pathEncoder.ts +394 -0
  234. package/src/utils/subagentParser.ts +13 -9
  235. package/src/utils/tokenCalculation.ts +43 -0
  236. package/src/utils/tokenEstimator.ts +68 -0
  237. package/dist/utils/configResolver.d.ts +0 -38
  238. package/dist/utils/configResolver.d.ts.map +0 -1
  239. package/dist/utils/configResolver.js +0 -106
  240. package/src/utils/configResolver.ts +0 -142
@@ -0,0 +1,589 @@
1
+ import { relative } from "path";
2
+ import { logger } from "../utils/globalLogger.js";
3
+ import { getDisplayPath } from "../utils/path.js";
4
+ /**
5
+ * Formats an LSP URI into a readable file path
6
+ */
7
+ function formatUri(uri, workdir) {
8
+ if (!uri) {
9
+ logger.warn("formatUri called with undefined URI - indicates malformed LSP server response");
10
+ return "<unknown location>";
11
+ }
12
+ let path = uri.replace(/^file:\/\//, "");
13
+ try {
14
+ path = decodeURIComponent(path);
15
+ }
16
+ catch (e) {
17
+ const message = e instanceof Error ? e.message : String(e);
18
+ logger.warn(`Failed to decode LSP URI '${uri}': ${message}. Using un-decoded path: ${path}`);
19
+ }
20
+ if (workdir) {
21
+ const relativePath = relative(workdir, path);
22
+ if (relativePath.length < path.length &&
23
+ !relativePath.startsWith("../../")) {
24
+ return relativePath;
25
+ }
26
+ }
27
+ return path;
28
+ }
29
+ /**
30
+ * Groups items by their URI
31
+ */
32
+ function groupItemsByUri(items, workdir) {
33
+ const map = new Map();
34
+ for (const item of items) {
35
+ let uri;
36
+ if ("uri" in item) {
37
+ uri = item.uri;
38
+ }
39
+ else if ("location" in item) {
40
+ uri = item.location.uri;
41
+ }
42
+ else {
43
+ uri = item.targetUri;
44
+ }
45
+ const path = formatUri(uri, workdir);
46
+ const existing = map.get(path);
47
+ if (existing) {
48
+ existing.push(item);
49
+ }
50
+ else {
51
+ map.set(path, [item]);
52
+ }
53
+ }
54
+ return map;
55
+ }
56
+ /**
57
+ * Formats a single location as path:line:character
58
+ */
59
+ function formatLocation(loc, workdir) {
60
+ const path = formatUri(loc.uri, workdir);
61
+ const line = loc.range.start.line + 1;
62
+ const character = loc.range.start.character + 1;
63
+ return `${path}:${line}:${character}`;
64
+ }
65
+ /**
66
+ * Converts a LocationLink to a Location
67
+ */
68
+ function locationLinkToLocation(link) {
69
+ return {
70
+ uri: link.targetUri,
71
+ range: link.targetSelectionRange || link.targetRange,
72
+ };
73
+ }
74
+ /**
75
+ * Checks if an object is a LocationLink
76
+ */
77
+ function isLocationLink(loc) {
78
+ return "targetUri" in loc;
79
+ }
80
+ /**
81
+ * Formats the result of a goToDefinition operation
82
+ */
83
+ function formatGoToDefinitionResult(result, workdir) {
84
+ if (!result) {
85
+ return "No definition found. This may occur if the cursor is not on a symbol, or if the definition is in an external library not indexed by the LSP server.";
86
+ }
87
+ if (Array.isArray(result)) {
88
+ const locations = result.map((loc) => isLocationLink(loc) ? locationLinkToLocation(loc) : loc);
89
+ const validLocations = locations.filter((loc) => loc && loc.uri);
90
+ if (validLocations.length === 0) {
91
+ return "No definition found. This may occur if the cursor is not on a symbol, or if the definition is in an external library not indexed by the LSP server.";
92
+ }
93
+ if (validLocations.length === 1) {
94
+ return `Defined in ${formatLocation(validLocations[0], workdir)}`;
95
+ }
96
+ const formatted = validLocations
97
+ .map((loc) => ` ${formatLocation(loc, workdir)}`)
98
+ .join("\n");
99
+ return `Found ${validLocations.length} definitions:\n${formatted}`;
100
+ }
101
+ const loc = isLocationLink(result) ? locationLinkToLocation(result) : result;
102
+ return `Defined in ${formatLocation(loc, workdir)}`;
103
+ }
104
+ /**
105
+ * Formats the result of a findReferences operation
106
+ */
107
+ function formatFindReferencesResult(result, workdir) {
108
+ if (!result || result.length === 0) {
109
+ return "No references found. This may occur if the symbol has no usages, or if the LSP server has not fully indexed the workspace.";
110
+ }
111
+ const validLocations = result.filter((loc) => loc && loc.uri);
112
+ if (validLocations.length === 0) {
113
+ return "No references found. This may occur if the symbol has no usages, or if the LSP server has not fully indexed the workspace.";
114
+ }
115
+ if (validLocations.length === 1) {
116
+ return `Found 1 reference:\n ${formatLocation(validLocations[0], workdir)}`;
117
+ }
118
+ const grouped = groupItemsByUri(validLocations, workdir);
119
+ const lines = [
120
+ `Found ${validLocations.length} references across ${grouped.size} files:`,
121
+ ];
122
+ for (const [path, locs] of grouped) {
123
+ lines.push(`\n${path}:`);
124
+ for (const loc of locs) {
125
+ const line = loc.range.start.line + 1;
126
+ const character = loc.range.start.character + 1;
127
+ lines.push(` Line ${line}:${character}`);
128
+ }
129
+ }
130
+ return lines.join("\n");
131
+ }
132
+ /**
133
+ * Formats hover contents
134
+ */
135
+ function formatHoverContents(contents) {
136
+ if (Array.isArray(contents)) {
137
+ return contents
138
+ .map((c) => (typeof c === "string" ? c : c.value))
139
+ .join("\n\n");
140
+ }
141
+ if (typeof contents === "string") {
142
+ return contents;
143
+ }
144
+ return contents.value;
145
+ }
146
+ /**
147
+ * Formats the result of a hover operation
148
+ */
149
+ function formatHoverResult(result) {
150
+ if (!result) {
151
+ return "No hover information available. This may occur if the cursor is not on a symbol, or if the LSP server has not fully indexed the file.";
152
+ }
153
+ const contents = formatHoverContents(result.contents);
154
+ if (result.range) {
155
+ const line = result.range.start.line + 1;
156
+ const character = result.range.start.character + 1;
157
+ return `Hover info at ${line}:${character}:\n\n${contents}`;
158
+ }
159
+ return contents;
160
+ }
161
+ /**
162
+ * Gets the name of a symbol kind
163
+ */
164
+ function getSymbolKindName(kind) {
165
+ const kinds = {
166
+ 1: "File",
167
+ 2: "Module",
168
+ 3: "Namespace",
169
+ 4: "Package",
170
+ 5: "Class",
171
+ 6: "Method",
172
+ 7: "Property",
173
+ 8: "Field",
174
+ 9: "Constructor",
175
+ 10: "Enum",
176
+ 11: "Interface",
177
+ 12: "Function",
178
+ 13: "Variable",
179
+ 14: "Constant",
180
+ 15: "String",
181
+ 16: "Number",
182
+ 17: "Boolean",
183
+ 18: "Array",
184
+ 19: "Object",
185
+ 20: "Key",
186
+ 21: "Null",
187
+ 22: "EnumMember",
188
+ 23: "Struct",
189
+ 24: "Event",
190
+ 25: "Operator",
191
+ 26: "TypeParameter",
192
+ };
193
+ return kinds[kind] || "Unknown";
194
+ }
195
+ /**
196
+ * Formats a single document symbol recursively
197
+ */
198
+ function formatDocumentSymbol(symbol, depth = 0) {
199
+ const results = [];
200
+ const indent = " ".repeat(depth);
201
+ const kindName = getSymbolKindName(symbol.kind);
202
+ let line = `${indent}${symbol.name} (${kindName})`;
203
+ if (symbol.detail) {
204
+ line += ` ${symbol.detail}`;
205
+ }
206
+ const startLine = symbol.range.start.line + 1;
207
+ line += ` - Line ${startLine}`;
208
+ results.push(line);
209
+ if (symbol.children && symbol.children.length > 0) {
210
+ for (const child of symbol.children) {
211
+ results.push(...formatDocumentSymbol(child, depth + 1));
212
+ }
213
+ }
214
+ return results;
215
+ }
216
+ /**
217
+ * Formats the result of a documentSymbol operation
218
+ */
219
+ function formatDocumentSymbolResult(result, workdir) {
220
+ if (!result || result.length === 0) {
221
+ return "No symbols found in document. This may occur if the file is empty, not supported by the LSP server, or if the server has not fully indexed the file.";
222
+ }
223
+ const first = result[0];
224
+ if (first && "location" in first) {
225
+ return formatWorkspaceSymbolResult(result, workdir);
226
+ }
227
+ const lines = ["Document symbols:"];
228
+ for (const symbol of result) {
229
+ lines.push(...formatDocumentSymbol(symbol));
230
+ }
231
+ return lines.join("\n");
232
+ }
233
+ /**
234
+ * Formats the result of a workspaceSymbol operation
235
+ */
236
+ function formatWorkspaceSymbolResult(result, workdir) {
237
+ if (!result || result.length === 0) {
238
+ return "No symbols found in workspace. This may occur if the workspace is empty, or if the LSP server has not finished indexing the project.";
239
+ }
240
+ const validSymbols = result.filter((s) => s && s.location && s.location.uri);
241
+ if (validSymbols.length === 0) {
242
+ return "No symbols found in workspace. This may occur if the workspace is empty, or if the LSP server has not finished indexing the project.";
243
+ }
244
+ const lines = [
245
+ `Found ${validSymbols.length} symbol${validSymbols.length === 1 ? "" : "s"} in workspace:`,
246
+ ];
247
+ const grouped = groupItemsByUri(validSymbols, workdir);
248
+ for (const [path, symbols] of grouped) {
249
+ lines.push(`\n${path}:`);
250
+ for (const s of symbols) {
251
+ const kindName = getSymbolKindName(s.kind);
252
+ const startLine = s.location.range.start.line + 1;
253
+ let line = ` ${s.name} (${kindName}) - Line ${startLine}`;
254
+ if (s.containerName) {
255
+ line += ` in ${s.containerName}`;
256
+ }
257
+ lines.push(line);
258
+ }
259
+ }
260
+ return lines.join("\n");
261
+ }
262
+ /**
263
+ * Formats a call hierarchy item
264
+ */
265
+ function formatCallHierarchyItem(item, workdir) {
266
+ if (!item.uri) {
267
+ logger.warn("formatCallHierarchyItem: CallHierarchyItem has undefined URI");
268
+ return `${item.name} (${getSymbolKindName(item.kind)}) - <unknown location>`;
269
+ }
270
+ const path = formatUri(item.uri, workdir);
271
+ const startLine = item.range.start.line + 1;
272
+ const kindName = getSymbolKindName(item.kind);
273
+ let line = `${item.name} (${kindName}) - ${path}:${startLine}`;
274
+ if (item.detail) {
275
+ line += ` [${item.detail}]`;
276
+ }
277
+ return line;
278
+ }
279
+ /**
280
+ * Formats the result of a prepareCallHierarchy operation
281
+ */
282
+ function formatPrepareCallHierarchyResult(result, workdir) {
283
+ if (!result || result.length === 0) {
284
+ return "No call hierarchy item found at this position";
285
+ }
286
+ if (result.length === 1) {
287
+ return `Call hierarchy item: ${formatCallHierarchyItem(result[0], workdir)}`;
288
+ }
289
+ const lines = [`Found ${result.length} call hierarchy items:`];
290
+ for (const item of result) {
291
+ lines.push(` ${formatCallHierarchyItem(item, workdir)}`);
292
+ }
293
+ return lines.join("\n");
294
+ }
295
+ /**
296
+ * Formats the result of an incomingCalls operation
297
+ */
298
+ function formatIncomingCallsResult(result, workdir) {
299
+ if (!result || result.length === 0) {
300
+ return "No incoming calls found (nothing calls this function)";
301
+ }
302
+ const lines = [
303
+ `Found ${result.length} incoming call${result.length === 1 ? "" : "s"}:`,
304
+ ];
305
+ const grouped = new Map();
306
+ for (const call of result) {
307
+ if (!call.from) {
308
+ logger.warn("formatIncomingCallsResult: CallHierarchyIncomingCall has undefined from field");
309
+ continue;
310
+ }
311
+ const path = formatUri(call.from.uri, workdir);
312
+ const existing = grouped.get(path);
313
+ if (existing) {
314
+ existing.push(call);
315
+ }
316
+ else {
317
+ grouped.set(path, [call]);
318
+ }
319
+ }
320
+ for (const [path, calls] of grouped) {
321
+ lines.push(`\n${path}:`);
322
+ for (const call of calls) {
323
+ if (!call.from)
324
+ continue;
325
+ const kindName = getSymbolKindName(call.from.kind);
326
+ const startLine = call.from.range.start.line + 1;
327
+ let line = ` ${call.from.name} (${kindName}) - Line ${startLine}`;
328
+ if (call.fromRanges && call.fromRanges.length > 0) {
329
+ const ranges = call.fromRanges
330
+ .map((r) => `${r.start.line + 1}:${r.start.character + 1}`)
331
+ .join(", ");
332
+ line += ` [calls at: ${ranges}]`;
333
+ }
334
+ lines.push(line);
335
+ }
336
+ }
337
+ return lines.join("\n");
338
+ }
339
+ /**
340
+ * Formats the result of an outgoingCalls operation
341
+ */
342
+ function formatOutgoingCallsResult(result, workdir) {
343
+ if (!result || result.length === 0) {
344
+ return "No outgoing calls found (this function calls nothing)";
345
+ }
346
+ const lines = [
347
+ `Found ${result.length} outgoing call${result.length === 1 ? "" : "s"}:`,
348
+ ];
349
+ const grouped = new Map();
350
+ for (const call of result) {
351
+ if (!call.to) {
352
+ logger.warn("formatOutgoingCallsResult: CallHierarchyOutgoingCall has undefined to field");
353
+ continue;
354
+ }
355
+ const path = formatUri(call.to.uri, workdir);
356
+ const existing = grouped.get(path);
357
+ if (existing) {
358
+ existing.push(call);
359
+ }
360
+ else {
361
+ grouped.set(path, [call]);
362
+ }
363
+ }
364
+ for (const [path, calls] of grouped) {
365
+ lines.push(`\n${path}:`);
366
+ for (const call of calls) {
367
+ if (!call.to)
368
+ continue;
369
+ const kindName = getSymbolKindName(call.to.kind);
370
+ const startLine = call.to.range.start.line + 1;
371
+ let line = ` ${call.to.name} (${kindName}) - Line ${startLine}`;
372
+ if (call.fromRanges && call.fromRanges.length > 0) {
373
+ const ranges = call.fromRanges
374
+ .map((r) => `${r.start.line + 1}:${r.start.character + 1}`)
375
+ .join(", ");
376
+ line += ` [called from: ${ranges}]`;
377
+ }
378
+ lines.push(line);
379
+ }
380
+ }
381
+ return lines.join("\n");
382
+ }
383
+ /**
384
+ * LSP tool plugin - interact with LSP servers for code intelligence
385
+ */
386
+ export const lspTool = {
387
+ name: "LSP",
388
+ config: {
389
+ type: "function",
390
+ function: {
391
+ name: "LSP",
392
+ description: `Interact with Language Server Protocol (LSP) servers to get code intelligence features.
393
+
394
+ Supported operations:
395
+ - goToDefinition: Find where a symbol is defined
396
+ - findReferences: Find all references to a symbol
397
+ - hover: Get hover information (documentation, type info) for a symbol
398
+ - documentSymbol: Get all symbols (functions, classes, variables) in a document
399
+ - workspaceSymbol: Search for symbols across the entire workspace
400
+ - goToImplementation: Find implementations of an interface or abstract method
401
+ - prepareCallHierarchy: Get call hierarchy item at a position (functions/methods)
402
+ - incomingCalls: Find all functions/methods that call the function at a position
403
+ - outgoingCalls: Find all functions/methods called by the function at a position
404
+
405
+ All operations require:
406
+ - filePath: The file to operate on
407
+ - line: The line number (1-based, as shown in editors)
408
+ - character: The character offset (1-based, as shown in editors)
409
+
410
+ Note: LSP servers must be configured for the file type. If no server is available, an error will be returned.`,
411
+ parameters: {
412
+ type: "object",
413
+ properties: {
414
+ operation: {
415
+ type: "string",
416
+ enum: [
417
+ "goToDefinition",
418
+ "findReferences",
419
+ "hover",
420
+ "documentSymbol",
421
+ "workspaceSymbol",
422
+ "goToImplementation",
423
+ "prepareCallHierarchy",
424
+ "incomingCalls",
425
+ "outgoingCalls",
426
+ ],
427
+ description: "The LSP operation to perform",
428
+ },
429
+ filePath: {
430
+ type: "string",
431
+ description: "The absolute or relative path to the file",
432
+ },
433
+ line: {
434
+ type: "number",
435
+ description: "The line number (1-based, as shown in editors)",
436
+ },
437
+ character: {
438
+ type: "number",
439
+ description: "The character offset (1-based, as shown in editors)",
440
+ },
441
+ },
442
+ required: ["operation", "filePath", "line", "character"],
443
+ },
444
+ },
445
+ },
446
+ execute: async (args, context) => {
447
+ const { operation, filePath, line, character } = args;
448
+ if (context.lspManager) {
449
+ try {
450
+ const result = await context.lspManager.execute({
451
+ operation,
452
+ filePath,
453
+ line,
454
+ character,
455
+ });
456
+ if (!result.success) {
457
+ return {
458
+ success: false,
459
+ content: "",
460
+ error: result.content,
461
+ };
462
+ }
463
+ const rawResult = JSON.parse(result.content);
464
+ let formattedContent;
465
+ switch (operation) {
466
+ case "goToDefinition":
467
+ case "goToImplementation":
468
+ formattedContent = formatGoToDefinitionResult(rawResult, context.workdir);
469
+ break;
470
+ case "findReferences":
471
+ formattedContent = formatFindReferencesResult(rawResult, context.workdir);
472
+ break;
473
+ case "hover":
474
+ formattedContent = formatHoverResult(rawResult);
475
+ break;
476
+ case "documentSymbol":
477
+ formattedContent = formatDocumentSymbolResult(rawResult, context.workdir);
478
+ break;
479
+ case "workspaceSymbol":
480
+ formattedContent = formatWorkspaceSymbolResult(rawResult, context.workdir);
481
+ break;
482
+ case "prepareCallHierarchy":
483
+ formattedContent = formatPrepareCallHierarchyResult(rawResult, context.workdir);
484
+ break;
485
+ case "incomingCalls":
486
+ formattedContent = formatIncomingCallsResult(rawResult, context.workdir);
487
+ break;
488
+ case "outgoingCalls":
489
+ formattedContent = formatOutgoingCallsResult(rawResult, context.workdir);
490
+ break;
491
+ default:
492
+ formattedContent = JSON.stringify(rawResult, null, 2);
493
+ }
494
+ return {
495
+ success: true,
496
+ content: formattedContent,
497
+ };
498
+ }
499
+ catch (error) {
500
+ return {
501
+ success: false,
502
+ content: "",
503
+ error: `LSP operation failed: ${error instanceof Error ? error.message : String(error)}`,
504
+ };
505
+ }
506
+ }
507
+ if (!context.mcpManager) {
508
+ return {
509
+ success: false,
510
+ content: "",
511
+ error: "MCP manager not available in tool context",
512
+ };
513
+ }
514
+ try {
515
+ // Call the MCP tool named "LSP"
516
+ // We assume there is an MCP server that provides this tool
517
+ const result = await context.mcpManager.executeMcpTool("LSP", {
518
+ operation,
519
+ filePath,
520
+ line,
521
+ character,
522
+ });
523
+ if (!result.success) {
524
+ return {
525
+ success: false,
526
+ content: "",
527
+ error: result.content,
528
+ };
529
+ }
530
+ let rawResult;
531
+ try {
532
+ rawResult = JSON.parse(result.content);
533
+ }
534
+ catch {
535
+ // If it's not JSON, it might already be formatted or an error message
536
+ return {
537
+ success: true,
538
+ content: result.content,
539
+ };
540
+ }
541
+ let formattedContent;
542
+ switch (operation) {
543
+ case "goToDefinition":
544
+ case "goToImplementation":
545
+ formattedContent = formatGoToDefinitionResult(rawResult, context.workdir);
546
+ break;
547
+ case "findReferences":
548
+ formattedContent = formatFindReferencesResult(rawResult, context.workdir);
549
+ break;
550
+ case "hover":
551
+ formattedContent = formatHoverResult(rawResult);
552
+ break;
553
+ case "documentSymbol":
554
+ formattedContent = formatDocumentSymbolResult(rawResult, context.workdir);
555
+ break;
556
+ case "workspaceSymbol":
557
+ formattedContent = formatWorkspaceSymbolResult(rawResult, context.workdir);
558
+ break;
559
+ case "prepareCallHierarchy":
560
+ formattedContent = formatPrepareCallHierarchyResult(rawResult, context.workdir);
561
+ break;
562
+ case "incomingCalls":
563
+ formattedContent = formatIncomingCallsResult(rawResult, context.workdir);
564
+ break;
565
+ case "outgoingCalls":
566
+ formattedContent = formatOutgoingCallsResult(rawResult, context.workdir);
567
+ break;
568
+ default:
569
+ formattedContent = JSON.stringify(rawResult, null, 2);
570
+ }
571
+ return {
572
+ success: true,
573
+ content: formattedContent,
574
+ };
575
+ }
576
+ catch (error) {
577
+ return {
578
+ success: false,
579
+ content: "",
580
+ error: `LSP operation failed: ${error instanceof Error ? error.message : String(error)}`,
581
+ };
582
+ }
583
+ },
584
+ formatCompactParams: (params, context) => {
585
+ const { operation, filePath, line, character } = params;
586
+ const displayPath = getDisplayPath(filePath, context.workdir);
587
+ return `${operation} ${displayPath}:${line}:${character}`;
588
+ },
589
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"multiEditTool.d.ts","sourceRoot":"","sources":["../../src/tools/multiEditTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAwBtE;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UAwO3B,CAAC"}
1
+ {"version":3,"file":"multiEditTool.d.ts","sourceRoot":"","sources":["../../src/tools/multiEditTool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAuBtE;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UAsQ3B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { readFile, writeFile } from "fs/promises";
2
+ import { logger } from "../utils/globalLogger.js";
2
3
  import { resolvePath, getDisplayPath } from "../utils/path.js";
3
- import { diffLines } from "diff";
4
4
  /**
5
5
  * Format compact parameter display
6
6
  */
@@ -123,7 +123,7 @@ export const multiEditTool = {
123
123
  if (edits[0] && edits[0].old_string === "") {
124
124
  originalContent = "";
125
125
  isNewFile = true;
126
- // logger.debug(`Creating new file: ${resolvedPath}`);
126
+ logger.debug(`Creating new file: ${resolvedPath}`);
127
127
  }
128
128
  else {
129
129
  return {
@@ -150,7 +150,7 @@ export const multiEditTool = {
150
150
  return {
151
151
  success: false,
152
152
  content: "",
153
- error: `Edit operation ${i + 1}: old_string not found in current content: "${edit.old_string}"`,
153
+ error: `Edit operation ${i + 1}: old_string not found in current content`,
154
154
  };
155
155
  }
156
156
  let replacementCount;
@@ -175,6 +175,31 @@ export const multiEditTool = {
175
175
  appliedEdits.push(`Replaced "${edit.old_string.substring(0, 50)}${edit.old_string.length > 50 ? "..." : ""}"`);
176
176
  }
177
177
  }
178
+ // Permission check after validation but before real operation
179
+ if (context.permissionManager &&
180
+ context.permissionMode &&
181
+ context.permissionMode !== "bypassPermissions") {
182
+ if (context.permissionManager.isRestrictedTool("MultiEdit")) {
183
+ try {
184
+ const permissionContext = context.permissionManager.createContext("MultiEdit", context.permissionMode, context.canUseToolCallback, { file_path: filePath, edits });
185
+ const permissionResult = await context.permissionManager.checkPermission(permissionContext);
186
+ if (permissionResult.behavior === "deny") {
187
+ return {
188
+ success: false,
189
+ content: "",
190
+ error: `MultiEdit operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
191
+ };
192
+ }
193
+ }
194
+ catch {
195
+ return {
196
+ success: false,
197
+ content: "",
198
+ error: "Permission check failed",
199
+ };
200
+ }
201
+ }
202
+ }
178
203
  // Write file
179
204
  try {
180
205
  await writeFile(resolvedPath, currentContent, "utf-8");
@@ -186,26 +211,21 @@ export const multiEditTool = {
186
211
  error: `Failed to write file: ${writeError instanceof Error ? writeError.message : String(writeError)}`,
187
212
  };
188
213
  }
189
- // Generate diff information
190
- const diffResult = diffLines(originalContent, currentContent);
191
214
  const shortResult = isNewFile
192
215
  ? `Created file with ${edits.length} operations`
193
216
  : `Applied ${edits.length} edits`;
194
217
  const detailedContent = `${shortResult}\n\nOperations performed:\n${appliedEdits.map((edit, i) => `${i + 1}. ${edit}`).join("\n")}`;
195
- // logger.debug(`MultiEdit tool: ${shortResult}`);
218
+ logger.debug(`MultiEdit tool: ${shortResult}`);
196
219
  return {
197
220
  success: true,
198
221
  content: detailedContent,
199
222
  shortResult,
200
223
  filePath: resolvedPath,
201
- originalContent,
202
- newContent: currentContent,
203
- diffResult,
204
224
  };
205
225
  }
206
226
  catch (error) {
207
227
  const errorMessage = error instanceof Error ? error.message : String(error);
208
- // logger.error(`MultiEdit tool error: ${errorMessage}`);
228
+ logger.error(`MultiEdit tool error: ${errorMessage}`);
209
229
  return {
210
230
  success: false,
211
231
  content: "",
@@ -1 +1 @@
1
- {"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAOtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA2LtB,CAAC"}
1
+ {"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AA4HtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAgMtB,CAAC"}