feat(core): support QWEN_HOME env var to customize config directory#2953
feat(core): support QWEN_HOME env var to customize config directory#2953tanzhenxin wants to merge 7 commits intomainfrom
Conversation
…tory Allow users to override the default ~/.qwen config directory location via the QWEN_CONFIG_DIR environment variable. This enables users on dev machines with external disk mounts or custom home directory layouts to persist config at a location of their choosing. Changes: - Add QWEN_CONFIG_DIR check to Storage.getGlobalQwenDir() (absolute and relative path support) - Eliminate 11 redundant '.qwen' constant definitions across packages - Replace 16+ direct os.homedir() + '.qwen' path constructions with Storage.getGlobalQwenDir() calls - Inline env var checks for packages that cannot import from core (channels, vscode-ide-companion, standalone scripts) - Add unit tests for the new env var behavior - Project-level .qwen/ directories are NOT affected Closes #2951
📋 Review SummaryThis PR adds support for the 🔍 General Feedback
🎯 Specific Feedback🟡 High
static getGlobalQwenDir(): string {
const envDir = process.env['QWEN_CONFIG_DIR'];
if (envDir) {
return this.resolveRuntimeBaseDir(envDir) ?? path.join(os.homedir(), QWEN_DIR);
}
// ... rest of implementation
}
🟢 Medium
if (envDir && envDir.trim()) {
return path.isAbsolute(envDir) ? envDir : path.resolve(envDir);
}
🔵 Low
✅ Highlights
|
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
… compat Hardcoded Unix paths like '/tmp/custom-qwen/settings.json' fail on Windows where path APIs produce backslash separators. Use path.resolve() for inputs and path.join() for assertions so the tests pass cross-platform.
…opes' test Timing-sensitive UI test that fails intermittently on Windows CI due to async ANSI output not settling within the wait window.
…getGlobalQwenDir() Update channel status, memory command, extension storage, skills discovery, and memory discovery to use Storage.getGlobalQwenDir() instead of hardcoded os.homedir()/.qwen paths, ensuring QWEN_CONFIG_DIR env var is respected throughout the codebase.
…alQwenDir Storage.getGlobalQwenDir() is now called during Config construction, which requires os.homedir() to be mocked before makeFakeConfig() is called. Also mock Storage.getGlobalQwenDir in memoryCommand tests since it uses a cross-package import that vi.spyOn doesn't intercept.
wenshao
left a comment
There was a problem hiding this comment.
[Critical] packages/cli/src/ui/AppContainer.tsx reimplements mid-turn queue draining from React state instead of using the hook's atomic drainQueue(). Because addMessage() writes the real queue synchronously before the next render, a tool-completion callback can drain a stale mirror and then clear the real queue, dropping freshly queued user input.
Suggested fix: reuse useMessageQueue()'s drainQueue() directly instead of maintaining a separate state-backed mirror in AppContainer.
— gpt-5.4 via Qwen Code /review
findEnvFile() walk-up would find legacy ~/.qwen/.env before checking QWEN_CONFIG_DIR/.env when the workspace was under $HOME. Skip the legacy path when a custom config dir is set so the fallback picks up the correct file. Also add a legacy fallback in readSourceInfo() since the installer always writes source.json to ~/.qwen/ regardless of QWEN_CONFIG_DIR.
…ath resolution Rename the env var before it ships (zero existing users) to match the convention of CARGO_HOME, GRADLE_USER_HOME, etc. — "HOME" means "root of all tool state", not just config. Key changes: - Rename QWEN_CONFIG_DIR → QWEN_HOME across all packages and scripts - Add shared path utils in vscode-ide-companion and channels/base to eliminate scattered inline env var resolution - Fix runtime path mismatch: IDE lock files and session paths in the vscode extension now route through getRuntimeBaseDir() (checking QWEN_RUNTIME_DIR first), matching core Storage behavior - Fix telemetry_utils.js otel path to check QWEN_RUNTIME_DIR for tmp/ - Add E2E integration tests for QWEN_HOME scenarios
tanzhenxin
left a comment
There was a problem hiding this comment.
Re: the AppContainer.tsx comment — not applicable. That file is not in this PR's changed files. This appears to be an unrelated finding from the automated review.
TLDR
Add support for the
QWEN_HOMEenvironment variable, allowing users to customize the~/.qwenconfig directory location. This is useful for users on dev machines with external disk mounts who cannot persist config at the default path.Interaction with
QWEN_RUNTIME_DIR~/.qwen~/.qwenQWEN_HOMEonlyQWEN_HOMEQWEN_HOMEQWEN_RUNTIME_DIRonly~/.qwenQWEN_RUNTIME_DIRQWEN_HOMEQWEN_RUNTIME_DIRThe 99% use case is "set
QWEN_HOMEonly" — everything moves together.Screenshots / Video Demo
N/A — no user-facing change beyond env var support. To verify:
Dive Deeper
Key design decisions:
Storage.getGlobalQwenDir()is the single source of truth — all global config paths flow through it.qwen/directories (workspace settings, project commands, etc.) are NOT affected by this env varvscode-ide-companion,channels, standalone scripts) use shared path utility modules within each package boundary instead of scattered inline logicgetRuntimeBaseDir(), checkingQWEN_RUNTIME_DIRfirst — fixing a path mismatch when both env vars are setprocess.cwd())What changed where:
storage.tsQWEN_CONFIG_DIR→QWEN_HOMEvscode-ide-companion/src/utils/paths.ts,channels/base/src/paths.tsgetGlobalQwenDir()andgetRuntimeBaseDir()ide-server.ts,qwenSessionManager.ts,qwenSessionReader.tsPairingStore.ts,accounts.tstelemetry.js,telemetry_utils.js,sandbox_command.jssettingsSchema.ts,settings.schema.jsonstorage.test.ts,config.test.tsqwen-config-dir.test.tsReviewer Test Plan
cd packages/core && npx vitest run src/config/storage.test.ts— tests cover absolute path, relative path, default fallback, config-path routing, project-level isolation, and independence fromQWEN_RUNTIME_DIRcd packages/core && npx vitest run src/core/prompts.test.ts src/tools/memoryTool.test.ts src/qwen/qwenOAuth2.test.ts src/qwen/sharedTokenManager.test.ts— all passnpm run build && npm run bundle && npx vitest run integration-tests/cli/qwen-config-dir.test.ts— 7 scenarios covering basic routing, dir creation, relative paths, project isolation, and QWEN_RUNTIME_DIR interactionQWEN_HOMEset — behavior should be identical to beforeTesting Matrix
Linked issues / bugs
Closes #2951