wave-agent-sdk 0.0.2 → 0.0.3

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 (64) hide show
  1. package/dist/agent.d.ts +5 -1
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +46 -2
  4. package/dist/index.d.ts +0 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +0 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +4 -7
  9. package/dist/managers/messageManager.d.ts +8 -0
  10. package/dist/managers/messageManager.d.ts.map +1 -1
  11. package/dist/managers/messageManager.js +26 -2
  12. package/dist/managers/skillManager.d.ts +4 -5
  13. package/dist/managers/skillManager.d.ts.map +1 -1
  14. package/dist/managers/skillManager.js +6 -82
  15. package/dist/managers/subagentManager.d.ts +96 -0
  16. package/dist/managers/subagentManager.d.ts.map +1 -0
  17. package/dist/managers/subagentManager.js +261 -0
  18. package/dist/managers/toolManager.d.ts +33 -1
  19. package/dist/managers/toolManager.d.ts.map +1 -1
  20. package/dist/managers/toolManager.js +43 -5
  21. package/dist/services/aiService.d.ts.map +1 -1
  22. package/dist/services/aiService.js +40 -14
  23. package/dist/tools/grepTool.d.ts.map +1 -1
  24. package/dist/tools/grepTool.js +8 -6
  25. package/dist/tools/readTool.d.ts.map +1 -1
  26. package/dist/tools/readTool.js +36 -6
  27. package/dist/tools/skillTool.d.ts +8 -0
  28. package/dist/tools/skillTool.d.ts.map +1 -0
  29. package/dist/tools/skillTool.js +72 -0
  30. package/dist/tools/taskTool.d.ts +8 -0
  31. package/dist/tools/taskTool.d.ts.map +1 -0
  32. package/dist/tools/taskTool.js +109 -0
  33. package/dist/tools/todoWriteTool.d.ts +6 -0
  34. package/dist/tools/todoWriteTool.d.ts.map +1 -0
  35. package/dist/tools/todoWriteTool.js +203 -0
  36. package/dist/types.d.ts +8 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/utils/fileFormat.d.ts +17 -0
  39. package/dist/utils/fileFormat.d.ts.map +1 -0
  40. package/dist/utils/fileFormat.js +35 -0
  41. package/dist/utils/messageOperations.d.ts +18 -0
  42. package/dist/utils/messageOperations.d.ts.map +1 -1
  43. package/dist/utils/messageOperations.js +43 -0
  44. package/dist/utils/subagentParser.d.ts +19 -0
  45. package/dist/utils/subagentParser.d.ts.map +1 -0
  46. package/dist/utils/subagentParser.js +159 -0
  47. package/package.json +1 -1
  48. package/src/agent.ts +53 -3
  49. package/src/index.ts +0 -1
  50. package/src/managers/aiManager.ts +5 -8
  51. package/src/managers/messageManager.ts +55 -1
  52. package/src/managers/skillManager.ts +7 -96
  53. package/src/managers/subagentManager.ts +368 -0
  54. package/src/managers/toolManager.ts +50 -5
  55. package/src/services/aiService.ts +43 -15
  56. package/src/tools/grepTool.ts +9 -6
  57. package/src/tools/readTool.ts +40 -6
  58. package/src/tools/skillTool.ts +82 -0
  59. package/src/tools/taskTool.ts +128 -0
  60. package/src/tools/todoWriteTool.ts +232 -0
  61. package/src/types.ts +10 -1
  62. package/src/utils/fileFormat.ts +40 -0
  63. package/src/utils/messageOperations.ts +80 -0
  64. package/src/utils/subagentParser.ts +223 -0
