wave-agent-sdk 0.7.1 → 0.8.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 (168) hide show
  1. package/dist/agent.d.ts +9 -79
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +85 -302
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +20 -13
  9. package/dist/managers/backgroundTaskManager.d.ts +1 -1
  10. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundTaskManager.js +1 -1
  12. package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
  13. package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
  14. package/dist/managers/{bashManager.js → bangManager.js} +5 -6
  15. package/dist/managers/hookManager.d.ts.map +1 -1
  16. package/dist/managers/hookManager.js +12 -3
  17. package/dist/managers/messageManager.d.ts +18 -6
  18. package/dist/managers/messageManager.d.ts.map +1 -1
  19. package/dist/managers/messageManager.js +42 -20
  20. package/dist/managers/permissionManager.d.ts +22 -1
  21. package/dist/managers/permissionManager.d.ts.map +1 -1
  22. package/dist/managers/permissionManager.js +106 -85
  23. package/dist/managers/planManager.d.ts +6 -0
  24. package/dist/managers/planManager.d.ts.map +1 -1
  25. package/dist/managers/planManager.js +21 -0
  26. package/dist/managers/skillManager.d.ts +7 -2
  27. package/dist/managers/skillManager.d.ts.map +1 -1
  28. package/dist/managers/skillManager.js +30 -10
  29. package/dist/managers/slashCommandManager.d.ts +7 -0
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +57 -45
  32. package/dist/managers/subagentManager.d.ts +4 -0
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +47 -13
  35. package/dist/managers/toolManager.d.ts +7 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +15 -2
  38. package/dist/prompts/index.d.ts +0 -4
  39. package/dist/prompts/index.d.ts.map +1 -1
  40. package/dist/prompts/index.js +0 -9
  41. package/dist/services/aiService.d.ts.map +1 -1
  42. package/dist/services/aiService.js +6 -6
  43. package/dist/services/configurationService.d.ts +2 -2
  44. package/dist/services/configurationService.d.ts.map +1 -1
  45. package/dist/services/configurationService.js +4 -4
  46. package/dist/services/hook.d.ts.map +1 -1
  47. package/dist/services/hook.js +6 -0
  48. package/dist/services/initializationService.d.ts +44 -0
  49. package/dist/services/initializationService.d.ts.map +1 -0
  50. package/dist/services/initializationService.js +170 -0
  51. package/dist/services/interactionService.d.ts +29 -0
  52. package/dist/services/interactionService.d.ts.map +1 -0
  53. package/dist/services/interactionService.js +97 -0
  54. package/dist/services/session.js +1 -1
  55. package/dist/services/taskManager.d.ts +5 -0
  56. package/dist/services/taskManager.d.ts.map +1 -1
  57. package/dist/services/taskManager.js +16 -2
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +7 -18
  60. package/dist/tools/editTool.js +1 -1
  61. package/dist/tools/exitPlanMode.js +1 -1
  62. package/dist/tools/lspTool.d.ts +2 -0
  63. package/dist/tools/lspTool.d.ts.map +1 -1
  64. package/dist/tools/lspTool.js +144 -52
  65. package/dist/tools/skillTool.d.ts.map +1 -1
  66. package/dist/tools/skillTool.js +97 -2
  67. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  68. package/dist/tools/taskManagementTools.js +23 -2
  69. package/dist/tools/taskTool.d.ts.map +1 -1
  70. package/dist/tools/taskTool.js +9 -15
  71. package/dist/tools/types.d.ts +1 -2
  72. package/dist/tools/types.d.ts.map +1 -1
  73. package/dist/tools/writeTool.js +1 -1
  74. package/dist/types/agent.d.ts +64 -0
  75. package/dist/types/agent.d.ts.map +1 -0
  76. package/dist/types/agent.js +1 -0
  77. package/dist/types/commands.d.ts +0 -4
  78. package/dist/types/commands.d.ts.map +1 -1
  79. package/dist/types/config.d.ts +1 -1
  80. package/dist/types/config.d.ts.map +1 -1
  81. package/dist/types/hooks.d.ts +3 -1
  82. package/dist/types/hooks.d.ts.map +1 -1
  83. package/dist/types/hooks.js +1 -0
  84. package/dist/types/index.d.ts +1 -0
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/index.js +1 -0
  87. package/dist/types/messaging.d.ts +3 -3
  88. package/dist/types/messaging.d.ts.map +1 -1
  89. package/dist/types/skills.d.ts +13 -0
  90. package/dist/types/skills.d.ts.map +1 -1
  91. package/dist/utils/commandPathResolver.d.ts +3 -36
  92. package/dist/utils/commandPathResolver.d.ts.map +1 -1
  93. package/dist/utils/commandPathResolver.js +16 -93
  94. package/dist/utils/configValidator.d.ts +2 -2
  95. package/dist/utils/configValidator.d.ts.map +1 -1
  96. package/dist/utils/configValidator.js +4 -6
  97. package/dist/utils/containerSetup.d.ts +3 -4
  98. package/dist/utils/containerSetup.d.ts.map +1 -1
  99. package/dist/utils/containerSetup.js +14 -9
  100. package/dist/utils/customCommands.d.ts +2 -3
  101. package/dist/utils/customCommands.d.ts.map +1 -1
  102. package/dist/utils/customCommands.js +20 -60
  103. package/dist/utils/gitUtils.d.ts +25 -0
  104. package/dist/utils/gitUtils.d.ts.map +1 -1
  105. package/dist/utils/gitUtils.js +75 -0
  106. package/dist/utils/markdownParser.d.ts +4 -0
  107. package/dist/utils/markdownParser.d.ts.map +1 -1
  108. package/dist/utils/markdownParser.js +33 -0
  109. package/dist/utils/messageOperations.d.ts +16 -7
  110. package/dist/utils/messageOperations.d.ts.map +1 -1
  111. package/dist/utils/messageOperations.js +45 -20
  112. package/dist/utils/nameGenerator.d.ts +1 -1
  113. package/dist/utils/nameGenerator.d.ts.map +1 -1
  114. package/dist/utils/nameGenerator.js +10 -6
  115. package/dist/utils/skillParser.d.ts.map +1 -1
  116. package/dist/utils/skillParser.js +48 -0
  117. package/package.json +1 -1
  118. package/src/agent.ts +103 -458
  119. package/src/index.ts +2 -2
  120. package/src/managers/aiManager.ts +23 -17
  121. package/src/managers/backgroundTaskManager.ts +2 -2
  122. package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
  123. package/src/managers/hookManager.ts +13 -3
  124. package/src/managers/messageManager.ts +55 -26
  125. package/src/managers/permissionManager.ts +121 -98
  126. package/src/managers/planManager.ts +26 -0
  127. package/src/managers/skillManager.ts +51 -14
  128. package/src/managers/slashCommandManager.ts +75 -55
  129. package/src/managers/subagentManager.ts +57 -13
  130. package/src/managers/toolManager.ts +22 -2
  131. package/src/prompts/index.ts +0 -15
  132. package/src/services/aiService.ts +9 -12
  133. package/src/services/configurationService.ts +4 -4
  134. package/src/services/hook.ts +7 -0
  135. package/src/services/initializationService.ts +291 -0
  136. package/src/services/interactionService.ts +171 -0
  137. package/src/services/session.ts +1 -1
  138. package/src/services/taskManager.ts +18 -2
  139. package/src/tools/bashTool.ts +8 -18
  140. package/src/tools/editTool.ts +1 -1
  141. package/src/tools/exitPlanMode.ts +1 -1
  142. package/src/tools/lsTool.ts +1 -1
  143. package/src/tools/lspTool.ts +184 -52
  144. package/src/tools/skillTool.ts +127 -2
  145. package/src/tools/taskManagementTools.ts +32 -2
  146. package/src/tools/taskTool.ts +13 -15
  147. package/src/tools/types.ts +1 -2
  148. package/src/tools/writeTool.ts +1 -1
  149. package/src/types/agent.ts +83 -0
  150. package/src/types/commands.ts +0 -6
  151. package/src/types/config.ts +1 -1
  152. package/src/types/hooks.ts +5 -1
  153. package/src/types/index.ts +1 -0
  154. package/src/types/messaging.ts +3 -3
  155. package/src/types/skills.ts +13 -0
  156. package/src/utils/commandPathResolver.ts +14 -117
  157. package/src/utils/configValidator.ts +5 -9
  158. package/src/utils/containerSetup.ts +17 -14
  159. package/src/utils/customCommands.ts +20 -83
  160. package/src/utils/gitUtils.ts +75 -0
  161. package/src/utils/markdownParser.ts +47 -0
  162. package/src/utils/messageOperations.ts +58 -28
  163. package/src/utils/nameGenerator.ts +10 -6
  164. package/src/utils/skillParser.ts +52 -0
  165. package/dist/managers/backgroundBashManager.d.ts +0 -27
  166. package/dist/managers/backgroundBashManager.d.ts.map +0 -1
  167. package/dist/managers/backgroundBashManager.js +0 -169
  168. package/src/managers/backgroundBashManager.ts +0 -206
