@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.
Files changed (261) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -0
  3. package/dist/bootstrap.d.ts +1 -0
  4. package/dist/bootstrap.js +22 -0
  5. package/dist/command-manager.d.ts +8 -0
  6. package/dist/command-manager.js +241 -0
  7. package/dist/config-field-definitions.d.ts +41 -0
  8. package/dist/config-field-definitions.js +37 -0
  9. package/dist/config-manager.d.ts +102 -0
  10. package/dist/config-manager.js +291 -0
  11. package/dist/config.d.ts +6 -0
  12. package/dist/config.js +10 -0
  13. package/dist/custom-stdio.d.ts +51 -0
  14. package/dist/custom-stdio.js +358 -0
  15. package/dist/data/official-app-ca.pem +12 -0
  16. package/dist/data/onboarding-prompts.json +70 -0
  17. package/dist/device/device-state.d.ts +13 -0
  18. package/dist/device/device-state.js +100 -0
  19. package/dist/device/device-status.d.ts +81 -0
  20. package/dist/device/device-status.js +156 -0
  21. package/dist/device/device.d.ts +16 -0
  22. package/dist/device/device.js +190 -0
  23. package/dist/device/execution-engine.d.ts +144 -0
  24. package/dist/device/execution-engine.js +195 -0
  25. package/dist/device/gateway-channel.d.ts +48 -0
  26. package/dist/device/gateway-channel.js +384 -0
  27. package/dist/device/gateway-config.d.ts +40 -0
  28. package/dist/device/gateway-config.js +207 -0
  29. package/dist/device/gateway-identity.d.ts +35 -0
  30. package/dist/device/gateway-identity.js +178 -0
  31. package/dist/device/gateway-pairing.d.ts +25 -0
  32. package/dist/device/gateway-pairing.js +105 -0
  33. package/dist/device/gateway-secure-transport.d.ts +25 -0
  34. package/dist/device/gateway-secure-transport.js +117 -0
  35. package/dist/device/gateway-tool-adapter.d.ts +17 -0
  36. package/dist/device/gateway-tool-adapter.js +284 -0
  37. package/dist/device/gateway-url-policy.d.ts +3 -0
  38. package/dist/device/gateway-url-policy.js +43 -0
  39. package/dist/device/linux-service.d.ts +70 -0
  40. package/dist/device/linux-service.js +268 -0
  41. package/dist/device/official-trust.d.ts +7 -0
  42. package/dist/device/official-trust.js +49 -0
  43. package/dist/device/project-inspection.d.ts +1 -0
  44. package/dist/device/project-inspection.js +180 -0
  45. package/dist/device/runtime-owner.d.ts +41 -0
  46. package/dist/device/runtime-owner.js +177 -0
  47. package/dist/device/windows-dpapi.d.ts +11 -0
  48. package/dist/device/windows-dpapi.js +67 -0
  49. package/dist/device/windows-service.d.ts +56 -0
  50. package/dist/device/windows-service.js +238 -0
  51. package/dist/error-handlers.d.ts +7 -0
  52. package/dist/error-handlers.js +15 -0
  53. package/dist/handlers/edit-search-handlers.d.ts +6 -0
  54. package/dist/handlers/edit-search-handlers.js +6 -0
  55. package/dist/handlers/filesystem-handlers.d.ts +38 -0
  56. package/dist/handlers/filesystem-handlers.js +440 -0
  57. package/dist/handlers/history-handlers.d.ts +12 -0
  58. package/dist/handlers/history-handlers.js +67 -0
  59. package/dist/handlers/index.d.ts +6 -0
  60. package/dist/handlers/index.js +7 -0
  61. package/dist/handlers/process-handlers.d.ts +9 -0
  62. package/dist/handlers/process-handlers.js +15 -0
  63. package/dist/handlers/search-handlers.d.ts +17 -0
  64. package/dist/handlers/search-handlers.js +224 -0
  65. package/dist/handlers/terminal-handlers.d.ts +21 -0
  66. package/dist/handlers/terminal-handlers.js +35 -0
  67. package/dist/index.d.ts +2 -0
  68. package/dist/index.js +138 -0
  69. package/dist/mcp-device.d.ts +2 -0
  70. package/dist/mcp-device.js +7 -0
  71. package/dist/npm-scripts/remote.d.ts +3 -0
  72. package/dist/npm-scripts/remote.js +314 -0
  73. package/dist/search-manager.d.ts +147 -0
  74. package/dist/search-manager.js +828 -0
  75. package/dist/server.d.ts +46 -0
  76. package/dist/server.js +1563 -0
  77. package/dist/terminal-manager.d.ts +104 -0
  78. package/dist/terminal-manager.js +635 -0
  79. package/dist/tools/config.d.ts +96 -0
  80. package/dist/tools/config.js +260 -0
  81. package/dist/tools/edit.d.ts +38 -0
  82. package/dist/tools/edit.js +435 -0
  83. package/dist/tools/feedback.d.ts +8 -0
  84. package/dist/tools/feedback.js +132 -0
  85. package/dist/tools/filesystem.d.ts +79 -0
  86. package/dist/tools/filesystem.js +947 -0
  87. package/dist/tools/fuzzySearch.d.ts +12 -0
  88. package/dist/tools/fuzzySearch.js +74 -0
  89. package/dist/tools/fuzzySearchCore.d.ts +52 -0
  90. package/dist/tools/fuzzySearchCore.js +125 -0
  91. package/dist/tools/improved-process-tools.d.ts +24 -0
  92. package/dist/tools/improved-process-tools.js +627 -0
  93. package/dist/tools/mime-types.d.ts +3 -0
  94. package/dist/tools/mime-types.js +28 -0
  95. package/dist/tools/pdf/extract-images.d.ts +34 -0
  96. package/dist/tools/pdf/extract-images.js +132 -0
  97. package/dist/tools/pdf/index.d.ts +6 -0
  98. package/dist/tools/pdf/index.js +3 -0
  99. package/dist/tools/pdf/lib/pdf2md.d.ts +36 -0
  100. package/dist/tools/pdf/lib/pdf2md.js +76 -0
  101. package/dist/tools/pdf/manipulations.d.ts +13 -0
  102. package/dist/tools/pdf/manipulations.js +99 -0
  103. package/dist/tools/pdf/markdown.d.ts +26 -0
  104. package/dist/tools/pdf/markdown.js +275 -0
  105. package/dist/tools/pdf/utils.d.ts +12 -0
  106. package/dist/tools/pdf/utils.js +34 -0
  107. package/dist/tools/process.d.ts +3 -0
  108. package/dist/tools/process.js +56 -0
  109. package/dist/tools/prompts.d.ts +28 -0
  110. package/dist/tools/prompts.js +259 -0
  111. package/dist/tools/schemas.d.ts +454 -0
  112. package/dist/tools/schemas.js +242 -0
  113. package/dist/tools/usage.d.ts +5 -0
  114. package/dist/tools/usage.js +24 -0
  115. package/dist/types.d.ts +83 -0
  116. package/dist/types.js +1 -0
  117. package/dist/ui/config-editor/config-editor-runtime.js +150 -0
  118. package/dist/ui/config-editor/index.html +13 -0
  119. package/dist/ui/config-editor/src/app.d.ts +43 -0
  120. package/dist/ui/config-editor/src/app.js +831 -0
  121. package/dist/ui/config-editor/src/array-modal.d.ts +19 -0
  122. package/dist/ui/config-editor/src/array-modal.js +185 -0
  123. package/dist/ui/config-editor/src/main.d.ts +1 -0
  124. package/dist/ui/config-editor/src/main.js +2 -0
  125. package/dist/ui/config-editor/styles.css +587 -0
  126. package/dist/ui/contracts.d.ts +14 -0
  127. package/dist/ui/contracts.js +21 -0
  128. package/dist/ui/file-preview/index.html +16 -0
  129. package/dist/ui/file-preview/preview-runtime.js +469 -0
  130. package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
  131. package/dist/ui/file-preview/shared/preview-file-types.js +59 -0
  132. package/dist/ui/file-preview/src/app.d.ts +4 -0
  133. package/dist/ui/file-preview/src/app.js +680 -0
  134. package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
  135. package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
  136. package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
  137. package/dist/ui/file-preview/src/components/highlighting.js +54 -0
  138. package/dist/ui/file-preview/src/components/html-renderer.d.ts +5 -0
  139. package/dist/ui/file-preview/src/components/html-renderer.js +47 -0
  140. package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
  141. package/dist/ui/file-preview/src/components/markdown-renderer.js +59 -0
  142. package/dist/ui/file-preview/src/directory-controller.d.ts +8 -0
  143. package/dist/ui/file-preview/src/directory-controller.js +240 -0
  144. package/dist/ui/file-preview/src/document-layout.d.ts +20 -0
  145. package/dist/ui/file-preview/src/document-layout.js +109 -0
  146. package/dist/ui/file-preview/src/document-outline.d.ts +17 -0
  147. package/dist/ui/file-preview/src/document-outline.js +97 -0
  148. package/dist/ui/file-preview/src/document-workspace.d.ts +19 -0
  149. package/dist/ui/file-preview/src/document-workspace.js +33 -0
  150. package/dist/ui/file-preview/src/file-type-handlers.d.ts +10 -0
  151. package/dist/ui/file-preview/src/file-type-handlers.js +109 -0
  152. package/dist/ui/file-preview/src/host/external-actions.d.ts +8 -0
  153. package/dist/ui/file-preview/src/host/external-actions.js +55 -0
  154. package/dist/ui/file-preview/src/host/selection-context.d.ts +9 -0
  155. package/dist/ui/file-preview/src/host/selection-context.js +106 -0
  156. package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
  157. package/dist/ui/file-preview/src/image-preview.js +21 -0
  158. package/dist/ui/file-preview/src/main.d.ts +1 -0
  159. package/dist/ui/file-preview/src/main.js +5 -0
  160. package/dist/ui/file-preview/src/markdown/conflict-dialog.d.ts +40 -0
  161. package/dist/ui/file-preview/src/markdown/conflict-dialog.js +163 -0
  162. package/dist/ui/file-preview/src/markdown/controller.d.ts +44 -0
  163. package/dist/ui/file-preview/src/markdown/controller.js +1043 -0
  164. package/dist/ui/file-preview/src/markdown/editor.d.ts +131 -0
  165. package/dist/ui/file-preview/src/markdown/editor.js +1479 -0
  166. package/dist/ui/file-preview/src/markdown/linking.d.ts +16 -0
  167. package/dist/ui/file-preview/src/markdown/linking.js +228 -0
  168. package/dist/ui/file-preview/src/markdown/outline.d.ts +2 -0
  169. package/dist/ui/file-preview/src/markdown/outline.js +16 -0
  170. package/dist/ui/file-preview/src/markdown/parser.d.ts +30 -0
  171. package/dist/ui/file-preview/src/markdown/parser.js +38 -0
  172. package/dist/ui/file-preview/src/markdown/preview.d.ts +1 -0
  173. package/dist/ui/file-preview/src/markdown/preview.js +20 -0
  174. package/dist/ui/file-preview/src/markdown/slugify.d.ts +3 -0
  175. package/dist/ui/file-preview/src/markdown/slugify.js +31 -0
  176. package/dist/ui/file-preview/src/markdown/utils.d.ts +1 -0
  177. package/dist/ui/file-preview/src/markdown/utils.js +15 -0
  178. package/dist/ui/file-preview/src/model.d.ts +35 -0
  179. package/dist/ui/file-preview/src/model.js +1 -0
  180. package/dist/ui/file-preview/src/panel-actions.d.ts +17 -0
  181. package/dist/ui/file-preview/src/panel-actions.js +182 -0
  182. package/dist/ui/file-preview/src/path-utils.d.ts +6 -0
  183. package/dist/ui/file-preview/src/path-utils.js +64 -0
  184. package/dist/ui/file-preview/src/payload-utils.d.ts +11 -0
  185. package/dist/ui/file-preview/src/payload-utils.js +119 -0
  186. package/dist/ui/file-preview/src/types.d.ts +1 -0
  187. package/dist/ui/file-preview/src/types.js +1 -0
  188. package/dist/ui/file-preview/styles.css +1631 -0
  189. package/dist/ui/resources.d.ts +28 -0
  190. package/dist/ui/resources.js +86 -0
  191. package/dist/ui/shared/compact-row.d.ts +11 -0
  192. package/dist/ui/shared/compact-row.js +18 -0
  193. package/dist/ui/shared/escape-html.d.ts +4 -0
  194. package/dist/ui/shared/escape-html.js +11 -0
  195. package/dist/ui/shared/host-context.d.ts +15 -0
  196. package/dist/ui/shared/host-context.js +51 -0
  197. package/dist/ui/shared/tool-bridge.d.ts +30 -0
  198. package/dist/ui/shared/tool-bridge.js +137 -0
  199. package/dist/ui/shared/tool-shell.d.ts +25 -0
  200. package/dist/ui/shared/tool-shell.js +107 -0
  201. package/dist/ui/shared/ui-event-tracker.d.ts +9 -0
  202. package/dist/ui/shared/ui-event-tracker.js +27 -0
  203. package/dist/ui/shared/widget-state.d.ts +33 -0
  204. package/dist/ui/shared/widget-state.js +158 -0
  205. package/dist/utils/ab-test.d.ts +12 -0
  206. package/dist/utils/ab-test.js +104 -0
  207. package/dist/utils/capture.d.ts +35 -0
  208. package/dist/utils/capture.js +481 -0
  209. package/dist/utils/dockerPrompt.d.ts +17 -0
  210. package/dist/utils/dockerPrompt.js +53 -0
  211. package/dist/utils/feature-flags.d.ts +59 -0
  212. package/dist/utils/feature-flags.js +215 -0
  213. package/dist/utils/files/base.d.ts +173 -0
  214. package/dist/utils/files/base.js +5 -0
  215. package/dist/utils/files/binary.d.ts +21 -0
  216. package/dist/utils/files/binary.js +65 -0
  217. package/dist/utils/files/docx.d.ts +47 -0
  218. package/dist/utils/files/docx.js +679 -0
  219. package/dist/utils/files/excel.d.ts +24 -0
  220. package/dist/utils/files/excel.js +437 -0
  221. package/dist/utils/files/factory.d.ts +41 -0
  222. package/dist/utils/files/factory.js +113 -0
  223. package/dist/utils/files/image.d.ts +21 -0
  224. package/dist/utils/files/image.js +78 -0
  225. package/dist/utils/files/index.d.ts +10 -0
  226. package/dist/utils/files/index.js +13 -0
  227. package/dist/utils/files/pdf.d.ts +32 -0
  228. package/dist/utils/files/pdf.js +142 -0
  229. package/dist/utils/files/text.d.ts +63 -0
  230. package/dist/utils/files/text.js +370 -0
  231. package/dist/utils/fuzzySearchLogger.d.ts +30 -0
  232. package/dist/utils/fuzzySearchLogger.js +126 -0
  233. package/dist/utils/lineEndingHandler.d.ts +21 -0
  234. package/dist/utils/lineEndingHandler.js +77 -0
  235. package/dist/utils/logger.d.ts +32 -0
  236. package/dist/utils/logger.js +72 -0
  237. package/dist/utils/mcp-ui-ab-test.d.ts +13 -0
  238. package/dist/utils/mcp-ui-ab-test.js +62 -0
  239. package/dist/utils/open-browser.d.ts +9 -0
  240. package/dist/utils/open-browser.js +42 -0
  241. package/dist/utils/process-detection.d.ts +23 -0
  242. package/dist/utils/process-detection.js +150 -0
  243. package/dist/utils/ripgrep-resolver.d.ts +9 -0
  244. package/dist/utils/ripgrep-resolver.js +74 -0
  245. package/dist/utils/system-info.d.ts +71 -0
  246. package/dist/utils/system-info.js +712 -0
  247. package/dist/utils/toolHistory.d.ts +86 -0
  248. package/dist/utils/toolHistory.js +257 -0
  249. package/dist/utils/trackTools.d.ts +6 -0
  250. package/dist/utils/trackTools.js +54 -0
  251. package/dist/utils/unsupportedParams.d.ts +24 -0
  252. package/dist/utils/unsupportedParams.js +66 -0
  253. package/dist/utils/usageTracker.d.ts +133 -0
  254. package/dist/utils/usageTracker.js +477 -0
  255. package/dist/utils/welcome-onboarding.d.ts +11 -0
  256. package/dist/utils/welcome-onboarding.js +99 -0
  257. package/dist/utils/withTimeout.d.ts +28 -0
  258. package/dist/utils/withTimeout.js +85 -0
  259. package/dist/version.d.ts +1 -0
  260. package/dist/version.js +1 -0
  261. 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();
@@ -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
+ }