@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,72 @@
1
+ /**
2
+ * Centralized logging utility for MCP Device
3
+ * Ensures all logging goes through proper channels based on initialization state
4
+ */
5
+ /**
6
+ * Log a message using the appropriate method based on MCP initialization state
7
+ */
8
+ export function log(level, message, data) {
9
+ try {
10
+ // Check if MCP transport is available
11
+ if (global.mcpTransport) {
12
+ // Always use MCP logging (will buffer if not initialized yet)
13
+ global.mcpTransport.sendLog(level, message, data);
14
+ }
15
+ else {
16
+ // This should rarely happen, but fallback to create a JSON-RPC notification manually
17
+ const notification = {
18
+ jsonrpc: "2.0",
19
+ method: "notifications/message",
20
+ params: {
21
+ level: level,
22
+ logger: "mcp-device",
23
+ data: data ? { message, ...data } : message
24
+ }
25
+ };
26
+ process.stdout.write(JSON.stringify(notification) + '\n');
27
+ }
28
+ }
29
+ catch (error) {
30
+ // Ultimate fallback - but this should be JSON-RPC too
31
+ const notification = {
32
+ jsonrpc: "2.0",
33
+ method: "notifications/message",
34
+ params: {
35
+ level: "error",
36
+ logger: "mcp-device",
37
+ data: `[LOG-ERROR] Failed to log message: ${message}`
38
+ }
39
+ };
40
+ process.stdout.write(JSON.stringify(notification) + '\n');
41
+ }
42
+ }
43
+ /**
44
+ * Convenience functions for different log levels
45
+ */
46
+ export const logger = {
47
+ emergency: (message, data) => log('emergency', message, data),
48
+ alert: (message, data) => log('alert', message, data),
49
+ critical: (message, data) => log('critical', message, data),
50
+ error: (message, data) => log('error', message, data),
51
+ warning: (message, data) => log('warning', message, data),
52
+ notice: (message, data) => log('notice', message, data),
53
+ info: (message, data) => log('info', message, data),
54
+ debug: (message, data) => log('debug', message, data),
55
+ };
56
+ /**
57
+ * Log to stderr during early initialization (before MCP is ready)
58
+ * Use this for critical startup messages that must be visible
59
+ * NOTE: This should also be JSON-RPC format
60
+ */
61
+ export function logToStderr(level, message) {
62
+ const notification = {
63
+ jsonrpc: "2.0",
64
+ method: "notifications/message",
65
+ params: {
66
+ level: level,
67
+ logger: "mcp-device",
68
+ data: message
69
+ }
70
+ };
71
+ process.stdout.write(JSON.stringify(notification) + '\n');
72
+ }
@@ -0,0 +1,13 @@
1
+ export declare const MCP_UI_EXPERIMENT_NAME = "McpUiPreviews";
2
+ export declare const MCP_UI_SHOW_VARIANT = "showMCPUi";
3
+ export declare const MCP_UI_HIDE_VARIANT = "notShowMCPUi";
4
+ export interface McpUiPreviewDecisionDeps {
5
+ getExistingAssignment: () => Promise<unknown>;
6
+ isFirstRun: () => boolean;
7
+ wasLoadedFromCache: () => boolean;
8
+ waitForFreshFlags: () => Promise<void>;
9
+ getABTestVariant: (experimentName: string) => Promise<string | null>;
10
+ capture: (event: string, properties?: Record<string, unknown>) => Promise<unknown> | unknown;
11
+ }
12
+ export declare function resolveMcpUiPreviewDecision(deps: McpUiPreviewDecisionDeps): Promise<boolean>;
13
+ export declare function shouldShowMcpUiPreviews(): Promise<boolean>;
@@ -0,0 +1,62 @@
1
+ import { configManager } from '../config-manager.js';
2
+ import { getABTestVariant } from './ab-test.js';
3
+ import { capture } from './capture.js';
4
+ import { featureFlagManager } from './feature-flags.js';
5
+ export const MCP_UI_EXPERIMENT_NAME = 'McpUiPreviews';
6
+ export const MCP_UI_SHOW_VARIANT = 'showMCPUi';
7
+ export const MCP_UI_HIDE_VARIANT = 'notShowMCPUi';
8
+ function variantEnablesMcpUi(variant) {
9
+ if (variant === MCP_UI_HIDE_VARIANT)
10
+ return false;
11
+ if (variant === MCP_UI_SHOW_VARIANT)
12
+ return true;
13
+ return null;
14
+ }
15
+ export async function resolveMcpUiPreviewDecision(deps) {
16
+ try {
17
+ const existingAssignment = await deps.getExistingAssignment();
18
+ const existingDecision = variantEnablesMcpUi(existingAssignment);
19
+ if (existingDecision !== null) {
20
+ if (!deps.wasLoadedFromCache()) {
21
+ await deps.waitForFreshFlags();
22
+ }
23
+ const currentVariant = await deps.getABTestVariant(MCP_UI_EXPERIMENT_NAME);
24
+ return variantEnablesMcpUi(currentVariant) ?? existingDecision;
25
+ }
26
+ if (!deps.isFirstRun()) {
27
+ return true;
28
+ }
29
+ if (!deps.wasLoadedFromCache()) {
30
+ await deps.waitForFreshFlags();
31
+ }
32
+ const variant = await deps.getABTestVariant(MCP_UI_EXPERIMENT_NAME);
33
+ const decision = variantEnablesMcpUi(variant);
34
+ if (decision === null) {
35
+ return true;
36
+ }
37
+ try {
38
+ await deps.capture('server_mcp_ui_ab_decision', {
39
+ experiment: MCP_UI_EXPERIMENT_NAME,
40
+ variant,
41
+ mcp_ui_enabled: decision,
42
+ });
43
+ }
44
+ catch {
45
+ // Telemetry must not change the assigned product experience.
46
+ }
47
+ return decision;
48
+ }
49
+ catch {
50
+ return true;
51
+ }
52
+ }
53
+ export async function shouldShowMcpUiPreviews() {
54
+ return resolveMcpUiPreviewDecision({
55
+ getExistingAssignment: () => configManager.getValue(`abTest_${MCP_UI_EXPERIMENT_NAME}`),
56
+ isFirstRun: () => configManager.isFirstRun(),
57
+ wasLoadedFromCache: () => featureFlagManager.wasLoadedFromCache(),
58
+ waitForFreshFlags: () => featureFlagManager.waitForFreshFlags(),
59
+ getABTestVariant,
60
+ capture,
61
+ });
62
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Open a URL in the default browser (cross-platform)
3
+ * Uses execFile/spawn with args array to avoid shell injection
4
+ */
5
+ export declare function openBrowser(url: string): Promise<void>;
6
+ /**
7
+ * Open the MCP Device project page.
8
+ */
9
+ export declare function openWelcomePage(_clientName?: string): Promise<void>;
@@ -0,0 +1,42 @@
1
+ import { execFile, spawn } from 'child_process';
2
+ import os from 'os';
3
+ import { logToStderr } from './logger.js';
4
+ /**
5
+ * Open a URL in the default browser (cross-platform)
6
+ * Uses execFile/spawn with args array to avoid shell injection
7
+ */
8
+ export async function openBrowser(url) {
9
+ const platform = os.platform();
10
+ return new Promise((resolve, reject) => {
11
+ const callback = (error) => {
12
+ if (error) {
13
+ logToStderr('error', `Failed to open browser: ${error.message}`);
14
+ reject(error);
15
+ }
16
+ else {
17
+ logToStderr('info', `Opened browser to: ${url}`);
18
+ resolve();
19
+ }
20
+ };
21
+ switch (platform) {
22
+ case 'darwin':
23
+ execFile('open', [url], callback);
24
+ break;
25
+ case 'win32':
26
+ // Windows 'start' is a shell builtin, use spawn with shell but pass URL as separate arg
27
+ spawn('cmd', ['/c', 'start', '', url], { shell: false, windowsHide: true }).on('close', (code) => {
28
+ code === 0 ? resolve() : reject(new Error(`Exit code ${code}`));
29
+ });
30
+ break;
31
+ default:
32
+ execFile('xdg-open', [url], callback);
33
+ break;
34
+ }
35
+ });
36
+ }
37
+ /**
38
+ * Open the MCP Device project page.
39
+ */
40
+ export async function openWelcomePage(_clientName) {
41
+ await openBrowser('https://github.com/Hiroshimeow/agent-mcp-device#readme');
42
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * REPL and Process State Detection Utilities
3
+ * Detects when processes are waiting for input vs finished vs running
4
+ */
5
+ export interface ProcessState {
6
+ isWaitingForInput: boolean;
7
+ isFinished: boolean;
8
+ isRunning: boolean;
9
+ detectedPrompt?: string;
10
+ lastOutput: string;
11
+ }
12
+ /**
13
+ * Analyze process output to determine current state
14
+ */
15
+ export declare function analyzeProcessState(output: string, pid?: number): ProcessState;
16
+ /**
17
+ * Clean output by removing prompts and input echoes
18
+ */
19
+ export declare function cleanProcessOutput(output: string, inputSent?: string): string;
20
+ /**
21
+ * Format process state for user display
22
+ */
23
+ export declare function formatProcessStateMessage(state: ProcessState, pid: number): string;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * REPL and Process State Detection Utilities
3
+ * Detects when processes are waiting for input vs finished vs running
4
+ */
5
+ // Common REPL prompt patterns
6
+ const REPL_PROMPTS = {
7
+ python: ['>>> ', '... '],
8
+ node: ['> ', '... '],
9
+ r: ['> ', '+ '],
10
+ julia: ['julia> ', ' '], // julia continuation is spaces
11
+ shell: ['$ ', '# ', '% ', 'bash-', 'zsh-'],
12
+ mysql: ['mysql> ', ' -> '],
13
+ postgres: ['=# ', '-# '],
14
+ redis: ['redis> '],
15
+ mongo: ['> ', '... ']
16
+ };
17
+ // Error patterns that indicate completion (even with errors)
18
+ const ERROR_COMPLETION_PATTERNS = [
19
+ /Error:/i,
20
+ /Exception:/i,
21
+ /Traceback/i,
22
+ /SyntaxError/i,
23
+ /NameError/i,
24
+ /TypeError/i,
25
+ /ValueError/i,
26
+ /ReferenceError/i,
27
+ /Uncaught/i,
28
+ /at Object\./i, // Node.js stack traces
29
+ /^\s*\^/m // Syntax error indicators
30
+ ];
31
+ // Process completion indicators
32
+ const COMPLETION_INDICATORS = [
33
+ /Process finished/i,
34
+ /Command completed/i,
35
+ /\[Process completed\]/i,
36
+ /Program terminated/i,
37
+ /Exit code:/i
38
+ ];
39
+ /**
40
+ * Analyze process output to determine current state
41
+ */
42
+ export function analyzeProcessState(output, pid) {
43
+ if (!output || output.trim().length === 0) {
44
+ return {
45
+ isWaitingForInput: false,
46
+ isFinished: false,
47
+ isRunning: true,
48
+ lastOutput: output
49
+ };
50
+ }
51
+ const lines = output.split('\n');
52
+ const lastLine = lines[lines.length - 1] || '';
53
+ const lastFewLines = lines.slice(-3).join('\n');
54
+ // Check for REPL prompts (waiting for input)
55
+ const allPrompts = Object.values(REPL_PROMPTS).flat();
56
+ const detectedPrompt = allPrompts.find(prompt => lastLine.endsWith(prompt) || lastLine.includes(prompt));
57
+ if (detectedPrompt) {
58
+ return {
59
+ isWaitingForInput: true,
60
+ isFinished: false,
61
+ isRunning: true,
62
+ detectedPrompt,
63
+ lastOutput: output
64
+ };
65
+ }
66
+ // Check for completion indicators
67
+ const hasCompletionIndicator = COMPLETION_INDICATORS.some(pattern => pattern.test(output));
68
+ if (hasCompletionIndicator) {
69
+ return {
70
+ isWaitingForInput: false,
71
+ isFinished: true,
72
+ isRunning: false,
73
+ lastOutput: output
74
+ };
75
+ }
76
+ // Check for error completion (errors usually end with prompts, but let's be thorough)
77
+ const hasErrorCompletion = ERROR_COMPLETION_PATTERNS.some(pattern => pattern.test(lastFewLines));
78
+ if (hasErrorCompletion) {
79
+ // Errors can indicate completion, but check if followed by prompt
80
+ if (detectedPrompt) {
81
+ return {
82
+ isWaitingForInput: true,
83
+ isFinished: false,
84
+ isRunning: true,
85
+ detectedPrompt,
86
+ lastOutput: output
87
+ };
88
+ }
89
+ else {
90
+ return {
91
+ isWaitingForInput: false,
92
+ isFinished: true,
93
+ isRunning: false,
94
+ lastOutput: output
95
+ };
96
+ }
97
+ }
98
+ // Default: process is running, not clearly waiting or finished
99
+ return {
100
+ isWaitingForInput: false,
101
+ isFinished: false,
102
+ isRunning: true,
103
+ lastOutput: output
104
+ };
105
+ }
106
+ /**
107
+ * Clean output by removing prompts and input echoes
108
+ */
109
+ export function cleanProcessOutput(output, inputSent) {
110
+ let cleaned = output;
111
+ // Remove input echo if provided
112
+ if (inputSent) {
113
+ const inputLines = inputSent.split('\n');
114
+ inputLines.forEach(line => {
115
+ if (line.trim()) {
116
+ cleaned = cleaned.replace(new RegExp(`^${escapeRegExp(line.trim())}\\s*\n?`, 'm'), '');
117
+ }
118
+ });
119
+ }
120
+ // Remove common prompt patterns from output
121
+ cleaned = cleaned.replace(/^>>>\s*/gm, ''); // Python >>>
122
+ cleaned = cleaned.replace(/^>\s*/gm, ''); // Node.js/Shell >
123
+ cleaned = cleaned.replace(/^\.{3}\s*/gm, ''); // Python ...
124
+ cleaned = cleaned.replace(/^\+\s*/gm, ''); // R +
125
+ // Remove trailing prompts
126
+ cleaned = cleaned.replace(/\n>>>\s*$/, '');
127
+ cleaned = cleaned.replace(/\n>\s*$/, '');
128
+ cleaned = cleaned.replace(/\n\+\s*$/, '');
129
+ return cleaned.trim();
130
+ }
131
+ /**
132
+ * Escape special regex characters
133
+ */
134
+ function escapeRegExp(string) {
135
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
136
+ }
137
+ /**
138
+ * Format process state for user display
139
+ */
140
+ export function formatProcessStateMessage(state, pid) {
141
+ if (state.isWaitingForInput) {
142
+ return `Process ${pid} is waiting for input${state.detectedPrompt ? ` (detected: "${state.detectedPrompt.trim()}")` : ''}`;
143
+ }
144
+ else if (state.isFinished) {
145
+ return `Process ${pid} has finished execution`;
146
+ }
147
+ else {
148
+ return `Process ${pid} is running`;
149
+ }
150
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Resolve ripgrep binary path with multiple fallback strategies
3
+ * This handles cases where @vscode/ripgrep postinstall fails in npx environments
4
+ */
5
+ export declare function getRipgrepPath(): Promise<string>;
6
+ /**
7
+ * Clear the cached ripgrep path (useful for testing)
8
+ */
9
+ export declare function clearRipgrepCache(): void;
@@ -0,0 +1,74 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync, chmodSync } from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ let cachedRgPath = null;
6
+ /**
7
+ * Resolve ripgrep binary path with multiple fallback strategies
8
+ * This handles cases where @vscode/ripgrep postinstall fails in npx environments
9
+ */
10
+ export async function getRipgrepPath() {
11
+ if (cachedRgPath) {
12
+ return cachedRgPath;
13
+ }
14
+ // Strategy 1: Try @vscode/ripgrep package
15
+ try {
16
+ const { rgPath } = await import('@vscode/ripgrep');
17
+ if (existsSync(rgPath)) {
18
+ // Ensure executable permissions on Unix systems
19
+ if (process.platform !== 'win32') {
20
+ try {
21
+ chmodSync(rgPath, 0o755);
22
+ }
23
+ catch (e) {
24
+ // Ignore chmod errors - might not have write access
25
+ }
26
+ }
27
+ cachedRgPath = rgPath;
28
+ return rgPath;
29
+ }
30
+ }
31
+ catch (e) {
32
+ // @vscode/ripgrep import or binary resolution failed, continue to fallbacks
33
+ }
34
+ // Strategy 2: Try system ripgrep using 'which' (Unix) or 'where' (Windows)
35
+ try {
36
+ const systemRg = process.platform === 'win32' ? 'rg.exe' : 'rg';
37
+ const whichCmd = process.platform === 'win32' ? 'where' : 'which';
38
+ const result = execSync(`${whichCmd} ${systemRg}`, { encoding: 'utf-8' }).trim().split(/\r?\n/)[0];
39
+ if (result && existsSync(result)) {
40
+ cachedRgPath = result;
41
+ return result;
42
+ }
43
+ }
44
+ catch (e) {
45
+ // System rg not found via which
46
+ }
47
+ // Strategy 3: Try common installation paths
48
+ const commonPaths = [];
49
+ if (process.platform === 'win32') {
50
+ commonPaths.push('C:\\Program Files\\Ripgrep\\rg.exe', 'C:\\Program Files (x86)\\Ripgrep\\rg.exe', path.join(os.homedir(), 'scoop', 'apps', 'ripgrep', 'current', 'rg.exe'), path.join(os.homedir(), '.cargo', 'bin', 'rg.exe'));
51
+ }
52
+ else {
53
+ commonPaths.push('/usr/local/bin/rg', '/usr/bin/rg', path.join(os.homedir(), '.cargo', 'bin', 'rg'), '/opt/homebrew/bin/rg' // Apple Silicon Homebrew
54
+ );
55
+ }
56
+ for (const possiblePath of commonPaths) {
57
+ if (existsSync(possiblePath)) {
58
+ cachedRgPath = possiblePath;
59
+ return possiblePath;
60
+ }
61
+ }
62
+ // No ripgrep found - provide helpful error message
63
+ throw new Error('ripgrep binary not found. MCP Device requires ripgrep to perform searches. ' +
64
+ 'Please install ripgrep:\n' +
65
+ ' macOS: brew install ripgrep\n' +
66
+ ' Linux: See https://github.com/BurntSushi/ripgrep#installation\n' +
67
+ ' Windows: choco install ripgrep or download from https://github.com/BurntSushi/ripgrep/releases');
68
+ }
69
+ /**
70
+ * Clear the cached ripgrep path (useful for testing)
71
+ */
72
+ export function clearRipgrepCache() {
73
+ cachedRgPath = null;
74
+ }
@@ -0,0 +1,71 @@
1
+ export interface DockerMount {
2
+ hostPath: string;
3
+ containerPath: string;
4
+ type: 'bind' | 'volume';
5
+ readOnly: boolean;
6
+ description: string;
7
+ }
8
+ export interface ContainerInfo {
9
+ isContainer: boolean;
10
+ containerType: 'docker' | 'podman' | 'kubernetes' | 'lxc' | 'systemd-nspawn' | 'other' | null;
11
+ orchestrator: 'kubernetes' | 'docker-compose' | 'docker-swarm' | 'podman-compose' | null;
12
+ isDocker: boolean;
13
+ mountPoints: DockerMount[];
14
+ containerEnvironment?: {
15
+ dockerImage?: string;
16
+ containerName?: string;
17
+ hostPlatform?: string;
18
+ kubernetesNamespace?: string;
19
+ kubernetesPod?: string;
20
+ kubernetesNode?: string;
21
+ };
22
+ }
23
+ export interface SystemInfo {
24
+ platform: string;
25
+ platformName: string;
26
+ defaultShell: string;
27
+ pathSeparator: string;
28
+ isWindows: boolean;
29
+ isMacOS: boolean;
30
+ isLinux: boolean;
31
+ docker: ContainerInfo;
32
+ isDXT: boolean;
33
+ nodeInfo?: {
34
+ version: string;
35
+ path: string;
36
+ npmVersion?: string;
37
+ };
38
+ pythonInfo?: {
39
+ available: boolean;
40
+ command: string;
41
+ version?: string;
42
+ };
43
+ processInfo: {
44
+ pid: number;
45
+ arch: string;
46
+ platform: string;
47
+ versions: NodeJS.ProcessVersions;
48
+ };
49
+ examplePaths: {
50
+ home: string;
51
+ temp: string;
52
+ absolute: string;
53
+ accessible?: string[];
54
+ };
55
+ }
56
+ /**
57
+ * Get comprehensive system information for tool prompts
58
+ */
59
+ export declare function getSystemInfo(): SystemInfo;
60
+ /**
61
+ * Generate OS-specific guidance for tool prompts
62
+ */
63
+ export declare function getOSSpecificGuidance(systemInfo: SystemInfo): string;
64
+ /**
65
+ * Get common development tool guidance based on OS
66
+ */
67
+ export declare function getDevelopmentToolGuidance(systemInfo: SystemInfo): string;
68
+ /**
69
+ * Get path guidance (simplified since paths are normalized)
70
+ */
71
+ export declare function getPathGuidance(systemInfo: SystemInfo): string;