@@ -14,6 +14,9 @@ import type {
14
14
  LspCallHierarchyOutgoingCall as CallHierarchyOutgoingCall,
15
15
  } from "../types/lsp.js";
16
16
 
17
+ export const MAX_RESULTS = 1000;
18
+ export const MAX_FILES = 100;
19
+
17
20
  /**
18
21
  * Formats an LSP URI into a readable file path
19
22
  */
@@ -126,10 +129,16 @@ function formatGoToDefinitionResult(
126
129
  return `Defined in ${formatLocation(validLocations[0], workdir)}`;
127
130
  }
128
131
 
129
- const formatted = validLocations
132
+ const shownLocations = validLocations.slice(0, MAX_RESULTS);
133
+ const formatted = shownLocations
130
134
  .map((loc) => ` ${formatLocation(loc, workdir)}`)
131
135
  .join("\n");
132
- return `Found ${validLocations.length} definitions:\n${formatted}`;
136
+
137
+ let header = `Found ${validLocations.length} definitions:`;
138
+ if (validLocations.length > MAX_RESULTS) {
139
+ header += ` (showing first ${MAX_RESULTS})`;
140
+ }
141
+ return `${header}\n${formatted}`;
133
142
  }
134
143
 
135
144
  const loc = isLocationLink(result) ? locationLinkToLocation(result) : result;
