@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
@@ -5,28 +5,25 @@ import { fileURLToPath } from 'url';
5
5
  import { dirname } from 'path';
6
6
  import { exec } from "node:child_process";
7
7
  import { version as nodeVersion } from 'process';
8
+ import * as https from 'https';
8
9
 
9
- // Optional analytics - will gracefully degrade if posthog-node isn't available
10
- let client = null;
10
+ // Google Analytics configuration
11
+ const GA_MEASUREMENT_ID = 'G-NGGDNL0K4L'; // Replace with your GA4 Measurement ID
12
+ const GA_API_SECRET = '5M0mC--2S_6t94m8WrI60A'; // Replace with your GA4 API Secret
13
+ const GA_BASE_URL = `https://www.google-analytics.com/mp/collect?measurement_id=${GA_MEASUREMENT_ID}&api_secret=${GA_API_SECRET}`;
14
+
15
+ // Optional analytics - will gracefully degrade if dependencies aren't available
11
16
  let uniqueUserId = 'unknown';
12
17
 
13
18
  try {
14
- const { PostHog } = await import('posthog-node');
19
+ // Only dependency is node-machine-id
15
20
  const machineIdModule = await import('node-machine-id');
16
-
17
- client = new PostHog(
18
- 'phc_BW8KJ0cajzj2v8qfMhvDQ4dtFdgHPzeYcMRvRFGvQdH',
19
- {
20
- host: 'https://eu.i.posthog.com',
21
- flushAt: 1, // send all every time
22
- flushInterval: 0 //send always
23
- }
24
- );
25
-
21
+
26
22
  // Get a unique user ID
27
23
  uniqueUserId = machineIdModule.machineIdSync();
28
24
  } catch (error) {
29
- //console.error('Analytics module not available - continuing without tracking');
25
+ // Fall back to a semi-unique identifier if machine-id is not available
26
+ uniqueUserId = `${platform()}-${process.env.USER || process.env.USERNAME || 'unknown'}-${Date.now()}`;
30
27
  }
31
28
 
32
29
  // Function to get npm version
@@ -127,33 +124,98 @@ async function getTrackingProperties(additionalProps = {}) {
127
124
  const version = await getVersion();
128
125
  return {
129
126
  platform: platform(),
130
- nodeVersion: nodeVersion,
131
- npmVersion: npmVersionCache,
132
- executionContext: context.runMethod,
133
- isCI: context.isCI,
127
+ node_version: nodeVersion,
128
+ npm_version: npmVersionCache,
129
+ execution_context: context.runMethod,
130
+ is_ci: context.isCI,
134
131
  shell: context.shell,
135
- DCVersion: version,
136
- timestamp: new Date().toISOString(),
132
+ app_version: version,
133
+ engagement_time_msec: "100",
137
134
  ...additionalProps
138
135
  };
139
136
  }
140
137
 
