wave-agent-sdk 0.0.8 → 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 (236) hide show
  1. package/dist/agent.d.ts +92 -23
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +340 -137
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -0
  7. package/dist/managers/aiManager.d.ts +14 -36
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +74 -77
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +4 -3
  12. package/dist/managers/hookManager.d.ts +3 -8
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +39 -29
  15. package/dist/managers/liveConfigManager.d.ts +55 -18
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  17. package/dist/managers/liveConfigManager.js +372 -90
  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 +8 -16
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +52 -74
  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 +0 -1
  32. package/dist/managers/subagentManager.d.ts +8 -23
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +97 -117
  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 +3 -1
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +123 -30
  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.map +1 -1
  45. package/dist/services/fileWatcher.js +5 -6
  46. package/dist/services/hook.d.ts +7 -124
  47. package/dist/services/hook.d.ts.map +1 -1
  48. package/dist/services/hook.js +46 -458
  49. package/dist/services/jsonlHandler.d.ts +24 -15
  50. package/dist/services/jsonlHandler.d.ts.map +1 -1
  51. package/dist/services/jsonlHandler.js +67 -88
  52. package/dist/services/memory.d.ts +0 -9
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +2 -49
  55. package/dist/services/session.d.ts +82 -33
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +275 -181
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +72 -13
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +25 -0
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +30 -6
  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 +26 -7
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +111 -2
  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 +25 -9
  78. package/dist/types/commands.d.ts +0 -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 +10 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +41 -0
  88. package/dist/types/environment.d.ts.map +1 -1
  89. package/dist/types/fileSearch.d.ts +5 -0
  90. package/dist/types/fileSearch.d.ts.map +1 -0
  91. package/dist/types/fileSearch.js +1 -0
  92. package/dist/types/hooks.d.ts +11 -2
  93. package/dist/types/hooks.d.ts.map +1 -1
  94. package/dist/types/hooks.js +1 -7
  95. package/dist/types/index.d.ts +5 -0
  96. package/dist/types/index.d.ts.map +1 -1
  97. package/dist/types/index.js +5 -0
  98. package/dist/types/lsp.d.ts +90 -0
  99. package/dist/types/lsp.d.ts.map +1 -0
  100. package/dist/types/lsp.js +4 -0
  101. package/dist/types/messaging.d.ts +6 -11
  102. package/dist/types/messaging.d.ts.map +1 -1
  103. package/dist/types/permissions.d.ts +35 -0
  104. package/dist/types/permissions.d.ts.map +1 -0
  105. package/dist/types/permissions.js +12 -0
  106. package/dist/types/session.d.ts +1 -6
  107. package/dist/types/session.d.ts.map +1 -1
  108. package/dist/types/skills.d.ts +1 -0
  109. package/dist/types/skills.d.ts.map +1 -1
  110. package/dist/types/tools.d.ts +35 -0
  111. package/dist/types/tools.d.ts.map +1 -0
  112. package/dist/types/tools.js +4 -0
  113. package/dist/utils/abortUtils.d.ts +34 -0
  114. package/dist/utils/abortUtils.d.ts.map +1 -0
  115. package/dist/utils/abortUtils.js +92 -0
  116. package/dist/utils/bashHistory.d.ts +4 -0
  117. package/dist/utils/bashHistory.d.ts.map +1 -1
  118. package/dist/utils/bashHistory.js +21 -4
  119. package/dist/utils/builtinSubagents.d.ts +7 -0
  120. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  121. package/dist/utils/builtinSubagents.js +65 -0
  122. package/dist/utils/cacheControlUtils.d.ts +8 -33
  123. package/dist/utils/cacheControlUtils.d.ts.map +1 -1
  124. package/dist/utils/cacheControlUtils.js +83 -126
  125. package/dist/utils/constants.d.ts +0 -12
  126. package/dist/utils/constants.d.ts.map +1 -1
  127. package/dist/utils/constants.js +1 -13
  128. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  129. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  130. package/dist/utils/convertMessagesForAPI.js +33 -14
  131. package/dist/utils/fileSearch.d.ts +14 -0
  132. package/dist/utils/fileSearch.d.ts.map +1 -0
  133. package/dist/utils/fileSearch.js +88 -0
  134. package/dist/utils/fileUtils.d.ts +14 -2
  135. package/dist/utils/fileUtils.d.ts.map +1 -1
  136. package/dist/utils/fileUtils.js +101 -17
  137. package/dist/utils/globalLogger.d.ts +0 -14
  138. package/dist/utils/globalLogger.d.ts.map +1 -1
  139. package/dist/utils/globalLogger.js +0 -16
  140. package/dist/utils/largeOutputHandler.d.ts +15 -0
  141. package/dist/utils/largeOutputHandler.d.ts.map +1 -0
  142. package/dist/utils/largeOutputHandler.js +40 -0
  143. package/dist/utils/markdownParser.d.ts.map +1 -1
  144. package/dist/utils/markdownParser.js +1 -17
  145. package/dist/utils/messageOperations.d.ts +1 -11
  146. package/dist/utils/messageOperations.d.ts.map +1 -1
  147. package/dist/utils/messageOperations.js +7 -24
  148. package/dist/utils/pathEncoder.d.ts +4 -0
  149. package/dist/utils/pathEncoder.d.ts.map +1 -1
  150. package/dist/utils/pathEncoder.js +16 -9
  151. package/dist/utils/subagentParser.d.ts +2 -2
  152. package/dist/utils/subagentParser.d.ts.map +1 -1
  153. package/dist/utils/subagentParser.js +10 -7
  154. package/dist/utils/tokenEstimator.d.ts +39 -0
  155. package/dist/utils/tokenEstimator.d.ts.map +1 -0
  156. package/dist/utils/tokenEstimator.js +55 -0
  157. package/package.json +5 -8
  158. package/src/agent.ts +460 -216
  159. package/src/index.ts +2 -0
  160. package/src/managers/aiManager.ts +107 -111
  161. package/src/managers/backgroundBashManager.ts +4 -3
  162. package/src/managers/hookManager.ts +44 -39
  163. package/src/managers/liveConfigManager.ts +524 -138
  164. package/src/managers/lspManager.ts +434 -0
  165. package/src/managers/messageManager.ts +73 -103
  166. package/src/managers/permissionManager.ts +276 -0
  167. package/src/managers/skillManager.ts +3 -1
  168. package/src/managers/slashCommandManager.ts +1 -2
  169. package/src/managers/subagentManager.ts +116 -159
  170. package/src/managers/toolManager.ts +95 -3
  171. package/src/services/aiService.ts +207 -26
  172. package/src/services/configurationService.ts +762 -0
  173. package/src/services/fileWatcher.ts +5 -6
  174. package/src/services/hook.ts +50 -631
  175. package/src/services/jsonlHandler.ts +84 -100
  176. package/src/services/memory.ts +2 -59
  177. package/src/services/session.ts +338 -213
  178. package/src/tools/bashTool.ts +89 -16
  179. package/src/tools/deleteFileTool.ts +36 -0
  180. package/src/tools/editTool.ts +41 -7
  181. package/src/tools/lspTool.ts +760 -0
  182. package/src/tools/multiEditTool.ts +37 -8
  183. package/src/tools/readTool.ts +125 -2
  184. package/src/tools/skillTool.ts +2 -2
  185. package/src/tools/todoWriteTool.ts +33 -1
  186. package/src/tools/types.ts +15 -9
  187. package/src/tools/writeTool.ts +36 -10
  188. package/src/types/commands.ts +0 -1
  189. package/src/types/config.ts +5 -0
  190. package/src/types/configuration.ts +73 -0
  191. package/src/types/core.ts +11 -0
  192. package/src/types/environment.ts +44 -0
  193. package/src/types/fileSearch.ts +4 -0
  194. package/src/types/hooks.ts +14 -11
  195. package/src/types/index.ts +5 -0
  196. package/src/types/lsp.ts +96 -0
  197. package/src/types/messaging.ts +8 -13
  198. package/src/types/permissions.ts +48 -0
  199. package/src/types/session.ts +3 -8
  200. package/src/types/skills.ts +1 -0
  201. package/src/types/tools.ts +38 -0
  202. package/src/utils/abortUtils.ts +118 -0
  203. package/src/utils/bashHistory.ts +28 -4
  204. package/src/utils/builtinSubagents.ts +71 -0
  205. package/src/utils/cacheControlUtils.ts +106 -171
  206. package/src/utils/constants.ts +1 -16
  207. package/src/utils/convertMessagesForAPI.ts +38 -14
  208. package/src/utils/fileSearch.ts +107 -0
  209. package/src/utils/fileUtils.ts +114 -19
  210. package/src/utils/globalLogger.ts +0 -17
  211. package/src/utils/largeOutputHandler.ts +55 -0
  212. package/src/utils/markdownParser.ts +1 -19
  213. package/src/utils/messageOperations.ts +7 -35
  214. package/src/utils/pathEncoder.ts +24 -9
  215. package/src/utils/subagentParser.ts +11 -8
  216. package/src/utils/tokenEstimator.ts +68 -0
  217. package/dist/constants/events.d.ts +0 -28
  218. package/dist/constants/events.d.ts.map +0 -1
  219. package/dist/constants/events.js +0 -27
  220. package/dist/services/configurationWatcher.d.ts +0 -120
  221. package/dist/services/configurationWatcher.d.ts.map +0 -1
  222. package/dist/services/configurationWatcher.js +0 -439
  223. package/dist/services/memoryStore.d.ts +0 -81
  224. package/dist/services/memoryStore.d.ts.map +0 -1
  225. package/dist/services/memoryStore.js +0 -200
  226. package/dist/types/memoryStore.d.ts +0 -82
  227. package/dist/types/memoryStore.d.ts.map +0 -1
  228. package/dist/types/memoryStore.js +0 -7
  229. package/dist/utils/configResolver.d.ts +0 -65
  230. package/dist/utils/configResolver.d.ts.map +0 -1
  231. package/dist/utils/configResolver.js +0 -210
  232. package/src/constants/events.ts +0 -38
  233. package/src/services/configurationWatcher.ts +0 -622
  234. package/src/services/memoryStore.ts +0 -279
  235. package/src/types/memoryStore.ts +0 -94
  236. package/src/utils/configResolver.ts +0 -302