@@ -157,18 +166,42 @@ function formatFindReferencesResult(
157
166
  }
158
167
 
159
168
  const grouped = groupItemsByUri(validLocations, workdir);
160
- const lines = [
161
- `Found ${validLocations.length} references across ${grouped.size} files:`,
162
- ];
169
+ const totalResults = validLocations.length;
170
+ const totalFiles = grouped.size;
171
+
172
+ let resultsShown = 0;
173
+ let filesShown = 0;
174
+ const lines: string[] = [];
163
175
 
164
176
  for (const [path, locs] of grouped) {
177
+ if (resultsShown >= MAX_RESULTS || filesShown >= MAX_FILES) break;
178
+
179
+ filesShown++;
180
+ const remainingResults = MAX_RESULTS - resultsShown;
181
+ const locsToShow = locs.slice(0, remainingResults);
182
+ const isTruncated = locsToShow.length < locs.length;
183
+
165
184
  lines.push(`\n${path}:`);
166
- for (const loc of locs) {
185
+ for (const loc of locsToShow) {
167
186
  const line = loc.range.start.line + 1;
168
187
  const character = loc.range.start.character + 1;
169
188
  lines.push(` Line ${line}:${character}`);
170
189
  }
190
+
191
+ if (isTruncated) {
192
+ lines.push(
193
+ ` ... and ${locs.length - locsToShow.length} more in this file`,
194
+ );
195
+ }
196
+
197
+ resultsShown += locsToShow.length;
198
+ }
199
+
200
+ let header = `Found ${totalResults} references across ${totalFiles} files:`;
201
+ if (totalResults > resultsShown || totalFiles > filesShown) {
202
+ header += ` (showing first ${resultsShown} results and ${filesShown} files)`;
171
203
  }
204
+ lines.unshift(header);
172
205
 
173
206
  return lines.join("\n");
174
207
  }
