wave-agent-sdk 1.0.5 → 1.0.6

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 (193) hide show
  1. package/dist/agent.d.ts +23 -1
  2. package/dist/agent.js +34 -4
  3. package/dist/managers/aiManager.d.ts +36 -0
  4. package/dist/managers/aiManager.js +240 -8
  5. package/dist/managers/messageManager.d.ts +1 -3
  6. package/dist/managers/messageManager.js +13 -6
  7. package/dist/managers/slashCommandManager.js +28 -0
  8. package/dist/managers/subagentManager.d.ts +0 -2
  9. package/dist/telemetry/instrumentation.d.ts +1 -1
  10. package/dist/telemetry/instrumentation.js +57 -28
  11. package/dist/tools/bashTool.js +16 -6
  12. package/dist/tools/grepTool.js +11 -3
  13. package/dist/types/index.d.ts +3 -0
  14. package/dist/types/messaging.d.ts +2 -0
  15. package/dist/utils/containerSetup.js +0 -3
  16. package/dist/utils/messageOperations.d.ts +2 -1
  17. package/dist/utils/messageOperations.js +2 -1
  18. package/dist/utils/notificationXml.js +5 -0
  19. package/dist/utils/ripgrep.d.ts +4 -4
  20. package/dist/utils/ripgrep.js +4 -27
  21. package/package.json +20 -8
  22. package/bin/rg +0 -79
  23. package/dist/managers/forkedAgentManager.d.ts +0 -50
  24. package/dist/managers/forkedAgentManager.js +0 -130
  25. package/scripts/install_ripgrep.js +0 -111
  26. package/scripts/postinstall.js +0 -38
  27. package/src/agent.ts +0 -1271
  28. package/src/constants/subagents.ts +0 -4
  29. package/src/constants/toolLimits.ts +0 -15
  30. package/src/constants/tools.ts +0 -24
  31. package/src/core/plugin.ts +0 -237
  32. package/src/core/session.ts +0 -9
  33. package/src/index.ts +0 -38
  34. package/src/managers/MemoryRuleManager.ts +0 -198
  35. package/src/managers/aiManager.ts +0 -2429
  36. package/src/managers/backgroundTaskManager.ts +0 -480
  37. package/src/managers/bangManager.ts +0 -119
  38. package/src/managers/cronManager.ts +0 -401
  39. package/src/managers/foregroundTaskManager.ts +0 -30
  40. package/src/managers/forkedAgentManager.ts +0 -216
  41. package/src/managers/hookManager.ts +0 -1089
  42. package/src/managers/liveConfigManager.ts +0 -445
  43. package/src/managers/lspManager.ts +0 -470
  44. package/src/managers/mcpManager.ts +0 -1010
  45. package/src/managers/messageManager.ts +0 -1184
  46. package/src/managers/messageQueue.ts +0 -157
  47. package/src/managers/permissionManager.ts +0 -1140
  48. package/src/managers/planManager.ts +0 -112
  49. package/src/managers/pluginManager.ts +0 -330
  50. package/src/managers/pluginScopeManager.ts +0 -124
  51. package/src/managers/reversionManager.ts +0 -178
  52. package/src/managers/skillManager.ts +0 -578
  53. package/src/managers/slashCommandManager.ts +0 -564
  54. package/src/managers/subagentManager.ts +0 -915
  55. package/src/managers/toolManager.ts +0 -489
  56. package/src/managers/workflowManager.ts +0 -493
  57. package/src/prompts/autoMemory.ts +0 -33
  58. package/src/prompts/autoMemoryExtraction.ts +0 -146
  59. package/src/prompts/index.ts +0 -506
  60. package/src/prompts/planModeReminders.ts +0 -126
  61. package/src/services/GitService.ts +0 -131
  62. package/src/services/MarketplaceService.ts +0 -1052
  63. package/src/services/MemoryRuleService.ts +0 -71
  64. package/src/services/aiService.ts +0 -919
  65. package/src/services/authService.ts +0 -565
  66. package/src/services/autoMemoryService.ts +0 -280
  67. package/src/services/configurationService.ts +0 -1520
  68. package/src/services/fileWatcher.ts +0 -319
  69. package/src/services/hook.ts +0 -348
  70. package/src/services/initializationService.ts +0 -357
  71. package/src/services/interactionService.ts +0 -229
  72. package/src/services/jsonlHandler.ts +0 -295
  73. package/src/services/memory.ts +0 -234
  74. package/src/services/pluginLoader.ts +0 -252
  75. package/src/services/remoteSettingsService.ts +0 -366
  76. package/src/services/reversionService.ts +0 -122
  77. package/src/services/session.ts +0 -917
  78. package/src/services/taskManager.ts +0 -321
  79. package/src/telemetry/events.ts +0 -65
  80. package/src/telemetry/instrumentation.ts +0 -499
  81. package/src/telemetry/sessionTracing.ts +0 -348
  82. package/src/tools/agentTool.ts +0 -322
  83. package/src/tools/askUserQuestion.ts +0 -160
  84. package/src/tools/bashTool.ts +0 -621
  85. package/src/tools/buildTool.ts +0 -61
  86. package/src/tools/cronCreateTool.ts +0 -161
  87. package/src/tools/cronDeleteTool.ts +0 -51
  88. package/src/tools/cronListTool.ts +0 -47
  89. package/src/tools/editTool.ts +0 -313
  90. package/src/tools/enterPlanMode.ts +0 -124
  91. package/src/tools/enterWorktreeTool.ts +0 -190
  92. package/src/tools/exitPlanMode.ts +0 -139
  93. package/src/tools/exitWorktreeTool.ts +0 -236
  94. package/src/tools/globTool.ts +0 -167
  95. package/src/tools/grepTool.ts +0 -399
  96. package/src/tools/lspTool.ts +0 -883
  97. package/src/tools/readTool.ts +0 -426
  98. package/src/tools/skillTool.ts +0 -248
  99. package/src/tools/taskManagementTools.ts +0 -574
  100. package/src/tools/taskStopTool.ts +0 -78
  101. package/src/tools/types.ts +0 -137
  102. package/src/tools/webFetchTool.ts +0 -373
  103. package/src/tools/workflowTool.ts +0 -205
  104. package/src/tools/writeTool.ts +0 -267
  105. package/src/types/agent.ts +0 -128
  106. package/src/types/auth.ts +0 -19
  107. package/src/types/commands.ts +0 -30
  108. package/src/types/config.ts +0 -43
  109. package/src/types/configuration.ts +0 -168
  110. package/src/types/core.ts +0 -105
  111. package/src/types/cron.ts +0 -13
  112. package/src/types/environment.ts +0 -106
  113. package/src/types/fileSearch.ts +0 -4
  114. package/src/types/history.ts +0 -7
  115. package/src/types/hooks.ts +0 -256
  116. package/src/types/index.ts +0 -41
  117. package/src/types/lsp.ts +0 -98
  118. package/src/types/marketplace.ts +0 -71
  119. package/src/types/mcp.ts +0 -43
  120. package/src/types/memoryRule.ts +0 -31
  121. package/src/types/messaging.ts +0 -114
  122. package/src/types/permissions.ts +0 -80
  123. package/src/types/plugins.ts +0 -39
  124. package/src/types/processes.ts +0 -99
  125. package/src/types/reversion.ts +0 -29
  126. package/src/types/session.ts +0 -12
  127. package/src/types/skills.ts +0 -108
  128. package/src/types/tasks.ts +0 -13
  129. package/src/types/telemetry.ts +0 -98
  130. package/src/types/tools.ts +0 -44
  131. package/src/types/workflow.ts +0 -6
  132. package/src/utils/abortUtils.ts +0 -118
  133. package/src/utils/atomicWrite.ts +0 -61
  134. package/src/utils/bashParser.ts +0 -899
  135. package/src/utils/cacheControlUtils.ts +0 -426
  136. package/src/utils/commandArgumentParser.ts +0 -161
  137. package/src/utils/commandPathResolver.ts +0 -88
  138. package/src/utils/configPaths.ts +0 -220
  139. package/src/utils/configValidator.ts +0 -100
  140. package/src/utils/constants.ts +0 -39
  141. package/src/utils/container.ts +0 -92
  142. package/src/utils/containerSetup.ts +0 -371
  143. package/src/utils/convertMessagesForAPI.ts +0 -326
  144. package/src/utils/cronTasks.ts +0 -128
  145. package/src/utils/cronTasksLock.ts +0 -182
  146. package/src/utils/cronToHuman.ts +0 -99
  147. package/src/utils/customCommands.ts +0 -95
  148. package/src/utils/editUtils.ts +0 -20
  149. package/src/utils/fileFormat.ts +0 -40
  150. package/src/utils/fileSearch.ts +0 -151
  151. package/src/utils/fileUtils.ts +0 -223
  152. package/src/utils/gitUtils.ts +0 -315
  153. package/src/utils/globalLogger.ts +0 -128
  154. package/src/utils/groupMessagesByApiRound.ts +0 -121
  155. package/src/utils/hookMatcher.ts +0 -176
  156. package/src/utils/markdownParser.ts +0 -317
  157. package/src/utils/mcpUtils.ts +0 -138
  158. package/src/utils/messageOperations.ts +0 -659
  159. package/src/utils/modelCapabilities.ts +0 -30
  160. package/src/utils/nameGenerator.ts +0 -99
  161. package/src/utils/notificationXml.ts +0 -57
  162. package/src/utils/openaiClient.ts +0 -251
  163. package/src/utils/parseCronExpression.ts +0 -78
  164. package/src/utils/path.ts +0 -72
  165. package/src/utils/pathEncoder.ts +0 -400
  166. package/src/utils/pathSafety.ts +0 -40
  167. package/src/utils/promptHistory.ts +0 -168
  168. package/src/utils/ripgrep.ts +0 -35
  169. package/src/utils/shellResolver.ts +0 -190
  170. package/src/utils/skillParser.ts +0 -246
  171. package/src/utils/stringUtils.ts +0 -156
  172. package/src/utils/subagentParser.ts +0 -279
  173. package/src/utils/taskReminder.ts +0 -96
  174. package/src/utils/tokenCalculation.ts +0 -43
  175. package/src/utils/tokenEstimate.ts +0 -34
  176. package/src/utils/toolResultStorage.ts +0 -117
  177. package/src/utils/worktreeSession.ts +0 -26
  178. package/src/utils/worktreeUtils.ts +0 -786
  179. package/src/workflow/budgetTracker.ts +0 -34
  180. package/src/workflow/concurrencyLimiter.ts +0 -47
  181. package/src/workflow/journal.ts +0 -95
  182. package/src/workflow/progressReporter.ts +0 -141
  183. package/src/workflow/runState.ts +0 -65
  184. package/src/workflow/scriptRuntime.ts +0 -274
  185. package/src/workflow/structuredOutput.ts +0 -123
  186. package/src/workflow/types.ts +0 -101
  187. package/src/workflow/workflowApis.ts +0 -410
  188. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  189. package/vendor/ripgrep/linux-x86_64/rg +0 -0
  190. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  191. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  192. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  193. package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
