wave-agent-sdk 0.10.1 → 0.10.2

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 (76) hide show
  1. package/dist/agent.d.ts +6 -0
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +2 -0
  4. package/dist/core/session.d.ts +1 -1
  5. package/dist/core/session.d.ts.map +1 -1
  6. package/dist/core/session.js +1 -1
  7. package/dist/managers/backgroundTaskManager.d.ts +3 -0
  8. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  9. package/dist/managers/backgroundTaskManager.js +3 -0
  10. package/dist/managers/permissionManager.d.ts.map +1 -1
  11. package/dist/managers/permissionManager.js +33 -4
  12. package/dist/managers/skillManager.d.ts +17 -2
  13. package/dist/managers/skillManager.d.ts.map +1 -1
  14. package/dist/managers/skillManager.js +93 -21
  15. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  16. package/dist/managers/slashCommandManager.js +7 -0
  17. package/dist/prompts/index.d.ts +1 -1
  18. package/dist/prompts/index.d.ts.map +1 -1
  19. package/dist/prompts/index.js +1 -0
  20. package/dist/services/configurationService.d.ts.map +1 -1
  21. package/dist/services/configurationService.js +1 -0
  22. package/dist/services/fileWatcher.d.ts.map +1 -1
  23. package/dist/services/fileWatcher.js +27 -15
  24. package/dist/services/session.d.ts +9 -2
  25. package/dist/services/session.d.ts.map +1 -1
  26. package/dist/services/session.js +77 -7
  27. package/dist/tools/bashTool.js +3 -3
  28. package/dist/tools/exitPlanMode.d.ts.map +1 -1
  29. package/dist/tools/exitPlanMode.js +3 -1
  30. package/dist/tools/grepTool.d.ts.map +1 -1
  31. package/dist/tools/grepTool.js +1 -1
  32. package/dist/tools/lspTool.d.ts.map +1 -1
  33. package/dist/tools/lspTool.js +47 -15
  34. package/dist/tools/taskOutputTool.d.ts.map +1 -1
  35. package/dist/tools/taskOutputTool.js +22 -5
  36. package/dist/tools/types.d.ts +1 -0
  37. package/dist/tools/types.d.ts.map +1 -1
  38. package/dist/types/agent.d.ts +2 -0
  39. package/dist/types/agent.d.ts.map +1 -1
  40. package/dist/types/configuration.d.ts +2 -0
  41. package/dist/types/configuration.d.ts.map +1 -1
  42. package/dist/types/skills.d.ts +4 -2
  43. package/dist/types/skills.d.ts.map +1 -1
  44. package/dist/utils/configPaths.d.ts +6 -0
  45. package/dist/utils/configPaths.d.ts.map +1 -1
  46. package/dist/utils/configPaths.js +23 -2
  47. package/dist/utils/containerSetup.d.ts.map +1 -1
  48. package/dist/utils/containerSetup.js +4 -1
  49. package/dist/utils/gitUtils.d.ts +6 -0
  50. package/dist/utils/gitUtils.d.ts.map +1 -1
  51. package/dist/utils/gitUtils.js +22 -0
  52. package/package.json +1 -1
  53. package/src/agent.ts +18 -2
  54. package/src/builtin-skills/settings/HOOKS.md +95 -0
  55. package/src/builtin-skills/settings/SKILL.md +86 -0
  56. package/src/core/session.ts +1 -0
  57. package/src/managers/backgroundTaskManager.ts +11 -1
  58. package/src/managers/permissionManager.ts +33 -4
  59. package/src/managers/skillManager.ts +111 -25
  60. package/src/managers/slashCommandManager.ts +8 -0
  61. package/src/prompts/index.ts +1 -0
  62. package/src/services/configurationService.ts +1 -0
  63. package/src/services/fileWatcher.ts +33 -17
  64. package/src/services/session.ts +83 -7
  65. package/src/tools/bashTool.ts +3 -3
  66. package/src/tools/exitPlanMode.ts +3 -1
  67. package/src/tools/grepTool.ts +2 -1
  68. package/src/tools/lspTool.ts +99 -9
  69. package/src/tools/taskOutputTool.ts +25 -6
  70. package/src/tools/types.ts +2 -0
  71. package/src/types/agent.ts +2 -0
  72. package/src/types/configuration.ts +2 -0
  73. package/src/types/skills.ts +4 -2
  74. package/src/utils/configPaths.ts +28 -2
  75. package/src/utils/containerSetup.ts +4 -1
  76. package/src/utils/gitUtils.ts +22 -0
