starmux 0.12.0 → 0.13.0

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 (93) hide show
  1. package/dist/src/cli/mac-mcp-gateway.js +4 -3
  2. package/dist/src/cli/mac-mcp-gateway.js.map +1 -1
  3. package/dist/src/cli/starmux.js +1 -1
  4. package/dist/src/cli/starmux.js.map +1 -1
  5. package/dist/src/runtime-paths.js +3 -3
  6. package/dist/src/runtime-paths.js.map +1 -1
  7. package/dist/vendor/desktop-commander/LICENSE +21 -0
  8. package/dist/vendor/desktop-commander/dist/bootstrap.js +22 -0
  9. package/dist/vendor/desktop-commander/dist/command-manager.js +246 -0
  10. package/dist/vendor/desktop-commander/dist/config-field-definitions.js +37 -0
  11. package/dist/vendor/desktop-commander/dist/config-manager.js +634 -0
  12. package/dist/vendor/desktop-commander/dist/config-recovery.js +81 -0
  13. package/dist/vendor/desktop-commander/dist/config.js +19 -0
  14. package/dist/vendor/desktop-commander/dist/custom-stdio.js +358 -0
  15. package/dist/vendor/desktop-commander/dist/error-handlers.js +15 -0
  16. package/dist/vendor/desktop-commander/dist/handlers/edit-search-handlers.js +6 -0
  17. package/dist/vendor/desktop-commander/dist/handlers/filesystem-handlers.js +450 -0
  18. package/dist/vendor/desktop-commander/dist/handlers/history-handlers.js +67 -0
  19. package/dist/vendor/desktop-commander/dist/handlers/index.js +7 -0
  20. package/dist/vendor/desktop-commander/dist/handlers/process-handlers.js +15 -0
  21. package/dist/vendor/desktop-commander/dist/handlers/search-answers.js +172 -0
  22. package/dist/vendor/desktop-commander/dist/handlers/search-handlers.js +136 -0
  23. package/dist/vendor/desktop-commander/dist/handlers/terminal-handlers.js +35 -0
  24. package/dist/vendor/desktop-commander/dist/index.js +88 -0
  25. package/dist/vendor/desktop-commander/dist/search-manager.js +1262 -0
  26. package/dist/vendor/desktop-commander/dist/server.js +1414 -0
  27. package/dist/vendor/desktop-commander/dist/terminal-manager.js +757 -0
  28. package/dist/vendor/desktop-commander/dist/tools/config.js +211 -0
  29. package/dist/vendor/desktop-commander/dist/tools/edit.js +455 -0
  30. package/dist/vendor/desktop-commander/dist/tools/feedback.js +10 -0
  31. package/dist/vendor/desktop-commander/dist/tools/filesystem.js +1047 -0
  32. package/dist/vendor/desktop-commander/dist/tools/fuzzySearch.js +74 -0
  33. package/dist/vendor/desktop-commander/dist/tools/fuzzySearchCore.js +125 -0
  34. package/dist/vendor/desktop-commander/dist/tools/improved-process-tools.js +726 -0
  35. package/dist/vendor/desktop-commander/dist/tools/mime-types.js +28 -0
  36. package/dist/vendor/desktop-commander/dist/tools/pdf/extract-images.js +131 -0
  37. package/dist/vendor/desktop-commander/dist/tools/pdf/index.js +4 -0
  38. package/dist/vendor/desktop-commander/dist/tools/pdf/lib/pdf2md.js +78 -0
  39. package/dist/vendor/desktop-commander/dist/tools/pdf/manipulations.js +112 -0
  40. package/dist/vendor/desktop-commander/dist/tools/pdf/markdown.js +30 -0
  41. package/dist/vendor/desktop-commander/dist/tools/pdf/utils.js +45 -0
  42. package/dist/vendor/desktop-commander/dist/tools/process.js +90 -0
  43. package/dist/vendor/desktop-commander/dist/tools/prompts.js +259 -0
  44. package/dist/vendor/desktop-commander/dist/tools/schemas.js +242 -0
  45. package/dist/vendor/desktop-commander/dist/tools/usage.js +24 -0
  46. package/dist/vendor/desktop-commander/dist/types.js +1 -0
  47. package/dist/vendor/desktop-commander/dist/ui/config-editor/config-editor-runtime.js +150 -0
  48. package/dist/vendor/desktop-commander/dist/ui/config-editor/index.html +13 -0
  49. package/dist/vendor/desktop-commander/dist/ui/config-editor/styles.css +587 -0
  50. package/dist/vendor/desktop-commander/dist/ui/contracts.js +57 -0
  51. package/dist/vendor/desktop-commander/dist/ui/file-preview/index.html +16 -0
  52. package/dist/vendor/desktop-commander/dist/ui/file-preview/preview-runtime.js +471 -0
  53. package/dist/vendor/desktop-commander/dist/ui/file-preview/shared/preview-file-types.js +59 -0
  54. package/dist/vendor/desktop-commander/dist/ui/file-preview/styles.css +1631 -0
  55. package/dist/vendor/desktop-commander/dist/ui/resources.js +93 -0
  56. package/dist/vendor/desktop-commander/dist/utils/ab-test.js +122 -0
  57. package/dist/vendor/desktop-commander/dist/utils/atomic-write.js +80 -0
  58. package/dist/vendor/desktop-commander/dist/utils/capture.js +40 -0
  59. package/dist/vendor/desktop-commander/dist/utils/dockerPrompt.js +9 -0
  60. package/dist/vendor/desktop-commander/dist/utils/exit-process.js +31 -0
  61. package/dist/vendor/desktop-commander/dist/utils/feature-flags.js +18 -0
  62. package/dist/vendor/desktop-commander/dist/utils/files/base.js +5 -0
  63. package/dist/vendor/desktop-commander/dist/utils/files/binary.js +65 -0
  64. package/dist/vendor/desktop-commander/dist/utils/files/docx.js +694 -0
  65. package/dist/vendor/desktop-commander/dist/utils/files/excel.js +497 -0
  66. package/dist/vendor/desktop-commander/dist/utils/files/factory.js +168 -0
  67. package/dist/vendor/desktop-commander/dist/utils/files/image.js +89 -0
  68. package/dist/vendor/desktop-commander/dist/utils/files/index.js +14 -0
  69. package/dist/vendor/desktop-commander/dist/utils/files/pdf.js +124 -0
  70. package/dist/vendor/desktop-commander/dist/utils/files/text.js +423 -0
  71. package/dist/vendor/desktop-commander/dist/utils/fuzzySearchLogger.js +126 -0
  72. package/dist/vendor/desktop-commander/dist/utils/internal-facts.js +23 -0
  73. package/dist/vendor/desktop-commander/dist/utils/lazy-package.js +44 -0
  74. package/dist/vendor/desktop-commander/dist/utils/lineEndingHandler.js +77 -0
  75. package/dist/vendor/desktop-commander/dist/utils/logger.js +72 -0
  76. package/dist/vendor/desktop-commander/dist/utils/mcp-ui-ab-test.js +62 -0
  77. package/dist/vendor/desktop-commander/dist/utils/open-browser.js +2 -0
  78. package/dist/vendor/desktop-commander/dist/utils/process-detection.js +260 -0
  79. package/dist/vendor/desktop-commander/dist/utils/process-tree.js +223 -0
  80. package/dist/vendor/desktop-commander/dist/utils/rename.js +74 -0
  81. package/dist/vendor/desktop-commander/dist/utils/ripgrep-resolver.js +69 -0
  82. package/dist/vendor/desktop-commander/dist/utils/shell.js +187 -0
  83. package/dist/vendor/desktop-commander/dist/utils/system-info.js +727 -0
  84. package/dist/vendor/desktop-commander/dist/utils/terminal-timestamps.js +18 -0
  85. package/dist/vendor/desktop-commander/dist/utils/toolHistory.js +309 -0
  86. package/dist/vendor/desktop-commander/dist/utils/trackTools.js +55 -0
  87. package/dist/vendor/desktop-commander/dist/utils/unsupportedParams.js +66 -0
  88. package/dist/vendor/desktop-commander/dist/utils/usageTracker.js +225 -0
  89. package/dist/vendor/desktop-commander/dist/utils/welcome-onboarding.js +2 -0
  90. package/dist/vendor/desktop-commander/dist/utils/withTimeout.js +85 -0
  91. package/dist/vendor/desktop-commander/dist/version.js +1 -0
  92. package/dist/vendor/desktop-commander/package.json +15 -0
  93. package/package.json +14 -2
