@wonderwhy-er/desktop-commander 0.1.34 → 0.1.35

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 (39) hide show
  1. package/README.md +105 -36
  2. package/dist/command-manager.d.ts +1 -7
  3. package/dist/command-manager.js +31 -50
  4. package/dist/config-manager.d.ts +27 -16
  5. package/dist/config-manager.js +109 -191
  6. package/dist/config.js +8 -4
  7. package/dist/error-handlers.js +4 -0
  8. package/dist/handlers/edit-search-handlers.js +9 -13
  9. package/dist/handlers/filesystem-handlers.d.ts +0 -4
  10. package/dist/handlers/filesystem-handlers.js +10 -18
  11. package/dist/handlers/index.d.ts +0 -1
  12. package/dist/handlers/index.js +0 -1
  13. package/dist/index.js +18 -3
  14. package/dist/sandbox/index.d.ts +9 -0
  15. package/dist/sandbox/index.js +50 -0
  16. package/dist/sandbox/mac-sandbox.d.ts +19 -0
  17. package/dist/sandbox/mac-sandbox.js +174 -0
  18. package/dist/server.js +152 -175
  19. package/dist/setup-claude-server.js +98 -49
  20. package/dist/terminal-manager.d.ts +1 -1
  21. package/dist/terminal-manager.js +20 -3
  22. package/dist/tools/config.d.ts +0 -58
  23. package/dist/tools/config.js +44 -107
  24. package/dist/tools/debug-path.d.ts +1 -0
  25. package/dist/tools/debug-path.js +44 -0
  26. package/dist/tools/edit.js +8 -5
  27. package/dist/tools/execute.js +4 -4
  28. package/dist/tools/filesystem-fixed.d.ts +22 -0
  29. package/dist/tools/filesystem-fixed.js +176 -0
  30. package/dist/tools/filesystem.d.ts +4 -6
  31. package/dist/tools/filesystem.js +101 -80
  32. package/dist/tools/schemas.d.ts +15 -14
  33. package/dist/tools/schemas.js +10 -6
  34. package/dist/tools/search.js +3 -3
  35. package/dist/utils.d.ts +5 -0
  36. package/dist/utils.js +92 -32
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/package.json +1 -2
@@ -0,0 +1,176 @@
1
+ if (returnMetadata === true) {
2
+ return { content, mimeType, isImage };
3
+ }
4
+ else {
5
+ return content;
6
+ }
7
+ try { }
8
+ catch (error) {
9
+ // If UTF-8 reading fails, treat as binary and return base64 but still as text
10
+ const buffer = await fs.readFile(validPath);
11
+ const content = `Binary file content (base64 encoded):\n${buffer.toString('base64')}`;
12
+ if (returnMetadata === true) {
13
+ return { content, mimeType: 'text/plain', isImage: false };
14
+ }
15
+ else {
16
+ return content;
17
+ }
18
+ }
19
+ ;
20
+ // Execute with timeout
21
+ const result = await withTimeout(readOperation(), FILE_READ_TIMEOUT, `Read file operation for ${filePath}`, returnMetadata ?
22
+ { content: `Operation timed out after ${FILE_READ_TIMEOUT / 1000} seconds`, mimeType: 'text/plain', isImage: false } :
23
+ `Operation timed out after ${FILE_READ_TIMEOUT / 1000} seconds`);
24
+ return result;
25
+ /**
26
+ * Read a file from either the local filesystem or a URL
27
+ * @param filePath Path to the file or URL
28
+ * @param returnMetadata Whether to return metadata with the content
29
+ * @param isUrl Whether the path is a URL
30
+ * @returns File content or file result with metadata
31
+ */
32
+ export async function readFile(filePath, returnMetadata, isUrl) {
33
+ return isUrl
34
+ ? readFileFromUrl(filePath, returnMetadata)
35
+ : readFileFromDisk(filePath, returnMetadata);
36
+ }
37
+ export async function writeFile(filePath, content) {
38
+ // Expand home directory in filePath before validation
39
+ const expandedFilePath = expandHome(filePath);
40
+ const validPath = await validatePath(expandedFilePath);
41
+ // Check if the path validation returned an error
42
+ if (validPath.startsWith('__ERROR__:')) {
43
+ throw new Error(validPath.substring('__ERROR__:'.length).trim());
44
+ }
45
+ await fs.writeFile(validPath, content, "utf-8");
46
+ }
47
+ export async function readMultipleFiles(paths) {
48
+ return Promise.all(paths.map(async (filePath) => {
49
+ try {
50
+ // Expand home directory in filePath before validation
51
+ const expandedFilePath = expandHome(filePath);
52
+ const validPath = await validatePath(expandedFilePath);
53
+ // Check if the path validation returned an error
54
+ if (validPath.startsWith('__ERROR__:')) {
55
+ return {
56
+ path: filePath,
57
+ error: validPath.substring('__ERROR__:'.length).trim()
58
+ };
59
+ }
60
+ const fileResult = await readFile(validPath, true);
61
+ return {
62
+ path: filePath,
63
+ content: typeof fileResult === 'string' ? fileResult : fileResult.content,
64
+ mimeType: typeof fileResult === 'string' ? "text/plain" : fileResult.mimeType,
65
+ isImage: typeof fileResult === 'string' ? false : fileResult.isImage
66
+ };
67
+ }
68
+ catch (error) {
69
+ const errorMessage = error instanceof Error ? error.message : String(error);
70
+ return {
71
+ path: filePath,
72
+ error: errorMessage
73
+ };
74
+ }
75
+ }));
76
+ }
77
+ export async function createDirectory(dirPath) {
78
+ // Expand home directory in dirPath before validation
79
+ const expandedDirPath = expandHome(dirPath);
80
+ const validPath = await validatePath(expandedDirPath);
81
+ // Check if the path validation returned an error
82
+ if (validPath.startsWith('__ERROR__:')) {
83
+ throw new Error(validPath.substring('__ERROR__:'.length).trim());
84
+ }
85
+ await fs.mkdir(validPath, { recursive: true });
86
+ }
87
+ export async function listDirectory(dirPath) {
88
+ console.log(`List directory called with: ${dirPath}`);
89
+ // Handle tilde expansion directly here as well
90
+ const expandedDirPath = expandHome(dirPath);
91
+ console.log(`Expanded dir path: ${expandedDirPath}`);
92
+ const validPath = await validatePath(expandedDirPath);
93
+ console.log(`Valid path: ${validPath}`);
94
+ // Check if the path starts with an error indicator
95
+ if (validPath.startsWith('__ERROR__:')) {
96
+ console.error(`Path validation error: ${validPath}`);
97
+ return [`Error: ${validPath.substring('__ERROR__:'.length).trim()}`];
98
+ }
99
+ try {
100
+ const entries = await fs.readdir(validPath, { withFileTypes: true });
101
+ return entries.map((entry) => `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`);
102
+ }
103
+ catch (error) {
104
+ const errorMessage = error instanceof Error ? error.message : String(error);
105
+ console.error(`Error reading directory: ${errorMessage}`);
106
+ return [`Error reading directory: ${errorMessage}`];
107
+ }
108
+ }
109
+ export async function moveFile(sourcePath, destinationPath) {
110
+ // Expand home directory in both paths before validation
111
+ const expandedSourcePath = expandHome(sourcePath);
112
+ const expandedDestPath = expandHome(destinationPath);
113
+ const validSourcePath = await validatePath(expandedSourcePath);
114
+ const validDestPath = await validatePath(expandedDestPath);
115
+ // Check if either path validation returned an error
116
+ if (validSourcePath.startsWith('__ERROR__:')) {
117
+ throw new Error(validSourcePath.substring('__ERROR__:'.length).trim());
118
+ }
119
+ if (validDestPath.startsWith('__ERROR__:')) {
120
+ throw new Error(validDestPath.substring('__ERROR__:'.length).trim());
121
+ }
122
+ await fs.rename(validSourcePath, validDestPath);
123
+ }
124
+ export async function searchFiles(rootPath, pattern) {
125
+ const results = [];
126
+ async function search(currentPath) {
127
+ const entries = await fs.readdir(currentPath, { withFileTypes: true });
128
+ for (const entry of entries) {
129
+ const fullPath = path.join(currentPath, entry.name);
130
+ try {
131
+ // No need to expand home directory here as we're generating full paths
132
+ // from the already validated rootPath
133
+ await validatePath(fullPath);
134
+ if (entry.name.toLowerCase().includes(pattern.toLowerCase())) {
135
+ results.push(fullPath);
136
+ }
137
+ if (entry.isDirectory()) {
138
+ await search(fullPath);
139
+ }
140
+ }
141
+ catch (error) {
142
+ continue;
143
+ }
144
+ }
145
+ }
146
+ // Expand home directory in rootPath before validation
147
+ const expandedRootPath = expandHome(rootPath);
148
+ const validPath = await validatePath(expandedRootPath);
149
+ // Check if the path validation returned an error
150
+ if (validPath.startsWith('__ERROR__:')) {
151
+ throw new Error(validPath.substring('__ERROR__:'.length).trim());
152
+ }
153
+ await search(validPath);
154
+ return results;
155
+ }
156
+ export async function getFileInfo(filePath) {
157
+ // Expand home directory in filePath before validation
158
+ const expandedFilePath = expandHome(filePath);
159
+ const validPath = await validatePath(expandedFilePath);
160
+ // Check if the path validation returned an error
161
+ if (validPath.startsWith('__ERROR__:')) {
162
+ throw new Error(validPath.substring('__ERROR__:'.length).trim());
163
+ }
164
+ const stats = await fs.stat(validPath);
165
+ return {
166
+ size: stats.size,
167
+ created: stats.birthtime,
168
+ modified: stats.mtime,
169
+ accessed: stats.atime,
170
+ isDirectory: stats.isDirectory(),
171
+ isFile: stats.isFile(),
172
+ permissions: stats.mode.toString(8).slice(-3),
173
+ };
174
+ }
175
+ // This function has been replaced with configManager.getConfig()
176
+ // Use get_config tool to retrieve allowedDirectories
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @param requestedPath The path to validate
7
7
  * @returns Promise<string> The validated path
