wave-agent-sdk 0.0.8 → 0.0.11

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 (236) hide show
  1. package/dist/agent.d.ts +92 -23
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +351 -137
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -0
  7. package/dist/managers/aiManager.d.ts +14 -36
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +74 -77
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +4 -3
  12. package/dist/managers/hookManager.d.ts +3 -8
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +39 -29
  15. package/dist/managers/liveConfigManager.d.ts +55 -18
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  17. package/dist/managers/liveConfigManager.js +372 -90
  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 +8 -16
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +52 -74
  24. package/dist/managers/permissionManager.d.ts +75 -0
  25. package/dist/managers/permissionManager.d.ts.map +1 -0
  26. package/dist/managers/permissionManager.js +368 -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 +0 -1
  32. package/dist/managers/subagentManager.d.ts +8 -23
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +97 -117
  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 +3 -1
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +123 -30
  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.map +1 -1
  45. package/dist/services/fileWatcher.js +5 -6
  46. package/dist/services/hook.d.ts +7 -124
  47. package/dist/services/hook.d.ts.map +1 -1
  48. package/dist/services/hook.js +46 -458
  49. package/dist/services/jsonlHandler.d.ts +24 -15
  50. package/dist/services/jsonlHandler.d.ts.map +1 -1
  51. package/dist/services/jsonlHandler.js +67 -88
  52. package/dist/services/memory.d.ts +0 -9
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +2 -49
  55. package/dist/services/session.d.ts +82 -33
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +275 -181
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +109 -11
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +25 -0
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +30 -6
  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 +26 -7
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +111 -2
  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 +25 -9
  78. package/dist/types/commands.d.ts +0 -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 +10 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +41 -0
  88. package/dist/types/environment.d.ts.map +1 -1
  89. package/dist/types/fileSearch.d.ts +5 -0
  90. package/dist/types/fileSearch.d.ts.map +1 -0
  91. package/dist/types/fileSearch.js +1 -0
  92. package/dist/types/hooks.d.ts +11 -2
  93. package/dist/types/hooks.d.ts.map +1 -1
  94. package/dist/types/hooks.js +1 -7
  95. package/dist/types/index.d.ts +5 -0
  96. package/dist/types/index.d.ts.map +1 -1
  97. package/dist/types/index.js +5 -0
  98. package/dist/types/lsp.d.ts +90 -0
  99. package/dist/types/lsp.d.ts.map +1 -0
  100. package/dist/types/lsp.js +4 -0
  101. package/dist/types/messaging.d.ts +6 -11
  102. package/dist/types/messaging.d.ts.map +1 -1
  103. package/dist/types/permissions.d.ts +39 -0
  104. package/dist/types/permissions.d.ts.map +1 -0
  105. package/dist/types/permissions.js +12 -0
  106. package/dist/types/session.d.ts +1 -6
  107. package/dist/types/session.d.ts.map +1 -1
  108. package/dist/types/skills.d.ts +1 -0
  109. package/dist/types/skills.d.ts.map +1 -1
  110. package/dist/types/tools.d.ts +35 -0
  111. package/dist/types/tools.d.ts.map +1 -0
  112. package/dist/types/tools.js +4 -0
  113. package/dist/utils/abortUtils.d.ts +34 -0
  114. package/dist/utils/abortUtils.d.ts.map +1 -0
  115. package/dist/utils/abortUtils.js +92 -0
  116. package/dist/utils/bashHistory.d.ts +4 -0
  117. package/dist/utils/bashHistory.d.ts.map +1 -1
  118. package/dist/utils/bashHistory.js +21 -4
  119. package/dist/utils/bashParser.d.ts +24 -0
  120. package/dist/utils/bashParser.d.ts.map +1 -0
  121. package/dist/utils/bashParser.js +413 -0
  122. package/dist/utils/builtinSubagents.d.ts +7 -0
  123. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  124. package/dist/utils/builtinSubagents.js +65 -0
  125. package/dist/utils/cacheControlUtils.d.ts +8 -33
  126. package/dist/utils/cacheControlUtils.d.ts.map +1 -1
  127. package/dist/utils/cacheControlUtils.js +83 -126
  128. package/dist/utils/constants.d.ts +0 -12
  129. package/dist/utils/constants.d.ts.map +1 -1
  130. package/dist/utils/constants.js +1 -13
  131. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  132. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  133. package/dist/utils/convertMessagesForAPI.js +33 -14
  134. package/dist/utils/fileSearch.d.ts +14 -0
  135. package/dist/utils/fileSearch.d.ts.map +1 -0
  136. package/dist/utils/fileSearch.js +88 -0
  137. package/dist/utils/fileUtils.d.ts +14 -2
  138. package/dist/utils/fileUtils.d.ts.map +1 -1
  139. package/dist/utils/fileUtils.js +101 -17
  140. package/dist/utils/globalLogger.d.ts +0 -14
  141. package/dist/utils/globalLogger.d.ts.map +1 -1
  142. package/dist/utils/globalLogger.js +0 -16
  143. package/dist/utils/markdownParser.d.ts.map +1 -1
  144. package/dist/utils/markdownParser.js +1 -17
  145. package/dist/utils/messageOperations.d.ts +1 -11
  146. package/dist/utils/messageOperations.d.ts.map +1 -1
  147. package/dist/utils/messageOperations.js +7 -24
  148. package/dist/utils/pathEncoder.d.ts +4 -0
  149. package/dist/utils/pathEncoder.d.ts.map +1 -1
  150. package/dist/utils/pathEncoder.js +16 -9
  151. package/dist/utils/pathSafety.d.ts +10 -0
  152. package/dist/utils/pathSafety.d.ts.map +1 -0
  153. package/dist/utils/pathSafety.js +23 -0
  154. package/dist/utils/subagentParser.d.ts +2 -2
  155. package/dist/utils/subagentParser.d.ts.map +1 -1
  156. package/dist/utils/subagentParser.js +10 -7
  157. package/package.json +9 -9
  158. package/src/agent.ts +475 -216
  159. package/src/index.ts +3 -0
  160. package/src/managers/aiManager.ts +107 -111
  161. package/src/managers/backgroundBashManager.ts +4 -3
  162. package/src/managers/hookManager.ts +44 -39
  163. package/src/managers/liveConfigManager.ts +524 -138
  164. package/src/managers/lspManager.ts +434 -0
  165. package/src/managers/messageManager.ts +73 -103
  166. package/src/managers/permissionManager.ts +480 -0
  167. package/src/managers/skillManager.ts +3 -1
  168. package/src/managers/slashCommandManager.ts +1 -2
  169. package/src/managers/subagentManager.ts +116 -159
  170. package/src/managers/toolManager.ts +95 -3
  171. package/src/services/aiService.ts +207 -26
  172. package/src/services/configurationService.ts +762 -0
  173. package/src/services/fileWatcher.ts +5 -6
  174. package/src/services/hook.ts +50 -631
  175. package/src/services/jsonlHandler.ts +84 -100
  176. package/src/services/memory.ts +2 -59
  177. package/src/services/session.ts +338 -213
  178. package/src/tools/bashTool.ts +126 -13
  179. package/src/tools/deleteFileTool.ts +36 -0
  180. package/src/tools/editTool.ts +41 -7
  181. package/src/tools/lspTool.ts +760 -0
  182. package/src/tools/multiEditTool.ts +37 -8
  183. package/src/tools/readTool.ts +125 -2
  184. package/src/tools/skillTool.ts +2 -2
  185. package/src/tools/todoWriteTool.ts +33 -1
  186. package/src/tools/types.ts +15 -9
  187. package/src/tools/writeTool.ts +36 -10
  188. package/src/types/commands.ts +0 -1
  189. package/src/types/config.ts +5 -0
  190. package/src/types/configuration.ts +73 -0
  191. package/src/types/core.ts +11 -0
  192. package/src/types/environment.ts +44 -0
  193. package/src/types/fileSearch.ts +4 -0
  194. package/src/types/hooks.ts +14 -11
  195. package/src/types/index.ts +5 -0
  196. package/src/types/lsp.ts +96 -0
  197. package/src/types/messaging.ts +8 -13
  198. package/src/types/permissions.ts +52 -0
  199. package/src/types/session.ts +3 -8
  200. package/src/types/skills.ts +1 -0
  201. package/src/types/tools.ts +38 -0
  202. package/src/utils/abortUtils.ts +118 -0
  203. package/src/utils/bashHistory.ts +28 -4
  204. package/src/utils/bashParser.ts +444 -0
  205. package/src/utils/builtinSubagents.ts +71 -0
  206. package/src/utils/cacheControlUtils.ts +106 -171
  207. package/src/utils/constants.ts +1 -16
  208. package/src/utils/convertMessagesForAPI.ts +38 -14
  209. package/src/utils/fileSearch.ts +107 -0
  210. package/src/utils/fileUtils.ts +114 -19
  211. package/src/utils/globalLogger.ts +0 -17
  212. package/src/utils/markdownParser.ts +1 -19
  213. package/src/utils/messageOperations.ts +7 -35
  214. package/src/utils/pathEncoder.ts +24 -9
  215. package/src/utils/pathSafety.ts +26 -0
  216. package/src/utils/subagentParser.ts +11 -8
  217. package/dist/constants/events.d.ts +0 -28
  218. package/dist/constants/events.d.ts.map +0 -1
  219. package/dist/constants/events.js +0 -27
  220. package/dist/services/configurationWatcher.d.ts +0 -120
  221. package/dist/services/configurationWatcher.d.ts.map +0 -1
  222. package/dist/services/configurationWatcher.js +0 -439
  223. package/dist/services/memoryStore.d.ts +0 -81
  224. package/dist/services/memoryStore.d.ts.map +0 -1
  225. package/dist/services/memoryStore.js +0 -200
  226. package/dist/types/memoryStore.d.ts +0 -82
  227. package/dist/types/memoryStore.d.ts.map +0 -1
  228. package/dist/types/memoryStore.js +0 -7
  229. package/dist/utils/configResolver.d.ts +0 -65
  230. package/dist/utils/configResolver.d.ts.map +0 -1
  231. package/dist/utils/configResolver.js +0 -210
  232. package/src/constants/events.ts +0 -38
  233. package/src/services/configurationWatcher.ts +0 -622
  234. package/src/services/memoryStore.ts +0 -279
  235. package/src/types/memoryStore.ts +0 -94
  236. package/src/utils/configResolver.ts +0 -302
