summaryrefslogtreecommitdiff
path: root/packages/cli/src/config/settings.ts
diff options
context:
space:
mode:
authorjerop <[email protected]>2025-06-06 13:54:59 +0000
committerJerop Kipruto <[email protected]>2025-06-06 11:47:37 -0400
commit4e9d365407564e0f440bf4645607aa47a1d16bca (patch)
tree257684bdade5e42fe7a07bd304321a990ea4ede7 /packages/cli/src/config/settings.ts
parent9ad615c2a486675c4ad75c986a0a5dbd8f8b030e (diff)
feat: Enable environment variable substitution in settings
This commit introduces the ability to use system environment variables within the settings files (e.g., `settings.json`). Users can now reference environment variables using the `${VAR_NAME}` syntax. This enhancement improves security and flexibility, particularly for configurations like MCP server settings, which often require sensitive tokens. Previously, to configure an MCP server, a token might be directly embedded: ```json "mcpServers": { "github": { "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "pat_abc123" } // ... } } ``` With this change, the same configuration can securely reference an environment variable: ```json "mcpServers": { "github": { "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}" } // ... } } ``` This allows users to avoid storing secrets directly in configuration files.
Diffstat (limited to 'packages/cli/src/config/settings.ts')
-rw-r--r--packages/cli/src/config/settings.ts41
1 files changed, 39 insertions, 2 deletions
diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts
index db5dabb6..8205a018 100644
--- a/packages/cli/src/config/settings.ts
+++ b/packages/cli/src/config/settings.ts
@@ -98,6 +98,39 @@ export class LoadedSettings {
}
}
+function resolveEnvVarsInString(value: string): string {
+ const envVarRegex = /\$(?:(\w+)|{([^}]+)})/g; // Find $VAR_NAME or ${VAR_NAME}
+ return value.replace(envVarRegex, (match, varName1, varName2) => {
+ const varName = varName1 || varName2;
+ if (process && process.env && typeof process.env[varName] === 'string') {
+ return process.env[varName]!;
+ }
+ return match;
+ });
+}
+
+function resolveEnvVarsInObject<T>(obj: T): T {
+ if (typeof obj === 'string') {
+ return resolveEnvVarsInString(obj) as unknown as T;
+ }
+
+ if (Array.isArray(obj)) {
+ return obj.map((item) => resolveEnvVarsInObject(item)) as unknown as T;
+ }
+
+ if (obj && typeof obj === 'object') {
+ const newObj = { ...obj } as T;
+ for (const key in newObj) {
+ if (Object.prototype.hasOwnProperty.call(newObj, key)) {
+ newObj[key] = resolveEnvVarsInObject(newObj[key]);
+ }
+ }
+ return newObj;
+ }
+
+ return obj;
+}
+
/**
* Loads settings from user and workspace directories.
* Project settings override user settings.
@@ -110,7 +143,10 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
try {
if (fs.existsSync(USER_SETTINGS_PATH)) {
const userContent = fs.readFileSync(USER_SETTINGS_PATH, 'utf-8');
- userSettings = JSON.parse(stripJsonComments(userContent)) as Settings;
+ const parsedUserSettings = JSON.parse(
+ stripJsonComments(userContent),
+ ) as Settings;
+ userSettings = resolveEnvVarsInObject(parsedUserSettings);
// Support legacy theme names
if (userSettings.theme && userSettings.theme === 'VS') {
userSettings.theme = DefaultLight.name;
@@ -132,9 +168,10 @@ export function loadSettings(workspaceDir: string): LoadedSettings {
try {
if (fs.existsSync(workspaceSettingsPath)) {
const projectContent = fs.readFileSync(workspaceSettingsPath, 'utf-8');
- workspaceSettings = JSON.parse(
+ const parsedWorkspaceSettings = JSON.parse(
stripJsonComments(projectContent),
) as Settings;
+ workspaceSettings = resolveEnvVarsInObject(parsedWorkspaceSettings);
if (workspaceSettings.theme && workspaceSettings.theme === 'VS') {
workspaceSettings.theme = DefaultLight.name;
} else if (