@hcu-lab.me/mcp-device 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +22 -0
- package/dist/command-manager.d.ts +8 -0
- package/dist/command-manager.js +241 -0
- package/dist/config-field-definitions.d.ts +41 -0
- package/dist/config-field-definitions.js +37 -0
- package/dist/config-manager.d.ts +102 -0
- package/dist/config-manager.js +291 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +10 -0
- package/dist/custom-stdio.d.ts +51 -0
- package/dist/custom-stdio.js +358 -0
- package/dist/data/official-app-ca.pem +12 -0
- package/dist/data/onboarding-prompts.json +70 -0
- package/dist/device/device-state.d.ts +13 -0
- package/dist/device/device-state.js +100 -0
- package/dist/device/device-status.d.ts +81 -0
- package/dist/device/device-status.js +156 -0
- package/dist/device/device.d.ts +16 -0
- package/dist/device/device.js +190 -0
- package/dist/device/execution-engine.d.ts +144 -0
- package/dist/device/execution-engine.js +195 -0
- package/dist/device/gateway-channel.d.ts +48 -0
- package/dist/device/gateway-channel.js +384 -0
- package/dist/device/gateway-config.d.ts +40 -0
- package/dist/device/gateway-config.js +207 -0
- package/dist/device/gateway-identity.d.ts +35 -0
- package/dist/device/gateway-identity.js +178 -0
- package/dist/device/gateway-pairing.d.ts +25 -0
- package/dist/device/gateway-pairing.js +105 -0
- package/dist/device/gateway-secure-transport.d.ts +25 -0
- package/dist/device/gateway-secure-transport.js +117 -0
- package/dist/device/gateway-tool-adapter.d.ts +17 -0
- package/dist/device/gateway-tool-adapter.js +284 -0
- package/dist/device/gateway-url-policy.d.ts +3 -0
- package/dist/device/gateway-url-policy.js +43 -0
- package/dist/device/linux-service.d.ts +70 -0
- package/dist/device/linux-service.js +268 -0
- package/dist/device/official-trust.d.ts +7 -0
- package/dist/device/official-trust.js +49 -0
- package/dist/device/project-inspection.d.ts +1 -0
- package/dist/device/project-inspection.js +180 -0
- package/dist/device/runtime-owner.d.ts +41 -0
- package/dist/device/runtime-owner.js +177 -0
- package/dist/device/windows-dpapi.d.ts +11 -0
- package/dist/device/windows-dpapi.js +67 -0
- package/dist/device/windows-service.d.ts +56 -0
- package/dist/device/windows-service.js +238 -0
- package/dist/error-handlers.d.ts +7 -0
- package/dist/error-handlers.js +15 -0
- package/dist/handlers/edit-search-handlers.d.ts +6 -0
- package/dist/handlers/edit-search-handlers.js +6 -0
- package/dist/handlers/filesystem-handlers.d.ts +38 -0
- package/dist/handlers/filesystem-handlers.js +440 -0
- package/dist/handlers/history-handlers.d.ts +12 -0
- package/dist/handlers/history-handlers.js +67 -0
- package/dist/handlers/index.d.ts +6 -0
- package/dist/handlers/index.js +7 -0
- package/dist/handlers/process-handlers.d.ts +9 -0
- package/dist/handlers/process-handlers.js +15 -0
- package/dist/handlers/search-handlers.d.ts +17 -0
- package/dist/handlers/search-handlers.js +224 -0
- package/dist/handlers/terminal-handlers.d.ts +21 -0
- package/dist/handlers/terminal-handlers.js +35 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +138 -0
- package/dist/mcp-device.d.ts +2 -0
- package/dist/mcp-device.js +7 -0
- package/dist/npm-scripts/remote.d.ts +3 -0
- package/dist/npm-scripts/remote.js +314 -0
- package/dist/search-manager.d.ts +147 -0
- package/dist/search-manager.js +828 -0
- package/dist/server.d.ts +46 -0
- package/dist/server.js +1563 -0
- package/dist/terminal-manager.d.ts +104 -0
- package/dist/terminal-manager.js +635 -0
- package/dist/tools/config.d.ts +96 -0
- package/dist/tools/config.js +260 -0
- package/dist/tools/edit.d.ts +38 -0
- package/dist/tools/edit.js +435 -0
- package/dist/tools/feedback.d.ts +8 -0
- package/dist/tools/feedback.js +132 -0
- package/dist/tools/filesystem.d.ts +79 -0
- package/dist/tools/filesystem.js +947 -0
- package/dist/tools/fuzzySearch.d.ts +12 -0
- package/dist/tools/fuzzySearch.js +74 -0
- package/dist/tools/fuzzySearchCore.d.ts +52 -0
- package/dist/tools/fuzzySearchCore.js +125 -0
- package/dist/tools/improved-process-tools.d.ts +24 -0
- package/dist/tools/improved-process-tools.js +627 -0
- package/dist/tools/mime-types.d.ts +3 -0
- package/dist/tools/mime-types.js +28 -0
- package/dist/tools/pdf/extract-images.d.ts +34 -0
- package/dist/tools/pdf/extract-images.js +132 -0
- package/dist/tools/pdf/index.d.ts +6 -0
- package/dist/tools/pdf/index.js +3 -0
- package/dist/tools/pdf/lib/pdf2md.d.ts +36 -0
- package/dist/tools/pdf/lib/pdf2md.js +76 -0
- package/dist/tools/pdf/manipulations.d.ts +13 -0
- package/dist/tools/pdf/manipulations.js +99 -0
- package/dist/tools/pdf/markdown.d.ts +26 -0
- package/dist/tools/pdf/markdown.js +275 -0
- package/dist/tools/pdf/utils.d.ts +12 -0
- package/dist/tools/pdf/utils.js +34 -0
- package/dist/tools/process.d.ts +3 -0
- package/dist/tools/process.js +56 -0
- package/dist/tools/prompts.d.ts +28 -0
- package/dist/tools/prompts.js +259 -0
- package/dist/tools/schemas.d.ts +454 -0
- package/dist/tools/schemas.js +242 -0
- package/dist/tools/usage.d.ts +5 -0
- package/dist/tools/usage.js +24 -0
- package/dist/types.d.ts +83 -0
- package/dist/types.js +1 -0
- package/dist/ui/config-editor/config-editor-runtime.js +150 -0
- package/dist/ui/config-editor/index.html +13 -0
- package/dist/ui/config-editor/src/app.d.ts +43 -0
- package/dist/ui/config-editor/src/app.js +831 -0
- package/dist/ui/config-editor/src/array-modal.d.ts +19 -0
- package/dist/ui/config-editor/src/array-modal.js +185 -0
- package/dist/ui/config-editor/src/main.d.ts +1 -0
- package/dist/ui/config-editor/src/main.js +2 -0
- package/dist/ui/config-editor/styles.css +587 -0
- package/dist/ui/contracts.d.ts +14 -0
- package/dist/ui/contracts.js +21 -0
- package/dist/ui/file-preview/index.html +16 -0
- package/dist/ui/file-preview/preview-runtime.js +469 -0
- package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
- package/dist/ui/file-preview/shared/preview-file-types.js +59 -0
- package/dist/ui/file-preview/src/app.d.ts +4 -0
- package/dist/ui/file-preview/src/app.js +680 -0
- package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
- package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
- package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
- package/dist/ui/file-preview/src/components/highlighting.js +54 -0
- package/dist/ui/file-preview/src/components/html-renderer.d.ts +5 -0
- package/dist/ui/file-preview/src/components/html-renderer.js +47 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.js +59 -0
- package/dist/ui/file-preview/src/directory-controller.d.ts +8 -0
- package/dist/ui/file-preview/src/directory-controller.js +240 -0
- package/dist/ui/file-preview/src/document-layout.d.ts +20 -0
- package/dist/ui/file-preview/src/document-layout.js +109 -0
- package/dist/ui/file-preview/src/document-outline.d.ts +17 -0
- package/dist/ui/file-preview/src/document-outline.js +97 -0
- package/dist/ui/file-preview/src/document-workspace.d.ts +19 -0
- package/dist/ui/file-preview/src/document-workspace.js +33 -0
- package/dist/ui/file-preview/src/file-type-handlers.d.ts +10 -0
- package/dist/ui/file-preview/src/file-type-handlers.js +109 -0
- package/dist/ui/file-preview/src/host/external-actions.d.ts +8 -0
- package/dist/ui/file-preview/src/host/external-actions.js +55 -0
- package/dist/ui/file-preview/src/host/selection-context.d.ts +9 -0
- package/dist/ui/file-preview/src/host/selection-context.js +106 -0
- package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
- package/dist/ui/file-preview/src/image-preview.js +21 -0
- package/dist/ui/file-preview/src/main.d.ts +1 -0
- package/dist/ui/file-preview/src/main.js +5 -0
- package/dist/ui/file-preview/src/markdown/conflict-dialog.d.ts +40 -0
- package/dist/ui/file-preview/src/markdown/conflict-dialog.js +163 -0
- package/dist/ui/file-preview/src/markdown/controller.d.ts +44 -0
- package/dist/ui/file-preview/src/markdown/controller.js +1043 -0
- package/dist/ui/file-preview/src/markdown/editor.d.ts +131 -0
- package/dist/ui/file-preview/src/markdown/editor.js +1479 -0
- package/dist/ui/file-preview/src/markdown/linking.d.ts +16 -0
- package/dist/ui/file-preview/src/markdown/linking.js +228 -0
- package/dist/ui/file-preview/src/markdown/outline.d.ts +2 -0
- package/dist/ui/file-preview/src/markdown/outline.js +16 -0
- package/dist/ui/file-preview/src/markdown/parser.d.ts +30 -0
- package/dist/ui/file-preview/src/markdown/parser.js +38 -0
- package/dist/ui/file-preview/src/markdown/preview.d.ts +1 -0
- package/dist/ui/file-preview/src/markdown/preview.js +20 -0
- package/dist/ui/file-preview/src/markdown/slugify.d.ts +3 -0
- package/dist/ui/file-preview/src/markdown/slugify.js +31 -0
- package/dist/ui/file-preview/src/markdown/utils.d.ts +1 -0
- package/dist/ui/file-preview/src/markdown/utils.js +15 -0
- package/dist/ui/file-preview/src/model.d.ts +35 -0
- package/dist/ui/file-preview/src/model.js +1 -0
- package/dist/ui/file-preview/src/panel-actions.d.ts +17 -0
- package/dist/ui/file-preview/src/panel-actions.js +182 -0
- package/dist/ui/file-preview/src/path-utils.d.ts +6 -0
- package/dist/ui/file-preview/src/path-utils.js +64 -0
- package/dist/ui/file-preview/src/payload-utils.d.ts +11 -0
- package/dist/ui/file-preview/src/payload-utils.js +119 -0
- package/dist/ui/file-preview/src/types.d.ts +1 -0
- package/dist/ui/file-preview/src/types.js +1 -0
- package/dist/ui/file-preview/styles.css +1631 -0
- package/dist/ui/resources.d.ts +28 -0
- package/dist/ui/resources.js +86 -0
- package/dist/ui/shared/compact-row.d.ts +11 -0
- package/dist/ui/shared/compact-row.js +18 -0
- package/dist/ui/shared/escape-html.d.ts +4 -0
- package/dist/ui/shared/escape-html.js +11 -0
- package/dist/ui/shared/host-context.d.ts +15 -0
- package/dist/ui/shared/host-context.js +51 -0
- package/dist/ui/shared/tool-bridge.d.ts +30 -0
- package/dist/ui/shared/tool-bridge.js +137 -0
- package/dist/ui/shared/tool-shell.d.ts +25 -0
- package/dist/ui/shared/tool-shell.js +107 -0
- package/dist/ui/shared/ui-event-tracker.d.ts +9 -0
- package/dist/ui/shared/ui-event-tracker.js +27 -0
- package/dist/ui/shared/widget-state.d.ts +33 -0
- package/dist/ui/shared/widget-state.js +158 -0
- package/dist/utils/ab-test.d.ts +12 -0
- package/dist/utils/ab-test.js +104 -0
- package/dist/utils/capture.d.ts +35 -0
- package/dist/utils/capture.js +481 -0
- package/dist/utils/dockerPrompt.d.ts +17 -0
- package/dist/utils/dockerPrompt.js +53 -0
- package/dist/utils/feature-flags.d.ts +59 -0
- package/dist/utils/feature-flags.js +215 -0
- package/dist/utils/files/base.d.ts +173 -0
- package/dist/utils/files/base.js +5 -0
- package/dist/utils/files/binary.d.ts +21 -0
- package/dist/utils/files/binary.js +65 -0
- package/dist/utils/files/docx.d.ts +47 -0
- package/dist/utils/files/docx.js +679 -0
- package/dist/utils/files/excel.d.ts +24 -0
- package/dist/utils/files/excel.js +437 -0
- package/dist/utils/files/factory.d.ts +41 -0
- package/dist/utils/files/factory.js +113 -0
- package/dist/utils/files/image.d.ts +21 -0
- package/dist/utils/files/image.js +78 -0
- package/dist/utils/files/index.d.ts +10 -0
- package/dist/utils/files/index.js +13 -0
- package/dist/utils/files/pdf.d.ts +32 -0
- package/dist/utils/files/pdf.js +142 -0
- package/dist/utils/files/text.d.ts +63 -0
- package/dist/utils/files/text.js +370 -0
- package/dist/utils/fuzzySearchLogger.d.ts +30 -0
- package/dist/utils/fuzzySearchLogger.js +126 -0
- package/dist/utils/lineEndingHandler.d.ts +21 -0
- package/dist/utils/lineEndingHandler.js +77 -0
- package/dist/utils/logger.d.ts +32 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/mcp-ui-ab-test.d.ts +13 -0
- package/dist/utils/mcp-ui-ab-test.js +62 -0
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.js +42 -0
- package/dist/utils/process-detection.d.ts +23 -0
- package/dist/utils/process-detection.js +150 -0
- package/dist/utils/ripgrep-resolver.d.ts +9 -0
- package/dist/utils/ripgrep-resolver.js +74 -0
- package/dist/utils/system-info.d.ts +71 -0
- package/dist/utils/system-info.js +712 -0
- package/dist/utils/toolHistory.d.ts +86 -0
- package/dist/utils/toolHistory.js +257 -0
- package/dist/utils/trackTools.d.ts +6 -0
- package/dist/utils/trackTools.js +54 -0
- package/dist/utils/unsupportedParams.d.ts +24 -0
- package/dist/utils/unsupportedParams.js +66 -0
- package/dist/utils/usageTracker.d.ts +133 -0
- package/dist/utils/usageTracker.js +477 -0
- package/dist/utils/welcome-onboarding.d.ts +11 -0
- package/dist/utils/welcome-onboarding.js +99 -0
- package/dist/utils/withTimeout.d.ts +28 -0
- package/dist/utils/withTimeout.js +85 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1,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;
|