@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.
@@ -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: os.platform() === 'win32' ? 'powershell.exe' : '/bin/sh',
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)
@@ -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
  */
@@ -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
  }
@@ -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
- const spawnOptions = {
58
- shell: shellToUse,
59
- env: {
60
- ...process.env,
61
- TERM: 'xterm-256color' // Better terminal compatibility
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
- // Spawn the process with an empty array of arguments and our options
65
- const childProcess = spawn(enhancedCommand, [], spawnOptions);
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.19";
1
+ export declare const VERSION = "0.2.21";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.2.19';
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.19",
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",