@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,358 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import process from "node:process";
3
+ /**
4
+ * Enhanced StdioServerTransport that wraps console output in valid JSON-RPC structures
5
+ * instead of filtering them out. This prevents crashes while maintaining debug visibility.
6
+ */
7
+ export class FilteredStdioServerTransport extends StdioServerTransport {
8
+ constructor() {
9
+ super();
10
+ this.isInitialized = false;
11
+ this.messageBuffer = [];
12
+ this.clientName = 'unknown';
13
+ this.disableNotifications = false;
14
+ // Store original methods
15
+ this.originalConsole = {
16
+ log: console.log,
17
+ warn: console.warn,
18
+ error: console.error,
19
+ debug: console.debug,
20
+ info: console.info,
21
+ };
22
+ this.originalStdoutWrite = process.stdout.write;
23
+ // Setup console redirection
24
+ this.setupConsoleRedirection();
25
+ // Setup stdout filtering for any other output
26
+ this.setupStdoutFiltering();
27
+ // Note: We defer the initialization notification until enableNotifications() is called
28
+ // to ensure MCP protocol compliance - notifications must not be sent before initialization
29
+ }
30
+ /**
31
+ * Call this method after MCP initialization is complete to enable JSON-RPC notifications
32
+ */
33
+ enableNotifications() {
34
+ this.isInitialized = true;
35
+ // Check if notifications should be disabled based on client
36
+ if (this.disableNotifications) {
37
+ // Clear buffer without sending - just log to stderr instead
38
+ if (this.messageBuffer.length > 0) {
39
+ process.stderr.write(`[INFO] ${this.messageBuffer.length} buffered messages suppressed for ${this.clientName}\n`);
40
+ }
41
+ this.messageBuffer = [];
42
+ return;
43
+ }
44
+ // Send the deferred initialization notification first
45
+ this.sendLogNotification('info', ['Enhanced FilteredStdioServerTransport initialized']);
46
+ // Replay all buffered messages in chronological order
47
+ if (this.messageBuffer.length > 0) {
48
+ this.sendLogNotification('info', [`Replaying ${this.messageBuffer.length} buffered initialization messages`]);
49
+ this.messageBuffer
50
+ .sort((a, b) => a.timestamp - b.timestamp)
51
+ .forEach(msg => {
52
+ this.sendLogNotification(msg.level, msg.args);
53
+ });
54
+ // Clear the buffer
55
+ this.messageBuffer = [];
56
+ }
57
+ this.sendLogNotification('info', ['JSON-RPC notifications enabled']);
58
+ }
59
+ /**
60
+ * Configure client-specific behavior
61
+ * Call this BEFORE enableNotifications()
62
+ */
63
+ configureForClient(clientName) {
64
+ this.clientName = clientName.toLowerCase();
65
+ // Detect Cline and disable notifications
66
+ if (this.clientName.includes('cline') ||
67
+ this.clientName.includes('vscode') ||
68
+ this.clientName === 'claude-dev') {
69
+ this.disableNotifications = true;
70
+ process.stderr.write(`[INFO] MCP Device: Notifications disabled for ${clientName}\n`);
71
+ }
72
+ }
73
+ /**
74
+ * Check if notifications are enabled
75
+ */
76
+ get isNotificationsEnabled() {
77
+ return this.isInitialized;
78
+ }
79
+ /**
80
+ * Get the current count of buffered messages
81
+ */
82
+ get bufferedMessageCount() {
83
+ return this.messageBuffer.length;
84
+ }
85
+ setupConsoleRedirection() {
86
+ console.log = (...args) => {
87
+ if (this.isInitialized) {
88
+ this.sendLogNotification("info", args);
89
+ }
90
+ else {
91
+ // Buffer for later replay to client
92
+ this.messageBuffer.push({
93
+ level: "info",
94
+ args,
95
+ timestamp: Date.now()
96
+ });
97
+ }
98
+ };
99
+ console.info = (...args) => {
100
+ if (this.isInitialized) {
101
+ this.sendLogNotification("info", args);
102
+ }
103
+ else {
104
+ this.messageBuffer.push({
105
+ level: "info",
106
+ args,
107
+ timestamp: Date.now()
108
+ });
109
+ }
110
+ };
111
+ console.warn = (...args) => {
112
+ if (this.isInitialized) {
113
+ this.sendLogNotification("warning", args);
114
+ }
115
+ else {
116
+ this.messageBuffer.push({
117
+ level: "warning",
118
+ args,
119
+ timestamp: Date.now()
120
+ });
121
+ }
122
+ };
123
+ console.error = (...args) => {
124
+ if (this.isInitialized) {
125
+ this.sendLogNotification("error", args);
126
+ }
127
+ else {
128
+ this.messageBuffer.push({
129
+ level: "error",
130
+ args,
131
+ timestamp: Date.now()
132
+ });
133
+ }
134
+ };
135
+ console.debug = (...args) => {
136
+ if (this.isInitialized) {
137
+ this.sendLogNotification("debug", args);
138
+ }
139
+ else {
140
+ this.messageBuffer.push({
141
+ level: "debug",
142
+ args,
143
+ timestamp: Date.now()
144
+ });
145
+ }
146
+ };
147
+ }
148
+ setupStdoutFiltering() {
149
+ process.stdout.write = (buffer, encoding, callback) => {
150
+ // Handle different call signatures
151
+ if (typeof buffer === 'string') {
152
+ const trimmed = buffer.trim();
153
+ // Check if this looks like a valid JSON-RPC message
154
+ if (trimmed.startsWith('{') && (trimmed.includes('"jsonrpc"') ||
155
+ trimmed.includes('"method"') ||
156
+ trimmed.includes('"id"'))) {
157
+ // This looks like a valid JSON-RPC message, allow it
158
+ return this.originalStdoutWrite.call(process.stdout, buffer, encoding, callback);
159
+ }
160
+ else if (trimmed.length > 0) {
161
+ // Non-JSON-RPC output, wrap it in a log notification
162
+ if (this.isInitialized) {
163
+ this.sendLogNotification("info", [buffer.replace(/\n$/, '')]);
164
+ }
165
+ else {
166
+ // Buffer for later replay to client
167
+ this.messageBuffer.push({
168
+ level: "info",
169
+ args: [buffer.replace(/\n$/, '')],
170
+ timestamp: Date.now()
171
+ });
172
+ }
173
+ if (callback)
174
+ callback();
175
+ return true;
176
+ }
177
+ }
178
+ // For non-string buffers or empty strings, let them through
179
+ return this.originalStdoutWrite.call(process.stdout, buffer, encoding, callback);
180
+ };
181
+ }
182
+ sendLogNotification(level, args) {
183
+ // Skip if notifications are disabled (e.g., for Cline)
184
+ if (this.disableNotifications) {
185
+ return;
186
+ }
187
+ try {
188
+ // For data, we can send structured data or string according to MCP spec
189
+ let data;
190
+ if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) {
191
+ // Single object - send as structured data
192
+ data = args[0];
193
+ }
194
+ else {
195
+ // Multiple args or primitives - convert to string
196
+ data = args.map(arg => {
197
+ if (typeof arg === 'object') {
198
+ try {
199
+ return JSON.stringify(arg, null, 2);
200
+ }
201
+ catch {
202
+ return String(arg);
203
+ }
204
+ }
205
+ return String(arg);
206
+ }).join(' ');
207
+ }
208
+ const notification = {
209
+ jsonrpc: "2.0",
210
+ method: "notifications/message",
211
+ params: {
212
+ level: level,
213
+ logger: "mcp-device",
214
+ data: data
215
+ }
216
+ };
217
+ // Send as valid JSON-RPC notification
218
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(notification) + '\n');
219
+ }
220
+ catch (error) {
221
+ // Fallback to a simple JSON-RPC error notification if JSON serialization fails
222
+ const fallbackNotification = {
223
+ jsonrpc: "2.0",
224
+ method: "notifications/message",
225
+ params: {
226
+ level: "error",
227
+ logger: "mcp-device",
228
+ data: `Log serialization failed: ${args.join(' ')}`
229
+ }
230
+ };
231
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(fallbackNotification) + '\n');
232
+ }
233
+ }
234
+ /**
235
+ * Public method to send log notifications from anywhere in the application
236
+ * Now properly buffers messages before MCP initialization to avoid breaking stdio protocol
237
+ */
238
+ sendLog(level, message, data) {
239
+ // Skip if notifications are disabled (e.g., for Cline)
240
+ if (this.disableNotifications) {
241
+ return;
242
+ }
243
+ // Buffer messages before initialization to avoid breaking MCP protocol
244
+ // MCP requires client to send first message - server cannot write to stdout before that
245
+ if (!this.isInitialized) {
246
+ this.messageBuffer.push({
247
+ level,
248
+ args: [data ? { message, ...data } : message],
249
+ timestamp: Date.now()
250
+ });
251
+ return;
252
+ }
253
+ try {
254
+ const notification = {
255
+ jsonrpc: "2.0",
256
+ method: "notifications/message",
257
+ params: {
258
+ level: level,
259
+ logger: "mcp-device",
260
+ data: data ? { message, ...data } : message
261
+ }
262
+ };
263
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(notification) + '\n');
264
+ }
265
+ catch (error) {
266
+ // Fallback to basic JSON-RPC notification
267
+ const fallbackNotification = {
268
+ jsonrpc: "2.0",
269
+ method: "notifications/message",
270
+ params: {
271
+ level: "error",
272
+ logger: "mcp-device",
273
+ data: `sendLog failed: ${message}`
274
+ }
275
+ };
276
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(fallbackNotification) + '\n');
277
+ }
278
+ }
279
+ /**
280
+ * Send a progress notification (useful for long-running operations)
281
+ */
282
+ sendProgress(token, value, total) {
283
+ // Don't send progress before initialization - would break MCP protocol
284
+ if (!this.isInitialized) {
285
+ return;
286
+ }
287
+ try {
288
+ const notification = {
289
+ jsonrpc: "2.0",
290
+ method: "notifications/progress",
291
+ params: {
292
+ progressToken: token,
293
+ value: value,
294
+ ...(total && { total })
295
+ }
296
+ };
297
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(notification) + '\n');
298
+ }
299
+ catch (error) {
300
+ // Fallback to basic JSON-RPC notification for progress
301
+ const fallbackNotification = {
302
+ jsonrpc: "2.0",
303
+ method: "notifications/message",
304
+ params: {
305
+ level: "info",
306
+ logger: "mcp-device",
307
+ data: `Progress ${token}: ${value}${total ? `/${total}` : ''}`
308
+ }
309
+ };
310
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(fallbackNotification) + '\n');
311
+ }
312
+ }
313
+ /**
314
+ * Send a custom notification with any method name
315
+ */
316
+ sendCustomNotification(method, params) {
317
+ // Don't send custom notifications before initialization - would break MCP protocol
318
+ if (!this.isInitialized) {
319
+ return;
320
+ }
321
+ try {
322
+ const notification = {
323
+ jsonrpc: "2.0",
324
+ method: method,
325
+ params: params
326
+ };
327
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(notification) + '\n');
328
+ }
329
+ catch (error) {
330
+ // Fallback to basic JSON-RPC notification for custom notifications
331
+ const fallbackNotification = {
332
+ jsonrpc: "2.0",
333
+ method: "notifications/message",
334
+ params: {
335
+ level: "error",
336
+ logger: "mcp-device",
337
+ data: `Custom notification failed: ${method}: ${JSON.stringify(params)}`
338
+ }
339
+ };
340
+ this.originalStdoutWrite.call(process.stdout, JSON.stringify(fallbackNotification) + '\n');
341
+ }
342
+ }
343
+ /**
344
+ * Cleanup method to restore original console methods if needed
345
+ */
346
+ cleanup() {
347
+ if (this.originalConsole) {
348
+ console.log = this.originalConsole.log;
349
+ console.warn = this.originalConsole.warn;
350
+ console.error = this.originalConsole.error;
351
+ console.debug = this.originalConsole.debug;
352
+ console.info = this.originalConsole.info;
353
+ }
354
+ if (this.originalStdoutWrite) {
355
+ process.stdout.write = this.originalStdoutWrite;
356
+ }
357
+ }
358
+ }
@@ -0,0 +1,12 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIBrzCCAVagAwIBAgIUJT4N8vTRvyxp9rlhfHuY8OOJvB4wCgYIKoZIzj0EAwIw
3
+ JDEiMCAGA1UEAwwZTUNQIERldmljZSBBcHBsaWNhdGlvbiBDQTAeFw0yNjA5MTYx
4
+ NDMyNDVaFw0zNjA5MTMxNDMyNDVaMCQxIjAgBgNVBAMMGU1DUCBEZXZpY2UgQXBw
5
+ bGljYXRpb24gQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARFvReUGN6fAVYg
6
+ FF4UTn6F7KQ78b9yhkBU9qBy1XEMnCJqpn07rxKQszaB/ABb0awH0kIQuOUt+NA/
7
+ 7iUVeyA4o2YwZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAd
8
+ BgNVHQ4EFgQUMtlUKf+st0jgEdxhESpzROwRDW0wHwYDVR0jBBgwFoAUMtlUKf+s
9
+ t0jgEdxhESpzROwRDW0wCgYIKoZIzj0EAwIDRwAwRAIgbjQRULWIJp+zuwOEQgVo
10
+ 9Y+3UygTogcwDkylzlR21lwCIDwbk3Vp07JVK7qBCLL9JplP8j4UWTTXVe5Oi+xJ
11
+ japd
12
+ -----END CERTIFICATE-----
@@ -0,0 +1,70 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "description": "Desktop Commander onboarding prompts - V2 simplified (5 prompts only)",
4
+ "prompts": [
5
+ {
6
+ "id": "onb2_01",
7
+ "title": "Organize my Downloads folder",
8
+ "description": "Clean up and organize your messy Downloads folder into relevant subfolders automatically.",
9
+ "prompt": "Let's organize your Downloads folder! \n\nFirst, let me check what we're working with. I'll look at your Downloads folder to see how many files are there and what types.\n\nShould I start by analyzing your Downloads folder?",
10
+ "categories": ["onboarding"],
11
+ "secondaryTag": "Quick Start",
12
+ "votes": 0,
13
+ "gaClicks": 0,
14
+ "icon": "FolderOpen",
15
+ "author": "DC team",
16
+ "verified": true
17
+ },
18
+ {
19
+ "id": "onb2_02",
20
+ "title": "Explain codebase or repository to me",
21
+ "description": "Analyze and explain any codebase - local project or GitHub repository - including architecture, dependencies, and how it works.",
22
+ "prompt": "I'll analyze and explain any codebase for you! 🔍\n\n**What should I analyze?**\n\n*Local project:* `~/work/my-project` (replace with your path)\n*GitHub repo:* `https://github.com/user/repo`\n\nI'll break down the architecture, dependencies, and how everything works together!",
23
+ "categories": ["onboarding"], "secondaryTag": "Code Analysis",
24
+ "votes": 0,
25
+ "gaClicks": 0,
26
+ "icon": "Code",
27
+ "author": "DC team",
28
+ "verified": true
29
+ },
30
+ {
31
+ "id": "onb2_03",
32
+ "title": "Create organized knowledge/documents folder",
33
+ "description": "Set up a well-structured knowledge base or document organization system with templates and suggested categories.",
34
+ "prompt": "Let's create an organized knowledge base! 📚\n\n**Where should I set it up?**\n\n*I suggest: `~/Documents/Knowledge-Base` (replace with your path) or give me a different location.*\n\nI'll create a clean folder structure with templates and organize any existing documents you have!",
35
+ "categories": ["onboarding"],
36
+ "secondaryTag": "Quick Start",
37
+ "votes": 0,
38
+ "gaClicks": 0,
39
+ "icon": "BookOpen",
40
+ "author": "DC team",
41
+ "verified": true
42
+ },
43
+ {
44
+ "id": "onb2_04",
45
+ "title": "Analyze my data file",
46
+ "description": "Upload or point to any data file (CSV, JSON, Excel, etc.) and get comprehensive analysis including patterns, insights, and summary reports.",
47
+ "prompt": "I'll help you analyze your data file! \n\nWhat's the path to your data file? (e.g., `/Users/yourname/data.csv`)\n\nOnce you give me the path, I'll start by checking what type of file it is and show you a quick preview, then we can dive deeper step by step.",
48
+ "categories": ["onboarding"],
49
+ "secondaryTag": "Quick Start",
50
+ "votes": 0,
51
+ "gaClicks": 0,
52
+ "icon": "BarChart3",
53
+ "author": "DC team",
54
+ "verified": true
55
+ },
56
+ {
57
+ "id": "onb2_05",
58
+ "title": "Check system health and resources",
59
+ "description": "Analyze your system's health, resource usage, running processes, and generate a comprehensive system status report.",
60
+ "prompt": "Let me check your system health and resources!\n\nI'll start by looking at your CPU, memory, and disk usage, then check for any performance issues.\n\nShould I begin the system analysis?",
61
+ "categories": ["onboarding"],
62
+ "secondaryTag": "Quick Start",
63
+ "votes": 0,
64
+ "gaClicks": 0,
65
+ "icon": "Activity",
66
+ "author": "DC team",
67
+ "verified": true
68
+ }
69
+ ]
70
+ }
@@ -0,0 +1,13 @@
1
+ export declare const DEVICE_STATE_FILES: readonly string[];
2
+ export interface DeviceStatePaths {
3
+ root: string;
4
+ legacyRoot: string;
5
+ identity: string;
6
+ config: string;
7
+ status: string;
8
+ }
9
+ export declare function deviceStatePaths(home?: string): DeviceStatePaths;
10
+ export declare function migrateLegacyDeviceState(paths?: DeviceStatePaths): Promise<{
11
+ migrated: string[];
12
+ legacyStateSeen: boolean;
13
+ }>;
@@ -0,0 +1,100 @@
1
+ import fs from 'fs/promises';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ export const DEVICE_STATE_FILES = Object.freeze([
5
+ 'gateway-identity.json',
6
+ 'gateway-config.json',
7
+ 'gateway-status.json'
8
+ ]);
9
+ export function deviceStatePaths(home = os.homedir()) {
10
+ const root = path.resolve(home, '.mcp-device');
11
+ const legacyRoot = path.resolve(home, '.hcu-device');
12
+ return {
13
+ root,
14
+ legacyRoot,
15
+ identity: path.join(root, 'gateway-identity.json'),
16
+ config: path.join(root, 'gateway-config.json'),
17
+ status: path.join(root, 'gateway-status.json')
18
+ };
19
+ }
20
+ async function readJsonIfExists(filePath) {
21
+ try {
22
+ return JSON.parse(await fs.readFile(filePath, 'utf8'));
23
+ }
24
+ catch (error) {
25
+ if (error?.code === 'ENOENT')
26
+ return null;
27
+ throw new Error(`Invalid MCP Device state file ${filePath}: ${error?.message || error}`);
28
+ }
29
+ }
30
+ async function copyAtomic(source, target) {
31
+ const content = await fs.readFile(source);
32
+ await fs.mkdir(path.dirname(target), { recursive: true, mode: 0o700 });
33
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
34
+ await fs.writeFile(temporary, content, { mode: 0o600, flag: 'wx' });
35
+ await fs.rename(temporary, target);
36
+ try {
37
+ await fs.chmod(target, 0o600);
38
+ }
39
+ catch { /* Windows ACLs inherit from the user profile. */ }
40
+ }
41
+ function identityFingerprint(value) {
42
+ if (!value)
43
+ return null;
44
+ const deviceId = String(value.deviceId || '').trim();
45
+ const publicKeyPem = String(value.publicKeyPem || '').trim();
46
+ return deviceId && publicKeyPem ? `${deviceId}\n${publicKeyPem}` : null;
47
+ }
48
+ export async function migrateLegacyDeviceState(paths = deviceStatePaths()) {
49
+ await fs.mkdir(paths.root, { recursive: true, mode: 0o700 });
50
+ const legacyIdentityPath = path.join(paths.legacyRoot, 'gateway-identity.json');
51
+ const canonicalIdentity = await readJsonIfExists(paths.identity);
52
+ const legacyIdentity = await readJsonIfExists(legacyIdentityPath);
53
+ const legacyPresence = await Promise.all(DEVICE_STATE_FILES.map(async (name) => {
54
+ try {
55
+ await fs.access(path.join(paths.legacyRoot, name));
56
+ return true;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }));
62
+ const legacyStateSeen = legacyPresence.some(Boolean);
63
+ if (canonicalIdentity && legacyIdentity) {
64
+ const canonicalFingerprint = identityFingerprint(canonicalIdentity);
65
+ const legacyFingerprint = identityFingerprint(legacyIdentity);
66
+ if (!canonicalFingerprint || !legacyFingerprint || canonicalFingerprint !== legacyFingerprint) {
67
+ throw new Error('MCP Device migration conflict: canonical and legacy device identities differ.');
68
+ }
69
+ }
70
+ if (legacyStateSeen && !legacyIdentity && !canonicalIdentity) {
71
+ throw new Error('MCP Device migration failed closed: legacy state exists without a device identity.');
72
+ }
73
+ const migrated = [];
74
+ for (const name of DEVICE_STATE_FILES) {
75
+ const source = path.join(paths.legacyRoot, name);
76
+ const target = path.join(paths.root, name);
77
+ let sourceExists = true;
78
+ try {
79
+ await fs.access(source);
80
+ }
81
+ catch {
82
+ sourceExists = false;
83
+ }
84
+ if (!sourceExists)
85
+ continue;
86
+ await readJsonIfExists(source);
87
+ let targetExists = true;
88
+ try {
89
+ await fs.access(target);
90
+ }
91
+ catch {
92
+ targetExists = false;
93
+ }
94
+ if (!targetExists) {
95
+ await copyAtomic(source, target);
96
+ migrated.push(name);
97
+ }
98
+ }
99
+ return { migrated, legacyStateSeen };
100
+ }
@@ -0,0 +1,81 @@
1
+ export interface GatewayAccountStatus {
2
+ connected: boolean;
3
+ label: string | null;
4
+ }
5
+ export interface GatewayUsageStatus {
6
+ connections: number;
7
+ reconnects: number;
8
+ toolCallsStarted: number;
9
+ toolCallsSucceeded: number;
10
+ toolCallsFailed: number;
11
+ requestBytes: number;
12
+ responseBytes: number;
13
+ lastSeenAt: number | null;
14
+ lastErrorCode: string | null;
15
+ }
16
+ export interface GatewaySchemaStatus {
17
+ toolCount: number;
18
+ toolSchemaBytes: number;
19
+ toolSchemaTokenEstimate: number;
20
+ tokenEstimateMethod: string;
21
+ tokenUsageKind: 'schema_estimate_not_billing';
22
+ }
23
+ export interface GatewayDeviceStatus {
24
+ version: 1;
25
+ gatewayUrl: string | null;
26
+ deviceId: string | null;
27
+ deviceName: string | null;
28
+ identityPresent: boolean;
29
+ account: GatewayAccountStatus;
30
+ connection: {
31
+ online: boolean;
32
+ connectionEpoch: number | string | null;
33
+ lastConnectedAt: number | null;
34
+ };
35
+ usage: GatewayUsageStatus | null;
36
+ schema: GatewaySchemaStatus | null;
37
+ usageFreshAt: number | null;
38
+ }
39
+ export interface GatewayServiceStatus {
40
+ installed: boolean;
41
+ running: boolean;
42
+ autostart?: boolean;
43
+ registration?: 'task' | 'run' | 'manual' | 'stale';
44
+ taskName?: string | null;
45
+ }
46
+ export interface GatewaySecurityStatus {
47
+ protocolFloor: number;
48
+ appCaProvisioned: boolean;
49
+ }
50
+ export interface GatewayProxyStatus {
51
+ mode: 'direct' | 'configured';
52
+ }
53
+ export declare class GatewayDeviceStatusStore {
54
+ readonly statusPath: string;
55
+ constructor(statusPath?: string);
56
+ load(): Promise<GatewayDeviceStatus>;
57
+ update(patch: Partial<GatewayDeviceStatus>): Promise<GatewayDeviceStatus>;
58
+ markOffline(): Promise<GatewayDeviceStatus>;
59
+ clearAccount(): Promise<GatewayDeviceStatus>;
60
+ private persist;
61
+ }
62
+ export declare function effectiveGatewayStatus(status: GatewayDeviceStatus, { runtimeOwned, serviceRunning }?: {
63
+ runtimeOwned?: boolean | undefined;
64
+ serviceRunning?: boolean | undefined;
65
+ }): GatewayDeviceStatus;
66
+ export declare function formatGatewayStatus(status: GatewayDeviceStatus, options?: {
67
+ json?: boolean;
68
+ service?: GatewayServiceStatus;
69
+ security?: GatewaySecurityStatus;
70
+ proxy?: GatewayProxyStatus;
71
+ runtime?: {
72
+ mode: string;
73
+ pid: number;
74
+ } | null;
75
+ managers?: Array<{
76
+ manager: string;
77
+ installed: boolean;
78
+ running: boolean;
79
+ autostart: boolean;
80
+ }>;
81
+ }): string;