141
- // Helper function for tracking that handles missing PostHog gracefully
138
+ // Helper function for tracking that handles errors gracefully
142
139
  async function trackEvent(eventName, additionalProps = {}) {
143
- if (!client) return; // Skip tracking if PostHog client isn't available
140
+ if (!GA_MEASUREMENT_ID || !GA_API_SECRET) return; // Skip tracking if GA isn't configured
144
141
 
145
142
  try {
146
- client.capture({
147
- distinctId: uniqueUserId,
148
- event: eventName,
149
- properties: await getTrackingProperties(additionalProps)
143
+ // Get enriched properties
144
+ const eventProperties = await getTrackingProperties(additionalProps);
145
+
146
+ // Prepare GA4 payload
147
+ const payload = {
148
+ client_id: uniqueUserId,
149
+ non_personalized_ads: false,
150
+ timestamp_micros: Date.now() * 1000,
151
+ events: [{
152
+ name: eventName,
153
+ params: eventProperties
154
+ }]
155
+ };
156
+
157
+ // Send to Google Analytics
158
+ const postData = JSON.stringify(payload);
159
+
160
+ const options = {
161
+ method: 'POST',
162
+ headers: {
163
+ 'Content-Type': 'application/json',
164
+ 'Content-Length': Buffer.byteLength(postData)
165
+ }
166
+ };
167
+
168
+ return new Promise((resolve) => {
169
+ const req = https.request(GA_BASE_URL, options, (res) => {
170
+ // Optional response handling
171
+ let data = '';
172
+ res.on('data', (chunk) => {
173
+ data += chunk;
174
+ });
175
+
176
+ res.on('end', () => {
177
+ resolve(true);
178
+ });
179
+ });
180
+
181
+ req.on('error', (error) => {
182
+ // Silently fail - we don't want tracking issues to break functionality
183
+ resolve(false);
184
+ });
185
+
186
+ // Set timeout to prevent blocking
187
+ req.setTimeout(3000, () => {
188
+ req.destroy();
189
+ resolve(false);
190
+ });
191
+
192
+ req.write(postData);
193
+ req.end();
194
+
195
+ // read response from request
196
+ req.on('response', (res) => {
197
+ // Optional response handling
198
+ let data = '';
199
+ res.on('data', (chunk) => {
200
+ data += chunk;
201
+ });
202
+
203
+ //response status
204
+ res.on('error', (error) => {
205
+ resolve(false);
206
+ });
207
+
208
+ res.on('end', () => {
209
+ resolve(true);
210
+ });
211
+ });
150
212
  });
151
213
  } catch (error) {
152
- // Silently fail if tracking fails - we don't want to break the setup process
153
- //console.log(`Note: Event tracking unavailable for ${eventName}`);
214
+ logToFile(`Error tracking event ${eventName}: ${error}`, true);
215
+ // Silently fail if tracking fails - we don't want to break the application
216
+ return false;
154
217
  }
155
218
  }
156
-
157
219
  // Initial tracking
158
220
  trackEvent('npx_setup_start');
159
221
 
@@ -258,12 +320,16 @@ async function restartClaude() {
258
320
  } else if (platform === "linux") {
259
321
  await execAsync(`claude`)
260
322
  }
261
- } catch{}
323
+ logToFile(`Claude has been restarted.`)
324
+ } catch{
262
325
 
263
- logToFile(`Claude has been restarted.`)
326
+ }
327
+
328
+
264
329
  } catch (error) {
265
330
  await trackEvent('npx_setup_restart_claude_error', { error: error.message });
266
- logToFile(`Failed to restart Claude: ${error}`, true)
331
+ logToFile(`Failed to restart Claude: ${error}. Please restart it manually.`, true)
332
+ logToFile(`If Claude Desktop is not installed use this link to download https://claude.ai/download`, true)
267
333
  }
268
334
  }
269
335
 
@@ -413,26 +479,9 @@ export default async function setup() {
413
479
 
414
480
  await trackEvent('npx_setup_complete');
415
481
 
416
- // Safe shutdown
417
- if (client) {
418
- try {
419
- await client.shutdown();
420
- } catch (error) {
421
- // Ignore shutdown errors
422
- }
423
- }
424
482
  } catch (error) {
425
483
  await trackEvent('npx_setup_final_error', { error: error.message });
426
484
  logToFile(`Error updating Claude configuration: ${error}`, true);
427
-
428
- // Safe shutdown
429
- if (client) {
430
- try {
431
- await client.shutdown();
432
- } catch (error) {
433
- // Ignore shutdown errors
434
- }
435
- }
436
485
  process.exit(1);
437
486
  }
438
487
  }
