diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 97c563cf03..09efc56cd1 100755 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -883,12 +883,6 @@ export async function loadCliConfig( } } - const experimentalCliArgs: Record = {}; - if (argv['experiment'] && Array.isArray(argv['experiment'])) { - for (const entry of argv['experiment']) { - const [key, ...valueParts] = entry.split('='); - const value = valueParts.join('='); - if (key && value !== undefined) { const experimentalCliArgs: Record = Object.create(null); if (argv['experiment'] && Array.isArray(argv['experiment'])) { for (const entry of argv['experiment']) { @@ -904,7 +898,6 @@ export async function loadCliConfig( } } } - } let clientName: string | undefined = undefined; if (isAcpMode) { diff --git a/packages/cli/src/ui/commands/experimentCommand.ts b/packages/cli/src/ui/commands/experimentCommand.ts index ca7b64256e..bdf59b3d05 100644 --- a/packages/cli/src/ui/commands/experimentCommand.ts +++ b/packages/cli/src/ui/commands/experimentCommand.ts @@ -70,7 +70,7 @@ const setExperimentCommand: SlashCommand = { } const name = parts[0]; - const rawValue = parts[1]; + const rawValue = args.trim().substring(name.length).trim(); const id = getExperimentFlagIdFromName(name); if (id === undefined) { @@ -110,13 +110,23 @@ const setExperimentCommand: SlashCommand = { const { settings, config } = context.services; if (!config) return; - const currentExperimental = { - ...((settings.merged.experimental as Record) || {}), + // SECURITY: Only persist user-scoped settings to prevent untrusted workspace settings + // from being promoted to the global user configuration. + const userExperimental = { + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + ...((settings.user.settings['experimental'] as Record) || + {}), }; - currentExperimental[name] = value; + userExperimental[name] = value; - settings.setValue(SettingScope.User, 'experimental', currentExperimental); - config.updateExperimentalSettings(currentExperimental); + settings.setValue(SettingScope.User, 'experimental', userExperimental); + + // Update the live config with the merged state so it takes effect immediately + const mergedExperimental = { + ...((settings.merged.experimental as Record) || {}), + ...userExperimental, + }; + config.updateExperimentalSettings(mergedExperimental); context.ui.addItem({ type: MessageType.INFO, @@ -144,25 +154,33 @@ const unsetExperimentCommand: SlashCommand = { const { settings, config } = context.services; if (!config) return; - const currentExperimental = { - ...((settings.merged.experimental as Record) || {}), + const userExperimental = { + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + ...((settings.user.settings['experimental'] as Record) || + {}), }; - if (!(name in currentExperimental)) { + if (!(name in userExperimental)) { context.ui.addItem({ type: MessageType.ERROR, - text: `No local override found for experiment: ${name}`, + text: `No local user override found for experiment: ${name}`, }); return; } - delete currentExperimental[name]; - settings.setValue(SettingScope.User, 'experimental', currentExperimental); - config.updateExperimentalSettings(currentExperimental); + delete userExperimental[name]; + settings.setValue(SettingScope.User, 'experimental', userExperimental); + + // Update the live config with the new merged state + const mergedExperimental = { + ...((settings.merged.experimental as Record) || {}), + }; + delete mergedExperimental[name]; + config.updateExperimentalSettings(mergedExperimental); context.ui.addItem({ type: MessageType.INFO, - text: `Local override for experiment ${name} removed.`, + text: `Local user override for experiment ${name} removed.`, }); }, };