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:
yiliang114
2025-12-03 00:27:20 +08:00
parent 2e449f4d45
commit c6299bf135
14 changed files with 788 additions and 198 deletions

View File

@@ -20,7 +20,7 @@ import type {
} from './connectionTypes.js';
import { AcpMessageHandler } from './acpMessageHandler.js';
import { AcpSessionManager } from './acpSessionManager.js';
import { statSync } from 'fs';
import { determineNodePathForCli } from '../cli/cliPathDetector.js';
/**
* ACP Connection Handler for VSCode Extension
@@ -66,74 +66,6 @@ export class AcpConnection {
this.sessionManager = new AcpSessionManager();
}
/**
* 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
*/
private determineNodePathForCli(cliPath: string): string | null {
// 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 {
if (statSync(nodePath).isFile()) {
// Verify it's executable
const stats = statSync(nodePath);
if (stats.mode & 0o111) {
// Check if executable
console.log(
`[ACP] Found Node.js executable for CLI at: ${nodePath}`,
);
return nodePath;
}
}
} catch (_error) {
// File doesn't exist or other error, continue to next pattern
continue;
}
}
// 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 {
if (statSync(nodePath).isFile()) {
const stats = statSync(nodePath);
if (stats.mode & 0o111) {
console.log(
`[ACP] Found Node.js executable in CLI directory at: ${nodePath}`,
);
return nodePath;
}
}
} catch (_error) {
// File doesn't exist, continue
continue;
}
}
console.log(`[ACP] Could not determine Node.js path for CLI: ${cliPath}`);
return null;
}
/**
* Connect to ACP backend
*
@@ -185,14 +117,21 @@ export class AcpConnection {
// Handle various Node.js version managers (nvm, n, manual installations)
if (cliPath.includes('/qwen') && !isWindows) {
// Try to determine the correct node executable for this qwen installation
const nodePath = this.determineNodePathForCli(cliPath);
if (nodePath) {
spawnCommand = nodePath;
const nodePathResult = determineNodePathForCli(cliPath);
if (nodePathResult.path) {
spawnCommand = nodePathResult.path;
spawnArgs = [cliPath, '--experimental-acp', ...extraArgs];
} else {
// Fallback to direct execution
spawnCommand = cliPath;
spawnArgs = ['--experimental-acp', ...extraArgs];
// Log any error for debugging
if (nodePathResult.error) {
console.warn(
`[ACP] Node.js path detection warning: ${nodePathResult.error}`,
);
}
}
} else {
spawnCommand = cliPath;