mirror of
https://github.com/hangwin/mcp-chrome.git
synced 2026-09-01 05:33:48 +08:00
fix: windows install fail
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mcp-chrome-bridge",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"description": "Chrome Native-Messaging host (Node)",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
|
||||
@@ -22,7 +22,19 @@ program
|
||||
try {
|
||||
// Detect if running with root/administrator privileges
|
||||
const isRoot = process.getuid && process.getuid() === 0; // Unix/Linux/Mac
|
||||
const isAdmin = process.platform === 'win32' && require('is-admin')(); // Windows requires additional package
|
||||
|
||||
let isAdmin = false;
|
||||
if (process.platform === 'win32') {
|
||||
try {
|
||||
isAdmin = require('is-admin')(); // Windows requires additional package
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
colorText('Warning: Unable to detect administrator privileges on Windows', 'yellow'),
|
||||
);
|
||||
isAdmin = false;
|
||||
}
|
||||
}
|
||||
|
||||
const hasElevatedPermissions = isRoot || isAdmin;
|
||||
|
||||
// If --system option is specified or running with root/administrator privileges
|
||||
|
||||
@@ -24,7 +24,11 @@ function detectGlobalInstall(): boolean {
|
||||
|
||||
// Method 2: Check if we're in a global pnpm directory structure
|
||||
// pnpm global packages are typically installed in ~/.local/share/pnpm/global/5/node_modules
|
||||
const globalPnpmPatterns = ['/pnpm/global/', '/.local/share/pnpm/', '/pnpm-global/'];
|
||||
// Windows: %APPDATA%\pnpm\global\5\node_modules
|
||||
const globalPnpmPatterns =
|
||||
process.platform === 'win32'
|
||||
? ['\\pnpm\\global\\', '\\pnpm-global\\', '\\AppData\\Roaming\\pnpm\\']
|
||||
: ['/pnpm/global/', '/.local/share/pnpm/', '/pnpm-global/'];
|
||||
|
||||
if (globalPnpmPatterns.some((pattern) => __dirname.includes(pattern))) {
|
||||
return true;
|
||||
@@ -35,6 +39,20 @@ function detectGlobalInstall(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method 4: Windows-specific global installation paths
|
||||
if (process.platform === 'win32') {
|
||||
const windowsGlobalPatterns = [
|
||||
'\\npm\\node_modules\\',
|
||||
'\\AppData\\Roaming\\npm\\node_modules\\',
|
||||
'\\Program Files\\nodejs\\node_modules\\',
|
||||
'\\nodejs\\node_modules\\',
|
||||
];
|
||||
|
||||
if (windowsGlobalPatterns.some((pattern) => __dirname.includes(pattern))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,22 +63,83 @@ if not defined NODE_EXEC (
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
REM Check for Volta (another Node.js version manager)
|
||||
if exist "%LOCALAPPDATA%\Volta\bin\node.exe" (
|
||||
if not defined NODE_EXEC (
|
||||
set "NODE_EXEC=%LOCALAPPDATA%\Volta\bin\node.exe"
|
||||
echo Found Volta node at %LOCALAPPDATA%\Volta\bin\node.exe >> "%WRAPPER_LOG%"
|
||||
)
|
||||
)
|
||||
|
||||
REM Check for fnm (Fast Node Manager)
|
||||
if exist "%LOCALAPPDATA%\fnm_multishells" (
|
||||
for /f "delims=" %%v in ('dir /b /ad "%LOCALAPPDATA%\fnm_multishells" 2^>nul ^| sort /r') do (
|
||||
if not defined NODE_EXEC if exist "%LOCALAPPDATA%\fnm_multishells\%%v\node.exe" (
|
||||
set "NODE_EXEC=%LOCALAPPDATA%\fnm_multishells\%%v\node.exe"
|
||||
echo Found fnm node at %LOCALAPPDATA%\fnm_multishells\%%v\node.exe >> "%WRAPPER_LOG%"
|
||||
goto :node_found
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
REM Check for Scoop installation
|
||||
if exist "%USERPROFILE%\scoop\apps\nodejs\current\node.exe" (
|
||||
if not defined NODE_EXEC (
|
||||
set "NODE_EXEC=%USERPROFILE%\scoop\apps\nodejs\current\node.exe"
|
||||
echo Found Scoop node at %USERPROFILE%\scoop\apps\nodejs\current\node.exe >> "%WRAPPER_LOG%"
|
||||
)
|
||||
)
|
||||
|
||||
REM Check for Chocolatey installation
|
||||
if exist "%ProgramData%\chocolatey\lib\nodejs\tools\node.exe" (
|
||||
if not defined NODE_EXEC (
|
||||
set "NODE_EXEC=%ProgramData%\chocolatey\lib\nodejs\tools\node.exe"
|
||||
echo Found Chocolatey node at %ProgramData%\chocolatey\lib\nodejs\tools\node.exe >> "%WRAPPER_LOG%"
|
||||
)
|
||||
)
|
||||
)
|
||||
:node_found
|
||||
|
||||
if not defined NODE_EXEC (
|
||||
echo ERROR: Node.js executable not found! >> "%WRAPPER_LOG%"
|
||||
echo Searched 'where node.exe' and common installation paths. >> "%WRAPPER_LOG%"
|
||||
echo Searched paths: >> "%WRAPPER_LOG%"
|
||||
echo - %ProgramFiles%\nodejs\node.exe >> "%WRAPPER_LOG%"
|
||||
echo - %ProgramFiles(x86)%\nodejs\node.exe >> "%WRAPPER_LOG%"
|
||||
echo - %LOCALAPPDATA%\Programs\nodejs\node.exe >> "%WRAPPER_LOG%"
|
||||
echo - %APPDATA%\nvm\* >> "%WRAPPER_LOG%"
|
||||
echo - %LOCALAPPDATA%\Volta\bin\node.exe >> "%WRAPPER_LOG%"
|
||||
echo - %LOCALAPPDATA%\fnm_multishells\* >> "%WRAPPER_LOG%"
|
||||
echo - %USERPROFILE%\scoop\apps\nodejs\current\node.exe >> "%WRAPPER_LOG%"
|
||||
echo - %ProgramData%\chocolatey\lib\nodejs\tools\node.exe >> "%WRAPPER_LOG%"
|
||||
echo Please install Node.js or ensure it's in your PATH. >> "%WRAPPER_LOG%"
|
||||
echo You can download Node.js from: https://nodejs.org/ >> "%WRAPPER_LOG%"
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
echo Using Node executable: %NODE_EXEC% >> "%WRAPPER_LOG%"
|
||||
echo Node version found by script: >> "%WRAPPER_LOG%"
|
||||
call "%NODE_EXEC%" -v >> "%WRAPPER_LOG%" 2>>&1
|
||||
|
||||
REM Verify Node.js script exists
|
||||
if not exist "%NODE_SCRIPT%" (
|
||||
echo ERROR: Node.js script not found: %NODE_SCRIPT% >> "%WRAPPER_LOG%"
|
||||
echo Please ensure the native host is properly installed. >> "%WRAPPER_LOG%"
|
||||
exit /B 1
|
||||
)
|
||||
|
||||
echo Node.js script exists: %NODE_SCRIPT% >> "%WRAPPER_LOG%"
|
||||
echo Executing: "%NODE_EXEC%" "%NODE_SCRIPT%" >> "%WRAPPER_LOG%"
|
||||
echo ==================== Starting Native Host ==================== >> "%WRAPPER_LOG%"
|
||||
|
||||
REM Execute the Node.js script. Stdout goes to Chrome. Stderr goes to the log file.
|
||||
call "%NODE_EXEC%" "%NODE_SCRIPT%" 2>> "%STDERR_LOG%"
|
||||
set "EXIT_CODE=%ERRORLEVEL%"
|
||||
|
||||
echo ==================== Native Host Exited ==================== >> "%WRAPPER_LOG%"
|
||||
echo Exit code: %EXIT_CODE% >> "%WRAPPER_LOG%"
|
||||
echo Execution completed at %DATE% %TIME% >> "%WRAPPER_LOG%"
|
||||
|
||||
endlocal
|
||||
exit /B %ERRORLEVEL%
|
||||
exit /B %EXIT_CODE%
|
||||
@@ -199,6 +199,28 @@ export async function createManifestContent(): Promise<any> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证Windows注册表项是否存在
|
||||
*/
|
||||
function verifyWindowsRegistryEntry(registryKey: string, expectedPath: string): boolean {
|
||||
if (os.platform() !== 'win32') {
|
||||
return true; // 非Windows平台跳过验证
|
||||
}
|
||||
|
||||
try {
|
||||
const result = execSync(`reg query "${registryKey}" /ve`, { encoding: 'utf8', stdio: 'pipe' });
|
||||
const lines = result.split('\n');
|
||||
for (const line of lines) {
|
||||
if (line.includes('REG_SZ') && line.includes(expectedPath.replace(/\\/g, '\\\\'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试注册用户级别的Native Messaging主机
|
||||
*/
|
||||
@@ -226,15 +248,25 @@ export async function tryRegisterUserLevelHost(): Promise<boolean> {
|
||||
if (os.platform() === 'win32') {
|
||||
const registryKey = `HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\${HOST_NAME}`;
|
||||
try {
|
||||
execSync(
|
||||
`reg add "${registryKey}" /ve /t REG_SZ /d "${manifestPath.replace(/\\/g, '\\\\')}" /f`,
|
||||
{ stdio: 'ignore' },
|
||||
);
|
||||
console.log(colorText('✓ Successfully created Windows registry entry', 'green'));
|
||||
// 确保路径使用正确的转义格式
|
||||
const escapedPath = manifestPath.replace(/\\/g, '\\\\');
|
||||
const regCommand = `reg add "${registryKey}" /ve /t REG_SZ /d "${escapedPath}" /f`;
|
||||
|
||||
console.log(colorText(`Executing registry command: ${regCommand}`, 'blue'));
|
||||
execSync(regCommand, { stdio: 'pipe' });
|
||||
|
||||
// 验证注册表项是否创建成功
|
||||
if (verifyWindowsRegistryEntry(registryKey, manifestPath)) {
|
||||
console.log(colorText('✓ Successfully created Windows registry entry', 'green'));
|
||||
} else {
|
||||
console.log(colorText('⚠️ Registry entry created but verification failed', 'yellow'));
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log(
|
||||
colorText(`⚠️ Unable to create Windows registry entry: ${error.message}`, 'yellow'),
|
||||
);
|
||||
console.log(colorText(`Registry key: ${registryKey}`, 'yellow'));
|
||||
console.log(colorText(`Manifest path: ${manifestPath}`, 'yellow'));
|
||||
return false; // Windows上如果注册表项创建失败,整个注册过程应该视为失败
|
||||
}
|
||||
}
|
||||
@@ -301,7 +333,7 @@ export async function registerWithElevatedPermissions(): Promise<void> {
|
||||
// 准备命令
|
||||
const command =
|
||||
os.platform() === 'win32'
|
||||
? `mkdir -p "${path.dirname(manifestPath)}" && copy "${tempManifestPath}" "${manifestPath}"`
|
||||
? `if not exist "${path.dirname(manifestPath)}" mkdir "${path.dirname(manifestPath)}" && copy "${tempManifestPath}" "${manifestPath}"`
|
||||
: `mkdir -p "${path.dirname(manifestPath)}" && cp "${tempManifestPath}" "${manifestPath}" && chmod 644 "${manifestPath}"`;
|
||||
|
||||
if (hasElevatedPermissions) {
|
||||
@@ -347,17 +379,29 @@ export async function registerWithElevatedPermissions(): Promise<void> {
|
||||
// 6. Windows特殊处理 - 设置系统级注册表
|
||||
if (os.platform() === 'win32') {
|
||||
const registryKey = `HKLM\\Software\\Google\\Chrome\\NativeMessagingHosts\\${HOST_NAME}`;
|
||||
const regCommand = `reg add "${registryKey}" /ve /t REG_SZ /d "${manifestPath.replace(/\\/g, '\\\\')}" /f`;
|
||||
// 确保路径使用正确的转义格式
|
||||
const escapedPath = manifestPath.replace(/\\/g, '\\\\');
|
||||
const regCommand = `reg add "${registryKey}" /ve /t REG_SZ /d "${escapedPath}" /f`;
|
||||
|
||||
console.log(colorText(`Creating system registry entry: ${registryKey}`, 'blue'));
|
||||
console.log(colorText(`Manifest path: ${manifestPath}`, 'blue'));
|
||||
|
||||
if (hasElevatedPermissions) {
|
||||
// 已经有管理员权限,直接执行注册表命令
|
||||
try {
|
||||
execSync(regCommand, { stdio: 'ignore' });
|
||||
console.log(colorText('Windows registry entry created successfully!', 'green'));
|
||||
execSync(regCommand, { stdio: 'pipe' });
|
||||
|
||||
// 验证注册表项是否创建成功
|
||||
if (verifyWindowsRegistryEntry(registryKey, manifestPath)) {
|
||||
console.log(colorText('Windows registry entry created successfully!', 'green'));
|
||||
} else {
|
||||
console.log(colorText('⚠️ Registry entry created but verification failed', 'yellow'));
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(
|
||||
colorText(`Windows registry entry creation failed: ${error.message}`, 'red'),
|
||||
);
|
||||
console.error(colorText(`Command: ${regCommand}`, 'red'));
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
@@ -368,6 +412,7 @@ export async function registerWithElevatedPermissions(): Promise<void> {
|
||||
console.error(
|
||||
colorText(`Windows registry entry creation failed: ${error.message}`, 'red'),
|
||||
);
|
||||
console.error(colorText(`Command: ${regCommand}`, 'red'));
|
||||
reject(error);
|
||||
} else {
|
||||
console.log(colorText('Windows registry entry created successfully!', 'green'));
|
||||
|
||||
Reference in New Issue
Block a user