@@ -243,23 +276,32 @@ function getSymbolKindName(kind: number): string {
243
276
  /**
244
277
  * Formats a single document symbol recursively
245
278
  */
246
- function formatDocumentSymbol(symbol: DocumentSymbol, depth = 0): string[] {
279
+ function formatDocumentSymbol(
280
+ symbol: DocumentSymbol,
281
+ state: { count: number; total: number },
282
+ depth = 0,
283
+ ): string[] {
284
+ state.total++;
247
285
  const results: string[] = [];
248
- const indent = " ".repeat(depth);
249
- const kindName = getSymbolKindName(symbol.kind);
250
- let line = `${indent}${symbol.name} (${kindName})`;
251
286
 
252
- if (symbol.detail) {
253
- line += ` ${symbol.detail}`;
254
- }
287
+ if (state.count < MAX_RESULTS) {
288
+ const indent = " ".repeat(depth);
289
+ const kindName = getSymbolKindName(symbol.kind);
290
+ let line = `${indent}${symbol.name} (${kindName})`;
291
+
292
+ if (symbol.detail) {
293
+ line += ` ${symbol.detail}`;
294
+ }
255
295
 
256
- const startLine = symbol.range.start.line + 1;
257
- line += ` - Line ${startLine}`;
258
- results.push(line);
296
+ const startLine = symbol.range.start.line + 1;
297
+ line += ` - Line ${startLine}`;
298
+ results.push(line);
299
+ state.count++;
300
+ }
259
301
 
260
302
  if (symbol.children && symbol.children.length > 0) {
261
303
  for (const child of symbol.children) {
262
- results.push(...formatDocumentSymbol(child, depth + 1));
304
+ results.push(...formatDocumentSymbol(child, state, depth + 1));
263
305
  }
264
306
  }
265
307
 
@@ -282,10 +324,18 @@ function formatDocumentSymbolResult(
282
324
  return formatWorkspaceSymbolResult(result as SymbolInformation[], workdir);
283
325
  }
284
326
 
285
- const lines = ["Document symbols:"];
327
+ const state = { count: 0, total: 0 };
328
+ const lines: string[] = [];
286
329
  for (const symbol of result as DocumentSymbol[]) {
287
- lines.push(...formatDocumentSymbol(symbol));
330
+ lines.push(...formatDocumentSymbol(symbol, state));
288
331
  }
332
+
333
+ let header = "Document symbols:";
334
+ if (state.total > MAX_RESULTS) {
335
+ header += ` (showing first ${MAX_RESULTS} of ${state.total})`;
336
+ }
337
+ lines.unshift(header);
338
+
289
339
  return lines.join("\n");
290
340
  }
291
341
 
@@ -305,14 +355,24 @@ function formatWorkspaceSymbolResult(
305
355
  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.";
306
356
  }
307
357
 
308
- const lines = [
309
- `Found ${validSymbols.length} symbol${validSymbols.length === 1 ? "" : "s"} in workspace:`,
310
- ];
311
358
  const grouped = groupItemsByUri(validSymbols, workdir);
359
+ const totalResults = validSymbols.length;
360
+ const totalFiles = grouped.size;
361
+
362
+ let resultsShown = 0;
363
+ let filesShown = 0;
364
+ const lines: string[] = [];
312
365
 
313
366
  for (const [path, symbols] of grouped) {
367
+ if (resultsShown >= MAX_RESULTS || filesShown >= MAX_FILES) break;
368
+
369
+ filesShown++;
370
+ const remainingResults = MAX_RESULTS - resultsShown;
371
+ const symbolsToShow = symbols.slice(0, remainingResults);
372
+ const isTruncated = symbolsToShow.length < symbols.length;
373
+
314
374
  lines.push(`\n${path}:`);
315
- for (const s of symbols) {
375
+ for (const s of symbolsToShow) {
316
376
  const kindName = getSymbolKindName(s.kind);
317
377
  const startLine = s.location.range.start.line + 1;
318
378
  let line = ` ${s.name} (${kindName}) - Line ${startLine}`;
@@ -321,7 +381,21 @@ function formatWorkspaceSymbolResult(
321
381
  }
322
382
  lines.push(line);
323
383
  }
384
+
385
+ if (isTruncated) {
386
+ lines.push(
387
+ ` ... and ${symbols.length - symbolsToShow.length} more in this file`,
388
+ );
389
+ }
390
+
391
+ resultsShown += symbolsToShow.length;
392
+ }
393
+
394
+ let header = `Found ${totalResults} symbol${totalResults === 1 ? "" : "s"} in workspace:`;
395
+ if (totalResults > resultsShown || totalFiles > filesShown) {
396
+ header += ` (showing first ${resultsShown} results and ${filesShown} files)`;
324
397
  }
398
+ lines.unshift(header);
325
399
 
326
400
  return lines.join("\n");
327
401
  }
@@ -364,10 +438,18 @@ function formatPrepareCallHierarchyResult(
364
438
  return `Call hierarchy item: ${formatCallHierarchyItem(result[0], workdir)}`;
365
439
  }
366
440
 
367
- const lines = [`Found ${result.length} call hierarchy items:`];
368
- for (const item of result) {
441
+ const shownItems = result.slice(0, MAX_RESULTS);
442
+ const lines: string[] = [];
443
+ for (const item of shownItems) {
369
444
  lines.push(` ${formatCallHierarchyItem(item, workdir)}`);
370
445
  }
446
+
447
+ let header = `Found ${result.length} call hierarchy items:`;
448
+ if (result.length > MAX_RESULTS) {
449
+ header += ` (showing first ${MAX_RESULTS})`;
450
+ }
451
+ lines.unshift(header);
452
+
371
453
  return lines.join("\n");
372
454
  }
373
455
 
@@ -382,10 +464,8 @@ function formatIncomingCallsResult(
382
464
  return "No incoming calls found (nothing calls this function)";
383
465
  }
384
466
 
385
- const lines = [
386
- `Found ${result.length} incoming call${result.length === 1 ? "" : "s"}:`,
387
- ];
388
467
  const grouped = new Map<string, CallHierarchyIncomingCall[]>();
468
+ const totalResults = result.length;
389
469
 
390
470
  for (const call of result) {
391
471
  if (!call.from) {
@@ -403,9 +483,21 @@ function formatIncomingCallsResult(
403
483
  }
404
484
  }
405
485
 
486
+ const totalFiles = grouped.size;
487
+ let resultsShown = 0;
488
+ let filesShown = 0;
489
+ const lines: string[] = [];
490
+
406
491
  for (const [path, calls] of grouped) {
492
+ if (resultsShown >= MAX_RESULTS || filesShown >= MAX_FILES) break;
493
+
494
+ filesShown++;
495
+ const remainingResults = MAX_RESULTS - resultsShown;
496
+ const callsToShow = calls.slice(0, remainingResults);
497
+ const isTruncated = callsToShow.length < calls.length;
498
+
407
499
  lines.push(`\n${path}:`);
408
- for (const call of calls) {
500
+ for (const call of callsToShow) {
409
501
  if (!call.from) continue;
410
502
  const kindName = getSymbolKindName(call.from.kind);
411
503
  const startLine = call.from.range.start.line + 1;
@@ -419,8 +511,22 @@ function formatIncomingCallsResult(
419
511
  }
420
512
  lines.push(line);
421
513
  }
514
+
515
+ if (isTruncated) {
516
+ lines.push(
517
+ ` ... and ${calls.length - callsToShow.length} more in this file`,
518
+ );
519
+ }
520
+
521
+ resultsShown += callsToShow.length;
422
522
  }
423
523
 
524
+ let header = `Found ${totalResults} incoming call${totalResults === 1 ? "" : "s"}:`;
525
+ if (totalResults > resultsShown || totalFiles > filesShown) {
526
+ header += ` (showing first ${resultsShown} results and ${filesShown} files)`;
527
+ }
528
+ lines.unshift(header);
529
+
424
530
  return lines.join("\n");
425
531
  }
426
532
 
@@ -435,10 +541,8 @@ function formatOutgoingCallsResult(
435
541
  return "No outgoing calls found (this function calls nothing)";
436
542
  }
437
543
 
438
- const lines = [
439
- `Found ${result.length} outgoing call${result.length === 1 ? "" : "s"}:`,
440
- ];
441
544
  const grouped = new Map<string, CallHierarchyOutgoingCall[]>();
545
+ const totalResults = result.length;
442
546
 
443
547
  for (const call of result) {
444
548
  if (!call.to) {
@@ -456,9 +560,21 @@ function formatOutgoingCallsResult(
456
560
  }
457
561
  }
458
562
 
563
+ const totalFiles = grouped.size;
564
+ let resultsShown = 0;
565
+ let filesShown = 0;
566
+ const lines: string[] = [];
567
+
459
568
  for (const [path, calls] of grouped) {
569
+ if (resultsShown >= MAX_RESULTS || filesShown >= MAX_FILES) break;
570
+
571
+ filesShown++;
572
+ const remainingResults = MAX_RESULTS - resultsShown;
573
+ const callsToShow = calls.slice(0, remainingResults);
574
+ const isTruncated = callsToShow.length < calls.length;
575
+
460
576
  lines.push(`\n${path}:`);
461
- for (const call of calls) {
577
+ for (const call of callsToShow) {
462
578
  if (!call.to) continue;
463
579
  const kindName = getSymbolKindName(call.to.kind);
464
580
  const startLine = call.to.range.start.line + 1;
@@ -472,7 +588,21 @@ function formatOutgoingCallsResult(
472
588
  }
473
589
  lines.push(line);
474
590
  }
591
+
592
+ if (isTruncated) {
593
+ lines.push(
594
+ ` ... and ${calls.length - callsToShow.length} more in this file`,
595
+ );
596
+ }
597
+
598
+ resultsShown += callsToShow.length;
599
+ }
600
+
601
+ let header = `Found ${totalResults} outgoing call${totalResults === 1 ? "" : "s"}:`;
602
+ if (totalResults > resultsShown || totalFiles > filesShown) {
603
+ header += ` (showing first ${resultsShown} results and ${filesShown} files)`;
475
604
  }
605
+ lines.unshift(header);
476
606
 
477
607
  return lines.join("\n");
478
608
  }
@@ -486,25 +616,7 @@ export const lspTool: ToolPlugin = {
486
616
  type: "function",
487
617
  function: {
488
618
  name: LSP_TOOL_NAME,
489
- description: `Interact with Language Server Protocol (LSP) servers to get code intelligence features.
490
-
491
- Supported operations:
492
- - goToDefinition: Find where a symbol is defined
493
- - findReferences: Find all references to a symbol
494
- - hover: Get hover information (documentation, type info) for a symbol
495
- - documentSymbol: Get all symbols (functions, classes, variables) in a document
496
- - workspaceSymbol: Search for symbols across the entire workspace
497
- - goToImplementation: Find implementations of an interface or abstract method
498
- - prepareCallHierarchy: Get call hierarchy item at a position (functions/methods)
499
- - incomingCalls: Find all functions/methods that call the function at a position
500
- - outgoingCalls: Find all functions/methods called by the function at a position
501
-
502
- All operations require:
503
- - filePath: The file to operate on
504
- - line: The line number (1-based, as shown in editors)
505
- - character: The character offset (1-based, as shown in editors)
506
-
507
- Note: LSP servers must be configured for the file type. If no server is available, an error will be returned.`,
619
+ description: `Interact with Language Server Protocol (LSP) servers to get code intelligence features.`,
508
620
  parameters: {
509
621
  type: "object",
510
622
  properties: {
@@ -540,6 +652,26 @@ Note: LSP servers must be configured for the file type. If no server is availabl
540
652
  },
541
653
  },
542
654
  },
655
+ prompt:
656
+ () => `Interact with Language Server Protocol (LSP) servers to get code intelligence features.
657
+
658
+ Supported operations:
659
+ - goToDefinition: Find where a symbol is defined
660
+ - findReferences: Find all references to a symbol
661
+ - hover: Get hover information (documentation, type info) for a symbol
662
+ - documentSymbol: Get all symbols (functions, classes, variables) in a document
663
+ - workspaceSymbol: Search for symbols across the entire workspace
664
+ - goToImplementation: Find implementations of an interface or abstract method
665
+ - prepareCallHierarchy: Get call hierarchy item at a position (functions/methods)
666
+ - incomingCalls: Find all functions/methods that call the function at a position
667
+ - outgoingCalls: Find all functions/methods called by the function at a position
668
+
669
+ All operations require:
670
+ - filePath: The file to operate on
671
+ - line: The line number (1-based, as shown in editors)
672
+ - character: The character offset (1-based, as shown in editors)
673
+
674
+ Note: LSP servers must be configured for the file type. If no server is available, an error will be returned.`,
543
675
  execute: async (
544
676
  args: Record<string, unknown>,
545
677
  context: ToolContext,
@@ -1,6 +1,12 @@
1
1
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
2
2
  import { SKILL_TOOL_NAME } from "../constants/tools.js";
3
+ import { GENERAL_PURPOSE_SUBAGENT_TYPE } from "../constants/subagents.js";
3
4
  import type { SkillMetadata } from "../types/skills.js";
5
+ import { logger } from "../utils/globalLogger.js";
6
+ import {
7
+ countToolBlocks,
8
+ formatToolTokenSummary,
9
+ } from "../utils/messageOperations.js";
4
10
 
5
11
  /**
6
12
  * Skill tool plugin for invoking Wave skills
@@ -20,6 +26,10 @@ export const skillTool: ToolPlugin = {
20
26
  type: "string",
21
27
  description: "Name of the skill to invoke",
22
28
  },
29
+ args: {
30
+ type: "string",
31
+ description: "Optional arguments to pass to the skill",
32
+ },
23
33
  },
24
34
  required: ["skill_name"],
25
35
  },
@@ -27,7 +37,9 @@ export const skillTool: ToolPlugin = {
27
37
  },
28
38
 
29
39
  prompt: (args?: { availableSkills?: SkillMetadata[] }) => {
30
- const availableSkills = args?.availableSkills;
40
+ const availableSkills = args?.availableSkills?.filter(
41
+ (skill) => !skill.disableModelInvocation,
42
+ );
31
43
  if (!availableSkills || availableSkills.length === 0) {
32
44
  return "Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific. No skills are currently available.";
33
45
  }
@@ -57,6 +69,8 @@ export const skillTool: ToolPlugin = {
57
69
 
58
70
  // Validate arguments
59
71
  const skillName = args.skill_name as string;
72
+ const skillArgs = args.args as string | undefined;
73
+
60
74
  if (!skillName || typeof skillName !== "string") {
61
75
  return {
62
76
  success: false,
@@ -65,11 +79,122 @@ export const skillTool: ToolPlugin = {
65
79
  };
66
80
  }
67
81
 
68
- // Execute the skill
82
+ const skillMetadata = skillManager.getSkillMetadata(skillName);
83
+
84
+ if (skillMetadata?.disableModelInvocation) {
85
+ return {
86
+ success: false,
87
+ content: "",
88
+ error: `Skill "${skillName}" is not available for model invocation.`,
89
+ };
90
+ }
91
+
92
+ // Handle fork context
93
+ if (skillMetadata?.context === "fork") {
94
+ const subagentManager = context.subagentManager;
95
+ if (!subagentManager) {
96
+ return {
97
+ success: false,
98
+ content: "",
99
+ error: "Subagent manager not available in tool context",
100
+ };
101
+ }
102
+
103
+ const agentType = skillMetadata.agent || GENERAL_PURPOSE_SUBAGENT_TYPE;
104
+ const configuration = await subagentManager.findSubagent(agentType);
105
+
106
+ if (!configuration) {
107
+ return {
108
+ success: false,
109
+ content: "",
110
+ error: `No subagent found matching "${agentType}" for skill "${skillName}"`,
111
+ };
112
+ }
113
+
114
+ // Execute the skill to get the content
115
+ const skillResult = await skillManager.executeSkill({
116
+ skill_name: skillName,
117
+ args: skillArgs,
118
+ });
119
+
120
+ logger.debug(`Skill ${skillName} executed, allowedTools:`, {
121
+ allowedTools: skillResult.allowedTools,
122
+ });
123
+
124
+ // Create subagent instance
125
+ const instance = await subagentManager.createInstance(
126
+ configuration,
127
+ {
128
+ description: `Skill: ${skillName}`,
129
+ prompt: skillResult.content,
130
+ subagent_type: agentType,
131
+ allowedTools: skillResult.allowedTools,
132
+ model: skillMetadata.model,
133
+ },
134
+ false, // run_in_background
135
+ () => {
136
+ // Update shortResult
137
+ const messages = instance.messageManager.getMessages();
138
+ const tokens = instance.messageManager.getlatestTotalTokens();
139
+ const lastTools = instance.lastTools;
140
+
141
+ const toolCount = countToolBlocks(messages);
142
+ const summary = formatToolTokenSummary(toolCount, tokens);
143
+
144
+ let shortResult = "";
145
+ if (toolCount > 2) {
146
+ shortResult += "... ";
147
+ }
148
+ if (lastTools.length > 0) {
149
+ shortResult += `${lastTools.join(", ")} `;
150
+ }
151
+ shortResult += summary;
152
+
153
+ context.onShortResultUpdate?.(shortResult);
154
+ },
155
+ );
156
+
157
+ try {
158
+ const result = await subagentManager.executeTask(
159
+ instance,
160
+ skillResult.content,
161
+ context.abortSignal,
162
+ false,
163
+ );
164
+
165
+ // Cleanup subagent instance after task completion
166
+ subagentManager.cleanupInstance(instance.subagentId);
167
+
168
+ const messages = instance.messageManager.getMessages();
169
+ const tokens = instance.messageManager.getlatestTotalTokens();
170
+ const toolCount = countToolBlocks(messages);
171
+ const summary = formatToolTokenSummary(toolCount, tokens);
172
+
173
+ return {
174
+ success: true,
175
+ content: result,
176
+ shortResult: `Invoked skill: ${skillName}${summary ? ` ${summary}` : ""}`,
177
+ };
178
+ } catch (error) {
179
+ return {
180
+ success: false,
181
+ content: "",
182
+ error: `Skill fork failed: ${error instanceof Error ? error.message : String(error)}`,
183
+ };
184
+ }
185
+ }
186
+
187
+ // Standard execution
69
188
  const result = await skillManager.executeSkill({
70
189
  skill_name: skillName,
190
+ args: skillArgs,
71
191
  });
72
192
 
193
+ // Add temporary rules if allowedTools are present
194
+ if (result.allowedTools && result.allowedTools.length > 0) {
195
+ context.permissionManager?.addTemporaryRules(result.allowedTools);
196
+ }
197
+
73
198
  return {
74
199
  success: true,
75
200
  content: result.content,
@@ -116,11 +116,12 @@ NOTE that you should not use this tool if there is only one trivial task to do.
116
116
 
117
117
  if (context.reversionManager && context.messageId) {
118
118
  const taskPath = taskManager.getTaskPath(taskId);
119
- await context.reversionManager.recordSnapshot(
119
+ const snapshotId = await context.reversionManager.recordSnapshot(
120
120
  context.messageId,
121
121
  taskPath,
122
122
  "create",
123
123
  );
124
+ await context.reversionManager.commitSnapshot(snapshotId);
124
125
  }
125
126
 
126
127
  return {
@@ -333,9 +334,10 @@ Set up task dependencies:
333
334
  };
334
335
  }
335
336
 
337
+ let snapshotId: string | undefined;
336
338
  if (context.reversionManager && context.messageId) {
337
339
  const taskPath = taskManager.getTaskPath(taskId);
338
- await context.reversionManager.recordSnapshot(
340
+ snapshotId = await context.reversionManager.recordSnapshot(
339
341
  context.messageId,
340
342
  taskPath,
341
343
  "modify",
@@ -402,10 +404,22 @@ Set up task dependencies:
402
404
  for (const targetId of blocksToAdd) {
403
405
  const targetTask = await taskManager.getTask(targetId);
404
406
  if (targetTask && !targetTask.blockedBy.includes(taskId)) {
407
+ let targetSnapshotId: string | undefined;
408
+ if (context.reversionManager && context.messageId) {
409
+ const targetPath = taskManager.getTaskPath(targetId);
410
+ targetSnapshotId = await context.reversionManager.recordSnapshot(
411
+ context.messageId,
412
+ targetPath,
413
+ "modify",
414
+ );
415
+ }
405
416
  await taskManager.updateTask({
406
417
  ...targetTask,
407
418
  blockedBy: [...targetTask.blockedBy, taskId],
408
419
  });
420
+ if (context.reversionManager && targetSnapshotId) {
421
+ await context.reversionManager.commitSnapshot(targetSnapshotId);
422
+ }
409
423
  }
410
424
  }
411
425
  }
@@ -423,10 +437,22 @@ Set up task dependencies:
423
437
  for (const targetId of blockedByToAdd) {
424
438
  const targetTask = await taskManager.getTask(targetId);
425
439
  if (targetTask && !targetTask.blocks.includes(taskId)) {
440
+ let targetSnapshotId: string | undefined;
441
+ if (context.reversionManager && context.messageId) {
442
+ const targetPath = taskManager.getTaskPath(targetId);
443
+ targetSnapshotId = await context.reversionManager.recordSnapshot(
444
+ context.messageId,
445
+ targetPath,
446
+ "modify",
447
+ );
448
+ }
426
449
  await taskManager.updateTask({
427
450
  ...targetTask,
428
451
  blocks: [...targetTask.blocks, taskId],
429
452
  });
453
+ if (context.reversionManager && targetSnapshotId) {
454
+ await context.reversionManager.commitSnapshot(targetSnapshotId);
455
+ }
430
456
  }
431
457
  }
432
458
  }
@@ -434,6 +460,10 @@ Set up task dependencies:
434
460
 
435
461
  await taskManager.updateTask(updatedTask);
436
462
 
463
+ if (context.reversionManager && snapshotId) {
464
+ await context.reversionManager.commitSnapshot(snapshotId);
465
+ }
466
+
437
467
  let content = `Updated task #${taskId} ${updatedFields.join(", ")}`;
438
468
  if (updatedTask.status === "completed") {
439
469
  content += `\n\nTask completed. Call TaskList now to find your next available task or see if your work unblocked others.`;
@@ -2,6 +2,10 @@ import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
2
2
  import { EXPLORE_SUBAGENT_TYPE } from "../constants/subagents.js";
3
3
  import { TASK_TOOL_NAME } from "../constants/tools.js";
4
4
  import type { SubagentConfiguration } from "../utils/subagentParser.js";
5
+ import {
6
+ countToolBlocks,
7
+ formatToolTokenSummary,
8
+ } from "../utils/messageOperations.js";
5
9
 
6
10
  /**
7
11
  * Task tool plugin for delegating tasks to specialized subagents
@@ -141,15 +145,8 @@ ${subagentList || "No subagents configured"}
141
145
  const tokens = instance.messageManager.getlatestTotalTokens();
142
146
  const lastTools = instance.lastTools;
143
147
 
144
- // Count tool blocks in messages
145
- let toolCount = 0;
146
- messages.forEach((msg) => {
147
- msg.blocks.forEach((block) => {
148
- if (block.type === "tool") {
149
- toolCount++;
150
- }
151
- });
152
- });
148
+ const toolCount = countToolBlocks(messages);
149
+ const summary = formatToolTokenSummary(toolCount, tokens);
153
150
 
154
151
  let shortResult = "";
155
152
  if (toolCount > 2) {
@@ -159,11 +156,7 @@ ${subagentList || "No subagents configured"}
159
156
  shortResult += `${lastTools.join(", ")} `;
160
157
  }
161
158
 
162
- shortResult += `(${toolCount} tools`;
163
- if (tokens > 0) {
164
- shortResult += ` | ${tokens.toLocaleString()} tokens`;
165
- }
166
- shortResult += ")";
159
+ shortResult += summary;
167
160
 
168
161
  context.onShortResultUpdate?.(shortResult);
169
162
  },
@@ -214,10 +207,15 @@ ${subagentList || "No subagents configured"}
214
207
  // Cleanup subagent instance after task completion
215
208
  subagentManager.cleanupInstance(instance.subagentId);
216
209
 
210
+ const messages = instance.messageManager.getMessages();
211
+ const tokens = instance.messageManager.getlatestTotalTokens();
212
+ const toolCount = countToolBlocks(messages);
213
+ const summary = formatToolTokenSummary(toolCount, tokens);
214
+
217
215
  return {
218
216
  success: true,
219
217
  content: result,
220
- shortResult: `Task completed by ${configuration.name}`,
218
+ shortResult: `Task completed${summary ? ` ${summary}` : ""}`,
221
219
  };
222
220
  } finally {
223
221
  if (!run_in_background && context.foregroundTaskManager) {
@@ -23,7 +23,7 @@ export interface ToolPlugin {
23
23
  context: ToolContext,
24
24
  ) => string;
25
25
  /**
26
- * Optional function to provide a prompt to be added to the system prompt
26
+ * Function to provide a prompt to be added to the tool description
27
27
  */
28
28
  prompt?: (args?: {
29
29
  availableSubagents?: SubagentConfiguration[];
@@ -53,7 +53,6 @@ export interface ToolResult {
53
53
 
54
54
  export interface ToolContext {
55
55
  abortSignal?: AbortSignal;
56
- backgroundBashManager?: import("../managers/backgroundBashManager.js").BackgroundBashManager;
57
56
  backgroundTaskManager?: import("../managers/backgroundTaskManager.js").BackgroundTaskManager;
58
57
  workdir: string;
59
58
  /** Permission mode for this tool execution */