@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,712 @@
1
+ import os from 'os';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { execSync } from 'child_process';
5
+ /**
6
+ * Detect container environment and type
7
+ */
8
+ function detectContainerEnvironment() {
9
+ // Method 1: Check environment variables first (most reliable when set)
10
+ // Docker-specific
11
+ if (process.env.MCP_CLIENT_DOCKER === 'true') {
12
+ return { isContainer: true, containerType: 'docker', orchestrator: null };
13
+ }
14
+ // Kubernetes detection
15
+ if (process.env.KUBERNETES_SERVICE_HOST || process.env.KUBERNETES_PORT) {
16
+ return { isContainer: true, containerType: 'kubernetes', orchestrator: 'kubernetes' };
17
+ }
18
+ // Podman detection
19
+ if (process.env.PODMAN_CONTAINER || process.env.CONTAINER_HOST?.includes('podman')) {
20
+ return { isContainer: true, containerType: 'podman', orchestrator: null };
21
+ }
22
+ // Method 2: Check for container indicator files
23
+ if (fs.existsSync('/.dockerenv')) {
24
+ return { isContainer: true, containerType: 'docker', orchestrator: null };
25
+ }
26
+ // Method 3: Check /proc/1/cgroup for container indicators (Linux only)
27
+ if (os.platform() === 'linux') {
28
+ try {
29
+ const cgroup = fs.readFileSync('/proc/1/cgroup', 'utf8');
30
+ // Docker detection
31
+ if (cgroup.includes('docker')) {
32
+ return { isContainer: true, containerType: 'docker', orchestrator: null };
33
+ }
34
+ // Kubernetes detection (pods run in containerd/cri-o)
35
+ if (cgroup.includes('kubepods') || cgroup.includes('pod')) {
36
+ return { isContainer: true, containerType: 'kubernetes', orchestrator: 'kubernetes' };
37
+ }
38
+ // Podman detection
39
+ if (cgroup.includes('podman') || cgroup.includes('libpod')) {
40
+ return { isContainer: true, containerType: 'podman', orchestrator: null };
41
+ }
42
+ // LXC detection
43
+ if (cgroup.includes('lxc')) {
44
+ return { isContainer: true, containerType: 'lxc', orchestrator: null };
45
+ }
46
+ // systemd-nspawn detection
47
+ if (cgroup.includes('machine.slice')) {
48
+ return { isContainer: true, containerType: 'systemd-nspawn', orchestrator: null };
49
+ }
50
+ // Generic containerd detection
51
+ if (cgroup.includes('containerd')) {
52
+ return { isContainer: true, containerType: 'other', orchestrator: null };
53
+ }
54
+ }
55
+ catch (error) {
56
+ // /proc/1/cgroup might not exist
57
+ }
58
+ }
59
+ // Method 4: Check /proc/1/environ for container indicators
60
+ if (os.platform() === 'linux') {
61
+ try {
62
+ const environ = fs.readFileSync('/proc/1/environ', 'utf8');
63
+ if (environ.includes('container=')) {
64
+ // systemd-nspawn sets container=systemd-nspawn
65
+ if (environ.includes('container=systemd-nspawn')) {
66
+ return { isContainer: true, containerType: 'systemd-nspawn', orchestrator: null };
67
+ }
68
+ // LXC sets container=lxc
69
+ if (environ.includes('container=lxc')) {
70
+ return { isContainer: true, containerType: 'lxc', orchestrator: null };
71
+ }
72
+ // Generic container detection
73
+ return { isContainer: true, containerType: 'other', orchestrator: null };
74
+ }
75
+ }
76
+ catch (error) {
77
+ // /proc/1/environ might not exist or be accessible
78
+ }
79
+ }
80
+ // Method 5: Check hostname for Kubernetes patterns
81
+ try {
82
+ const hostname = os.hostname();
83
+ // Kubernetes pods often have hostnames like: podname-deploymentid-randomid
84
+ if (hostname && (hostname.includes('-') && hostname.split('-').length >= 3)) {
85
+ // Additional check for Kubernetes service account
86
+ if (fs.existsSync('/var/run/secrets/kubernetes.io')) {
87
+ return { isContainer: true, containerType: 'kubernetes', orchestrator: 'kubernetes' };
88
+ }
89
+ }
90
+ }
91
+ catch (error) {
92
+ // Hostname check failed
93
+ }
94
+ // Method 6: Check for orchestrator-specific indicators
95
+ // Docker Compose detection
96
+ if (process.env.COMPOSE_PROJECT_NAME || process.env.COMPOSE_SERVICE) {
97
+ return { isContainer: true, containerType: 'docker', orchestrator: 'docker-compose' };
98
+ }
99
+ // Docker Swarm detection
100
+ if (process.env.DOCKER_SWARM_MODE || process.env.DOCKER_NODE_ID) {
101
+ return { isContainer: true, containerType: 'docker', orchestrator: 'docker-swarm' };
102
+ }
103
+ return { isContainer: false, containerType: null, orchestrator: null };
104
+ }
105
+ /**
106
+ * Discover container mount points
107
+ */
108
+ function discoverContainerMounts(isContainer) {
109
+ const mounts = [];
110
+ if (!isContainer) {
111
+ return mounts;
112
+ }
113
+ // Method 1: Parse /proc/mounts (Linux only)
114
+ if (os.platform() === 'linux') {
115
+ try {
116
+ const mountsContent = fs.readFileSync('/proc/mounts', 'utf8');
117
+ const mountLines = mountsContent.split('\n');
118
+ // System filesystem types that are never user mounts
119
+ const systemFsTypes = new Set([
120
+ 'overlay', 'tmpfs', 'proc', 'sysfs', 'devpts', 'cgroup', 'cgroup2',
121
+ 'mqueue', 'debugfs', 'securityfs', 'pstore', 'configfs', 'fusectl',
122
+ 'hugetlbfs', 'autofs', 'devtmpfs', 'bpf', 'tracefs', 'shm'
123
+ ]);
124
+ // Filesystem types that indicate host mounts
125
+ const hostMountFsTypes = new Set(['fakeowner', '9p', 'virtiofs', 'fuse.sshfs']);
126
+ for (const line of mountLines) {
127
+ const parts = line.split(' ');
128
+ if (parts.length >= 4) {
129
+ const device = parts[0];
130
+ const mountPoint = parts[1];
131
+ const fsType = parts[2];
132
+ const options = parts[3].split(',');
133
+ // Skip system mount points
134
+ const isSystemMountPoint = mountPoint === '/' ||
135
+ mountPoint.startsWith('/dev') ||
136
+ mountPoint.startsWith('/sys') ||
137
+ mountPoint.startsWith('/proc') ||
138
+ mountPoint.startsWith('/run') ||
139
+ mountPoint.startsWith('/sbin') ||
140
+ mountPoint === '/etc/resolv.conf' ||
141
+ mountPoint === '/etc/hostname' ||
142
+ mountPoint === '/etc/hosts';
143
+ if (isSystemMountPoint) {
144
+ continue;
145
+ }
146
+ // Detect user mounts by:
147
+ // 1. Known host-mount filesystem types (fakeowner, 9p, virtiofs)
148
+ // 2. Device from /run/host_mark/ (docker-mcp-gateway pattern)
149
+ // 3. Non-system filesystem type with user-like mount point
150
+ const isHostMountFs = hostMountFsTypes.has(fsType);
151
+ const isHostMarkDevice = device.startsWith('/run/host_mark/');
152
+ const isNonSystemFs = !systemFsTypes.has(fsType);
153
+ const isUserLikePath = mountPoint.startsWith('/mnt/') ||
154
+ mountPoint.startsWith('/workspace') ||
155
+ mountPoint.startsWith('/data/') ||
156
+ mountPoint.startsWith('/home/') ||
157
+ mountPoint.startsWith('/Users/') ||
158
+ mountPoint.startsWith('/app/') ||
159
+ mountPoint.startsWith('/project/') ||
160
+ mountPoint.startsWith('/src/') ||
161
+ mountPoint.startsWith('/code/');
162
+ if (isHostMountFs || isHostMarkDevice || (isNonSystemFs && isUserLikePath)) {
163
+ const isReadOnly = options.includes('ro');
164
+ mounts.push({
165
+ hostPath: device,
166
+ containerPath: mountPoint,
167
+ type: 'bind',
168
+ readOnly: isReadOnly,
169
+ description: `Mounted directory: ${path.basename(mountPoint)}`
170
+ });
171
+ }
172
+ }
173
+ }
174
+ }
175
+ catch (error) {
176
+ // /proc/mounts might not be available
177
+ }
178
+ }
179
+ // Method 2: Check /mnt directory contents
180
+ try {
181
+ if (fs.existsSync('/mnt')) {
182
+ const contents = fs.readdirSync('/mnt');
183
+ for (const item of contents) {
184
+ const itemPath = `/mnt/${item}`;
185
+ try {
186
+ const stats = fs.statSync(itemPath);
187
+ if (stats.isDirectory()) {
188
+ // Check if we already have this mount
189
+ const exists = mounts.some(m => m.containerPath === itemPath);
190
+ if (!exists) {
191
+ mounts.push({
192
+ hostPath: `<host>/${item}`,
193
+ containerPath: itemPath,
194
+ type: 'bind',
195
+ readOnly: false,
196
+ description: `Mounted folder: ${item}`
197
+ });
198
+ }
199
+ }
200
+ }
201
+ catch (itemError) {
202
+ // Skip items we can't stat
203
+ }
204
+ }
205
+ }
206
+ }
207
+ catch (error) {
208
+ // /mnt directory doesn't exist or not accessible
209
+ }
210
+ // Method 3: Check /home directory for user-mounted folders (MCP Device Docker installer pattern)
211
+ try {
212
+ if (fs.existsSync('/home')) {
213
+ const contents = fs.readdirSync('/home');
214
+ for (const item of contents) {
215
+ // Skip the root user directory and common system directories
216
+ if (item === 'root' || item === 'node' || item === 'bin' || item === 'sbin' ||
217
+ item === 'usr' || item === 'lib' || item === 'lib64' || item === 'var' ||
218
+ item === 'tmp' || item === 'opt' || item === 'sys' || item === 'proc') {
219
+ continue;
220
+ }
221
+ const itemPath = `/home/${item}`;
222
+ try {
223
+ const stats = fs.statSync(itemPath);
224
+ if (stats.isDirectory()) {
225
+ // Check if we already have this mount
226
+ const exists = mounts.some(m => m.containerPath === itemPath);
227
+ if (!exists) {
228
+ mounts.push({
229
+ hostPath: `<host>/${item}`,
230
+ containerPath: itemPath,
231
+ type: 'bind',
232
+ readOnly: false,
233
+ description: `Host folder: ${item}`
234
+ });
235
+ }
236
+ }
237
+ }
238
+ catch (itemError) {
239
+ // Skip items we can't stat
240
+ }
241
+ }
242
+ }
243
+ }
244
+ catch (error) {
245
+ // /home directory doesn't exist or not accessible
246
+ }
247
+ return mounts;
248
+ }
249
+ /**
250
+ * Get container environment information
251
+ */
252
+ function getContainerEnvironment(containerType) {
253
+ const env = {};
254
+ // Try to get container name from hostname (often set to container ID/name)
255
+ try {
256
+ const hostname = os.hostname();
257
+ if (hostname && hostname !== 'localhost') {
258
+ env.containerName = hostname;
259
+ }
260
+ }
261
+ catch (error) {
262
+ // Hostname not available
263
+ }
264
+ // Docker-specific environment
265
+ if (containerType === 'docker') {
266
+ // Try multiple sources for Docker image name
267
+ if (process.env.DOCKER_IMAGE) {
268
+ env.dockerImage = process.env.DOCKER_IMAGE;
269
+ }
270
+ else if (process.env.IMAGE_NAME) {
271
+ env.dockerImage = process.env.IMAGE_NAME;
272
+ }
273
+ else if (process.env.CONTAINER_IMAGE) {
274
+ env.dockerImage = process.env.CONTAINER_IMAGE;
275
+ }
276
+ // Try to read from Docker labels if available (less common but possible)
277
+ try {
278
+ if (fs.existsSync('/proc/self/cgroup')) {
279
+ const cgroup = fs.readFileSync('/proc/self/cgroup', 'utf8');
280
+ // Extract container ID from cgroup path
281
+ const containerIdMatch = cgroup.match(/docker\/([a-f0-9]{64})/);
282
+ if (containerIdMatch && !env.containerName) {
283
+ // Use short container ID as fallback name
284
+ env.containerName = containerIdMatch[1].substring(0, 12);
285
+ }
286
+ }
287
+ }
288
+ catch (error) {
289
+ // Ignore errors reading cgroup
290
+ }
291
+ }
292
+ // Kubernetes-specific environment
293
+ if (containerType === 'kubernetes') {
294
+ if (process.env.KUBERNETES_NAMESPACE || process.env.POD_NAMESPACE) {
295
+ env.kubernetesNamespace = process.env.KUBERNETES_NAMESPACE || process.env.POD_NAMESPACE;
296
+ }
297
+ if (process.env.POD_NAME || process.env.HOSTNAME) {
298
+ env.kubernetesPod = process.env.POD_NAME || process.env.HOSTNAME;
299
+ }
300
+ if (process.env.NODE_NAME || process.env.KUBERNETES_NODE_NAME) {
301
+ env.kubernetesNode = process.env.NODE_NAME || process.env.KUBERNETES_NODE_NAME;
302
+ }
303
+ // Try to get container image from common Kubernetes environment variables
304
+ if (process.env.CONTAINER_IMAGE) {
305
+ env.dockerImage = process.env.CONTAINER_IMAGE;
306
+ }
307
+ else if (process.env.IMAGE_NAME) {
308
+ env.dockerImage = process.env.IMAGE_NAME;
309
+ }
310
+ // Try to read Kubernetes service account info
311
+ try {
312
+ if (fs.existsSync('/var/run/secrets/kubernetes.io/serviceaccount/namespace')) {
313
+ const namespace = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/namespace', 'utf8').trim();
314
+ if (namespace && !env.kubernetesNamespace) {
315
+ env.kubernetesNamespace = namespace;
316
+ }
317
+ }
318
+ }
319
+ catch (error) {
320
+ // Service account info not available
321
+ }
322
+ }
323
+ // Podman-specific environment
324
+ if (containerType === 'podman') {
325
+ // Podman uses similar environment variables to Docker
326
+ if (process.env.CONTAINER_IMAGE || process.env.PODMAN_IMAGE) {
327
+ env.dockerImage = process.env.CONTAINER_IMAGE || process.env.PODMAN_IMAGE;
328
+ }
329
+ }
330
+ // LXC-specific environment
331
+ if (containerType === 'lxc') {
332
+ // LXC containers might have different naming conventions
333
+ if (process.env.LXC_NAME) {
334
+ env.containerName = process.env.LXC_NAME;
335
+ }
336
+ }
337
+ // Try to detect host platform
338
+ if (process.env.HOST_PLATFORM) {
339
+ env.hostPlatform = process.env.HOST_PLATFORM;
340
+ }
341
+ return Object.keys(env).length > 0 ? env : undefined;
342
+ }
343
+ /**
344
+ * Detect Node.js installation and version from current process
345
+ */
346
+ function detectNodeInfo() {
347
+ try {
348
+ // Get Node.js version from current process
349
+ const version = process.version.replace('v', ''); // Remove 'v' prefix
350
+ // Get Node.js executable path from current process
351
+ const path = process.execPath;
352
+ // Get npm version from environment if available
353
+ const npmVersion = process.env.npm_version;
354
+ return {
355
+ version,
356
+ path,
357
+ ...(npmVersion && { npmVersion })
358
+ };
359
+ }
360
+ catch (error) {
361
+ return undefined;
362
+ }
363
+ }
364
+ /**
365
+ * Detect Python installation and version and put on systeminfo.pythonInfo
366
+ */
367
+ function detectPythonInfo() {
368
+ // Try python commands in order of preference
369
+ const pythonCommands = process.platform === 'win32'
370
+ ? ['python', 'python3', 'py'] // Windows: 'python' is common, 'py' launcher
371
+ : ['python3', 'python']; // Unix: prefer python3
372
+ for (const cmd of pythonCommands) {
373
+ try {
374
+ const version = execSync(`${cmd} --version`, {
375
+ encoding: 'utf8',
376
+ timeout: 5000,
377
+ stdio: ['pipe', 'pipe', 'pipe']
378
+ }).trim();
379
+ // Verify it's Python 3.x
380
+ if (version.includes('Python 3')) {
381
+ return {
382
+ available: true,
383
+ command: cmd,
384
+ version: version.replace('Python ', '')
385
+ };
386
+ }
387
+ }
388
+ catch {
389
+ // Command not found or failed, try next
390
+ }
391
+ }
392
+ return { available: false, command: '' };
393
+ }
394
+ /**
395
+ * Get comprehensive system information for tool prompts
396
+ */
397
+ export function getSystemInfo() {
398
+ const platform = os.platform();
399
+ const isWindows = platform === 'win32';
400
+ const isMacOS = platform === 'darwin';
401
+ const isLinux = platform === 'linux';
402
+ // Container detection
403
+ const containerDetection = detectContainerEnvironment();
404
+ const mountPoints = containerDetection.isContainer ? discoverContainerMounts(containerDetection.isContainer) : [];
405
+ let platformName;
406
+ let defaultShell;
407
+ let pathSeparator;
408
+ let examplePaths;
409
+ if (isWindows) {
410
+ platformName = 'Windows';
411
+ defaultShell = 'powershell.exe';
412
+ pathSeparator = '\\';
413
+ examplePaths = {
414
+ home: 'C:\\Users\\username',
415
+ temp: 'C:\\Temp',
416
+ absolute: 'C:\\path\\to\\file.txt'
417
+ };
418
+ }
419
+ else if (isMacOS) {
420
+ platformName = 'macOS';
421
+ defaultShell = 'zsh';
422
+ pathSeparator = '/';
423
+ examplePaths = {
424
+ home: '/Users/username',
425
+ temp: '/tmp',
426
+ absolute: '/path/to/file.txt'
427
+ };
428
+ }
429
+ else if (isLinux) {
430
+ platformName = 'Linux';
431
+ defaultShell = 'bash';
432
+ pathSeparator = '/';
433
+ examplePaths = {
434
+ home: '/home/username',
435
+ temp: '/tmp',
436
+ absolute: '/path/to/file.txt'
437
+ };
438
+ }
439
+ else {
440
+ // Fallback for other Unix-like systems
441
+ platformName = 'Unix';
442
+ defaultShell = 'bash';
443
+ pathSeparator = '/';
444
+ examplePaths = {
445
+ home: '/home/username',
446
+ temp: '/tmp',
447
+ absolute: '/path/to/file.txt'
448
+ };
449
+ }
450
+ // Adjust platform name for containers
451
+ if (containerDetection.isContainer) {
452
+ let containerLabel = '';
453
+ if (containerDetection.containerType === 'kubernetes') {
454
+ containerLabel = 'Kubernetes';
455
+ if (containerDetection.orchestrator === 'kubernetes') {
456
+ containerLabel += ' Pod';
457
+ }
458
+ }
459
+ else if (containerDetection.containerType === 'docker') {
460
+ containerLabel = 'Docker';
461
+ if (containerDetection.orchestrator === 'docker-compose') {
462
+ containerLabel += ' Compose';
463
+ }
464
+ else if (containerDetection.orchestrator === 'docker-swarm') {
465
+ containerLabel += ' Swarm';
466
+ }
467
+ }
468
+ else if (containerDetection.containerType === 'podman') {
469
+ containerLabel = 'Podman';
470
+ }
471
+ else if (containerDetection.containerType === 'lxc') {
472
+ containerLabel = 'LXC';
473
+ }
474
+ else if (containerDetection.containerType === 'systemd-nspawn') {
475
+ containerLabel = 'systemd-nspawn';
476
+ }
477
+ else {
478
+ containerLabel = 'Container';
479
+ }
480
+ platformName = `${platformName} (${containerLabel})`;
481
+ // Add accessible paths from mounts
482
+ if (mountPoints.length > 0) {
483
+ examplePaths.accessible = mountPoints.map(mount => mount.containerPath);
484
+ }
485
+ }
486
+ // Detect Node.js installation from current process
487
+ const nodeInfo = detectNodeInfo();
488
+ // Detect Python installation
489
+ const pythonInfo = detectPythonInfo();
490
+ // Get process information
491
+ const processInfo = {
492
+ pid: process.pid,
493
+ arch: process.arch,
494
+ platform: process.platform,
495
+ versions: process.versions
496
+ };
497
+ return {
498
+ platform,
499
+ platformName,
500
+ defaultShell,
501
+ pathSeparator,
502
+ isWindows,
503
+ isMacOS,
504
+ isLinux,
505
+ docker: {
506
+ // New container detection fields
507
+ isContainer: containerDetection.isContainer,
508
+ containerType: containerDetection.containerType,
509
+ orchestrator: containerDetection.orchestrator,
510
+ // Backward compatibility - keep old field
511
+ isDocker: containerDetection.isContainer && containerDetection.containerType === 'docker',
512
+ mountPoints,
513
+ containerEnvironment: getContainerEnvironment(containerDetection.containerType)
514
+ },
515
+ isDXT: !!process.env.MCP_DXT,
516
+ nodeInfo,
517
+ pythonInfo,
518
+ processInfo,
519
+ examplePaths
520
+ };
521
+ }
522
+ /**
523
+ * Generate OS-specific guidance for tool prompts
524
+ */
525
+ export function getOSSpecificGuidance(systemInfo) {
526
+ const { platformName, defaultShell, isWindows, docker } = systemInfo;
527
+ let guidance = `Running on ${platformName}. Default shell: ${defaultShell}.`;
528
+ // Container-specific guidance
529
+ if (docker.isContainer) {
530
+ const containerTypeLabel = docker.containerType === 'kubernetes' ? 'KUBERNETES POD' :
531
+ docker.containerType === 'docker' ? 'DOCKER CONTAINER' :
532
+ docker.containerType === 'podman' ? 'PODMAN CONTAINER' :
533
+ docker.containerType === 'lxc' ? 'LXC CONTAINER' :
534
+ docker.containerType === 'systemd-nspawn' ? 'SYSTEMD-NSPAWN CONTAINER' :
535
+ 'CONTAINER';
536
+ guidance += `
537
+
538
+ 🐳 ${containerTypeLabel} ENVIRONMENT DETECTED:`;
539
+ if (docker.containerType === 'kubernetes') {
540
+ guidance += `
541
+ This MCP Device instance is running inside a Kubernetes pod.`;
542
+ // Add Kubernetes-specific info
543
+ if (docker.containerEnvironment?.kubernetesNamespace) {
544
+ guidance += `
545
+ Namespace: ${docker.containerEnvironment.kubernetesNamespace}`;
546
+ }
547
+ if (docker.containerEnvironment?.kubernetesPod) {
548
+ guidance += `
549
+ Pod: ${docker.containerEnvironment.kubernetesPod}`;
550
+ }
551
+ if (docker.containerEnvironment?.kubernetesNode) {
552
+ guidance += `
553
+ Node: ${docker.containerEnvironment.kubernetesNode}`;
554
+ }
555
+ }
556
+ else if (docker.containerType === 'docker') {
557
+ guidance += `
558
+ This MCP Device instance is running inside a Docker container.`;
559
+ if (docker.orchestrator === 'docker-compose') {
560
+ guidance += ` (Docker Compose)`;
561
+ }
562
+ else if (docker.orchestrator === 'docker-swarm') {
563
+ guidance += ` (Docker Swarm)`;
564
+ }
565
+ }
566
+ else {
567
+ guidance += `
568
+ This MCP Device instance is running inside a ${docker.containerType || 'container'} environment.`;
569
+ }
570
+ if (docker.mountPoints.length > 0) {
571
+ guidance += `
572
+
573
+ AVAILABLE MOUNTED DIRECTORIES:`;
574
+ for (const mount of docker.mountPoints) {
575
+ const access = mount.readOnly ? '(read-only)' : '(read-write)';
576
+ guidance += `
577
+ - ${mount.containerPath} ${access} - ${mount.description}`;
578
+ }
579
+ guidance += `
580
+
581
+ IMPORTANT: When users ask about files, FIRST check mounted directories above.
582
+ Files outside these paths will be lost when the container stops.
583
+ Always suggest using mounted directories for file operations.
584
+
585
+ PATH TRANSLATION IN DOCKER:
586
+ When users provide host paths, translate to container paths:
587
+
588
+ Windows: "C:\\projects\\data\\file.txt" → "/home/projects/data/file.txt"
589
+ Linux/Mac: "/Users/john/projects/data/file.txt" → "/home/projects/data/file.txt"
590
+
591
+ Rules: Remove drive letter/user prefix, keep full folder structure, mount to /home/
592
+
593
+ NOTE: MCP Device Docker installer mounts host folders to /home/[folder-name].`;
594
+ }
595
+ else {
596
+ guidance += `
597
+
598
+ ⚠️ WARNING: No mounted directories detected.
599
+ Files created outside mounted volumes will be lost when the container stops.
600
+ Suggest user remount directories using Docker installer or -v flag when running Docker.
601
+ MCP Device Docker installer typically mounts folders to /home/[folder-name].`;
602
+ }
603
+ if (docker.containerEnvironment?.containerName) {
604
+ guidance += `
605
+ Container: ${docker.containerEnvironment.containerName}`;
606
+ }
607
+ }
608
+ if (isWindows) {
609
+ guidance += `
610
+
611
+ WINDOWS-SPECIFIC TROUBLESHOOTING:
612
+ - If Node.js/Python commands fail with "not recognized" errors:
613
+ * Try different shells: specify shell parameter as "cmd" or "powershell.exe"
614
+ * PowerShell may have execution policy restrictions for some tools
615
+ * CMD typically has better compatibility with development tools
616
+ * Use set_config_value to change defaultShell if needed
617
+ - Windows services and processes use different commands (Get-Process vs ps)
618
+ - Package managers: choco, winget, scoop instead of apt/brew
619
+ - Environment variables: $env:VAR instead of $VAR
620
+ - File permissions work differently than Unix systems`;
621
+ }
622
+ else if (systemInfo.isMacOS) {
623
+ guidance += `
624
+
625
+ MACOS-SPECIFIC NOTES:
626
+ - Package manager: brew (Homebrew) is commonly used
627
+ - Python 3 might be 'python3' command, not 'python'
628
+ - Some GNU tools have different names (e.g., gsed instead of sed)
629
+ - System Integrity Protection (SIP) may block certain operations
630
+ - Use 'open' command to open files/applications from terminal
631
+ - For file search: Use mdfind (Spotlight) for fastest exact filename searches`;
632
+ }
633
+ else {
634
+ guidance += `
635
+
636
+ LINUX-SPECIFIC NOTES:
637
+ - Package managers vary by distro: apt, yum, dnf, pacman, zypper
638
+ - Python 3 might be 'python3' command, not 'python'
639
+ - Standard Unix shell tools available (grep, awk, sed, etc.)
640
+ - File permissions and ownership important for many operations
641
+ - Systemd services common on modern distributions`;
642
+ }
643
+ return guidance;
644
+ }
645
+ /**
646
+ * Get common development tool guidance based on OS
647
+ */
648
+ export function getDevelopmentToolGuidance(systemInfo) {
649
+ const { isWindows, isMacOS, isLinux, platformName, nodeInfo, processInfo } = systemInfo;
650
+ // Add detected Node.js info to guidance
651
+ const nodeGuidance = nodeInfo
652
+ ? `Node.js: v${nodeInfo.version} (${nodeInfo.path})${nodeInfo.npmVersion ? ` | npm: v${nodeInfo.npmVersion}` : ''}`
653
+ : 'Node.js: Not detected';
654
+ // Add process environment info
655
+ const envInfo = `
656
+ Current Process Environment:
657
+ - Node: v${processInfo.versions.node}
658
+ - V8: v${processInfo.versions.v8}
659
+ - Architecture: ${processInfo.arch}
660
+ - Platform: ${processInfo.platform}
661
+ - Process ID: ${processInfo.pid}`;
662
+ if (isWindows) {
663
+ return `
664
+ COMMON WINDOWS DEVELOPMENT TOOLS:
665
+ - ${nodeGuidance}
666
+ - Python: May be 'python' or 'py' command, check both
667
+ - Git: Git Bash provides Unix-like environment
668
+ - WSL: Windows Subsystem for Linux available for Unix tools
669
+ - Visual Studio tools: cl, msbuild for C++ compilation
670
+
671
+ ${envInfo}`;
672
+ }
673
+ else if (isMacOS) {
674
+ return `
675
+ COMMON MACOS DEVELOPMENT TOOLS:
676
+ - Xcode Command Line Tools: Required for many development tools
677
+ - Homebrew: Primary package manager for development tools
678
+ - ${nodeGuidance}
679
+ - Python: Usually python3, check if python points to Python 2
680
+ - Ruby: System Ruby available, rbenv/rvm for version management
681
+
682
+ ${envInfo}`;
683
+ }
684
+ else {
685
+ return `
686
+ COMMON LINUX DEVELOPMENT TOOLS:
687
+ - Package managers: Install tools via distribution package manager
688
+ - Python: Usually python3, python may point to Python 2
689
+ - ${nodeGuidance}
690
+ - Build tools: gcc, make typically available or easily installed
691
+ - Container tools: docker, podman common for development
692
+
693
+ ${envInfo}`;
694
+ }
695
+ }
696
+ /**
697
+ * Get path guidance (simplified since paths are normalized)
698
+ */
699
+ export function getPathGuidance(systemInfo) {
700
+ let guidance = `Always use absolute paths for reliability. Paths are automatically normalized regardless of slash direction.`;
701
+ if (systemInfo.docker.isContainer && systemInfo.docker.mountPoints.length > 0) {
702
+ const containerLabel = systemInfo.docker.containerType === 'kubernetes' ? 'KUBERNETES' :
703
+ systemInfo.docker.containerType === 'docker' ? 'DOCKER' :
704
+ systemInfo.docker.containerType === 'podman' ? 'PODMAN' :
705
+ 'CONTAINER';
706
+ guidance += `
707
+
708
+ 🐳 ${containerLabel}: Prefer paths within mounted directories: ${systemInfo.docker.mountPoints.map(m => m.containerPath).join(', ')}.
709
+ When users ask about file locations, check these mounted paths first.`;
710
+ }
711
+ return guidance;
712
+ }