@@ -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":"AAEA,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,7 +1,6 @@
1
1
  import { readFile, writeFile } from "fs/promises";
2
2
  import { logger } from "../utils/globalLogger.js";
3
3
  import { resolvePath, getDisplayPath } from "../utils/path.js";
4
- import { diffLines } from "diff";
5
4
  /**
6
5
  * Format compact parameter display
7
6
  */
@@ -151,7 +150,7 @@ export const multiEditTool = {
151
150
  return {
152
151
  success: false,
153
152
  content: "",
154
- 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`,
155
154
  };
156
155
  }
157
156
  let replacementCount;
@@ -176,6 +175,31 @@ export const multiEditTool = {
176
175
  appliedEdits.push(`Replaced "${edit.old_string.substring(0, 50)}${edit.old_string.length > 50 ? "..." : ""}"`);
177
176
  }
178
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
+ }
179
203
  // Write file
180
204
  try {
181
205
  await writeFile(resolvedPath, currentContent, "utf-8");
@@ -187,8 +211,6 @@ export const multiEditTool = {
187
211
  error: `Failed to write file: ${writeError instanceof Error ? writeError.message : String(writeError)}`,
188
212
  };
189
213
  }
190
- // Generate diff information
191
- const diffResult = diffLines(originalContent, currentContent);
192
214
  const shortResult = isNewFile
193
215
  ? `Created file with ${edits.length} operations`
194
216
  : `Applied ${edits.length} edits`;
@@ -199,9 +221,6 @@ export const multiEditTool = {
199
221
  content: detailedContent,
200
222
  shortResult,
201
223
  filePath: resolvedPath,
202
- originalContent,
203
- newContent: currentContent,
204
- diffResult,
205
224
  };
206
225
  }
207
226
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AAEA,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"}