starmux 0.11.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.
- package/CONTRIBUTING.md +1 -1
- package/README.md +169 -97
- package/SECURITY.md +3 -3
- package/dist/src/access-control.js +23 -20
- package/dist/src/access-control.js.map +1 -1
- package/dist/src/access-dashboard.js +8 -2
- package/dist/src/access-dashboard.js.map +1 -1
- package/dist/src/cli/instances.js +87 -14
- package/dist/src/cli/instances.js.map +1 -1
- package/dist/src/cli/mac-mcp-gateway.js +4 -3
- package/dist/src/cli/mac-mcp-gateway.js.map +1 -1
- package/dist/src/cli/starmux-status.js +122 -0
- package/dist/src/cli/starmux-status.js.map +1 -0
- package/dist/src/cli/starmux.js +222 -49
- package/dist/src/cli/starmux.js.map +1 -1
- package/dist/src/deny-dashboard.js +2 -2
- package/dist/src/deny-dashboard.js.map +1 -1
- package/dist/src/instance-runtime.js +11 -2
- package/dist/src/instance-runtime.js.map +1 -1
- package/dist/src/instance-store.js +3 -1
- package/dist/src/instance-store.js.map +1 -1
- package/dist/src/ops-dashboard.js +4 -4
- package/dist/src/ops-dashboard.js.map +1 -1
- package/dist/src/permissions-dashboard.js +2 -2
- package/dist/src/permissions-dashboard.js.map +1 -1
- package/dist/src/runtime-paths.js +3 -3
- package/dist/src/runtime-paths.js.map +1 -1
- package/dist/src/starmux-migration.js +1 -1
- package/dist/src/starmux-migration.js.map +1 -1
- package/dist/vendor/desktop-commander/LICENSE +21 -0
- package/dist/vendor/desktop-commander/dist/bootstrap.js +22 -0
- package/dist/vendor/desktop-commander/dist/command-manager.js +246 -0
- package/dist/vendor/desktop-commander/dist/config-field-definitions.js +37 -0
- package/dist/vendor/desktop-commander/dist/config-manager.js +634 -0
- package/dist/vendor/desktop-commander/dist/config-recovery.js +81 -0
- package/dist/vendor/desktop-commander/dist/config.js +19 -0
- package/dist/vendor/desktop-commander/dist/custom-stdio.js +358 -0
- package/dist/vendor/desktop-commander/dist/error-handlers.js +15 -0
- package/dist/vendor/desktop-commander/dist/handlers/edit-search-handlers.js +6 -0
- package/dist/vendor/desktop-commander/dist/handlers/filesystem-handlers.js +450 -0
- package/dist/vendor/desktop-commander/dist/handlers/history-handlers.js +67 -0
- package/dist/vendor/desktop-commander/dist/handlers/index.js +7 -0
- package/dist/vendor/desktop-commander/dist/handlers/process-handlers.js +15 -0
- package/dist/vendor/desktop-commander/dist/handlers/search-answers.js +172 -0
- package/dist/vendor/desktop-commander/dist/handlers/search-handlers.js +136 -0
- package/dist/vendor/desktop-commander/dist/handlers/terminal-handlers.js +35 -0
- package/dist/vendor/desktop-commander/dist/index.js +88 -0
- package/dist/vendor/desktop-commander/dist/search-manager.js +1262 -0
- package/dist/vendor/desktop-commander/dist/server.js +1414 -0
- package/dist/vendor/desktop-commander/dist/terminal-manager.js +757 -0
- package/dist/vendor/desktop-commander/dist/tools/config.js +211 -0
- package/dist/vendor/desktop-commander/dist/tools/edit.js +455 -0
- package/dist/vendor/desktop-commander/dist/tools/feedback.js +10 -0
- package/dist/vendor/desktop-commander/dist/tools/filesystem.js +1047 -0
- package/dist/vendor/desktop-commander/dist/tools/fuzzySearch.js +74 -0
- package/dist/vendor/desktop-commander/dist/tools/fuzzySearchCore.js +125 -0
- package/dist/vendor/desktop-commander/dist/tools/improved-process-tools.js +726 -0
- package/dist/vendor/desktop-commander/dist/tools/mime-types.js +28 -0
- package/dist/vendor/desktop-commander/dist/tools/pdf/extract-images.js +131 -0
- package/dist/vendor/desktop-commander/dist/tools/pdf/index.js +4 -0
- package/dist/vendor/desktop-commander/dist/tools/pdf/lib/pdf2md.js +78 -0
- package/dist/vendor/desktop-commander/dist/tools/pdf/manipulations.js +112 -0
- package/dist/vendor/desktop-commander/dist/tools/pdf/markdown.js +30 -0
- package/dist/vendor/desktop-commander/dist/tools/pdf/utils.js +45 -0
- package/dist/vendor/desktop-commander/dist/tools/process.js +90 -0
- package/dist/vendor/desktop-commander/dist/tools/prompts.js +259 -0
- package/dist/vendor/desktop-commander/dist/tools/schemas.js +242 -0
- package/dist/vendor/desktop-commander/dist/tools/usage.js +24 -0
- package/dist/vendor/desktop-commander/dist/types.js +1 -0
- package/dist/vendor/desktop-commander/dist/ui/config-editor/config-editor-runtime.js +150 -0
- package/dist/vendor/desktop-commander/dist/ui/config-editor/index.html +13 -0
- package/dist/vendor/desktop-commander/dist/ui/config-editor/styles.css +587 -0
- package/dist/vendor/desktop-commander/dist/ui/contracts.js +57 -0
- package/dist/vendor/desktop-commander/dist/ui/file-preview/index.html +16 -0
- package/dist/vendor/desktop-commander/dist/ui/file-preview/preview-runtime.js +471 -0
- package/dist/vendor/desktop-commander/dist/ui/file-preview/shared/preview-file-types.js +59 -0
- package/dist/vendor/desktop-commander/dist/ui/file-preview/styles.css +1631 -0
- package/dist/vendor/desktop-commander/dist/ui/resources.js +93 -0
- package/dist/vendor/desktop-commander/dist/utils/ab-test.js +122 -0
- package/dist/vendor/desktop-commander/dist/utils/atomic-write.js +80 -0
- package/dist/vendor/desktop-commander/dist/utils/capture.js +40 -0
- package/dist/vendor/desktop-commander/dist/utils/dockerPrompt.js +9 -0
- package/dist/vendor/desktop-commander/dist/utils/exit-process.js +31 -0
- package/dist/vendor/desktop-commander/dist/utils/feature-flags.js +18 -0
- package/dist/vendor/desktop-commander/dist/utils/files/base.js +5 -0
- package/dist/vendor/desktop-commander/dist/utils/files/binary.js +65 -0
- package/dist/vendor/desktop-commander/dist/utils/files/docx.js +694 -0
- package/dist/vendor/desktop-commander/dist/utils/files/excel.js +497 -0
- package/dist/vendor/desktop-commander/dist/utils/files/factory.js +168 -0
- package/dist/vendor/desktop-commander/dist/utils/files/image.js +89 -0
- package/dist/vendor/desktop-commander/dist/utils/files/index.js +14 -0
- package/dist/vendor/desktop-commander/dist/utils/files/pdf.js +124 -0
- package/dist/vendor/desktop-commander/dist/utils/files/text.js +423 -0
- package/dist/vendor/desktop-commander/dist/utils/fuzzySearchLogger.js +126 -0
- package/dist/vendor/desktop-commander/dist/utils/internal-facts.js +23 -0
- package/dist/vendor/desktop-commander/dist/utils/lazy-package.js +44 -0
- package/dist/vendor/desktop-commander/dist/utils/lineEndingHandler.js +77 -0
- package/dist/vendor/desktop-commander/dist/utils/logger.js +72 -0
- package/dist/vendor/desktop-commander/dist/utils/mcp-ui-ab-test.js +62 -0
- package/dist/vendor/desktop-commander/dist/utils/open-browser.js +2 -0
- package/dist/vendor/desktop-commander/dist/utils/process-detection.js +260 -0
- package/dist/vendor/desktop-commander/dist/utils/process-tree.js +223 -0
- package/dist/vendor/desktop-commander/dist/utils/rename.js +74 -0
- package/dist/vendor/desktop-commander/dist/utils/ripgrep-resolver.js +69 -0
- package/dist/vendor/desktop-commander/dist/utils/shell.js +187 -0
- package/dist/vendor/desktop-commander/dist/utils/system-info.js +727 -0
- package/dist/vendor/desktop-commander/dist/utils/terminal-timestamps.js +18 -0
- package/dist/vendor/desktop-commander/dist/utils/toolHistory.js +309 -0
- package/dist/vendor/desktop-commander/dist/utils/trackTools.js +55 -0
- package/dist/vendor/desktop-commander/dist/utils/unsupportedParams.js +66 -0
- package/dist/vendor/desktop-commander/dist/utils/usageTracker.js +225 -0
- package/dist/vendor/desktop-commander/dist/utils/welcome-onboarding.js +2 -0
- package/dist/vendor/desktop-commander/dist/utils/withTimeout.js +85 -0
- package/dist/vendor/desktop-commander/dist/version.js +1 -0
- package/dist/vendor/desktop-commander/package.json +15 -0
- package/docs/ACCESS_CONTROL.md +5 -5
- package/docs/CLIENTS.md +11 -19
- package/docs/CONNECT_CHATGPT.md +4 -6
- package/docs/INSTALL.md +9 -5
- package/docs/INSTANCES.md +5 -2
- package/docs/OAUTH.md +6 -14
- package/docs/PLATFORMS.md +4 -4
- package/docs/README.md +2 -11
- package/docs/REMOTE_SETUP.md +13 -13
- package/docs/SECURITY.md +5 -5
- package/docs/assets/starmux-architecture.svg +315 -0
- package/package.json +14 -2
- package/docs/ARCHITECTURE.md +0 -51
- package/docs/MIGRATION.md +0 -37
- package/docs/RELEASE_STATUS.md +0 -31
- package/docs/TYPESCRIPT_MIGRATION.md +0 -56
- package/docs/VALIDATION_OAUTH.md +0 -79
- package/docs/VALIDATION_TUNNEL.md +0 -39
- package/docs/VALIDATION_WORKBUDDY.md +0 -59
- package/docs/assets/mcp-connection-route.svg +0 -104
- package/docs/assets/mcp-gateway-simple.svg +0 -62
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { usageTracker } from '../utils/usageTracker.js';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
// Get the directory path for ES modules
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
let cachedPromptsData = null;
|
|
9
|
+
/**
|
|
10
|
+
* Clear cached prompts data (for development/testing)
|
|
11
|
+
*/
|
|
12
|
+
function clearCache() {
|
|
13
|
+
cachedPromptsData = null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Load prompts data from JSON file with caching
|
|
17
|
+
*/
|
|
18
|
+
export async function loadPromptsData() {
|
|
19
|
+
if (cachedPromptsData) {
|
|
20
|
+
return cachedPromptsData;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const dataPath = path.join(__dirname, '..', 'data', 'onboarding-prompts.json');
|
|
24
|
+
const fileContent = await fs.readFile(dataPath, 'utf-8');
|
|
25
|
+
cachedPromptsData = JSON.parse(fileContent);
|
|
26
|
+
if (!cachedPromptsData) {
|
|
27
|
+
throw new Error('Failed to parse prompts data');
|
|
28
|
+
}
|
|
29
|
+
return cachedPromptsData;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new Error(`Failed to load prompts data: ${error instanceof Error ? error.message : String(error)}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get prompts - SIMPLIFIED VERSION (only get_prompt action)
|
|
37
|
+
*/
|
|
38
|
+
export async function getPrompts(params) {
|
|
39
|
+
try {
|
|
40
|
+
// Validate and cast parameters
|
|
41
|
+
const { action, promptId, anonymous_user_use_case } = params;
|
|
42
|
+
if (!action) {
|
|
43
|
+
return {
|
|
44
|
+
content: [{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: "❌ Error: 'action' parameter is required. Use 'get_prompt'"
|
|
47
|
+
}],
|
|
48
|
+
isError: true
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Only support get_prompt action now
|
|
52
|
+
if (action === 'get_prompt') {
|
|
53
|
+
if (!promptId) {
|
|
54
|
+
return {
|
|
55
|
+
content: [{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: "❌ Error: promptId is required when action is 'get_prompt'"
|
|
58
|
+
}],
|
|
59
|
+
isError: true
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return await getPrompt(promptId, anonymous_user_use_case);
|
|
63
|
+
}
|
|
64
|
+
// Legacy actions return deprecation notice
|
|
65
|
+
return {
|
|
66
|
+
content: [{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: "❌ Error: Only 'get_prompt' action is supported. Use promptId to get a specific prompt."
|
|
69
|
+
}],
|
|
70
|
+
isError: true
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
content: [{
|
|
76
|
+
type: "text",
|
|
77
|
+
text: `❌ Error: ${error instanceof Error ? error.message : String(error)}`
|
|
78
|
+
}],
|
|
79
|
+
isError: true
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* List all available categories
|
|
85
|
+
*/
|
|
86
|
+
async function listCategories() {
|
|
87
|
+
const data = await loadPromptsData();
|
|
88
|
+
// Extract unique categories and count prompts in each
|
|
89
|
+
const categoryMap = new Map();
|
|
90
|
+
data.prompts.forEach(prompt => {
|
|
91
|
+
prompt.categories.forEach(category => {
|
|
92
|
+
categoryMap.set(category, (categoryMap.get(category) || 0) + 1);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
const categories = Array.from(categoryMap.entries()).map(([name, count]) => ({
|
|
96
|
+
name,
|
|
97
|
+
count,
|
|
98
|
+
description: getCategoryDescription(name)
|
|
99
|
+
}));
|
|
100
|
+
const response = formatCategoriesResponse(categories, data.prompts.length);
|
|
101
|
+
return {
|
|
102
|
+
content: [{
|
|
103
|
+
type: "text",
|
|
104
|
+
text: response
|
|
105
|
+
}]
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* List prompts, optionally filtered by category
|
|
110
|
+
*/
|
|
111
|
+
async function listPrompts(category) {
|
|
112
|
+
const data = await loadPromptsData();
|
|
113
|
+
let filteredPrompts = data.prompts;
|
|
114
|
+
// Filter by category if specified
|
|
115
|
+
if (category) {
|
|
116
|
+
filteredPrompts = data.prompts.filter(prompt => prompt.categories.includes(category));
|
|
117
|
+
if (filteredPrompts.length === 0) {
|
|
118
|
+
return {
|
|
119
|
+
content: [{
|
|
120
|
+
type: "text",
|
|
121
|
+
text: `❌ No prompts found in category "${category}". Use action='list_categories' to see available categories.`
|
|
122
|
+
}],
|
|
123
|
+
isError: true
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const response = formatPromptsListResponse(filteredPrompts, category);
|
|
128
|
+
return {
|
|
129
|
+
content: [{
|
|
130
|
+
type: "text",
|
|
131
|
+
text: response
|
|
132
|
+
}]
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get a specific prompt by ID and inject it into the chat
|
|
137
|
+
*/
|
|
138
|
+
async function getPrompt(promptId, anonymousUseCase) {
|
|
139
|
+
const data = await loadPromptsData();
|
|
140
|
+
const prompt = data.prompts.find(p => p.id === promptId);
|
|
141
|
+
if (!prompt) {
|
|
142
|
+
return {
|
|
143
|
+
content: [{
|
|
144
|
+
type: "text",
|
|
145
|
+
text: `❌ Prompt with ID '${promptId}' not found. Use action='list_prompts' to see available prompts.`
|
|
146
|
+
}],
|
|
147
|
+
isError: true
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// Mark prompt as used in user's onboarding state (for analytics)
|
|
151
|
+
await usageTracker.markPromptUsed(promptId, prompt.categories[0] || 'uncategorized');
|
|
152
|
+
const response = formatPromptResponse(prompt);
|
|
153
|
+
return {
|
|
154
|
+
content: [{
|
|
155
|
+
type: "text",
|
|
156
|
+
text: response
|
|
157
|
+
}]
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get category description (can be expanded later)
|
|
162
|
+
*/
|
|
163
|
+
function getCategoryDescription(category) {
|
|
164
|
+
const descriptions = {
|
|
165
|
+
'onboarding': 'Curated prompts perfect for first-time Desktop Commander users',
|
|
166
|
+
'Analyze data': 'Data analysis, visualization, and insights generation',
|
|
167
|
+
'Build features and products': 'Full-stack development and application building',
|
|
168
|
+
'Explore codebase': 'Code analysis, documentation, and understanding',
|
|
169
|
+
'Organize files': 'File management, cleanup, and organization',
|
|
170
|
+
'Deploy': 'Infrastructure setup, deployment, and DevOps tasks',
|
|
171
|
+
'Optimize code': 'Code optimization, refactoring, and performance',
|
|
172
|
+
'Write documentation': 'Technical writing, API docs, and guides',
|
|
173
|
+
'Optimize workflow': 'Process improvements and productivity enhancements',
|
|
174
|
+
'Automate tasks': 'Workflow automation and scripting',
|
|
175
|
+
'Design systems': 'Architecture planning and system design'
|
|
176
|
+
};
|
|
177
|
+
return descriptions[category] || 'Desktop Commander prompts and workflows';
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Format categories list response
|
|
181
|
+
*/
|
|
182
|
+
function formatCategoriesResponse(categories, totalPrompts) {
|
|
183
|
+
const sortedCategories = categories.sort((a, b) => b.count - a.count);
|
|
184
|
+
// AI INSTRUCTION: When listing prompts, do not show prompt IDs to users - they are for your reference only
|
|
185
|
+
let response = `📚 **Desktop Commander Prompt Categories** (${categories.length} categories, ${totalPrompts} prompts)\n\n`;
|
|
186
|
+
sortedCategories.forEach(cat => {
|
|
187
|
+
response += `• **${cat.name}** (${cat.count} prompts) - ${cat.description}\n`;
|
|
188
|
+
});
|
|
189
|
+
response += `\n**Usage:**\n`;
|
|
190
|
+
response += `• \`get_prompts(action='list_prompts', category='onboarding')\` - See prompts in category\n`;
|
|
191
|
+
response += `• \`get_prompts(action='list_prompts')\` - See all available prompts\n`;
|
|
192
|
+
response += `• \`get_prompts(action='get_prompt', promptId='PROMPT_ID')\` - Get a specific prompt`;
|
|
193
|
+
return response;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Format prompts list response using secondary tags for clean organization
|
|
197
|
+
*/
|
|
198
|
+
function formatPromptsListResponse(prompts, category) {
|
|
199
|
+
const categoryText = category ? ` in "${category}"` : '';
|
|
200
|
+
let response = `Desktop Commander Examples${categoryText}\n\n`;
|
|
201
|
+
// Group by secondary tag
|
|
202
|
+
const groupedPrompts = new Map();
|
|
203
|
+
prompts.forEach(prompt => {
|
|
204
|
+
const tag = prompt.secondaryTag || 'Other';
|
|
205
|
+
if (!groupedPrompts.has(tag)) {
|
|
206
|
+
groupedPrompts.set(tag, []);
|
|
207
|
+
}
|
|
208
|
+
groupedPrompts.get(tag).push(prompt);
|
|
209
|
+
});
|
|
210
|
+
let promptNumber = 1;
|
|
211
|
+
// Display groups in preferred order
|
|
212
|
+
const preferredOrder = ['Quick Start', 'Code Analysis', 'Build & Deploy', 'Other'];
|
|
213
|
+
preferredOrder.forEach(tag => {
|
|
214
|
+
if (groupedPrompts.has(tag)) {
|
|
215
|
+
const tagPrompts = groupedPrompts.get(tag);
|
|
216
|
+
// Add emoji for each section
|
|
217
|
+
const emoji = tag === 'Quick Start' ? '🚀' : tag === 'Code Analysis' ? '💻' : tag === 'Build & Deploy' ? '🔨' : '📋';
|
|
218
|
+
response += `**${emoji} ${tag}**\n`;
|
|
219
|
+
tagPrompts.forEach(prompt => {
|
|
220
|
+
response += `• ${promptNumber}. ${prompt.title}\n`;
|
|
221
|
+
promptNumber++;
|
|
222
|
+
});
|
|
223
|
+
response += `\n`;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
response += `Say "Try #3" or "Let's do #1" to start any example.\n\n`;
|
|
227
|
+
response += `<INSTRUCTION>Output options for user exactly as provided without missing numbers.
|
|
228
|
+
Its important so user can choose an options by entering number only. Also do not forget new lines between numbers for easy reading</INSTRUCTION>\n\n`;
|
|
229
|
+
// AI reference mapping (do not show to user):
|
|
230
|
+
response += `<!-- AI_PROMPT_MAP: `;
|
|
231
|
+
let mapNumber = 1;
|
|
232
|
+
preferredOrder.forEach(tag => {
|
|
233
|
+
if (groupedPrompts.has(tag)) {
|
|
234
|
+
groupedPrompts.get(tag).forEach(prompt => {
|
|
235
|
+
response += `${mapNumber}=${prompt.id}${mapNumber < prompts.length ? ',' : ''}`;
|
|
236
|
+
mapNumber++;
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
response += ` -->`;
|
|
241
|
+
return response;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Format individual prompt response with the actual prompt content
|
|
245
|
+
*/
|
|
246
|
+
function formatPromptResponse(prompt) {
|
|
247
|
+
const verifiedBadge = prompt.verified ? ' ✅' : '';
|
|
248
|
+
const categoryText = prompt.categories.join(', ');
|
|
249
|
+
let response = `# 🎯 ${prompt.title}${verifiedBadge}\n\n`;
|
|
250
|
+
response += `**Category:** ${categoryText} • **Author:** ${prompt.author}\n\n`;
|
|
251
|
+
response += `## Description\n${prompt.description}\n\n`;
|
|
252
|
+
if (prompt.votes > 0) {
|
|
253
|
+
response += `*📊 This prompt has been used successfully by ${prompt.votes}+ users*\n\n`;
|
|
254
|
+
}
|
|
255
|
+
response += `## Ready to Use This Prompt\nThe prompt below is ready to use. I'll start executing it right away:\n\n`;
|
|
256
|
+
response += `---\n\n${prompt.prompt}`;
|
|
257
|
+
// AI metadata (not shown to user): Executed prompt ID = ${prompt.id}
|
|
258
|
+
return response;
|
|
259
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Config tools schemas
|
|
3
|
+
export const GetConfigArgsSchema = z.object({
|
|
4
|
+
// 'ui' marks calls the config-editor widget fires programmatically; they are
|
|
5
|
+
// excluded from tool-call telemetry (see isUiOriginCall in server.ts).
|
|
6
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
7
|
+
});
|
|
8
|
+
export const SetConfigValueArgsSchema = z.object({
|
|
9
|
+
key: z.string(),
|
|
10
|
+
value: z.union([
|
|
11
|
+
z.string(),
|
|
12
|
+
z.number(),
|
|
13
|
+
z.boolean(),
|
|
14
|
+
z.array(z.string()),
|
|
15
|
+
z.null(),
|
|
16
|
+
]),
|
|
17
|
+
// 'ui' marks widget-fired calls; excluded from tool-call telemetry.
|
|
18
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
19
|
+
});
|
|
20
|
+
// Empty schemas
|
|
21
|
+
export const ListProcessesArgsSchema = z.object({});
|
|
22
|
+
// Terminal tools schemas
|
|
23
|
+
export const StartProcessArgsSchema = z.object({
|
|
24
|
+
command: z.string(),
|
|
25
|
+
timeout_ms: z.number(),
|
|
26
|
+
shell: z.string().optional(),
|
|
27
|
+
verbose_timing: z.boolean().optional(),
|
|
28
|
+
// 'ui' marks widget-fired calls (e.g. open-in-folder/editor buttons);
|
|
29
|
+
// excluded from tool-call telemetry (see isUiOriginCall in server.ts).
|
|
30
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
31
|
+
});
|
|
32
|
+
export const ReadProcessOutputArgsSchema = z.object({
|
|
33
|
+
pid: z.number(),
|
|
34
|
+
timeout_ms: z.number().optional(),
|
|
35
|
+
offset: z.number().optional(), // Line offset: 0=from last read, positive=absolute, negative=tail
|
|
36
|
+
length: z.number().optional(), // Max lines to return (default from config.fileReadLineLimit)
|
|
37
|
+
verbose_timing: z.boolean().optional(),
|
|
38
|
+
});
|
|
39
|
+
export const ForceTerminateArgsSchema = z.object({
|
|
40
|
+
pid: z.number(),
|
|
41
|
+
});
|
|
42
|
+
export const ListSessionsArgsSchema = z.object({});
|
|
43
|
+
export const KillProcessArgsSchema = z.object({
|
|
44
|
+
// process.kill reads 0 and negative PIDs as process groups: 0 is the server's
|
|
45
|
+
// own (on Windows the server itself), -1 every process the user may signal.
|
|
46
|
+
// A refinement rather than .positive(), so the published schema is unchanged.
|
|
47
|
+
pid: z.number().refine((pid) => pid > 0, { message: 'Number must be greater than 0' }),
|
|
48
|
+
});
|
|
49
|
+
// Filesystem tools schemas
|
|
50
|
+
export const ReadFileArgsSchema = z.object({
|
|
51
|
+
path: z.string(),
|
|
52
|
+
isUrl: z.boolean().optional().default(false),
|
|
53
|
+
offset: z.number().optional().default(0),
|
|
54
|
+
length: z.number().optional().default(1000),
|
|
55
|
+
sheet: z.string().optional(), // String only for MCP client compatibility (Cursor doesn't support union types in JSON Schema)
|
|
56
|
+
range: z.string().optional(),
|
|
57
|
+
options: z.record(z.any()).optional(),
|
|
58
|
+
// Whether the call came from the file-preview UI (refresh/navigation) or the
|
|
59
|
+
// LLM. 'ui' calls are excluded from tool-call telemetry; see isUiOriginCall
|
|
60
|
+
// in server.ts.
|
|
61
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
62
|
+
});
|
|
63
|
+
export const ReadMultipleFilesArgsSchema = z.object({
|
|
64
|
+
paths: z.array(z.string()),
|
|
65
|
+
});
|
|
66
|
+
export const WriteFileArgsSchema = z.object({
|
|
67
|
+
path: z.string(),
|
|
68
|
+
content: z.string(),
|
|
69
|
+
mode: z.enum(['rewrite', 'append']).default('rewrite'),
|
|
70
|
+
// 'ui' when fired by the file-preview UI, else 'llm'. 'ui' calls are
|
|
71
|
+
// excluded from tool-call telemetry; see isUiOriginCall in server.ts.
|
|
72
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
73
|
+
});
|
|
74
|
+
// PDF modification schemas - exported for reuse
|
|
75
|
+
export const PdfInsertOperationSchema = z.object({
|
|
76
|
+
type: z.literal('insert'),
|
|
77
|
+
pageIndex: z.number(),
|
|
78
|
+
markdown: z.string().optional(),
|
|
79
|
+
sourcePdfPath: z.string().optional(),
|
|
80
|
+
pdfOptions: z.object({}).passthrough().optional(),
|
|
81
|
+
});
|
|
82
|
+
export const PdfDeleteOperationSchema = z.object({
|
|
83
|
+
type: z.literal('delete'),
|
|
84
|
+
pageIndexes: z.array(z.number()),
|
|
85
|
+
});
|
|
86
|
+
export const PdfOperationSchema = z.union([PdfInsertOperationSchema, PdfDeleteOperationSchema]);
|
|
87
|
+
export const WritePdfArgsSchema = z.object({
|
|
88
|
+
path: z.string(),
|
|
89
|
+
// Preprocess content to handle JSON strings that should be parsed as arrays
|
|
90
|
+
content: z.preprocess((val) => {
|
|
91
|
+
// If it's a string that looks like JSON array, parse it
|
|
92
|
+
if (typeof val === 'string' && val.trim().startsWith('[')) {
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(val);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// If parsing fails, return as-is (might be markdown content)
|
|
98
|
+
return val;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Otherwise return as-is
|
|
102
|
+
return val;
|
|
103
|
+
}, z.union([z.string(), z.array(PdfOperationSchema)])),
|
|
104
|
+
outputPath: z.string().optional(),
|
|
105
|
+
options: z.object({}).passthrough().optional(), // Allow passing options to md-to-pdf
|
|
106
|
+
});
|
|
107
|
+
export const CreateDirectoryArgsSchema = z.object({
|
|
108
|
+
path: z.string(),
|
|
109
|
+
});
|
|
110
|
+
export const ListDirectoryArgsSchema = z.object({
|
|
111
|
+
path: z.string(),
|
|
112
|
+
depth: z.number().optional().default(2),
|
|
113
|
+
// 'ui' when fired by the file-preview UI, else 'llm'. 'ui' calls are
|
|
114
|
+
// excluded from tool-call telemetry; see isUiOriginCall in server.ts.
|
|
115
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
116
|
+
});
|
|
117
|
+
export const MoveFileArgsSchema = z.object({
|
|
118
|
+
source: z.string(),
|
|
119
|
+
destination: z.string(),
|
|
120
|
+
});
|
|
121
|
+
export const GetFileInfoArgsSchema = z.object({
|
|
122
|
+
path: z.string(),
|
|
123
|
+
});
|
|
124
|
+
// Edit tools schema - SIMPLIFIED from three modes to two
|
|
125
|
+
// Previously supported: text replacement, location-based edits (edits array), and range rewrites
|
|
126
|
+
// Now supports only: text replacement and range rewrites
|
|
127
|
+
// Removed 'edits' array parameter - location-based surgical edits were complex and unnecessary
|
|
128
|
+
// Range rewrites are more powerful and cover all structured file editing needs
|
|
129
|
+
export const EditBlockArgsSchema = z.object({
|
|
130
|
+
file_path: z.string(),
|
|
131
|
+
// Text file string replacement
|
|
132
|
+
old_string: z.string().optional(),
|
|
133
|
+
new_string: z.string().optional(),
|
|
134
|
+
expected_replacements: z.number().optional().default(1),
|
|
135
|
+
// Structured file range rewrite (Excel, etc.)
|
|
136
|
+
range: z.string().optional(),
|
|
137
|
+
content: z.any().optional(),
|
|
138
|
+
options: z.record(z.any()).optional(),
|
|
139
|
+
// 'ui' when fired by the file-preview UI, else 'llm'. 'ui' calls are
|
|
140
|
+
// excluded from tool-call telemetry; see isUiOriginCall in server.ts.
|
|
141
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
142
|
+
}).refine(data => {
|
|
143
|
+
// Helper to check if value is actually provided (not undefined, not empty string)
|
|
144
|
+
const hasValue = (v) => v !== undefined && v !== '';
|
|
145
|
+
return (hasValue(data.old_string) && data.new_string !== undefined) ||
|
|
146
|
+
(hasValue(data.range) && hasValue(data.content));
|
|
147
|
+
}, { message: "Must provide either (old_string + new_string) or (range + content)" });
|
|
148
|
+
// Send input to process schema
|
|
149
|
+
export const InteractWithProcessArgsSchema = z.object({
|
|
150
|
+
pid: z.number(),
|
|
151
|
+
input: z.string(),
|
|
152
|
+
timeout_ms: z.number().optional(),
|
|
153
|
+
wait_for_prompt: z.boolean().optional(),
|
|
154
|
+
verbose_timing: z.boolean().optional(),
|
|
155
|
+
});
|
|
156
|
+
// Usage stats schema
|
|
157
|
+
export const GetUsageStatsArgsSchema = z.object({});
|
|
158
|
+
// Feedback tool schema - no pre-filled parameters, all user input
|
|
159
|
+
export const GiveFeedbackArgsSchema = z.object({
|
|
160
|
+
// No parameters needed - form will be filled manually by user
|
|
161
|
+
// Only auto-filled hidden fields remain:
|
|
162
|
+
// - tool_call_count (auto)
|
|
163
|
+
// - days_using (auto)
|
|
164
|
+
// - platform (auto)
|
|
165
|
+
// - client_id (auto)
|
|
166
|
+
});
|
|
167
|
+
/** A whole number (at least `min`, if given), rejected with a message that says so */
|
|
168
|
+
function wholeNumber(name, min) {
|
|
169
|
+
const message = `${name} must be a whole number${min === undefined ? '' : ` of at least ${min}`}`;
|
|
170
|
+
const number = z.number().int({ message });
|
|
171
|
+
return min === undefined ? number : number.min(min, { message });
|
|
172
|
+
}
|
|
173
|
+
// Search schemas (renamed for natural language)
|
|
174
|
+
export const StartSearchArgsSchema = z.object({
|
|
175
|
+
path: z.string(),
|
|
176
|
+
pattern: z.string(),
|
|
177
|
+
searchType: z.enum(['files', 'content']).default('files'),
|
|
178
|
+
filePattern: z.string().optional(),
|
|
179
|
+
ignoreCase: z.boolean().optional().default(true),
|
|
180
|
+
maxResults: wholeNumber('maxResults', 0).optional(), // 0: no limit
|
|
181
|
+
includeHidden: z.boolean().optional().default(false),
|
|
182
|
+
contextLines: wholeNumber('contextLines', 0).optional().default(5),
|
|
183
|
+
timeout_ms: wholeNumber('timeout_ms', 0).optional(), // Match process naming convention; 0: no time limit
|
|
184
|
+
earlyTermination: z.boolean().optional(), // Stop search early when exact filename match is found (default: true for files, false for content)
|
|
185
|
+
literalSearch: z.boolean().optional().default(false), // Force literal string matching (-F flag) instead of regex
|
|
186
|
+
// 'ui' marks widget-fired calls (e.g. markdown link-target search);
|
|
187
|
+
// excluded from tool-call telemetry (see isUiOriginCall in server.ts).
|
|
188
|
+
origin: z.enum(['ui', 'llm']).optional(),
|
|
189
|
+
});
|
|
190
|
+
export const GetMoreSearchResultsArgsSchema = z.object({
|
|
191
|
+
sessionId: z.string(),
|
|
192
|
+
offset: wholeNumber('offset').optional().default(0), // Same as file reading
|
|
193
|
+
length: wholeNumber('length', 1).optional().default(100), // Same as file reading (but smaller default)
|
|
194
|
+
});
|
|
195
|
+
export const StopSearchArgsSchema = z.object({
|
|
196
|
+
sessionId: z.string(),
|
|
197
|
+
});
|
|
198
|
+
export const ListSearchesArgsSchema = z.object({});
|
|
199
|
+
// Tool history schema
|
|
200
|
+
export const GetRecentToolCallsArgsSchema = z.object({
|
|
201
|
+
maxResults: z.number().min(1).max(1000).optional().default(50),
|
|
202
|
+
toolName: z.string().optional(),
|
|
203
|
+
since: z.string().datetime().optional(),
|
|
204
|
+
});
|
|
205
|
+
export const TrackUiEventArgsSchema = z.object({
|
|
206
|
+
event: z.string().min(1).max(80),
|
|
207
|
+
component: z.string().optional().default('file_preview'),
|
|
208
|
+
params: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional().default({}),
|
|
209
|
+
});
|
|
210
|
+
/**
|
|
211
|
+
* Map of tool name -> argument schema, used by the dispatcher to detect and warn
|
|
212
|
+
* about parameters a caller sent that the tool does not support. Keep in sync
|
|
213
|
+
* with the tool definitions in server.ts.
|
|
214
|
+
*/
|
|
215
|
+
export const toolArgSchemas = {
|
|
216
|
+
get_config: GetConfigArgsSchema,
|
|
217
|
+
set_config_value: SetConfigValueArgsSchema,
|
|
218
|
+
read_file: ReadFileArgsSchema,
|
|
219
|
+
read_multiple_files: ReadMultipleFilesArgsSchema,
|
|
220
|
+
write_file: WriteFileArgsSchema,
|
|
221
|
+
write_pdf: WritePdfArgsSchema,
|
|
222
|
+
create_directory: CreateDirectoryArgsSchema,
|
|
223
|
+
list_directory: ListDirectoryArgsSchema,
|
|
224
|
+
move_file: MoveFileArgsSchema,
|
|
225
|
+
start_search: StartSearchArgsSchema,
|
|
226
|
+
get_more_search_results: GetMoreSearchResultsArgsSchema,
|
|
227
|
+
stop_search: StopSearchArgsSchema,
|
|
228
|
+
list_searches: ListSearchesArgsSchema,
|
|
229
|
+
get_file_info: GetFileInfoArgsSchema,
|
|
230
|
+
edit_block: EditBlockArgsSchema,
|
|
231
|
+
start_process: StartProcessArgsSchema,
|
|
232
|
+
read_process_output: ReadProcessOutputArgsSchema,
|
|
233
|
+
interact_with_process: InteractWithProcessArgsSchema,
|
|
234
|
+
force_terminate: ForceTerminateArgsSchema,
|
|
235
|
+
list_sessions: ListSessionsArgsSchema,
|
|
236
|
+
list_processes: ListProcessesArgsSchema,
|
|
237
|
+
kill_process: KillProcessArgsSchema,
|
|
238
|
+
get_usage_stats: GetUsageStatsArgsSchema,
|
|
239
|
+
get_recent_tool_calls: GetRecentToolCallsArgsSchema,
|
|
240
|
+
give_feedback_to_desktop_commander: GiveFeedbackArgsSchema,
|
|
241
|
+
track_ui_event: TrackUiEventArgsSchema,
|
|
242
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { usageTracker } from '../utils/usageTracker.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get usage statistics for debugging and analysis
|
|
4
|
+
*/
|
|
5
|
+
export async function getUsageStats() {
|
|
6
|
+
try {
|
|
7
|
+
const summary = await usageTracker.getUsageSummary();
|
|
8
|
+
return {
|
|
9
|
+
content: [{
|
|
10
|
+
type: "text",
|
|
11
|
+
text: summary
|
|
12
|
+
}]
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: `Error retrieving usage stats: ${error instanceof Error ? error.message : String(error)}`
|
|
20
|
+
}],
|
|
21
|
+
isError: true
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|