@@ -2,7 +2,6 @@ import { readFile, writeFile } from "fs/promises";
2
2
  import { logger } from "../utils/globalLogger.js";
3
3
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
4
4
  import { resolvePath, getDisplayPath } from "../utils/path.js";
5
- import { diffLines } from "diff";
6
5
 
7
6
  interface EditOperation {
8
7
  old_string: string;
@@ -182,7 +181,7 @@ export const multiEditTool: ToolPlugin = {
182
181
  return {
183
182
  success: false,
184
183
  content: "",
185
- error: `Edit operation ${i + 1}: old_string not found in current content: "${edit.old_string}"`,
184
+ error: `Edit operation ${i + 1}: old_string not found in current content`,
186
185
  };
187
186
  }
188
187
 
@@ -217,6 +216,42 @@ export const multiEditTool: ToolPlugin = {
217
216
  }
218
217
  }
219
218
 
219
+ // Permission check after validation but before real operation
220
+ if (
221
+ context.permissionManager &&
222
+ context.permissionMode &&
223
+ context.permissionMode !== "bypassPermissions"
224
+ ) {
225
+ if (context.permissionManager.isRestrictedTool("MultiEdit")) {
226
+ try {
227
+ const permissionContext = context.permissionManager.createContext(
228
+ "MultiEdit",
229
+ context.permissionMode,
230
+ context.canUseToolCallback,
231
+ { file_path: filePath, edits },
232
+ );
233
+ const permissionResult =
234
+ await context.permissionManager.checkPermission(
235
+ permissionContext,
236
+ );
237
+
238
+ if (permissionResult.behavior === "deny") {
239
+ return {
240
+ success: false,
241
+ content: "",
242
+ error: `MultiEdit operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
243
+ };
244
+ }
245
+ } catch {
246
+ return {
247
+ success: false,
248
+ content: "",
249
+ error: "Permission check failed",
250
+ };
251
+ }
252
+ }
253
+ }
254
+
220
255
  // Write file
221
256
  try {
222
257
  await writeFile(resolvedPath, currentContent, "utf-8");
@@ -228,9 +263,6 @@ export const multiEditTool: ToolPlugin = {
228
263
  };
229
264
  }
230
265
 
231
- // Generate diff information
232
- const diffResult = diffLines(originalContent, currentContent);
233
-
234
266
  const shortResult = isNewFile
235
267
  ? `Created file with ${edits.length} operations`
236
268
  : `Applied ${edits.length} edits`;
@@ -244,9 +276,6 @@ export const multiEditTool: ToolPlugin = {
244
276
  content: detailedContent,
245
277
  shortResult,
246
278
  filePath: resolvedPath,
247
- originalContent,
248
- newContent: currentContent,
249
- diffResult,
250
279
  };
251
280
  } catch (error) {
252
281
  const errorMessage =
@@ -1,4 +1,5 @@
1
- import { readFile } from "fs/promises";
1
+ import { readFile, stat } from "fs/promises";
2
+ import { extname } from "path";
2
3
  import { logger } from "../utils/globalLogger.js";
3
4
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
4
5
  import { resolvePath, getDisplayPath } from "../utils/path.js";
@@ -6,6 +7,123 @@ import {
6
7
  isBinaryDocument,
7
8
  getBinaryDocumentError,
8
9
  } from "../utils/fileFormat.js";
10
+ import { convertImageToBase64 } from "../utils/messageOperations.js";
11
+
12
+ /**
13
+ * Supported image file extensions
14
+ */
15
+ const SUPPORTED_IMAGE_EXTENSIONS = [
16
+ "png",
17
+ "jpeg",
18
+ "jpg",
19
+ "gif",
20
+ "webp",
21
+ ] as const;
22
+
23
+ /**
24
+ * Check if a file path represents an image file
25
+ * @param filePath - Path to the file
26
+ * @returns true if the file is a supported image format
27
+ */
28
+ function isImageFile(filePath: string): boolean {
29
+ const ext = extname(filePath).toLowerCase().substring(1);
30
+ return (SUPPORTED_IMAGE_EXTENSIONS as readonly string[]).includes(ext);
31
+ }
32
+
33
+ /**
34
+ * Validate image file size
35
+ * @param filePath - Path to the image file
36
+ * @param maxSizeBytes - Maximum allowed file size in bytes (default: 20MB)
37
+ * @returns Promise<boolean> - true if file size is within limit
38
+ */
39
+ async function validateImageFileSize(
40
+ filePath: string,
41
+ maxSizeBytes: number = 20 * 1024 * 1024,
42
+ ): Promise<boolean> {
43
+ try {
44
+ const stats = await stat(filePath);
45
+ return stats.size <= maxSizeBytes;
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Get MIME type for image file based on extension
53
+ * @param filePath - Path to the image file
54
+ * @returns MIME type string
55
+ */
56
+ function getImageMimeType(filePath: string): string {
57
+ const ext = extname(filePath).toLowerCase().substring(1);
58
+ switch (ext) {
59
+ case "png":
60
+ return "image/png";
61
+ case "jpg":
62
+ case "jpeg":
63
+ return "image/jpeg";
64
+ case "gif":
65
+ return "image/gif";
66
+ case "webp":
67
+ return "image/webp";
68
+ default:
69
+ return "image/png"; // Default fallback
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Process an image file and return ToolResult with image data
75
+ * @param filePath - Path to the image file
76
+ * @param context - Tool execution context
77
+ * @returns Promise<ToolResult> with image data
78
+ */
79
+ async function processImageFile(
80
+ filePath: string,
81
+ context: ToolContext,
82
+ ): Promise<ToolResult> {
83
+ try {
84
+ // Resolve path
85
+ const actualFilePath = filePath.startsWith("/")
86
+ ? filePath
87
+ : resolvePath(filePath, context.workdir);
88
+
89
+ // Validate file size
90
+ const isValidSize = await validateImageFileSize(actualFilePath);
91
+ if (!isValidSize) {
92
+ const stats = await stat(actualFilePath);
93
+ const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
94
+ return {
95
+ success: false,
96
+ content: "",
97
+ error: `Image file exceeds 20MB limit (actual: ${sizeMB}MB)`,
98
+ };
99
+ }
100
+
101
+ // Convert image to base64
102
+ const imageDataUrl = convertImageToBase64(actualFilePath);
103
+ const mimeType = getImageMimeType(actualFilePath);
104
+
105
+ // Extract base64 data from data URL (remove data:image/type;base64, prefix)
106
+ const base64Data = imageDataUrl.split(",")[1] || "";
107
+
108
+ return {
109
+ success: true,
110
+ content: `Image file processed: ${getDisplayPath(filePath, context.workdir)}\nFormat: ${mimeType}\nSize: Available for AI processing`,
111
+ shortResult: `Image processed (${mimeType})`,
112
+ images: [
113
+ {
114
+ data: base64Data,
115
+ mediaType: mimeType,
116
+ },
117
+ ],
118
+ };
119
+ } catch (error) {
120
+ return {
121
+ success: false,
122
+ content: "",
123
+ error: `Failed to process image: ${error instanceof Error ? error.message : String(error)}`,
124
+ };
125
+ }
126
+ }
9
127
 
10
128
  /**
11
129
  * Read Tool Plugin - Read file content
@@ -17,7 +135,7 @@ export const readTool: ToolPlugin = {
17
135
  function: {
18
136
  name: "Read",
19
137
  description:
20
- "Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path\n- By default, it reads up to 2000 lines starting from the beginning of the file\n- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters\n- Any lines longer than 2000 characters will be truncated\n- Results are returned using cat -n format, with line numbers starting at 1\n- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.\n- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.\n- You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png\n- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.\n- Binary document formats (PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX) are not supported and will return an error.",
138
+ "Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path\n- By default, it reads up to 2000 lines starting from the beginning of the file\n- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters\n- Any lines longer than 2000 characters will be truncated\n- Results are returned using cat -n format, with line numbers starting at 1\n- This tool allows Agent to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Agent is a multimodal LLM.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.\n- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.\n- You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png\n- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.\n- Binary document formats (PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX) are not supported and will return an error.",
21
139
  parameters: {
22
140
  type: "object",
23
141
  properties: {
@@ -65,6 +183,11 @@ export const readTool: ToolPlugin = {
65
183
  };
66
184
  }
67
185
 
186
+ // Check if this is an image file
187
+ if (isImageFile(filePath)) {
188
+ return processImageFile(filePath, context);
189
+ }
190
+
68
191
  try {
69
192
  // Note: New Read tool requires absolute paths, so we don't use resolvePath
70
193
  // But for compatibility, if it's not an absolute path, we still try to resolve
@@ -23,11 +23,11 @@ export function createSkillTool(skillManager: SkillManager): ToolPlugin {
23
23
  };
24
24
 
25
25
  return {
26
- name: "skill",
26
+ name: "Skill",
27
27
  config: {
28
28
  type: "function",
29
29
  function: {
30
- name: "skill",
30
+ name: "Skill",
31
31
  description: getToolDescription(),
32
32
  parameters: {
33
33
  type: "object",
@@ -1,4 +1,4 @@
1
- import type { ToolPlugin, ToolResult } from "./types.js";
1
+ import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
2
2
 
3
3
  interface TodoItem {
4
4
  content: string;
@@ -101,6 +101,38 @@ When in doubt, use this tool. Being proactive with task management demonstrates
101
101
  },
102
102
  },
103
103
 
104
+ formatCompactParams: (
105
+ params: Record<string, unknown>,
106
+ context: ToolContext,
107
+ ) => {
108
+ void context; // Context not needed for this tool
109
+ try {
110
+ const { todos } = params as { todos?: TodoItem[] };
111
+
112
+ // Handle invalid or missing tasks array
113
+ if (!todos || !Array.isArray(todos)) {
114
+ return "invalid todos";
115
+ }
116
+
117
+ // Handle empty task list
118
+ if (todos.length === 0) {
119
+ return "0 tasks";
120
+ }
121
+
122
+ // Count completed tasks
123
+ const completedCount = todos.filter(
124
+ (todo) => todo && todo.status === "completed",
125
+ ).length;
126
+ const totalCount = todos.length;
127
+
128
+ // Format with proper singular/plural
129
+ const taskWord = totalCount === 1 ? "task" : "tasks";
130
+ return `${completedCount}/${totalCount} ${taskWord}`;
131
+ } catch {
132
+ return "invalid todos";
133
+ }
134
+ },
135
+
104
136
  execute: async (args: Record<string, unknown>): Promise<ToolResult> => {
105
137
  try {
106
138
  // Validate arguments
@@ -3,6 +3,10 @@
3
3
  */
4
4
 
5
5
  import { ChatCompletionFunctionTool } from "openai/resources.js";
6
+ import type {
7
+ PermissionMode,
8
+ PermissionCallback,
9
+ } from "../types/permissions.js";
6
10
 
7
11
  export interface ToolPlugin {
8
12
  name: string;
@@ -23,15 +27,7 @@ export interface ToolResult {
23
27
  error?: string;
24
28
  // Short output, used to display summary information in collapsed state
25
29
  shortResult?: string;
26
- // Additional properties for file editing tools
27
- originalContent?: string;
28
- newContent?: string;
29
- diffResult?: Array<{
30
- count?: number;
31
- value: string;
32
- added?: boolean;
33
- removed?: boolean;
34
- }>;
30
+ // File path for operations that affect files
35
31
  filePath?: string;
36
32
  // Image data, for supporting multimedia content
37
33
  images?: Array<{
@@ -44,4 +40,14 @@ export interface ToolContext {
44
40
  abortSignal?: AbortSignal;
45
41
  backgroundBashManager?: import("../managers/backgroundBashManager.js").BackgroundBashManager;
46
42
  workdir: string;
43
+ /** Permission mode for this tool execution */
44
+ permissionMode?: PermissionMode;
45
+ /** Custom permission callback */
46
+ canUseToolCallback?: PermissionCallback;
47
+ /** Permission manager instance for permission checks */
48
+ permissionManager?: import("../managers/permissionManager.js").PermissionManager;
49
+ /** MCP manager instance for calling MCP tools */
50
+ mcpManager?: import("../managers/mcpManager.js").McpManager;
51
+ /** LSP manager instance for code intelligence */
52
+ lspManager?: import("../types/lsp.js").ILspManager;
47
53
  }
@@ -3,7 +3,6 @@ import { dirname } from "path";
3
3
  import { logger } from "../utils/globalLogger.js";
4
4
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
5
5
  import { resolvePath, getDisplayPath } from "../utils/path.js";
6
- import { diffLines } from "diff";
7
6
 
8
7
  /**
9
8
  * File Write Tool Plugin
@@ -80,9 +79,6 @@ export const writeTool: ToolPlugin = {
80
79
  content: `File ${filePath} already has the same content, no changes needed`,
81
80
  shortResult: "No changes needed",
82
81
  filePath: resolvedPath,
83
- originalContent,
84
- newContent: content,
85
- diffResult: [],
86
82
  };
87
83
  }
88
84
 
@@ -102,6 +98,42 @@ export const writeTool: ToolPlugin = {
102
98
  }
103
99
  }
104
100
 
101
+ // Permission check after validation but before real operation
102
+ if (
103
+ context.permissionManager &&
104
+ context.permissionMode &&
105
+ context.permissionMode !== "bypassPermissions"
106
+ ) {
107
+ if (context.permissionManager.isRestrictedTool("Write")) {
108
+ try {
109
+ const permissionContext = context.permissionManager.createContext(
110
+ "Write",
111
+ context.permissionMode,
112
+ context.canUseToolCallback,
113
+ { file_path: filePath, content },
114
+ );
115
+ const permissionResult =
116
+ await context.permissionManager.checkPermission(
117
+ permissionContext,
118
+ );
119
+
120
+ if (permissionResult.behavior === "deny") {
121
+ return {
122
+ success: false,
123
+ content: "",
124
+ error: `Write operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
125
+ };
126
+ }
127
+ } catch {
128
+ return {
129
+ success: false,
130
+ content: "",
131
+ error: "Permission check failed",
132
+ };
133
+ }
134
+ }
135
+ }
136
+
105
137
  // Write file
