@wonderwhy-er/desktop-commander 0.2.3 → 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.
Files changed (43) hide show
  1. package/README.md +25 -3
  2. package/dist/config-manager.d.ts +10 -0
  3. package/dist/config-manager.js +7 -1
  4. package/dist/handlers/edit-search-handlers.js +25 -6
  5. package/dist/handlers/terminal-handlers.d.ts +8 -4
  6. package/dist/handlers/terminal-handlers.js +16 -10
  7. package/dist/index-dxt.d.ts +2 -0
  8. package/dist/index-dxt.js +76 -0
  9. package/dist/index-with-startup-detection.d.ts +5 -0
  10. package/dist/index-with-startup-detection.js +180 -0
  11. package/dist/server.d.ts +5 -0
  12. package/dist/server.js +343 -42
  13. package/dist/terminal-manager.d.ts +7 -0
  14. package/dist/terminal-manager.js +93 -18
  15. package/dist/tools/client.d.ts +10 -0
  16. package/dist/tools/client.js +13 -0
  17. package/dist/tools/config.d.ts +1 -1
  18. package/dist/tools/config.js +21 -3
  19. package/dist/tools/edit.js +4 -3
  20. package/dist/tools/environment.d.ts +55 -0
  21. package/dist/tools/environment.js +65 -0
  22. package/dist/tools/feedback.d.ts +8 -0
  23. package/dist/tools/feedback.js +132 -0
  24. package/dist/tools/filesystem.js +152 -57
  25. package/dist/tools/improved-process-tools.js +170 -29
  26. package/dist/tools/schemas.d.ts +20 -2
  27. package/dist/tools/schemas.js +20 -2
  28. package/dist/tools/usage.d.ts +5 -0
  29. package/dist/tools/usage.js +24 -0
  30. package/dist/utils/capture.js +23 -1
  31. package/dist/utils/early-logger.d.ts +4 -0
  32. package/dist/utils/early-logger.js +35 -0
  33. package/dist/utils/mcp-logger.d.ts +30 -0
  34. package/dist/utils/mcp-logger.js +59 -0
  35. package/dist/utils/smithery-detector.d.ts +94 -0
  36. package/dist/utils/smithery-detector.js +292 -0
  37. package/dist/utils/startup-detector.d.ts +65 -0
  38. package/dist/utils/startup-detector.js +390 -0
  39. package/dist/utils/usageTracker.d.ts +85 -0
  40. package/dist/utils/usageTracker.js +280 -0
  41. package/dist/version.d.ts +1 -1
  42. package/dist/version.js +1 -1
  43. package/package.json +3 -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)
@@ -182,8 +186,9 @@ The server provides a comprehensive set of tools organized into several categori
182
186
  |----------|------|-------------|
183
187
  | **Configuration** | `get_config` | Get the complete server configuration as JSON (includes blockedCommands, defaultShell, allowedDirectories, fileReadLineLimit, fileWriteLineLimit, telemetryEnabled) |
184
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) |
185
- | **Terminal** | `execute_command` | Execute a terminal command with configurable timeout and shell selection |
186
- | | `read_output` | Read new output from a running terminal session |
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 |
187
192
  | | `force_terminate` | Force terminate a running terminal session |
188
193
  | | `list_sessions` | List all active terminal sessions |
189
194
  | | `list_processes` | List all running processes with detailed information |
@@ -199,6 +204,23 @@ The server provides a comprehensive set of tools organized into several categori
199
204
  | | `get_file_info` | Retrieve detailed metadata about a file or directory |
200
205
  | **Text Editing** | `edit_block` | Apply targeted text replacements with enhanced prompting for smaller edits (includes character-level diff feedback) |
201
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
+
202
224
  ### Tool Usage Examples
203
225
 
204
226
  Search/Replace Block Format:
@@ -615,4 +637,4 @@ For complete details about data collection, please see our [Privacy Policy](PRIV
615
637
 
616
638
  ## License
617
639
 
618
- MIT
640
+ MIT
@@ -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 {};
@@ -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' : 'bash',
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: parsed.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
- results.forEach(result => {
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 += `\n${result.file}:\n`;
79
+ formattedResults += newFileHeader;
62
80
  currentFile = result.file;
63
81
  }
64
- formattedResults += ` ${result.line}: ${result.match}\n`;
65
- });
82
+ formattedResults += newLine;
83
+ resultsProcessed++;
84
+ }
66
85
  return {
67
86
  content: [{ type: "text", text: formattedResults.trim() }],
68
87
  };
@@ -1,12 +1,16 @@
1
1
  import { ServerResult } from '../types.js';
2
2
  /**
3
- * Handle execute_command command
3
+ * Handle start_process command (improved execute_command)
4
4
  */
5
- export declare function handleExecuteCommand(args: unknown): Promise<ServerResult>;
5
+ export declare function handleStartProcess(args: unknown): Promise<ServerResult>;
6
6
  /**
7
- * Handle read_output command
7
+ * Handle read_process_output command (improved read_output)
8
8
  */
9
- export declare function handleReadOutput(args: unknown): Promise<ServerResult>;
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 { executeCommand, readOutput, forceTerminate, listSessions } from '../tools/execute.js';
2
- import { ExecuteCommandArgsSchema, ReadOutputArgsSchema, ForceTerminateArgsSchema } from '../tools/schemas.js';
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 execute_command command
4
+ * Handle start_process command (improved execute_command)
5
5
  */
6
- export async function handleExecuteCommand(args) {
7
- const parsed = ExecuteCommandArgsSchema.parse(args);
8
- return executeCommand(parsed);
6
+ export async function handleStartProcess(args) {
7
+ const parsed = StartProcessArgsSchema.parse(args);
8
+ return startProcess(parsed);
9
9
  }
10
10
  /**
11
- * Handle read_output command
11
+ * Handle read_process_output command (improved read_output)
12
12
  */
13
- export async function handleReadOutput(args) {
14
- const parsed = ReadOutputArgsSchema.parse(args);
15
- return readOutput(parsed);
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,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -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,5 @@
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
+ export {};
@@ -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
+ });
package/dist/server.d.ts CHANGED
@@ -22,3 +22,8 @@ export declare const server: Server<{
22
22
  [x: string]: unknown;
23
23
  } | undefined;
24
24
  }>;
25
+ declare let currentClient: {
26
+ name: string;
27
+ version: string;
28
+ };
29
+ export { currentClient };