8
- * @throws Error if the path or its parent directories don't exist
8
+ * @throws Error if the path or its parent directories don't exist or if the path is not allowed
9
9
  */
10
10
  export declare function validatePath(requestedPath: string): Promise<string>;
11
11
  export interface FileResult {
@@ -16,17 +16,16 @@ export interface FileResult {
16
16
  /**
17
17
  * Read file content from a URL
18
18
  * @param url URL to fetch content from
19
- * @param returnMetadata Whether to return metadata with the content
20
19
  * @returns File content or file result with metadata
21
20
  */
22
- export declare function readFileFromUrl(url: string, returnMetadata?: boolean): Promise<string | FileResult>;
21
+ export declare function readFileFromUrl(url: string): Promise<FileResult>;
23
22
  /**
24
23
  * Read file content from the local filesystem
25
24
  * @param filePath Path to the file
26
25
  * @param returnMetadata Whether to return metadata with the content
27
26
  * @returns File content or file result with metadata
28
27
  */
29
- export declare function readFileFromDisk(filePath: string, returnMetadata?: boolean): Promise<string | FileResult>;
28
+ export declare function readFileFromDisk(filePath: string): Promise<FileResult>;
30
29
  /**
31
30
  * Read a file from either the local filesystem or a URL
32
31
  * @param filePath Path to the file or URL
@@ -34,7 +33,7 @@ export declare function readFileFromDisk(filePath: string, returnMetadata?: bool
34
33
  * @param isUrl Whether the path is a URL
35
34
  * @returns File content or file result with metadata
36
35
  */
37
- export declare function readFile(filePath: string, returnMetadata?: boolean, isUrl?: boolean): Promise<string | FileResult>;
36
+ export declare function readFile(filePath: string, isUrl?: boolean): Promise<FileResult>;
38
37
  export declare function writeFile(filePath: string, content: string): Promise<void>;
39
38
  export interface MultiFileResult {
40
39
  path: string;
@@ -49,4 +48,3 @@ export declare function listDirectory(dirPath: string): Promise<string[]>;
49
48
  export declare function moveFile(sourcePath: string, destinationPath: string): Promise<void>;
50
49
  export declare function searchFiles(rootPath: string, pattern: string): Promise<string[]>;
51
50
  export declare function getFileInfo(filePath: string): Promise<Record<string, any>>;
52
- export declare function listAllowedDirectories(): string[];
@@ -2,22 +2,35 @@ import fs from "fs/promises";
2
2
  import path from "path";
3
3
  import os from 'os';
4
4
  import fetch from 'cross-fetch';
5
- import { withTimeout } from '../utils.js';
6
- // Store allowed directories - temporarily allowing all paths
7
- // TODO: Make this configurable through a configuration file
8
- const allowedDirectories = [
9
- "/" // Root directory - effectively allows all paths
10
- ];
11
- // Original implementation commented out for future reference
12
- /*
13
- const allowedDirectories: string[] = [
14
- process.cwd(), // Current working directory
15
- os.homedir() // User's home directory
16
- ];
17
- */
5
+ import { capture, withTimeout } from '../utils.js';
6
+ import { configManager } from '../config-manager.js';
7
+ // Initialize allowed directories from configuration
8
+ async function getAllowedDirs() {
9
+ try {
10
+ let allowedDirectories;
11
+ const config = await configManager.getConfig();
12
+ if (config.allowedDirectories && Array.isArray(config.allowedDirectories)) {
13
+ allowedDirectories = config.allowedDirectories;
14
+ }
15
+ else {
16
+ // Fall back to default directories if not configured
17
+ allowedDirectories = [
18
+ os.homedir() // User's home directory
19
+ ];
20
+ // Update config with default
21
+ await configManager.setValue('allowedDirectories', allowedDirectories);
22
+ }
23
+ return allowedDirectories;
24
+ }
25
+ catch (error) {
26
+ console.error('Failed to initialize allowed directories:', error);
27
+ // Keep the default permissive path
28
+ }
29
+ return [];
30
+ }
18
31
  // Normalize all paths consistently
19
32
  function normalizePath(p) {
20
- return path.normalize(p).toLowerCase();
33
+ return path.normalize(expandHome(p)).toLowerCase();
21
34
  }
22
35
  function expandHome(filepath) {
23
36
  if (filepath.startsWith('~/') || filepath === '~') {
@@ -49,6 +62,47 @@ async function validateParentDirectories(directoryPath) {
49
62
  return validateParentDirectories(parentDir);
50
63
  }
51
64
  }
65
+ /**
66
+ * Checks if a path is within any of the allowed directories
67
+ *
68
+ * @param pathToCheck Path to check
69
+ * @returns boolean True if path is allowed
70
+ */
71
+ async function isPathAllowed(pathToCheck) {
72
+ // If root directory is allowed, all paths are allowed
73
+ const allowedDirectories = await getAllowedDirs();
74
+ if (allowedDirectories.includes('/') || allowedDirectories.length === 0) {
75
+ return true;
76
+ }
77
+ let normalizedPathToCheck = normalizePath(pathToCheck);
78
+ if (normalizedPathToCheck.slice(-1) === path.sep) {
79
+ normalizedPathToCheck = normalizedPathToCheck.slice(0, -1);
80
+ }
81
+ // Check if the path is within any allowed directory
82
+ const isAllowed = allowedDirectories.some(allowedDir => {
83
+ let normalizedAllowedDir = normalizePath(allowedDir);
84
+ if (normalizedAllowedDir.slice(-1) === path.sep) {
85
+ normalizedAllowedDir = normalizedAllowedDir.slice(0, -1);
86
+ }
87
+ // Check if path is exactly the allowed directory
88
+ if (normalizedPathToCheck === normalizedAllowedDir) {
89
+ return true;
90
+ }
91
+ // Check if path is a subdirectory of the allowed directory
92
+ // Make sure to add a separator to prevent partial directory name matches
93
+ // e.g. /home/user vs /home/username
94
+ const subdirCheck = normalizedPathToCheck.startsWith(normalizedAllowedDir + path.sep);
95
+ if (subdirCheck) {
96
+ return true;
97
+ }
98
+ // If allowed directory is the root (C:\ on Windows), allow access to the entire drive
99
+ if (normalizedAllowedDir === 'c:' && process.platform === 'win32') {
100
+ return normalizedPathToCheck.startsWith('c:');
101
+ }
102
+ return false;
103
+ });
104
+ return isAllowed;
105
+ }
52
106
  /**
53
107
  * Validates a path to ensure it can be accessed or created.
54
108
  * For existing paths, returns the real path (resolving symlinks).
@@ -56,7 +110,7 @@ async function validateParentDirectories(directoryPath) {
56
110
  *
57
111
  * @param requestedPath The path to validate
58
112
  * @returns Promise<string> The validated path
59
- * @throws Error if the path or its parent directories don't exist
113
+ * @throws Error if the path or its parent directories don't exist or if the path is not allowed
60
114
  */
61
115
  export async function validatePath(requestedPath) {
62
116
  const PATH_VALIDATION_TIMEOUT = 10000; // 10 seconds timeout
@@ -67,6 +121,10 @@ export async function validatePath(requestedPath) {
67
121
  const absolute = path.isAbsolute(expandedPath)
68
122
  ? path.resolve(expandedPath)
69
123
  : path.resolve(process.cwd(), expandedPath);
124
+ // Check if path is allowed
125
+ if (!(await isPathAllowed(absolute))) {
126
+ throw (`Path not allowed: ${requestedPath}. Must be within one of these directories: ${(await getAllowedDirs()).join(', ')}`);
127
+ }
70
128
  // Check if path exists
71
129
  try {
72
130
  const stats = await fs.stat(absolute);
@@ -88,17 +146,16 @@ export async function validatePath(requestedPath) {
88
146
  const result = await withTimeout(validationOperation(), PATH_VALIDATION_TIMEOUT, `Path validation for ${requestedPath}`, null);
89
147
  if (result === null) {
90
148
  // Return a path with an error indicator instead of throwing
91
- return `__ERROR__: Path validation timed out after ${PATH_VALIDATION_TIMEOUT / 1000} seconds for: ${requestedPath}`;
149
+ throw new Error(`Path validation failed for path: ${requestedPath}`);
92
150
  }
93
151
  return result;
94
152
  }
95
153
  /**
96
154
  * Read file content from a URL
97
155
  * @param url URL to fetch content from
98
- * @param returnMetadata Whether to return metadata with the content
99
156
  * @returns File content or file result with metadata
100
157
  */
101
- export async function readFileFromUrl(url, returnMetadata) {
158
+ export async function readFileFromUrl(url) {
102
159
  // Import the MIME type utilities
103
160
  const { isImageFile } = await import('./mime-types.js');
104
161
  // Set up fetch with timeout
@@ -121,22 +178,12 @@ export async function readFileFromUrl(url, returnMetadata) {
121
178
  // For images, convert to base64
122
179
  const buffer = await response.arrayBuffer();
123
180
  const content = Buffer.from(buffer).toString('base64');
124
- if (returnMetadata === true) {
125
- return { content, mimeType: contentType, isImage };
126
- }
127
- else {
128
- return content;
129
- }
181
+ return { content, mimeType: contentType, isImage };
130
182
  }
131
183
  else {
132
184
  // For text content
133
185
  const content = await response.text();
134
- if (returnMetadata === true) {
135
- return { content, mimeType: contentType, isImage };
136
- }
137
- else {
138
- return content;
139
- }
186
+ return { content, mimeType: contentType, isImage };
140
187
  }
141
188
  }
142
189
  catch (error) {
@@ -146,16 +193,7 @@ export async function readFileFromUrl(url, returnMetadata) {
146
193
  const errorMessage = error instanceof DOMException && error.name === 'AbortError'
147
194
  ? `URL fetch timed out after ${FETCH_TIMEOUT_MS}ms: ${url}`
148
195
  : `Failed to fetch URL: ${error instanceof Error ? error.message : String(error)}`;
149
- if (returnMetadata === true) {
150
- return {
151
- content: `Error: ${errorMessage}`,
152
- mimeType: 'text/plain',
153
- isImage: false
154
- };
155
- }
156
- else {
157
- return `Error: ${errorMessage}`;
158
- }
196
+ throw new Error(errorMessage);
159
197
  }
160
198
  }
161
199
  /**
@@ -164,7 +202,7 @@ export async function readFileFromUrl(url, returnMetadata) {
164
202
  * @param returnMetadata Whether to return metadata with the content
165
203
  * @returns File content or file result with metadata
166
204
  */
167
- export async function readFileFromDisk(filePath, returnMetadata) {
205
+ export async function readFileFromDisk(filePath) {
168
206
  // Import the MIME type utilities
169
207
  const { getMimeType, isImageFile } = await import('./mime-types.js');
170
208
  const validPath = await validatePath(filePath);
@@ -174,21 +212,18 @@ export async function readFileFromDisk(filePath, returnMetadata) {
174
212
  const MAX_SIZE = 100 * 1024; // 100KB limit
175
213
  if (stats.size > MAX_SIZE) {
176
214
  const message = `File too large (${(stats.size / 1024).toFixed(2)}KB > ${MAX_SIZE / 1024}KB limit)`;
177
- if (returnMetadata) {
178
- return {
179
- content: message,
180
- mimeType: 'text/plain',
181
- isImage: false
182
- };
183
- }
184
- else {
185
- return message;
186
- }
215
+ return {
216
+ content: message,
217
+ mimeType: 'text/plain',
218
+ isImage: false
219
+ };
187
220
  }
188
221
  }
189
222
  catch (error) {
223
+ console.error('error catch ' + error);
224
+ capture('server_read_file_error', { error: error });
190
225
  // If we can't stat the file, continue anyway and let the read operation handle errors
191
- console.error(`Failed to stat file ${validPath}:`, error);
226
+ //console.error(`Failed to stat file ${validPath}:`, error);
192
227
  }
193
228
  // Detect the MIME type based on file extension
194
229
  const mimeType = getMimeType(validPath);
@@ -200,41 +235,28 @@ export async function readFileFromDisk(filePath, returnMetadata) {
200
235
  // For image files, read as Buffer and convert to base64
201
236
  const buffer = await fs.readFile(validPath);
202
237
  const content = buffer.toString('base64');
203
- if (returnMetadata === true) {
204
- return { content, mimeType, isImage };
205
- }
206
- else {
207
- return content;
208
- }
238
+ return { content, mimeType, isImage };
209
239
  }
210
240
  else {
211
241
  // For all other files, try to read as UTF-8 text
212
242
  try {
213
243
  const content = await fs.readFile(validPath, "utf-8");
214
- if (returnMetadata === true) {
215
- return { content, mimeType, isImage };
216
- }
217
- else {
218
- return content;
219
- }
244
+ return { content, mimeType, isImage };
220
245
  }
221
246
  catch (error) {
222
247
  // If UTF-8 reading fails, treat as binary and return base64 but still as text
223
248
  const buffer = await fs.readFile(validPath);
224
249
  const content = `Binary file content (base64 encoded):\n${buffer.toString('base64')}`;
225
- if (returnMetadata === true) {
226
- return { content, mimeType: 'text/plain', isImage: false };
227
- }
228
- else {
229
- return content;
230
- }
250
+ return { content, mimeType: 'text/plain', isImage: false };
231
251
  }
232
252
  }
233
253
  };
234
254
  // Execute with timeout
235
- const result = await withTimeout(readOperation(), FILE_READ_TIMEOUT, `Read file operation for ${filePath}`, returnMetadata ?
236
- { content: `Operation timed out after ${FILE_READ_TIMEOUT / 1000} seconds`, mimeType: 'text/plain', isImage: false } :
237
- `Operation timed out after ${FILE_READ_TIMEOUT / 1000} seconds`);
255
+ const result = await withTimeout(readOperation(), FILE_READ_TIMEOUT, `Read file operation for ${filePath}`, null);
256
+ if (result == null) {
257
+ // Handles the impossible case where withTimeout resolves to null instead of throwing
258
+ throw new Error('Failed to read the file');
259
+ }
238
260
  return result;
239
261
  }
240
262
  /**
@@ -244,10 +266,10 @@ export async function readFileFromDisk(filePath, returnMetadata) {
244
266
  * @param isUrl Whether the path is a URL
245
267
  * @returns File content or file result with metadata
246
268
  */
247
- export async function readFile(filePath, returnMetadata, isUrl) {
269
+ export async function readFile(filePath, isUrl) {
248
270
  return isUrl
249
- ? readFileFromUrl(filePath, returnMetadata)
250
- : readFileFromDisk(filePath, returnMetadata);
271
+ ? readFileFromUrl(filePath)
272
+ : readFileFromDisk(filePath);
251
273
  }
252
274
  export async function writeFile(filePath, content) {
253
275
  const validPath = await validatePath(filePath);
@@ -257,7 +279,7 @@ export async function readMultipleFiles(paths) {
257
279
  return Promise.all(paths.map(async (filePath) => {
258
280
  try {
259
281
  const validPath = await validatePath(filePath);
260
- const fileResult = await readFile(validPath, true);
282
+ const fileResult = await readFile(validPath);
261
283
  return {
262
284
  path: filePath,
263
285
  content: typeof fileResult === 'string' ? fileResult : fileResult.content,
@@ -326,6 +348,5 @@ export async function getFileInfo(filePath) {
326
348
  permissions: stats.mode.toString(8).slice(-3),
327
349
  };
328
350
  }
329
- export function listAllowedDirectories() {
330
- return ["/ (All paths are currently allowed)"];
331
- }
351
+ // This function has been replaced with configManager.getConfig()
352
+ // Use get_config tool to retrieve allowedDirectories
@@ -1,13 +1,28 @@
1
1
  import { z } from "zod";
2
+ export declare const GetConfigArgsSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
3
+ export declare const SetConfigValueArgsSchema: z.ZodObject<{
4
+ key: z.ZodString;
5
+ value: z.ZodAny;
6
+ }, "strip", z.ZodTypeAny, {
7
+ key: string;
8
+ value?: any;
9
+ }, {
10
+ key: string;
11
+ value?: any;
12
+ }>;
13
+ export declare const ListProcessesArgsSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
2
14
  export declare const ExecuteCommandArgsSchema: z.ZodObject<{
3
15
  command: z.ZodString;
4
16
  timeout_ms: z.ZodOptional<z.ZodNumber>;
17
+ shell: z.ZodOptional<z.ZodString>;
5
18
  }, "strip", z.ZodTypeAny, {
6
19
  command: string;
7
20
  timeout_ms?: number | undefined;
21
+ shell?: string | undefined;
8
22
  }, {
9
23
  command: string;
10
24
  timeout_ms?: number | undefined;
25
+ shell?: string | undefined;
11
26
  }>;
12
27
  export declare const ReadOutputArgsSchema: z.ZodObject<{
13
28
  pid: z.ZodNumber;
@@ -31,20 +46,6 @@ export declare const KillProcessArgsSchema: z.ZodObject<{
31
46
  }, {
32
47
  pid: number;
33
48
  }>;
34
- export declare const BlockCommandArgsSchema: z.ZodObject<{
35
- command: z.ZodString;
36
- }, "strip", z.ZodTypeAny, {
37
- command: string;
38
- }, {
39
- command: string;
40
- }>;
41
- export declare const UnblockCommandArgsSchema: z.ZodObject<{
42
- command: z.ZodString;
43
- }, "strip", z.ZodTypeAny, {
44
- command: string;
45
- }, {
46
- command: string;
47
- }>;
48
49
  export declare const ReadFileArgsSchema: z.ZodObject<{
49
50
  path: z.ZodString;
50
51
  isUrl: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -1,8 +1,18 @@
1
1
  import { z } from "zod";
2
+ console.error("Loading schemas.ts");
3
+ // Config tools schemas
4
+ export const GetConfigArgsSchema = z.object({});
5
+ export const SetConfigValueArgsSchema = z.object({
6
+ key: z.string(),
7
+ value: z.any(),
8
+ });
9
+ // Empty schemas
10
+ export const ListProcessesArgsSchema = z.object({});
2
11
  // Terminal tools schemas
3
12
  export const ExecuteCommandArgsSchema = z.object({
4
13
  command: z.string(),
5
14
  timeout_ms: z.number().optional(),
15
+ shell: z.string().optional(),
6
16
  });
7
17
  export const ReadOutputArgsSchema = z.object({
8
18
  pid: z.number(),
@@ -14,12 +24,6 @@ export const ListSessionsArgsSchema = z.object({});
14
24
  export const KillProcessArgsSchema = z.object({
15
25
  pid: z.number(),
16
26
  });
17
- export const BlockCommandArgsSchema = z.object({
18
- command: z.string(),
19
- });
20
- export const UnblockCommandArgsSchema = z.object({
21
- command: z.string(),
22
- });
23
27
  // Filesystem tools schemas
24
28
  export const ReadFileArgsSchema = z.object({
25
29
  path: z.string(),
@@ -3,6 +3,7 @@ import path from 'path';
3
3
  import fs from 'fs/promises';
4
4
  import { validatePath } from './filesystem.js';
5
5
  import { rgPath } from '@vscode/ripgrep';
6
+ import { capture } from "../utils.js";
6
7
  // Function to search file contents using ripgrep
7
8
  export async function searchCode(options) {
8
9
  const { rootPath, pattern, filePattern, ignoreCase = true, maxResults = 1000, includeHidden = false, contextLines = 0 } = options;
@@ -77,8 +78,8 @@ export async function searchCode(options) {
77
78
  }
78
79
  }
79
80
  catch (e) {
80
- // Skip non-JSON output
81
- console.error('Error parsing ripgrep output:', e);
81
+ capture('server_request_error', { error: 'Error parsing ripgrep output:' + e });
82
+ console.error();
82
83
  }
83
84
  }
84
85
  resolve(results);
@@ -164,7 +165,6 @@ export async function searchTextInFiles(options) {
164
165
  return await searchCode(options);
165
166
  }
166
167
  catch (error) {
167
- console.error('Ripgrep search failed, falling back to native implementation:', error);
168
168
  return searchCodeFallback({
169
169
  ...options,
170
170
  excludeDirs: ['node_modules', '.git', 'dist']
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Send an event to Google Analytics
3
+ * @param event Event name
4
+ * @param properties Optional event properties
5
+ */
1
6
  export declare const capture: (event: string, properties?: any) => void;
2
7
  /**
3
8
  * Executes a promise with a timeout. If the promise doesn't resolve or reject within