@@ -1,578 +0,0 @@
1
- import { readdir, stat } from "fs/promises";
2
- import { join } from "path";
3
- import { homedir } from "os";
4
- import { EventEmitter } from "events";
5
- import { FileWatcherService } from "../services/fileWatcher.js";
6
- import type {
7
- SkillManagerOptions,
8
- SkillMetadata,
9
- Skill,
10
- SkillCollection,
11
- SkillDiscoveryResult,
12
- SkillToolArgs,
13
- SkillInvocationContext,
14
- } from "../types/index.js";
15
- import { parseSkillFile, formatSkillError } from "../utils/skillParser.js";
16
- import { substituteCommandParameters } from "../utils/commandArgumentParser.js";
17
- import {
18
- parseBashCommands,
19
- replaceBashCommandsWithOutput,
20
- executeBashCommands,
21
- } from "../utils/markdownParser.js";
22
- import { getBuiltinSkillsDir } from "../utils/configPaths.js";
23
-
24
- import { Container } from "../utils/container.js";
25
- import { logger } from "../utils/globalLogger.js";
26
-
27
- /**
28
- * Manages skill discovery and loading
29
- */
30
- export class SkillManager extends EventEmitter {
31
- private personalSkillsPath: string;
32
- private personalClaudeSkillsPath: string;
33
- private personalAgentsSkillsPath: string;
34
- private scanTimeout: number;
35
- private workdir: string;
36
-
37
- private skillMetadata = new Map<string, SkillMetadata>();
38
- private skillContent = new Map<string, Skill>();
39
- private pluginSkillMetadata = new Map<string, SkillMetadata>();
40
- private pluginSkillContent = new Map<string, Skill>();
41
- private initialized = false;
42
- private fileWatcher: FileWatcherService | null = null;
43
- private watchEnabled: boolean;
44
-
45
- constructor(
46
- private container: Container,
47
- options: SkillManagerOptions = {},
48
- ) {
49
- super();
50
- this.personalSkillsPath =
51
- options.personalSkillsPath || join(homedir(), ".wave", "skills");
52
- this.personalClaudeSkillsPath =
53
- options.personalClaudeSkillsPath || join(homedir(), ".claude", "skills");
54
- this.personalAgentsSkillsPath =
55
- options.personalAgentsSkillsPath || join(homedir(), ".agents", "skills");
56
- this.scanTimeout = options.scanTimeout || 5000;
57
- this.workdir = options.workdir || process.cwd();
58
- this.watchEnabled = options.watch ?? false;
59
- }
60
-
61
- /**
62
- * Initialize the skill manager by discovering available skills
63
- */
64
- async initialize(): Promise<void> {
65
- logger?.debug("Initializing SkillManager...");
66
-
67
- try {
68
- await this.refreshSkills();
69
-
70
- if (this.watchEnabled && !this.fileWatcher) {
71
- await this.setupWatcher();
72
- }
73
-
74
- this.initialized = true;
75
- logger?.debug(
76
- `SkillManager initialized with ${this.skillMetadata.size} skills`,
77
- );
78
- } catch (error) {
79
- logger?.error("Failed to initialize SkillManager:", error);
80
- throw error;
81
- }
82
- }
83
-
84
- /**
85
- * Refresh skills by re-discovering them
86
- */
87
- private async refreshSkills(): Promise<void> {
88
- // Clear only discovered skills (builtin/personal/project), preserve plugin skills
89
- this.skillMetadata.clear();
90
- this.skillContent.clear();
91
-
92
- const discovery = await this.discoverSkills();
93
-
94
- // Store discovered skill metadata
95
- discovery.builtinSkills.forEach((skill, name) => {
96
- this.skillMetadata.set(name, skill);
97
- });
98
- discovery.personalSkills.forEach((skill, name) => {
99
- this.skillMetadata.set(name, skill);
100
- });
101
- discovery.projectSkills.forEach((skill, name) => {
102
- this.skillMetadata.set(name, skill);
103
- });
104
-
105
- // Restore plugin skills
106
- this.pluginSkillMetadata.forEach((metadata, name) => {
107
- this.skillMetadata.set(name, metadata);
108
- });
109
- this.pluginSkillContent.forEach((skill, name) => {
110
- this.skillContent.set(name, skill);
111
- });
112
-
113
- // Log any discovery errors
114
- if (discovery.errors.length > 0) {
115
- logger?.warn(`Found ${discovery.errors.length} skill discovery errors`);
116
- discovery.errors.forEach((error) => {
117
- logger?.warn(`Skill error in ${error.skillPath}: ${error.message}`);
118
- });
119
- }
120
-
121
- this.emit("refreshed", Array.from(this.skillMetadata.values()));
122
- }
123
-
124
- /**
125
- * Setup file watcher for skill directories
126
- */
127
- private async setupWatcher(): Promise<void> {
128
- if (this.fileWatcher) {
129
- await this.fileWatcher.cleanup();
130
- }
131
-
132
- this.fileWatcher = new FileWatcherService(logger);
133
-
134
- const pathsToWatch = [
135
- this.personalSkillsPath,
136
- this.personalClaudeSkillsPath,
137
- this.personalAgentsSkillsPath,
138
- join(this.workdir, ".wave", "skills"),
139
- join(this.workdir, ".claude", "skills"),
140
- join(this.workdir, ".agents", "skills"),
141
- ];
142
-
143
- logger?.debug(`Setting up skill watcher for: ${pathsToWatch.join(", ")}`);
144
-
145
- for (const pathToWatch of pathsToWatch) {
146
- await this.fileWatcher.watchFile(pathToWatch, async (event) => {
147
- if (
148
- event.path.endsWith("SKILL.md") ||
149
- event.type === "delete" ||
150
- event.type === "create"
151
- ) {
152
- logger?.debug(
153
- `Skill change detected (${event.type}): ${event.path}. Refreshing skills...`,
154
- );
155
- try {
156
- await this.refreshSkills();
157
- } catch (error) {
158
- logger?.error("Failed to refresh skills after change:", error);
159
- }
160
- }
161
- });
162
- }
163
- }
164
-
165
- /**
166
- * Cleanup resources
167
- */
168
- async destroy(): Promise<void> {
169
- if (this.fileWatcher) {
170
- await this.fileWatcher.cleanup();
171
- this.fileWatcher = null;
172
- }
173
- }
174
-
175
- /**
176
- * Check if the skill manager is initialized
177
- */
178
- isInitialized(): boolean {
179
- return this.initialized;
180
- }
181
-
182
- /**
183
- * Get all available skills metadata
184
- */
185
- getAvailableSkills(): SkillMetadata[] {
186
- if (!this.initialized) {
187
- throw new Error("SkillManager not initialized. Call initialize() first.");
188
- }
189
-
190
- return Array.from(this.skillMetadata.values());
191
- }
192
-
193
- /**
194
- * Get metadata for a specific skill by name
195
- */
196
- getSkillMetadata(name: string): SkillMetadata | undefined {
197
- if (!this.initialized) {
198
- throw new Error("SkillManager not initialized. Call initialize() first.");
199
- }
200
-
201
- return this.skillMetadata.get(name);
202
- }
203
-
204
- /**
205
- * Load a specific skill by name
206
- * Returns the skill content that was loaded during initialization
207
- */
208
- async loadSkill(skillName: string): Promise<Skill | null> {
209
- if (!this.initialized) {
210
- throw new Error("SkillManager not initialized. Call initialize() first.");
211
- }
212
-
213
- // Return skill content that was loaded during initialization
214
- const skill = this.skillContent.get(skillName);
215
- if (skill) {
216
- logger?.debug(`Skill '${skillName}' retrieved from loaded content`);
217
- return skill;
218
- }
219
-
220
- logger?.debug(`Skill '${skillName}' not found`);
221
- return null;
222
- }
223
-
224
- /**
225
- * Discover skills in builtin, personal and project directories
226
- */
227
- private async discoverSkills(): Promise<SkillDiscoveryResult> {
228
- const builtinCollection = await this.discoverSkillCollection(
229
- getBuiltinSkillsDir(),
230
- "builtin",
231
- );
232
-
233
- const personalAgentsCollection = await this.discoverSkillCollection(
234
- this.personalAgentsSkillsPath,
235
- "personal",
236
- );
237
-
238
- const personalClaudeCollection = await this.discoverSkillCollection(
239
- this.personalClaudeSkillsPath,
240
- "personal",
241
- );
242
-
243
- const personalCollection = await this.discoverSkillCollection(
244
- this.personalSkillsPath,
245
- "personal",
246
- );
247
-
248
- const projectCollection = await this.discoverSkillCollection(
249
- this.workdir,
250
- "project",
251
- );
252
-
253
- return {
254
- builtinSkills: builtinCollection.skills,
255
- personalSkills: new Map([
256
- ...personalAgentsCollection.skills, // lowest priority
257
- ...personalClaudeCollection.skills, // overrides .agents
258
- ...personalCollection.skills, // .wave overrides .claude
259
- ]),
260
- projectSkills: projectCollection.skills,
261
- errors: [
262
- ...builtinCollection.errors,
263
- ...personalAgentsCollection.errors,
264
- ...personalClaudeCollection.errors,
265
- ...personalCollection.errors,
266
- ...projectCollection.errors,
267
- ],
268
- };
269
- }
270
-
271
- /**
272
- * Discover skills in a specific directory
273
- */
274
- private async discoverSkillCollection(
275
- basePath: string,
276
- type: "personal" | "project" | "builtin",
277
- ): Promise<SkillCollection> {
278
- const collection: SkillCollection = {
279
- type,
280
- basePath,
281
- skills: new Map(),
282
- errors: [],
283
- };
284
-
285
- if (type === "project") {
286
- // Scan .agents/skills first, then .claude/skills, then .wave/skills (wave overrides)
287
- const agentsPath = join(basePath, ".agents", "skills");
288
- const claudePath = join(basePath, ".claude", "skills");
289
- const wavePath = join(basePath, ".wave", "skills");
290
- await this.scanSkillPath(agentsPath, collection);
291
- await this.scanSkillPath(claudePath, collection);
292
- await this.scanSkillPath(wavePath, collection);
293
- } else {
294
- await this.scanSkillPath(basePath, collection);
295
- }
296
-
297
- return collection;
298
- }
299
-
300
- private async scanSkillPath(
301
- skillsPath: string,
302
- collection: SkillCollection,
303
- ): Promise<void> {
304
- try {
305
- const skillDirs = await this.findSkillDirectories(skillsPath);
306
- logger?.debug(
307
- `Found ${skillDirs.length} potential skill directories in ${skillsPath}`,
308
- );
309
- await this.processSkillDirs(skillDirs, collection);
310
- } catch (error) {
311
- logger?.debug(
312
- `Could not scan ${skillsPath}: ${error instanceof Error ? error.message : String(error)}`,
313
- );
314
- }
315
- }
316
-
317
- private async processSkillDirs(
318
- skillDirs: string[],
319
- collection: SkillCollection,
320
- ): Promise<void> {
321
- for (const skillDir of skillDirs) {
322
- try {
323
- const skillFilePath = join(skillDir, "SKILL.md");
324
-
325
- // Check if SKILL.md exists
326
- try {
327
- await stat(skillFilePath);
328
- } catch {
329
- continue; // Skip directories without SKILL.md
330
- }
331
-
332
- const parsed = parseSkillFile(skillFilePath, {
333
- basePath: skillDir,
334
- validateMetadata: true,
335
- });
336
-
337
- if (parsed.isValid) {
338
- // Override the skill type with the collection type
339
- const skillMetadata: SkillMetadata = {
340
- ...parsed.skillMetadata,
341
- type: collection.type,
342
- };
343
-
344
- // Create full skill object with content
345
- const skill: Skill = {
346
- ...skillMetadata,
347
- content: parsed.content,
348
- frontmatter: parsed.frontmatter,
349
- isValid: parsed.isValid,
350
- errors: parsed.validationErrors,
351
- };
352
-
353
- collection.skills.set(skillMetadata.name, skillMetadata);
354
- // Store the full skill content in the manager's skillContent map
355
- this.skillContent.set(skillMetadata.name, skill);
356
- } else {
357
- collection.errors.push({
358
- skillPath: skillDir,
359
- message: parsed.validationErrors.join("; "),
360
- });
361
- }
362
- } catch (error) {
363
- collection.errors.push({
364
- skillPath: skillDir,
365
- message: `Failed to process skill: ${error instanceof Error ? error.message : String(error)}`,
366
- });
367
- }
368
- }
369
- }
370
-
371
- /**
372
- * Find all directories that could contain skills
373
- */
374
- private async findSkillDirectories(skillsPath: string): Promise<string[]> {
375
- const directories: string[] = [];
376
-
377
- try {
378
- const entries = await readdir(skillsPath, { withFileTypes: true });
379
-
380
- for (const entry of entries) {
381
- const fullPath = join(skillsPath, entry.name);
382
- if (entry.isDirectory()) {
383
- directories.push(fullPath);
384
- } else if (entry.isSymbolicLink()) {
385
- try {
386
- const s = await stat(fullPath);
387
- if (s.isDirectory()) {
388
- directories.push(fullPath);
389
- }
390
- } catch {
391
- // Ignore broken symlinks or other errors
392
- }
393
- }
394
- }
395
- } catch {
396
- // Directory doesn't exist - return empty array
397
- }
398
-
399
- return directories;
400
- }
401
-
402
- /**
403
- * Execute a skill by name
404
- */
405
- async executeSkill(args: SkillToolArgs): Promise<{
406
- content: string;
407
- context?: SkillInvocationContext;
408
- allowedTools?: string[];
409
- }> {
410
- const { skill_name } = args;
411
-
412
- logger?.debug(`Invoking skill: ${skill_name}`);
413
-
414
- const prepared = await this.prepareSkill(args);
415
- if (!prepared.skill) {
416
- return { content: prepared.content };
417
- }
418
-
419
- try {
420
- const finalContent = await this.executeBashInSkillContent(
421
- prepared.content,
422
- );
423
-
424
- return {
425
- content: finalContent,
426
- context: {
427
- skillName: skill_name,
428
- },
429
- allowedTools: prepared.skill.allowedTools,
430
- };
431
- } catch (error) {
432
- logger?.error(`Failed to execute skill '${skill_name}':`, error);
433
- return {
434
- content: `**Error executing skill**: ${error instanceof Error ? error.message : String(error)}`,
435
- };
436
- }
437
- }
438
-
439
- /**
440
- * Prepare a skill by name without executing bash commands
441
- */
442
- async prepareSkill(args: SkillToolArgs): Promise<
443
- | {
444
- content: string;
445
- skill: Skill;
446
- }
447
- | { content: string; skill?: undefined }
448
- > {
449
- const { skill_name, args: skillArgs } = args;
450
-
451
- try {
452
- const skill = await this.loadSkill(skill_name);
453
-
454
- if (!skill) {
455
- return {
456
- content: `**Skill not found**: "${skill_name}"\n\nAvailable skills:\n${this.formatAvailableSkills()}`,
457
- };
458
- }
459
-
460
- if (!skill.isValid) {
461
- const errorMsg = formatSkillError(skill.skillPath, skill.errors);
462
- return {
463
- content: `**Skill validation failed**:\n\n\`\`\`\n${errorMsg}\n\`\`\``,
464
- };
465
- }
466
-
467
- const preparedContent = this.prepareSkillContent(skill, skillArgs || "");
468
- return { content: preparedContent, skill };
469
- } catch (error) {
470
- logger?.error(`Failed to prepare skill '${skill_name}':`, error);
471
- return {
472
- content: `**Error preparing skill**: ${error instanceof Error ? error.message : String(error)}`,
473
- };
474
- }
475
- }
476
-
477
- /**
478
- * Prepare skill content with arguments but without bash execution
479
- */
480
- private prepareSkillContent(skill: Skill, argsString: string): string {
481
- const skillPath = `Base directory for this skill: ${skill.skillPath}\n\n`;
482
-
483
- // Extract content after frontmatter
484
- const contentMatch = skill.content.match(
485
- /^---\r?\n[\s\S]*?\r?\n---\r?\n([\s\S]*)$/,
486
- );
487
- let mainContent = contentMatch ? contentMatch[1].trim() : skill.content;
488
-
489
- // 1. Substitute parameters ($1, $ARGUMENTS, etc.)
490
- mainContent = substituteCommandParameters(mainContent, argsString);
491
-
492
- // 2. Substitute ${WAVE_SKILL_DIR} and ${CLAUDE_SKILL_DIR}
493
- mainContent = mainContent.replace(/\$\{WAVE_SKILL_DIR\}/g, skill.skillPath);
494
- mainContent = mainContent.replace(
495
- /\$\{CLAUDE_SKILL_DIR\}/g,
496
- skill.skillPath,
497
- );
498
-
499
- // 3. Substitute ${WAVE_PLUGIN_ROOT} and ${CLAUDE_PLUGIN_ROOT}
500
- if (skill.pluginRoot) {
501
- mainContent = mainContent.replace(
502
- /\$\{WAVE_PLUGIN_ROOT\}/g,
503
- skill.pluginRoot,
504
- );
505
- mainContent = mainContent.replace(
506
- /\$\{CLAUDE_PLUGIN_ROOT\}/g,
507
- skill.pluginRoot,
508
- );
509
- }
510
-
511
- return skillPath + mainContent;
512
- }
513
-
514
- /**
515
- * Execute bash commands in prepared skill content
516
- */
517
- private async executeBashInSkillContent(content: string): Promise<string> {
518
- const { commands } = parseBashCommands(content);
519
- if (commands.length > 0) {
520
- const currentWorkdir =
521
- this.container.get<string>("Workdir") ?? this.workdir;
522
- const results = await executeBashCommands(commands, currentWorkdir);
523
- return replaceBashCommandsWithOutput(content, results);
524
- }
525
- return content;
526
- }
527
-
528
- /**
529
- * Format available skills list for error messages
530
- */
531
- private formatAvailableSkills(): string {
532
- const skills = this.getAvailableSkills();
533
-
534
- if (skills.length === 0) {
535
- return "• No skills available\n\nTo create skills, see the Wave Skills documentation.";
536
- }
537
-
538
- return skills
539
- .map(
540
- (skill) => `• **${skill.name}** (${skill.type}): ${skill.description}`,
541
- )
542
- .join("\n");
543
- }
544
-
545
- /**
546
- * Register skills provided by a plugin
547
- */
548
- registerPluginSkills(pluginName: string, skills: Skill[]): void {
549
- for (const skill of skills) {
550
- const namespacedName = `${pluginName}:${skill.name}`;
551
- const metadata: SkillMetadata = {
552
- name: namespacedName,
553
- description: skill.description,
554
- type: skill.type,
555
- skillPath: skill.skillPath,
556
- allowedTools: skill.allowedTools,
557
- context: skill.context,
558
- agent: skill.agent,
559
- model: skill.model,
560
- disableModelInvocation: skill.disableModelInvocation,
561
- userInvocable: skill.userInvocable,
562
- pluginName,
563
- pluginRoot: skill.pluginRoot,
564
- };
565
- // Update the skill object itself to have the namespaced name
566
- skill.name = namespacedName;
567
-
568
- this.skillMetadata.set(namespacedName, metadata);
569
- this.skillContent.set(namespacedName, skill);
570
- // Also store in plugin-specific maps so they survive refreshSkills()
571
- this.pluginSkillMetadata.set(namespacedName, metadata);
572
- this.pluginSkillContent.set(namespacedName, skill);
573
- }
574
- logger?.debug(
575
- `Registered ${skills.length} plugin skills from ${pluginName}. Total skills: ${this.skillMetadata.size}`,
576
- );
577
- }
578
- }