mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 17:27:54 +00:00
feat(vscode-ide-companion): improve CLI path detection and error handling
- Move determineNodePathForCli function to dedicated cliPathDetector.ts file - Enhance error handling with specific guidance for permission issues - Add detailed error messages for different failure scenarios - Improve logging for debugging CLI path detection issues This change improves the reliability of CLI path detection by providing better error messages and handling edge cases more gracefully.
This commit is contained in:
@@ -124,9 +124,26 @@ export class CliDetector {
|
||||
} catch (detectionError) {
|
||||
console.log('[CliDetector] CLI not found, error:', detectionError);
|
||||
// CLI not found
|
||||
let error = `Qwen Code CLI not found in PATH. Please install it using: npm install -g @qwen-code/qwen-code@latest`;
|
||||
|
||||
// Provide specific guidance for permission errors
|
||||
if (detectionError instanceof Error) {
|
||||
const errorMessage = detectionError.message;
|
||||
if (
|
||||
errorMessage.includes('EACCES') ||
|
||||
errorMessage.includes('Permission denied')
|
||||
) {
|
||||
error += `\n\nThis may be due to permission issues. Possible solutions:
|
||||
\n1. Reinstall the CLI without sudo: npm install -g @qwen-code/qwen-code@latest
|
||||
\n2. If previously installed with sudo, fix ownership: sudo chown -R $(whoami) $(npm config get prefix)/lib/node_modules/@qwen-code/qwen-code
|
||||
\n3. Use nvm for Node.js version management to avoid permission issues
|
||||
\n4. Check your PATH environment variable includes npm's global bin directory`;
|
||||
}
|
||||
}
|
||||
|
||||
this.cachedResult = {
|
||||
isInstalled: false,
|
||||
error: `Qwen Code CLI not found in PATH. Please install it using: npm install -g @qwen-code/qwen-code@latest`,
|
||||
error,
|
||||
};
|
||||
this.lastCheckTime = now;
|
||||
return this.cachedResult;
|
||||
@@ -135,9 +152,24 @@ export class CliDetector {
|
||||
console.log('[CliDetector] General detection error:', error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
|
||||
let userFriendlyError = `Failed to detect Qwen Code CLI: ${errorMessage}`;
|
||||
|
||||
// Provide specific guidance for permission errors
|
||||
if (
|
||||
errorMessage.includes('EACCES') ||
|
||||
errorMessage.includes('Permission denied')
|
||||
) {
|
||||
userFriendlyError += `\n\nThis may be due to permission issues. Possible solutions:
|
||||
\n1. Reinstall the CLI without sudo: npm install -g @qwen-code/qwen-code@latest
|
||||
\n2. If previously installed with sudo, fix ownership: sudo chown -R $(whoami) $(npm config get prefix)/lib/node_modules/@qwen-code/qwen-code
|
||||
\n3. Use nvm for Node.js version management to avoid permission issues
|
||||
\n4. Check your PATH environment variable includes npm's global bin directory`;
|
||||
}
|
||||
|
||||
this.cachedResult = {
|
||||
isInstalled: false,
|
||||
error: `Failed to detect Qwen Code CLI: ${errorMessage}`,
|
||||
error: userFriendlyError,
|
||||
};
|
||||
this.lastCheckTime = now;
|
||||
return this.cachedResult;
|
||||
|
||||
@@ -161,9 +161,23 @@ export class CliInstaller {
|
||||
console.error('[CliInstaller] Installation failed:', errorMessage);
|
||||
console.error('[CliInstaller] Error stack:', error);
|
||||
|
||||
// Provide specific guidance for permission errors
|
||||
let userFriendlyMessage = `Failed to install Qwen Code CLI: ${errorMessage}`;
|
||||
|
||||
if (
|
||||
errorMessage.includes('EACCES') ||
|
||||
errorMessage.includes('Permission denied')
|
||||
) {
|
||||
userFriendlyMessage += `\n\nThis is likely due to permission issues. Possible solutions:
|
||||
\n1. Reinstall without sudo: npm install -g @qwen-code/qwen-code@latest
|
||||
\n2. Fix npm permissions: sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
|
||||
\n3. Use nvm for Node.js version management to avoid permission issues
|
||||
\n4. Configure npm to use a different directory: npm config set prefix ~/.npm-global`;
|
||||
}
|
||||
|
||||
vscode.window
|
||||
.showErrorMessage(
|
||||
`Failed to install Qwen Code CLI: ${errorMessage}`,
|
||||
userFriendlyMessage,
|
||||
'Try Manual Installation',
|
||||
'View Documentation',
|
||||
)
|
||||
@@ -173,9 +187,26 @@ export class CliInstaller {
|
||||
'Qwen Code Installation',
|
||||
);
|
||||
terminal.show();
|
||||
terminal.sendText(
|
||||
'npm install -g @qwen-code/qwen-code@latest',
|
||||
);
|
||||
|
||||
// Provide different installation commands based on error type
|
||||
if (
|
||||
errorMessage.includes('EACCES') ||
|
||||
errorMessage.includes('Permission denied')
|
||||
) {
|
||||
terminal.sendText('# Try installing without sudo:');
|
||||
terminal.sendText(
|
||||
'npm install -g @qwen-code/qwen-code@latest',
|
||||
);
|
||||
terminal.sendText('');
|
||||
terminal.sendText('# Or fix npm permissions:');
|
||||
terminal.sendText(
|
||||
'sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}',
|
||||
);
|
||||
} else {
|
||||
terminal.sendText(
|
||||
'npm install -g @qwen-code/qwen-code@latest',
|
||||
);
|
||||
}
|
||||
} else if (selection === 'View Documentation') {
|
||||
vscode.env.openExternal(
|
||||
vscode.Uri.parse(
|
||||
|
||||
128
packages/vscode-ide-companion/src/cli/cliPathDetector.ts
Normal file
128
packages/vscode-ide-companion/src/cli/cliPathDetector.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { statSync } from 'fs';
|
||||
|
||||
export interface CliPathDetectionResult {
|
||||
path: string | null;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the correct Node.js executable path for a given CLI installation
|
||||
* Handles various Node.js version managers (nvm, n, manual installations)
|
||||
*
|
||||
* @param cliPath - Path to the CLI executable
|
||||
* @returns Path to the Node.js executable, or null if not found
|
||||
*/
|
||||
export function determineNodePathForCli(
|
||||
cliPath: string,
|
||||
): CliPathDetectionResult {
|
||||
// Common patterns for Node.js installations
|
||||
const nodePathPatterns = [
|
||||
// NVM pattern: /Users/user/.nvm/versions/node/vXX.XX.X/bin/qwen -> /Users/user/.nvm/versions/node/vXX.XX.X/bin/node
|
||||
cliPath.replace(/\/bin\/qwen$/, '/bin/node'),
|
||||
|
||||
// N pattern: /Users/user/n/bin/qwen -> /Users/user/n/bin/node
|
||||
cliPath.replace(/\/bin\/qwen$/, '/bin/node'),
|
||||
|
||||
// Manual installation pattern: /usr/local/bin/qwen -> /usr/local/bin/node
|
||||
cliPath.replace(/\/qwen$/, '/node'),
|
||||
|
||||
// Alternative pattern: /opt/nodejs/bin/qwen -> /opt/nodejs/bin/node
|
||||
cliPath.replace(/\/bin\/qwen$/, '/bin/node'),
|
||||
];
|
||||
|
||||
// Check each pattern
|
||||
for (const nodePath of nodePathPatterns) {
|
||||
try {
|
||||
const stats = statSync(nodePath);
|
||||
if (stats.isFile()) {
|
||||
// Verify it's executable
|
||||
if (stats.mode & 0o111) {
|
||||
console.log(`[CLI] Found Node.js executable for CLI at: ${nodePath}`);
|
||||
return { path: nodePath };
|
||||
} else {
|
||||
console.log(`[CLI] Node.js found at ${nodePath} but not executable`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Node.js found at ${nodePath} but not executable. You may need to fix file permissions or reinstall the CLI.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Differentiate between error types
|
||||
if (error instanceof Error) {
|
||||
if ('code' in error && error.code === 'EACCES') {
|
||||
console.log(`[CLI] Permission denied accessing ${nodePath}`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Permission denied accessing ${nodePath}. The CLI may have been installed with sudo privileges. Try reinstalling without sudo or adjusting file permissions.`,
|
||||
};
|
||||
} else if ('code' in error && error.code === 'ENOENT') {
|
||||
// File not found, continue to next pattern
|
||||
continue;
|
||||
} else {
|
||||
console.log(`[CLI] Error accessing ${nodePath}: ${error.message}`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Error accessing Node.js at ${nodePath}: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find node in the same directory as the CLI
|
||||
const cliDir = cliPath.substring(0, cliPath.lastIndexOf('/'));
|
||||
const potentialNodePaths = [`${cliDir}/node`, `${cliDir}/bin/node`];
|
||||
|
||||
for (const nodePath of potentialNodePaths) {
|
||||
try {
|
||||
const stats = statSync(nodePath);
|
||||
if (stats.isFile()) {
|
||||
if (stats.mode & 0o111) {
|
||||
console.log(
|
||||
`[CLI] Found Node.js executable in CLI directory at: ${nodePath}`,
|
||||
);
|
||||
return { path: nodePath };
|
||||
} else {
|
||||
console.log(`[CLI] Node.js found at ${nodePath} but not executable`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Node.js found at ${nodePath} but not executable. You may need to fix file permissions or reinstall the CLI.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Differentiate between error types
|
||||
if (error instanceof Error) {
|
||||
if ('code' in error && error.code === 'EACCES') {
|
||||
console.log(`[CLI] Permission denied accessing ${nodePath}`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Permission denied accessing ${nodePath}. The CLI may have been installed with sudo privileges. Try reinstalling without sudo or adjusting file permissions.`,
|
||||
};
|
||||
} else if ('code' in error && error.code === 'ENOENT') {
|
||||
// File not found, continue
|
||||
continue;
|
||||
} else {
|
||||
console.log(`[CLI] Error accessing ${nodePath}: ${error.message}`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Error accessing Node.js at ${nodePath}: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[CLI] Could not determine Node.js path for CLI: ${cliPath}`);
|
||||
return {
|
||||
path: null,
|
||||
error: `Could not find Node.js executable for CLI at ${cliPath}. Please verify the CLI installation.`,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user