@@ -9,7 +9,7 @@ interface CompletedSession {
9
9
  export declare class TerminalManager {
10
10
  private sessions;
11
11
  private completedSessions;
12
- executeCommand(command: string, timeoutMs?: number): Promise<CommandExecutionResult>;
12
+ executeCommand(command: string, timeoutMs?: number, shell?: string): Promise<CommandExecutionResult>;
13
13
  getNewOutput(pid: number): string | null;
14
14
  forceTerminate(pid: number): boolean;
15
15
  listActiveSessions(): ActiveSession[];
@@ -1,12 +1,29 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { DEFAULT_COMMAND_TIMEOUT } from './config.js';
3
+ import { configManager } from './config-manager.js';
4
+ import { capture } from "./utils.js";
3
5
  export class TerminalManager {
4
6
  constructor() {
5
7
  this.sessions = new Map();
6
8
  this.completedSessions = new Map();
7
9
  }
8
- async executeCommand(command, timeoutMs = DEFAULT_COMMAND_TIMEOUT) {
9
- const process = spawn(command, [], { shell: true });
10
+ async executeCommand(command, timeoutMs = DEFAULT_COMMAND_TIMEOUT, shell) {
11
+ // Get the shell from config if not specified
12
+ let shellToUse = shell;
13
+ if (!shellToUse) {
14
+ try {
15
+ const config = await configManager.getConfig();
16
+ shellToUse = config.shell || true;
17
+ }
18
+ catch (error) {
19
+ // If there's an error getting the config, fall back to default
20
+ shellToUse = true;
21
+ }
22
+ }
23
+ const spawnOptions = {
24
+ shell: shellToUse
25
+ };
26
+ const process = spawn(command, [], spawnOptions);
10
27
  let output = '';
11
28
  // Ensure process.pid is defined before proceeding
12
29
  if (!process.pid) {
@@ -101,7 +118,7 @@ export class TerminalManager {
101
118
  return true;
102
119
  }
103
120
  catch (error) {
104
- console.error(`Failed to terminate process ${pid}:`, error);
121
+ capture('server_request_error', { error: error, message: `Failed to terminate process ${pid}:` });
105
122
  return false;
106
123
  }
107
124
  }
@@ -1,29 +1,3 @@
1
- import { z } from 'zod';
2
- export declare const GetConfigArgsSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
3
- export declare const GetConfigValueArgsSchema: z.ZodObject<{
4
- key: z.ZodString;
5
- }, "strip", z.ZodTypeAny, {
6
- key: string;
7
- }, {
8
- key: string;
9
- }>;
10
- export declare const SetConfigValueArgsSchema: z.ZodObject<{
11
- key: z.ZodString;
12
- value: z.ZodAny;
13
- }, "strip", z.ZodTypeAny, {
14
- key: string;
15
- value?: any;
16
- }, {
17
- key: string;
18
- value?: any;
19
- }>;
20
- export declare const UpdateConfigArgsSchema: z.ZodObject<{
21
- config: z.ZodRecord<z.ZodString, z.ZodAny>;
22
- }, "strip", z.ZodTypeAny, {
23
- config: Record<string, any>;
24
- }, {
25
- config: Record<string, any>;
26
- }>;
27
1
  /**
28
2
  * Get the entire config
29
3
  */
@@ -33,22 +7,6 @@ export declare function getConfig(): Promise<{
33
7
  text: string;
34
8
  }[];
35
9
  }>;
36
- /**
37
- * Get a specific config value
38
- */
39
- export declare function getConfigValue(args: unknown): Promise<{
40
- content: {
41
- type: string;
42
- text: string;
43
- }[];
44
- isError: boolean;
45
- } | {
46
- content: {
47
- type: string;
48
- text: string;
49
- }[];
50
- isError?: undefined;
51
- }>;
52
10
  /**
53
11
  * Set a specific config value
54
12
  */
@@ -65,19 +23,3 @@ export declare function setConfigValue(args: unknown): Promise<{
65
23
  }[];
66
24
  isError?: undefined;
67
25
  }>;
68
- /**
69
- * Update multiple config values at once
70
- */
71
- export declare function updateConfig(args: unknown): Promise<{
72
- content: {
73
- type: string;
74
- text: string;
75
- }[];
76
- isError: boolean;
77
- } | {
78
- content: {
79
- type: string;
80
- text: string;
81
- }[];
82
- isError?: undefined;
83
- }>;
@@ -1,17 +1,5 @@
1
- import { z } from 'zod';
2
1
  import { configManager } from '../config-manager.js';
3
- // Schemas for config operations
4
- export const GetConfigArgsSchema = z.object({});
5
- export const GetConfigValueArgsSchema = z.object({
6
- key: z.string(),
7
- });
8
- export const SetConfigValueArgsSchema = z.object({
9
- key: z.string(),
10
- value: z.any(),
11
- });
12
- export const UpdateConfigArgsSchema = z.object({
13
- config: z.record(z.any()),
14
- });
2
+ import { SetConfigValueArgsSchema } from './schemas.js';
15
3
  /**
16
4
  * Get the entire config
17
5
  */
@@ -39,46 +27,6 @@ export async function getConfig() {
39
27
  };
40
28
  }
41
29
  }
42
- /**
43
- * Get a specific config value
44
- */
45
- export async function getConfigValue(args) {
46
- console.error(`getConfigValue called with args: ${JSON.stringify(args)}`);
47
- try {
48
- const parsed = GetConfigValueArgsSchema.safeParse(args);
49
- if (!parsed.success) {
50
- console.error(`Invalid arguments for get_config_value: ${parsed.error}`);
51
- return {
52
- content: [{
53
- type: "text",
54
- text: `Invalid arguments: ${parsed.error}`
55
- }],
56
- isError: true
57
- };
58
- }
59
- const value = await configManager.getValue(parsed.data.key);
60
- console.error(`getConfigValue result for key ${parsed.data.key}: ${JSON.stringify(value)}`);
61
- return {
62
- content: [{
63
- type: "text",
64
- text: value !== undefined
65
- ? `Value for ${parsed.data.key}: ${JSON.stringify(value, null, 2)}`
66
- : `No value found for key: ${parsed.data.key}`
67
- }],
68
- };
69
- }
70
- catch (error) {
71
- console.error(`Error in getConfigValue: ${error instanceof Error ? error.message : String(error)}`);
72
- console.error(error instanceof Error && error.stack ? error.stack : 'No stack trace available');
73
- return {
74
- content: [{
75
- type: "text",
76
- text: `Error retrieving value: ${error instanceof Error ? error.message : String(error)}`
77
- }],
78
- isError: true
79
- };
80
- }
81
- }
82
30
  /**
83
31
  * Set a specific config value
84
32
  */
@@ -97,12 +45,52 @@ export async function setConfigValue(args) {
97
45
  };
98
46
  }
