@google/gemini-cli 0.0.777 → 0.0.899

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@google/gemini-cli",
3
- "version": "0.0.777",
3
+ "version": "0.0.899",
4
4
  "description": "Gemini CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,14 +22,10 @@
22
22
  "typecheck": "tsc --noEmit"
23
23
  },
24
24
  "files": [
25
- "dist",
26
- "npm-shrinkwrap.json"
27
- ],
28
- "bundleDependencies": [
29
- "@google/gemini-cli-core"
25
+ "dist"
30
26
  ],
31
27
  "config": {
32
- "sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.0.777"
28
+ "sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.0.899"
33
29
  },
34
30
  "dependencies": {
35
31
  "@google/gemini-cli-core": "file:../core",
@@ -4,10 +4,9 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { type CommandModule } from 'yargs';
7
- import { SettingScope } from '../../config/settings.js';
8
7
  interface DisableArgs {
9
8
  name: string;
10
- scope: SettingScope;
9
+ scope?: string;
11
10
  }
12
11
  export declare function handleDisable(args: DisableArgs): void;
13
12
  export declare const disableCommand: CommandModule;
@@ -9,7 +9,12 @@ import { SettingScope } from '../../config/settings.js';
9
9
  import { getErrorMessage } from '../../utils/errors.js';
10
10
  export function handleDisable(args) {
11
11
  try {
12
- disableExtension(args.name, args.scope);
12
+ if (args.scope?.toLowerCase() === 'workspace') {
13
+ disableExtension(args.name, SettingScope.Workspace);
14
+ }
15
+ else {
16
+ disableExtension(args.name, SettingScope.User);
17
+ }
13
18
  console.log(`Extension "${args.name}" successfully disabled for scope "${args.scope}".`);
14
19
  }
15
20
  catch (error) {
@@ -29,9 +34,18 @@ export const disableCommand = {
29
34
  describe: 'The scope to disable the extenison in.',
30
35
  type: 'string',
31
36
  default: SettingScope.User,
32
- choices: [SettingScope.User, SettingScope.Workspace],
33
37
  })
34
- .check((_argv) => true),
38
+ .check((argv) => {
39
+ if (argv.scope &&
40
+ !Object.values(SettingScope)
41
+ .map((s) => s.toLowerCase())
42
+ .includes(argv.scope.toLowerCase())) {
43
+ throw new Error(`Invalid scope: ${argv.scope}. Please use one of ${Object.values(SettingScope)
44
+ .map((s) => s.toLowerCase())
45
+ .join(', ')}.`);
46
+ }
47
+ return true;
48
+ }),
35
49
  handler: (argv) => {
36
50
  handleDisable({
37
51
  name: argv['name'],
@@ -1 +1 @@
1
- {"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../../src/commands/extensions/disable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAOxD,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC7C,IAAI,CAAC;QACH,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CACT,cAAc,IAAI,CAAC,IAAI,sCAAsC,IAAI,CAAC,KAAK,IAAI,CAC5E,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,OAAO,EAAE,0BAA0B;IACnC,QAAQ,EAAE,wBAAwB;IAClC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,uCAAuC;QACjD,IAAI,EAAE,QAAQ;KACf,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,QAAQ,EAAE,wCAAwC;QAClD,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,YAAY,CAAC,IAAI;QAC1B,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC;KACrD,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC;IAC3B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,aAAa,CAAC;YACZ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAW;YAC5B,KAAK,EAAE,IAAI,CAAC,OAAO,CAAiB;SACrC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../../src/commands/extensions/disable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAOxD,MAAM,UAAU,aAAa,CAAC,IAAiB;IAC7C,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;YAC9C,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,CAAC,GAAG,CACT,cAAc,IAAI,CAAC,IAAI,sCAAsC,IAAI,CAAC,KAAK,IAAI,CAC5E,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,OAAO,EAAE,0BAA0B;IACnC,QAAQ,EAAE,wBAAwB;IAClC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,uCAAuC;QACjD,IAAI,EAAE,QAAQ;KACf,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,QAAQ,EAAE,wCAAwC;QAClD,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,YAAY,CAAC,IAAI;KAC3B,CAAC;SACD,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;QACd,IACE,IAAI,CAAC,KAAK;YACV,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;iBACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;iBAC3B,QAAQ,CAAE,IAAI,CAAC,KAAgB,CAAC,WAAW,EAAE,CAAC,EACjD,CAAC;YACD,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,KAAK,uBAAuB,MAAM,CAAC,MAAM,CAC9D,YAAY,CACb;iBACE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;iBAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CACjB,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IACN,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,aAAa,CAAC;YACZ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAW;YAC5B,KAAK,EAAE,IAAI,CAAC,OAAO,CAAW;SAC/B,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -4,10 +4,9 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { type CommandModule } from 'yargs';
7
- import { SettingScope } from '../../config/settings.js';
8
7
  interface EnableArgs {
9
8
  name: string;
10
- scope?: SettingScope;
9
+ scope?: string;
11
10
  }
12
11
  export declare function handleEnable(args: EnableArgs): void;
13
12
  export declare const enableCommand: CommandModule;
@@ -9,8 +9,12 @@ import { enableExtension } from '../../config/extension.js';
9
9
  import { SettingScope } from '../../config/settings.js';
10
10
  export function handleEnable(args) {
11
11
  try {
12
- const scope = args.scope ? args.scope : SettingScope.User;
13
- enableExtension(args.name, scope);
12
+ if (args.scope?.toLowerCase() === 'workspace') {
13
+ enableExtension(args.name, SettingScope.Workspace);
14
+ }
15
+ else {
16
+ enableExtension(args.name, SettingScope.User);
17
+ }
14
18
  if (args.scope) {
15
19
  console.log(`Extension "${args.name}" successfully enabled for scope "${args.scope}".`);
16
20
  }
@@ -33,9 +37,18 @@ export const enableCommand = {
33
37
  .option('scope', {
34
38
  describe: 'The scope to enable the extenison in. If not set, will be enabled in all scopes.',
35
39
  type: 'string',
36
- choices: [SettingScope.User, SettingScope.Workspace],
37
40
  })
38
- .check((_argv) => true),
41
+ .check((argv) => {
42
+ if (argv.scope &&
43
+ !Object.values(SettingScope)
44
+ .map((s) => s.toLowerCase())
45
+ .includes(argv.scope.toLowerCase())) {
46
+ throw new Error(`Invalid scope: ${argv.scope}. Please use one of ${Object.values(SettingScope)
47
+ .map((s) => s.toLowerCase())
48
+ .join(', ')}.`);
49
+ }
50
+ return true;
51
+ }),
39
52
  handler: (argv) => {
40
53
  handleEnable({
41
54
  name: argv['name'],
@@ -1 +1 @@
1
- {"version":3,"file":"enable.js","sourceRoot":"","sources":["../../../../src/commands/extensions/enable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAOxD,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;QAC1D,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CACT,cAAc,IAAI,CAAC,IAAI,qCAAqC,IAAI,CAAC,KAAK,IAAI,CAC3E,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CACT,cAAc,IAAI,CAAC,IAAI,uCAAuC,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,gBAAgB,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,OAAO,EAAE,yBAAyB;IAClC,QAAQ,EAAE,uBAAuB;IACjC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,sCAAsC;QAChD,IAAI,EAAE,QAAQ;KACf,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,QAAQ,EACN,kFAAkF;QACpF,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC;KACrD,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC;IAC3B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,YAAY,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,MAAM,CAAW;YAC5B,KAAK,EAAE,IAAI,CAAC,OAAO,CAAiB;SACrC,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"enable.js","sourceRoot":"","sources":["../../../../src/commands/extensions/enable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAOxD,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;YAC9C,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CACT,cAAc,IAAI,CAAC,IAAI,qCAAqC,IAAI,CAAC,KAAK,IAAI,CAC3E,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CACT,cAAc,IAAI,CAAC,IAAI,uCAAuC,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,gBAAgB,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,OAAO,EAAE,yBAAyB;IAClC,QAAQ,EAAE,uBAAuB;IACjC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,KAAK;SACF,UAAU,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,sCAAsC;QAChD,IAAI,EAAE,QAAQ;KACf,CAAC;SACD,MAAM,CAAC,OAAO,EAAE;QACf,QAAQ,EACN,kFAAkF;QACpF,IAAI,EAAE,QAAQ;KACf,CAAC;SACD,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;QACd,IACE,IAAI,CAAC,KAAK;YACV,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;iBACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;iBAC3B,QAAQ,CAAE,IAAI,CAAC,KAAgB,CAAC,WAAW,EAAE,CAAC,EACjD,CAAC;YACD,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,CAAC,KAAK,uBAAuB,MAAM,CAAC,MAAM,CAC9D,YAAY,CACb;iBACE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;iBAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CACjB,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IACN,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,YAAY,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,MAAM,CAAW;YAC5B,KAAK,EAAE,IAAI,CAAC,OAAO,CAAW;SAC/B,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -9,6 +9,20 @@ export interface ExtensionEnablementConfig {
9
9
  export interface AllExtensionsEnablementConfig {
10
10
  [extensionName: string]: ExtensionEnablementConfig;
11
11
  }
12
+ export declare class Override {
13
+ baseRule: string;
14
+ isDisable: boolean;
15
+ includeSubdirs: boolean;
16
+ constructor(baseRule: string, isDisable: boolean, includeSubdirs: boolean);
17
+ static fromInput(inputRule: string, includeSubdirs: boolean): Override;
18
+ static fromFileRule(fileRule: string): Override;
19
+ conflictsWith(other: Override): boolean;
20
+ isEqualTo(other: Override): boolean;
21
+ asRegex(): RegExp;
22
+ isChildOf(parent: Override): boolean;
23
+ output(): string;
24
+ matchesPath(path: string): boolean;
25
+ }
12
26
  /**
13
27
  * Determines if an extension is enabled based on the configuration and current path.
14
28
  * The last matching rule in the overrides list wins.
@@ -5,6 +5,69 @@
5
5
  */
6
6
  import fs from 'node:fs';
7
7
  import path from 'node:path';
8
+ export class Override {
9
+ baseRule;
10
+ isDisable;
11
+ includeSubdirs;
12
+ constructor(baseRule, isDisable, includeSubdirs) {
13
+ this.baseRule = baseRule;
14
+ this.isDisable = isDisable;
15
+ this.includeSubdirs = includeSubdirs;
16
+ }
17
+ static fromInput(inputRule, includeSubdirs) {
18
+ const isDisable = inputRule.startsWith('!');
19
+ let baseRule = isDisable ? inputRule.substring(1) : inputRule;
20
+ baseRule = ensureLeadingAndTrailingSlash(baseRule);
21
+ return new Override(baseRule, isDisable, includeSubdirs);
22
+ }
23
+ static fromFileRule(fileRule) {
24
+ const isDisable = fileRule.startsWith('!');
25
+ let baseRule = isDisable ? fileRule.substring(1) : fileRule;
26
+ const includeSubdirs = baseRule.endsWith('*');
27
+ baseRule = includeSubdirs
28
+ ? baseRule.substring(0, baseRule.length - 1)
29
+ : baseRule;
30
+ return new Override(baseRule, isDisable, includeSubdirs);
31
+ }
32
+ conflictsWith(other) {
33
+ if (this.baseRule === other.baseRule) {
34
+ return (this.includeSubdirs !== other.includeSubdirs ||
35
+ this.isDisable !== other.isDisable);
36
+ }
37
+ return false;
38
+ }
39
+ isEqualTo(other) {
40
+ return (this.baseRule === other.baseRule &&
41
+ this.includeSubdirs === other.includeSubdirs &&
42
+ this.isDisable === other.isDisable);
43
+ }
44
+ asRegex() {
45
+ return globToRegex(`${this.baseRule}${this.includeSubdirs ? '*' : ''}`);
46
+ }
47
+ isChildOf(parent) {
48
+ if (!parent.includeSubdirs) {
49
+ return false;
50
+ }
51
+ return parent.asRegex().test(this.baseRule);
52
+ }
53
+ output() {
54
+ return `${this.isDisable ? '!' : ''}${this.baseRule}${this.includeSubdirs ? '*' : ''}`;
55
+ }
56
+ matchesPath(path) {
57
+ return this.asRegex().test(path);
58
+ }
59
+ }
60
+ const ensureLeadingAndTrailingSlash = function (dirPath) {
61
+ // Normalize separators to forward slashes for consistent matching across platforms.
62
+ let result = dirPath.replace(/\\/g, '/');
63
+ if (result.charAt(0) !== '/') {
64
+ result = '/' + result;
65
+ }
66
+ if (result.charAt(result.length - 1) !== '/') {
67
+ result = result + '/';
68
+ }
69
+ return result;
70
+ };
8
71
  /**
9
72
  * Converts a glob pattern to a RegExp object.
10
73
  * This is a simplified implementation that supports `*`.
@@ -15,7 +78,7 @@ import path from 'node:path';
15
78
  function globToRegex(glob) {
16
79
  const regexString = glob
17
80
  .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape special regex characters
18
- .replace(/\*/g, '.*'); // Convert * to .*
81
+ .replace(/(\/?)\*/g, '($1.*)?'); // Convert * to optional group
19
82
  return new RegExp(`^${regexString}$`);
20
83
  }
21
84
  /**
@@ -38,12 +101,11 @@ export class ExtensionEnablementManager {
38
101
  const extensionConfig = config[extensionName];
39
102
  // Extensions are enabled by default.
40
103
  let enabled = true;
41
- for (const rule of extensionConfig?.overrides ?? []) {
42
- const isDisableRule = rule.startsWith('!');
43
- const globPattern = isDisableRule ? rule.substring(1) : rule;
44
- const regex = globToRegex(globPattern);
45
- if (regex.test(currentPath)) {
46
- enabled = !isDisableRule;
104
+ const allOverrides = extensionConfig?.overrides ?? [];
105
+ for (const rule of allOverrides) {
106
+ const override = Override.fromFileRule(rule);
107
+ if (override.matchesPath(ensureLeadingAndTrailingSlash(currentPath))) {
108
+ enabled = !override.isDisable;
47
109
  }
48
110
  }
49
111
  return enabled;
@@ -72,35 +134,21 @@ export class ExtensionEnablementManager {
72
134
  if (!config[extensionName]) {
73
135
  config[extensionName] = { overrides: [] };
74
136
  }
75
- const pathWithGlob = `${scopePath}*`;
76
- const pathWithoutGlob = scopePath;
77
- const newPath = includeSubdirs ? pathWithGlob : pathWithoutGlob;
78
- const conflictingPath = includeSubdirs ? pathWithoutGlob : pathWithGlob;
79
- config[extensionName].overrides = config[extensionName].overrides.filter((rule) => rule !== conflictingPath &&
80
- rule !== `!${conflictingPath}` &&
81
- rule !== `!${newPath}`);
82
- if (!config[extensionName].overrides.includes(newPath)) {
83
- config[extensionName].overrides.push(newPath);
84
- }
137
+ const override = Override.fromInput(scopePath, includeSubdirs);
138
+ const overrides = config[extensionName].overrides.filter((rule) => {
139
+ const fileOverride = Override.fromFileRule(rule);
140
+ if (fileOverride.conflictsWith(override) ||
141
+ fileOverride.isEqualTo(override)) {
142
+ return false; // Remove conflicts and equivalent values.
143
+ }
144
+ return !fileOverride.isChildOf(override);
145
+ });
146
+ overrides.push(override.output());
147
+ config[extensionName].overrides = overrides;
85
148
  this.writeConfig(config);
86
149
  }
87
150
  disable(extensionName, includeSubdirs, scopePath) {
88
- const config = this.readConfig();
89
- if (!config[extensionName]) {
90
- config[extensionName] = { overrides: [] };
91
- }
92
- const pathWithGlob = `${scopePath}*`;
93
- const pathWithoutGlob = scopePath;
94
- const targetPath = includeSubdirs ? pathWithGlob : pathWithoutGlob;
95
- const newRule = `!${targetPath}`;
96
- const conflictingPath = includeSubdirs ? pathWithoutGlob : pathWithGlob;
97
- config[extensionName].overrides = config[extensionName].overrides.filter((rule) => rule !== conflictingPath &&
98
- rule !== `!${conflictingPath}` &&
99
- rule !== targetPath);
100
- if (!config[extensionName].overrides.includes(newRule)) {
101
- config[extensionName].overrides.push(newRule);
102
- }
103
- this.writeConfig(config);
151
+ this.enable(extensionName, includeSubdirs, `!${scopePath}`);
104
152
  }
105
153
  remove(extensionName) {
106
154
  const config = this.readConfig();
@@ -1 +1 @@
1
- {"version":3,"file":"extensionEnablement.js","sourceRoot":"","sources":["../../../../src/config/extensions/extensionEnablement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"extensionEnablement.js","sourceRoot":"","sources":["../../../../src/config/extensions/extensionEnablement.ts"],"names":[],"mappings":"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"}
@@ -3,11 +3,11 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import * as path from 'node:path';
6
7
  import fs from 'node:fs';
7
8
  import os from 'node:os';
8
- import path from 'node:path';
9
9
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
10
- import { ExtensionEnablementManager } from './extensionEnablement.js';
10
+ import { ExtensionEnablementManager, Override } from './extensionEnablement.js';
11
11
  // Helper to create a temporary directory for testing
12
12
  function createTestDir() {
13
13
  const dirPath = fs.mkdtempSync(path.join(os.tmpdir(), 'gemini-test-'));
@@ -40,12 +40,12 @@ describe('ExtensionEnablementManager', () => {
40
40
  expect(manager.isEnabled('ext-test', '/any/path')).toBe(true);
41
41
  });
42
42
  it('should enable a path based on an override rule', () => {
43
- manager.disable('ext-test', true, '*'); // Disable globally
43
+ manager.disable('ext-test', true, '/');
44
44
  manager.enable('ext-test', true, '/home/user/projects/');
45
45
  expect(manager.isEnabled('ext-test', '/home/user/projects/my-app')).toBe(true);
46
46
  });
47
47
  it('should disable a path based on a disable override rule', () => {
48
- manager.enable('ext-test', true, '*'); // Enable globally
48
+ manager.enable('ext-test', true, '/');
49
49
  manager.disable('ext-test', true, '/home/user/projects/');
50
50
  expect(manager.isEnabled('ext-test', '/home/user/projects/my-app')).toBe(false);
51
51
  });
@@ -59,58 +59,203 @@ describe('ExtensionEnablementManager', () => {
59
59
  manager.disable('ext-test', false, '/home/user/projects/my-app');
60
60
  expect(manager.isEnabled('ext-test', '/home/user/projects/my-app')).toBe(false);
61
61
  });
62
+ it('should handle', () => {
63
+ manager.enable('ext-test', true, '/home/user/projects');
64
+ manager.disable('ext-test', false, '/home/user/projects/my-app');
65
+ expect(manager.isEnabled('ext-test', '/home/user/projects/my-app')).toBe(false);
66
+ expect(manager.isEnabled('ext-test', '/home/user/projects/something-else')).toBe(true);
67
+ });
62
68
  });
63
69
  describe('includeSubdirs', () => {
64
70
  it('should add a glob when enabling with includeSubdirs', () => {
65
71
  manager.enable('ext-test', true, '/path/to/dir');
66
72
  const config = manager.readConfig();
67
- expect(config['ext-test'].overrides).toContain('/path/to/dir*');
73
+ expect(config['ext-test'].overrides).toContain('/path/to/dir/*');
68
74
  });
69
75
  it('should not add a glob when enabling without includeSubdirs', () => {
70
76
  manager.enable('ext-test', false, '/path/to/dir');
71
77
  const config = manager.readConfig();
72
- expect(config['ext-test'].overrides).toContain('/path/to/dir');
73
- expect(config['ext-test'].overrides).not.toContain('/path/to/dir*');
78
+ expect(config['ext-test'].overrides).toContain('/path/to/dir/');
79
+ expect(config['ext-test'].overrides).not.toContain('/path/to/dir/*');
74
80
  });
75
81
  it('should add a glob when disabling with includeSubdirs', () => {
76
82
  manager.disable('ext-test', true, '/path/to/dir');
77
83
  const config = manager.readConfig();
78
- expect(config['ext-test'].overrides).toContain('!/path/to/dir*');
84
+ expect(config['ext-test'].overrides).toContain('!/path/to/dir/*');
79
85
  });
80
86
  it('should remove conflicting glob rule when enabling without subdirs', () => {
81
87
  manager.enable('ext-test', true, '/path/to/dir'); // Adds /path/to/dir*
82
88
  manager.enable('ext-test', false, '/path/to/dir'); // Should remove the glob
83
89
  const config = manager.readConfig();
84
- expect(config['ext-test'].overrides).toContain('/path/to/dir');
85
- expect(config['ext-test'].overrides).not.toContain('/path/to/dir*');
90
+ expect(config['ext-test'].overrides).toContain('/path/to/dir/');
91
+ expect(config['ext-test'].overrides).not.toContain('/path/to/dir/*');
86
92
  });
87
93
  it('should remove conflicting non-glob rule when enabling with subdirs', () => {
88
94
  manager.enable('ext-test', false, '/path/to/dir'); // Adds /path/to/dir
89
95
  manager.enable('ext-test', true, '/path/to/dir'); // Should remove the non-glob
90
96
  const config = manager.readConfig();
91
- expect(config['ext-test'].overrides).toContain('/path/to/dir*');
92
- expect(config['ext-test'].overrides).not.toContain('/path/to/dir');
97
+ expect(config['ext-test'].overrides).toContain('/path/to/dir/*');
98
+ expect(config['ext-test'].overrides).not.toContain('/path/to/dir/');
93
99
  });
94
100
  it('should remove conflicting rules when disabling', () => {
95
101
  manager.enable('ext-test', true, '/path/to/dir'); // enabled with glob
96
102
  manager.disable('ext-test', false, '/path/to/dir'); // disabled without
97
103
  const config = manager.readConfig();
98
- expect(config['ext-test'].overrides).toContain('!/path/to/dir');
99
- expect(config['ext-test'].overrides).not.toContain('/path/to/dir*');
104
+ expect(config['ext-test'].overrides).toContain('!/path/to/dir/');
105
+ expect(config['ext-test'].overrides).not.toContain('/path/to/dir/*');
100
106
  });
101
107
  it('should correctly evaluate isEnabled with subdirs', () => {
102
- manager.disable('ext-test', true, '*');
108
+ manager.disable('ext-test', true, '/');
103
109
  manager.enable('ext-test', true, '/path/to/dir');
104
- expect(manager.isEnabled('ext-test', '/path/to/dir')).toBe(true);
105
- expect(manager.isEnabled('ext-test', '/path/to/dir/sub')).toBe(true);
106
- expect(manager.isEnabled('ext-test', '/path/to/another')).toBe(false);
110
+ expect(manager.isEnabled('ext-test', '/path/to/dir/')).toBe(true);
111
+ expect(manager.isEnabled('ext-test', '/path/to/dir/sub/')).toBe(true);
112
+ expect(manager.isEnabled('ext-test', '/path/to/another/')).toBe(false);
107
113
  });
108
114
  it('should correctly evaluate isEnabled without subdirs', () => {
109
- manager.disable('ext-test', true, '*');
115
+ manager.disable('ext-test', true, '/*');
110
116
  manager.enable('ext-test', false, '/path/to/dir');
111
117
  expect(manager.isEnabled('ext-test', '/path/to/dir')).toBe(true);
112
118
  expect(manager.isEnabled('ext-test', '/path/to/dir/sub')).toBe(false);
113
119
  });
114
120
  });
121
+ describe('pruning child rules', () => {
122
+ it('should remove child rules when enabling a parent with subdirs', () => {
123
+ // Pre-existing rules for children
124
+ manager.enable('ext-test', false, '/path/to/dir/subdir1');
125
+ manager.disable('ext-test', true, '/path/to/dir/subdir2');
126
+ manager.enable('ext-test', false, '/path/to/another/dir');
127
+ // Enable the parent directory
128
+ manager.enable('ext-test', true, '/path/to/dir');
129
+ const config = manager.readConfig();
130
+ const overrides = config['ext-test'].overrides;
131
+ // The new parent rule should be present
132
+ expect(overrides).toContain(`/path/to/dir/*`);
133
+ // Child rules should be removed
134
+ expect(overrides).not.toContain('/path/to/dir/subdir1/');
135
+ expect(overrides).not.toContain(`!/path/to/dir/subdir2/*`);
136
+ // Unrelated rules should remain
137
+ expect(overrides).toContain('/path/to/another/dir/');
138
+ });
139
+ it('should remove child rules when disabling a parent with subdirs', () => {
140
+ // Pre-existing rules for children
141
+ manager.enable('ext-test', false, '/path/to/dir/subdir1');
142
+ manager.disable('ext-test', true, '/path/to/dir/subdir2');
143
+ manager.enable('ext-test', false, '/path/to/another/dir');
144
+ // Disable the parent directory
145
+ manager.disable('ext-test', true, '/path/to/dir');
146
+ const config = manager.readConfig();
147
+ const overrides = config['ext-test'].overrides;
148
+ // The new parent rule should be present
149
+ expect(overrides).toContain(`!/path/to/dir/*`);
150
+ // Child rules should be removed
151
+ expect(overrides).not.toContain('/path/to/dir/subdir1/');
152
+ expect(overrides).not.toContain(`!/path/to/dir/subdir2/*`);
153
+ // Unrelated rules should remain
154
+ expect(overrides).toContain('/path/to/another/dir/');
155
+ });
156
+ it('should not remove child rules if includeSubdirs is false', () => {
157
+ manager.enable('ext-test', false, '/path/to/dir/subdir1');
158
+ manager.enable('ext-test', false, '/path/to/dir'); // Not including subdirs
159
+ const config = manager.readConfig();
160
+ const overrides = config['ext-test'].overrides;
161
+ expect(overrides).toContain('/path/to/dir/subdir1/');
162
+ expect(overrides).toContain('/path/to/dir/');
163
+ });
164
+ });
165
+ it('should enable a path based on an enable override', () => {
166
+ manager.disable('ext-test', true, '/Users/chrstn');
167
+ manager.enable('ext-test', true, '/Users/chrstn/gemini-cli');
168
+ expect(manager.isEnabled('ext-test', '/Users/chrstn/gemini-cli')).toBe(true);
169
+ });
170
+ it('should ignore subdirs', () => {
171
+ manager.disable('ext-test', false, '/Users/chrstn');
172
+ expect(manager.isEnabled('ext-test', '/Users/chrstn/gemini-cli')).toBe(true);
173
+ });
174
+ });
175
+ describe('Override', () => {
176
+ it('should create an override from input', () => {
177
+ const override = Override.fromInput('/path/to/dir', true);
178
+ expect(override.baseRule).toBe(`/path/to/dir/`);
179
+ expect(override.isDisable).toBe(false);
180
+ expect(override.includeSubdirs).toBe(true);
181
+ });
182
+ it('should create a disable override from input', () => {
183
+ const override = Override.fromInput('!/path/to/dir', false);
184
+ expect(override.baseRule).toBe(`/path/to/dir/`);
185
+ expect(override.isDisable).toBe(true);
186
+ expect(override.includeSubdirs).toBe(false);
187
+ });
188
+ it('should create an override from a file rule', () => {
189
+ const override = Override.fromFileRule('/path/to/dir');
190
+ expect(override.baseRule).toBe('/path/to/dir');
191
+ expect(override.isDisable).toBe(false);
192
+ expect(override.includeSubdirs).toBe(false);
193
+ });
194
+ it('should create a disable override from a file rule', () => {
195
+ const override = Override.fromFileRule('!/path/to/dir/');
196
+ expect(override.isDisable).toBe(true);
197
+ expect(override.baseRule).toBe('/path/to/dir/');
198
+ expect(override.includeSubdirs).toBe(false);
199
+ });
200
+ it('should create an override with subdirs from a file rule', () => {
201
+ const override = Override.fromFileRule('/path/to/dir/*');
202
+ expect(override.baseRule).toBe('/path/to/dir/');
203
+ expect(override.isDisable).toBe(false);
204
+ expect(override.includeSubdirs).toBe(true);
205
+ });
206
+ it('should correctly identify conflicting overrides', () => {
207
+ const override1 = Override.fromInput('/path/to/dir', true);
208
+ const override2 = Override.fromInput('/path/to/dir', false);
209
+ expect(override1.conflictsWith(override2)).toBe(true);
210
+ });
211
+ it('should correctly identify non-conflicting overrides', () => {
212
+ const override1 = Override.fromInput('/path/to/dir', true);
213
+ const override2 = Override.fromInput('/path/to/another/dir', true);
214
+ expect(override1.conflictsWith(override2)).toBe(false);
215
+ });
216
+ it('should correctly identify equal overrides', () => {
217
+ const override1 = Override.fromInput('/path/to/dir', true);
218
+ const override2 = Override.fromInput('/path/to/dir', true);
219
+ expect(override1.isEqualTo(override2)).toBe(true);
220
+ });
221
+ it('should correctly identify unequal overrides', () => {
222
+ const override1 = Override.fromInput('/path/to/dir', true);
223
+ const override2 = Override.fromInput('!/path/to/dir', true);
224
+ expect(override1.isEqualTo(override2)).toBe(false);
225
+ });
226
+ it('should generate the correct regex', () => {
227
+ const override = Override.fromInput('/path/to/dir', true);
228
+ const regex = override.asRegex();
229
+ expect(regex.test('/path/to/dir/')).toBe(true);
230
+ expect(regex.test('/path/to/dir/subdir')).toBe(true);
231
+ expect(regex.test('/path/to/another/dir')).toBe(false);
232
+ });
233
+ it('should correctly identify child overrides', () => {
234
+ const parent = Override.fromInput('/path/to/dir', true);
235
+ const child = Override.fromInput('/path/to/dir/subdir', false);
236
+ expect(child.isChildOf(parent)).toBe(true);
237
+ });
238
+ it('should correctly identify child overrides with glob', () => {
239
+ const parent = Override.fromInput('/path/to/dir/*', true);
240
+ const child = Override.fromInput('/path/to/dir/subdir', false);
241
+ expect(child.isChildOf(parent)).toBe(true);
242
+ });
243
+ it('should correctly identify non-child overrides', () => {
244
+ const parent = Override.fromInput('/path/to/dir', true);
245
+ const other = Override.fromInput('/path/to/another/dir', false);
246
+ expect(other.isChildOf(parent)).toBe(false);
247
+ });
248
+ it('should generate the correct output string', () => {
249
+ const override = Override.fromInput('/path/to/dir', true);
250
+ expect(override.output()).toBe(`/path/to/dir/*`);
251
+ });
252
+ it('should generate the correct output string for a disable override', () => {
253
+ const override = Override.fromInput('!/path/to/dir', false);
254
+ expect(override.output()).toBe(`!/path/to/dir/`);
255
+ });
256
+ it('should disable a path based on a disable override rule', () => {
257
+ const override = Override.fromInput('!/path/to/dir', false);
258
+ expect(override.output()).toBe(`!/path/to/dir/`);
259
+ });
115
260
  });
116
261
  //# sourceMappingURL=extensionEnablement.test.js.map