@wonderwhy-er/desktop-commander 0.1.35 → 0.1.36
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/LICENSE +2 -2
- package/README.md +88 -27
- package/dist/command-manager.js +1 -1
- package/dist/config-manager.d.ts +1 -0
- package/dist/config-manager.js +21 -4
- package/dist/config.d.ts +2 -2
- package/dist/config.js +2 -3
- package/dist/error-handlers.js +1 -1
- package/dist/handlers/edit-search-handlers.d.ts +3 -1
- package/dist/handlers/edit-search-handlers.js +6 -12
- package/dist/handlers/filesystem-handlers.js +1 -1
- package/dist/index.js +1 -1
- package/dist/polyform-license-src/edit/edit.d.ts +15 -0
- package/dist/polyform-license-src/edit/edit.js +163 -0
- package/dist/polyform-license-src/edit/fuzzySearch.d.ts +30 -0
- package/dist/polyform-license-src/edit/fuzzySearch.js +121 -0
- package/dist/polyform-license-src/edit/handlers.d.ts +16 -0
- package/dist/polyform-license-src/edit/handlers.js +24 -0
- package/dist/polyform-license-src/edit/index.d.ts +12 -0
- package/dist/polyform-license-src/edit/index.js +13 -0
- package/dist/polyform-license-src/edit/schemas.d.ts +25 -0
- package/dist/polyform-license-src/edit/schemas.js +16 -0
- package/dist/polyform-license-src/index.d.ts +9 -0
- package/dist/polyform-license-src/index.js +10 -0
- package/dist/server.js +71 -43
- package/dist/setup-claude-server.js +549 -288
- package/dist/terminal-manager.js +4 -2
- package/dist/tools/edit.d.ts +8 -6
- package/dist/tools/edit.js +161 -34
- package/dist/tools/execute.js +2 -2
- package/dist/tools/filesystem.js +59 -10
- package/dist/tools/fuzzySearch.d.ts +22 -0
- package/dist/tools/fuzzySearch.js +113 -0
- package/dist/tools/pdf-reader.d.ts +13 -0
- package/dist/tools/pdf-reader.js +214 -0
- package/dist/tools/schemas.d.ts +12 -3
- package/dist/tools/schemas.js +5 -2
- package/dist/tools/search.js +5 -4
- package/dist/utils/capture.d.ts +15 -0
- package/dist/utils/capture.js +175 -0
- package/dist/utils/withTimeout.d.ts +11 -0
- package/dist/utils/withTimeout.js +52 -0
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +99 -26
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { platform } from 'os';
|
|
2
|
-
import {
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
3
|
import * as https from 'https';
|
|
4
|
+
import { configManager } from './config-manager.js';
|
|
4
5
|
let VERSION = 'unknown';
|
|
5
6
|
try {
|
|
6
7
|
const versionModule = await import('./version.js');
|
|
@@ -13,38 +14,106 @@ catch {
|
|
|
13
14
|
const GA_MEASUREMENT_ID = 'G-NGGDNL0K4L'; // Replace with your GA4 Measurement ID
|
|
14
15
|
const GA_API_SECRET = '5M0mC--2S_6t94m8WrI60A'; // Replace with your GA4 API Secret
|
|
15
16
|
const GA_BASE_URL = `https://www.google-analytics.com/mp/collect?measurement_id=${GA_MEASUREMENT_ID}&api_secret=${GA_API_SECRET}`;
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const GA_DEBUG_BASE_URL = `https://www.google-analytics.com/debug/mp/collect?measurement_id=${GA_MEASUREMENT_ID}&api_secret=${GA_API_SECRET}`;
|
|
18
|
+
// Will be initialized when needed
|
|
18
19
|
let uniqueUserId = 'unknown';
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
20
|
+
// Function to get or create a persistent UUID
|
|
21
|
+
async function getOrCreateUUID() {
|
|
22
|
+
try {
|
|
23
|
+
// Try to get the UUID from the config
|
|
24
|
+
let clientId = await configManager.getValue('clientId');
|
|
25
|
+
// If it doesn't exist, create a new one and save it
|
|
26
|
+
if (!clientId) {
|
|
27
|
+
clientId = randomUUID();
|
|
28
|
+
await configManager.setValue('clientId', clientId);
|
|
29
|
+
}
|
|
30
|
+
return clientId;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// Fallback to a random UUID if config operations fail
|
|
34
|
+
return randomUUID();
|
|
35
|
+
}
|
|
31
36
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Sanitizes error objects to remove potentially sensitive information like file paths
|
|
39
|
+
* @param error Error object or string to sanitize
|
|
40
|
+
* @returns An object with sanitized message and optional error code
|
|
41
|
+
*/
|
|
42
|
+
export function sanitizeError(error) {
|
|
43
|
+
let errorMessage = '';
|
|
44
|
+
let errorCode = undefined;
|
|
45
|
+
if (error instanceof Error) {
|
|
46
|
+
// Extract just the error name and message without stack trace
|
|
47
|
+
errorMessage = error.name + ': ' + error.message;
|
|
48
|
+
// Extract error code if available (common in Node.js errors)
|
|
49
|
+
if ('code' in error) {
|
|
50
|
+
errorCode = error.code;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (typeof error === 'string') {
|
|
54
|
+
errorMessage = error;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
errorMessage = 'Unknown error';
|
|
58
|
+
}
|
|
59
|
+
// Remove any file paths using regex
|
|
60
|
+
// This pattern matches common path formats including Windows and Unix-style paths
|
|
61
|
+
errorMessage = errorMessage.replace(/(?:\/|\\)[\w\d_.-\/\\]+/g, '[PATH]');
|
|
62
|
+
errorMessage = errorMessage.replace(/[A-Za-z]:\\[\w\d_.-\/\\]+/g, '[PATH]');
|
|
63
|
+
return {
|
|
64
|
+
message: errorMessage,
|
|
65
|
+
code: errorCode
|
|
66
|
+
};
|
|
37
67
|
}
|
|
38
68
|
/**
|
|
39
69
|
* Send an event to Google Analytics
|
|
40
70
|
* @param event Event name
|
|
41
71
|
* @param properties Optional event properties
|
|
42
72
|
*/
|
|
43
|
-
export const capture = (event, properties) => {
|
|
44
|
-
if (!isTrackingEnabled || !GA_MEASUREMENT_ID || !GA_API_SECRET) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
73
|
+
export const capture = async (event, properties) => {
|
|
47
74
|
try {
|
|
75
|
+
// Check if telemetry is enabled in config (defaults to true if not set)
|
|
76
|
+
const telemetryEnabled = await configManager.getValue('telemetryEnabled');
|
|
77
|
+
// If telemetry is explicitly disabled or GA credentials are missing, don't send
|
|
78
|
+
if (telemetryEnabled === false || !GA_MEASUREMENT_ID || !GA_API_SECRET) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Get or create the client ID if not already initialized
|
|
82
|
+
if (uniqueUserId === 'unknown') {
|
|
83
|
+
uniqueUserId = await getOrCreateUUID();
|
|
84
|
+
}
|
|
85
|
+
// Create a deep copy of properties to avoid modifying the original objects
|
|
86
|
+
// This ensures we don't alter error objects that are also returned to the AI
|
|
87
|
+
let sanitizedProperties;
|
|
88
|
+
try {
|
|
89
|
+
sanitizedProperties = properties ? JSON.parse(JSON.stringify(properties)) : {};
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
sanitizedProperties = {};
|
|
93
|
+
}
|
|
94
|
+
// Sanitize error objects if present
|
|
95
|
+
if (sanitizedProperties.error) {
|
|
96
|
+
// Handle different types of error objects
|
|
97
|
+
if (typeof sanitizedProperties.error === 'object' && sanitizedProperties.error !== null) {
|
|
98
|
+
const sanitized = sanitizeError(sanitizedProperties.error);
|
|
99
|
+
sanitizedProperties.error = sanitized.message;
|
|
100
|
+
if (sanitized.code) {
|
|
101
|
+
sanitizedProperties.errorCode = sanitized.code;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (typeof sanitizedProperties.error === 'string') {
|
|
105
|
+
sanitizedProperties.error = sanitizeError(sanitizedProperties.error).message;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Remove any properties that might contain paths
|
|
109
|
+
const sensitiveKeys = ['path', 'filePath', 'directory', 'file_path', 'sourcePath', 'destinationPath', 'fullPath', 'rootPath'];
|
|
110
|
+
for (const key of Object.keys(sanitizedProperties)) {
|
|
111
|
+
const lowerKey = key.toLowerCase();
|
|
112
|
+
if (sensitiveKeys.some(sensitiveKey => lowerKey.includes(sensitiveKey)) &&
|
|
113
|
+
lowerKey !== 'fileextension') { // keep fileExtension as it's safe
|
|
114
|
+
delete sanitizedProperties[key];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
48
117
|
// Prepare standard properties
|
|
49
118
|
const baseProperties = {
|
|
50
119
|
timestamp: new Date().toISOString(),
|
|
@@ -52,10 +121,10 @@ export const capture = (event, properties) => {
|
|
|
52
121
|
app_version: VERSION,
|
|
53
122
|
engagement_time_msec: "100"
|
|
54
123
|
};
|
|
55
|
-
// Combine with
|
|
124
|
+
// Combine with sanitized properties
|
|
56
125
|
const eventProperties = {
|
|
57
126
|
...baseProperties,
|
|
58
|
-
...
|
|
127
|
+
...sanitizedProperties
|
|
59
128
|
};
|
|
60
129
|
// Prepare GA4 payload
|
|
61
130
|
const payload = {
|
|
@@ -115,6 +184,7 @@ export const capture = (event, properties) => {
|
|
|
115
184
|
* @returns Promise that resolves with the operation result or the default value on timeout
|
|
116
185
|
*/
|
|
117
186
|
export function withTimeout(operation, timeoutMs, operationName, defaultValue) {
|
|
187
|
+
// Don't sanitize operation name for logs - only telemetry will sanitize if needed
|
|
118
188
|
return new Promise((resolve, reject) => {
|
|
119
189
|
let isCompleted = false;
|
|
120
190
|
// Set up timeout
|
|
@@ -125,6 +195,8 @@ export function withTimeout(operation, timeoutMs, operationName, defaultValue) {
|
|
|
125
195
|
resolve(defaultValue);
|
|
126
196
|
}
|
|
127
197
|
else {
|
|
198
|
+
// Keep the original operation name in the error message
|
|
199
|
+
// Telemetry sanitization happens at the capture level
|
|
128
200
|
reject(`__ERROR__: ${operationName} timed out after ${timeoutMs / 1000} seconds`);
|
|
129
201
|
}
|
|
130
202
|
}
|
|
@@ -146,6 +218,7 @@ export function withTimeout(operation, timeoutMs, operationName, defaultValue) {
|
|
|
146
218
|
resolve(defaultValue);
|
|
147
219
|
}
|
|
148
220
|
else {
|
|
221
|
+
// Pass the original error unchanged - sanitization for telemetry happens in capture
|
|
149
222
|
reject(error);
|
|
150
223
|
}
|
|
151
224
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.36";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.1.
|
|
1
|
+
export const VERSION = '0.1.36';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wonderwhy-er/desktop-commander",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "MCP server for terminal operations and file editing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eduards Ruzga",
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"@modelcontextprotocol/sdk": "^1.8.0",
|
|
63
63
|
"@vscode/ripgrep": "^1.15.9",
|
|
64
64
|
"cross-fetch": "^4.1.0",
|
|
65
|
+
"fastest-levenshtein": "^1.0.16",
|
|
65
66
|
"glob": "^10.3.10",
|
|
66
|
-
"node-machine-id": "^1.1.12",
|
|
67
67
|
"zod": "^3.24.1",
|
|
68
68
|
"zod-to-json-schema": "^3.23.5"
|
|
69
69
|
},
|