99
47
  try {
100
- await configManager.setValue(parsed.data.key, parsed.data.value);
101
- console.error(`setConfigValue: Successfully set ${parsed.data.key} to ${JSON.stringify(parsed.data.value)}`);
48
+ // Parse string values that should be arrays or objects
49
+ let valueToStore = parsed.data.value;
50
+ // If the value is a string that looks like an array or object, try to parse it
51
+ if (typeof valueToStore === 'string' &&
52
+ (valueToStore.startsWith('[') || valueToStore.startsWith('{'))) {
53
+ try {
54
+ valueToStore = JSON.parse(valueToStore);
55
+ console.error(`Parsed string value to object/array: ${JSON.stringify(valueToStore)}`);
56
+ }
57
+ catch (parseError) {
58
+ console.error(`Failed to parse string as JSON, using as-is: ${parseError}`);
59
+ }
60
+ }
61
+ // Special handling for known array configuration keys
62
+ if ((parsed.data.key === 'allowedDirectories' || parsed.data.key === 'blockedCommands') &&
63
+ !Array.isArray(valueToStore)) {
64
+ if (typeof valueToStore === 'string') {
65
+ try {
66
+ valueToStore = JSON.parse(valueToStore);
67
+ }
68
+ catch (parseError) {
69
+ console.error(`Failed to parse string as array for ${parsed.data.key}: ${parseError}`);
70
+ // If parsing failed and it's a single value, convert to an array with one item
71
+ if (!valueToStore.includes('[')) {
72
+ valueToStore = [valueToStore];
73
+ }
74
+ }
75
+ }
76
+ else {
77
+ // If not a string or array, convert to an array with one item
78
+ valueToStore = [valueToStore];
79
+ }
80
+ // Ensure the value is an array after all our conversions
81
+ if (!Array.isArray(valueToStore)) {
82
+ console.error(`Value for ${parsed.data.key} is still not an array, converting to array`);
83
+ valueToStore = [String(valueToStore)];
84
+ }
85
+ }
86
+ await configManager.setValue(parsed.data.key, valueToStore);
87
+ // Get the updated configuration to show the user
88
+ const updatedConfig = await configManager.getConfig();
89
+ console.error(`setConfigValue: Successfully set ${parsed.data.key} to ${JSON.stringify(valueToStore)}`);
102
90
  return {
103
91
  content: [{
104
92
  type: "text",
105
- text: `Successfully set ${parsed.data.key} to ${JSON.stringify(parsed.data.value, null, 2)}`
93
+ text: `Successfully set ${parsed.data.key} to ${JSON.stringify(valueToStore, null, 2)}\n\nUpdated configuration:\n${JSON.stringify(updatedConfig, null, 2)}`
106
94
  }],
107
95
  };
108
96
  }
