Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/cli/src/utils/installationInfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,30 @@ describe('getInstallationInfo', () => {
expect(infoDisabled.updateMessage).toContain('Please run npm install');
});

it('should detect Volta installation (Unix-style)', () => {
const voltaPath =
'/Users/test/.volta/tools/image/node/20.0.0/lib/node_modules/@google/gemini-cli/dist/index.js';
process.argv[1] = voltaPath;
mockedRealPathSync.mockReturnValue(voltaPath);

const info = getInstallationInfo(projectRoot, true);

expect(info.packageManager).toBe(PackageManager.VOLTA);
expect(info.updateCommand).toBe('volta install @google/gemini-cli@latest');
});

it('should detect Volta installation (Windows-style)', () => {
const voltaPath =
'C:\\Users\\test\\AppData\\Local\\Volta\\tools\\image\\node\\20.0.0\\node_modules\\@google/gemini-cli\\dist\\index.js';
process.argv[1] = voltaPath;
mockedRealPathSync.mockReturnValue(voltaPath);

const info = getInstallationInfo(projectRoot, true);

expect(info.packageManager).toBe(PackageManager.VOLTA);
expect(info.updateCommand).toBe('volta install @google/gemini-cli@latest');
});

it('should NOT detect Homebrew if gemini-cli is installed in brew but running from npm location', () => {
Object.defineProperty(process, 'platform', {
value: 'darwin',
Expand Down
14 changes: 14 additions & 0 deletions packages/cli/src/utils/installationInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum PackageManager {
HOMEBREW = 'homebrew',
NPX = 'npx',
BINARY = 'binary',
VOLTA = 'volta',
UNKNOWN = 'unknown',
}

Expand Down Expand Up @@ -116,6 +117,19 @@ export function getInstallationInfo(
}
}

// Check for Volta
if (realPath.includes('/.volta/') || realPath.includes('/Volta/')) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The detection logic for Volta is too broad and may lead to false positives if the project or any parent directory is named Volta or .volta. Since Volta specifically installs global tools into a tools/image subdirectory, it's safer to include that in the check to ensure we are actually running from a Volta-managed installation. Ensure consistent path resolution by using a single, robust function like resolveToRealPath for all related path validations.

Suggested change
if (realPath.includes('/.volta/') || realPath.includes('/Volta/')) {
if (realPath.includes('/.volta/tools/image/') || realPath.includes('/Volta/tools/image/')) {
References
  1. Ensure consistent path resolution by using a single, robust function (e.g., resolveToRealPath) for all related path validations.

const updateCommand = 'volta install @google/gemini-cli@latest';
return {
packageManager: PackageManager.VOLTA,
isGlobal: true,
updateCommand,
updateMessage: isAutoUpdateEnabled
? 'Installed with Volta. Attempting to automatically update now...'
: `Please run ${updateCommand} to update`,
};
}

// Check for pnpm
if (
realPath.includes('/.pnpm/global') ||
Expand Down
Loading