wave-agent-sdk 0.0.7 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/dist/agent.d.ts +105 -24
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +438 -53
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -0
  7. package/dist/managers/aiManager.d.ts +18 -7
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +254 -142
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +11 -9
  12. package/dist/managers/hookManager.d.ts +6 -6
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +81 -39
  15. package/dist/managers/liveConfigManager.d.ts +95 -0
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -0
  17. package/dist/managers/liveConfigManager.js +442 -0
  18. package/dist/managers/lspManager.d.ts +43 -0
  19. package/dist/managers/lspManager.d.ts.map +1 -0
  20. package/dist/managers/lspManager.js +326 -0
  21. package/dist/managers/messageManager.d.ts +41 -24
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +184 -73
  24. package/dist/managers/permissionManager.d.ts +66 -0
  25. package/dist/managers/permissionManager.d.ts.map +1 -0
  26. package/dist/managers/permissionManager.js +208 -0
  27. package/dist/managers/skillManager.d.ts +1 -0
  28. package/dist/managers/skillManager.d.ts.map +1 -1
  29. package/dist/managers/skillManager.js +2 -1
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +4 -2
  32. package/dist/managers/subagentManager.d.ts +42 -6
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +213 -62
  35. package/dist/managers/toolManager.d.ts +38 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +66 -2
  38. package/dist/services/aiService.d.ts +15 -5
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +446 -77
  41. package/dist/services/configurationService.d.ts +116 -0
  42. package/dist/services/configurationService.d.ts.map +1 -0
  43. package/dist/services/configurationService.js +585 -0
  44. package/dist/services/fileWatcher.d.ts +69 -0
  45. package/dist/services/fileWatcher.d.ts.map +1 -0
  46. package/dist/services/fileWatcher.js +212 -0
  47. package/dist/services/hook.d.ts +5 -40
  48. package/dist/services/hook.d.ts.map +1 -1
  49. package/dist/services/hook.js +47 -109
  50. package/dist/services/jsonlHandler.d.ts +71 -0
  51. package/dist/services/jsonlHandler.d.ts.map +1 -0
  52. package/dist/services/jsonlHandler.js +236 -0
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +33 -11
  55. package/dist/services/session.d.ts +116 -52
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +415 -143
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +77 -17
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +27 -1
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +33 -8
  64. package/dist/tools/lspTool.d.ts +6 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -0
  66. package/dist/tools/lspTool.js +589 -0
  67. package/dist/tools/multiEditTool.d.ts.map +1 -1
  68. package/dist/tools/multiEditTool.js +30 -10
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +113 -3
  71. package/dist/tools/skillTool.js +2 -2
  72. package/dist/tools/todoWriteTool.d.ts.map +1 -1
  73. package/dist/tools/todoWriteTool.js +23 -0
  74. package/dist/tools/types.d.ts +11 -8
  75. package/dist/tools/types.d.ts.map +1 -1
  76. package/dist/tools/writeTool.d.ts.map +1 -1
  77. package/dist/tools/writeTool.js +30 -15
  78. package/dist/types/commands.d.ts +4 -1
  79. package/dist/types/commands.d.ts.map +1 -1
  80. package/dist/types/config.d.ts +4 -0
  81. package/dist/types/config.d.ts.map +1 -1
  82. package/dist/types/configuration.d.ts +69 -0
  83. package/dist/types/configuration.d.ts.map +1 -0
  84. package/dist/types/configuration.js +8 -0
  85. package/dist/types/core.d.ts +45 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +83 -0
  88. package/dist/types/environment.d.ts.map +1 -0
  89. package/dist/types/environment.js +21 -0
  90. package/dist/types/fileSearch.d.ts +5 -0
  91. package/dist/types/fileSearch.d.ts.map +1 -0
  92. package/dist/types/fileSearch.js +1 -0
  93. package/dist/types/hooks.d.ts +18 -3
  94. package/dist/types/hooks.d.ts.map +1 -1
  95. package/dist/types/hooks.js +8 -8
  96. package/dist/types/index.d.ts +7 -0
  97. package/dist/types/index.d.ts.map +1 -1
  98. package/dist/types/index.js +7 -0
  99. package/dist/types/lsp.d.ts +90 -0
  100. package/dist/types/lsp.d.ts.map +1 -0
  101. package/dist/types/lsp.js +4 -0
  102. package/dist/types/messaging.d.ts +19 -12
  103. package/dist/types/messaging.d.ts.map +1 -1
  104. package/dist/types/permissions.d.ts +35 -0
  105. package/dist/types/permissions.d.ts.map +1 -0
  106. package/dist/types/permissions.js +12 -0
  107. package/dist/types/session.d.ts +15 -0
  108. package/dist/types/session.d.ts.map +1 -0
  109. package/dist/types/session.js +7 -0
  110. package/dist/types/skills.d.ts +1 -0
  111. package/dist/types/skills.d.ts.map +1 -1
  112. package/dist/types/tools.d.ts +35 -0
  113. package/dist/types/tools.d.ts.map +1 -0
  114. package/dist/types/tools.js +4 -0
  115. package/dist/utils/abortUtils.d.ts +34 -0
  116. package/dist/utils/abortUtils.d.ts.map +1 -0
  117. package/dist/utils/abortUtils.js +92 -0
  118. package/dist/utils/bashHistory.d.ts +4 -0
  119. package/dist/utils/bashHistory.d.ts.map +1 -1
  120. package/dist/utils/bashHistory.js +48 -30
  121. package/dist/utils/builtinSubagents.d.ts +7 -0
  122. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  123. package/dist/utils/builtinSubagents.js +65 -0
  124. package/dist/utils/cacheControlUtils.d.ts +96 -0
  125. package/dist/utils/cacheControlUtils.d.ts.map +1 -0
  126. package/dist/utils/cacheControlUtils.js +324 -0
  127. package/dist/utils/commandPathResolver.d.ts +52 -0
  128. package/dist/utils/commandPathResolver.d.ts.map +1 -0
  129. package/dist/utils/commandPathResolver.js +145 -0
  130. package/dist/utils/configPaths.d.ts +85 -0
  131. package/dist/utils/configPaths.d.ts.map +1 -0
  132. package/dist/utils/configPaths.js +121 -0
  133. package/dist/utils/constants.d.ts +1 -13
  134. package/dist/utils/constants.d.ts.map +1 -1
  135. package/dist/utils/constants.js +2 -14
  136. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  137. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  138. package/dist/utils/convertMessagesForAPI.js +39 -18
  139. package/dist/utils/customCommands.d.ts.map +1 -1
  140. package/dist/utils/customCommands.js +66 -21
  141. package/dist/utils/fileSearch.d.ts +14 -0
  142. package/dist/utils/fileSearch.d.ts.map +1 -0
  143. package/dist/utils/fileSearch.js +88 -0
  144. package/dist/utils/fileUtils.d.ts +27 -0
  145. package/dist/utils/fileUtils.d.ts.map +1 -0
  146. package/dist/utils/fileUtils.js +145 -0
  147. package/dist/utils/globalLogger.d.ts +88 -0
  148. package/dist/utils/globalLogger.d.ts.map +1 -0
  149. package/dist/utils/globalLogger.js +120 -0
  150. package/dist/utils/largeOutputHandler.d.ts +15 -0
  151. package/dist/utils/largeOutputHandler.d.ts.map +1 -0
  152. package/dist/utils/largeOutputHandler.js +40 -0
  153. package/dist/utils/markdownParser.d.ts.map +1 -1
  154. package/dist/utils/markdownParser.js +1 -17
  155. package/dist/utils/mcpUtils.d.ts.map +1 -1
  156. package/dist/utils/mcpUtils.js +25 -3
  157. package/dist/utils/messageOperations.d.ts +20 -18
  158. package/dist/utils/messageOperations.d.ts.map +1 -1
  159. package/dist/utils/messageOperations.js +30 -38
  160. package/dist/utils/pathEncoder.d.ts +108 -0
  161. package/dist/utils/pathEncoder.d.ts.map +1 -0
  162. package/dist/utils/pathEncoder.js +279 -0
  163. package/dist/utils/subagentParser.d.ts +2 -2
  164. package/dist/utils/subagentParser.d.ts.map +1 -1
  165. package/dist/utils/subagentParser.js +12 -8
  166. package/dist/utils/tokenCalculation.d.ts +26 -0
  167. package/dist/utils/tokenCalculation.d.ts.map +1 -0
  168. package/dist/utils/tokenCalculation.js +36 -0
  169. package/dist/utils/tokenEstimator.d.ts +39 -0
  170. package/dist/utils/tokenEstimator.d.ts.map +1 -0
  171. package/dist/utils/tokenEstimator.js +55 -0
  172. package/package.json +6 -6
  173. package/src/agent.ts +586 -78
  174. package/src/index.ts +4 -0
  175. package/src/managers/aiManager.ts +341 -192
  176. package/src/managers/backgroundBashManager.ts +11 -9
  177. package/src/managers/hookManager.ts +102 -54
  178. package/src/managers/liveConfigManager.ts +634 -0
  179. package/src/managers/lspManager.ts +434 -0
  180. package/src/managers/messageManager.ts +258 -121
  181. package/src/managers/permissionManager.ts +276 -0
  182. package/src/managers/skillManager.ts +3 -1
  183. package/src/managers/slashCommandManager.ts +5 -3
  184. package/src/managers/subagentManager.ts +295 -76
  185. package/src/managers/toolManager.ts +95 -3
  186. package/src/services/aiService.ts +656 -84
  187. package/src/services/configurationService.ts +762 -0
  188. package/src/services/fileWatcher.ts +300 -0
  189. package/src/services/hook.ts +54 -144
  190. package/src/services/jsonlHandler.ts +303 -0
  191. package/src/services/memory.ts +34 -11
  192. package/src/services/session.ts +522 -173
  193. package/src/tools/bashTool.ts +94 -20
  194. package/src/tools/deleteFileTool.ts +38 -1
  195. package/src/tools/editTool.ts +44 -9
  196. package/src/tools/lspTool.ts +760 -0
  197. package/src/tools/multiEditTool.ts +41 -11
  198. package/src/tools/readTool.ts +127 -3
  199. package/src/tools/skillTool.ts +2 -2
  200. package/src/tools/todoWriteTool.ts +33 -1
  201. package/src/tools/types.ts +15 -9
  202. package/src/tools/writeTool.ts +43 -16
  203. package/src/types/commands.ts +6 -1
  204. package/src/types/config.ts +5 -0
  205. package/src/types/configuration.ts +73 -0
  206. package/src/types/core.ts +55 -0
  207. package/src/types/environment.ts +104 -0
  208. package/src/types/fileSearch.ts +4 -0
  209. package/src/types/hooks.ts +32 -16
  210. package/src/types/index.ts +7 -0
  211. package/src/types/lsp.ts +96 -0
  212. package/src/types/messaging.ts +21 -14
  213. package/src/types/permissions.ts +48 -0
  214. package/src/types/session.ts +20 -0
  215. package/src/types/skills.ts +1 -0
  216. package/src/types/tools.ts +38 -0
  217. package/src/utils/abortUtils.ts +118 -0
  218. package/src/utils/bashHistory.ts +55 -31
  219. package/src/utils/builtinSubagents.ts +71 -0
  220. package/src/utils/cacheControlUtils.ts +475 -0
  221. package/src/utils/commandPathResolver.ts +189 -0
  222. package/src/utils/configPaths.ts +163 -0
  223. package/src/utils/constants.ts +2 -17
  224. package/src/utils/convertMessagesForAPI.ts +44 -18
  225. package/src/utils/customCommands.ts +90 -22
  226. package/src/utils/fileSearch.ts +107 -0
  227. package/src/utils/fileUtils.ts +160 -0
  228. package/src/utils/globalLogger.ts +128 -0
  229. package/src/utils/largeOutputHandler.ts +55 -0
  230. package/src/utils/markdownParser.ts +1 -19
  231. package/src/utils/mcpUtils.ts +34 -3
  232. package/src/utils/messageOperations.ts +47 -53
  233. package/src/utils/pathEncoder.ts +394 -0
  234. package/src/utils/subagentParser.ts +13 -9
  235. package/src/utils/tokenCalculation.ts +43 -0
  236. package/src/utils/tokenEstimator.ts +68 -0
  237. package/dist/utils/configResolver.d.ts +0 -38
  238. package/dist/utils/configResolver.d.ts.map +0 -1
  239. package/dist/utils/configResolver.js +0 -106
  240. package/src/utils/configResolver.ts +0 -142
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Path encoding utility for converting working directory paths to filesystem-safe names
3
+ * Handles cross-platform directory name encoding for project-based session organization
4
+ */
5
+ import { resolve, join } from "path";
6
+ import { createHash } from "crypto";
7
+ import { realpath, mkdir } from "fs/promises";
8
+ import { homedir, platform } from "os";
9
+ /**
10
+ * PathEncoder class for converting working directory paths to filesystem-safe names
11
+ */
12
+ export class PathEncoder {
13
+ constructor(options = {}) {
14
+ this.options = {
15
+ maxLength: options.maxLength ?? 200,
16
+ pathSeparatorReplacement: options.pathSeparatorReplacement ?? "-",
17
+ spaceReplacement: options.spaceReplacement ?? "_",
18
+ invalidCharReplacement: options.invalidCharReplacement ?? "_",
19
+ preserveCase: options.preserveCase ?? false,
20
+ hashLength: options.hashLength ?? 8,
21
+ };
22
+ this.constraints = this.getFilesystemConstraints();
23
+ }
24
+ /**
25
+ * Encode a working directory path to a filesystem-safe directory name
26
+ */
27
+ async encode(originalPath) {
28
+ // Resolve symbolic links and normalize path
29
+ const resolvedPath = await this.resolvePath(originalPath);
30
+ return this.encodeSync(resolvedPath);
31
+ }
32
+ /**
33
+ * Synchronously encode a path to a filesystem-safe directory name
34
+ * Note: Does not resolve symbolic links - use encode() for full path resolution
35
+ */
36
+ encodeSync(pathToEncode) {
37
+ // Convert to safe directory name
38
+ let encoded = pathToEncode;
39
+ // Remove leading slash to avoid empty directory names
40
+ if (encoded.startsWith("/")) {
41
+ encoded = encoded.substring(1);
42
+ }
43
+ // Replace path separators with hyphens
44
+ encoded = encoded.replace(/[/\\]/g, this.options.pathSeparatorReplacement);
45
+ // Replace spaces with underscores
46
+ encoded = encoded.replace(/\s+/g, this.options.spaceReplacement);
47
+ // Replace invalid characters with underscores
48
+ const escapedChars = this.constraints.invalidCharacters
49
+ .map((c) => `\\${c}`)
50
+ .join("");
51
+ const invalidChars = new RegExp(`[${escapedChars}]`, "g");
52
+ encoded = encoded.replace(invalidChars, this.options.invalidCharReplacement);
53
+ // Convert to lowercase unless preserveCase is true
54
+ if (!this.options.preserveCase) {
55
+ encoded = encoded.toLowerCase();
56
+ }
57
+ // Handle length limit with hash
58
+ if (encoded.length > this.options.maxLength) {
59
+ const hash = this.generateHash(pathToEncode, this.options.hashLength);
60
+ const maxBaseLength = this.options.maxLength - this.options.hashLength - 1; // -1 for separator
61
+ encoded = `${encoded.substring(0, maxBaseLength)}-${hash}`;
62
+ }
63
+ return encoded;
64
+ }
65
+ /**
66
+ * Decode an encoded directory name back to original path (limited functionality)
67
+ * Note: This is best-effort as encoding is lossy
68
+ */
69
+ async decode(encodedName) {
70
+ return this.decodeSync(encodedName);
71
+ }
72
+ /**
73
+ * Synchronously decode an encoded directory name back to original path (limited functionality)
74
+ * Note: This is best-effort as encoding is lossy
75
+ */
76
+ decodeSync(encodedName) {
77
+ // This is a simplified version - full reversal is not always possible
78
+ // due to lossy encoding (case changes, character replacements, hashing)
79
+ // Check if this has a hash suffix
80
+ const hashPattern = new RegExp(`-[a-f0-9]{${this.options.hashLength}}$`);
81
+ if (hashPattern.test(encodedName)) {
82
+ // Cannot reliably decode hashed paths
83
+ return null;
84
+ }
85
+ // Attempt basic reversal
86
+ let decoded = encodedName;
87
+ // Reverse path separator replacement
88
+ decoded = decoded.replace(new RegExp(this.options.pathSeparatorReplacement, "g"), "/");
89
+ // Reverse space replacement
90
+ decoded = decoded.replace(new RegExp(this.options.spaceReplacement, "g"), " ");
91
+ // Add leading slash
92
+ decoded = `/${decoded}`;
93
+ return decoded;
94
+ }
95
+ /**
96
+ * Resolve symbolic links and normalize path before encoding
97
+ */
98
+ async resolvePath(path) {
99
+ try {
100
+ // Expand tilde to home directory
101
+ const expandedPath = this.expandTilde(path);
102
+ // Resolve to absolute path
103
+ const absolutePath = resolve(expandedPath);
104
+ // Resolve symbolic links
105
+ const resolvedPath = await realpath(absolutePath);
106
+ return resolvedPath;
107
+ }
108
+ catch (error) {
109
+ throw new Error(`Failed to resolve path "${path}": ${error}`);
110
+ }
111
+ }
112
+ /**
113
+ * Get project directory info without creating the directory
114
+ */
115
+ async getProjectDirectory(originalPath, baseSessionDir) {
116
+ // Resolve the original path and check for symbolic links
117
+ const expandedPath = this.expandTilde(originalPath);
118
+ const absolutePath = resolve(expandedPath);
119
+ let resolvedPath;
120
+ let isSymbolicLink = false;
121
+ try {
122
+ resolvedPath = await realpath(absolutePath);
123
+ isSymbolicLink = resolvedPath !== absolutePath;
124
+ }
125
+ catch {
126
+ // If realpath fails, use the absolute path
127
+ resolvedPath = absolutePath;
128
+ }
129
+ // Encode the resolved path
130
+ const encodedName = await this.encode(resolvedPath);
131
+ const encodedPath = join(baseSessionDir, encodedName);
132
+ // Generate hash if encoding resulted in truncation
133
+ let pathHash;
134
+ if (resolvedPath.length > this.options.maxLength) {
135
+ pathHash = this.generateHash(resolvedPath, this.options.hashLength);
136
+ }
137
+ return {
138
+ originalPath: resolvedPath,
139
+ encodedName,
140
+ encodedPath,
141
+ pathHash,
142
+ isSymbolicLink,
143
+ };
144
+ }
145
+ /**
146
+ * Create project directory entity from original path
147
+ */
148
+ async createProjectDirectory(originalPath, baseSessionDir) {
149
+ const projectDirectory = await this.getProjectDirectory(originalPath, baseSessionDir);
150
+ // Ensure the encoded directory exists
151
+ try {
152
+ await mkdir(projectDirectory.encodedPath, { recursive: true });
153
+ }
154
+ catch {
155
+ // Ignore errors if directory already exists
156
+ }
157
+ return projectDirectory;
158
+ }
159
+ /**
160
+ * Validate that an encoded name is filesystem-safe
161
+ */
162
+ validateEncodedName(encodedName) {
163
+ // Check length
164
+ if (encodedName.length > this.constraints.maxDirectoryNameLength) {
165
+ return false;
166
+ }
167
+ // Check for invalid characters
168
+ for (const char of this.constraints.invalidCharacters) {
169
+ if (encodedName.includes(char)) {
170
+ return false;
171
+ }
172
+ }
173
+ // Check for reserved names
174
+ const lowerName = encodedName.toLowerCase();
175
+ if (this.constraints.reservedNames.some((reserved) => reserved.toLowerCase() === lowerName)) {
176
+ return false;
177
+ }
178
+ // Check for empty or dots-only names
179
+ if (!encodedName.trim() || /^\.+$/.test(encodedName)) {
180
+ return false;
181
+ }
182
+ return true;
183
+ }
184
+ /**
185
+ * Handle encoding collisions by generating unique names
186
+ */
187
+ resolveCollision(baseName, existingNames) {
188
+ if (!existingNames.has(baseName)) {
189
+ return baseName;
190
+ }
191
+ // Try numbered suffixes first
192
+ for (let i = 1; i <= 999; i++) {
193
+ const candidate = `${baseName}-${i}`;
194
+ if (!existingNames.has(candidate)) {
195
+ return candidate;
196
+ }
197
+ }
198
+ // If all numbered suffixes are taken, use hash
199
+ const hash = this.generateHash(baseName + Date.now(), this.options.hashLength);
200
+ return `${baseName}-${hash}`;
201
+ }
202
+ /**
203
+ * Get platform-specific filesystem constraints
204
+ */
205
+ getFilesystemConstraints() {
206
+ const currentPlatform = platform();
207
+ switch (currentPlatform) {
208
+ case "win32":
209
+ return {
210
+ maxDirectoryNameLength: 255,
211
+ maxPathLength: 260,
212
+ invalidCharacters: ["<", ">", ":", '"', "|", "?", "*"],
213
+ reservedNames: [
214
+ "CON",
215
+ "PRN",
216
+ "AUX",
217
+ "NUL",
218
+ "COM1",
219
+ "COM2",
220
+ "COM3",
221
+ "COM4",
222
+ "COM5",
223
+ "COM6",
224
+ "COM7",
225
+ "COM8",
226
+ "COM9",
227
+ "LPT1",
228
+ "LPT2",
229
+ "LPT3",
230
+ "LPT4",
231
+ "LPT5",
232
+ "LPT6",
233
+ "LPT7",
234
+ "LPT8",
235
+ "LPT9",
236
+ ],
237
+ caseSensitive: false,
238
+ };
239
+ case "darwin":
240
+ return {
241
+ maxDirectoryNameLength: 255,
242
+ maxPathLength: 1024,
243
+ invalidCharacters: [":"],
244
+ reservedNames: [],
245
+ caseSensitive: false, // HFS+ is case-insensitive by default
246
+ };
247
+ default: // Linux and other Unix-like systems
248
+ return {
249
+ maxDirectoryNameLength: 255,
250
+ maxPathLength: 4096,
251
+ invalidCharacters: ["\0"],
252
+ reservedNames: [],
253
+ caseSensitive: true,
254
+ };
255
+ }
256
+ }
257
+ /**
258
+ * Generate hash for collision resolution
259
+ */
260
+ generateHash(input, length) {
261
+ return createHash("sha256")
262
+ .update(input)
263
+ .digest("hex")
264
+ .substring(0, length);
265
+ }
266
+ /**
267
+ * Expand tilde (~) to home directory
268
+ */
269
+ expandTilde(path) {
270
+ if (path.startsWith("~/") || path === "~") {
271
+ return path.replace(/^~/, homedir());
272
+ }
273
+ return path;
274
+ }
275
+ }
276
+ /**
277
+ * Default PathEncoder instance
278
+ */
279
+ export const pathEncoder = new PathEncoder();
@@ -5,11 +5,11 @@ export interface SubagentConfiguration {
5
5
  model?: string;
6
6
  systemPrompt: string;
7
7
  filePath: string;
8
- scope: "project" | "user";
8
+ scope: "project" | "user" | "builtin";
9
9
  priority: number;
10
10
  }
