@wonderwhy-er/desktop-commander 0.2.9 → 0.2.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.
- package/README.md +17 -5
- package/dist/custom-stdio.d.ts +14 -0
- package/dist/custom-stdio.js +140 -13
- package/dist/handlers/edit-search-handlers.d.ts +0 -5
- package/dist/handlers/edit-search-handlers.js +0 -82
- package/dist/handlers/filesystem-handlers.d.ts +0 -4
- package/dist/handlers/filesystem-handlers.js +2 -36
- package/dist/handlers/index.d.ts +1 -0
- package/dist/handlers/index.js +1 -0
- package/dist/handlers/search-handlers.d.ts +17 -0
- package/dist/handlers/search-handlers.js +219 -0
- package/dist/index.js +50 -64
- package/dist/npm-scripts/setup.d.ts +1 -0
- package/dist/npm-scripts/setup.js +40 -0
- package/dist/npm-scripts/uninstall.d.ts +1 -0
- package/dist/npm-scripts/uninstall.js +40 -0
- package/dist/search-manager.d.ts +107 -0
- package/dist/search-manager.js +467 -0
- package/dist/server.js +99 -31
- package/dist/setup.log +63 -0
- package/dist/tools/filesystem.js +59 -1
- package/dist/tools/schemas.d.ts +55 -41
- package/dist/tools/schemas.js +22 -16
- package/dist/tools/search.js +31 -3
- package/dist/track-installation.js +368 -0
- package/dist/utils/capture.js +56 -8
- package/dist/utils/dedent.d.ts +8 -0
- package/dist/utils/dedent.js +38 -0
- package/dist/utils/logger.d.ts +32 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/system-info.d.ts +8 -2
- package/dist/utils/system-info.js +247 -30
- package/dist/utils/usageTracker.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
package/dist/setup.log
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
2025-08-21T08:55:05.547Z - ✅ Desktop Commander MCP v0.2.9 successfully added to Claude’s configuration.
|
|
2
|
+
2025-08-21T08:55:05.547Z - Configuration location: /Users/fiberta/Library/Application Support/Claude/claude_desktop_config.json
|
|
3
|
+
2025-08-21T08:55:08.757Z -
|
|
4
|
+
✅ Claude has been restarted automatically!
|
|
5
|
+
2025-08-21T08:55:08.778Z -
|
|
6
|
+
✅ Installation successfully completed! Thank you for using Desktop Commander!
|
|
7
|
+
|
|
8
|
+
2025-08-21T08:55:08.779Z -
|
|
9
|
+
The server is available as "desktop-commander" in Claude's MCP server list
|
|
10
|
+
2025-08-21T08:55:08.779Z - Future updates will install automatically — no need to run this setup again.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
2025-08-21T08:55:08.779Z - 🤔 Need help or have feedback? Happy to jump on a quick call:
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
2025-08-21T08:55:08.779Z - https://calendar.app.google/SHMNZN5MJznJWC5A7
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
2025-08-21T08:55:08.779Z - or join our community: https://discord.com/invite/kQ27sNnZr7
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
2025-08-21T14:58:41.568Z - ✅ Desktop Commander MCP v0.2.9 successfully added to Claude’s configuration.
|
|
23
|
+
2025-08-21T14:58:41.568Z - Configuration location: /Users/fiberta/Library/Application Support/Claude/claude_desktop_config.json
|
|
24
|
+
2025-08-21T14:58:44.701Z -
|
|
25
|
+
✅ Claude has been restarted automatically!
|
|
26
|
+
2025-08-21T14:58:44.728Z -
|
|
27
|
+
✅ Installation successfully completed! Thank you for using Desktop Commander!
|
|
28
|
+
|
|
29
|
+
2025-08-21T14:58:44.728Z -
|
|
30
|
+
The server is available as "desktop-commander" in Claude's MCP server list
|
|
31
|
+
2025-08-21T14:58:44.728Z - Future updates will install automatically — no need to run this setup again.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
2025-08-21T14:58:44.728Z - 🤔 Need help or have feedback? Happy to jump on a quick call:
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
2025-08-21T14:58:44.728Z - https://calendar.app.google/SHMNZN5MJznJWC5A7
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
2025-08-21T14:58:44.728Z - or join our community: https://discord.com/invite/kQ27sNnZr7
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
2025-08-21T15:01:40.796Z - ✅ Desktop Commander MCP v0.2.9 successfully added to Claude’s configuration.
|
|
44
|
+
2025-08-21T15:01:40.796Z - Configuration location: /Users/fiberta/Library/Application Support/Claude/claude_desktop_config.json
|
|
45
|
+
2025-08-21T15:01:43.911Z -
|
|
46
|
+
✅ Claude has been restarted automatically!
|
|
47
|
+
2025-08-21T15:01:43.932Z -
|
|
48
|
+
✅ Installation successfully completed! Thank you for using Desktop Commander!
|
|
49
|
+
|
|
50
|
+
2025-08-21T15:01:43.932Z -
|
|
51
|
+
The server is available as "desktop-commander" in Claude's MCP server list
|
|
52
|
+
2025-08-21T15:01:43.932Z - Future updates will install automatically — no need to run this setup again.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
2025-08-21T15:01:43.932Z - 🤔 Need help or have feedback? Happy to jump on a quick call:
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
2025-08-21T15:01:43.932Z - https://calendar.app.google/SHMNZN5MJznJWC5A7
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
2025-08-21T15:01:43.932Z - or join our community: https://discord.com/invite/kQ27sNnZr7
|
|
62
|
+
|
|
63
|
+
|
package/dist/tools/filesystem.js
CHANGED
|
@@ -768,6 +768,63 @@ export async function moveFile(sourcePath, destinationPath) {
|
|
|
768
768
|
await fs.rename(validSourcePath, validDestPath);
|
|
769
769
|
}
|
|
770
770
|
export async function searchFiles(rootPath, pattern) {
|
|
771
|
+
// Use the new search manager for better performance
|
|
772
|
+
// This provides a temporary compatibility layer until we fully migrate to search sessions
|
|
773
|
+
const { searchManager } = await import('../search-manager.js');
|
|
774
|
+
try {
|
|
775
|
+
const result = await searchManager.startSearch({
|
|
776
|
+
rootPath,
|
|
777
|
+
pattern,
|
|
778
|
+
searchType: 'files',
|
|
779
|
+
ignoreCase: true,
|
|
780
|
+
maxResults: 5000, // Higher limit for compatibility
|
|
781
|
+
earlyTermination: true, // Use early termination for better performance
|
|
782
|
+
});
|
|
783
|
+
const sessionId = result.sessionId;
|
|
784
|
+
// Poll for results until complete
|
|
785
|
+
let allResults = [];
|
|
786
|
+
let isComplete = result.isComplete;
|
|
787
|
+
let startTime = Date.now();
|
|
788
|
+
// Add initial results
|
|
789
|
+
for (const searchResult of result.results) {
|
|
790
|
+
if (searchResult.type === 'file') {
|
|
791
|
+
allResults.push(searchResult.file);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
while (!isComplete) {
|
|
795
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // Wait 100ms
|
|
796
|
+
const results = searchManager.readSearchResults(sessionId);
|
|
797
|
+
isComplete = results.isComplete;
|
|
798
|
+
// Add new file paths to results
|
|
799
|
+
for (const searchResult of results.results) {
|
|
800
|
+
if (searchResult.file !== '__LAST_READ_MARKER__' && searchResult.type === 'file') {
|
|
801
|
+
allResults.push(searchResult.file);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
// Safety check to prevent infinite loops (30 second timeout)
|
|
805
|
+
if (Date.now() - startTime > 30000) {
|
|
806
|
+
searchManager.terminateSearch(sessionId);
|
|
807
|
+
break;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
// Log only the count of found files, not their paths
|
|
811
|
+
capture('server_search_files_complete', {
|
|
812
|
+
resultsCount: allResults.length,
|
|
813
|
+
patternLength: pattern.length,
|
|
814
|
+
usedRipgrep: true
|
|
815
|
+
});
|
|
816
|
+
return allResults;
|
|
817
|
+
}
|
|
818
|
+
catch (error) {
|
|
819
|
+
// Fallback to original Node.js implementation if ripgrep fails
|
|
820
|
+
capture('server_search_files_ripgrep_fallback', {
|
|
821
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
822
|
+
});
|
|
823
|
+
return await searchFilesNodeJS(rootPath, pattern);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
// Keep the original Node.js implementation as fallback
|
|
827
|
+
async function searchFilesNodeJS(rootPath, pattern) {
|
|
771
828
|
const results = [];
|
|
772
829
|
async function search(currentPath) {
|
|
773
830
|
let entries;
|
|
@@ -800,7 +857,8 @@ export async function searchFiles(rootPath, pattern) {
|
|
|
800
857
|
// Log only the count of found files, not their paths
|
|
801
858
|
capture('server_search_files_complete', {
|
|
802
859
|
resultsCount: results.length,
|
|
803
|
-
patternLength: pattern.length
|
|
860
|
+
patternLength: pattern.length,
|
|
861
|
+
usedRipgrep: false
|
|
804
862
|
});
|
|
805
863
|
return results;
|
|
806
864
|
}
|
package/dist/tools/schemas.d.ts
CHANGED
|
@@ -109,19 +109,6 @@ export declare const MoveFileArgsSchema: z.ZodObject<{
|
|
|
109
109
|
source: string;
|
|
110
110
|
destination: string;
|
|
111
111
|
}>;
|
|
112
|
-
export declare const SearchFilesArgsSchema: z.ZodObject<{
|
|
113
|
-
path: z.ZodString;
|
|
114
|
-
pattern: z.ZodString;
|
|
115
|
-
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
116
|
-
}, "strip", z.ZodTypeAny, {
|
|
117
|
-
path: string;
|
|
118
|
-
pattern: string;
|
|
119
|
-
timeoutMs?: number | undefined;
|
|
120
|
-
}, {
|
|
121
|
-
path: string;
|
|
122
|
-
pattern: string;
|
|
123
|
-
timeoutMs?: number | undefined;
|
|
124
|
-
}>;
|
|
125
112
|
export declare const GetFileInfoArgsSchema: z.ZodObject<{
|
|
126
113
|
path: z.ZodString;
|
|
127
114
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -129,34 +116,6 @@ export declare const GetFileInfoArgsSchema: z.ZodObject<{
|
|
|
129
116
|
}, {
|
|
130
117
|
path: string;
|
|
131
118
|
}>;
|
|
132
|
-
export declare const SearchCodeArgsSchema: z.ZodObject<{
|
|
133
|
-
path: z.ZodString;
|
|
134
|
-
pattern: z.ZodString;
|
|
135
|
-
filePattern: z.ZodOptional<z.ZodString>;
|
|
136
|
-
ignoreCase: z.ZodOptional<z.ZodBoolean>;
|
|
137
|
-
maxResults: z.ZodOptional<z.ZodNumber>;
|
|
138
|
-
includeHidden: z.ZodOptional<z.ZodBoolean>;
|
|
139
|
-
contextLines: z.ZodOptional<z.ZodNumber>;
|
|
140
|
-
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
141
|
-
}, "strip", z.ZodTypeAny, {
|
|
142
|
-
path: string;
|
|
143
|
-
pattern: string;
|
|
144
|
-
timeoutMs?: number | undefined;
|
|
145
|
-
filePattern?: string | undefined;
|
|
146
|
-
ignoreCase?: boolean | undefined;
|
|
147
|
-
maxResults?: number | undefined;
|
|
148
|
-
includeHidden?: boolean | undefined;
|
|
149
|
-
contextLines?: number | undefined;
|
|
150
|
-
}, {
|
|
151
|
-
path: string;
|
|
152
|
-
pattern: string;
|
|
153
|
-
timeoutMs?: number | undefined;
|
|
154
|
-
filePattern?: string | undefined;
|
|
155
|
-
ignoreCase?: boolean | undefined;
|
|
156
|
-
maxResults?: number | undefined;
|
|
157
|
-
includeHidden?: boolean | undefined;
|
|
158
|
-
contextLines?: number | undefined;
|
|
159
|
-
}>;
|
|
160
119
|
export declare const EditBlockArgsSchema: z.ZodObject<{
|
|
161
120
|
file_path: z.ZodString;
|
|
162
121
|
old_string: z.ZodString;
|
|
@@ -191,3 +150,58 @@ export declare const InteractWithProcessArgsSchema: z.ZodObject<{
|
|
|
191
150
|
}>;
|
|
192
151
|
export declare const GetUsageStatsArgsSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
193
152
|
export declare const GiveFeedbackArgsSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
153
|
+
export declare const StartSearchArgsSchema: z.ZodObject<{
|
|
154
|
+
path: z.ZodString;
|
|
155
|
+
pattern: z.ZodString;
|
|
156
|
+
searchType: z.ZodDefault<z.ZodEnum<["files", "content"]>>;
|
|
157
|
+
filePattern: z.ZodOptional<z.ZodString>;
|
|
158
|
+
ignoreCase: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
159
|
+
maxResults: z.ZodOptional<z.ZodNumber>;
|
|
160
|
+
includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
161
|
+
contextLines: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
162
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
163
|
+
earlyTermination: z.ZodOptional<z.ZodBoolean>;
|
|
164
|
+
}, "strip", z.ZodTypeAny, {
|
|
165
|
+
path: string;
|
|
166
|
+
pattern: string;
|
|
167
|
+
searchType: "content" | "files";
|
|
168
|
+
ignoreCase: boolean;
|
|
169
|
+
includeHidden: boolean;
|
|
170
|
+
contextLines: number;
|
|
171
|
+
timeout_ms?: number | undefined;
|
|
172
|
+
filePattern?: string | undefined;
|
|
173
|
+
maxResults?: number | undefined;
|
|
174
|
+
earlyTermination?: boolean | undefined;
|
|
175
|
+
}, {
|
|
176
|
+
path: string;
|
|
177
|
+
pattern: string;
|
|
178
|
+
timeout_ms?: number | undefined;
|
|
179
|
+
searchType?: "content" | "files" | undefined;
|
|
180
|
+
filePattern?: string | undefined;
|
|
181
|
+
ignoreCase?: boolean | undefined;
|
|
182
|
+
maxResults?: number | undefined;
|
|
183
|
+
includeHidden?: boolean | undefined;
|
|
184
|
+
contextLines?: number | undefined;
|
|
185
|
+
earlyTermination?: boolean | undefined;
|
|
186
|
+
}>;
|
|
187
|
+
export declare const GetMoreSearchResultsArgsSchema: z.ZodObject<{
|
|
188
|
+
sessionId: z.ZodString;
|
|
189
|
+
offset: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
190
|
+
length: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
191
|
+
}, "strip", z.ZodTypeAny, {
|
|
192
|
+
length: number;
|
|
193
|
+
offset: number;
|
|
194
|
+
sessionId: string;
|
|
195
|
+
}, {
|
|
196
|
+
sessionId: string;
|
|
197
|
+
length?: number | undefined;
|
|
198
|
+
offset?: number | undefined;
|
|
199
|
+
}>;
|
|
200
|
+
export declare const StopSearchArgsSchema: z.ZodObject<{
|
|
201
|
+
sessionId: z.ZodString;
|
|
202
|
+
}, "strip", z.ZodTypeAny, {
|
|
203
|
+
sessionId: string;
|
|
204
|
+
}, {
|
|
205
|
+
sessionId: string;
|
|
206
|
+
}>;
|
|
207
|
+
export declare const ListSearchesArgsSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
package/dist/tools/schemas.js
CHANGED
|
@@ -49,25 +49,9 @@ export const MoveFileArgsSchema = z.object({
|
|
|
49
49
|
source: z.string(),
|
|
50
50
|
destination: z.string(),
|
|
51
51
|
});
|
|
52
|
-
export const SearchFilesArgsSchema = z.object({
|
|
53
|
-
path: z.string(),
|
|
54
|
-
pattern: z.string(),
|
|
55
|
-
timeoutMs: z.number().optional(),
|
|
56
|
-
});
|
|
57
52
|
export const GetFileInfoArgsSchema = z.object({
|
|
58
53
|
path: z.string(),
|
|
59
54
|
});
|
|
60
|
-
// Search tools schema
|
|
61
|
-
export const SearchCodeArgsSchema = z.object({
|
|
62
|
-
path: z.string(),
|
|
63
|
-
pattern: z.string(),
|
|
64
|
-
filePattern: z.string().optional(),
|
|
65
|
-
ignoreCase: z.boolean().optional(),
|
|
66
|
-
maxResults: z.number().optional(),
|
|
67
|
-
includeHidden: z.boolean().optional(),
|
|
68
|
-
contextLines: z.number().optional(),
|
|
69
|
-
timeoutMs: z.number().optional(),
|
|
70
|
-
});
|
|
71
55
|
// Edit tools schema
|
|
72
56
|
export const EditBlockArgsSchema = z.object({
|
|
73
57
|
file_path: z.string(),
|
|
@@ -93,3 +77,25 @@ export const GiveFeedbackArgsSchema = z.object({
|
|
|
93
77
|
// - platform (auto)
|
|
94
78
|
// - client_id (auto)
|
|
95
79
|
});
|
|
80
|
+
// Search schemas (renamed for natural language)
|
|
81
|
+
export const StartSearchArgsSchema = z.object({
|
|
82
|
+
path: z.string(),
|
|
83
|
+
pattern: z.string(),
|
|
84
|
+
searchType: z.enum(['files', 'content']).default('files'),
|
|
85
|
+
filePattern: z.string().optional(),
|
|
86
|
+
ignoreCase: z.boolean().optional().default(true),
|
|
87
|
+
maxResults: z.number().optional(),
|
|
88
|
+
includeHidden: z.boolean().optional().default(false),
|
|
89
|
+
contextLines: z.number().optional().default(5),
|
|
90
|
+
timeout_ms: z.number().optional(), // Match process naming convention
|
|
91
|
+
earlyTermination: z.boolean().optional(), // Stop search early when exact filename match is found (default: true for files, false for content)
|
|
92
|
+
});
|
|
93
|
+
export const GetMoreSearchResultsArgsSchema = z.object({
|
|
94
|
+
sessionId: z.string(),
|
|
95
|
+
offset: z.number().optional().default(0), // Same as file reading
|
|
96
|
+
length: z.number().optional().default(100), // Same as file reading (but smaller default)
|
|
97
|
+
});
|
|
98
|
+
export const StopSearchArgsSchema = z.object({
|
|
99
|
+
sessionId: z.string(),
|
|
100
|
+
});
|
|
101
|
+
export const ListSearchesArgsSchema = z.object({});
|
package/dist/tools/search.js
CHANGED
|
@@ -27,7 +27,15 @@ export async function searchCode(options) {
|
|
|
27
27
|
args.push('-C', contextLines.toString());
|
|
28
28
|
}
|
|
29
29
|
if (filePattern) {
|
|
30
|
-
|
|
30
|
+
const patterns = filePattern
|
|
31
|
+
.split('|')
|
|
32
|
+
.map(p => p.trim()) // remove surrounding spaces
|
|
33
|
+
.filter(Boolean); // drop empty tokens
|
|
34
|
+
// If all patterns were empty, return no results
|
|
35
|
+
if (patterns.length === 0) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
patterns.forEach(p => args.push('-g', p));
|
|
31
39
|
}
|
|
32
40
|
// Add pattern and path
|
|
33
41
|
args.push(pattern, validPath);
|
|
@@ -97,7 +105,21 @@ export async function searchCodeFallback(options) {
|
|
|
97
105
|
const validPath = await validatePath(rootPath);
|
|
98
106
|
const results = [];
|
|
99
107
|
const regex = new RegExp(pattern, ignoreCase ? 'i' : '');
|
|
100
|
-
|
|
108
|
+
// Handle filePattern similarly to main implementation
|
|
109
|
+
let fileRegex = null;
|
|
110
|
+
if (filePattern) {
|
|
111
|
+
const patterns = filePattern
|
|
112
|
+
.split('|')
|
|
113
|
+
.map(p => p.trim())
|
|
114
|
+
.filter(Boolean);
|
|
115
|
+
// If all patterns were empty, return no results
|
|
116
|
+
if (patterns.length === 0) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
// Create a regex that matches any of the patterns
|
|
120
|
+
const combinedPattern = patterns.map(p => p.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/\?/g, '.')).join('|');
|
|
121
|
+
fileRegex = new RegExp(`^(${combinedPattern})$`);
|
|
122
|
+
}
|
|
101
123
|
async function searchDir(dirPath) {
|
|
102
124
|
if (results.length >= maxResults)
|
|
103
125
|
return;
|
|
@@ -163,12 +185,18 @@ export async function searchCodeFallback(options) {
|
|
|
163
185
|
// Main function that tries ripgrep first, falls back to native implementation
|
|
164
186
|
export async function searchTextInFiles(options) {
|
|
165
187
|
try {
|
|
188
|
+
// For better performance and consistency, prefer the search session manager
|
|
189
|
+
// when doing content search, but keep the original direct ripgrep approach as primary
|
|
166
190
|
return await searchCode(options);
|
|
167
191
|
}
|
|
168
192
|
catch (error) {
|
|
193
|
+
capture('searchTextInFiles_ripgrep_fallback', {
|
|
194
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
195
|
+
});
|
|
196
|
+
// Use consistent exclusions - remove 'dist' to match ripgrep behavior
|
|
169
197
|
return searchCodeFallback({
|
|
170
198
|
...options,
|
|
171
|
-
excludeDirs: ['node_modules', '.git'
|
|
199
|
+
excludeDirs: ['node_modules', '.git']
|
|
172
200
|
});
|
|
173
201
|
}
|
|
174
202
|
}
|