summaryrefslogtreecommitdiff
path: root/packages/cli/src
diff options
context:
space:
mode:
authorTIRUMALASETTI PRANITH <[email protected]>2025-08-02 03:52:17 +0530
committerGitHub <[email protected]>2025-08-01 22:22:17 +0000
commit15a1f1af9d0e4628e9e82f81d384d614899770e3 (patch)
tree19c1c76b177faa5c774f06de2f150a13a03fc57b /packages/cli/src
parent387706607dfa372f4f0c6fee14286bf4a290b258 (diff)
fix(config): Resolve duplicate config loading from home directory (#5090)
Co-authored-by: Allen Hutchison <[email protected]> Co-authored-by: Allen Hutchison <[email protected]>
Diffstat (limited to 'packages/cli/src')
-rw-r--r--packages/cli/src/config/config.ts17
-rw-r--r--packages/cli/src/config/settings.test.ts16
-rw-r--r--packages/cli/src/config/settings.ts59
3 files changed, 68 insertions, 24 deletions
diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts
index a147bca8..9274b65e 100644
--- a/packages/cli/src/config/config.ts
+++ b/packages/cli/src/config/config.ts
@@ -4,6 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
+import * as fs from 'fs';
+import * as path from 'path';
+import { homedir } from 'node:os';
import yargs from 'yargs/yargs';
import { hideBin } from 'yargs/helpers';
import process from 'node:process';
@@ -244,16 +247,24 @@ export async function loadHierarchicalGeminiMemory(
memoryImportFormat: 'flat' | 'tree' = 'tree',
fileFilteringOptions?: FileFilteringOptions,
): Promise<{ memoryContent: string; fileCount: number }> {
+ // FIX: Use real, canonical paths for a reliable comparison to handle symlinks.
+ const realCwd = fs.realpathSync(path.resolve(currentWorkingDirectory));
+ const realHome = fs.realpathSync(path.resolve(homedir()));
+ const isHomeDirectory = realCwd === realHome;
+
+ // If it is the home directory, pass an empty string to the core memory
+ // function to signal that it should skip the workspace search.
+ const effectiveCwd = isHomeDirectory ? '' : currentWorkingDirectory;
+
if (debugMode) {
logger.debug(
`CLI: Delegating hierarchical memory load to server for CWD: ${currentWorkingDirectory} (memoryImportFormat: ${memoryImportFormat})`,
);
}
- // Directly call the server function.
- // The server function will use its own homedir() for the global path.
+ // Directly call the server function with the corrected path.
return loadServerHierarchicalMemory(
- currentWorkingDirectory,
+ effectiveCwd,
debugMode,
fileService,
extensionContextFilePaths,
diff --git a/packages/cli/src/config/settings.test.ts b/packages/cli/src/config/settings.test.ts
index 5a54e46e..b8ecbb62 100644
--- a/packages/cli/src/config/settings.test.ts
+++ b/packages/cli/src/config/settings.test.ts
@@ -59,7 +59,21 @@ const MOCK_WORKSPACE_SETTINGS_PATH = pathActual.join(
'settings.json',
);
-vi.mock('fs');
+vi.mock('fs', async (importOriginal) => {
+ // Get all the functions from the real 'fs' module
+ const actualFs = await importOriginal<typeof fs>();
+
+ return {
+ ...actualFs, // Keep all the real functions
+ // Now, just override the ones we need for the test
+ existsSync: vi.fn(),
+ readFileSync: vi.fn(),
+ writeFileSync: vi.fn(),
+ mkdirSync: vi.fn(),
+ realpathSync: (p: string) => p,
+ };
+});
+
vi.mock('strip-json-comments', () => ({
default: vi.fn((content) => content),
}));
diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts
index 4f701c6d..a875ffc1 100644
--- a/packages/cli/src/config/settings.ts
+++ b/packages/cli/src/config/settings.ts
@@ -312,6 +312,22 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
let workspaceSettings: Settings = {};
const settingsErrors: SettingsError[] = [];
const systemSettingsPath = getSystemSettingsPath();
+
+ // FIX: Resolve paths to their canonical representation to handle symlinks
+ const resolvedWorkspaceDir = path.resolve(workspaceDir);
+ const resolvedHomeDir = path.resolve(homedir());
+
+ let realWorkspaceDir = resolvedWorkspaceDir;
+ try {
+ // fs.realpathSync gets the "true" path, resolving any symlinks
+ realWorkspaceDir = fs.realpathSync(resolvedWorkspaceDir);
+ } catch (_e) {
+ // This is okay. The path might not exist yet, and that's a valid state.
+ }
+
+ // We expect homedir to always exist and be resolvable.
+ const realHomeDir = fs.realpathSync(resolvedHomeDir);
+
// Load system settings
try {
if (fs.existsSync(systemSettingsPath)) {
@@ -356,28 +372,31 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
'settings.json',
);
- // Load workspace settings
- try {
- if (fs.existsSync(workspaceSettingsPath)) {
- const projectContent = fs.readFileSync(workspaceSettingsPath, 'utf-8');
- const parsedWorkspaceSettings = JSON.parse(
- stripJsonComments(projectContent),
- ) as Settings;
- workspaceSettings = resolveEnvVarsInObject(parsedWorkspaceSettings);
- if (workspaceSettings.theme && workspaceSettings.theme === 'VS') {
- workspaceSettings.theme = DefaultLight.name;
- } else if (
- workspaceSettings.theme &&
- workspaceSettings.theme === 'VS2015'
- ) {
- workspaceSettings.theme = DefaultDark.name;
+ // This comparison is now much more reliable.
+ if (realWorkspaceDir !== realHomeDir) {
+ // Load workspace settings
+ try {
+ if (fs.existsSync(workspaceSettingsPath)) {
+ const projectContent = fs.readFileSync(workspaceSettingsPath, 'utf-8');
+ const parsedWorkspaceSettings = JSON.parse(
+ stripJsonComments(projectContent),
+ ) as Settings;
+ workspaceSettings = resolveEnvVarsInObject(parsedWorkspaceSettings);
+ if (workspaceSettings.theme && workspaceSettings.theme === 'VS') {
+ workspaceSettings.theme = DefaultLight.name;
+ } else if (
+ workspaceSettings.theme &&
+ workspaceSettings.theme === 'VS2015'
+ ) {
+ workspaceSettings.theme = DefaultDark.name;
+ }
}
+ } catch (error: unknown) {
+ settingsErrors.push({
+ message: getErrorMessage(error),
+ path: workspaceSettingsPath,
+ });
}
- } catch (error: unknown) {
- settingsErrors.push({
- message: getErrorMessage(error),
- path: workspaceSettingsPath,
- });
}
return new LoadedSettings(