@@ -58,6 +58,28 @@ export function getGitCommonDir(cwd) {
58
58
  return getGitRepoRoot(cwd);
59
59
  }
60
60
  }
61
+ /**
62
+ * Get the main repository root directory (the first worktree in the list)
63
+ * @param cwd Working directory
64
+ * @returns Main repository root path
65
+ */
66
+ export function getGitMainRepoRoot(cwd) {
67
+ try {
68
+ const output = execSync("git worktree list --porcelain", {
69
+ cwd,
70
+ encoding: "utf8",
71
+ stdio: ["ignore", "pipe", "ignore"],
72
+ }).trim();
73
+ const lines = output.split("\n");
74
+ if (lines.length > 0 && lines[0].startsWith("worktree ")) {
75
+ return lines[0].substring("worktree ".length).trim();
76
+ }
77
+ return getGitRepoRoot(cwd);
78
+ }
79
+ catch {
80
+ return getGitRepoRoot(cwd);
81
+ }
82
+ }
61
83
  /**
62
84
  * Get the default remote branch (e.g., origin/main)
63
85
  * @param cwd Working directory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
package/src/agent.ts CHANGED
@@ -235,7 +235,14 @@ export class Agent {
235
235
  public getBackgroundShellOutput(
236
236
  id: string,
237
237
  filter?: string,
238
- ): { stdout: string; stderr: string; status: string } | null {
238
+ ): {
239
+ stdout: string;
240
+ stderr: string;
241
+ status: string;
242
+ outputPath?: string;
243
+ type: string;
244
+ exitCode?: number;
245
+ } | null {
239
246
  return this.backgroundTaskManager.getOutput(id, filter);
240
247
  }
241
248
 
@@ -248,7 +255,14 @@ export class Agent {
248
255
  public getBackgroundTaskOutput(
249
256
  id: string,
250
257
  filter?: string,
251
- ): { stdout: string; stderr: string; status: string } | null {
258
+ ): {
259
+ stdout: string;
260
+ stderr: string;
261
+ status: string;
262
+ outputPath?: string;
263
+ type: string;
264
+ exitCode?: number;
265
+ } | null {
252
266
  return this.backgroundTaskManager.getOutput(id, filter);
253
267
  }
254
268
 
@@ -456,6 +470,8 @@ export class Agent {
456
470
  }
457
471
  // Cleanup subagent manager
458
472
  this.subagentManager.cleanup();
473
+ // Cleanup skill manager
474
+ await this.skillManager.destroy();
459
475
  // Cleanup live configuration reload
460
476
  try {
461
477
  await this.liveConfigManager.shutdown();
@@ -0,0 +1,95 @@
1
+ # Wave Hooks Configuration
2
+
3
+ Hooks allow you to automate tasks when certain events occur in Wave. This document provides detailed guidance on how to configure complex hooks in `settings.json`.
4
+
5
+ ## Hook Events
6
+
7
+ Wave supports the following hook events:
8
+
9
+ - `WorktreeCreate`: Triggered when a new worktree is created.
10
+ - `TaskStart`: Triggered when a task starts.
11
+ - `TaskComplete`: Triggered when a task is completed.
12
+ - `TaskError`: Triggered when a task fails.
13
+ - `SessionStart`: Triggered when a new session starts.
14
+ - `SessionEnd`: Triggered when a session ends.
15
+
16
+ ## Hook Configuration Structure
17
+
18
+ Hooks are configured in the `hooks` field of `settings.json`. Each event can have multiple hook configurations.
19
+
20
+ ```json
21
+ {
22
+ "hooks": {
23
+ "WorktreeCreate": [
24
+ {
25
+ "command": "pnpm install",
26
+ "description": "Install dependencies in new worktree",
27
+ "blocking": true,
28
+ "timeout": 300000
29
+ }
30
+ ],
31
+ "TaskComplete": [
32
+ {
33
+ "command": "pnpm test",
34
+ "description": "Run tests after task completion",
35
+ "blocking": false
36
+ }
37
+ ]
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## Hook Configuration Fields
43
+
44
+ - `command`: The shell command to execute.
45
+ - `description`: A brief description of the hook's purpose.
46
+ - `blocking`: (Optional) Whether the hook should block the main agent's execution (default: `false`).
47
+ - `timeout`: (Optional) Maximum execution time in milliseconds (default: `60000`).
48
+ - `env`: (Optional) Environment variables specific to this hook.
49
+ - `cwd`: (Optional) Working directory for the hook command.
50
+
51
+ ## Advanced Hook Examples
52
+
53
+ ### 1. Conditional Hooks
54
+ You can use shell logic within the `command` field to create conditional hooks.
55
+ ```json
56
+ {
57
+ "hooks": {
58
+ "TaskComplete": [
59
+ {
60
+ "command": "if [ \"$WAVE_TASK_STATUS\" = \"completed\" ]; then pnpm lint; fi",
61
+ "description": "Run linting only on successful task completion"
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ ```
67
+
68
+ ### 2. Hook Chaining
69
+ You can chain multiple commands in a single hook or define multiple hooks for the same event.
70
+ ```json
71
+ {
72
+ "hooks": {
73
+ "WorktreeCreate": [
74
+ {
75
+ "command": "pnpm install && pnpm build",
76
+ "description": "Install and build in new worktree"
77
+ }
78
+ ]
79
+ }
80
+ }
81
+ ```
82
+
83
+ ### 3. Using Environment Variables
84
+ Wave provides several environment variables to hooks:
85
+ - `WAVE_PROJECT_DIR`: The root directory of the project.
86
+ - `WAVE_SESSION_ID`: The current session ID.
87
+ - `WAVE_TASK_ID`: The current task ID (if applicable).
88
+ - `WAVE_TASK_STATUS`: The status of the task (for `TaskComplete` and `TaskError`).
89
+
90
+ ## Best Practices
91
+
92
+ - **Keep hooks fast**: Long-running hooks can slow down your workflow, especially if they are `blocking`.
93
+ - **Use descriptive names**: Help yourself and others understand what each hook does.
94
+ - **Test your hooks**: Run the commands manually first to ensure they work as expected.
95
+ - **Use local overrides**: For machine-specific hooks, use `.wave/settings.local.json`.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: settings
3
+ description: Manage Wave settings and get guidance on settings.json
4
+ allowed-tools: Bash, Read, Write
5
+ ---
6
+
7
+ # Wave Settings Skill
8
+
9
+ This skill helps you manage your Wave configuration and provides guidance on how to use `settings.json`.
10
+
11
+ ## What is `settings.json`?
12
+
13
+ `settings.json` is the central configuration file for Wave. It allows you to customize hooks, environment variables, tool permissions, and more.
14
+
15
+ Wave looks for `settings.json` in three scopes:
16
+ 1. **User Scope**: Global settings for all projects. Located at `~/.wave/settings.json`.
17
+ 2. **Project Scope**: Settings specific to the current project. Located at `.wave/settings.json` in your project root.
18
+ 3. **Local Scope**: Local overrides for the current project (not committed to git). Located at `.wave/settings.local.json`.
19
+
20
+ ## Common Settings
21
+
22
+ ### 1. Hooks
23
+ Hooks allow you to automate tasks when certain events occur (e.g., `WorktreeCreate`, `TaskStart`).
24
+ For detailed hook configuration, see [HOOKS.md](${WAVE_SKILL_DIR}/HOOKS.md).
25
+
26
+ ### 2. Environment Variables
27
+ Set environment variables that will be available to all tools and hooks.
28
+ ```json
29
+ {
30
+ "env": {
31
+ "NODE_ENV": "development",
32
+ "API_KEY": "your-api-key"
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### 3. Permissions
38
+ Manage tool permissions and define the "Safe Zone".
39
+ ```json
40
+ {
41
+ "permissions": {
42
+ "allow": ["Bash", "Read"],
43
+ "deny": ["Write"],
44
+ "defaultMode": "interactive",
45
+ "additionalDirectories": ["/tmp/wave-exports"]
46
+ }
47
+ }
48
+ ```
49
+
50
+ ### 4. Enabled Plugins
51
+ Enable or disable specific plugins.
52
+ ```json
53
+ {
54
+ "enabledPlugins": {
55
+ "git-plugin": true,
56
+ "experimental-plugin": false
57
+ }
58
+ }
59
+ ```
60
+
61
+ ### 5. Model and Token Configuration
62
+ Define which AI models Wave should use and set token limits via environment variables.
63
+ ```json
64
+ {
65
+ "env": {
66
+ "WAVE_MODEL": "gemini-3-flash",
67
+ "WAVE_FAST_MODEL": "gemini-2.5-flash",
68
+ "WAVE_MAX_INPUT_TOKENS": "100000",
69
+ "WAVE_MAX_OUTPUT_TOKENS": "4096"
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### 6. Other Settings
75
+ - `language`: Preferred language for agent communication (e.g., `"en"`, `"zh"`).
76
+ - `autoMemoryEnabled`: Enable or disable auto-memory (default: `true`).
77
+
78
+ ## How to use this skill
79
+
80
+ You can ask me to:
81
+ - "Show my current settings"
82
+ - "Update my project settings to enable auto-memory"
83
+ - "How do I configure a post-commit hook?"
84
+ - "What are the available permission modes?"
85
+
86
+ I will guide you through the process and ensure your configuration is valid.
@@ -1,5 +1,6 @@
1
1
  export {
2
2
  listSessions,
3
+ listAllSessions,
3
4
  truncateContent,
4
5
  loadSessionFromJsonl,
5
6
  loadFullMessageThread,
@@ -293,7 +293,14 @@ export class BackgroundTaskManager {
293
293
  public getOutput(
294
294
  id: string,
295
295
  filter?: string,
296
- ): { stdout: string; stderr: string; status: string } | null {
296
+ ): {
297
+ stdout: string;
298
+ stderr: string;
299
+ status: string;
300
+ outputPath?: string;
301
+ type: string;
302
+ exitCode?: number;
303
+ } | null {
297
304
  const task = this.tasks.get(id);
298
305
  if (!task) {
299
306
  return null;
@@ -323,6 +330,9 @@ export class BackgroundTaskManager {
323
330
  stdout,
324
331
  stderr,
325
332
  status: task.status,
333
+ outputPath: task.outputPath,
334
+ type: task.type,
335
+ exitCode: task.exitCode,
326
336
  };
327
337
  }
328
338
 
@@ -34,7 +34,19 @@ import {
34
34
  import { Container } from "../utils/container.js";
35
35
  import { ConfigurationService } from "../services/configurationService.js";
36
36
 
37
- const SAFE_COMMANDS = ["cd", "ls", "pwd", "true", "false"];
37
+ const SAFE_COMMANDS = [
38
+ "cd",
39
+ "ls",
40
+ "pwd",
41
+ "true",
42
+ "false",
43
+ "grep",
44
+ "rg",
45
+ "cat",
46
+ "head",
47
+ "tail",
48
+ "wc",
49
+ ];
38
50
 
39
51
  const DEFAULT_ALLOWED_RULES = [
40
52
  "Bash(git status*)",
@@ -69,7 +81,12 @@ const DEFAULT_ALLOWED_RULES = [
69
81
  "Bash(whoami*)",
70
82
  "Bash(date*)",
71
83
  "Bash(uptime*)",
72
- "Bash(wc -l*)",
84
+ "Bash(grep*)",
85
+ "Bash(rg*)",
86
+ "Bash(cat*)",
87
+ "Bash(head*)",
88
+ "Bash(tail*)",
89
+ "Bash(wc*)",
73
90
  ];
74
91
 
75
92
  import { logger } from "../utils/globalLogger.js";
@@ -649,7 +666,13 @@ export class PermissionManager {
649
666
  cmd === "pwd" ||
650
667
  cmd === "true" ||
651
668
  cmd === "false" ||
652
- cmd === "ls"
669
+ cmd === "ls" ||
670
+ cmd === "grep" ||
671
+ cmd === "rg" ||
672
+ cmd === "cat" ||
673
+ cmd === "head" ||
674
+ cmd === "tail" ||
675
+ cmd === "wc"
653
676
  ) {
654
677
  return true;
655
678
  }
@@ -751,7 +774,13 @@ export class PermissionManager {
751
774
  cmd === "pwd" ||
752
775
  cmd === "true" ||
753
776
  cmd === "false" ||
754
- cmd === "ls"
777
+ cmd === "ls" ||
778
+ cmd === "grep" ||
779
+ cmd === "rg" ||
780
+ cmd === "cat" ||
781
+ cmd === "head" ||
782
+ cmd === "tail" ||
783
+ cmd === "wc"
755
784
  ) {
756
785
  isSafe = true;
757
786
  } else {
@@ -1,6 +1,8 @@
1
1
  import { readdir, stat } from "fs/promises";
2
2
  import { join } from "path";
3
3
  import { homedir } from "os";
4
+ import { EventEmitter } from "events";
5
+ import { FileWatcherService } from "../services/fileWatcher.js";
4
6
  import type {
5
7
  SkillManagerOptions,
6
8
  SkillMetadata,
@@ -17,6 +19,7 @@ import {
17
19
  replaceBashCommandsWithOutput,
18
20
  executeBashCommands,
19
21
  } from "../utils/markdownParser.js";
22
+ import { getBuiltinSkillsDir } from "../utils/configPaths.js";
20
23
 
21
24
  import { Container } from "../utils/container.js";
22
25
  import { logger } from "../utils/globalLogger.js";
@@ -24,7 +27,7 @@ import { logger } from "../utils/globalLogger.js";
24
27
  /**
25
28
  * Manages skill discovery and loading
26
29
  */
