mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-28 05:55:17 -07:00
Fix extensions enablement bugs (#8797)
This commit is contained in:
@@ -15,6 +15,80 @@ export interface AllExtensionsEnablementConfig {
|
||||
[extensionName: string]: ExtensionEnablementConfig;
|
||||
}
|
||||
|
||||
export class Override {
|
||||
constructor(
|
||||
public baseRule: string,
|
||||
public isDisable: boolean,
|
||||
public includeSubdirs: boolean,
|
||||
) {}
|
||||
|
||||
static fromInput(inputRule: string, includeSubdirs: boolean): Override {
|
||||
const isDisable = inputRule.startsWith('!');
|
||||
let baseRule = isDisable ? inputRule.substring(1) : inputRule;
|
||||
baseRule = ensureLeadingAndTrailingSlash(baseRule);
|
||||
return new Override(baseRule, isDisable, includeSubdirs);
|
||||
}
|
||||
|
||||
static fromFileRule(fileRule: string): Override {
|
||||
const isDisable = fileRule.startsWith('!');
|
||||
let baseRule = isDisable ? fileRule.substring(1) : fileRule;
|
||||
const includeSubdirs = baseRule.endsWith('*');
|
||||
baseRule = includeSubdirs
|
||||
? baseRule.substring(0, baseRule.length - 1)
|
||||
: baseRule;
|
||||
return new Override(baseRule, isDisable, includeSubdirs);
|
||||
}
|
||||
|
||||
conflictsWith(other: Override): boolean {
|
||||
if (this.baseRule === other.baseRule) {
|
||||
return (
|
||||
this.includeSubdirs !== other.includeSubdirs ||
|
||||
this.isDisable !== other.isDisable
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isEqualTo(other: Override): boolean {
|
||||
return (
|
||||
this.baseRule === other.baseRule &&
|
||||
this.includeSubdirs === other.includeSubdirs &&
|
||||
this.isDisable === other.isDisable
|
||||
);
|
||||
}
|
||||
|
||||
asRegex(): RegExp {
|
||||
return globToRegex(`${this.baseRule}${this.includeSubdirs ? '*' : ''}`);
|
||||
}
|
||||
|
||||
isChildOf(parent: Override) {
|
||||
if (!parent.includeSubdirs) {
|
||||
return false;
|
||||
}
|
||||
return parent.asRegex().test(this.baseRule);
|
||||
}
|
||||
|
||||
output(): string {
|
||||
return `${this.isDisable ? '!' : ''}${this.baseRule}${this.includeSubdirs ? '*' : ''}`;
|
||||
}
|
||||
|
||||
matchesPath(path: string) {
|
||||
return this.asRegex().test(path);
|
||||
}
|
||||
}
|
||||
|
||||
const ensureLeadingAndTrailingSlash = function (dirPath: string): string {
|
||||
// Normalize separators to forward slashes for consistent matching across platforms.
|
||||
let result = dirPath.replace(/\\/g, '/');
|
||||
if (result.charAt(0) !== '/') {
|
||||
result = '/' + result;
|
||||
}
|
||||
if (result.charAt(result.length - 1) !== '/') {
|
||||
result = result + '/';
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a glob pattern to a RegExp object.
|
||||
* This is a simplified implementation that supports `*`.
|
||||
@@ -25,7 +99,7 @@ export interface AllExtensionsEnablementConfig {
|
||||
function globToRegex(glob: string): RegExp {
|
||||
const regexString = glob
|
||||
.replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape special regex characters
|
||||
.replace(/\*/g, '.*'); // Convert * to .*
|
||||
.replace(/(\/?)\*/g, '($1.*)?'); // Convert * to optional group
|
||||
|
||||
return new RegExp(`^${regexString}$`);
|
||||
}
|
||||
@@ -52,16 +126,13 @@ export class ExtensionEnablementManager {
|
||||
const extensionConfig = config[extensionName];
|
||||
// Extensions are enabled by default.
|
||||
let enabled = true;
|
||||
|
||||
for (const rule of extensionConfig?.overrides ?? []) {
|
||||
const isDisableRule = rule.startsWith('!');
|
||||
const globPattern = isDisableRule ? rule.substring(1) : rule;
|
||||
const regex = globToRegex(globPattern);
|
||||
if (regex.test(currentPath)) {
|
||||
enabled = !isDisableRule;
|
||||
const allOverrides = extensionConfig?.overrides ?? [];
|
||||
for (const rule of allOverrides) {
|
||||
const override = Override.fromFileRule(rule);
|
||||
if (override.matchesPath(ensureLeadingAndTrailingSlash(currentPath))) {
|
||||
enabled = !override.isDisable;
|
||||
}
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@@ -96,24 +167,19 @@ export class ExtensionEnablementManager {
|
||||
if (!config[extensionName]) {
|
||||
config[extensionName] = { overrides: [] };
|
||||
}
|
||||
|
||||
const pathWithGlob = `${scopePath}*`;
|
||||
const pathWithoutGlob = scopePath;
|
||||
|
||||
const newPath = includeSubdirs ? pathWithGlob : pathWithoutGlob;
|
||||
const conflictingPath = includeSubdirs ? pathWithoutGlob : pathWithGlob;
|
||||
|
||||
config[extensionName].overrides = config[extensionName].overrides.filter(
|
||||
(rule) =>
|
||||
rule !== conflictingPath &&
|
||||
rule !== `!${conflictingPath}` &&
|
||||
rule !== `!${newPath}`,
|
||||
);
|
||||
|
||||
if (!config[extensionName].overrides.includes(newPath)) {
|
||||
config[extensionName].overrides.push(newPath);
|
||||
}
|
||||
|
||||
const override = Override.fromInput(scopePath, includeSubdirs);
|
||||
const overrides = config[extensionName].overrides.filter((rule) => {
|
||||
const fileOverride = Override.fromFileRule(rule);
|
||||
if (
|
||||
fileOverride.conflictsWith(override) ||
|
||||
fileOverride.isEqualTo(override)
|
||||
) {
|
||||
return false; // Remove conflicts and equivalent values.
|
||||
}
|
||||
return !fileOverride.isChildOf(override);
|
||||
});
|
||||
overrides.push(override.output());
|
||||
config[extensionName].overrides = overrides;
|
||||
this.writeConfig(config);
|
||||
}
|
||||
|
||||
@@ -122,30 +188,7 @@ export class ExtensionEnablementManager {
|
||||
includeSubdirs: boolean,
|
||||
scopePath: string,
|
||||
): void {
|
||||
const config = this.readConfig();
|
||||
if (!config[extensionName]) {
|
||||
config[extensionName] = { overrides: [] };
|
||||
}
|
||||
|
||||
const pathWithGlob = `${scopePath}*`;
|
||||
const pathWithoutGlob = scopePath;
|
||||
|
||||
const targetPath = includeSubdirs ? pathWithGlob : pathWithoutGlob;
|
||||
const newRule = `!${targetPath}`;
|
||||
const conflictingPath = includeSubdirs ? pathWithoutGlob : pathWithGlob;
|
||||
|
||||
config[extensionName].overrides = config[extensionName].overrides.filter(
|
||||
(rule) =>
|
||||
rule !== conflictingPath &&
|
||||
rule !== `!${conflictingPath}` &&
|
||||
rule !== targetPath,
|
||||
);
|
||||
|
||||
if (!config[extensionName].overrides.includes(newRule)) {
|
||||
config[extensionName].overrides.push(newRule);
|
||||
}
|
||||
|
||||
this.writeConfig(config);
|
||||
this.enable(extensionName, includeSubdirs, `!${scopePath}`);
|
||||
}
|
||||
|
||||
remove(extensionName: string): void {
|
||||
|
||||
Reference in New Issue
Block a user