diff --git a/docs/cli/configuration.md b/docs/cli/configuration.md index eb4c6316..7b404c69 100644 --- a/docs/cli/configuration.md +++ b/docs/cli/configuration.md @@ -36,6 +36,12 @@ When you create a `.gemini/settings.json` file for project-specific settings, or ### Available Settings in `settings.json`: +- **`contextFileName`** (string, optional): + + - **Description:** Specifies the filename for context files (e.g., `GEMINI.md`, `AGENTS.md`). + - **Default:** `GEMINI.md` + - **Example:** `"contextFileName": "AGENTS.md"` + - **`coreTools`** (array of strings, optional): - **Description:** Allows you to specify a list of core tool names that should be made available to the model. This can be used to restrict or customize the set of built-in tools. - **Example:** `"coreTools": ["ReadFileTool", "GlobTool", "SearchText"]`. @@ -164,15 +170,15 @@ Arguments passed directly when running the CLI can override other configurations - **`--help`** (or **`-h`**): - Displays help information about command-line arguments. -## 4. `GEMINI.md` Files (Hierarchical Instructional Context) +## 4. Context Files (Hierarchical Instructional Context) -While not strictly configuration for the CLI's _behavior_, `GEMINI.md` files are crucial for configuring the _instructional context_ (also referred to as "memory") provided to the Gemini model. This powerful feature allows you to give project-specific instructions, coding style guides, or any relevant background information to the AI, making its responses more tailored and accurate to your needs. The CLI includes UI elements, such as an indicator in the footer showing the number of loaded `GEMINI.md` files, to keep you informed about the active context. +While not strictly configuration for the CLI's _behavior_, context files (defaulting to `GEMINI.md` but configurable via the `contextFileName` setting) are crucial for configuring the _instructional context_ (also referred to as "memory") provided to the Gemini model. This powerful feature allows you to give project-specific instructions, coding style guides, or any relevant background information to the AI, making its responses more tailored and accurate to your needs. The CLI includes UI elements, such as an indicator in the footer showing the number of loaded context files, to keep you informed about the active context. - **Purpose:** These Markdown files contain instructions, guidelines, or context that you want the Gemini model to be aware of during your interactions. The system is designed to manage this instructional context hierarchically. -### Example `GEMINI.md` Content +### Example Context File Content (e.g., `GEMINI.md`) -Here's a conceptual example of what a `GEMINI.md` file at the root of a TypeScript project might contain: +Here's a conceptual example of what a context file at the root of a TypeScript project might contain: ```markdown # Project: My Awesome TypeScript Library @@ -203,25 +209,25 @@ Here's a conceptual example of what a `GEMINI.md` file at the root of a TypeScri - If a new dependency is required, please state the reason. ``` -This example demonstrates how you can provide general project context, specific coding conventions, and even notes about particular files or components. The more relevant and precise your `GEMINI.md` files are, the better the AI can assist you. Project-specific `GEMINI.md` files are highly encouraged to establish conventions and context. +This example demonstrates how you can provide general project context, specific coding conventions, and even notes about particular files or components. The more relevant and precise your context files are, the better the AI can assist you. Project-specific context files are highly encouraged to establish conventions and context. -- **Hierarchical Loading and Precedence:** The CLI implements a sophisticated hierarchical memory system by loading `GEMINI.md` files from several locations. Content from files lower in this list (more specific) typically overrides or supplements content from files higher up (more general). The exact concatenation order and final context can be inspected using the `/showmemory` command. The typical loading order is: - 1. **Global `GEMINI.md`:** - - Location: `~/.gemini/GEMINI.md` (in your user home directory). +- **Hierarchical Loading and Precedence:** The CLI implements a sophisticated hierarchical memory system by loading context files (e.g., `GEMINI.md`) from several locations. Content from files lower in this list (more specific) typically overrides or supplements content from files higher up (more general). The exact concatenation order and final context can be inspected using the `/showmemory` command. The typical loading order is: + 1. **Global Context File:** + - Location: `~/.gemini/` (e.g., `~/.gemini/GEMINI.md` in your user home directory). - Scope: Provides default instructions for all your projects. - 2. **Project Root & Ancestors `GEMINI.md`:** - - Location: The CLI searches for `GEMINI.md` in the current working directory and then in each parent directory up to either the project root (identified by a `.git` folder) or your home directory. + 2. **Project Root & Ancestors Context Files:** + - Location: The CLI searches for the configured context file in the current working directory and then in each parent directory up to either the project root (identified by a `.git` folder) or your home directory. - Scope: Provides context relevant to the entire project or a significant portion of it. - 3. **Sub-directory `GEMINI.md` (Contextual/Local):** - - Location: The CLI also scans for `GEMINI.md` files in subdirectories _below_ the current working directory (respecting common ignore patterns like `node_modules`, `.git`, etc.). + 3. **Sub-directory Context Files (Contextual/Local):** + - Location: The CLI also scans for the configured context file in subdirectories _below_ the current working directory (respecting common ignore patterns like `node_modules`, `.git`, etc.). - Scope: Allows for highly specific instructions relevant to a particular component, module, or sub-section of your project. -- **Concatenation & UI Indication:** The contents of all found `GEMINI.md` files are concatenated (with separators indicating their origin and path) and provided as part of the system prompt to the Gemini model. The CLI footer displays the count of loaded `GEMINI.md` files, giving you a quick visual cue about the active instructional context. +- **Concatenation & UI Indication:** The contents of all found context files are concatenated (with separators indicating their origin and path) and provided as part of the system prompt to the Gemini model. The CLI footer displays the count of loaded context files, giving you a quick visual cue about the active instructional context. - **Commands for Memory Management:** - - Use `/memory refresh` to force a re-scan and reload of all `GEMINI.md` files from all configured locations. This updates the AI's instructional context. + - Use `/memory refresh` to force a re-scan and reload of all context files from all configured locations. This updates the AI's instructional context. - Use `/memory show` to display the combined instructional context currently loaded, allowing you to verify the hierarchy and content being used by the AI. - See the [Commands documentation](./commands.md#memory) for full details on the `/memory` command and its sub-commands (`show` and `refresh`). -By understanding and utilizing these configuration layers and the hierarchical nature of `GEMINI.md` files, you can effectively manage the AI's memory and tailor the Gemini CLI's responses to your specific needs and projects. +By understanding and utilizing these configuration layers and the hierarchical nature of context files, you can effectively manage the AI's memory and tailor the Gemini CLI's responses to your specific needs and projects. ## Theming diff --git a/package-lock.json b/package-lock.json index f9888f13..3df2cc33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,13 +86,6 @@ "lru-cache": "^10.4.3" } }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -127,13 +120,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", - "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.4.tgz", + "integrity": "sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -143,9 +136,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", - "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz", + "integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==", "dev": true, "license": "MIT", "engines": { @@ -153,9 +146,9 @@ } }, "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz", + "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==", "dev": true, "license": "MIT", "dependencies": { @@ -197,9 +190,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.3.tgz", - "integrity": "sha512-XBG3talrhid44BY1x3MHzUx/aTG8+x/Zi57M4aTKK9RFB4aLlF3TTSzfzn8nWVHWL3FgAXAxmupmDd6VWww+pw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", "dev": true, "funding": [ { @@ -216,14 +209,14 @@ "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/css-color-parser": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.9.tgz", - "integrity": "sha512-wILs5Zk7BU86UArYBJTPy/FMPPKVKHMj1ycCEyf3VUptol0JNRLFU/BZsJ4aiIHJEbSLiizzRrw8Pc1uAEDrXw==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", + "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", "dev": true, "funding": [ { @@ -238,20 +231,20 @@ "license": "MIT", "dependencies": { "@csstools/color-helpers": "^5.0.2", - "@csstools/css-calc": "^2.1.3" + "@csstools/css-calc": "^2.1.4" }, "engines": { "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", - "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", "dev": true, "funding": [ { @@ -268,13 +261,13 @@ "node": ">=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.3" + "@csstools/css-tokenizer": "^3.0.4" } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", - "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", "dev": true, "funding": [ { @@ -292,9 +285,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], @@ -309,9 +302,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], @@ -326,9 +319,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], @@ -343,9 +336,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], @@ -360,9 +353,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], @@ -377,9 +370,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], @@ -394,9 +387,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], @@ -411,9 +404,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], @@ -428,9 +421,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], @@ -445,9 +438,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], @@ -462,9 +455,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], @@ -479,9 +472,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], @@ -496,9 +489,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], @@ -513,9 +506,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], @@ -530,9 +523,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], @@ -547,9 +540,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], @@ -564,9 +557,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], @@ -581,9 +574,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", "cpu": [ "arm64" ], @@ -598,9 +591,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], @@ -615,9 +608,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", "cpu": [ "arm64" ], @@ -632,9 +625,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], @@ -649,9 +642,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", "cpu": [ "x64" ], @@ -666,9 +659,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], @@ -683,9 +676,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], @@ -700,9 +693,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], @@ -834,9 +827,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.27.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", - "integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "dev": true, "license": "MIT", "engines": { @@ -879,9 +872,9 @@ "link": true }, "node_modules/@google/genai": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.0.1.tgz", - "integrity": "sha512-qf8sq9vpuKUeBKukAn43z2eC1I/Jw63b9wo6O+1x3EIroF3oDouJOtW1AzwvfO+9gzCPfLjuCUONhMKiBC8vkQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.3.0.tgz", + "integrity": "sha512-rrMzAELX4P902FUpuWy/W3NcQ7L3q/qtCzfCmGVqIce8yWpptTF9hkKsw744tvZpwqhuzD0URibcJA95wd8QFA==", "license": "Apache-2.0", "dependencies": { "google-auth-library": "^9.14.2", @@ -1001,91 +994,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1207,9 +1115,9 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.0.tgz", - "integrity": "sha512-m//7RlINx1F3sz3KqwY1WWzVgTcYX52HYk4bJ1hkBXV3zccAEth+jRvG8DBRrdaQuRsPAJOx2MH3zaHNCKL7Zg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz", + "integrity": "sha512-KG1CZhZfWg+u8pxeM/mByJDScJSrjjxLc8fwQqbsS8xCjBmQfMNEBTotYdNanKekepnfRI85GtgQlctLFpcYPw==", "license": "MIT", "dependencies": { "ajv": "^6.12.6", @@ -1275,9 +1183,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz", - "integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", "cpu": [ "arm" ], @@ -1290,9 +1198,9 @@ "peer": true }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz", - "integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", "cpu": [ "arm64" ], @@ -1305,9 +1213,9 @@ "peer": true }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz", - "integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", "cpu": [ "arm64" ], @@ -1320,9 +1228,9 @@ "peer": true }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz", - "integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", "cpu": [ "x64" ], @@ -1335,9 +1243,9 @@ "peer": true }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz", - "integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", "cpu": [ "arm64" ], @@ -1350,9 +1258,9 @@ "peer": true }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz", - "integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", "cpu": [ "x64" ], @@ -1365,9 +1273,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz", - "integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", "cpu": [ "arm" ], @@ -1380,9 +1288,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz", - "integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", "cpu": [ "arm" ], @@ -1395,9 +1303,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz", - "integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", "cpu": [ "arm64" ], @@ -1410,9 +1318,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz", - "integrity": "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", "cpu": [ "arm64" ], @@ -1425,9 +1333,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz", - "integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", "cpu": [ "loong64" ], @@ -1440,9 +1348,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz", - "integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", "cpu": [ "ppc64" ], @@ -1455,9 +1363,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz", - "integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", "cpu": [ "riscv64" ], @@ -1470,9 +1378,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz", - "integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", "cpu": [ "riscv64" ], @@ -1485,9 +1393,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz", - "integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", "cpu": [ "s390x" ], @@ -1500,9 +1408,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", - "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", + "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", "cpu": [ "x64" ], @@ -1515,9 +1423,9 @@ "peer": true }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz", - "integrity": "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", + "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", "cpu": [ "x64" ], @@ -1530,9 +1438,9 @@ "peer": true }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz", - "integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", "cpu": [ "arm64" ], @@ -1545,9 +1453,9 @@ "peer": true }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz", - "integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", "cpu": [ "ia32" ], @@ -1560,9 +1468,9 @@ "peer": true }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz", - "integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", "cpu": [ "x64" ], @@ -1691,9 +1599,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.17.50", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.50.tgz", - "integrity": "sha512-Mxiq0ULv/zo1OzOhwPqOA13I81CV/W3nvd3ChtQZRT5Cwz3cr0FKo/wMSsbTqL3EXpaBAEQhva2B8ByRkOIh9A==", + "version": "20.17.57", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.57.tgz", + "integrity": "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1714,9 +1622,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.22", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.22.tgz", - "integrity": "sha512-vUhG0YmQZ7kL/tmKLrD3g5zXbXXreZXB3pmROW8bg3CnLnpjkRVwUlLne7Ufa2r9yJ8+/6B73RzhAek5TBKh2Q==", + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1771,17 +1679,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", - "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.0.tgz", + "integrity": "sha512-CACyQuqSHt7ma3Ns601xykeBK/rDeZa3w6IS6UtMQbixO5DWy+8TilKkviGDH6jtWCo8FGRKEK5cLLkPvEammQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.32.1", - "@typescript-eslint/type-utils": "8.32.1", - "@typescript-eslint/utils": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/type-utils": "8.33.0", + "@typescript-eslint/utils": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -1795,15 +1703,15 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.33.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", - "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -1811,16 +1719,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", - "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz", + "integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.32.1", - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/typescript-estree": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4" }, "engines": { @@ -1835,15 +1743,16 @@ "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz", - "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.0.tgz", + "integrity": "sha512-d1hz0u9l6N+u/gcrk6s6gYdl7/+pp8yHheRTqP6X5hVDKALEaTn8WfGiit7G511yueBEL3OpOEpD+3/MBdoN+A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1" + "@typescript-eslint/tsconfig-utils": "^8.33.0", + "@typescript-eslint/types": "^8.33.0", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1853,15 +1762,50 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz", - "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.0.tgz", + "integrity": "sha512-LMi/oqrzpqxyO72ltP+dBSP6V0xiUb4saY7WLtxSfiNEBI8m321LLVFU9/QDJxjDQG9/tjSqKz/E3380TEqSTw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.32.1", - "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.0.tgz", + "integrity": "sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.0.tgz", + "integrity": "sha512-lScnHNCBqL1QayuSrWeqAL5GmqNdVUQAAMTaCwdYEdWfIrSrOGzyLGRCHXcCixa5NK6i5l0AfSO2oBSjCjf4XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/utils": "8.33.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -1878,9 +1822,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz", - "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==", "dev": true, "license": "MIT", "engines": { @@ -1892,14 +1836,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz", - "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.0.tgz", + "integrity": "sha512-vegY4FQoB6jL97Tu/lWRsAiUUp8qJTqzAmENH2k59SJhw0Th1oszb9Idq/FyyONLuNqT1OADJPXfyUNOR8SzAQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1", + "@typescript-eslint/project-service": "8.33.0", + "@typescript-eslint/tsconfig-utils": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1958,16 +1904,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz", - "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.0.tgz", + "integrity": "sha512-lPFuQaLA9aSNa7D5u2EpRiqdAUhzShwGg/nhpBlc4GR6kcTABttCuyjFs8BcEZ8VWrjCBof/bePhP3Q3fS+Yrw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.32.1", - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/typescript-estree": "8.32.1" + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1982,13 +1928,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz", - "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.0.tgz", + "integrity": "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2179,15 +2125,6 @@ "node": ">= 0.6" } }, - "node_modules/accepts/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", @@ -2211,6 +2148,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2764,18 +2710,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/cli-truncate/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -2827,21 +2761,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2856,6 +2775,47 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3333,9 +3293,10 @@ "license": "MIT" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, "license": "MIT" }, "node_modules/encodeurl": { @@ -3347,17 +3308,6 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, "node_modules/entities": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", @@ -3384,9 +3334,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.10", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz", - "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3417,7 +3367,9 @@ "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", + "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", @@ -3432,6 +3384,7 @@ "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", @@ -3593,9 +3546,9 @@ ] }, "node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3606,31 +3559,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" } }, "node_modules/escalade": { @@ -3662,9 +3615,9 @@ } }, "node_modules/eslint": { - "version": "9.27.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", - "integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3674,7 +3627,7 @@ "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.14.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.27.0", + "@eslint/js": "9.28.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -4330,19 +4283,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4433,28 +4373,6 @@ "node": ">=14" } }, - "node_modules/gaxios/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/gaxios/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/gcp-metadata": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", @@ -4545,6 +4463,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4558,10 +4497,36 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.1.0.tgz", - "integrity": "sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "dev": true, "license": "MIT", "engines": { @@ -4771,12 +4736,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -4813,6 +4772,33 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/hyperdyperid": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", @@ -4971,33 +4957,6 @@ "ink": ">=4" } }, - "node_modules/ink-gradient/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ink-gradient/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/ink-select-input": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/ink-select-input/-/ink-select-input-6.2.0.tgz", @@ -5078,18 +5037,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ink/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/ink/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -5120,6 +5067,12 @@ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "license": "MIT" }, + "node_modules/ink/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/ink/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -5137,19 +5090,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ink/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/ink/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/ink/node_modules/ws": { @@ -5478,6 +5433,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5861,44 +5829,6 @@ } } }, - "node_modules/jsdom/node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/jsdom/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/jsdom/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/jsdom/node_modules/ws": { "version": "8.18.2", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", @@ -6100,6 +6030,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -6286,6 +6222,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6318,6 +6264,15 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -6764,23 +6719,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -6845,9 +6783,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", + "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", "dev": true, "funding": [ { @@ -6865,7 +6803,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7232,6 +7170,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -7243,9 +7187,9 @@ } }, "node_modules/rollup": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz", - "integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", + "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", "dev": true, "license": "MIT", "dependencies": { @@ -7259,26 +7203,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.41.0", - "@rollup/rollup-android-arm64": "4.41.0", - "@rollup/rollup-darwin-arm64": "4.41.0", - "@rollup/rollup-darwin-x64": "4.41.0", - "@rollup/rollup-freebsd-arm64": "4.41.0", - "@rollup/rollup-freebsd-x64": "4.41.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", - "@rollup/rollup-linux-arm-musleabihf": "4.41.0", - "@rollup/rollup-linux-arm64-gnu": "4.41.0", - "@rollup/rollup-linux-arm64-musl": "4.41.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", - "@rollup/rollup-linux-riscv64-gnu": "4.41.0", - "@rollup/rollup-linux-riscv64-musl": "4.41.0", - "@rollup/rollup-linux-s390x-gnu": "4.41.0", - "@rollup/rollup-linux-x64-gnu": "4.41.0", - "@rollup/rollup-linux-x64-musl": "4.41.0", - "@rollup/rollup-win32-arm64-msvc": "4.41.0", - "@rollup/rollup-win32-ia32-msvc": "4.41.0", - "@rollup/rollup-win32-x64-msvc": "4.41.0", + "@rollup/rollup-android-arm-eabi": "4.41.1", + "@rollup/rollup-android-arm64": "4.41.1", + "@rollup/rollup-darwin-arm64": "4.41.1", + "@rollup/rollup-darwin-x64": "4.41.1", + "@rollup/rollup-freebsd-arm64": "4.41.1", + "@rollup/rollup-freebsd-x64": "4.41.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", + "@rollup/rollup-linux-arm-musleabihf": "4.41.1", + "@rollup/rollup-linux-arm64-gnu": "4.41.1", + "@rollup/rollup-linux-arm64-musl": "4.41.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-musl": "4.41.1", + "@rollup/rollup-linux-s390x-gnu": "4.41.1", + "@rollup/rollup-linux-x64-gnu": "4.41.1", + "@rollup/rollup-linux-x64-musl": "4.41.1", + "@rollup/rollup-win32-arm64-msvc": "4.41.1", + "@rollup/rollup-win32-ia32-msvc": "4.41.1", + "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" } }, @@ -7679,10 +7623,17 @@ "license": "ISC" }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/slice-ansi": { "version": "7.1.0", @@ -7828,17 +7779,21 @@ } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width-cjs": { @@ -7857,6 +7812,13 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -7867,11 +7829,15 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { "node": ">=8" } @@ -7975,15 +7941,18 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi-cjs": { @@ -8000,6 +7969,18 @@ "node": ">=8" } }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8079,27 +8060,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/test-exclude/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/test-exclude/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -8116,16 +8076,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/test-exclude/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/thingies": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", @@ -8160,9 +8110,9 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8177,9 +8127,9 @@ } }, "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", "dev": true, "license": "MIT", "peerDependencies": { @@ -8215,9 +8165,9 @@ } }, "node_modules/tinypool": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", - "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz", + "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==", "dev": true, "license": "MIT", "engines": { @@ -8526,15 +8476,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.32.1.tgz", - "integrity": "sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.0.tgz", + "integrity": "sha512-5YmNhF24ylCsvdNW2oJwMzTbaeO4bg90KeGtMjUw0AGtHksgEPLRTUil+coHwCfiu4QjVJFnjp94DmU6zV7DhQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.32.1", - "@typescript-eslint/parser": "8.32.1", - "@typescript-eslint/utils": "8.32.1" + "@typescript-eslint/eslint-plugin": "8.33.0", + "@typescript-eslint/parser": "8.33.0", + "@typescript-eslint/utils": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8735,9 +8685,9 @@ } }, "node_modules/vite/node_modules/fdir": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9029,18 +8979,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/widest-line/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/widest-line/node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -9064,21 +9002,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/widest-line/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -9090,17 +9013,18 @@ } }, "node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=18" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9125,22 +9049,56 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9149,44 +9107,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -9268,6 +9188,47 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -9288,9 +9249,9 @@ "license": "MIT" }, "node_modules/zod": { - "version": "3.25.27", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.27.tgz", - "integrity": "sha512-xkYsE+ztNLzBeoAG8Ipd2ICr86gyMpovQlB+Vid1LT7V16/Dj0z+Up1u1qxNX58cmJ/AtG2mvGw/7+jK48xEYw==", + "version": "3.25.42", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.42.tgz", + "integrity": "sha512-PcALTLskaucbeHc41tU/xfjfhcz8z0GdhhDcSgrCTmSazUuqnYqiXO63M0QUBVwpBlsLsNVn5qHSC5Dw3KZvaQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -9349,18 +9310,6 @@ "node": ">=18" } }, - "packages/cli/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "packages/cli/node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -9384,21 +9333,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/cli/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "packages/core": { "name": "@gemini-code/core", "version": "0.1.0", @@ -9419,28 +9353,6 @@ "engines": { "node": ">=18" } - }, - "packages/server": { - "name": "@gemini-code/server", - "version": "0.1.0", - "extraneous": true, - "dependencies": { - "@google/genai": "^1.0.1", - "@modelcontextprotocol/sdk": "^1.11.0", - "diff": "^7.0.0", - "dotenv": "^16.4.7", - "fast-glob": "^3.3.3", - "shell-quote": "^1.8.2" - }, - "devDependencies": { - "@types/diff": "^7.0.2", - "@types/dotenv": "^6.1.1", - "typescript": "^5.3.3", - "vitest": "^3.1.1" - }, - "engines": { - "node": ">=18" - } } } } diff --git a/package.json b/package.json index 373f0134..483cd711 100644 --- a/package.json +++ b/package.json @@ -62,5 +62,6 @@ "typescript-eslint": "^8.30.1", "yargs": "^17.7.2", "json": "^11.0.0" - } + }, + "dependencies": {} } diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 04347427..44057fad 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -13,6 +13,8 @@ import { createServerConfig, loadServerHierarchicalMemory, ConfigParameters, + setGeminiMdFilename as setServerGeminiMdFilename, + getCurrentGeminiMdFilename, } from '@gemini-code/core'; import { Settings } from './settings.js'; import { readPackageUp } from 'read-package-up'; @@ -132,6 +134,17 @@ export async function loadCliConfig(settings: Settings): Promise { const argv = await parseArguments(); const debugMode = argv.debug || false; + // Set the context filename in the server's memoryTool module BEFORE loading memory + // TODO(b/343434939): This is a bit of a hack. The contextFileName should ideally be passed + // directly to the Config constructor in core, and have core handle setGeminiMdFilename. + // However, loadHierarchicalGeminiMemory is called *before* createServerConfig. + if (settings.contextFileName) { + setServerGeminiMdFilename(settings.contextFileName); + } else { + // Reset to default if not provided in settings. + setServerGeminiMdFilename(getCurrentGeminiMdFilename()); + } + // Call the (now wrapper) loadHierarchicalGeminiMemory which calls the server's version const { memoryContent, fileCount } = await loadHierarchicalGeminiMemory( process.cwd(), @@ -159,7 +172,8 @@ export async function loadCliConfig(settings: Settings): Promise { userMemory: memoryContent, geminiMdFileCount: fileCount, vertexai: useVertexAI, - showMemoryUsage: argv.show_memory_usage || false, + showMemoryUsage: + argv.show_memory_usage || settings.showMemoryUsage || false, }; return createServerConfig(configParams); diff --git a/packages/cli/src/config/settings.test.ts b/packages/cli/src/config/settings.test.ts new file mode 100644 index 00000000..4d61ed8b --- /dev/null +++ b/packages/cli/src/config/settings.test.ts @@ -0,0 +1,309 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/// + +const MOCK_HOME_DIR = '/mock/home/user'; // MUST BE FIRST + +// Mock 'os' first. Its factory uses MOCK_HOME_DIR. +import * as osActual from 'os'; // Import for type info for the mock factory +vi.mock('os', async (importOriginal) => { + const actualOs = await importOriginal(); + return { + ...actualOs, + homedir: vi.fn(() => MOCK_HOME_DIR), + }; +}); + +// Mock './settings.js' to ensure it uses the mocked 'os.homedir()' for its internal constants. +vi.mock('./settings.js', async (importActual) => { + const originalModule = await importActual(); + return { + __esModule: true, // Ensure correct module shape + ...originalModule, // Re-export all original members + // We are relying on originalModule's USER_SETTINGS_PATH being constructed with mocked os.homedir() + }; +}); + +// NOW import everything else, including the (now effectively re-exported) settings.js +import * as pathActual from 'path'; // Restored for MOCK_WORKSPACE_SETTINGS_PATH +import { + describe, + it, + expect, + vi, + beforeEach, + afterEach, + type Mocked, + type Mock, +} from 'vitest'; +import * as fs from 'fs'; // fs will be mocked separately +import stripJsonComments from 'strip-json-comments'; // Will be mocked separately + +// These imports will get the versions from the vi.mock('./settings.js', ...) factory. +import { + LoadedSettings, + loadSettings, + USER_SETTINGS_PATH, // This IS the mocked path. + SETTINGS_DIRECTORY_NAME, // This is from the original module, but used by the mock. + SettingScope, +} from './settings.js'; + +const MOCK_WORKSPACE_DIR = '/mock/workspace'; +// Use the (mocked) SETTINGS_DIRECTORY_NAME for consistency +const MOCK_WORKSPACE_SETTINGS_PATH = pathActual.join( + MOCK_WORKSPACE_DIR, + SETTINGS_DIRECTORY_NAME, + 'settings.json', +); + +vi.mock('fs'); +vi.mock('strip-json-comments', () => ({ + default: vi.fn((content) => content), +})); + +describe('Settings Loading and Merging', () => { + let mockFsExistsSync: Mocked; + let mockStripJsonComments: Mocked; + let mockFsMkdirSync: Mocked; + + beforeEach(() => { + vi.resetAllMocks(); + + mockFsExistsSync = vi.mocked(fs.existsSync); + mockFsMkdirSync = vi.mocked(fs.mkdirSync); + mockStripJsonComments = vi.mocked(stripJsonComments); + + vi.mocked(osActual.homedir).mockReturnValue(MOCK_HOME_DIR); + (mockStripJsonComments as unknown as Mock).mockImplementation( + (jsonString: string) => jsonString, + ); + (mockFsExistsSync as Mock).mockReturnValue(false); + (fs.readFileSync as Mock).mockReturnValue('{}'); // Return valid empty JSON + (mockFsMkdirSync as Mock).mockImplementation(() => undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('loadSettings', () => { + it('should load empty settings if no files exist', () => { + const settings = loadSettings(MOCK_WORKSPACE_DIR); + expect(settings.user.settings).toEqual({}); + expect(settings.workspace.settings).toEqual({}); + expect(settings.merged).toEqual({}); + }); + + it('should load user settings if only user file exists', () => { + const expectedUserSettingsPath = USER_SETTINGS_PATH; // Use the path actually resolved by the (mocked) module + + (mockFsExistsSync as Mock).mockImplementation( + (p: fs.PathLike) => p === expectedUserSettingsPath, + ); + const userSettingsContent = { + theme: 'dark', + contextFileName: 'USER_CONTEXT.md', + }; + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === expectedUserSettingsPath) + return JSON.stringify(userSettingsContent); + return '{}'; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + + expect(fs.readFileSync).toHaveBeenCalledWith( + expectedUserSettingsPath, + 'utf-8', + ); + expect(settings.user.settings).toEqual(userSettingsContent); + expect(settings.workspace.settings).toEqual({}); + expect(settings.merged).toEqual(userSettingsContent); + }); + + it('should load workspace settings if only workspace file exists', () => { + (mockFsExistsSync as Mock).mockImplementation( + (p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH, + ); + const workspaceSettingsContent = { + sandbox: true, + contextFileName: 'WORKSPACE_CONTEXT.md', + }; + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === MOCK_WORKSPACE_SETTINGS_PATH) + return JSON.stringify(workspaceSettingsContent); + return ''; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + + expect(fs.readFileSync).toHaveBeenCalledWith( + MOCK_WORKSPACE_SETTINGS_PATH, + 'utf-8', + ); + expect(settings.user.settings).toEqual({}); + expect(settings.workspace.settings).toEqual(workspaceSettingsContent); + expect(settings.merged).toEqual(workspaceSettingsContent); + }); + + it('should merge user and workspace settings, with workspace taking precedence', () => { + (mockFsExistsSync as Mock).mockReturnValue(true); + const userSettingsContent = { + theme: 'dark', + sandbox: false, + contextFileName: 'USER_CONTEXT.md', + }; + const workspaceSettingsContent = { + sandbox: true, + coreTools: ['tool1'], + contextFileName: 'WORKSPACE_CONTEXT.md', + }; + + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === USER_SETTINGS_PATH) + return JSON.stringify(userSettingsContent); + if (p === MOCK_WORKSPACE_SETTINGS_PATH) + return JSON.stringify(workspaceSettingsContent); + return ''; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + + expect(settings.user.settings).toEqual(userSettingsContent); + expect(settings.workspace.settings).toEqual(workspaceSettingsContent); + expect(settings.merged).toEqual({ + theme: 'dark', + sandbox: true, + coreTools: ['tool1'], + contextFileName: 'WORKSPACE_CONTEXT.md', + }); + }); + + it('should handle contextFileName correctly when only in user settings', () => { + (mockFsExistsSync as Mock).mockImplementation( + (p: fs.PathLike) => p === USER_SETTINGS_PATH, + ); + const userSettingsContent = { contextFileName: 'CUSTOM.md' }; + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === USER_SETTINGS_PATH) + return JSON.stringify(userSettingsContent); + return ''; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + expect(settings.merged.contextFileName).toBe('CUSTOM.md'); + }); + + it('should handle contextFileName correctly when only in workspace settings', () => { + (mockFsExistsSync as Mock).mockImplementation( + (p: fs.PathLike) => p === MOCK_WORKSPACE_SETTINGS_PATH, + ); + const workspaceSettingsContent = { + contextFileName: 'PROJECT_SPECIFIC.md', + }; + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === MOCK_WORKSPACE_SETTINGS_PATH) + return JSON.stringify(workspaceSettingsContent); + return ''; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + expect(settings.merged.contextFileName).toBe('PROJECT_SPECIFIC.md'); + }); + + it('should default contextFileName to undefined if not in any settings file', () => { + (mockFsExistsSync as Mock).mockReturnValue(true); + const userSettingsContent = { theme: 'dark' }; + const workspaceSettingsContent = { sandbox: true }; + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + if (p === USER_SETTINGS_PATH) + return JSON.stringify(userSettingsContent); + if (p === MOCK_WORKSPACE_SETTINGS_PATH) + return JSON.stringify(workspaceSettingsContent); + return ''; + }, + ); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + expect(settings.merged.contextFileName).toBeUndefined(); + }); + + it('should handle JSON parsing errors gracefully', () => { + (mockFsExistsSync as Mock).mockReturnValue(true); + (fs.readFileSync as Mock).mockImplementation( + (p: fs.PathOrFileDescriptor) => { + // Make it return invalid json for the paths it will try to read + if (p === USER_SETTINGS_PATH || p === MOCK_WORKSPACE_SETTINGS_PATH) + return 'invalid json'; + return ''; + }, + ); + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + const settings = loadSettings(MOCK_WORKSPACE_DIR); + + expect(settings.user.settings).toEqual({}); + expect(settings.workspace.settings).toEqual({}); + expect(settings.merged).toEqual({}); + expect(consoleErrorSpy).toHaveBeenCalledTimes(2); + + consoleErrorSpy.mockRestore(); + }); + }); + + describe('LoadedSettings class', () => { + it('setValue should update the correct scope and recompute merged settings', () => { + (mockFsExistsSync as Mock).mockReturnValue(false); + const loadedSettings = loadSettings(MOCK_WORKSPACE_DIR) as LoadedSettings; + + vi.mocked(fs.writeFileSync).mockImplementation(() => {}); + // mkdirSync is mocked in beforeEach to return undefined, which is fine for void usage + + loadedSettings.setValue(SettingScope.User, 'theme', 'matrix'); + expect(loadedSettings.user.settings.theme).toBe('matrix'); + expect(loadedSettings.merged.theme).toBe('matrix'); + expect(fs.writeFileSync).toHaveBeenCalledWith( + USER_SETTINGS_PATH, + JSON.stringify({ theme: 'matrix' }, null, 2), + 'utf-8', + ); + + loadedSettings.setValue( + SettingScope.Workspace, + 'contextFileName', + 'MY_AGENTS.md', + ); + expect(loadedSettings.workspace.settings.contextFileName).toBe( + 'MY_AGENTS.md', + ); + expect(loadedSettings.merged.contextFileName).toBe('MY_AGENTS.md'); + expect(loadedSettings.merged.theme).toBe('matrix'); + expect(fs.writeFileSync).toHaveBeenCalledWith( + MOCK_WORKSPACE_SETTINGS_PATH, + JSON.stringify({ contextFileName: 'MY_AGENTS.md' }, null, 2), + 'utf-8', + ); + + loadedSettings.setValue(SettingScope.Workspace, 'theme', 'ocean'); + expect(loadedSettings.workspace.settings.theme).toBe('ocean'); + expect(loadedSettings.merged.theme).toBe('ocean'); + }); + }); +}); diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index 1aabc127..5d51ba15 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -30,6 +30,7 @@ export interface Settings { mcpServerCommand?: string; mcpServers?: Record; showMemoryUsage?: boolean; + contextFileName?: string; // Add other settings here. } diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx new file mode 100644 index 00000000..a7811f6a --- /dev/null +++ b/packages/cli/src/ui/App.test.tsx @@ -0,0 +1,289 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect, vi, beforeEach, afterEach, Mock } from 'vitest'; +import { render } from 'ink-testing-library'; +import { App } from './App.js'; +import { Config as ServerConfig, MCPServerConfig } from '@gemini-code/core'; +import type { ToolRegistry } from '@gemini-code/core'; +import { LoadedSettings, SettingsFile, Settings } from '../config/settings.js'; + +// Define a more complete mock server config based on actual Config +interface MockServerConfig { + apiKey: string; + model: string; + sandbox: boolean | string; + targetDir: string; + debugMode: boolean; + question?: string; + fullContext: boolean; + coreTools?: string[]; + toolDiscoveryCommand?: string; + toolCallCommand?: string; + mcpServerCommand?: string; + mcpServers?: Record; // Use imported MCPServerConfig + userAgent: string; + userMemory: string; + geminiMdFileCount: number; + alwaysSkipModificationConfirmation: boolean; + vertexai?: boolean; + showMemoryUsage?: boolean; + + getApiKey: Mock<() => string>; + getModel: Mock<() => string>; + getSandbox: Mock<() => boolean | string>; + getTargetDir: Mock<() => string>; + getToolRegistry: Mock<() => ToolRegistry>; // Use imported ToolRegistry type + getDebugMode: Mock<() => boolean>; + getQuestion: Mock<() => string | undefined>; + getFullContext: Mock<() => boolean>; + getCoreTools: Mock<() => string[] | undefined>; + getToolDiscoveryCommand: Mock<() => string | undefined>; + getToolCallCommand: Mock<() => string | undefined>; + getMcpServerCommand: Mock<() => string | undefined>; + getMcpServers: Mock<() => Record | undefined>; + getUserAgent: Mock<() => string>; + getUserMemory: Mock<() => string>; + setUserMemory: Mock<(newUserMemory: string) => void>; + getGeminiMdFileCount: Mock<() => number>; + setGeminiMdFileCount: Mock<(count: number) => void>; + getAlwaysSkipModificationConfirmation: Mock<() => boolean>; + setAlwaysSkipModificationConfirmation: Mock<(skip: boolean) => void>; + getVertexAI: Mock<() => boolean | undefined>; + getShowMemoryUsage: Mock<() => boolean>; +} + +// Mock @gemini-code/core and its Config class +vi.mock('@gemini-code/core', async (importOriginal) => { + const actualCore = await importOriginal(); + const ConfigClassMock = vi + .fn() + .mockImplementation((optionsPassedToConstructor) => { + const opts = { ...optionsPassedToConstructor }; // Clone + // Basic mock structure, will be extended by the instance in tests + return { + apiKey: opts.apiKey || 'test-key', + model: opts.model || 'test-model-in-mock-factory', + sandbox: typeof opts.sandbox === 'boolean' ? opts.sandbox : false, + targetDir: opts.targetDir || '/test/dir', + debugMode: opts.debugMode || false, + question: opts.question, + fullContext: opts.fullContext ?? false, + coreTools: opts.coreTools, + toolDiscoveryCommand: opts.toolDiscoveryCommand, + toolCallCommand: opts.toolCallCommand, + mcpServerCommand: opts.mcpServerCommand, + mcpServers: opts.mcpServers, + userAgent: opts.userAgent || 'test-agent', + userMemory: opts.userMemory || '', + geminiMdFileCount: opts.geminiMdFileCount || 0, + alwaysSkipModificationConfirmation: + opts.alwaysSkipModificationConfirmation ?? false, + vertexai: opts.vertexai, + showMemoryUsage: opts.showMemoryUsage ?? false, + + getApiKey: vi.fn(() => opts.apiKey || 'test-key'), + getModel: vi.fn(() => opts.model || 'test-model-in-mock-factory'), + getSandbox: vi.fn(() => + typeof opts.sandbox === 'boolean' ? opts.sandbox : false, + ), + getTargetDir: vi.fn(() => opts.targetDir || '/test/dir'), + getToolRegistry: vi.fn(() => ({}) as ToolRegistry), // Simple mock + getDebugMode: vi.fn(() => opts.debugMode || false), + getQuestion: vi.fn(() => opts.question), + getFullContext: vi.fn(() => opts.fullContext ?? false), + getCoreTools: vi.fn(() => opts.coreTools), + getToolDiscoveryCommand: vi.fn(() => opts.toolDiscoveryCommand), + getToolCallCommand: vi.fn(() => opts.toolCallCommand), + getMcpServerCommand: vi.fn(() => opts.mcpServerCommand), + getMcpServers: vi.fn(() => opts.mcpServers), + getUserAgent: vi.fn(() => opts.userAgent || 'test-agent'), + getUserMemory: vi.fn(() => opts.userMemory || ''), + setUserMemory: vi.fn(), + getGeminiMdFileCount: vi.fn(() => opts.geminiMdFileCount || 0), + setGeminiMdFileCount: vi.fn(), + getAlwaysSkipModificationConfirmation: vi.fn( + () => opts.alwaysSkipModificationConfirmation ?? false, + ), + setAlwaysSkipModificationConfirmation: vi.fn(), + getVertexAI: vi.fn(() => opts.vertexai), + getShowMemoryUsage: vi.fn(() => opts.showMemoryUsage ?? false), + }; + }); + return { + ...actualCore, + Config: ConfigClassMock, + MCPServerConfig: actualCore.MCPServerConfig, + }; +}); + +// Mock heavy dependencies or those with side effects +vi.mock('./hooks/useGeminiStream', () => ({ + useGeminiStream: vi.fn(() => ({ + streamingState: 'Idle', + submitQuery: vi.fn(), + initError: null, + pendingHistoryItems: [], + })), +})); + +vi.mock('./hooks/useLogger', () => ({ + useLogger: vi.fn(() => ({ + getPreviousUserMessages: vi.fn().mockResolvedValue([]), + })), +})); + +vi.mock('../config/config.js', async (importOriginal) => { + const actual = await importOriginal(); + return { + // @ts-expect-error - this is fine + ...actual, + loadHierarchicalGeminiMemory: vi + .fn() + .mockResolvedValue({ memoryContent: '', fileCount: 0 }), + }; +}); + +describe('App UI', () => { + let mockConfig: MockServerConfig; + let mockSettings: LoadedSettings; + let currentUnmount: (() => void) | undefined; + + const createMockSettings = ( + settings: Partial = {}, + ): LoadedSettings => { + const userSettingsFile: SettingsFile = { + path: '/user/settings.json', + settings: {}, + }; + const workspaceSettingsFile: SettingsFile = { + path: '/workspace/.gemini/settings.json', + settings, + }; + return new LoadedSettings(userSettingsFile, workspaceSettingsFile); + }; + + beforeEach(() => { + const ServerConfigMocked = vi.mocked(ServerConfig, true); + mockConfig = new ServerConfigMocked({ + apiKey: 'test-key', + model: 'test-model-in-options', + sandbox: false, + targetDir: '/test/dir', + debugMode: false, + userAgent: 'test-agent', + userMemory: '', + geminiMdFileCount: 0, + showMemoryUsage: false, + // Provide other required fields for ConfigParameters if necessary + }) as unknown as MockServerConfig; + + // Ensure the getShowMemoryUsage mock function is specifically set up if not covered by constructor mock + if (!mockConfig.getShowMemoryUsage) { + mockConfig.getShowMemoryUsage = vi.fn(() => false); + } + mockConfig.getShowMemoryUsage.mockReturnValue(false); // Default for most tests + + mockSettings = createMockSettings(); + }); + + afterEach(() => { + if (currentUnmount) { + currentUnmount(); + currentUnmount = undefined; + } + vi.clearAllMocks(); // Clear mocks after each test + }); + + it('should display default "GEMINI.md" in footer when contextFileName is not set and count is 1', async () => { + mockConfig.getGeminiMdFileCount.mockReturnValue(1); + // For this test, ensure showMemoryUsage is false or debugMode is false if it relies on that + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + await Promise.resolve(); // Wait for any async updates + expect(lastFrame()).toContain('Using 1 GEMINI.md file'); + }); + + it('should display default "GEMINI.md" with plural when contextFileName is not set and count is > 1', async () => { + mockConfig.getGeminiMdFileCount.mockReturnValue(2); + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + await Promise.resolve(); + expect(lastFrame()).toContain('Using 2 GEMINI.md files'); + }); + + it('should display custom contextFileName in footer when set and count is 1', async () => { + mockSettings = createMockSettings({ contextFileName: 'AGENTS.MD' }); + mockConfig.getGeminiMdFileCount.mockReturnValue(1); + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + await Promise.resolve(); + expect(lastFrame()).toContain('Using 1 AGENTS.MD file'); + }); + + it('should display custom contextFileName with plural when set and count is > 1', async () => { + mockSettings = createMockSettings({ contextFileName: 'MY_NOTES.TXT' }); + mockConfig.getGeminiMdFileCount.mockReturnValue(3); + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + await Promise.resolve(); + expect(lastFrame()).toContain('Using 3 MY_NOTES.TXT files'); + }); + + it('should not display context file message if count is 0, even if contextFileName is set', async () => { + mockSettings = createMockSettings({ contextFileName: 'ANY_FILE.MD' }); + mockConfig.getGeminiMdFileCount.mockReturnValue(0); + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + await Promise.resolve(); + expect(lastFrame()).not.toContain('ANY_FILE.MD'); + }); +}); diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index e1657984..2f216db7 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -39,7 +39,11 @@ import { DetailedMessagesDisplay } from './components/DetailedMessagesDisplay.js import { HistoryItemDisplay } from './components/HistoryItemDisplay.js'; import { useHistory } from './hooks/useHistoryManager.js'; import process from 'node:process'; -import { getErrorMessage, type Config } from '@gemini-code/core'; +import { + getErrorMessage, + type Config, + getCurrentGeminiMdFilename, +} from '@gemini-code/core'; import { useLogger } from './hooks/useLogger.js'; import { StreamingContext } from './contexts/StreamingContext.js'; import { useGitBranchName } from './hooks/useGitBranchName.js'; @@ -398,7 +402,10 @@ export const App = ({ ) : geminiMdFileCount > 0 ? ( - Using {geminiMdFileCount} GEMINI.md file + Using {geminiMdFileCount}{' '} + {settings.merged.contextFileName || + getCurrentGeminiMdFilename()}{' '} + file {geminiMdFileCount > 1 ? 's' : ''} ) : ( diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index f84ad746..c3c46659 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -4,10 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect, vi, beforeEach /*, afterEach */ } from 'vitest'; // afterEach removed as it was unused -import { Config, createServerConfig, ConfigParameters } from './config.js'; // Adjust import path +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { Config, createServerConfig, ConfigParameters } from './config.js'; import * as path from 'path'; -// import { ToolRegistry } from '../tools/tool-registry'; // ToolRegistry removed as it was unused +import { setGeminiMdFilename as mockSetGeminiMdFilename } from '../tools/memoryTool.js'; // Mock dependencies that might be called during Config construction or createServerConfig vi.mock('../tools/tool-registry', () => { @@ -30,6 +30,12 @@ vi.mock('../tools/shell'); vi.mock('../tools/write-file'); vi.mock('../tools/web-fetch'); vi.mock('../tools/read-many-files'); +vi.mock('../tools/memoryTool', () => ({ + MemoryTool: vi.fn(), + setGeminiMdFilename: vi.fn(), + getCurrentGeminiMdFilename: vi.fn(() => 'GEMINI.md'), // Mock the original filename + DEFAULT_CONTEXT_FILENAME: 'GEMINI.md', +})); describe('Server Config (config.ts)', () => { const API_KEY = 'server-api-key'; @@ -106,4 +112,34 @@ describe('Server Config (config.ts)', () => { const config = createServerConfig(paramsWithRelativeDir); expect(config.getTargetDir()).toBe(expectedResolvedDir); }); + + it('createServerConfig should call setGeminiMdFilename with contextFileName if provided', () => { + const contextFileName = 'CUSTOM_AGENTS.md'; + const paramsWithContextFile: ConfigParameters = { + ...baseParams, + contextFileName, + }; + createServerConfig(paramsWithContextFile); + expect(mockSetGeminiMdFilename).toHaveBeenCalledWith(contextFileName); + }); + + it('createServerConfig should not call setGeminiMdFilename if contextFileName is not provided', () => { + createServerConfig(baseParams); // baseParams does not have contextFileName + expect(mockSetGeminiMdFilename).not.toHaveBeenCalled(); + }); + + it('Config constructor should call setGeminiMdFilename with contextFileName if provided', () => { + const contextFileName = 'CUSTOM_AGENTS.md'; + const paramsWithContextFile: ConfigParameters = { + ...baseParams, + contextFileName, + }; + new Config(paramsWithContextFile); + expect(mockSetGeminiMdFilename).toHaveBeenCalledWith(contextFileName); + }); + + it('Config constructor should not call setGeminiMdFilename if contextFileName is not provided', () => { + new Config(baseParams); // baseParams does not have contextFileName + expect(mockSetGeminiMdFilename).not.toHaveBeenCalled(); + }); }); diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 0cd7a4fa..d918de04 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -19,7 +19,7 @@ import { ShellTool } from '../tools/shell.js'; import { WriteFileTool } from '../tools/write-file.js'; import { WebFetchTool } from '../tools/web-fetch.js'; import { ReadManyFilesTool } from '../tools/read-many-files.js'; -import { MemoryTool } from '../tools/memoryTool.js'; +import { MemoryTool, setGeminiMdFilename } from '../tools/memoryTool.js'; import { WebSearchTool } from '../tools/web-search.js'; export class MCPServerConfig { @@ -56,6 +56,7 @@ export interface ConfigParameters { alwaysSkipModificationConfirmation?: boolean; vertexai?: boolean; showMemoryUsage?: boolean; + contextFileName?: string; } export class Config { @@ -100,6 +101,10 @@ export class Config { this.vertexai = params.vertexai; this.showMemoryUsage = params.showMemoryUsage ?? false; + if (params.contextFileName) { + setGeminiMdFilename(params.contextFileName); + } + this.toolRegistry = createToolRegistry(this); } diff --git a/packages/core/src/tools/memoryTool.test.ts b/packages/core/src/tools/memoryTool.test.ts index 42b1329d..612a08dc 100644 --- a/packages/core/src/tools/memoryTool.test.ts +++ b/packages/core/src/tools/memoryTool.test.ts @@ -5,7 +5,12 @@ */ import { vi, describe, it, expect, beforeEach, afterEach, Mock } from 'vitest'; -import { MemoryTool } from './memoryTool.js'; +import { + MemoryTool, + setGeminiMdFilename, + getCurrentGeminiMdFilename, + DEFAULT_CONTEXT_FILENAME, +} from './memoryTool.js'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; @@ -50,10 +55,33 @@ describe('MemoryTool', () => { afterEach(() => { vi.restoreAllMocks(); + // Reset GEMINI_MD_FILENAME to its original value after each test + setGeminiMdFilename(DEFAULT_CONTEXT_FILENAME); + }); + + describe('setGeminiMdFilename', () => { + it('should update currentGeminiMdFilename when a valid new name is provided', () => { + const newName = 'CUSTOM_CONTEXT.md'; + setGeminiMdFilename(newName); + expect(getCurrentGeminiMdFilename()).toBe(newName); + }); + + it('should not update currentGeminiMdFilename if the new name is empty or whitespace', () => { + const initialName = getCurrentGeminiMdFilename(); // Get current before trying to change + setGeminiMdFilename(' '); + expect(getCurrentGeminiMdFilename()).toBe(initialName); + + setGeminiMdFilename(''); + expect(getCurrentGeminiMdFilename()).toBe(initialName); + }); }); describe('performAddMemoryEntry (static method)', () => { - const testFilePath = path.join('/mock/home', '.gemini', 'GEMINI.md'); + const testFilePath = path.join( + '/mock/home', + '.gemini', + DEFAULT_CONTEXT_FILENAME, // Use the default for basic tests + ); it('should create section and save a fact if file does not exist', async () => { mockFsAdapter.readFile.mockRejectedValue({ code: 'ENOENT' }); // Simulate file not found @@ -168,7 +196,12 @@ describe('MemoryTool', () => { it('should call performAddMemoryEntry with correct parameters and return success', async () => { const params = { fact: 'The sky is blue' }; const result = await memoryTool.execute(params, mockAbortSignal); - const expectedFilePath = path.join('/mock/home', '.gemini', 'GEMINI.md'); + // Use getCurrentGeminiMdFilename for the default expectation before any setGeminiMdFilename calls in a test + const expectedFilePath = path.join( + '/mock/home', + '.gemini', + getCurrentGeminiMdFilename(), // This will be DEFAULT_CONTEXT_FILENAME unless changed by a test + ); // For this test, we expect the actual fs methods to be passed const expectedFsArgument = { diff --git a/packages/core/src/tools/memoryTool.ts b/packages/core/src/tools/memoryTool.ts index 49dce59d..a0c62eae 100644 --- a/packages/core/src/tools/memoryTool.ts +++ b/packages/core/src/tools/memoryTool.ts @@ -46,15 +46,29 @@ Do NOT use this tool: `; export const GEMINI_CONFIG_DIR = '.gemini'; -export const GEMINI_MD_FILENAME = 'GEMINI.md'; +export const DEFAULT_CONTEXT_FILENAME = 'GEMINI.md'; export const MEMORY_SECTION_HEADER = '## Gemini Added Memories'; +// This variable will hold the currently configured filename for GEMINI.md context files. +// It defaults to DEFAULT_CONTEXT_FILENAME but can be overridden by setGeminiMdFilename. +let currentGeminiMdFilename = DEFAULT_CONTEXT_FILENAME; + +export function setGeminiMdFilename(newFilename: string): void { + if (newFilename && newFilename.trim() !== '') { + currentGeminiMdFilename = newFilename.trim(); + } +} + +export function getCurrentGeminiMdFilename(): string { + return currentGeminiMdFilename; +} + interface SaveMemoryParams { fact: string; } function getGlobalMemoryFilePath(): string { - return path.join(homedir(), GEMINI_CONFIG_DIR, GEMINI_MD_FILENAME); + return path.join(homedir(), GEMINI_CONFIG_DIR, getCurrentGeminiMdFilename()); } /** diff --git a/packages/core/src/tools/read-many-files.ts b/packages/core/src/tools/read-many-files.ts index d826c9ba..4ba09ef0 100644 --- a/packages/core/src/tools/read-many-files.ts +++ b/packages/core/src/tools/read-many-files.ts @@ -9,7 +9,7 @@ import { SchemaValidator } from '../utils/schemaValidator.js'; import { getErrorMessage } from '../utils/errors.js'; import * as path from 'path'; import fg from 'fast-glob'; -import { GEMINI_MD_FILENAME } from './memoryTool.js'; +import { getCurrentGeminiMdFilename } from './memoryTool.js'; import { detectFileType, processSingleFileContent, @@ -98,7 +98,7 @@ const DEFAULT_EXCLUDES: string[] = [ '**/*.odp', '**/*.DS_Store', '**/.env', - `**/${GEMINI_MD_FILENAME}`, + `**/${getCurrentGeminiMdFilename()}`, ]; const DEFAULT_OUTPUT_SEPARATOR_FORMAT = '--- {filePath} ---'; diff --git a/packages/core/src/utils/memoryDiscovery.test.ts b/packages/core/src/utils/memoryDiscovery.test.ts index 229f51e5..db0ffd1d 100644 --- a/packages/core/src/utils/memoryDiscovery.test.ts +++ b/packages/core/src/utils/memoryDiscovery.test.ts @@ -4,22 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - vi, - describe, - it, - expect, - beforeEach, - // afterEach, // Removed unused import - Mocked, -} from 'vitest'; +import { vi, describe, it, expect, beforeEach, Mocked } from 'vitest'; import * as fsPromises from 'fs/promises'; -import * as fsSync from 'fs'; // For constants -import { Stats, Dirent } from 'fs'; // Import types directly from 'fs' +import * as fsSync from 'fs'; +import { Stats, Dirent } from 'fs'; import * as os from 'os'; import * as path from 'path'; import { loadServerHierarchicalMemory } from './memoryDiscovery.js'; -import { GEMINI_CONFIG_DIR, GEMINI_MD_FILENAME } from '../tools/memoryTool.js'; +import { + GEMINI_CONFIG_DIR, + setGeminiMdFilename, + getCurrentGeminiMdFilename, + DEFAULT_CONTEXT_FILENAME, +} from '../tools/memoryTool.js'; + +const ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST = DEFAULT_CONTEXT_FILENAME; // Mock the entire fs/promises module vi.mock('fs/promises'); @@ -29,8 +28,6 @@ vi.mock('fs', async (importOriginal) => { return { ...actual, // Spread actual to get all exports, including Stats and Dirent if they are classes/constructors constants: { ...actual.constants }, // Preserve constants - // Mock other fsSync functions if directly used by memoryDiscovery, e.g., existsSync - // existsSync: vi.fn(), }; }); vi.mock('os'); @@ -42,20 +39,29 @@ describe('loadServerHierarchicalMemory', () => { const CWD = '/test/project/src'; const PROJECT_ROOT = '/test/project'; const USER_HOME = '/test/userhome'; - const GLOBAL_GEMINI_DIR = path.join(USER_HOME, GEMINI_CONFIG_DIR); - const GLOBAL_GEMINI_FILE = path.join(GLOBAL_GEMINI_DIR, GEMINI_MD_FILENAME); + + let GLOBAL_GEMINI_DIR: string; + let GLOBAL_GEMINI_FILE: string; // Defined in beforeEach beforeEach(() => { vi.resetAllMocks(); - + setGeminiMdFilename(DEFAULT_CONTEXT_FILENAME); // Use defined const mockOs.homedir.mockReturnValue(USER_HOME); + + // Define these here to use potentially reset/updated values from imports + GLOBAL_GEMINI_DIR = path.join(USER_HOME, GEMINI_CONFIG_DIR); + GLOBAL_GEMINI_FILE = path.join( + GLOBAL_GEMINI_DIR, + getCurrentGeminiMdFilename(), // Use current filename + ); + mockFs.stat.mockRejectedValue(new Error('File not found')); mockFs.readdir.mockResolvedValue([]); mockFs.readFile.mockRejectedValue(new Error('File not found')); mockFs.access.mockRejectedValue(new Error('File not found')); }); - it('should return empty memory and count if no GEMINI.md files are found', async () => { + it('should return empty memory and count if no context files are found', async () => { const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, @@ -64,15 +70,19 @@ describe('loadServerHierarchicalMemory', () => { expect(fileCount).toBe(0); }); - it('should load only the global GEMINI.md if present and others are not', async () => { + it('should load only the global context file if present and others are not (default filename)', async () => { + const globalDefaultFile = path.join( + GLOBAL_GEMINI_DIR, + DEFAULT_CONTEXT_FILENAME, + ); mockFs.access.mockImplementation(async (p) => { - if (p === GLOBAL_GEMINI_FILE) { + if (p === globalDefaultFile) { return undefined; } throw new Error('File not found'); }); mockFs.readFile.mockImplementation(async (p) => { - if (p === GLOBAL_GEMINI_FILE) { + if (p === globalDefaultFile) { return 'Global memory content'; } throw new Error('File not found'); @@ -84,15 +94,157 @@ describe('loadServerHierarchicalMemory', () => { ); expect(memoryContent).toBe( - `--- Context from: ${path.relative(CWD, GLOBAL_GEMINI_FILE)} ---\nGlobal memory content\n--- End of Context from: ${path.relative(CWD, GLOBAL_GEMINI_FILE)} ---`, + `--- Context from: ${path.relative(CWD, globalDefaultFile)} ---\nGlobal memory content\n--- End of Context from: ${path.relative(CWD, globalDefaultFile)} ---`, ); expect(fileCount).toBe(1); - expect(mockFs.readFile).toHaveBeenCalledWith(GLOBAL_GEMINI_FILE, 'utf-8'); + expect(mockFs.readFile).toHaveBeenCalledWith(globalDefaultFile, 'utf-8'); }); - it('should load GEMINI.md files by upward traversal from CWD to project root', async () => { - const projectRootGeminiFile = path.join(PROJECT_ROOT, GEMINI_MD_FILENAME); - const srcGeminiFile = path.join(CWD, GEMINI_MD_FILENAME); + it('should load only the global custom context file if present and filename is changed', async () => { + const customFilename = 'CUSTOM_AGENTS.md'; + setGeminiMdFilename(customFilename); + const globalCustomFile = path.join(GLOBAL_GEMINI_DIR, customFilename); + + mockFs.access.mockImplementation(async (p) => { + if (p === globalCustomFile) { + return undefined; + } + throw new Error('File not found'); + }); + mockFs.readFile.mockImplementation(async (p) => { + if (p === globalCustomFile) { + return 'Global custom memory'; + } + throw new Error('File not found'); + }); + + const { memoryContent, fileCount } = await loadServerHierarchicalMemory( + CWD, + false, + ); + + expect(memoryContent).toBe( + `--- Context from: ${path.relative(CWD, globalCustomFile)} ---\nGlobal custom memory\n--- End of Context from: ${path.relative(CWD, globalCustomFile)} ---`, + ); + expect(fileCount).toBe(1); + expect(mockFs.readFile).toHaveBeenCalledWith(globalCustomFile, 'utf-8'); + }); + + it('should load context files by upward traversal with custom filename', async () => { + const customFilename = 'PROJECT_CONTEXT.md'; + setGeminiMdFilename(customFilename); + const projectRootCustomFile = path.join(PROJECT_ROOT, customFilename); + const srcCustomFile = path.join(CWD, customFilename); + + mockFs.stat.mockImplementation(async (p) => { + if (p === path.join(PROJECT_ROOT, '.git')) { + return { isDirectory: () => true } as Stats; + } + throw new Error('File not found'); + }); + + mockFs.access.mockImplementation(async (p) => { + if (p === projectRootCustomFile || p === srcCustomFile) { + return undefined; + } + throw new Error('File not found'); + }); + + mockFs.readFile.mockImplementation(async (p) => { + if (p === projectRootCustomFile) { + return 'Project root custom memory'; + } + if (p === srcCustomFile) { + return 'Src directory custom memory'; + } + throw new Error('File not found'); + }); + + const { memoryContent, fileCount } = await loadServerHierarchicalMemory( + CWD, + false, + ); + const expectedContent = + `--- Context from: ${path.relative(CWD, projectRootCustomFile)} ---\nProject root custom memory\n--- End of Context from: ${path.relative(CWD, projectRootCustomFile)} ---\n\n` + + `--- Context from: ${customFilename} ---\nSrc directory custom memory\n--- End of Context from: ${customFilename} ---`; + + expect(memoryContent).toBe(expectedContent); + expect(fileCount).toBe(2); + expect(mockFs.readFile).toHaveBeenCalledWith( + projectRootCustomFile, + 'utf-8', + ); + expect(mockFs.readFile).toHaveBeenCalledWith(srcCustomFile, 'utf-8'); + }); + + it('should load context files by downward traversal with custom filename', async () => { + const customFilename = 'LOCAL_CONTEXT.md'; + setGeminiMdFilename(customFilename); + const subDir = path.join(CWD, 'subdir'); + const subDirCustomFile = path.join(subDir, customFilename); + const cwdCustomFile = path.join(CWD, customFilename); + + mockFs.access.mockImplementation(async (p) => { + if (p === cwdCustomFile || p === subDirCustomFile) return undefined; + throw new Error('File not found'); + }); + + mockFs.readFile.mockImplementation(async (p) => { + if (p === cwdCustomFile) return 'CWD custom memory'; + if (p === subDirCustomFile) return 'Subdir custom memory'; + throw new Error('File not found'); + }); + + mockFs.readdir.mockImplementation((async ( + p: fsSync.PathLike, + ): Promise => { + if (p === CWD) { + return [ + { + name: customFilename, + isFile: () => true, + isDirectory: () => false, + } as Dirent, + { + name: 'subdir', + isFile: () => false, + isDirectory: () => true, + } as Dirent, + ] as Dirent[]; + } + if (p === subDir) { + return [ + { + name: customFilename, + isFile: () => true, + isDirectory: () => false, + } as Dirent, + ] as Dirent[]; + } + return [] as Dirent[]; + }) as unknown as typeof fsPromises.readdir); + + const { memoryContent, fileCount } = await loadServerHierarchicalMemory( + CWD, + false, + ); + const expectedContent = + `--- Context from: ${customFilename} ---\nCWD custom memory\n--- End of Context from: ${customFilename} ---\n\n` + + `--- Context from: ${path.join('subdir', customFilename)} ---\nSubdir custom memory\n--- End of Context from: ${path.join('subdir', customFilename)} ---`; + + expect(memoryContent).toBe(expectedContent); + expect(fileCount).toBe(2); + }); + + it('should load ORIGINAL_GEMINI_MD_FILENAME files by upward traversal from CWD to project root', async () => { + const projectRootGeminiFile = path.join( + PROJECT_ROOT, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); + const srcGeminiFile = path.join( + CWD, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); mockFs.stat.mockImplementation(async (p) => { if (p === path.join(PROJECT_ROOT, '.git')) { @@ -124,7 +276,7 @@ describe('loadServerHierarchicalMemory', () => { ); const expectedContent = `--- Context from: ${path.relative(CWD, projectRootGeminiFile)} ---\nProject root memory\n--- End of Context from: ${path.relative(CWD, projectRootGeminiFile)} ---\n\n` + - `--- Context from: ${GEMINI_MD_FILENAME} ---\nSrc directory memory\n--- End of Context from: ${GEMINI_MD_FILENAME} ---`; + `--- Context from: ${ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST} ---\nSrc directory memory\n--- End of Context from: ${ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST} ---`; expect(memoryContent).toBe(expectedContent); expect(fileCount).toBe(2); @@ -135,10 +287,16 @@ describe('loadServerHierarchicalMemory', () => { expect(mockFs.readFile).toHaveBeenCalledWith(srcGeminiFile, 'utf-8'); }); - it('should load GEMINI.md files by downward traversal from CWD', async () => { + it('should load ORIGINAL_GEMINI_MD_FILENAME files by downward traversal from CWD', async () => { const subDir = path.join(CWD, 'subdir'); - const subDirGeminiFile = path.join(subDir, GEMINI_MD_FILENAME); - const cwdGeminiFile = path.join(CWD, GEMINI_MD_FILENAME); + const subDirGeminiFile = path.join( + subDir, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); + const cwdGeminiFile = path.join( + CWD, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); mockFs.access.mockImplementation(async (p) => { if (p === cwdGeminiFile || p === subDirGeminiFile) return undefined; @@ -157,59 +315,79 @@ describe('loadServerHierarchicalMemory', () => { if (p === CWD) { return [ { - name: GEMINI_MD_FILENAME, + name: ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, isFile: () => true, isDirectory: () => false, - }, - { name: 'subdir', isFile: () => false, isDirectory: () => true }, + } as Dirent, + { + name: 'subdir', + isFile: () => false, + isDirectory: () => true, + } as Dirent, ] as Dirent[]; } if (p === subDir) { return [ { - name: GEMINI_MD_FILENAME, + name: ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, isFile: () => true, isDirectory: () => false, - }, + } as Dirent, ] as Dirent[]; } return [] as Dirent[]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }) as any); + }) as unknown as typeof fsPromises.readdir); const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, ); const expectedContent = - `--- Context from: ${GEMINI_MD_FILENAME} ---\nCWD memory\n--- End of Context from: ${GEMINI_MD_FILENAME} ---\n\n` + - `--- Context from: ${path.join('subdir', GEMINI_MD_FILENAME)} ---\nSubdir memory\n--- End of Context from: ${path.join('subdir', GEMINI_MD_FILENAME)} ---`; + `--- Context from: ${ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST} ---\nCWD memory\n--- End of Context from: ${ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST} ---\n\n` + + `--- Context from: ${path.join('subdir', ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST)} ---\nSubdir memory\n--- End of Context from: ${path.join('subdir', ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST)} ---`; expect(memoryContent).toBe(expectedContent); expect(fileCount).toBe(2); }); - it('should load and correctly order global, upward, and downward GEMINI.md files', async () => { + it('should load and correctly order global, upward, and downward ORIGINAL_GEMINI_MD_FILENAME files', async () => { + setGeminiMdFilename(ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST); // Explicitly set for this test + + const globalFileToUse = path.join( + GLOBAL_GEMINI_DIR, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); const projectParentDir = path.dirname(PROJECT_ROOT); const projectParentGeminiFile = path.join( projectParentDir, - GEMINI_MD_FILENAME, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); + const projectRootGeminiFile = path.join( + PROJECT_ROOT, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); + const cwdGeminiFile = path.join( + CWD, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, ); - const projectRootGeminiFile = path.join(PROJECT_ROOT, GEMINI_MD_FILENAME); - const cwdGeminiFile = path.join(CWD, GEMINI_MD_FILENAME); const subDir = path.join(CWD, 'sub'); - const subDirGeminiFile = path.join(subDir, GEMINI_MD_FILENAME); + const subDirGeminiFile = path.join( + subDir, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); mockFs.stat.mockImplementation(async (p) => { if (p === path.join(PROJECT_ROOT, '.git')) { return { isDirectory: () => true } as Stats; + } else if (p === path.join(PROJECT_ROOT, '.gemini')) { + return { isDirectory: () => true } as Stats; } throw new Error('File not found'); }); mockFs.access.mockImplementation(async (p) => { if ( - p === GLOBAL_GEMINI_FILE || + p === globalFileToUse || // Use the dynamically set global file path p === projectParentGeminiFile || p === projectRootGeminiFile || p === cwdGeminiFile || @@ -221,7 +399,7 @@ describe('loadServerHierarchicalMemory', () => { }); mockFs.readFile.mockImplementation(async (p) => { - if (p === GLOBAL_GEMINI_FILE) return 'Global memory'; + if (p === globalFileToUse) return 'Global memory'; // Use the dynamically set global file path if (p === projectParentGeminiFile) return 'Project parent memory'; if (p === projectRootGeminiFile) return 'Project root memory'; if (p === cwdGeminiFile) return 'CWD memory'; @@ -234,21 +412,24 @@ describe('loadServerHierarchicalMemory', () => { ): Promise => { if (p === CWD) { return [ - { name: 'sub', isFile: () => false, isDirectory: () => true }, + { + name: 'sub', + isFile: () => false, + isDirectory: () => true, + } as Dirent, ] as Dirent[]; } if (p === subDir) { return [ { - name: GEMINI_MD_FILENAME, + name: ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, isFile: () => true, isDirectory: () => false, - }, + } as Dirent, ] as Dirent[]; } return [] as Dirent[]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }) as any); + }) as unknown as typeof fsPromises.readdir); const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, @@ -258,8 +439,11 @@ describe('loadServerHierarchicalMemory', () => { const relPathGlobal = path.relative(CWD, GLOBAL_GEMINI_FILE); const relPathProjectParent = path.relative(CWD, projectParentGeminiFile); const relPathProjectRoot = path.relative(CWD, projectRootGeminiFile); - const relPathCwd = GEMINI_MD_FILENAME; - const relPathSubDir = path.join('sub', GEMINI_MD_FILENAME); + const relPathCwd = ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST; + const relPathSubDir = path.join( + 'sub', + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); const expectedContent = [ `--- Context from: ${relPathGlobal} ---\nGlobal memory\n--- End of Context from: ${relPathGlobal} ---`, @@ -275,11 +459,14 @@ describe('loadServerHierarchicalMemory', () => { it('should ignore specified directories during downward scan', async () => { const ignoredDir = path.join(CWD, 'node_modules'); - const ignoredDirGeminiFile = path.join(ignoredDir, GEMINI_MD_FILENAME); + const ignoredDirGeminiFile = path.join( + ignoredDir, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, + ); // Corrected const regularSubDir = path.join(CWD, 'my_code'); const regularSubDirGeminiFile = path.join( regularSubDir, - GEMINI_MD_FILENAME, + ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, ); mockFs.access.mockImplementation(async (p) => { @@ -303,38 +490,41 @@ describe('loadServerHierarchicalMemory', () => { name: 'node_modules', isFile: () => false, isDirectory: () => true, - }, - { name: 'my_code', isFile: () => false, isDirectory: () => true }, + } as Dirent, + { + name: 'my_code', + isFile: () => false, + isDirectory: () => true, + } as Dirent, ] as Dirent[]; } if (p === regularSubDir) { return [ { - name: GEMINI_MD_FILENAME, + name: ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, isFile: () => true, isDirectory: () => false, - }, + } as Dirent, ] as Dirent[]; } if (p === ignoredDir) { return [ { - name: GEMINI_MD_FILENAME, + name: ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST, isFile: () => true, isDirectory: () => false, - }, + } as Dirent, ] as Dirent[]; } return [] as Dirent[]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }) as any); + }) as unknown as typeof fsPromises.readdir); const { memoryContent, fileCount } = await loadServerHierarchicalMemory( CWD, false, ); - const expectedContent = `--- Context from: ${path.join('my_code', GEMINI_MD_FILENAME)} ---\nMy code memory\n--- End of Context from: ${path.join('my_code', GEMINI_MD_FILENAME)} ---`; + const expectedContent = `--- Context from: ${path.join('my_code', ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST)} ---\nMy code memory\n--- End of Context from: ${path.join('my_code', ORIGINAL_GEMINI_MD_FILENAME_CONST_FOR_TEST)} ---`; expect(memoryContent).toBe(expectedContent); expect(fileCount).toBe(1); @@ -365,8 +555,7 @@ describe('loadServerHierarchicalMemory', () => { if (p.toString().startsWith(path.join(CWD, 'deep_dir_'))) return [] as Dirent[]; return [] as Dirent[]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }) as any); + }) as unknown as typeof fsPromises.readdir); mockFs.access.mockRejectedValue(new Error('not found')); await loadServerHierarchicalMemory(CWD, true); diff --git a/packages/core/src/utils/memoryDiscovery.ts b/packages/core/src/utils/memoryDiscovery.ts index 362134d8..2e6ce9fc 100644 --- a/packages/core/src/utils/memoryDiscovery.ts +++ b/packages/core/src/utils/memoryDiscovery.ts @@ -8,7 +8,10 @@ import * as fs from 'fs/promises'; import * as fsSync from 'fs'; import * as path from 'path'; import { homedir } from 'os'; -import { GEMINI_CONFIG_DIR, GEMINI_MD_FILENAME } from '../tools/memoryTool.js'; +import { + GEMINI_CONFIG_DIR, + getCurrentGeminiMdFilename, +} from '../tools/memoryTool.js'; // Simple console logger, similar to the one previously in CLI's config.ts // TODO: Integrate with a more robust server-side logger if available/appropriate. @@ -92,7 +95,7 @@ async function collectDownwardGeminiFiles( if (debugMode) logger.debug( - `Scanning downward for ${GEMINI_MD_FILENAME} files in: ${directory} (scanned: ${scannedDirCount.count}/${maxScanDirs})`, + `Scanning downward for ${getCurrentGeminiMdFilename()} files in: ${directory} (scanned: ${scannedDirCount.count}/${maxScanDirs})`, ); const collectedPaths: string[] = []; try { @@ -113,18 +116,21 @@ async function collectDownwardGeminiFiles( maxScanDirs, ); collectedPaths.push(...subDirPaths); - } else if (entry.isFile() && entry.name === GEMINI_MD_FILENAME) { + } else if ( + entry.isFile() && + entry.name === getCurrentGeminiMdFilename() + ) { try { await fs.access(fullPath, fsSync.constants.R_OK); collectedPaths.push(fullPath); if (debugMode) logger.debug( - `Found readable downward ${GEMINI_MD_FILENAME}: ${fullPath}`, + `Found readable downward ${getCurrentGeminiMdFilename()}: ${fullPath}`, ); } catch { if (debugMode) logger.debug( - `Downward ${GEMINI_MD_FILENAME} not readable, skipping: ${fullPath}`, + `Downward ${getCurrentGeminiMdFilename()} not readable, skipping: ${fullPath}`, ); } } @@ -139,7 +145,7 @@ async function collectDownwardGeminiFiles( async function getGeminiMdFilePathsInternal( currentWorkingDirectory: string, - userHomePath: string, // Keep userHomePath as a parameter for clarity + userHomePath: string, debugMode: boolean, ): Promise { const resolvedCwd = path.resolve(currentWorkingDirectory); @@ -147,13 +153,13 @@ async function getGeminiMdFilePathsInternal( const globalMemoryPath = path.join( resolvedHome, GEMINI_CONFIG_DIR, - GEMINI_MD_FILENAME, + getCurrentGeminiMdFilename(), ); const paths: string[] = []; if (debugMode) logger.debug( - `Searching for ${GEMINI_MD_FILENAME} starting from CWD: ${resolvedCwd}`, + `Searching for ${getCurrentGeminiMdFilename()} starting from CWD: ${resolvedCwd}`, ); if (debugMode) logger.debug(`User home directory: ${resolvedHome}`); @@ -162,12 +168,12 @@ async function getGeminiMdFilePathsInternal( paths.push(globalMemoryPath); if (debugMode) logger.debug( - `Found readable global ${GEMINI_MD_FILENAME}: ${globalMemoryPath}`, + `Found readable global ${getCurrentGeminiMdFilename()}: ${globalMemoryPath}`, ); } catch { if (debugMode) logger.debug( - `Global ${GEMINI_MD_FILENAME} not found or not readable: ${globalMemoryPath}`, + `Global ${getCurrentGeminiMdFilename()} not found or not readable: ${globalMemoryPath}`, ); } @@ -186,7 +192,7 @@ async function getGeminiMdFilePathsInternal( // Loop until filesystem root or currentDir is empty if (debugMode) { logger.debug( - `Checking for ${GEMINI_MD_FILENAME} in (upward scan): ${currentDir}`, + `Checking for ${getCurrentGeminiMdFilename()} in (upward scan): ${currentDir}`, ); } @@ -201,7 +207,7 @@ async function getGeminiMdFilePathsInternal( break; } - const potentialPath = path.join(currentDir, GEMINI_MD_FILENAME); + const potentialPath = path.join(currentDir, getCurrentGeminiMdFilename()); try { await fs.access(potentialPath, fsSync.constants.R_OK); // Add to upwardPaths only if it's not the already added globalMemoryPath @@ -209,14 +215,14 @@ async function getGeminiMdFilePathsInternal( upwardPaths.unshift(potentialPath); if (debugMode) { logger.debug( - `Found readable upward ${GEMINI_MD_FILENAME}: ${potentialPath}`, + `Found readable upward ${getCurrentGeminiMdFilename()}: ${potentialPath}`, ); } } } catch { if (debugMode) { logger.debug( - `Upward ${GEMINI_MD_FILENAME} not found or not readable in: ${currentDir}`, + `Upward ${getCurrentGeminiMdFilename()} not found or not readable in: ${currentDir}`, ); } } @@ -247,7 +253,7 @@ async function getGeminiMdFilePathsInternal( downwardPaths.sort(); // Sort for consistent ordering, though hierarchy might be more complex if (debugMode && downwardPaths.length > 0) logger.debug( - `Found downward ${GEMINI_MD_FILENAME} files (sorted): ${JSON.stringify(downwardPaths)}`, + `Found downward ${getCurrentGeminiMdFilename()} files (sorted): ${JSON.stringify(downwardPaths)}`, ); // Add downward paths only if they haven't been included already (e.g. from upward scan) for (const dPath of downwardPaths) { @@ -258,7 +264,7 @@ async function getGeminiMdFilePathsInternal( if (debugMode) logger.debug( - `Final ordered ${GEMINI_MD_FILENAME} paths to read: ${JSON.stringify(paths)}`, + `Final ordered ${getCurrentGeminiMdFilename()} paths to read: ${JSON.stringify(paths)}`, ); return paths; } @@ -279,7 +285,7 @@ async function readGeminiMdFiles( } catch (error: unknown) { const message = error instanceof Error ? error.message : String(error); logger.warn( - `Warning: Could not read ${GEMINI_MD_FILENAME} file at ${filePath}. Error: ${message}`, + `Warning: Could not read ${getCurrentGeminiMdFilename()} file at ${filePath}. Error: ${message}`, ); results.push({ filePath, content: null }); // Still include it with null content if (debugMode) logger.debug(`Failed to read: ${filePath}`);