27
- export class SkillManager {
30
+ export class SkillManager extends EventEmitter {
28
31
  private personalSkillsPath: string;
29
32
  private scanTimeout: number;
30
33
  private workdir: string;
@@ -32,15 +35,19 @@ export class SkillManager {
32
35
  private skillMetadata = new Map<string, SkillMetadata>();
33
36
  private skillContent = new Map<string, Skill>();
34
37
  private initialized = false;
38
+ private fileWatcher: FileWatcherService | null = null;
39
+ private watchEnabled: boolean;
35
40
 
36
41
  constructor(
37
42
  private container: Container,
38
43
  options: SkillManagerOptions = {},
39
44
  ) {
45
+ super();
40
46
  this.personalSkillsPath =
41
47
  options.personalSkillsPath || join(homedir(), ".wave", "skills");
42
48
  this.scanTimeout = options.scanTimeout || 5000;
43
49
  this.workdir = options.workdir || process.cwd();
50
+ this.watchEnabled = options.watch ?? false;
44
51
  }
45
52
 
46
53
  /**
@@ -50,26 +57,10 @@ export class SkillManager {
50
57
  logger?.debug("Initializing SkillManager...");
51
58
 
52
59
  try {
53
- // Clear existing data before discovery
54
- this.skillMetadata.clear();
55
- this.skillContent.clear();
60
+ await this.refreshSkills();
56
61
 
57
- const discovery = await this.discoverSkills();
58
-
59
- // Store discovered skill metadata
60
- discovery.personalSkills.forEach((skill, name) => {
61
- this.skillMetadata.set(name, skill);
62
- });
63
- discovery.projectSkills.forEach((skill, name) => {
64
- this.skillMetadata.set(name, skill);
65
- });
66
-
67
- // Log any discovery errors
68
- if (discovery.errors.length > 0) {
69
- logger?.warn(`Found ${discovery.errors.length} skill discovery errors`);
70
- discovery.errors.forEach((error) => {
71
- logger?.warn(`Skill error in ${error.skillPath}: ${error.message}`);
72
- });
62
+ if (this.watchEnabled && !this.fileWatcher) {
63
+ await this.setupWatcher();
73
64
  }
74
65
 
75
66
  this.initialized = true;
@@ -82,6 +73,85 @@ export class SkillManager {
82
73
  }
83
74
  }
84
75
 
76
+ /**
77
+ * Refresh skills by re-discovering them
78
+ */
79
+ private async refreshSkills(): Promise<void> {
80
+ // Clear existing data before discovery
81
+ this.skillMetadata.clear();
82
+ this.skillContent.clear();
83
+
84
+ const discovery = await this.discoverSkills();
85
+
86
+ // Store discovered skill metadata
87
+ discovery.builtinSkills.forEach((skill, name) => {
88
+ this.skillMetadata.set(name, skill);
89
+ });
90
+ discovery.personalSkills.forEach((skill, name) => {
91
+ this.skillMetadata.set(name, skill);
92
+ });
93
+ discovery.projectSkills.forEach((skill, name) => {
94
+ this.skillMetadata.set(name, skill);
95
+ });
96
+
97
+ // Log any discovery errors
98
+ if (discovery.errors.length > 0) {
99
+ logger?.warn(`Found ${discovery.errors.length} skill discovery errors`);
100
+ discovery.errors.forEach((error) => {
101
+ logger?.warn(`Skill error in ${error.skillPath}: ${error.message}`);
102
+ });
103
+ }
104
+
105
+ this.emit("refreshed", Array.from(this.skillMetadata.values()));
106
+ }
107
+
108
+ /**
109
+ * Setup file watcher for skill directories
110
+ */
111
+ private async setupWatcher(): Promise<void> {
112
+ if (this.fileWatcher) {
113
+ await this.fileWatcher.cleanup();
114
+ }
115
+
116
+ this.fileWatcher = new FileWatcherService(logger);
117
+
118
+ const pathsToWatch = [
119
+ this.personalSkillsPath,
120
+ join(this.workdir, ".wave", "skills"),
121
+ ];
122
+
123
+ logger?.debug(`Setting up skill watcher for: ${pathsToWatch.join(", ")}`);
124
+
125
+ for (const pathToWatch of pathsToWatch) {
126
+ await this.fileWatcher.watchFile(pathToWatch, async (event) => {
127
+ if (
128
+ event.path.endsWith("SKILL.md") ||
129
+ event.type === "delete" ||
130
+ event.type === "create"
131
+ ) {
132
+ logger?.debug(
133
+ `Skill change detected (${event.type}): ${event.path}. Refreshing skills...`,
134
+ );
135
+ try {
136
+ await this.refreshSkills();
137
+ } catch (error) {
138
+ logger?.error("Failed to refresh skills after change:", error);
139
+ }
140
+ }
141
+ });
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Cleanup resources
147
+ */
148
+ async destroy(): Promise<void> {
149
+ if (this.fileWatcher) {
150
+ await this.fileWatcher.cleanup();
151
+ this.fileWatcher = null;
152
+ }
153
+ }
154
+
85
155
  /**
86
156
  * Check if the skill manager is initialized
87
157
  */
@@ -132,9 +202,14 @@ export class SkillManager {
132
202
  }
133
203
 
134
204
  /**
135
- * Discover skills in both personal and project directories
205
+ * Discover skills in builtin, personal and project directories
136
206
  */
137
207
  private async discoverSkills(): Promise<SkillDiscoveryResult> {
208
+ const builtinCollection = await this.discoverSkillCollection(
209
+ getBuiltinSkillsDir(),
210
+ "builtin",
211
+ );
212
+
138
213
  const personalCollection = await this.discoverSkillCollection(
139
214
  this.personalSkillsPath,
140
215
  "personal",
@@ -146,9 +221,14 @@ export class SkillManager {
146
221
  );
147
222
 
148
223
  return {
224
+ builtinSkills: builtinCollection.skills,
149
225
  personalSkills: personalCollection.skills,
150
226
  projectSkills: projectCollection.skills,
151
- errors: [...personalCollection.errors, ...projectCollection.errors],
227
+ errors: [
228
+ ...builtinCollection.errors,
229
+ ...personalCollection.errors,
230
+ ...projectCollection.errors,
231
+ ],
152
232
  };
153
233
  }
154
234
 
@@ -157,7 +237,7 @@ export class SkillManager {
157
237
  */
158
238
  private async discoverSkillCollection(
159
239
  basePath: string,
160
- type: "personal" | "project",
240
+ type: "personal" | "project" | "builtin",
161
241
  ): Promise<SkillCollection> {
162
242
  const collection: SkillCollection = {
163
243
  type,
@@ -166,8 +246,14 @@ export class SkillManager {
166
246
  errors: [],
167
247
  };
168
248
 
169
- const skillsPath =
170
- type === "personal" ? basePath : join(basePath, ".wave", "skills");
249
+ let skillsPath: string;
250
+ if (type === "personal") {
251
+ skillsPath = basePath;
252
+ } else if (type === "builtin") {
253
+ skillsPath = basePath;
254
+ } else {
255
+ skillsPath = join(basePath, ".wave", "skills");
256
+ }
171
257
 
172
258
  try {
173
259
  const skillDirs = await this.findSkillDirectories(skillsPath);
@@ -42,6 +42,14 @@ export class SlashCommandManager {
42
42
  public initialize(): void {
43
43
  this.initializeBuiltinCommands();
44
44
  this.loadCustomCommands();
45
+
46
+ // Listen for skill refreshes and update skill commands
47
+ const skillManager = this.container.get<SkillManager>("SkillManager");
48
+ if (skillManager) {
49
+ skillManager.on("refreshed", (skills: SkillMetadata[]) => {
50
+ this.registerSkillCommands(skills);
51
+ });
52
+ }
45
53
  }
46
54
 
47
55
  private get messageManager(): MessageManager {
@@ -256,6 +256,7 @@ Usage notes:
256
256
  - Avoid listing every component or file structure that can be easily discovered.
257
257
  - Don't include generic development practices.
258
258
  - If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include the important parts.
259
+ - Do NOT include rules from .wave/rules/ as they are automatically loaded by the system.
259
260
  - If there is a README.md, make sure to include the important parts.
260
261
  - Do not make up information such as "Common Development Tasks", "Tips for Development", "Support and Documentation" unless this is expressly included in other files that you read.
261
262
  - Be sure to prefix the file with the following text:
@@ -588,6 +588,7 @@ export class ConfigurationService {
588
588
  return {
589
589
  userPaths: allPaths.userPaths,
590
590
  projectPaths: allPaths.projectPaths,
591
+ builtinPaths: allPaths.builtinPaths,
591
592
  allPaths: allPaths.allPaths,
592
593
  existingPaths: existingPaths.existingPaths,
593
594
  };