11
11
  /**
12
- * Load all subagent configurations from project and user directories
12
+ * Load all subagent configurations from project and user directories, plus built-in subagents
13
13
  */
14
14
  export declare function loadSubagentConfigurations(workdir: string): Promise<SubagentConfiguration[]>;
15
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"subagentParser.d.ts","sourceRoot":"","sources":["../../src/utils/subagentParser.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AA+KD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAmBlC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAGvC"}
1
+ {"version":3,"file":"subagentParser.d.ts","sourceRoot":"","sources":["../../src/utils/subagentParser.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AA+KD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAsBlC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAGvC"}
@@ -1,5 +1,6 @@
1
1
  import { readFileSync, readdirSync, statSync } from "fs";
2
2
  import { join, extname } from "path";
3
+ import { logger } from "./globalLogger.js";
3
4
  /**
4
5
  * Parse YAML frontmatter from markdown file content
5
6
  */
@@ -67,10 +68,10 @@ function validateConfiguration(config, filePath) {
67
68
  if (!config.description) {
68
69
  throw new Error(`Missing required field 'description' in ${filePath}`);
69
70
  }
70
- // Validate name pattern
71
- const namePattern = /^[a-z][a-z0-9-]*$/;
71
+ // Validate name pattern - allow letters (upper/lowercase), numbers, and hyphens
72
+ const namePattern = /^[a-zA-Z][a-zA-Z0-9-]*$/;
72
73
  if (!namePattern.test(config.name)) {
73
- throw new Error(`Invalid subagent name '${config.name}' in ${filePath}. Must start with a letter and contain only lowercase letters, numbers, and hyphens.`);
74
+ throw new Error(`Invalid subagent name '${config.name}' in ${filePath}. Must start with a letter and contain only letters, numbers, and hyphens.`);
74
75
  }
75
76
  // Validate model if specified - allow any non-empty string
76
77
  if (config.model && typeof config.model !== "string") {
@@ -120,7 +121,7 @@ function scanSubagentDirectory(dirPath, scope) {
120
121
  }
121
122
  catch (parseError) {
122
123
  // Log error but continue with other files
123
- console.warn(`Warning: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
124
+ logger.warn(`Warning: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
124
125
  }
125
126
  }
126
127
  }
@@ -131,17 +132,20 @@ function scanSubagentDirectory(dirPath, scope) {
131
132
  return configurations;
132
133
  }
133
134
  /**
134
- * Load all subagent configurations from project and user directories
135
+ * Load all subagent configurations from project and user directories, plus built-in subagents
135
136
  */
136
137
  export async function loadSubagentConfigurations(workdir) {
137
138
  const projectDir = join(workdir, ".wave", "agents");
138
139
  const userDir = join(process.env.HOME || "~", ".wave", "agents");
140
+ // Load configurations from all sources
141
+ const { getBuiltinSubagents } = await import("./builtinSubagents.js");
142
+ const builtinConfigs = getBuiltinSubagents();
139
143
  const projectConfigs = scanSubagentDirectory(projectDir, "project");
140
144
  const userConfigs = scanSubagentDirectory(userDir, "user");
141
- // Merge configurations, with project configs taking precedence
145
+ // Merge configurations, with project configs taking highest precedence
142
146
  const configMap = new Map();
143
- // Process in reverse priority order (user first, then project)
144
- for (const config of [...userConfigs, ...projectConfigs]) {
147
+ // Process in reverse priority order (built-in first, then user, then project)
148
+ for (const config of [...builtinConfigs, ...userConfigs, ...projectConfigs]) {
145
149
  configMap.set(config.name, config);
146
150
  }
147
151
  return Array.from(configMap.values()).sort((a, b) => {
@@ -0,0 +1,26 @@
1
+ import type { Usage } from "../types/index.js";
2
+ /**
3
+ * Calculate comprehensive total tokens including cache-related tokens
4
+ *
5
+ * This function computes the true total token cost by including:
6
+ * - Base total_tokens (prompt + completion)
7
+ * - Cache read tokens (cost savings indicator)
8
+ * - Cache creation tokens (cache investment)
9
+ *
10
+ * For accurate cost tracking with Claude models that support cache control.
11
+ *
12
+ * @param usage - Usage statistics from AI operation
13
+ * @returns Comprehensive total including all cache-related tokens
14
+ */
15
+ export declare function calculateComprehensiveTotalTokens(usage: Usage): number;
16
+ /**
17
+ * Extract the latest total tokens from the last message with usage data
18
+ * Uses comprehensive calculation that includes cache tokens for accurate tracking
19
+ *
20
+ * @param messages - Array of messages to search
21
+ * @returns Comprehensive total tokens from the most recent usage data, or 0 if none found
22
+ */
23
+ export declare function extractLatestTotalTokens(messages: Array<{
24
+ usage?: Usage;
25
+ }>): number;
26
+ //# sourceMappingURL=tokenCalculation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenCalculation.d.ts","sourceRoot":"","sources":["../../src/utils/tokenCalculation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAMtE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,KAAK,CAAC;IAAE,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,GACjC,MAAM,CAUR"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Calculate comprehensive total tokens including cache-related tokens
3
+ *
4
+ * This function computes the true total token cost by including:
5
+ * - Base total_tokens (prompt + completion)
6
+ * - Cache read tokens (cost savings indicator)
7
+ * - Cache creation tokens (cache investment)
8
+ *
9
+ * For accurate cost tracking with Claude models that support cache control.
10
+ *
11
+ * @param usage - Usage statistics from AI operation
12
+ * @returns Comprehensive total including all cache-related tokens
13
+ */
14
+ export function calculateComprehensiveTotalTokens(usage) {
15
+ const baseTokens = usage.total_tokens;
16
+ const cacheReadTokens = usage.cache_read_input_tokens || 0;
17
+ const cacheCreateTokens = usage.cache_creation_input_tokens || 0;
18
+ return baseTokens + cacheReadTokens + cacheCreateTokens;
19
+ }
20
+ /**
21
+ * Extract the latest total tokens from the last message with usage data
22
+ * Uses comprehensive calculation that includes cache tokens for accurate tracking
23
+ *
24
+ * @param messages - Array of messages to search
25
+ * @returns Comprehensive total tokens from the most recent usage data, or 0 if none found
26
+ */
27
+ export function extractLatestTotalTokens(messages) {
28
+ // Find the last message with usage data (iterate backwards for efficiency)
29
+ for (let i = messages.length - 1; i >= 0; i--) {
30
+ const message = messages[i];
31
+ if (message.usage) {
32
+ return calculateComprehensiveTotalTokens(message.usage);
33
+ }
34
+ }
35
+ return 0; // No usage data found
36
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Simple token estimation utility for text content
3
+ *
4
+ * This provides a fast approximation of token count without requiring
5
+ * actual tokenization, which would be expensive for large content.
6
+ */
7
+ /**
8
+ * Estimate the number of tokens in a text string
9
+ *
10
+ * Uses a simple heuristic based on character count and common patterns:
11
+ * - Average token length varies by language and content type
12
+ * - English text: ~4-5 characters per token
13
+ * - Code/structured text: ~3-4 characters per token
14
+ * - Numbers/symbols: ~2-3 characters per token
15
+ *
16
+ * This function uses a conservative estimate of 4 characters per token
17
+ * which works well for mixed content (text + code + symbols).
18
+ *
19
+ * @param text - The text to estimate tokens for
20
+ * @returns Estimated number of tokens
21
+ */
22
+ export declare function estimateTokenCount(text: string): number;
23
+ /**
24
+ * Check if estimated token count exceeds a threshold
25
+ *
26
+ * @param text - The text to check
27
+ * @param threshold - Token threshold (default: 20,000)
28
+ * @returns True if estimated tokens exceed threshold
29
+ */
30
+ export declare function exceedsTokenThreshold(text: string, threshold?: number): boolean;
31
+ /**
32
+ * Get a human-readable description of estimated token usage
33
+ *
34
+ * @param text - The text to analyze
35
+ * @param threshold - Token threshold for comparison
36
+ * @returns Description string with token count and threshold info
37
+ */
38
+ export declare function getTokenUsageDescription(text: string, threshold?: number): string;
39
+ //# sourceMappingURL=tokenEstimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenEstimator.d.ts","sourceRoot":"","sources":["../../src/utils/tokenEstimator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAc,GACxB,OAAO,CAET;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAc,GACxB,MAAM,CAKR"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Simple token estimation utility for text content
3
+ *
4
+ * This provides a fast approximation of token count without requiring
5
+ * actual tokenization, which would be expensive for large content.
6
+ */
7
+ /**
8
+ * Estimate the number of tokens in a text string
9
+ *
10
+ * Uses a simple heuristic based on character count and common patterns:
11
+ * - Average token length varies by language and content type
12
+ * - English text: ~4-5 characters per token
13
+ * - Code/structured text: ~3-4 characters per token
14
+ * - Numbers/symbols: ~2-3 characters per token
15
+ *
16
+ * This function uses a conservative estimate of 4 characters per token
17
+ * which works well for mixed content (text + code + symbols).
18
+ *
19
+ * @param text - The text to estimate tokens for
20
+ * @returns Estimated number of tokens
21
+ */
22
+ export function estimateTokenCount(text) {
23
+ if (!text || text.length === 0) {
24
+ return 0;
25
+ }
26
+ // Base estimation: 4 characters per token (conservative)
27
+ const baseEstimate = Math.ceil(text.length / 4);
28
+ // Adjust for whitespace (spaces don't contribute much to token count)
29
+ const whitespaceCount = (text.match(/\s/g) || []).length;
30
+ const adjustedEstimate = Math.ceil((text.length - whitespaceCount * 0.5) / 4);
31
+ // Use the more conservative (higher) estimate
32
+ return Math.max(baseEstimate, adjustedEstimate);
33
+ }
34
+ /**
35
+ * Check if estimated token count exceeds a threshold
36
+ *
37
+ * @param text - The text to check
38
+ * @param threshold - Token threshold (default: 20,000)
39
+ * @returns True if estimated tokens exceed threshold
40
+ */
41
+ export function exceedsTokenThreshold(text, threshold = 20000) {
42
+ return estimateTokenCount(text) > threshold;
43
+ }
44
+ /**
45
+ * Get a human-readable description of estimated token usage
46
+ *
47
+ * @param text - The text to analyze
48
+ * @param threshold - Token threshold for comparison
49
+ * @returns Description string with token count and threshold info
50
+ */
51
+ export function getTokenUsageDescription(text, threshold = 20000) {
52
+ const estimatedTokens = estimateTokenCount(text);
53
+ const exceedsThreshold = estimatedTokens > threshold;
54
+ return `${estimatedTokens.toLocaleString()} tokens (${exceedsThreshold ? "exceeds" : "within"} ${threshold.toLocaleString()} limit)`;
55
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
@@ -21,25 +21,25 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/sdk": "^1.18.2",
23
23
  "@vscode/ripgrep": "^1.15.14",
24
- "diff": "^8.0.2",
25
- "glob": "^11.0.3",
24
+ "chokidar": "^5.0.0",
25
+ "glob": "^13.0.0",
26
26
  "minimatch": "^10.0.3",
27
27
  "openai": "^5.12.2"
28
28
  },
29
29
  "devDependencies": {
30
- "rimraf": "^6.0.1",
30
+ "rimraf": "^6.1.2",
31
31
  "tsc-alias": "^1.8.16",
32
32
  "tsx": "^4.20.4",
33
33
  "vitest": "^3.2.4"
34
34
  },
35
35
  "engines": {
36
- "node": ">=16.0.0"
36
+ "node": ">=22.0.0"
37
37
  },
38
38
  "license": "MIT",
39
39
  "scripts": {
40
40
  "build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
41
41
  "type-check": "tsc --noEmit --incremental",
42
- "dev": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
42
+ "watch": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
43
43
  "test": "vitest run",
44
44
  "lint": "eslint --cache",
45
45
  "format": "prettier --write ."