@@ -130,54 +118,3 @@ export async function setConfigValue(args) {
130
118
  };
131
119
  }
132
120
  }
133
- /**
134
- * Update multiple config values at once
135
- */
136
- export async function updateConfig(args) {
137
- console.error(`updateConfig called with args: ${JSON.stringify(args)}`);
138
- try {
139
- const parsed = UpdateConfigArgsSchema.safeParse(args);
140
- if (!parsed.success) {
141
- console.error(`Invalid arguments for update_config: ${parsed.error}`);
142
- return {
143
- content: [{
144
- type: "text",
145
- text: `Invalid arguments: ${parsed.error}`
146
- }],
147
- isError: true
148
- };
149
- }
150
- try {
151
- const updatedConfig = await configManager.updateConfig(parsed.data.config);
152
- console.error(`updateConfig result: ${JSON.stringify(updatedConfig, null, 2)}`);
153
- return {
154
- content: [{
155
- type: "text",
156
- text: `Configuration updated successfully.\nNew configuration:\n${JSON.stringify(updatedConfig, null, 2)}`
157
- }],
158
- };
159
- }
160
- catch (saveError) {
161
- console.error(`Error saving updated config: ${saveError.message}`);
162
- // Return useful response instead of crashing
163
- return {
164
- content: [{
165
- type: "text",
166
- text: `Configuration updated in memory but couldn't be saved to disk: ${saveError.message}`
167
- }],
168
- isError: true
169
- };
170
- }
171
- }
172
- catch (error) {
173
- console.error(`Error in updateConfig: ${error instanceof Error ? error.message : String(error)}`);
174
- console.error(error instanceof Error && error.stack ? error.stack : 'No stack trace available');
175
- return {
176
- content: [{
177
- type: "text",
178
- text: `Error updating configuration: ${error instanceof Error ? error.message : String(error)}`
179
- }],
180
- isError: true
181
- };
182
- }
183
- }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ // This is a debug script to help understand how ~ expansion works
2
+ import os from 'os';
3
+ import path from 'path';
4
+ function expandHome(filepath) {
5
+ console.log(`Expanding ${filepath}`);
6
+ // Handle both '~' alone or '~/' path prefix
7
+ if (filepath === '~') {
8
+ const home = os.homedir();
9
+ console.log(`~ expanded to ${home}`);
10
+ return home;
11
+ }
12
+ else if (filepath.startsWith('~/')) {
13
+ const joinedPath = path.join(os.homedir(), filepath.slice(2));
14
+ console.log(`~/ expanded to ${joinedPath}`);
15
+ return joinedPath;
16
+ }
17
+ return filepath;
18
+ }
19
+ console.log(`Home directory: ${os.homedir()}`);
20
+ console.log(`Current working directory: ${process.cwd()}`);
21
+ console.log(`Expanding ~: ${expandHome('~')}`);
22
+ console.log(`Expanding ~/Documents: ${expandHome('~/Documents')}`);
23
+ console.log(`Expanding /tmp: ${expandHome('/tmp')}`);
24
+ // Create lowercase normalized paths for comparison
25
+ function normalizePath(p) {
26
+ return path.normalize(p).toLowerCase();
27
+ }
28
+ const allowedDir = '~';
29
+ const expandedAllowedDir = expandHome(allowedDir);
30
+ const normalizedAllowedDir = normalizePath(expandedAllowedDir);
31
+ console.log(`Allowed dir: ${allowedDir}`);
32
+ console.log(`Expanded allowed dir: ${expandedAllowedDir}`);
33
+ console.log(`Normalized allowed dir: ${normalizedAllowedDir}`);
34
+ // Example path to check
35
+ const pathToCheck = '~';
36
+ const expandedPathToCheck = expandHome(pathToCheck);
37
+ const normalizedPathToCheck = normalizePath(expandedPathToCheck);
38
+ console.log(`Path to check: ${pathToCheck}`);
39
+ console.log(`Expanded path to check: ${expandedPathToCheck}`);
40
+ console.log(`Normalized path to check: ${normalizedPathToCheck}`);
41
+ // Check if path is allowed
42
+ const isAllowed = normalizedPathToCheck === normalizedAllowedDir ||
43
+ normalizedPathToCheck.startsWith(normalizedAllowedDir + path.sep);
44
+ console.log(`Is path allowed: ${isAllowed}`);
@@ -1,20 +1,23 @@
1
1
  import { readFile, writeFile } from './filesystem.js';
