@hcu-lab.me/mcp-device 1.0.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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +22 -0
- package/dist/command-manager.d.ts +8 -0
- package/dist/command-manager.js +241 -0
- package/dist/config-field-definitions.d.ts +41 -0
- package/dist/config-field-definitions.js +37 -0
- package/dist/config-manager.d.ts +102 -0
- package/dist/config-manager.js +291 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +10 -0
- package/dist/custom-stdio.d.ts +51 -0
- package/dist/custom-stdio.js +358 -0
- package/dist/data/official-app-ca.pem +12 -0
- package/dist/data/onboarding-prompts.json +70 -0
- package/dist/device/device-state.d.ts +13 -0
- package/dist/device/device-state.js +100 -0
- package/dist/device/device-status.d.ts +81 -0
- package/dist/device/device-status.js +156 -0
- package/dist/device/device.d.ts +16 -0
- package/dist/device/device.js +190 -0
- package/dist/device/execution-engine.d.ts +144 -0
- package/dist/device/execution-engine.js +195 -0
- package/dist/device/gateway-channel.d.ts +48 -0
- package/dist/device/gateway-channel.js +384 -0
- package/dist/device/gateway-config.d.ts +40 -0
- package/dist/device/gateway-config.js +207 -0
- package/dist/device/gateway-identity.d.ts +35 -0
- package/dist/device/gateway-identity.js +178 -0
- package/dist/device/gateway-pairing.d.ts +25 -0
- package/dist/device/gateway-pairing.js +105 -0
- package/dist/device/gateway-secure-transport.d.ts +25 -0
- package/dist/device/gateway-secure-transport.js +117 -0
- package/dist/device/gateway-tool-adapter.d.ts +17 -0
- package/dist/device/gateway-tool-adapter.js +284 -0
- package/dist/device/gateway-url-policy.d.ts +3 -0
- package/dist/device/gateway-url-policy.js +43 -0
- package/dist/device/linux-service.d.ts +70 -0
- package/dist/device/linux-service.js +268 -0
- package/dist/device/official-trust.d.ts +7 -0
- package/dist/device/official-trust.js +49 -0
- package/dist/device/project-inspection.d.ts +1 -0
- package/dist/device/project-inspection.js +180 -0
- package/dist/device/runtime-owner.d.ts +41 -0
- package/dist/device/runtime-owner.js +177 -0
- package/dist/device/windows-dpapi.d.ts +11 -0
- package/dist/device/windows-dpapi.js +67 -0
- package/dist/device/windows-service.d.ts +56 -0
- package/dist/device/windows-service.js +238 -0
- package/dist/error-handlers.d.ts +7 -0
- package/dist/error-handlers.js +15 -0
- package/dist/handlers/edit-search-handlers.d.ts +6 -0
- package/dist/handlers/edit-search-handlers.js +6 -0
- package/dist/handlers/filesystem-handlers.d.ts +38 -0
- package/dist/handlers/filesystem-handlers.js +440 -0
- package/dist/handlers/history-handlers.d.ts +12 -0
- package/dist/handlers/history-handlers.js +67 -0
- package/dist/handlers/index.d.ts +6 -0
- package/dist/handlers/index.js +7 -0
- package/dist/handlers/process-handlers.d.ts +9 -0
- package/dist/handlers/process-handlers.js +15 -0
- package/dist/handlers/search-handlers.d.ts +17 -0
- package/dist/handlers/search-handlers.js +224 -0
- package/dist/handlers/terminal-handlers.d.ts +21 -0
- package/dist/handlers/terminal-handlers.js +35 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +138 -0
- package/dist/mcp-device.d.ts +2 -0
- package/dist/mcp-device.js +7 -0
- package/dist/npm-scripts/remote.d.ts +3 -0
- package/dist/npm-scripts/remote.js +314 -0
- package/dist/search-manager.d.ts +147 -0
- package/dist/search-manager.js +828 -0
- package/dist/server.d.ts +46 -0
- package/dist/server.js +1563 -0
- package/dist/terminal-manager.d.ts +104 -0
- package/dist/terminal-manager.js +635 -0
- package/dist/tools/config.d.ts +96 -0
- package/dist/tools/config.js +260 -0
- package/dist/tools/edit.d.ts +38 -0
- package/dist/tools/edit.js +435 -0
- package/dist/tools/feedback.d.ts +8 -0
- package/dist/tools/feedback.js +132 -0
- package/dist/tools/filesystem.d.ts +79 -0
- package/dist/tools/filesystem.js +947 -0
- package/dist/tools/fuzzySearch.d.ts +12 -0
- package/dist/tools/fuzzySearch.js +74 -0
- package/dist/tools/fuzzySearchCore.d.ts +52 -0
- package/dist/tools/fuzzySearchCore.js +125 -0
- package/dist/tools/improved-process-tools.d.ts +24 -0
- package/dist/tools/improved-process-tools.js +627 -0
- package/dist/tools/mime-types.d.ts +3 -0
- package/dist/tools/mime-types.js +28 -0
- package/dist/tools/pdf/extract-images.d.ts +34 -0
- package/dist/tools/pdf/extract-images.js +132 -0
- package/dist/tools/pdf/index.d.ts +6 -0
- package/dist/tools/pdf/index.js +3 -0
- package/dist/tools/pdf/lib/pdf2md.d.ts +36 -0
- package/dist/tools/pdf/lib/pdf2md.js +76 -0
- package/dist/tools/pdf/manipulations.d.ts +13 -0
- package/dist/tools/pdf/manipulations.js +99 -0
- package/dist/tools/pdf/markdown.d.ts +26 -0
- package/dist/tools/pdf/markdown.js +275 -0
- package/dist/tools/pdf/utils.d.ts +12 -0
- package/dist/tools/pdf/utils.js +34 -0
- package/dist/tools/process.d.ts +3 -0
- package/dist/tools/process.js +56 -0
- package/dist/tools/prompts.d.ts +28 -0
- package/dist/tools/prompts.js +259 -0
- package/dist/tools/schemas.d.ts +454 -0
- package/dist/tools/schemas.js +242 -0
- package/dist/tools/usage.d.ts +5 -0
- package/dist/tools/usage.js +24 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.js +1 -0
- package/dist/ui/config-editor/config-editor-runtime.js +150 -0
- package/dist/ui/config-editor/index.html +13 -0
- package/dist/ui/config-editor/src/app.d.ts +43 -0
- package/dist/ui/config-editor/src/app.js +831 -0
- package/dist/ui/config-editor/src/array-modal.d.ts +19 -0
- package/dist/ui/config-editor/src/array-modal.js +185 -0
- package/dist/ui/config-editor/src/main.d.ts +1 -0
- package/dist/ui/config-editor/src/main.js +2 -0
- package/dist/ui/config-editor/styles.css +587 -0
- package/dist/ui/contracts.d.ts +14 -0
- package/dist/ui/contracts.js +21 -0
- package/dist/ui/file-preview/index.html +16 -0
- package/dist/ui/file-preview/preview-runtime.js +469 -0
- package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
- package/dist/ui/file-preview/shared/preview-file-types.js +59 -0
- package/dist/ui/file-preview/src/app.d.ts +4 -0
- package/dist/ui/file-preview/src/app.js +680 -0
- package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
- package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
- package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
- package/dist/ui/file-preview/src/components/highlighting.js +54 -0
- package/dist/ui/file-preview/src/components/html-renderer.d.ts +5 -0
- package/dist/ui/file-preview/src/components/html-renderer.js +47 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.js +59 -0
- package/dist/ui/file-preview/src/directory-controller.d.ts +8 -0
- package/dist/ui/file-preview/src/directory-controller.js +240 -0
- package/dist/ui/file-preview/src/document-layout.d.ts +20 -0
- package/dist/ui/file-preview/src/document-layout.js +109 -0
- package/dist/ui/file-preview/src/document-outline.d.ts +17 -0
- package/dist/ui/file-preview/src/document-outline.js +97 -0
- package/dist/ui/file-preview/src/document-workspace.d.ts +19 -0
- package/dist/ui/file-preview/src/document-workspace.js +33 -0
- package/dist/ui/file-preview/src/file-type-handlers.d.ts +10 -0
- package/dist/ui/file-preview/src/file-type-handlers.js +109 -0
- package/dist/ui/file-preview/src/host/external-actions.d.ts +8 -0
- package/dist/ui/file-preview/src/host/external-actions.js +55 -0
- package/dist/ui/file-preview/src/host/selection-context.d.ts +9 -0
- package/dist/ui/file-preview/src/host/selection-context.js +106 -0
- package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
- package/dist/ui/file-preview/src/image-preview.js +21 -0
- package/dist/ui/file-preview/src/main.d.ts +1 -0
- package/dist/ui/file-preview/src/main.js +5 -0
- package/dist/ui/file-preview/src/markdown/conflict-dialog.d.ts +40 -0
- package/dist/ui/file-preview/src/markdown/conflict-dialog.js +163 -0
- package/dist/ui/file-preview/src/markdown/controller.d.ts +44 -0
- package/dist/ui/file-preview/src/markdown/controller.js +1043 -0
- package/dist/ui/file-preview/src/markdown/editor.d.ts +131 -0
- package/dist/ui/file-preview/src/markdown/editor.js +1479 -0
- package/dist/ui/file-preview/src/markdown/linking.d.ts +16 -0
- package/dist/ui/file-preview/src/markdown/linking.js +228 -0
- package/dist/ui/file-preview/src/markdown/outline.d.ts +2 -0
- package/dist/ui/file-preview/src/markdown/outline.js +16 -0
- package/dist/ui/file-preview/src/markdown/parser.d.ts +30 -0
- package/dist/ui/file-preview/src/markdown/parser.js +38 -0
- package/dist/ui/file-preview/src/markdown/preview.d.ts +1 -0
- package/dist/ui/file-preview/src/markdown/preview.js +20 -0
- package/dist/ui/file-preview/src/markdown/slugify.d.ts +3 -0
- package/dist/ui/file-preview/src/markdown/slugify.js +31 -0
- package/dist/ui/file-preview/src/markdown/utils.d.ts +1 -0
- package/dist/ui/file-preview/src/markdown/utils.js +15 -0
- package/dist/ui/file-preview/src/model.d.ts +35 -0
- package/dist/ui/file-preview/src/model.js +1 -0
- package/dist/ui/file-preview/src/panel-actions.d.ts +17 -0
- package/dist/ui/file-preview/src/panel-actions.js +182 -0
- package/dist/ui/file-preview/src/path-utils.d.ts +6 -0
- package/dist/ui/file-preview/src/path-utils.js +64 -0
- package/dist/ui/file-preview/src/payload-utils.d.ts +11 -0
- package/dist/ui/file-preview/src/payload-utils.js +119 -0
- package/dist/ui/file-preview/src/types.d.ts +1 -0
- package/dist/ui/file-preview/src/types.js +1 -0
- package/dist/ui/file-preview/styles.css +1631 -0
- package/dist/ui/resources.d.ts +28 -0
- package/dist/ui/resources.js +86 -0
- package/dist/ui/shared/compact-row.d.ts +11 -0
- package/dist/ui/shared/compact-row.js +18 -0
- package/dist/ui/shared/escape-html.d.ts +4 -0
- package/dist/ui/shared/escape-html.js +11 -0
- package/dist/ui/shared/host-context.d.ts +15 -0
- package/dist/ui/shared/host-context.js +51 -0
- package/dist/ui/shared/tool-bridge.d.ts +30 -0
- package/dist/ui/shared/tool-bridge.js +137 -0
- package/dist/ui/shared/tool-shell.d.ts +25 -0
- package/dist/ui/shared/tool-shell.js +107 -0
- package/dist/ui/shared/ui-event-tracker.d.ts +9 -0
- package/dist/ui/shared/ui-event-tracker.js +27 -0
- package/dist/ui/shared/widget-state.d.ts +33 -0
- package/dist/ui/shared/widget-state.js +158 -0
- package/dist/utils/ab-test.d.ts +12 -0
- package/dist/utils/ab-test.js +104 -0
- package/dist/utils/capture.d.ts +35 -0
- package/dist/utils/capture.js +481 -0
- package/dist/utils/dockerPrompt.d.ts +17 -0
- package/dist/utils/dockerPrompt.js +53 -0
- package/dist/utils/feature-flags.d.ts +59 -0
- package/dist/utils/feature-flags.js +215 -0
- package/dist/utils/files/base.d.ts +173 -0
- package/dist/utils/files/base.js +5 -0
- package/dist/utils/files/binary.d.ts +21 -0
- package/dist/utils/files/binary.js +65 -0
- package/dist/utils/files/docx.d.ts +47 -0
- package/dist/utils/files/docx.js +679 -0
- package/dist/utils/files/excel.d.ts +24 -0
- package/dist/utils/files/excel.js +437 -0
- package/dist/utils/files/factory.d.ts +41 -0
- package/dist/utils/files/factory.js +113 -0
- package/dist/utils/files/image.d.ts +21 -0
- package/dist/utils/files/image.js +78 -0
- package/dist/utils/files/index.d.ts +10 -0
- package/dist/utils/files/index.js +13 -0
- package/dist/utils/files/pdf.d.ts +32 -0
- package/dist/utils/files/pdf.js +142 -0
- package/dist/utils/files/text.d.ts +63 -0
- package/dist/utils/files/text.js +370 -0
- package/dist/utils/fuzzySearchLogger.d.ts +30 -0
- package/dist/utils/fuzzySearchLogger.js +126 -0
- package/dist/utils/lineEndingHandler.d.ts +21 -0
- package/dist/utils/lineEndingHandler.js +77 -0
- package/dist/utils/logger.d.ts +32 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/mcp-ui-ab-test.d.ts +13 -0
- package/dist/utils/mcp-ui-ab-test.js +62 -0
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.js +42 -0
- package/dist/utils/process-detection.d.ts +23 -0
- package/dist/utils/process-detection.js +150 -0
- package/dist/utils/ripgrep-resolver.d.ts +9 -0
- package/dist/utils/ripgrep-resolver.js +74 -0
- package/dist/utils/system-info.d.ts +71 -0
- package/dist/utils/system-info.js +712 -0
- package/dist/utils/toolHistory.d.ts +86 -0
- package/dist/utils/toolHistory.js +257 -0
- package/dist/utils/trackTools.d.ts +6 -0
- package/dist/utils/trackTools.js +54 -0
- package/dist/utils/unsupportedParams.d.ts +24 -0
- package/dist/utils/unsupportedParams.js +66 -0
- package/dist/utils/usageTracker.d.ts +133 -0
- package/dist/utils/usageTracker.js +477 -0
- package/dist/utils/welcome-onboarding.d.ts +11 -0
- package/dist/utils/welcome-onboarding.js +99 -0
- package/dist/utils/withTimeout.d.ts +28 -0
- package/dist/utils/withTimeout.js +85 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { mkdir } from 'fs/promises';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { VERSION } from './version.js';
|
|
7
|
+
import { CONFIG_FILE } from './config.js';
|
|
8
|
+
export function normalizeTelemetryEnabledValue(value) {
|
|
9
|
+
if (typeof value !== 'string') {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
const normalized = value.trim().toLowerCase();
|
|
13
|
+
if (normalized === 'true') {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (normalized === 'false') {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
export function isTelemetryDisabledValue(value) {
|
|
22
|
+
return normalizeTelemetryEnabledValue(value) === false;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Singleton config manager for the server
|
|
26
|
+
*/
|
|
27
|
+
class ConfigManager {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.config = {};
|
|
30
|
+
this.initialized = false;
|
|
31
|
+
this._isFirstRun = false; // Track if this is the first run (config was just created)
|
|
32
|
+
// Serializes all disk writes so concurrent saves can't corrupt config.json.
|
|
33
|
+
this.writeChain = Promise.resolve();
|
|
34
|
+
// True while a coalesced background write is already queued (see scheduleSave).
|
|
35
|
+
this.saveScheduled = false;
|
|
36
|
+
// Get user's home directory
|
|
37
|
+
// Define config directory and file paths
|
|
38
|
+
this.configPath = CONFIG_FILE;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Initialize configuration - load from disk or create default
|
|
42
|
+
*/
|
|
43
|
+
async init() {
|
|
44
|
+
if (this.initialized)
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
// Ensure config directory exists
|
|
48
|
+
const configDir = path.dirname(this.configPath);
|
|
49
|
+
if (!existsSync(configDir)) {
|
|
50
|
+
await mkdir(configDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
// Check if config file exists
|
|
53
|
+
try {
|
|
54
|
+
await fs.access(this.configPath);
|
|
55
|
+
// Load existing config
|
|
56
|
+
const configData = await fs.readFile(this.configPath, 'utf8');
|
|
57
|
+
this.config = JSON.parse(configData);
|
|
58
|
+
this._isFirstRun = false;
|
|
59
|
+
// Configs created before this marker existed must not receive the
|
|
60
|
+
// welcome page retroactively when client eligibility changes later.
|
|
61
|
+
// New configs get this field from getDefaultConfig() and remain
|
|
62
|
+
// eligible across restarts until their first initialization.
|
|
63
|
+
if (this.config['welcomeOnboardingEligible'] === undefined) {
|
|
64
|
+
this.config['welcomeOnboardingEligible'] = false;
|
|
65
|
+
this.config['pendingWelcomeOnboarding'] = false;
|
|
66
|
+
await this.saveConfig();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
// Config file doesn't exist, create default
|
|
71
|
+
this.config = this.getDefaultConfig();
|
|
72
|
+
this._isFirstRun = true; // This is a first run!
|
|
73
|
+
await this.saveConfig();
|
|
74
|
+
}
|
|
75
|
+
this.config['version'] = VERSION;
|
|
76
|
+
this.initialized = true;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error('Failed to initialize config:', error);
|
|
80
|
+
// Fall back to default config in memory
|
|
81
|
+
this.config = this.getDefaultConfig();
|
|
82
|
+
this.initialized = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Alias for init() to maintain backward compatibility
|
|
87
|
+
*/
|
|
88
|
+
async loadConfig() {
|
|
89
|
+
return this.init();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create default configuration
|
|
93
|
+
*/
|
|
94
|
+
getDefaultConfig() {
|
|
95
|
+
return {
|
|
96
|
+
blockedCommands: [
|
|
97
|
+
// Disk and partition management
|
|
98
|
+
"mkfs", // Create a filesystem on a device
|
|
99
|
+
"format", // Format a storage device (cross-platform)
|
|
100
|
+
"mount", // Mount a filesystem
|
|
101
|
+
"umount", // Unmount a filesystem
|
|
102
|
+
"fdisk", // Manipulate disk partition tables
|
|
103
|
+
"dd", // Convert and copy files, can write directly to disks
|
|
104
|
+
"parted", // Disk partition manipulator
|
|
105
|
+
"diskpart", // Windows disk partitioning utility
|
|
106
|
+
// System administration and user management
|
|
107
|
+
"sudo", // Execute command as superuser
|
|
108
|
+
"su", // Substitute user identity
|
|
109
|
+
"passwd", // Change user password
|
|
110
|
+
"adduser", // Add a user to the system
|
|
111
|
+
"useradd", // Create a new user
|
|
112
|
+
"usermod", // Modify user account
|
|
113
|
+
"groupadd", // Create a new group
|
|
114
|
+
"chsh", // Change login shell
|
|
115
|
+
"visudo", // Edit the sudoers file
|
|
116
|
+
// System control
|
|
117
|
+
"shutdown", // Shutdown the system
|
|
118
|
+
"reboot", // Restart the system
|
|
119
|
+
"halt", // Stop the system
|
|
120
|
+
"poweroff", // Power off the system
|
|
121
|
+
"init", // Change system runlevel
|
|
122
|
+
// Network and security
|
|
123
|
+
"iptables", // Linux firewall administration
|
|
124
|
+
"firewall", // Generic firewall command
|
|
125
|
+
"netsh", // Windows network configuration
|
|
126
|
+
// Windows system commands
|
|
127
|
+
"sfc", // System File Checker
|
|
128
|
+
"bcdedit", // Boot Configuration Data editor
|
|
129
|
+
"reg", // Windows registry editor
|
|
130
|
+
"net", // Network/user/service management
|
|
131
|
+
"sc", // Service Control manager
|
|
132
|
+
"runas", // Execute command as another user
|
|
133
|
+
"cipher", // Encrypt/decrypt files or wipe data
|
|
134
|
+
"takeown" // Take ownership of files
|
|
135
|
+
],
|
|
136
|
+
defaultShell: (() => {
|
|
137
|
+
if (os.platform() === 'win32') {
|
|
138
|
+
return 'powershell.exe';
|
|
139
|
+
}
|
|
140
|
+
// Use user's actual shell from environment
|
|
141
|
+
// On macOS, default to zsh (default since Catalina) since process.env.SHELL
|
|
142
|
+
// may not be set when running inside Claude Desktop
|
|
143
|
+
const fallbackShell = os.platform() === 'darwin' ? '/bin/zsh' : '/bin/sh';
|
|
144
|
+
const userShell = process.env.SHELL || fallbackShell;
|
|
145
|
+
// Return just the shell path - we'll handle login shell flag elsewhere
|
|
146
|
+
return userShell;
|
|
147
|
+
})(),
|
|
148
|
+
allowedDirectories: [],
|
|
149
|
+
telemetryEnabled: true, // Default to opt-out approach (telemetry on by default)
|
|
150
|
+
fileWriteLineLimit: 50, // Default line limit for file write operations (changed from 100)
|
|
151
|
+
fileReadLineLimit: 1000, // Default line limit for file read operations (changed from character-based)
|
|
152
|
+
pendingWelcomeOnboarding: true, // New install flag - triggers A/B test for welcome page
|
|
153
|
+
welcomeOnboardingEligible: true // Distinguishes new installs from migrated legacy configs
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Write the current in-memory config to disk. All writes funnel through
|
|
158
|
+
* writeChain (see saveConfig / scheduleSave) so overlapping saves can never
|
|
159
|
+
* interleave and corrupt the file. Previously every tool call could fire its
|
|
160
|
+
* own independent fs.writeFile of the same path.
|
|
161
|
+
*/
|
|
162
|
+
async writeConfigToDisk() {
|
|
163
|
+
await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2), 'utf8');
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Awaitable save, serialized on writeChain. Use for explicit, user-driven
|
|
167
|
+
* config changes where the caller wants on-disk confirmation.
|
|
168
|
+
*/
|
|
169
|
+
async saveConfig() {
|
|
170
|
+
const write = this.writeChain.then(() => this.writeConfigToDisk());
|
|
171
|
+
// Keep the chain alive even if this write rejects, so later writes still run.
|
|
172
|
+
this.writeChain = write.catch(() => { });
|
|
173
|
+
return write;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Non-blocking, coalesced save. Returns immediately; the write runs in the
|
|
177
|
+
* background. A burst of calls collapses to at most one queued write behind
|
|
178
|
+
* the in-flight one, so a storm of tool calls can't storm the disk — and,
|
|
179
|
+
* critically, can't pile up behind a saturated libuv threadpool and gate the
|
|
180
|
+
* tool-call response path. Used for high-frequency, non-critical persistence
|
|
181
|
+
* such as usage stats.
|
|
182
|
+
*/
|
|
183
|
+
scheduleSave() {
|
|
184
|
+
if (this.saveScheduled)
|
|
185
|
+
return; // a queued write will capture the latest config
|
|
186
|
+
this.saveScheduled = true;
|
|
187
|
+
this.writeChain = this.writeChain.then(async () => {
|
|
188
|
+
this.saveScheduled = false; // let the next burst queue a fresh write
|
|
189
|
+
try {
|
|
190
|
+
await this.writeConfigToDisk();
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
console.error('Failed to save config (background):', error);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the entire config
|
|
199
|
+
*/
|
|
200
|
+
async getConfig() {
|
|
201
|
+
await this.init();
|
|
202
|
+
return { ...this.config };
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get a specific configuration value
|
|
206
|
+
*/
|
|
207
|
+
async getValue(key) {
|
|
208
|
+
await this.init();
|
|
209
|
+
return this.config[key];
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Set a specific configuration value
|
|
213
|
+
*/
|
|
214
|
+
async setValue(key, value) {
|
|
215
|
+
await this.init();
|
|
216
|
+
if (key === 'telemetryEnabled') {
|
|
217
|
+
value = normalizeTelemetryEnabledValue(value);
|
|
218
|
+
}
|
|
219
|
+
// Special handling for telemetry opt-out
|
|
220
|
+
if (key === 'telemetryEnabled' && isTelemetryDisabledValue(value)) {
|
|
221
|
+
// Get the current value before changing it
|
|
222
|
+
const currentValue = this.config[key];
|
|
223
|
+
const telemetryAlreadyDisabled = isTelemetryDisabledValue(currentValue);
|
|
224
|
+
// Only capture the opt-out event if telemetry was previously enabled
|
|
225
|
+
if (!telemetryAlreadyDisabled) {
|
|
226
|
+
// Import the capture function dynamically to avoid circular dependencies
|
|
227
|
+
const { capture } = await import('./utils/capture.js');
|
|
228
|
+
// Send a final telemetry event noting that the user has opted out
|
|
229
|
+
// This helps us track opt-out rates while respecting the user's choice
|
|
230
|
+
await capture('server_telemetry_opt_out', {
|
|
231
|
+
reason: 'user_disabled',
|
|
232
|
+
prev_value: currentValue
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Update the value
|
|
237
|
+
this.config[key] = value;
|
|
238
|
+
await this.saveConfig();
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Update a value in memory and persist it WITHOUT blocking the caller.
|
|
242
|
+
* The tool-call response path must never wait on a disk write: when the libuv
|
|
243
|
+
* threadpool is saturated (e.g. many parallel reads stalled on a slow/cloud
|
|
244
|
+
* filesystem) an awaited write can't get a thread and would hang the response
|
|
245
|
+
* of even pure-memory tools. The in-memory value is updated synchronously so
|
|
246
|
+
* subsequent reads see it immediately; the write is coalesced in the
|
|
247
|
+
* background. Callers needing on-disk confirmation should use setValue.
|
|
248
|
+
*/
|
|
249
|
+
async setValueNonBlocking(key, value) {
|
|
250
|
+
await this.init();
|
|
251
|
+
this.config[key] = value;
|
|
252
|
+
this.scheduleSave();
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Update multiple configuration values at once
|
|
256
|
+
*/
|
|
257
|
+
async updateConfig(updates) {
|
|
258
|
+
await this.init();
|
|
259
|
+
this.config = { ...this.config, ...updates };
|
|
260
|
+
await this.saveConfig();
|
|
261
|
+
return { ...this.config };
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Reset configuration to defaults
|
|
265
|
+
*/
|
|
266
|
+
async resetConfig() {
|
|
267
|
+
this.config = this.getDefaultConfig();
|
|
268
|
+
await this.saveConfig();
|
|
269
|
+
return { ...this.config };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Check if this is the first run (config file was just created)
|
|
273
|
+
*/
|
|
274
|
+
isFirstRun() {
|
|
275
|
+
return this._isFirstRun;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get or create a persistent client ID for analytics and A/B tests
|
|
279
|
+
*/
|
|
280
|
+
async getOrCreateClientId() {
|
|
281
|
+
let clientId = await this.getValue('clientId');
|
|
282
|
+
if (!clientId) {
|
|
283
|
+
const { randomUUID } = await import('crypto');
|
|
284
|
+
clientId = randomUUID();
|
|
285
|
+
await this.setValue('clientId', clientId);
|
|
286
|
+
}
|
|
287
|
+
return clientId;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Export singleton instance
|
|
291
|
+
export const configManager = new ConfigManager();
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const USER_HOME: string;
|
|
2
|
+
export declare const CONFIG_DIR: string;
|
|
3
|
+
export declare const CONFIG_FILE: string;
|
|
4
|
+
export declare const TOOL_CALL_FILE: string;
|
|
5
|
+
export declare const TOOL_CALL_FILE_MAX_SIZE: number;
|
|
6
|
+
export declare const DEFAULT_COMMAND_TIMEOUT = 1000;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
// MCP Device owns one canonical per-user state/config root.
|
|
4
|
+
export const USER_HOME = os.homedir();
|
|
5
|
+
export const CONFIG_DIR = path.resolve(process.env.MCP_DEVICE_CONFIG_DIR || process.env.DESKTOP_COMMANDER_CONFIG_DIR || path.join(USER_HOME, '.mcp-device'));
|
|
6
|
+
// Paths relative to the config directory.
|
|
7
|
+
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
8
|
+
export const TOOL_CALL_FILE = path.join(CONFIG_DIR, 'logs', 'tool-calls.log');
|
|
9
|
+
export const TOOL_CALL_FILE_MAX_SIZE = 1024 * 1024 * 10; // 10 MB
|
|
10
|
+
export const DEFAULT_COMMAND_TIMEOUT = 1000; // milliseconds
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced StdioServerTransport that wraps console output in valid JSON-RPC structures
|
|
4
|
+
* instead of filtering them out. This prevents crashes while maintaining debug visibility.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FilteredStdioServerTransport extends StdioServerTransport {
|
|
7
|
+
private originalConsole;
|
|
8
|
+
private originalStdoutWrite;
|
|
9
|
+
private isInitialized;
|
|
10
|
+
private messageBuffer;
|
|
11
|
+
private clientName;
|
|
12
|
+
private disableNotifications;
|
|
13
|
+
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Call this method after MCP initialization is complete to enable JSON-RPC notifications
|
|
16
|
+
*/
|
|
17
|
+
enableNotifications(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Configure client-specific behavior
|
|
20
|
+
* Call this BEFORE enableNotifications()
|
|
21
|
+
*/
|
|
22
|
+
configureForClient(clientName: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Check if notifications are enabled
|
|
25
|
+
*/
|
|
26
|
+
get isNotificationsEnabled(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Get the current count of buffered messages
|
|
29
|
+
*/
|
|
30
|
+
get bufferedMessageCount(): number;
|
|
31
|
+
private setupConsoleRedirection;
|
|
32
|
+
private setupStdoutFiltering;
|
|
33
|
+
private sendLogNotification;
|
|
34
|
+
/**
|
|
35
|
+
* Public method to send log notifications from anywhere in the application
|
|
36
|
+
* Now properly buffers messages before MCP initialization to avoid breaking stdio protocol
|
|
37
|
+
*/
|
|
38
|
+
sendLog(level: "emergency" | "alert" | "critical" | "error" | "warning" | "notice" | "info" | "debug", message: string, data?: any): void;
|
|
39
|
+
/**
|
|
40
|
+
* Send a progress notification (useful for long-running operations)
|
|
41
|
+
*/
|
|
42
|
+
sendProgress(token: string, value: number, total?: number): void;
|
|
43
|
+
/**
|
|
44
|
+
* Send a custom notification with any method name
|
|
45
|
+
*/
|
|
46
|
+
sendCustomNotification(method: string, params: any): void;
|
|
47
|
+
/**
|
|
48
|
+
* Cleanup method to restore original console methods if needed
|
|
49
|
+
*/
|
|
50
|
+
cleanup(): void;
|
|
51
|
+
}
|