@wonderwhy-er/desktop-commander 0.2.19 → 0.2.21
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/dist/config-manager.js +9 -1
- package/dist/custom-stdio.d.ts +7 -0
- package/dist/custom-stdio.js +33 -0
- package/dist/server.js +5 -0
- package/dist/terminal-manager.js +88 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/dist/config-manager.js
CHANGED
|
@@ -101,7 +101,15 @@ class ConfigManager {
|
|
|
101
101
|
"cipher", // Encrypt/decrypt files or wipe data
|
|
102
102
|
"takeown" // Take ownership of files
|
|
103
103
|
],
|
|
104
|
-
defaultShell:
|
|
104
|
+
defaultShell: (() => {
|
|
105
|
+
if (os.platform() === 'win32') {
|
|
106
|
+
return 'powershell.exe';
|
|
107
|
+
}
|
|
108
|
+
// Use user's actual shell from environment, or fall back to /bin/sh
|
|
109
|
+
const userShell = process.env.SHELL || '/bin/sh';
|
|
110
|
+
// Return just the shell path - we'll handle login shell flag elsewhere
|
|
111
|
+
return userShell;
|
|
112
|
+
})(),
|
|
105
113
|
allowedDirectories: [],
|
|
106
114
|
telemetryEnabled: true, // Default to opt-out approach (telemetry on by default)
|
|
107
115
|
fileWriteLineLimit: 50, // Default line limit for file write operations (changed from 100)
|
package/dist/custom-stdio.d.ts
CHANGED
|
@@ -8,11 +8,18 @@ export declare class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
8
8
|
private originalStdoutWrite;
|
|
9
9
|
private isInitialized;
|
|
10
10
|
private messageBuffer;
|
|
11
|
+
private clientName;
|
|
12
|
+
private disableNotifications;
|
|
11
13
|
constructor();
|
|
12
14
|
/**
|
|
13
15
|
* Call this method after MCP initialization is complete to enable JSON-RPC notifications
|
|
14
16
|
*/
|
|
15
17
|
enableNotifications(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Configure client-specific behavior
|
|
20
|
+
* Call this BEFORE enableNotifications()
|
|
21
|
+
*/
|
|
22
|
+
configureForClient(clientName: string): void;
|
|
16
23
|
/**
|
|
17
24
|
* Check if notifications are enabled
|
|
18
25
|
*/
|
package/dist/custom-stdio.js
CHANGED
|
@@ -9,6 +9,8 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
9
9
|
super();
|
|
10
10
|
this.isInitialized = false;
|
|
11
11
|
this.messageBuffer = [];
|
|
12
|
+
this.clientName = 'unknown';
|
|
13
|
+
this.disableNotifications = false;
|
|
12
14
|
// Store original methods
|
|
13
15
|
this.originalConsole = {
|
|
14
16
|
log: console.log,
|
|
@@ -30,6 +32,15 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
30
32
|
*/
|
|
31
33
|
enableNotifications() {
|
|
32
34
|
this.isInitialized = true;
|
|
35
|
+
// Check if notifications should be disabled based on client
|
|
36
|
+
if (this.disableNotifications) {
|
|
37
|
+
// Clear buffer without sending - just log to stderr instead
|
|
38
|
+
if (this.messageBuffer.length > 0) {
|
|
39
|
+
process.stderr.write(`[INFO] ${this.messageBuffer.length} buffered messages suppressed for ${this.clientName}\n`);
|
|
40
|
+
}
|
|
41
|
+
this.messageBuffer = [];
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
33
44
|
// Send the deferred initialization notification first
|
|
34
45
|
this.sendLogNotification('info', ['Enhanced FilteredStdioServerTransport initialized']);
|
|
35
46
|
// Replay all buffered messages in chronological order
|
|
@@ -45,6 +56,20 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
45
56
|
}
|
|
46
57
|
this.sendLogNotification('info', ['JSON-RPC notifications enabled']);
|
|
47
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Configure client-specific behavior
|
|
61
|
+
* Call this BEFORE enableNotifications()
|
|
62
|
+
*/
|
|
63
|
+
configureForClient(clientName) {
|
|
64
|
+
this.clientName = clientName.toLowerCase();
|
|
65
|
+
// Detect Cline and disable notifications
|
|
66
|
+
if (this.clientName.includes('cline') ||
|
|
67
|
+
this.clientName.includes('vscode') ||
|
|
68
|
+
this.clientName === 'claude-dev') {
|
|
69
|
+
this.disableNotifications = true;
|
|
70
|
+
process.stderr.write(`[INFO] Desktop Commander: Notifications disabled for ${clientName}\n`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
48
73
|
/**
|
|
49
74
|
* Check if notifications are enabled
|
|
50
75
|
*/
|
|
@@ -155,6 +180,10 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
155
180
|
};
|
|
156
181
|
}
|
|
157
182
|
sendLogNotification(level, args) {
|
|
183
|
+
// Skip if notifications are disabled (e.g., for Cline)
|
|
184
|
+
if (this.disableNotifications) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
158
187
|
try {
|
|
159
188
|
// For data, we can send structured data or string according to MCP spec
|
|
160
189
|
let data;
|
|
@@ -206,6 +235,10 @@ export class FilteredStdioServerTransport extends StdioServerTransport {
|
|
|
206
235
|
* Public method to send log notifications from anywhere in the application
|
|
207
236
|
*/
|
|
208
237
|
sendLog(level, message, data) {
|
|
238
|
+
// Skip if notifications are disabled (e.g., for Cline)
|
|
239
|
+
if (this.disableNotifications) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
209
242
|
try {
|
|
210
243
|
const notification = {
|
|
211
244
|
jsonrpc: "2.0",
|
package/dist/server.js
CHANGED
|
@@ -70,6 +70,11 @@ server.setRequestHandler(InitializeRequestSchema, async (request) => {
|
|
|
70
70
|
name: clientInfo.name || 'unknown',
|
|
71
71
|
version: clientInfo.version || 'unknown'
|
|
72
72
|
};
|
|
73
|
+
// Configure transport for client-specific behavior
|
|
74
|
+
const transport = global.mcpTransport;
|
|
75
|
+
if (transport && typeof transport.configureForClient === 'function') {
|
|
76
|
+
transport.configureForClient(currentClient.name);
|
|
77
|
+
}
|
|
73
78
|
// Defer client connection message until after initialization
|
|
74
79
|
deferLog('info', `Client connected: ${currentClient.name} v${currentClient.version}`);
|
|
75
80
|
}
|
package/dist/terminal-manager.js
CHANGED
|
@@ -1,8 +1,63 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
2
3
|
import { DEFAULT_COMMAND_TIMEOUT } from './config.js';
|
|
3
4
|
import { configManager } from './config-manager.js';
|
|
4
5
|
import { capture } from "./utils/capture.js";
|
|
5
6
|
import { analyzeProcessState } from './utils/process-detection.js';
|
|
7
|
+
/**
|
|
8
|
+
* Get the appropriate spawn configuration for a given shell
|
|
9
|
+
* This handles login shell flags for different shell types
|
|
10
|
+
*/
|
|
11
|
+
function getShellSpawnArgs(shellPath, command) {
|
|
12
|
+
const shellName = path.basename(shellPath).toLowerCase();
|
|
13
|
+
// Unix shells with login flag support
|
|
14
|
+
if (shellName.includes('bash') || shellName.includes('zsh')) {
|
|
15
|
+
return {
|
|
16
|
+
executable: shellPath,
|
|
17
|
+
args: ['-l', '-c', command],
|
|
18
|
+
useShellOption: false
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// PowerShell Core (cross-platform, supports -Login)
|
|
22
|
+
if (shellName === 'pwsh' || shellName === 'pwsh.exe') {
|
|
23
|
+
return {
|
|
24
|
+
executable: shellPath,
|
|
25
|
+
args: ['-Login', '-Command', command],
|
|
26
|
+
useShellOption: false
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Windows PowerShell 5.1 (no login flag support)
|
|
30
|
+
if (shellName === 'powershell' || shellName === 'powershell.exe') {
|
|
31
|
+
return {
|
|
32
|
+
executable: shellPath,
|
|
33
|
+
args: ['-Command', command],
|
|
34
|
+
useShellOption: false
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// CMD
|
|
38
|
+
if (shellName === 'cmd' || shellName === 'cmd.exe') {
|
|
39
|
+
return {
|
|
40
|
+
executable: shellPath,
|
|
41
|
+
args: ['/c', command],
|
|
42
|
+
useShellOption: false
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Fish shell (uses -l for login, -c for command)
|
|
46
|
+
if (shellName.includes('fish')) {
|
|
47
|
+
return {
|
|
48
|
+
executable: shellPath,
|
|
49
|
+
args: ['-l', '-c', command],
|
|
50
|
+
useShellOption: false
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Unknown/other shells - use shell option for safety
|
|
54
|
+
// This provides a fallback for shells we don't explicitly handle
|
|
55
|
+
return {
|
|
56
|
+
executable: command,
|
|
57
|
+
args: [],
|
|
58
|
+
useShellOption: shellPath
|
|
59
|
+
};
|
|
60
|
+
}
|
|
6
61
|
export class TerminalManager {
|
|
7
62
|
constructor() {
|
|
8
63
|
this.sessions = new Map();
|
|
@@ -54,15 +109,40 @@ export class TerminalManager {
|
|
|
54
109
|
enhancedCommand = command.replace(/^ssh /, 'ssh -t ');
|
|
55
110
|
console.log(`Enhanced SSH command: ${enhancedCommand}`);
|
|
56
111
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
112
|
+
// Get the appropriate spawn configuration for the shell
|
|
113
|
+
let spawnConfig;
|
|
114
|
+
let spawnOptions;
|
|
115
|
+
if (typeof shellToUse === 'string') {
|
|
116
|
+
// Use shell-specific configuration with login flags where appropriate
|
|
117
|
+
spawnConfig = getShellSpawnArgs(shellToUse, enhancedCommand);
|
|
118
|
+
spawnOptions = {
|
|
119
|
+
env: {
|
|
120
|
+
...process.env,
|
|
121
|
+
TERM: 'xterm-256color' // Better terminal compatibility
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
// Add shell option if needed (for unknown shells)
|
|
125
|
+
if (spawnConfig.useShellOption) {
|
|
126
|
+
spawnOptions.shell = spawnConfig.useShellOption;
|
|
62
127
|
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Boolean or undefined shell - use default shell option behavior
|
|
131
|
+
spawnConfig = {
|
|
132
|
+
executable: enhancedCommand,
|
|
133
|
+
args: [],
|
|
134
|
+
useShellOption: shellToUse
|
|
135
|
+
};
|
|
136
|
+
spawnOptions = {
|
|
137
|
+
shell: shellToUse,
|
|
138
|
+
env: {
|
|
139
|
+
...process.env,
|
|
140
|
+
TERM: 'xterm-256color'
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// Spawn the process with appropriate arguments
|
|
145
|
+
const childProcess = spawn(spawnConfig.executable, spawnConfig.args, spawnOptions);
|
|
66
146
|
let output = '';
|
|
67
147
|
// Ensure childProcess.pid is defined before proceeding
|
|
68
148
|
if (!childProcess.pid) {
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.
|
|
1
|
+
export declare const VERSION = "0.2.21";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.2.
|
|
1
|
+
export const VERSION = '0.2.21';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wonderwhy-er/desktop-commander",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.21",
|
|
4
4
|
"description": "MCP server for terminal operations and file editing",
|
|
5
5
|
"mcpName": "io.github.wonderwhy-er/desktop-commander",
|
|
6
6
|
"license": "MIT",
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
"zod-to-json-schema": "^3.23.5"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
|
+
"@anthropic-ai/mcpb": "^1.2.0",
|
|
90
91
|
"@types/node": "^20.17.24",
|
|
91
92
|
"commander": "^13.1.0",
|
|
92
93
|
"nexe": "^5.0.0-beta.4",
|