@@ -0,0 +1,172 @@
1
+ import { SHOWN_TEXT_CHARS, MAX_OUTPUT_LINE_CHARS } from '../search-manager.js';
2
+ /**
3
+ * The words of the search answers (start_search, get_more_search_results), in
4
+ * one place (#768). Each answer ends saying how the search ended: its outcome
5
+ * (SearchOutcome in search-manager.ts).
6
+ */
7
+ export const SEARCH_WORDS = {
8
+ /** "Total results: …", the same in both answers */
9
+ total: (matches, rows) => `${matches === 1 ? '1 match' : `${matches} matches`}${rows > matches ? ` (${rows} rows with context)` : ''}`,
10
+ matchRow: (file, line, text) => `📄 ${file}:${line} - ${text}`,
11
+ contextRow: (file, line, text) => ` ${file}:${line} · ${text}`,
12
+ fileRow: (file) => `📁 ${file}`,
13
+ /** A page with no results */
14
+ noMatches: 'No matches found.',
15
+ noneAtOffset: (offset, rows) => `No results at offset ${offset} (${rows} in total).`,
16
+ noneYet: (offset, rows) => `Still running: ${rows === 1 ? '1 result' : `${rows} results`} so far${offset >= 0 ? `, none at offset ${offset} yet` : ''}.`,
17
+ /** After a page's results: whether there are more */
18
+ moreResults: (nextOffset) => `📖 More results available. Use get_more_search_results with offset: ${nextOffset}`,
19
+ moreMayCome: 'Still running: more may come.',
20
+ inProgress: '🔄 Search in progress. Use get_more_search_results to get more results.',
21
+ /** How the search ended, by outcome */
22
+ completed: '✅ Search completed.',
23
+ timedOut: (ms) => `⏱️ Stopped after ${ms} ms: results may be incomplete.`,
24
+ stopped: '⏹️ Stopped on request: results may be incomplete.',
25
+ maxResults: (n) => `Stopped at maxResults (${n}): there may be more.`,
26
+ /** Partial, when the only files it couldn't search were ones it may not read: as it always said */
27
+ permissionsOnly: '✅ Search completed.\n⚠️ Warning: Some files were inaccessible due to permissions. Results may be incomplete.',
28
+ partial: (reasons) => `⚠️ Completed, but some files couldn't be searched: ${reasons.join('; ')}.`,
29
+ unsearched: {
30
+ permissions: () => 'some files were inaccessible due to permissions',
31
+ ripgrep_error: (u) => `ripgrep: ${u.example}${andMore(u)}`,
32
+ ripgrep_ended: (u) => `ripgrep stopped unexpectedly (${u.example})`,
33
+ excel_search: (u) => `the Excel search failed (${u.example})`,
34
+ docx_search: (u) => `the DOCX search failed (${u.example})`,
35
+ excel_file: (u) => `${counted(u, 'an Excel file', 'Excel files')} couldn't be read (${u.example}${andMore(u)})`,
36
+ docx_file: (u) => `${counted(u, 'a DOCX file', 'DOCX files')} couldn't be read (${u.example}${andMore(u)})`,
37
+ excel_folder: (u) => `${counted(u, 'a folder', 'folders')} couldn't be listed for the Excel search (${u.example}${andMore(u)})`,
38
+ docx_folder: (u) => `${counted(u, 'a folder', 'folders')} couldn't be listed for the DOCX search (${u.example}${andMore(u)})`,
39
+ },
40
+ /** A failed search's whole answer */
41
+ failedWithError: (sessionId, error) => `Search session ${sessionId} encountered an error: ${error}`,
42
+ failedRipgrepEnded: (sessionId, how) => `Search session ${sessionId} failed: ripgrep stopped unexpectedly (${how}).`,
43
+ };
44
+ const andMore = (u) => (u.count > 1 ? ` and ${u.count - 1} more` : '');
45
+ const counted = (u, one, many) => (u.count === 1 ? one : `${u.count} ${many}`);
46
+ /**
47
+ * Which lines a search skipped as too long: how many, in which files. Part of a
48
+ * successful answer, worded so that nobody retries: the same search skips them again.
49
+ */
50
+ function describeSkippedLines(skipped) {
51
+ const lines = skipped.reduce((sum, { count }) => sum + count, 0);
52
+ const files = skipped.slice(0, 5).map(({ file }) => file || 'a file whose name is not valid UTF-8').join(', ');
53
+ const more = skipped.length > 5 ? ` and ${skipped.length - 5} more files` : '';
54
+ const exclude = skipped.length === 1 ? "that file (filePattern) if it isn't" : "those files (filePattern) if they aren't";
55
+ return `Skipped ${lines === 1 ? 'a line' : `${lines} lines`} over ${Math.round(MAX_OUTPUT_LINE_CHARS / 1024 / 1024)} MB in ${files}${more}: too long to search. ` +
56
+ `Searching again gives the same result; exclude ${exclude} needed.`;
57
+ }
58
+ /** A result as answers list it: a match, a line around one, or a file */
59
+ function resultRow(result) {
60
+ if (result.type !== 'content')
61
+ return SEARCH_WORDS.fileRow(result.file);
62
+ const text = `${result.match?.substring(0, SHOWN_TEXT_CHARS)}${result.match && result.match.length > SHOWN_TEXT_CHARS ? '...' : ''}`;
63
+ return (result.context ? SEARCH_WORDS.contextRow : SEARCH_WORDS.matchRow)(result.file, result.line, text);
64
+ }
65
+ /** How a complete search ended, as its answer's last line(s); undefined while it runs */
66
+ function endedText(state) {
67
+ switch (state.outcome) {
68
+ case 'completed': return SEARCH_WORDS.completed;
69
+ case 'timed_out': return SEARCH_WORDS.timedOut(state.timeLimitMs);
70
+ case 'stopped': return SEARCH_WORDS.stopped;
71
+ case 'max_results': return SEARCH_WORDS.maxResults(state.maxResults);
72
+ case 'partial':
73
+ return state.unsearched.every(u => u.kind === 'permissions')
74
+ ? SEARCH_WORDS.permissionsOnly
75
+ : SEARCH_WORDS.partial(state.unsearched.map(u => SEARCH_WORDS.unsearched[u.kind](u)));
76
+ default: return undefined;
77
+ }
78
+ }
79
+ /** The answer to a search that failed, whichever tool reads it */
80
+ function failedAnswer(state) {
81
+ const failure = state.failure;
82
+ const text = 'error' in failure
83
+ ? SEARCH_WORDS.failedWithError(state.sessionId, failure.error)
84
+ : SEARCH_WORDS.failedRipgrepEnded(state.sessionId, failure.ripgrepEnded);
85
+ return {
86
+ content: [{ type: 'text', text }],
87
+ isError: true,
88
+ structuredContent: { sessionId: state.sessionId, isComplete: state.isComplete, outcome: state.outcome },
89
+ };
90
+ }
91
+ /** start_search's answer: the search as it is once it started, with its first results */
92
+ export function startSearchAnswer(search, args) {
93
+ if (search.outcome === 'failed')
94
+ return failedAnswer(search);
95
+ let text = `Started ${args.searchType === 'content' ? 'content search' : 'file search'} session: ${search.sessionId}\n`;
96
+ text += `Pattern: "${args.pattern}"\n`;
97
+ text += `Path: ${args.path}\n`;
98
+ text += `Status: ${search.isComplete ? 'COMPLETED' : 'RUNNING'}\n`;
99
+ text += `Runtime: ${Math.round(search.runtime)}ms\n`;
100
+ text += `Total results: ${SEARCH_WORDS.total(search.totalMatches, search.totalResults)}\n\n`;
101
+ if (search.results.length > 0) {
102
+ text += 'Initial results:\n';
103
+ for (const result of search.results.slice(0, 10)) {
104
+ text += `${resultRow(result)}\n`;
105
+ }
106
+ if (search.results.length > 10) {
107
+ text += `... and ${search.results.length - 10} more results\n`;
108
+ }
109
+ }
110
+ text += `\n${endedText(search) ?? SEARCH_WORDS.inProgress}`;
111
+ return {
112
+ content: [{ type: 'text', text }],
113
+ structuredContent: {
114
+ sessionId: search.sessionId,
115
+ isComplete: search.isComplete,
116
+ outcome: search.outcome,
117
+ totalResults: search.totalMatches,
118
+ },
119
+ };
120
+ }
121
+ /** get_more_search_results' answer: one page of a search's results (a negative offset: its last results) */
122
+ export function searchResultsAnswer(page, offset) {
123
+ if (page.outcome === 'failed')
124
+ return failedAnswer(page);
125
+ let text = `Search session: ${page.sessionId}\n`;
126
+ text += `Status: ${page.isComplete ? 'COMPLETED' : 'IN PROGRESS'}\n`;
127
+ text += `Runtime: ${Math.round(page.runtime / 1000)}s\n`;
128
+ text += `Total results: ${SEARCH_WORDS.total(page.totalMatches, page.totalResults)}\n`;
129
+ if (page.returnedCount > 0) {
130
+ text += offset < 0
131
+ ? `Showing last ${page.returnedCount} results\n`
132
+ : `Showing results ${offset}-${offset + page.returnedCount - 1}\n`;
133
+ }
134
+ text += '\n';
135
+ const nextOffset = offset + page.returnedCount;
136
+ if (page.returnedCount === 0) {
137
+ if (!page.isComplete)
138
+ text += SEARCH_WORDS.noneYet(offset, page.totalResults);
139
+ else
140
+ text += page.totalResults === 0 ? SEARCH_WORDS.noMatches : SEARCH_WORDS.noneAtOffset(offset, page.totalResults);
141
+ }
142
+ else {
143
+ text += 'Results:\n';
144
+ for (const result of page.results) {
145
+ text += `${resultRow(result)}\n`;
146
+ }
147
+ if (offset >= 0 && nextOffset < page.totalResults) {
148
+ text += `\n${SEARCH_WORDS.moreResults(nextOffset)}`;
149
+ }
150
+ else if (!page.isComplete) {
151
+ text += `\n${SEARCH_WORDS.moreMayCome}`;
152
+ }
153
+ }
154
+ if (page.skippedLines.length > 0) {
155
+ text += `\n${describeSkippedLines(page.skippedLines)}`;
156
+ }
157
+ const ended = endedText(page);
158
+ if (ended)
159
+ text += `\n${ended}`;
160
+ return {
161
+ content: [{ type: 'text', text }],
162
+ structuredContent: {
163
+ sessionId: page.sessionId,
164
+ isComplete: page.isComplete,
165
+ outcome: page.outcome,
166
+ totalResults: page.totalResults,
167
+ totalMatches: page.totalMatches,
168
+ returnedCount: page.returnedCount,
169
+ hasMoreResults: page.hasMoreResults,
170
+ },
171
+ };
172
+ }
@@ -0,0 +1,136 @@
1
+ import { searchManager } from '../search-manager.js';
2
+ import { StartSearchArgsSchema, GetMoreSearchResultsArgsSchema, StopSearchArgsSchema } from '../tools/schemas.js';
3
+ import { capture } from '../utils/capture.js';
4
+ import { startSearchAnswer, searchResultsAnswer } from './search-answers.js';
5
+ /**
6
+ * Handle start_search command
7
+ */
8
+ export async function handleStartSearch(args) {
9
+ const parsed = StartSearchArgsSchema.safeParse(args);
10
+ if (!parsed.success) {
11
+ return {
12
+ content: [{ type: "text", text: `Invalid arguments for start_search: ${parsed.error}` }],
13
+ isError: true,
14
+ };
15
+ }
16
+ try {
17
+ const result = await searchManager.startSearch({
18
+ rootPath: parsed.data.path,
19
+ pattern: parsed.data.pattern,
20
+ searchType: parsed.data.searchType,
21
+ filePattern: parsed.data.filePattern,
22
+ ignoreCase: parsed.data.ignoreCase,
23
+ maxResults: parsed.data.maxResults,
24
+ includeHidden: parsed.data.includeHidden,
25
+ contextLines: parsed.data.contextLines,
26
+ timeout: parsed.data.timeout_ms,
27
+ earlyTermination: parsed.data.earlyTermination,
28
+ literalSearch: parsed.data.literalSearch,
29
+ });
30
+ return startSearchAnswer(result, parsed.data);
31
+ }
32
+ catch (error) {
33
+ const errorMessage = error instanceof Error ? error.message : String(error);
34
+ capture('search_session_start_error', { error: errorMessage });
35
+ return {
36
+ content: [{ type: "text", text: `Error starting search session: ${errorMessage}` }],
37
+ isError: true,
38
+ };
39
+ }
40
+ }
41
+ /**
42
+ * Handle get_more_search_results command
43
+ */
44
+ export async function handleGetMoreSearchResults(args) {
45
+ const parsed = GetMoreSearchResultsArgsSchema.safeParse(args);
46
+ if (!parsed.success) {
47
+ return {
48
+ content: [{ type: "text", text: `Invalid arguments for get_more_search_results: ${parsed.error}` }],
49
+ isError: true,
50
+ };
51
+ }
52
+ try {
53
+ const page = searchManager.readSearchResults(parsed.data.sessionId, parsed.data.offset, parsed.data.length);
54
+ return searchResultsAnswer(page, parsed.data.offset);
55
+ }
56
+ catch (error) {
57
+ const errorMessage = error instanceof Error ? error.message : String(error);
58
+ return {
59
+ content: [{ type: "text", text: `Error reading search results: ${errorMessage}` }],
60
+ isError: true,
61
+ };
62
+ }
63
+ }
64
+ /**
65
+ * Handle stop_search command
66
+ */
67
+ export async function handleStopSearch(args) {
68
+ const parsed = StopSearchArgsSchema.safeParse(args);
69
+ if (!parsed.success) {
70
+ return {
71
+ content: [{ type: "text", text: `Invalid arguments for stop_search: ${parsed.error}` }],
72
+ isError: true,
73
+ };
74
+ }
75
+ try {
76
+ const success = searchManager.terminateSearch(parsed.data.sessionId);
77
+ if (success) {
78
+ return {
79
+ content: [{
80
+ type: "text",
81
+ text: `Search session ${parsed.data.sessionId} terminated successfully.`
82
+ }],
83
+ };
84
+ }
85
+ else {
86
+ return {
87
+ content: [{
88
+ type: "text",
89
+ text: `Search session ${parsed.data.sessionId} not found or already completed.`
90
+ }],
91
+ };
92
+ }
93
+ }
94
+ catch (error) {
95
+ const errorMessage = error instanceof Error ? error.message : String(error);
96
+ return {
97
+ content: [{ type: "text", text: `Error terminating search session: ${errorMessage}` }],
98
+ isError: true,
99
+ };
100
+ }
101
+ }
102
+ /**
103
+ * Handle list_searches command
104
+ */
105
+ export async function handleListSearches() {
106
+ try {
107
+ const sessions = searchManager.listSearchSessions();
108
+ if (sessions.length === 0) {
109
+ return {
110
+ content: [{ type: "text", text: "No active searches." }],
111
+ };
112
+ }
113
+ let output = `Active Searches (${sessions.length}):\n\n`;
114
+ for (const session of sessions) {
115
+ const status = session.isComplete
116
+ ? (session.isError ? '❌ ERROR' : '✅ COMPLETED')
117
+ : '🔄 RUNNING';
118
+ output += `Session: ${session.id}\n`;
119
+ output += ` Type: ${session.searchType}\n`;
120
+ output += ` Pattern: "${session.pattern}"\n`;
121
+ output += ` Status: ${status}\n`;
122
+ output += ` Runtime: ${Math.round(session.runtime / 1000)}s\n`;
123
+ output += ` Results: ${session.totalResults}\n\n`;
124
+ }
125
+ return {
126
+ content: [{ type: "text", text: output }],
127
+ };
128
+ }
129
+ catch (error) {
130
+ const errorMessage = error instanceof Error ? error.message : String(error);
131
+ return {
132
+ content: [{ type: "text", text: `Error listing search sessions: ${errorMessage}` }],
133
+ isError: true,
134
+ };
135
+ }
136
+ }
@@ -0,0 +1,35 @@
1
+ import { startProcess, readProcessOutput, interactWithProcess, forceTerminate, listSessions } from '../tools/improved-process-tools.js';
2
+ import { StartProcessArgsSchema, ReadProcessOutputArgsSchema, ForceTerminateArgsSchema } from '../tools/schemas.js';
3
+ /**
4
+ * Handle start_process command (improved execute_command)
5
+ */
6
+ export async function handleStartProcess(args) {
7
+ const parsed = StartProcessArgsSchema.parse(args);
8
+ return startProcess(parsed);
9
+ }
10
+ /**
11
+ * Handle read_process_output command (improved read_output)
12
+ */
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);
22
+ }
23
+ /**
24
+ * Handle force_terminate command
25
+ */
26
+ export async function handleForceTerminate(args) {
27
+ const parsed = ForceTerminateArgsSchema.parse(args);
28
+ return forceTerminate(parsed);
29
+ }
30
+ /**
31
+ * Handle list_sessions command
32
+ */
33
+ export async function handleListSessions() {
34
+ return listSessions();
35
+ }
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ import './bootstrap.js';
3
+ import { FilteredStdioServerTransport } from './custom-stdio.js';
4
+ import { server, flushDeferredMessages } from './server.js';
5
+ import { configManager } from './config-manager.js';
6
+ import { logToStderr, logger } from './utils/logger.js';
7
+ import { exitProcess } from './utils/exit-process.js';
8
+ import { preloadFileSupport } from './utils/files/index.js';
9
+
10
+ const deferredMessages = [];
11
+ function deferLog(level, message) {
12
+ deferredMessages.push({ level, message });
13
+ }
14
+
15
+ async function runServer() {
16
+ try {
17
+ global.disableOnboarding = true;
18
+ const transport = new FilteredStdioServerTransport();
19
+ global.mcpTransport = transport;
20
+ try {
21
+ deferLog('info', 'Loading configuration...');
22
+ await configManager.loadConfig();
23
+ deferLog('info', 'Configuration loaded successfully');
24
+ } catch (configError) {
25
+ deferLog('error', `Failed to load configuration: ${configError instanceof Error ? configError.message : String(configError)}`);
26
+ deferLog('warning', 'Continuing with in-memory configuration only');
27
+ }
28
+
29
+ process.on('uncaughtException', async (error) => {
30
+ const errorMessage = error instanceof Error ? error.message : String(error);
31
+ if (errorMessage.includes('JSON') && errorMessage.includes('Unexpected token')) {
32
+ logger.error(`JSON parsing error: ${errorMessage}`);
33
+ return;
34
+ }
35
+ logger.error(`Uncaught exception: ${errorMessage}`);
36
+ exitProcess(1);
37
+ });
38
+
39
+ process.on('unhandledRejection', async (reason) => {
40
+ const errorMessage = reason instanceof Error ? reason.message : String(reason);
41
+ if (errorMessage.includes('JSON') && errorMessage.includes('Unexpected token')) {
42
+ logger.error(`JSON parsing rejection: ${errorMessage}`);
43
+ return;
44
+ }
45
+ logger.error(`Unhandled rejection: ${errorMessage}`);
46
+ });
47
+
48
+ deferLog('info', 'Connecting server...');
49
+ server.oninitialized = () => {
50
+ transport.enableNotifications();
51
+ while (deferredMessages.length > 0) {
52
+ const msg = deferredMessages.shift();
53
+ transport.sendLog('info', msg.message);
54
+ }
55
+ flushDeferredMessages();
56
+ transport.sendLog('info', 'Server connected successfully');
57
+ transport.sendLog('info', 'MCP fully initialized, all startup messages sent');
58
+ preloadFileSupport();
59
+ };
60
+ await server.connect(transport);
61
+ } catch (error) {
62
+ const errorMessage = error instanceof Error ? error.message : String(error);
63
+ logger.error(`FATAL ERROR: ${errorMessage}`);
64
+ const errorNotification = {
65
+ jsonrpc: '2.0',
66
+ method: 'notifications/message',
67
+ params: {
68
+ level: 'error',
69
+ logger: 'desktop-commander',
70
+ data: `Failed to start server: ${errorMessage} (${new Date().toISOString()})`,
71
+ },
72
+ };
73
+ process.stdout.write(JSON.stringify(errorNotification) + '\n');
74
+ exitProcess(1);
75
+ }
76
+ }
77
+
78
+ runServer().catch(async (error) => {
79
+ const errorMessage = error instanceof Error ? error.message : String(error);
80
+ process.stderr.write(
81
+ JSON.stringify({
82
+ type: 'error',
83
+ timestamp: new Date().toISOString(),
84
+ message: `Fatal error running server: ${errorMessage}`,
85
+ }) + '\n'
86
+ );
87
+ exitProcess(1);
88
+ });