2
2
  export async function performSearchReplace(filePath, block) {
3
3
  // Read file as plain string (don't pass true to get just the string)
4
- const content = await readFile(filePath);
4
+ const { content } = await readFile(filePath);
5
5
  // Make sure content is a string
6
- const contentStr = typeof content === 'string' ? content : content.content;
6
+ if (typeof content !== 'string') {
7
+ throw new Error('Wrong content for file ' + filePath);
8
+ }
9
+ ;
7
10
  // Find first occurrence
8
- const searchIndex = contentStr.indexOf(block.search);
11
+ const searchIndex = content.indexOf(block.search);
9
12
  if (searchIndex === -1) {
10
13
  return {
11
14
  content: [{ type: "text", text: `Search content not found in ${filePath}.` }],
12
15
  };
13
16
  }
14
17
  // Replace content
15
- const newContent = contentStr.substring(0, searchIndex) +
18
+ const newContent = content.substring(0, searchIndex) +
16
19
  block.replace +
17
- contentStr.substring(searchIndex + block.search.length);
20
+ content.substring(searchIndex + block.search.length);
18
21
  await writeFile(filePath, newContent);
19
22
  return {
20
23
  content: [{ type: "text", text: `Successfully applied edit to ${filePath}` }],
@@ -24,16 +24,16 @@ export async function executeCommand(args) {
24
24
  capture('server_execute_command', {
25
25
  command: commandManager.getBaseCommand(parsed.data.command)
26
26
  });
27
- // Log the error but continue execution
28
- console.error('Error during command extraction:', error);
29
27
  }
30
- if (!commandManager.validateCommand(parsed.data.command)) {
28
+ // Command validation is now async
29
+ const isAllowed = await commandManager.validateCommand(parsed.data.command);
30
+ if (!isAllowed) {
31
31
  return {
32
32
  content: [{ type: "text", text: `Error: Command not allowed: ${parsed.data.command}` }],
33
33
  isError: true,
34
34
  };
35
35
  }
36
- const result = await terminalManager.executeCommand(parsed.data.command, parsed.data.timeout_ms);
36
+ const result = await terminalManager.executeCommand(parsed.data.command, parsed.data.timeout_ms, parsed.data.shell);
37
37
  // Check for error condition (pid = -1)
38
38
  if (result.pid === -1) {
39
39
  return {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Read a file from either the local filesystem or a URL
3
+ * @param filePath Path to the file or URL
4
+ * @param returnMetadata Whether to return metadata with the content
5
+ * @param isUrl Whether the path is a URL
6
+ * @returns File content or file result with metadata
7
+ */
8
+ export declare function readFile(filePath: string, returnMetadata?: boolean, isUrl?: boolean): Promise<string | FileResult>;
9
+ export declare function writeFile(filePath: string, content: string): Promise<void>;
10
+ export interface MultiFileResult {
11
+ path: string;
12
+ content?: string;
13
+ mimeType?: string;
14
+ isImage?: boolean;
15
+ error?: string;
16
+ }
17
+ export declare function readMultipleFiles(paths: string[]): Promise<MultiFileResult[]>;
18
+ export declare function createDirectory(dirPath: string): Promise<void>;
19
+ export declare function listDirectory(dirPath: string): Promise<string[]>;
20
+ export declare function moveFile(sourcePath: string, destinationPath: string): Promise<void>;
21
+ export declare function searchFiles(rootPath: string, pattern: string): Promise<string[]>;
22
+ export declare function getFileInfo(filePath: string): Promise<Record<string, any>>;