@@ -0,0 +1,223 @@
1
+ import { readFileSync, readdirSync, statSync } from "fs";
2
+ import { join, extname } from "path";
3
+
4
+ export interface SubagentConfiguration {
5
+ name: string;
6
+ description: string;
7
+ tools?: string[];
8
+ model?: string;
9
+ systemPrompt: string;
10
+ filePath: string;
11
+ scope: "project" | "user";
12
+ priority: number;
13
+ }
14
+
15
+ interface SubagentFrontmatter {
16
+ name?: string;
17
+ description?: string;
18
+ tools?: string[];
19
+ model?: string;
20
+ }
21
+
22
+ /**
23
+ * Parse YAML frontmatter from markdown file content
24
+ */
25
+ function parseFrontmatter(content: string): {
26
+ frontmatter: SubagentFrontmatter;
27
+ body: string;
28
+ } {
29
+ const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
30
+ const match = content.match(frontmatterRegex);
31
+
32
+ if (!match) {
33
+ return { frontmatter: {}, body: content.trim() };
34
+ }
35
+
36
+ const [, yamlContent, body] = match;
37
+ const frontmatter = parseYamlFrontmatter(yamlContent);
38
+
39
+ return { frontmatter, body: body.trim() };
40
+ }
41
+
42
+ /**
43
+ * Simple YAML frontmatter parser for subagent files
44
+ */
45
+ function parseYamlFrontmatter(yamlContent: string): SubagentFrontmatter {
46
+ const frontmatter: SubagentFrontmatter = {};
47
+
48
+ try {
49
+ const lines = yamlContent.split("\n");
50
+ for (const line of lines) {
51
+ const trimmed = line.trim();
52
+ if (!trimmed || trimmed.startsWith("#")) continue;
53
+
54
+ const colonIndex = trimmed.indexOf(":");
55
+ if (colonIndex === -1) continue;
56
+
57
+ const key = trimmed.substring(0, colonIndex).trim();
58
+ const value = trimmed
59
+ .substring(colonIndex + 1)
60
+ .trim()
61
+ .replace(/^["']|["']$/g, "");
62
+
63
+ if (key && value) {
64
+ // Handle array values for tools
65
+ if (key === "tools" && value) {
66
+ let arrayValue = value;
67
+ if (arrayValue.startsWith("[") && arrayValue.endsWith("]")) {
68
+ arrayValue = arrayValue.slice(1, -1);
69
+ }
70
+ frontmatter[key] = arrayValue
71
+ .split(",")
72
+ .map((s) => s.trim())
73
+ .filter(Boolean);
74
+ } else {
75
+ if (key === "name" || key === "description" || key === "model") {
76
+ frontmatter[key] = value;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ } catch {
82
+ // Return empty frontmatter on parse error - validation will catch missing fields
83
+ }
84
+
85
+ return frontmatter;
86
+ }
87
+
88
+ /**
89
+ * Validate subagent configuration
90
+ */
91
+ function validateConfiguration(
92
+ config: SubagentFrontmatter,
93
+ filePath: string,
94
+ ): void {
95
+ if (!config.name) {
96
+ throw new Error(`Missing required field 'name' in ${filePath}`);
97
+ }
98
+
99
+ if (!config.description) {
100
+ throw new Error(`Missing required field 'description' in ${filePath}`);
101
+ }
102
+
103
+ // Validate name pattern
104
+ const namePattern = /^[a-z][a-z0-9-]*$/;
105
+ if (!namePattern.test(config.name)) {
106
+ throw new Error(
107
+ `Invalid subagent name '${config.name}' in ${filePath}. Must start with a letter and contain only lowercase letters, numbers, and hyphens.`,
108
+ );
109
+ }
110
+
111
+ // Validate model if specified - allow any non-empty string
112
+ if (config.model && typeof config.model !== "string") {
113
+ throw new Error(
114
+ `Invalid model '${config.model}' in ${filePath}. Must be a string.`,
115
+ );
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Parse a single subagent markdown file
121
+ */
122
+ function parseSubagentFile(
123
+ filePath: string,
124
+ scope: "project" | "user",
125
+ ): SubagentConfiguration {
126
+ try {
127
+ const content = readFileSync(filePath, "utf-8");
128
+ const { frontmatter, body } = parseFrontmatter(content);
129
+
130
+ validateConfiguration(frontmatter, filePath);
131
+
132
+ if (!body.trim()) {
133
+ throw new Error(`Empty system prompt in ${filePath}`);
134
+ }
135
+
136
+ return {
137
+ name: frontmatter.name!,
138
+ description: frontmatter.description!,
139
+ tools: frontmatter.tools,
140
+ model: frontmatter.model,
141
+ systemPrompt: body,
142
+ filePath,
143
+ scope,
144
+ priority: scope === "project" ? 1 : 2,
145
+ };
146
+ } catch (error) {
147
+ throw new Error(
148
+ `Failed to parse subagent file ${filePath}: ${error instanceof Error ? error.message : String(error)}`,
149
+ );
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Scan directory for subagent files
155
+ */
156
+ function scanSubagentDirectory(
157
+ dirPath: string,
158
+ scope: "project" | "user",
159
+ ): SubagentConfiguration[] {
160
+ const configurations: SubagentConfiguration[] = [];
161
+
162
+ try {
163
+ const entries = readdirSync(dirPath);
164
+
165
+ for (const entry of entries) {
166
+ const fullPath = join(dirPath, entry);
167
+ const stat = statSync(fullPath);
168
+
169
+ if (stat.isFile() && extname(entry) === ".md") {
170
+ try {
171
+ const config = parseSubagentFile(fullPath, scope);
172
+ configurations.push(config);
173
+ } catch (parseError) {
174
+ // Log error but continue with other files
175
+ console.warn(
176
+ `Warning: ${parseError instanceof Error ? parseError.message : String(parseError)}`,
177
+ );
178
+ }
179
+ }
180
+ }
181
+ } catch {
182
+ // Directory doesn't exist or can't be read - this is OK
183
+ }
184
+
185
+ return configurations;
186
+ }
187
+
188
+ /**
189
+ * Load all subagent configurations from project and user directories
190
+ */
191
+ export async function loadSubagentConfigurations(
192
+ workdir: string,
193
+ ): Promise<SubagentConfiguration[]> {
194
+ const projectDir = join(workdir, ".wave", "agents");
195
+ const userDir = join(process.env.HOME || "~", ".wave", "agents");
196
+
197
+ const projectConfigs = scanSubagentDirectory(projectDir, "project");
198
+ const userConfigs = scanSubagentDirectory(userDir, "user");
199
+
200
+ // Merge configurations, with project configs taking precedence
201
+ const configMap = new Map<string, SubagentConfiguration>();
202
+
203
+ // Process in reverse priority order (user first, then project)
204
+ for (const config of [...userConfigs, ...projectConfigs]) {
205
+ configMap.set(config.name, config);
206
+ }
207
+
208
+ return Array.from(configMap.values()).sort((a, b) => {
209
+ if (a.priority !== b.priority) return a.priority - b.priority;
210
+ return a.name.localeCompare(b.name);
211
+ });
212
+ }
213
+
214
+ /**
215
+ * Find subagent by exact name match
216
+ */
217
+ export async function findSubagentByName(
218
+ name: string,
219
+ workdir: string,
220
+ ): Promise<SubagentConfiguration | null> {
221
+ const configurations = await loadSubagentConfigurations(workdir);
222
+ return configurations.find((config) => config.name === name) || null;
223
+ }