106
138
  try {
107
139
  await writeFile(resolvedPath, content, "utf-8");
@@ -113,9 +145,6 @@ export const writeTool: ToolPlugin = {
113
145
  };
114
146
  }
115
147
 
116
- // Generate diff information
117
- const diffResult = diffLines(originalContent, content);
118
-
119
148
  const shortResult = isExistingFile ? "File overwritten" : "File created";
120
149
 
121
150
  const lines = content.split("\n").length;
@@ -129,9 +158,6 @@ export const writeTool: ToolPlugin = {
129
158
  content: detailedContent,
130
159
  shortResult,
131
160
  filePath: resolvedPath,
132
- originalContent,
133
- newContent: content,
134
- diffResult,
135
161
  };
136
162
  } catch (error) {
137
163
  const errorMessage =
@@ -11,7 +11,6 @@ export interface SlashCommand {
11
11
  }
12
12
 
13
13
  export interface CustomSlashCommandConfig {
14
- allowedTools?: string[];
15
14
  model?: string;
16
15
  description?: string;
17
16
  }
@@ -3,9 +3,14 @@
3
3
  * Dependencies: None
4
4
  */
5
5
 
6
+ import OpenAI from "openai";
7
+
6
8
  export interface GatewayConfig {
7
9
  apiKey: string;
8
10
  baseURL: string;
11
+ defaultHeaders?: Record<string, string>;
12
+ fetchOptions?: OpenAI["fetchOptions"];
13
+ fetch?: OpenAI["fetch"];
9
14
  }
10
15
 
11
16
  export interface ModelConfig {
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Configuration Management Types
3
+ *
4
+ * Types for centralized configuration loading and validation services.
5
+ * These support the refactored configuration architecture that separates
6
+ * configuration management from hook execution.
7
+ */
8
+
9
+ import type { WaveConfiguration } from "./hooks.js";
10
+
11
+ /**
12
+ * Result of configuration loading operations with detailed status information
13
+ */
14
+ export interface ConfigurationLoadResult {
15
+ /** The loaded configuration, or null if loading failed */
16
+ configuration: WaveConfiguration | null;
17
+ /** Whether the loading operation was successful */
18
+ success: boolean;
19
+ /** Error message if loading failed */
20
+ error?: string;
21
+ /** Path of the successfully loaded file */
22
+ sourcePath?: string;
23
+ /** Non-critical warnings during loading */
24
+ warnings: string[];
25
+ }
26
+
27
+ /**
28
+ * Result of configuration validation operations
29
+ */
30
+ export interface ValidationResult {
31
+ /** Whether the configuration is valid */
32
+ isValid: boolean;
33
+ /** Critical errors that prevent configuration use */
34
+ errors: string[];
35
+ /** Non-critical warnings about the configuration */
36
+ warnings: string[];
37
+ }
38
+
39
+ /**
40
+ * Configuration file paths organized by category
41
+ */
42
+ export interface ConfigurationPaths {
43
+ /** User-specific configuration file paths in priority order */
44
+ userPaths: string[];
45
+ /** Project-specific configuration file paths in priority order */
46
+ projectPaths: string[];
47
+ /** All configuration paths combined */
48
+ allPaths: string[];
49
+ /** Only the paths that actually exist on the filesystem */
50
+ existingPaths: string[];
51
+ }
52
+
53
+ /**
54
+ * Options for configuring the ConfigurationService
55
+ */
56
+ export interface ConfigurationServiceOptions {
57
+ /** Working directory for resolving project configurations */
58
+ workdir: string;
59
+ /** Optional logger for configuration operations */
60
+ logger?: Logger;
61
+ /** Whether to enable validation during loading (default: true) */
62
+ enableValidation?: boolean;
63
+ }
64
+
65
+ /**
66
+ * Minimal logger interface for configuration services
67
+ */
68
+ interface Logger {
69
+ error: (...args: unknown[]) => void;
70
+ warn: (...args: unknown[]) => void;
71
+ info: (...args: unknown[]) => void;
72
+ debug: (...args: unknown[]) => void;
73
+ }
package/src/types/core.ts CHANGED
@@ -70,6 +70,17 @@ export interface ClaudeUsage extends CompletionUsage {
70
70
  };
71
71
  }
72
72
 
73
+ /**
74
+ * Represents a diff change for tool parameter-based diff display
75
+ * Contains the old content and new content for comparison
76
+ */
77
+ export interface Change {
78
+ /** The original content (empty string for additions) */
79
+ oldContent: string;
80
+ /** The new content (empty string for deletions) */
81
+ newContent: string;
82
+ }
83
+
73
84
  export class ConfigurationError extends Error {
74
85
  constructor(
75
86
  message: string,
@@ -58,3 +58,47 @@ export interface EnvironmentMergeOptions {
58
58
  /** Whether to validate variable names for common patterns */
59
59
  validateVariableNames?: boolean;
60
60
  }
61
+
62
+ /**
63
+ * Result of environment variable processing operations
64
+ */
65
+ export interface EnvironmentProcessResult {
66
+ /** The processed environment variables */
67
+ processedVars: Record<string, string>;
68
+ /** Any conflicts that occurred during processing */
69
+ conflicts: EnvironmentConflict[];
70
+ /** Non-critical warnings during processing */
71
+ warnings: string[];
72
+ /** Whether the variables were successfully applied to process.env */
73
+ applied: boolean;
74
+ }
75
+
76
+ /**
77
+ * Enhanced environment merge context with conflict details
78
+ */
79
+ export interface EnvironmentMergeContext {
80
+ /** User-provided environment variables */
81
+ userVars: Record<string, string>;
82
+ /** Project-provided environment variables */
83
+ projectVars: Record<string, string>;
84
+ /** Final merged environment variables */
85
+ mergedVars: Record<string, string>;
86
+ /** Detailed conflict information */
87
+ conflicts: EnvironmentConflict[];
88
+ }
89
+
90
+ /**
91
+ * Detailed information about an environment variable conflict
92
+ */
93
+ export interface EnvironmentConflict {
94
+ /** The environment variable key */
95
+ key: string;
96
+ /** Value from user configuration */
97
+ userValue: string;
98
+ /** Value from project configuration */
99
+ projectValue: string;
100
+ /** Final resolved value (which source won) */
101
+ resolvedValue: string;
102
+ /** Which source provided the final value */
103
+ source: "user" | "project";
104
+ }
@@ -0,0 +1,4 @@
1
+ export interface FileItem {
2
+ path: string;
3
+ type: "file" | "directory";
4
+ }
@@ -5,22 +5,14 @@
5
5
  * enabling automated actions at specific workflow points.
6
6
  */
7
7
 
8
- import { join } from "path";
9
- import { homedir } from "os";
10
-
11
- // Session path utility (simplified version for hooks)
12
- export function getSessionFilePath(sessionId: string): string {
13
- const shortId = sessionId.split("_")[2] || sessionId.slice(-8);
14
- return join(homedir(), ".wave", "sessions", `session_${shortId}.json`);
15
- }
16
-
17
8
  // Hook event types - trigger points in the AI workflow
18
9
  export type HookEvent =
19
10
  | "PreToolUse"
20
11
  | "PostToolUse"
21
12
  | "UserPromptSubmit"
22
13
  | "Stop"
23
- | "SubagentStop";
14
+ | "SubagentStop"
15
+ | "Notification";
24
16
 
25
17
  // Individual hook command configuration
26
18
  export interface HookCommand {
@@ -38,6 +30,11 @@ export interface HookEventConfig {
38
30
  export interface WaveConfiguration {
39
31
  hooks?: Partial<Record<HookEvent, HookEventConfig[]>>;
40
32
  env?: Record<string, string>; // Environment variables key-value pairs
33
+ defaultMode?: "default" | "bypassPermissions" | "acceptEdits"; // Default permission mode for restricted tools
34
+ /** New field for persistent permissions */
35
+ permissions?: {
36
+ allow?: string[];
37
+ };
41
38
  }
42
39
 
43
40
  // Legacy alias for backward compatibility - will be deprecated
@@ -117,6 +114,7 @@ export function isValidHookEvent(event: string): event is HookEvent {
117
114
  "UserPromptSubmit",
118
115
  "Stop",
119
116
  "SubagentStop",
117
+ "Notification",
120
118
  ].includes(event);
121
119
  }
122
120
 
@@ -155,7 +153,7 @@ export interface HookJsonInput {
155
153
  session_id: string; // Format: "wave_session_{uuid}_{shortId}"
156
154
  transcript_path: string; // Format: "~/.wave/sessions/session_{shortId}.json"
157
155
  cwd: string; // Absolute path to current working directory
158
- hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop"
156
+ hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "Notification"
159
157
 
160
158
  // Optional fields based on event type
161
159
  tool_name?: string; // Present for PreToolUse, PostToolUse
@@ -163,6 +161,8 @@ export interface HookJsonInput {
163
161
  tool_response?: unknown; // Present for PostToolUse only
164
162
  user_prompt?: string; // Present for UserPromptSubmit only
165
163
  subagent_type?: string; // Present when hook is executed by a subagent
164
+ message?: string; // Present for Notification events
165
+ notification_type?: string; // Present for Notification events
166
166
  }
167
167
 
168
168
  // Extended context interface for passing additional data to hook executor
@@ -172,8 +172,11 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
172
172
  cwd?: string; // Current working directory
173
173
  toolInput?: unknown; // Tool input parameters (PreToolUse/PostToolUse)
174
174
  toolResponse?: unknown; // Tool execution result (PostToolUse only)
175
+ env?: Record<string, string>; // Additional environment variables (from configuration)
175
176
  userPrompt?: string; // User prompt text (UserPromptSubmit only)
176
177
  subagentType?: string; // Subagent type when hook is executed by a subagent
178
+ message?: string; // Notification message (Notification only)
179
+ notificationType?: string; // Notification type (Notification only)
177
180
  }
178
181
 
179
182
  // Environment variables injected into hook processes
@@ -23,3 +23,8 @@ export * from "./skills.js";
23
23
  export * from "./config.js";
24
24
  export * from "./session.js";
25
25
  export * from "./environment.js";
26
+ export * from "./configuration.js"; // New configuration management types
27
+ export * from "./permissions.js";
28
+ export * from "./tools.js"; // Tool parameter types
29
+ export * from "./fileSearch.js"; // File search types
30
+ export * from "./lsp.js";