@wonderwhy-er/desktop-commander 0.2.2 → 0.2.4
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 +27 -4
- package/dist/config-manager.d.ts +10 -0
- package/dist/config-manager.js +7 -1
- package/dist/handlers/edit-search-handlers.js +25 -6
- package/dist/handlers/filesystem-handlers.js +2 -4
- package/dist/handlers/terminal-handlers.d.ts +8 -4
- package/dist/handlers/terminal-handlers.js +16 -10
- package/dist/index-dxt.d.ts +2 -0
- package/dist/index-dxt.js +76 -0
- package/dist/index-with-startup-detection.d.ts +5 -0
- package/dist/index-with-startup-detection.js +180 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +381 -65
- package/dist/terminal-manager.d.ts +7 -0
- package/dist/terminal-manager.js +93 -18
- package/dist/tools/client.d.ts +10 -0
- package/dist/tools/client.js +13 -0
- package/dist/tools/config.d.ts +1 -1
- package/dist/tools/config.js +21 -3
- package/dist/tools/edit.js +4 -3
- package/dist/tools/environment.d.ts +55 -0
- package/dist/tools/environment.js +65 -0
- package/dist/tools/feedback.d.ts +8 -0
- package/dist/tools/feedback.js +132 -0
- package/dist/tools/filesystem.d.ts +10 -0
- package/dist/tools/filesystem.js +410 -60
- package/dist/tools/improved-process-tools.d.ts +24 -0
- package/dist/tools/improved-process-tools.js +453 -0
- package/dist/tools/schemas.d.ts +20 -2
- package/dist/tools/schemas.js +20 -3
- package/dist/tools/usage.d.ts +5 -0
- package/dist/tools/usage.js +24 -0
- package/dist/utils/capture.d.ts +2 -0
- package/dist/utils/capture.js +40 -9
- package/dist/utils/early-logger.d.ts +4 -0
- package/dist/utils/early-logger.js +35 -0
- package/dist/utils/mcp-logger.d.ts +30 -0
- package/dist/utils/mcp-logger.js +59 -0
- package/dist/utils/process-detection.d.ts +23 -0
- package/dist/utils/process-detection.js +150 -0
- package/dist/utils/smithery-detector.d.ts +94 -0
- package/dist/utils/smithery-detector.js +292 -0
- package/dist/utils/startup-detector.d.ts +65 -0
- package/dist/utils/startup-detector.js +390 -0
- package/dist/utils/system-info.d.ts +30 -0
- package/dist/utils/system-info.js +146 -0
- package/dist/utils/usageTracker.d.ts +85 -0
- package/dist/utils/usageTracker.js +280 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -38,6 +38,10 @@ Execute long-running terminal commands on your computer and manage processes thr
|
|
|
38
38
|
|
|
39
39
|
## Features
|
|
40
40
|
|
|
41
|
+
- **Enhanced terminal commands with interactive process control**
|
|
42
|
+
- **Execute code in memory (Python, Node.js, R) without saving files**
|
|
43
|
+
- **Instant data analysis - just ask to analyze CSV/JSON files**
|
|
44
|
+
- **Interact with running processes (SSH, databases, development servers)**
|
|
41
45
|
- Execute terminal commands with output streaming
|
|
42
46
|
- Command timeout and background execution support
|
|
43
47
|
- Process management (list and kill processes)
|
|
@@ -52,6 +56,7 @@ Execute long-running terminal commands on your computer and manage processes thr
|
|
|
52
56
|
- Move files/directories
|
|
53
57
|
- Search files
|
|
54
58
|
- Get file metadata
|
|
59
|
+
- **Negative offset file reading**: Read from end of files using negative offset values (like Unix tail)
|
|
55
60
|
- Code editing capabilities:
|
|
56
61
|
- Surgical text replacements for small changes
|
|
57
62
|
- Full file rewrites for major changes
|
|
@@ -181,13 +186,14 @@ The server provides a comprehensive set of tools organized into several categori
|
|
|
181
186
|
|----------|------|-------------|
|
|
182
187
|
| **Configuration** | `get_config` | Get the complete server configuration as JSON (includes blockedCommands, defaultShell, allowedDirectories, fileReadLineLimit, fileWriteLineLimit, telemetryEnabled) |
|
|
183
188
|
| | `set_config_value` | Set a specific configuration value by key. Available settings: <br>• `blockedCommands`: Array of shell commands that cannot be executed<br>• `defaultShell`: Shell to use for commands (e.g., bash, zsh, powershell)<br>• `allowedDirectories`: Array of filesystem paths the server can access for file operations (⚠️ terminal commands can still access files outside these directories)<br>• `fileReadLineLimit`: Maximum lines to read at once (default: 1000)<br>• `fileWriteLineLimit`: Maximum lines to write at once (default: 50)<br>• `telemetryEnabled`: Enable/disable telemetry (boolean) |
|
|
184
|
-
| **Terminal** | `
|
|
185
|
-
| | `
|
|
189
|
+
| **Terminal** | `start_process` | Start programs with smart detection of when they're ready for input |
|
|
190
|
+
| | `interact_with_process` | Send commands to running programs and get responses |
|
|
191
|
+
| | `read_process_output` | Read output from running processes |
|
|
186
192
|
| | `force_terminate` | Force terminate a running terminal session |
|
|
187
193
|
| | `list_sessions` | List all active terminal sessions |
|
|
188
194
|
| | `list_processes` | List all running processes with detailed information |
|
|
189
195
|
| | `kill_process` | Terminate a running process by PID |
|
|
190
|
-
| **Filesystem** | `read_file` | Read contents from local filesystem or URLs with line-based pagination (supports offset and length parameters) |
|
|
196
|
+
| **Filesystem** | `read_file` | Read contents from local filesystem or URLs with line-based pagination (supports positive/negative offset and length parameters) |
|
|
191
197
|
| | `read_multiple_files` | Read multiple files simultaneously |
|
|
192
198
|
| | `write_file` | Write file contents with options for rewrite or append mode (uses configurable line limits) |
|
|
193
199
|
| | `create_directory` | Create a new directory or ensure it exists |
|
|
@@ -198,6 +204,23 @@ The server provides a comprehensive set of tools organized into several categori
|
|
|
198
204
|
| | `get_file_info` | Retrieve detailed metadata about a file or directory |
|
|
199
205
|
| **Text Editing** | `edit_block` | Apply targeted text replacements with enhanced prompting for smaller edits (includes character-level diff feedback) |
|
|
200
206
|
|
|
207
|
+
### Quick Examples
|
|
208
|
+
|
|
209
|
+
**Data Analysis:**
|
|
210
|
+
```
|
|
211
|
+
"Analyze sales.csv and show top customers" → Claude runs Python code in memory
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Remote Access:**
|
|
215
|
+
```
|
|
216
|
+
"SSH to my server and check disk space" → Claude maintains SSH session
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Development:**
|
|
220
|
+
```
|
|
221
|
+
"Start Node.js and test this API" → Claude runs interactive Node session
|
|
222
|
+
```
|
|
223
|
+
|
|
201
224
|
### Tool Usage Examples
|
|
202
225
|
|
|
203
226
|
Search/Replace Block Format:
|
|
@@ -614,4 +637,4 @@ For complete details about data collection, please see our [Privacy Policy](PRIV
|
|
|
614
637
|
|
|
615
638
|
## License
|
|
616
639
|
|
|
617
|
-
MIT
|
|
640
|
+
MIT
|
package/dist/config-manager.d.ts
CHANGED
|
@@ -5,8 +5,14 @@ export interface ServerConfig {
|
|
|
5
5
|
telemetryEnabled?: boolean;
|
|
6
6
|
fileWriteLineLimit?: number;
|
|
7
7
|
fileReadLineLimit?: number;
|
|
8
|
+
clientId?: string;
|
|
9
|
+
currentClient?: ClientInfo;
|
|
8
10
|
[key: string]: any;
|
|
9
11
|
}
|
|
12
|
+
export interface ClientInfo {
|
|
13
|
+
name: string;
|
|
14
|
+
version: string;
|
|
15
|
+
}
|
|
10
16
|
/**
|
|
11
17
|
* Singleton config manager for the server
|
|
12
18
|
*/
|
|
@@ -51,6 +57,10 @@ declare class ConfigManager {
|
|
|
51
57
|
* Reset configuration to defaults
|
|
52
58
|
*/
|
|
53
59
|
resetConfig(): Promise<ServerConfig>;
|
|
60
|
+
/**
|
|
61
|
+
* Get current client information for analytics
|
|
62
|
+
*/
|
|
63
|
+
getCurrentClientInfo(): ClientInfo | null;
|
|
54
64
|
}
|
|
55
65
|
export declare const configManager: ConfigManager;
|
|
56
66
|
export {};
|
package/dist/config-manager.js
CHANGED
|
@@ -101,7 +101,7 @@ 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' : '
|
|
104
|
+
defaultShell: os.platform() === 'win32' ? 'powershell.exe' : '/bin/sh',
|
|
105
105
|
allowedDirectories: [],
|
|
106
106
|
telemetryEnabled: true, // Default to opt-out approach (telemetry on by default)
|
|
107
107
|
fileWriteLineLimit: 50, // Default line limit for file write operations (changed from 100)
|
|
@@ -176,6 +176,12 @@ class ConfigManager {
|
|
|
176
176
|
await this.saveConfig();
|
|
177
177
|
return { ...this.config };
|
|
178
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Get current client information for analytics
|
|
181
|
+
*/
|
|
182
|
+
getCurrentClientInfo() {
|
|
183
|
+
return this.config.currentClient || null;
|
|
184
|
+
}
|
|
179
185
|
}
|
|
180
186
|
// Export singleton instance
|
|
181
187
|
export const configManager = new ConfigManager();
|
|
@@ -14,6 +14,8 @@ export { handleEditBlock };
|
|
|
14
14
|
export async function handleSearchCode(args) {
|
|
15
15
|
const parsed = SearchCodeArgsSchema.parse(args);
|
|
16
16
|
const timeoutMs = parsed.timeoutMs || 30000; // 30 seconds default
|
|
17
|
+
// Limit maxResults to prevent overwhelming responses
|
|
18
|
+
const safeMaxResults = parsed.maxResults ? Math.min(parsed.maxResults, 5000) : 2000; // Default to 2000 instead of 1000
|
|
17
19
|
// Apply timeout at the handler level
|
|
18
20
|
const searchOperation = async () => {
|
|
19
21
|
return await searchTextInFiles({
|
|
@@ -21,7 +23,7 @@ export async function handleSearchCode(args) {
|
|
|
21
23
|
pattern: parsed.pattern,
|
|
22
24
|
filePattern: parsed.filePattern,
|
|
23
25
|
ignoreCase: parsed.ignoreCase,
|
|
24
|
-
maxResults:
|
|
26
|
+
maxResults: safeMaxResults,
|
|
25
27
|
includeHidden: parsed.includeHidden,
|
|
26
28
|
contextLines: parsed.contextLines,
|
|
27
29
|
// Don't pass timeoutMs down to the implementation
|
|
@@ -53,16 +55,33 @@ export async function handleSearchCode(args) {
|
|
|
53
55
|
content: [{ type: "text", text: "No matches found" }],
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
|
-
// Format the results in a VS Code-like format
|
|
58
|
+
// Format the results in a VS Code-like format with early truncation
|
|
57
59
|
let currentFile = "";
|
|
58
60
|
let formattedResults = "";
|
|
59
|
-
|
|
61
|
+
const MAX_RESPONSE_SIZE = 900000; // 900KB limit - well below the 1MB API limit
|
|
62
|
+
let resultsProcessed = 0;
|
|
63
|
+
let totalResults = results.length;
|
|
64
|
+
for (const result of results) {
|
|
65
|
+
// Check if adding this result would exceed our limit
|
|
66
|
+
const newFileHeader = result.file !== currentFile ? `\n${result.file}:\n` : '';
|
|
67
|
+
const newLine = ` ${result.line}: ${result.match}\n`;
|
|
68
|
+
const potentialAddition = newFileHeader + newLine;
|
|
69
|
+
// If adding this would exceed the limit, truncate here
|
|
70
|
+
if (formattedResults.length + potentialAddition.length > MAX_RESPONSE_SIZE) {
|
|
71
|
+
const remainingResults = totalResults - resultsProcessed;
|
|
72
|
+
const avgResultLength = formattedResults.length / Math.max(resultsProcessed, 1);
|
|
73
|
+
const estimatedRemainingChars = remainingResults * avgResultLength;
|
|
74
|
+
const truncationMessage = `\n\n[Results truncated - ${remainingResults} more results available (approximately ${Math.round(estimatedRemainingChars).toLocaleString()} more characters). Try refining your search pattern or using a more specific file pattern to get fewer results.]`;
|
|
75
|
+
formattedResults += truncationMessage;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
60
78
|
if (result.file !== currentFile) {
|
|
61
|
-
formattedResults +=
|
|
79
|
+
formattedResults += newFileHeader;
|
|
62
80
|
currentFile = result.file;
|
|
63
81
|
}
|
|
64
|
-
formattedResults +=
|
|
65
|
-
|
|
82
|
+
formattedResults += newLine;
|
|
83
|
+
resultsProcessed++;
|
|
84
|
+
}
|
|
66
85
|
return {
|
|
67
86
|
content: [{ type: "text", text: formattedResults.trim() }],
|
|
68
87
|
};
|
|
@@ -125,11 +125,9 @@ export async function handleWriteFile(args) {
|
|
|
125
125
|
const lineCount = lines.length;
|
|
126
126
|
let errorMessage = "";
|
|
127
127
|
if (lineCount > MAX_LINES) {
|
|
128
|
-
errorMessage =
|
|
128
|
+
errorMessage = `✅ File written successfully! (${lineCount} lines)
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
1. First chunk: write_file(path, firstChunk, {mode: 'rewrite'})
|
|
132
|
-
2. Additional chunks: write_file(path, nextChunk, {mode: 'append'})`;
|
|
130
|
+
💡 Performance tip: For optimal speed, consider chunking files into ≤30 line pieces in future operations.`;
|
|
133
131
|
}
|
|
134
132
|
// Pass the mode parameter to writeFile
|
|
135
133
|
await writeFile(parsed.path, parsed.content, parsed.mode);
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { ServerResult } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Handle
|
|
3
|
+
* Handle start_process command (improved execute_command)
|
|
4
4
|
*/
|
|
5
|
-
export declare function
|
|
5
|
+
export declare function handleStartProcess(args: unknown): Promise<ServerResult>;
|
|
6
6
|
/**
|
|
7
|
-
* Handle
|
|
7
|
+
* Handle read_process_output command (improved read_output)
|
|
8
8
|
*/
|
|
9
|
-
export declare function
|
|
9
|
+
export declare function handleReadProcessOutput(args: unknown): Promise<ServerResult>;
|
|
10
|
+
/**
|
|
11
|
+
* Handle interact_with_process command (improved send_input)
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleInteractWithProcess(args: unknown): Promise<ServerResult>;
|
|
10
14
|
/**
|
|
11
15
|
* Handle force_terminate command
|
|
12
16
|
*/
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { startProcess, readProcessOutput, interactWithProcess, forceTerminate, listSessions } from '../tools/improved-process-tools.js';
|
|
2
|
+
import { StartProcessArgsSchema, ReadProcessOutputArgsSchema, ForceTerminateArgsSchema } from '../tools/schemas.js';
|
|
3
3
|
/**
|
|
4
|
-
* Handle
|
|
4
|
+
* Handle start_process command (improved execute_command)
|
|
5
5
|
*/
|
|
6
|
-
export async function
|
|
7
|
-
const parsed =
|
|
8
|
-
return
|
|
6
|
+
export async function handleStartProcess(args) {
|
|
7
|
+
const parsed = StartProcessArgsSchema.parse(args);
|
|
8
|
+
return startProcess(parsed);
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Handle
|
|
11
|
+
* Handle read_process_output command (improved read_output)
|
|
12
12
|
*/
|
|
13
|
-
export async function
|
|
14
|
-
const parsed =
|
|
15
|
-
return
|
|
13
|
+
export async function handleReadProcessOutput(args) {
|
|
14
|
+
const parsed = ReadProcessOutputArgsSchema.parse(args);
|
|
15
|
+
return readProcessOutput(parsed);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Handle interact_with_process command (improved send_input)
|
|
19
|
+
*/
|
|
20
|
+
export async function handleInteractWithProcess(args) {
|
|
21
|
+
return interactWithProcess(args);
|
|
16
22
|
}
|
|
17
23
|
/**
|
|
18
24
|
* Handle force_terminate command
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Add immediate logging before any imports
|
|
3
|
+
console.error("[DXT] === ENTRY POINT START ===");
|
|
4
|
+
console.error(`[DXT] Node version: ${process.version}`);
|
|
5
|
+
console.error(`[DXT] Platform: ${process.platform}`);
|
|
6
|
+
console.error(`[DXT] Working directory: ${process.cwd()}`);
|
|
7
|
+
console.error(`[DXT] __dirname: ${__dirname}`);
|
|
8
|
+
console.error(`[DXT] Args: ${JSON.stringify(process.argv)}`);
|
|
9
|
+
// Add error handlers immediately
|
|
10
|
+
process.on('uncaughtException', (error) => {
|
|
11
|
+
console.error(`[DXT] UNCAUGHT EXCEPTION: ${error.message}`);
|
|
12
|
+
console.error(`[DXT] Stack: ${error.stack}`);
|
|
13
|
+
});
|
|
14
|
+
process.on('unhandledRejection', (reason) => {
|
|
15
|
+
console.error(`[DXT] UNHANDLED REJECTION: ${String(reason)}`);
|
|
16
|
+
});
|
|
17
|
+
process.on('exit', (code) => {
|
|
18
|
+
console.error(`[DXT] PROCESS EXITING with code: ${code}`);
|
|
19
|
+
});
|
|
20
|
+
console.error("[DXT] About to import modules...");
|
|
21
|
+
// Simplified entry point for DXT that avoids configuration loading issues
|
|
22
|
+
import { FilteredStdioServerTransport } from './custom-stdio.js';
|
|
23
|
+
console.error("[DXT] FilteredStdioServerTransport imported");
|
|
24
|
+
import { server } from './server.js';
|
|
25
|
+
console.error("[DXT] Server imported");
|
|
26
|
+
async function runDXTServer() {
|
|
27
|
+
try {
|
|
28
|
+
console.error("[DXT] === runDXTServer() START ===");
|
|
29
|
+
console.error("=== DXT DEBUG START ===");
|
|
30
|
+
console.error(`Node version: ${process.version}`);
|
|
31
|
+
console.error(`Platform: ${process.platform}`);
|
|
32
|
+
console.error(`Working directory: ${process.cwd()}`);
|
|
33
|
+
console.error(`__dirname: ${__dirname}`);
|
|
34
|
+
console.error(`Args: ${JSON.stringify(process.argv)}`);
|
|
35
|
+
console.error("=== DXT DEBUG END ===");
|
|
36
|
+
console.error("[DXT] About to create transport...");
|
|
37
|
+
// Create transport
|
|
38
|
+
const transport = new FilteredStdioServerTransport();
|
|
39
|
+
console.error("[DXT] Transport created successfully");
|
|
40
|
+
// Send structured debug info
|
|
41
|
+
transport.sendLog("info", "DXT Server Starting", {
|
|
42
|
+
nodeVersion: process.version,
|
|
43
|
+
platform: process.platform,
|
|
44
|
+
cwd: process.cwd(),
|
|
45
|
+
dirname: __dirname,
|
|
46
|
+
argv: process.argv
|
|
47
|
+
});
|
|
48
|
+
console.error("[DXT] Debug info sent via transport");
|
|
49
|
+
// Connect server
|
|
50
|
+
console.error("[DXT] About to connect server...");
|
|
51
|
+
console.error("Connecting MCP server...");
|
|
52
|
+
await server.connect(transport);
|
|
53
|
+
console.error("[DXT] Server connected successfully!");
|
|
54
|
+
console.error("MCP server connected successfully");
|
|
55
|
+
transport.sendLog("info", "MCP server connected successfully in DXT mode");
|
|
56
|
+
console.error("[DXT] === runDXTServer() END ===");
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
60
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
61
|
+
console.error(`[DXT] FATAL ERROR in runDXTServer: ${errorMessage}`);
|
|
62
|
+
if (errorStack) {
|
|
63
|
+
console.error(`[DXT] Stack: ${errorStack}`);
|
|
64
|
+
}
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
console.error("[DXT] About to call runDXTServer...");
|
|
69
|
+
// Run the server
|
|
70
|
+
runDXTServer().catch((error) => {
|
|
71
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
72
|
+
console.error(`[DXT] Failed to start in catch block: ${errorMessage}`);
|
|
73
|
+
console.error(`[DXT] Failed to start: ${errorMessage}`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
76
|
+
console.error("[DXT] === ENTRY POINT END ===");
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example integration of startup detection in your server.ts file
|
|
3
|
+
* This shows how to add startup detection to your existing server
|
|
4
|
+
*/
|
|
5
|
+
import { FilteredStdioServerTransport } from './custom-stdio.js';
|
|
6
|
+
import { server } from './server.js';
|
|
7
|
+
import { configManager } from './config-manager.js';
|
|
8
|
+
import { getStartupInfo, getStartupMethod, isProduction, isDevelopment, isDocker, isCi } from './utils/startup-detector.js';
|
|
9
|
+
import { capture } from './utils/capture.js';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
12
|
+
import { platform } from 'os';
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
const isWindows = platform() === 'win32';
|
|
16
|
+
function createFileURL(filePath) {
|
|
17
|
+
if (isWindows) {
|
|
18
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
19
|
+
if (normalizedPath.startsWith('/')) {
|
|
20
|
+
return new URL(`file://${normalizedPath}`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return new URL(`file:///${normalizedPath}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return pathToFileURL(filePath);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function runSetup() {
|
|
31
|
+
try {
|
|
32
|
+
const setupScriptPath = join(__dirname, 'setup-claude-server.js');
|
|
33
|
+
const setupScriptUrl = createFileURL(setupScriptPath);
|
|
34
|
+
const { default: setupModule } = await import(setupScriptUrl.href);
|
|
35
|
+
if (typeof setupModule === 'function') {
|
|
36
|
+
await setupModule();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error('Error running setup:', error);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function runServer() {
|
|
45
|
+
try {
|
|
46
|
+
// Check if first argument is "setup"
|
|
47
|
+
if (process.argv[2] === 'setup') {
|
|
48
|
+
await runSetup();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// ============ NEW: Startup Detection Integration ============
|
|
52
|
+
const startupInfo = getStartupInfo();
|
|
53
|
+
const startupMethod = getStartupMethod();
|
|
54
|
+
// Log startup information
|
|
55
|
+
console.error(`🚀 Desktop Commander starting via: ${startupMethod}`);
|
|
56
|
+
console.error(`📍 Environment: ${startupInfo.environment}`);
|
|
57
|
+
console.error(`🔍 Detection confidence: ${startupInfo.confidence}%`);
|
|
58
|
+
if (startupInfo.details.evidence.length > 0) {
|
|
59
|
+
console.error(`📝 Evidence: ${startupInfo.details.evidence.join(', ')}`);
|
|
60
|
+
}
|
|
61
|
+
// Conditional behavior based on startup method
|
|
62
|
+
if (isProduction()) {
|
|
63
|
+
console.error('🏭 Production mode: Enhanced error handling enabled');
|
|
64
|
+
// Enable production-specific features
|
|
65
|
+
process.on('uncaughtException', (error) => {
|
|
66
|
+
console.error('[PRODUCTION] Uncaught exception:', error);
|
|
67
|
+
// More robust error handling in production
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else if (isDevelopment()) {
|
|
72
|
+
console.error('🛠️ Development mode: Debug features enabled');
|
|
73
|
+
// Enable development-specific features
|
|
74
|
+
}
|
|
75
|
+
if (isDocker()) {
|
|
76
|
+
console.error('🐳 Docker environment detected');
|
|
77
|
+
// Docker-specific configuration
|
|
78
|
+
}
|
|
79
|
+
if (isCi()) {
|
|
80
|
+
console.error('🤖 CI/CD environment detected');
|
|
81
|
+
// CI-specific behavior (minimal logging, etc.)
|
|
82
|
+
}
|
|
83
|
+
// Log startup analytics
|
|
84
|
+
capture('desktop_commander_startup', {
|
|
85
|
+
startup_method: startupInfo.method,
|
|
86
|
+
environment: startupInfo.environment,
|
|
87
|
+
confidence: startupInfo.confidence,
|
|
88
|
+
npm_script: startupInfo.details.npmScript || null,
|
|
89
|
+
ci_platform: startupInfo.details.ciPlatform || null,
|
|
90
|
+
docker_container: startupInfo.details.dockerContainer || false
|
|
91
|
+
});
|
|
92
|
+
// Adjust logging verbosity based on environment
|
|
93
|
+
const logLevel = isProduction() ? 'error' :
|
|
94
|
+
isDevelopment() ? 'debug' :
|
|
95
|
+
isCi() ? 'warn' : 'info';
|
|
96
|
+
console.error(`📊 Log level set to: ${logLevel}`);
|
|
97
|
+
// ========================================================
|
|
98
|
+
const transport = new FilteredStdioServerTransport();
|
|
99
|
+
// Enhanced error handling with startup context
|
|
100
|
+
process.on('uncaughtException', async (error) => {
|
|
101
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
102
|
+
if (errorMessage.includes('JSON') && errorMessage.includes('Unexpected token')) {
|
|
103
|
+
process.stderr.write(`[desktop-commander] JSON parsing error: ${errorMessage}\n`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Include startup context in error capture
|
|
107
|
+
capture('run_server_uncaught_exception', {
|
|
108
|
+
error: errorMessage,
|
|
109
|
+
startup_method: startupInfo.method,
|
|
110
|
+
environment: startupInfo.environment
|
|
111
|
+
});
|
|
112
|
+
process.stderr.write(`[desktop-commander] Uncaught exception: ${errorMessage}\n`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
});
|
|
115
|
+
process.on('unhandledRejection', async (reason) => {
|
|
116
|
+
const errorMessage = reason instanceof Error ? reason.message : String(reason);
|
|
117
|
+
if (errorMessage.includes('JSON') && errorMessage.includes('Unexpected token')) {
|
|
118
|
+
process.stderr.write(`[desktop-commander] JSON parsing rejection: ${errorMessage}\n`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
capture('run_server_unhandled_rejection', {
|
|
122
|
+
error: errorMessage,
|
|
123
|
+
startup_method: startupInfo.method,
|
|
124
|
+
environment: startupInfo.environment
|
|
125
|
+
});
|
|
126
|
+
process.stderr.write(`[desktop-commander] Unhandled rejection: ${errorMessage}\n`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
});
|
|
129
|
+
capture('run_server_start', {
|
|
130
|
+
startup_method: startupInfo.method,
|
|
131
|
+
environment: startupInfo.environment
|
|
132
|
+
});
|
|
133
|
+
try {
|
|
134
|
+
console.error("Loading configuration...");
|
|
135
|
+
await configManager.loadConfig();
|
|
136
|
+
console.error("Configuration loaded successfully");
|
|
137
|
+
}
|
|
138
|
+
catch (configError) {
|
|
139
|
+
console.error(`Failed to load configuration: ${configError instanceof Error ? configError.message : String(configError)}`);
|
|
140
|
+
console.error(configError instanceof Error && configError.stack ? configError.stack : 'No stack trace available');
|
|
141
|
+
console.error("Continuing with in-memory configuration only");
|
|
142
|
+
}
|
|
143
|
+
console.error("Connecting server...");
|
|
144
|
+
await server.connect(transport);
|
|
145
|
+
console.error("✅ Server connected successfully");
|
|
146
|
+
console.error(`🎯 Running in ${startupInfo.environment} environment via ${startupMethod}`);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
150
|
+
console.error(`FATAL ERROR: ${errorMessage}`);
|
|
151
|
+
console.error(error instanceof Error && error.stack ? error.stack : 'No stack trace available');
|
|
152
|
+
process.stderr.write(JSON.stringify({
|
|
153
|
+
type: 'error',
|
|
154
|
+
timestamp: new Date().toISOString(),
|
|
155
|
+
message: `Failed to start server: ${errorMessage}`,
|
|
156
|
+
startup_method: getStartupInfo().method
|
|
157
|
+
}) + '\n');
|
|
158
|
+
capture('run_server_failed_start_error', {
|
|
159
|
+
error: errorMessage,
|
|
160
|
+
startup_method: getStartupInfo().method
|
|
161
|
+
});
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
runServer().catch(async (error) => {
|
|
166
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
167
|
+
console.error(`RUNTIME ERROR: ${errorMessage}`);
|
|
168
|
+
console.error(error instanceof Error && error.stack ? error.stack : 'No stack trace available');
|
|
169
|
+
process.stderr.write(JSON.stringify({
|
|
170
|
+
type: 'error',
|
|
171
|
+
timestamp: new Date().toISOString(),
|
|
172
|
+
message: `Fatal error running server: ${errorMessage}`,
|
|
173
|
+
startup_method: getStartupInfo().method
|
|
174
|
+
}) + '\n');
|
|
175
|
+
capture('run_server_fatal_error', {
|
|
176
|
+
error: errorMessage,
|
|
177
|
+
startup_method: getStartupInfo().method
|
|
178
|
+
});
|
|
179
|
+
process.exit(1);
|
|
180
|
+
});
|