mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix: change .geminiignore to .qwenignore
This commit is contained in:
@@ -35,7 +35,7 @@
|
|||||||
- Added deterministic cache control for the DashScope provider.
|
- Added deterministic cache control for the DashScope provider.
|
||||||
- Added option to choose a project-level or global save location.
|
- Added option to choose a project-level or global save location.
|
||||||
- Limited `grep` results to 25 items by default.
|
- Limited `grep` results to 25 items by default.
|
||||||
- `grep` now respects `.geminiignore`.
|
- `grep` now respects `.qwenignore`.
|
||||||
- Miscellaneous improvements and bug fixes.
|
- Miscellaneous improvements and bug fixes.
|
||||||
|
|
||||||
## 0.0.7
|
## 0.0.7
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ You can directly embed the content of a file or a directory listing into your pr
|
|||||||
|
|
||||||
- **File Injection**: `@{path/to/file.txt}` is replaced by the content of `file.txt`.
|
- **File Injection**: `@{path/to/file.txt}` is replaced by the content of `file.txt`.
|
||||||
- **Multimodal Support**: If the path points to a supported image (e.g., PNG, JPEG), PDF, audio, or video file, it will be correctly encoded and injected as multimodal input. Other binary files are handled gracefully and skipped.
|
- **Multimodal Support**: If the path points to a supported image (e.g., PNG, JPEG), PDF, audio, or video file, it will be correctly encoded and injected as multimodal input. Other binary files are handled gracefully and skipped.
|
||||||
- **Directory Listing**: `@{path/to/dir}` is traversed and each file present within the directory and all subdirectories are inserted into the prompt. This respects `.gitignore` and `.geminiignore` if enabled.
|
- **Directory Listing**: `@{path/to/dir}` is traversed and each file present within the directory and all subdirectories are inserted into the prompt. This respects `.gitignore` and `.qwenignore` if enabled.
|
||||||
- **Workspace-Aware**: The command searches for the path in the current directory and any other workspace directories. Absolute paths are allowed if they are within the workspace.
|
- **Workspace-Aware**: The command searches for the path in the current directory and any other workspace directories. Absolute paths are allowed if they are within the workspace.
|
||||||
- **Processing Order**: File content injection with `@{...}` is processed _before_ shell commands (`!{...}`) and argument substitution (`{{args}}`).
|
- **Processing Order**: File content injection with `@{...}` is processed _before_ shell commands (`!{...}`) and argument substitution (`{{args}}`).
|
||||||
- **Parsing**: The parser requires the content inside `@{...}` (the path) to have balanced braces (`{` and `}`).
|
- **Parsing**: The parser requires the content inside `@{...}` (the path) to have balanced braces (`{` and `}`).
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ In addition to a project settings file, a project's `.qwen` directory can contai
|
|||||||
|
|
||||||
If you are experiencing performance issues with file searching (e.g., with `@` completions), especially in projects with a very large number of files, here are a few things you can try in order of recommendation:
|
If you are experiencing performance issues with file searching (e.g., with `@` completions), especially in projects with a very large number of files, here are a few things you can try in order of recommendation:
|
||||||
|
|
||||||
1. **Use `.geminiignore`:** Create a `.geminiignore` file in your project root to exclude directories that contain a large number of files that you don't need to reference (e.g., build artifacts, logs, `node_modules`). Reducing the total number of files crawled is the most effective way to improve performance.
|
1. **Use `.qwenignore`:** Create a `.qwenignore` file in your project root to exclude directories that contain a large number of files that you don't need to reference (e.g., build artifacts, logs, `node_modules`). Reducing the total number of files crawled is the most effective way to improve performance.
|
||||||
|
|
||||||
2. **Disable Fuzzy Search:** If ignoring files is not enough, you can disable fuzzy search by setting `disableFuzzySearch` to `true` in your `settings.json` file. This will use a simpler, non-fuzzy matching algorithm, which can be faster.
|
2. **Disable Fuzzy Search:** If ignoring files is not enough, you can disable fuzzy search by setting `disableFuzzySearch` to `true` in your `settings.json` file. This will use a simpler, non-fuzzy matching algorithm, which can be faster.
|
||||||
|
|
||||||
@@ -135,12 +135,12 @@ If you are experiencing performance issues with file searching (e.g., with `@` c
|
|||||||
- **Example:** `"sandbox": "docker"`
|
- **Example:** `"sandbox": "docker"`
|
||||||
|
|
||||||
- **`toolDiscoveryCommand`** (string):
|
- **`toolDiscoveryCommand`** (string):
|
||||||
- **Description:** Defines a custom shell command for discovering tools from your project. The shell command must return on `stdout` a JSON array of [function declarations](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations). Tool wrappers are optional.
|
- **Description:** **Align with Gemini CLI.** Defines a custom shell command for discovering tools from your project. The shell command must return on `stdout` a JSON array of [function declarations](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations). Tool wrappers are optional.
|
||||||
- **Default:** Empty
|
- **Default:** Empty
|
||||||
- **Example:** `"toolDiscoveryCommand": "bin/get_tools"`
|
- **Example:** `"toolDiscoveryCommand": "bin/get_tools"`
|
||||||
|
|
||||||
- **`toolCallCommand`** (string):
|
- **`toolCallCommand`** (string):
|
||||||
- **Description:** Defines a custom shell command for calling a specific tool that was discovered using `toolDiscoveryCommand`. The shell command must meet the following criteria:
|
- **Description:** **Align with Gemini CLI.** Defines a custom shell command for calling a specific tool that was discovered using `toolDiscoveryCommand`. The shell command must meet the following criteria:
|
||||||
- It must take function `name` (exactly as in [function declaration](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations)) as first command line argument.
|
- It must take function `name` (exactly as in [function declaration](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations)) as first command line argument.
|
||||||
- It must read function arguments as JSON on `stdin`, analogous to [`functionCall.args`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functioncall).
|
- It must read function arguments as JSON on `stdin`, analogous to [`functionCall.args`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functioncall).
|
||||||
- It must return function output as JSON on `stdout`, analogous to [`functionResponse.response.content`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functionresponse).
|
- It must return function output as JSON on `stdout`, analogous to [`functionResponse.response.content`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functionresponse).
|
||||||
@@ -404,6 +404,8 @@ The CLI automatically loads environment variables from an `.env` file. The loadi
|
|||||||
|
|
||||||
**Environment Variable Exclusion:** Some environment variables (like `DEBUG` and `DEBUG_MODE`) are automatically excluded from project `.env` files by default to prevent interference with the CLI behavior. Variables from `.qwen/.env` files are never excluded. You can customize this behavior using the `excludedProjectEnvVars` setting in your `settings.json` file.
|
**Environment Variable Exclusion:** Some environment variables (like `DEBUG` and `DEBUG_MODE`) are automatically excluded from project `.env` files by default to prevent interference with the CLI behavior. Variables from `.qwen/.env` files are never excluded. You can customize this behavior using the `excludedProjectEnvVars` setting in your `settings.json` file.
|
||||||
|
|
||||||
|
**To avoid confusion, we will reorganize all available environment variables in an upcoming release.**
|
||||||
|
|
||||||
- **`GEMINI_API_KEY`**:
|
- **`GEMINI_API_KEY`**:
|
||||||
- Your API key for the Gemini API.
|
- Your API key for the Gemini API.
|
||||||
- One of several available [authentication methods](./authentication.md).
|
- One of several available [authentication methods](./authentication.md).
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
# Ignoring Files
|
|
||||||
|
|
||||||
This document provides an overview of the Gemini Ignore (`.geminiignore`) feature of Qwen Code.
|
|
||||||
|
|
||||||
Qwen Code includes the ability to automatically ignore files, similar to `.gitignore` (used by Git) and `.aiexclude` (used by Gemini Code Assist). Adding paths to your `.geminiignore` file will exclude them from tools that support this feature, although they will still be visible to other services (such as Git).
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
When you add a path to your `.geminiignore` file, tools that respect this file will exclude matching files and directories from their operations. For example, when you use the [`read_many_files`](./tools/multi-file.md) command, any paths in your `.geminiignore` file will be automatically excluded.
|
|
||||||
|
|
||||||
For the most part, `.geminiignore` follows the conventions of `.gitignore` files:
|
|
||||||
|
|
||||||
- Blank lines and lines starting with `#` are ignored.
|
|
||||||
- Standard glob patterns are supported (such as `*`, `?`, and `[]`).
|
|
||||||
- Putting a `/` at the end will only match directories.
|
|
||||||
- Putting a `/` at the beginning anchors the path relative to the `.geminiignore` file.
|
|
||||||
- `!` negates a pattern.
|
|
||||||
|
|
||||||
You can update your `.geminiignore` file at any time. To apply the changes, you must restart your Qwen Code session.
|
|
||||||
|
|
||||||
## How to use `.geminiignore`
|
|
||||||
|
|
||||||
To enable `.geminiignore`:
|
|
||||||
|
|
||||||
1. Create a file named `.geminiignore` in the root of your project directory.
|
|
||||||
|
|
||||||
To add a file or directory to `.geminiignore`:
|
|
||||||
|
|
||||||
1. Open your `.geminiignore` file.
|
|
||||||
2. Add the path or file you want to ignore, for example: `/archive/` or `apikeys.txt`.
|
|
||||||
|
|
||||||
### `.geminiignore` examples
|
|
||||||
|
|
||||||
You can use `.geminiignore` to ignore directories and files:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Exclude your /packages/ directory and all subdirectories
|
|
||||||
/packages/
|
|
||||||
|
|
||||||
# Exclude your apikeys.txt file
|
|
||||||
apikeys.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
You can use wildcards in your `.geminiignore` file with `*`:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Exclude all .md files
|
|
||||||
*.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, you can exclude files and directories from exclusion with `!`:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Exclude all .md files except README.md
|
|
||||||
*.md
|
|
||||||
!README.md
|
|
||||||
```
|
|
||||||
|
|
||||||
To remove paths from your `.geminiignore` file, delete the relevant lines.
|
|
||||||
59
docs/qwen-ignore.md
Normal file
59
docs/qwen-ignore.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# Ignoring Files
|
||||||
|
|
||||||
|
This document provides an overview of the Gemini Ignore (`.qwenignore`) feature of Qwen Code.
|
||||||
|
|
||||||
|
Qwen Code includes the ability to automatically ignore files, similar to `.gitignore` (used by Git) and `.aiexclude` (used by Gemini Code Assist). Adding paths to your `.qwenignore` file will exclude them from tools that support this feature, although they will still be visible to other services (such as Git).
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
When you add a path to your `.qwenignore` file, tools that respect this file will exclude matching files and directories from their operations. For example, when you use the [`read_many_files`](./tools/multi-file.md) command, any paths in your `.qwenignore` file will be automatically excluded.
|
||||||
|
|
||||||
|
For the most part, `.qwenignore` follows the conventions of `.gitignore` files:
|
||||||
|
|
||||||
|
- Blank lines and lines starting with `#` are ignored.
|
||||||
|
- Standard glob patterns are supported (such as `*`, `?`, and `[]`).
|
||||||
|
- Putting a `/` at the end will only match directories.
|
||||||
|
- Putting a `/` at the beginning anchors the path relative to the `.qwenignore` file.
|
||||||
|
- `!` negates a pattern.
|
||||||
|
|
||||||
|
You can update your `.qwenignore` file at any time. To apply the changes, you must restart your Qwen Code session.
|
||||||
|
|
||||||
|
## How to use `.qwenignore`
|
||||||
|
|
||||||
|
To enable `.qwenignore`:
|
||||||
|
|
||||||
|
1. Create a file named `.qwenignore` in the root of your project directory.
|
||||||
|
|
||||||
|
To add a file or directory to `.qwenignore`:
|
||||||
|
|
||||||
|
1. Open your `.qwenignore` file.
|
||||||
|
2. Add the path or file you want to ignore, for example: `/archive/` or `apikeys.txt`.
|
||||||
|
|
||||||
|
### `.qwenignore` examples
|
||||||
|
|
||||||
|
You can use `.qwenignore` to ignore directories and files:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Exclude your /packages/ directory and all subdirectories
|
||||||
|
/packages/
|
||||||
|
|
||||||
|
# Exclude your apikeys.txt file
|
||||||
|
apikeys.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use wildcards in your `.qwenignore` file with `*`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Exclude all .md files
|
||||||
|
*.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, you can exclude files and directories from exclusion with `!`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Exclude all .md files except README.md
|
||||||
|
*.md
|
||||||
|
!README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
To remove paths from your `.qwenignore` file, delete the relevant lines.
|
||||||
@@ -448,11 +448,11 @@ export const SETTINGS_SCHEMA = {
|
|||||||
},
|
},
|
||||||
respectGeminiIgnore: {
|
respectGeminiIgnore: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
label: 'Respect .geminiignore',
|
label: 'Respect .qwenignore',
|
||||||
category: 'Context',
|
category: 'Context',
|
||||||
requiresRestart: true,
|
requiresRestart: true,
|
||||||
default: true,
|
default: true,
|
||||||
description: 'Respect .geminiignore files when searching',
|
description: 'Respect .qwenignore files when searching',
|
||||||
showInDialog: true,
|
showInDialog: true,
|
||||||
},
|
},
|
||||||
enableRecursiveFileSearch: {
|
enableRecursiveFileSearch: {
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ describe('AtFileProcessor', () => {
|
|||||||
expect(context.ui.addItem).toHaveBeenCalledWith(
|
expect(context.ui.addItem).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
type: MessageType.INFO,
|
type: MessageType.INFO,
|
||||||
text: "File '@{ignored.txt}' was ignored by .gitignore or .geminiignore and was not included in the prompt.",
|
text: "File '@{ignored.txt}' was ignored by .gitignore or .qwenignore and was not included in the prompt.",
|
||||||
},
|
},
|
||||||
expect.any(Number),
|
expect.any(Number),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export class AtFileProcessor implements IPromptProcessor {
|
|||||||
try {
|
try {
|
||||||
const fileContentParts = await readPathFromWorkspace(pathStr, config);
|
const fileContentParts = await readPathFromWorkspace(pathStr, config);
|
||||||
if (fileContentParts.length === 0) {
|
if (fileContentParts.length === 0) {
|
||||||
const uiMessage = `File '@{${pathStr}}' was ignored by .gitignore or .geminiignore and was not included in the prompt.`;
|
const uiMessage = `File '@{${pathStr}}' was ignored by .gitignore or .qwenignore and was not included in the prompt.`;
|
||||||
context.ui.addItem(
|
context.ui.addItem(
|
||||||
{ type: MessageType.INFO, text: uiMessage },
|
{ type: MessageType.INFO, text: uiMessage },
|
||||||
Date.now(),
|
Date.now(),
|
||||||
|
|||||||
@@ -581,7 +581,7 @@ describe('handleAtCommand', () => {
|
|||||||
describe('gemini-ignore filtering', () => {
|
describe('gemini-ignore filtering', () => {
|
||||||
it('should skip gemini-ignored files in @ commands', async () => {
|
it('should skip gemini-ignored files in @ commands', async () => {
|
||||||
await createTestFile(
|
await createTestFile(
|
||||||
path.join(testRootDir, '.geminiignore'),
|
path.join(testRootDir, '.qwenignore'),
|
||||||
'build/output.js',
|
'build/output.js',
|
||||||
);
|
);
|
||||||
const geminiIgnoredFile = await createTestFile(
|
const geminiIgnoredFile = await createTestFile(
|
||||||
@@ -611,9 +611,9 @@ describe('handleAtCommand', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should process non-ignored files when .geminiignore is present', async () => {
|
it('should process non-ignored files when .qwenignore is present', async () => {
|
||||||
await createTestFile(
|
await createTestFile(
|
||||||
path.join(testRootDir, '.geminiignore'),
|
path.join(testRootDir, '.qwenignore'),
|
||||||
'build/output.js',
|
'build/output.js',
|
||||||
);
|
);
|
||||||
const validFile = await createTestFile(
|
const validFile = await createTestFile(
|
||||||
@@ -645,7 +645,7 @@ describe('handleAtCommand', () => {
|
|||||||
|
|
||||||
it('should handle mixed gemini-ignored and valid files', async () => {
|
it('should handle mixed gemini-ignored and valid files', async () => {
|
||||||
await createTestFile(
|
await createTestFile(
|
||||||
path.join(testRootDir, '.geminiignore'),
|
path.join(testRootDir, '.qwenignore'),
|
||||||
'dist/bundle.js',
|
'dist/bundle.js',
|
||||||
);
|
);
|
||||||
const validFile = await createTestFile(
|
const validFile = await createTestFile(
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ describe('FileDiscoveryService', () => {
|
|||||||
expect(service.shouldGitIgnoreFile('node_modules/foo.js')).toBe(false);
|
expect(service.shouldGitIgnoreFile('node_modules/foo.js')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load .geminiignore patterns even when not in a git repo', async () => {
|
it('should load .qwenignore patterns even when not in a git repo', async () => {
|
||||||
await createTestFile('.geminiignore', 'secrets.txt');
|
await createTestFile('.qwenignore', 'secrets.txt');
|
||||||
const service = new FileDiscoveryService(projectRoot);
|
const service = new FileDiscoveryService(projectRoot);
|
||||||
|
|
||||||
expect(service.shouldGeminiIgnoreFile('secrets.txt')).toBe(true);
|
expect(service.shouldGeminiIgnoreFile('secrets.txt')).toBe(true);
|
||||||
@@ -66,7 +66,7 @@ describe('FileDiscoveryService', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await fs.mkdir(path.join(projectRoot, '.git'));
|
await fs.mkdir(path.join(projectRoot, '.git'));
|
||||||
await createTestFile('.gitignore', 'node_modules/\n.git/\ndist');
|
await createTestFile('.gitignore', 'node_modules/\n.git/\ndist');
|
||||||
await createTestFile('.geminiignore', 'logs/');
|
await createTestFile('.qwenignore', 'logs/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter out git-ignored and gemini-ignored files by default', () => {
|
it('should filter out git-ignored and gemini-ignored files by default', () => {
|
||||||
@@ -140,7 +140,7 @@ describe('FileDiscoveryService', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await fs.mkdir(path.join(projectRoot, '.git'));
|
await fs.mkdir(path.join(projectRoot, '.git'));
|
||||||
await createTestFile('.gitignore', 'node_modules/');
|
await createTestFile('.gitignore', 'node_modules/');
|
||||||
await createTestFile('.geminiignore', '*.log');
|
await createTestFile('.qwenignore', '*.log');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for git-ignored files', () => {
|
it('should return true for git-ignored files', () => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { GitIgnoreParser } from '../utils/gitIgnoreParser.js';
|
|||||||
import { isGitRepository } from '../utils/gitUtils.js';
|
import { isGitRepository } from '../utils/gitUtils.js';
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
|
|
||||||
const GEMINI_IGNORE_FILE_NAME = '.geminiignore';
|
const GEMINI_IGNORE_FILE_NAME = '.qwenignore';
|
||||||
|
|
||||||
export interface FilterFilesOptions {
|
export interface FilterFilesOptions {
|
||||||
respectGitIgnore?: boolean;
|
respectGitIgnore?: boolean;
|
||||||
@@ -104,7 +104,7 @@ export class FileDiscoveryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns loaded patterns from .geminiignore
|
* Returns loaded patterns from .qwenignore
|
||||||
*/
|
*/
|
||||||
getGeminiIgnorePatterns(): string[] {
|
getGeminiIgnorePatterns(): string[] {
|
||||||
return this.geminiIgnoreFilter?.getPatterns() ?? [];
|
return this.geminiIgnoreFilter?.getPatterns() ?? [];
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export interface LSToolParams {
|
|||||||
ignore?: string[];
|
ignore?: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to respect .gitignore and .geminiignore patterns (optional, defaults to true)
|
* Whether to respect .gitignore and .qwenignore patterns (optional, defaults to true)
|
||||||
*/
|
*/
|
||||||
file_filtering_options?: {
|
file_filtering_options?: {
|
||||||
respect_git_ignore?: boolean;
|
respect_git_ignore?: boolean;
|
||||||
@@ -297,7 +297,7 @@ export class LSTool extends BaseDeclarativeTool<LSToolParams, ToolResult> {
|
|||||||
},
|
},
|
||||||
file_filtering_options: {
|
file_filtering_options: {
|
||||||
description:
|
description:
|
||||||
'Optional: Whether to respect ignore patterns from .gitignore or .geminiignore',
|
'Optional: Whether to respect ignore patterns from .gitignore or .qwenignore',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
respect_git_ignore: {
|
respect_git_ignore: {
|
||||||
@@ -307,7 +307,7 @@ export class LSTool extends BaseDeclarativeTool<LSToolParams, ToolResult> {
|
|||||||
},
|
},
|
||||||
respect_gemini_ignore: {
|
respect_gemini_ignore: {
|
||||||
description:
|
description:
|
||||||
'Optional: Whether to respect .geminiignore patterns when listing files. Defaults to true.',
|
'Optional: Whether to respect .qwenignore patterns when listing files. Defaults to true.',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -409,21 +409,21 @@ describe('ReadFileTool', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with .geminiignore', () => {
|
describe('with .qwenignore', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await fsp.writeFile(
|
await fsp.writeFile(
|
||||||
path.join(tempRootDir, '.geminiignore'),
|
path.join(tempRootDir, '.qwenignore'),
|
||||||
['foo.*', 'ignored/'].join('\n'),
|
['foo.*', 'ignored/'].join('\n'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw error if path is ignored by a .geminiignore pattern', async () => {
|
it('should throw error if path is ignored by a .qwenignore pattern', async () => {
|
||||||
const ignoredFilePath = path.join(tempRootDir, 'foo.bar');
|
const ignoredFilePath = path.join(tempRootDir, 'foo.bar');
|
||||||
await fsp.writeFile(ignoredFilePath, 'content', 'utf-8');
|
await fsp.writeFile(ignoredFilePath, 'content', 'utf-8');
|
||||||
const params: ReadFileToolParams = {
|
const params: ReadFileToolParams = {
|
||||||
absolute_path: ignoredFilePath,
|
absolute_path: ignoredFilePath,
|
||||||
};
|
};
|
||||||
const expectedError = `File path '${ignoredFilePath}' is ignored by .geminiignore pattern(s).`;
|
const expectedError = `File path '${ignoredFilePath}' is ignored by .qwenignore pattern(s).`;
|
||||||
expect(() => tool.build(params)).toThrow(expectedError);
|
expect(() => tool.build(params)).toThrow(expectedError);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -435,7 +435,7 @@ describe('ReadFileTool', () => {
|
|||||||
const params: ReadFileToolParams = {
|
const params: ReadFileToolParams = {
|
||||||
absolute_path: ignoredFilePath,
|
absolute_path: ignoredFilePath,
|
||||||
};
|
};
|
||||||
const expectedError = `File path '${ignoredFilePath}' is ignored by .geminiignore pattern(s).`;
|
const expectedError = `File path '${ignoredFilePath}' is ignored by .qwenignore pattern(s).`;
|
||||||
expect(() => tool.build(params)).toThrow(expectedError);
|
expect(() => tool.build(params)).toThrow(expectedError);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ export class ReadFileTool extends BaseDeclarativeTool<
|
|||||||
|
|
||||||
const fileService = this.config.getFileService();
|
const fileService = this.config.getFileService();
|
||||||
if (fileService.shouldGeminiIgnoreFile(params.absolute_path)) {
|
if (fileService.shouldGeminiIgnoreFile(params.absolute_path)) {
|
||||||
return `File path '${filePath}' is ignored by .geminiignore pattern(s).`;
|
return `File path '${filePath}' is ignored by .qwenignore pattern(s).`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ describe('ReadManyFilesTool', () => {
|
|||||||
tempDirOutsideRoot = fs.realpathSync(
|
tempDirOutsideRoot = fs.realpathSync(
|
||||||
fs.mkdtempSync(path.join(os.tmpdir(), 'read-many-files-external-')),
|
fs.mkdtempSync(path.join(os.tmpdir(), 'read-many-files-external-')),
|
||||||
);
|
);
|
||||||
fs.writeFileSync(path.join(tempRootDir, '.geminiignore'), 'foo.*');
|
fs.writeFileSync(path.join(tempRootDir, '.qwenignore'), 'foo.*');
|
||||||
const fileService = new FileDiscoveryService(tempRootDir);
|
const fileService = new FileDiscoveryService(tempRootDir);
|
||||||
const mockConfig = {
|
const mockConfig = {
|
||||||
getFileService: () => fileService,
|
getFileService: () => fileService,
|
||||||
@@ -466,7 +466,7 @@ describe('ReadManyFilesTool', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return error if path is ignored by a .geminiignore pattern', async () => {
|
it('should return error if path is ignored by a .qwenignore pattern', async () => {
|
||||||
createFile('foo.bar', '');
|
createFile('foo.bar', '');
|
||||||
createFile('bar.ts', '');
|
createFile('bar.ts', '');
|
||||||
createFile('foo.quux', '');
|
createFile('foo.quux', '');
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export interface ReadManyFilesParams {
|
|||||||
useDefaultExcludes?: boolean;
|
useDefaultExcludes?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to respect .gitignore and .geminiignore patterns (optional, defaults to true)
|
* Whether to respect .gitignore and .qwenignore patterns (optional, defaults to true)
|
||||||
*/
|
*/
|
||||||
file_filtering_options?: {
|
file_filtering_options?: {
|
||||||
respect_git_ignore?: boolean;
|
respect_git_ignore?: boolean;
|
||||||
@@ -149,13 +149,13 @@ ${finalExclusionPatternsForDescription
|
|||||||
: 'none specified'
|
: 'none specified'
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
// Add a note if .geminiignore patterns contributed to the final list of exclusions
|
// Add a note if .qwenignore patterns contributed to the final list of exclusions
|
||||||
if (geminiIgnorePatterns.length > 0) {
|
if (geminiIgnorePatterns.length > 0) {
|
||||||
const geminiPatternsInEffect = geminiIgnorePatterns.filter((p) =>
|
const geminiPatternsInEffect = geminiIgnorePatterns.filter((p) =>
|
||||||
finalExclusionPatternsForDescription.includes(p),
|
finalExclusionPatternsForDescription.includes(p),
|
||||||
).length;
|
).length;
|
||||||
if (geminiPatternsInEffect > 0) {
|
if (geminiPatternsInEffect > 0) {
|
||||||
excludeDesc += ` (includes ${geminiPatternsInEffect} from .geminiignore)`;
|
excludeDesc += ` (includes ${geminiPatternsInEffect} from .qwenignore)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,7 +571,7 @@ export class ReadManyFilesTool extends BaseDeclarativeTool<
|
|||||||
},
|
},
|
||||||
file_filtering_options: {
|
file_filtering_options: {
|
||||||
description:
|
description:
|
||||||
'Whether to respect ignore patterns from .gitignore or .geminiignore',
|
'Whether to respect ignore patterns from .gitignore or .qwenignore',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
respect_git_ignore: {
|
respect_git_ignore: {
|
||||||
@@ -581,7 +581,7 @@ export class ReadManyFilesTool extends BaseDeclarativeTool<
|
|||||||
},
|
},
|
||||||
respect_gemini_ignore: {
|
respect_gemini_ignore: {
|
||||||
description:
|
description:
|
||||||
'Optional: Whether to respect .geminiignore patterns when listing files. Defaults to true.',
|
'Optional: Whether to respect .qwenignore patterns when listing files. Defaults to true.',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ describe('bfsFileSearch', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore geminiignored files', async () => {
|
it('should ignore geminiignored files', async () => {
|
||||||
await createTestFile('node_modules/', 'project', '.geminiignore');
|
await createTestFile('node_modules/', 'project', '.qwenignore');
|
||||||
await createTestFile('content', 'project', 'node_modules', 'target.txt');
|
await createTestFile('content', 'project', 'node_modules', 'target.txt');
|
||||||
const targetFilePath = await createTestFile(
|
const targetFilePath = await createTestFile(
|
||||||
'content',
|
'content',
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ describe('crawler', () => {
|
|||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use .geminiignore rules', async () => {
|
it('should use .qwenignore rules', async () => {
|
||||||
tmpDir = await createTmpDir({
|
tmpDir = await createTmpDir({
|
||||||
'.geminiignore': 'dist/',
|
'.qwenignore': 'dist/',
|
||||||
dist: ['ignored.js'],
|
dist: ['ignored.js'],
|
||||||
src: ['not-ignored.js'],
|
src: ['not-ignored.js'],
|
||||||
});
|
});
|
||||||
@@ -48,16 +48,16 @@ describe('crawler', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
'.',
|
'.',
|
||||||
'src/',
|
'src/',
|
||||||
'.geminiignore',
|
'.qwenignore',
|
||||||
'src/not-ignored.js',
|
'src/not-ignored.js',
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should combine .gitignore and .geminiignore rules', async () => {
|
it('should combine .gitignore and .qwenignore rules', async () => {
|
||||||
tmpDir = await createTmpDir({
|
tmpDir = await createTmpDir({
|
||||||
'.gitignore': 'dist/',
|
'.gitignore': 'dist/',
|
||||||
'.geminiignore': 'build/',
|
'.qwenignore': 'build/',
|
||||||
dist: ['ignored-by-git.js'],
|
dist: ['ignored-by-git.js'],
|
||||||
build: ['ignored-by-gemini.js'],
|
build: ['ignored-by-gemini.js'],
|
||||||
src: ['not-ignored.js'],
|
src: ['not-ignored.js'],
|
||||||
@@ -82,7 +82,7 @@ describe('crawler', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
'.',
|
'.',
|
||||||
'src/',
|
'src/',
|
||||||
'.geminiignore',
|
'.qwenignore',
|
||||||
'.gitignore',
|
'.gitignore',
|
||||||
'src/not-ignored.js',
|
'src/not-ignored.js',
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ describe('FileSearch', () => {
|
|||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use .geminiignore rules', async () => {
|
it('should use .qwenignore rules', async () => {
|
||||||
tmpDir = await createTmpDir({
|
tmpDir = await createTmpDir({
|
||||||
'.geminiignore': 'dist/',
|
'.qwenignore': 'dist/',
|
||||||
dist: ['ignored.js'],
|
dist: ['ignored.js'],
|
||||||
src: ['not-ignored.js'],
|
src: ['not-ignored.js'],
|
||||||
});
|
});
|
||||||
@@ -38,13 +38,13 @@ describe('FileSearch', () => {
|
|||||||
await fileSearch.initialize();
|
await fileSearch.initialize();
|
||||||
const results = await fileSearch.search('');
|
const results = await fileSearch.search('');
|
||||||
|
|
||||||
expect(results).toEqual(['src/', '.geminiignore', 'src/not-ignored.js']);
|
expect(results).toEqual(['src/', '.qwenignore', 'src/not-ignored.js']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should combine .gitignore and .geminiignore rules', async () => {
|
it('should combine .gitignore and .qwenignore rules', async () => {
|
||||||
tmpDir = await createTmpDir({
|
tmpDir = await createTmpDir({
|
||||||
'.gitignore': 'dist/',
|
'.gitignore': 'dist/',
|
||||||
'.geminiignore': 'build/',
|
'.qwenignore': 'build/',
|
||||||
dist: ['ignored-by-git.js'],
|
dist: ['ignored-by-git.js'],
|
||||||
build: ['ignored-by-gemini.js'],
|
build: ['ignored-by-gemini.js'],
|
||||||
src: ['not-ignored.js'],
|
src: ['not-ignored.js'],
|
||||||
@@ -66,7 +66,7 @@ describe('FileSearch', () => {
|
|||||||
|
|
||||||
expect(results).toEqual([
|
expect(results).toEqual([
|
||||||
'src/',
|
'src/',
|
||||||
'.geminiignore',
|
'.qwenignore',
|
||||||
'.gitignore',
|
'.gitignore',
|
||||||
'src/not-ignored.js',
|
'src/not-ignored.js',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ describe('loadIgnoreRules', () => {
|
|||||||
expect(fileFilter('test.txt')).toBe(false);
|
expect(fileFilter('test.txt')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load rules from .geminiignore', async () => {
|
it('should load rules from .qwenignore', async () => {
|
||||||
tmpDir = await createTmpDir({
|
tmpDir = await createTmpDir({
|
||||||
'.geminiignore': '*.log',
|
'.qwenignore': '*.log',
|
||||||
});
|
});
|
||||||
const ignore = loadIgnoreRules({
|
const ignore = loadIgnoreRules({
|
||||||
projectRoot: tmpDir,
|
projectRoot: tmpDir,
|
||||||
@@ -104,10 +104,10 @@ describe('loadIgnoreRules', () => {
|
|||||||
expect(fileFilter('test.txt')).toBe(false);
|
expect(fileFilter('test.txt')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should combine rules from .gitignore and .geminiignore', async () => {
|
it('should combine rules from .gitignore and .qwenignore', async () => {
|
||||||
tmpDir = await createTmpDir({
|
tmpDir = await createTmpDir({
|
||||||
'.gitignore': '*.log',
|
'.gitignore': '*.log',
|
||||||
'.geminiignore': '*.txt',
|
'.qwenignore': '*.txt',
|
||||||
});
|
});
|
||||||
const ignore = loadIgnoreRules({
|
const ignore = loadIgnoreRules({
|
||||||
projectRoot: tmpDir,
|
projectRoot: tmpDir,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export function loadIgnoreRules(options: LoadIgnoreRulesOptions): Ignore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.useGeminiignore) {
|
if (options.useGeminiignore) {
|
||||||
const geminiignorePath = path.join(options.projectRoot, '.geminiignore');
|
const geminiignorePath = path.join(options.projectRoot, '.qwenignore');
|
||||||
if (fs.existsSync(geminiignorePath)) {
|
if (fs.existsSync(geminiignorePath)) {
|
||||||
ignorer.add(fs.readFileSync(geminiignorePath, 'utf8'));
|
ignorer.add(fs.readFileSync(geminiignorePath, 'utf8'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ ${testRootDir}${path.sep}
|
|||||||
describe('with geminiignore', () => {
|
describe('with geminiignore', () => {
|
||||||
it('should ignore geminiignore files by default', async () => {
|
it('should ignore geminiignore files by default', async () => {
|
||||||
await fsPromises.writeFile(
|
await fsPromises.writeFile(
|
||||||
nodePath.join(testRootDir, '.geminiignore'),
|
nodePath.join(testRootDir, '.qwenignore'),
|
||||||
'ignored.txt\nnode_modules/\n.gemini/\n!/.gemini/config.yaml',
|
'ignored.txt\nnode_modules/\n.gemini/\n!/.gemini/config.yaml',
|
||||||
);
|
);
|
||||||
await createTestFile('file1.txt');
|
await createTestFile('file1.txt');
|
||||||
@@ -315,7 +315,7 @@ ${testRootDir}${path.sep}
|
|||||||
|
|
||||||
it('should not ignore files if respectGeminiIgnore is false', async () => {
|
it('should not ignore files if respectGeminiIgnore is false', async () => {
|
||||||
await fsPromises.writeFile(
|
await fsPromises.writeFile(
|
||||||
nodePath.join(testRootDir, '.geminiignore'),
|
nodePath.join(testRootDir, '.qwenignore'),
|
||||||
'ignored.txt\nnode_modules/\n.gemini/\n!/.gemini/config.yaml',
|
'ignored.txt\nnode_modules/\n.gemini/\n!/.gemini/config.yaml',
|
||||||
);
|
);
|
||||||
await createTestFile('file1.txt');
|
await createTestFile('file1.txt');
|
||||||
|
|||||||
@@ -82,16 +82,16 @@ node_modules/
|
|||||||
|
|
||||||
it('should handle custom patterns file name', async () => {
|
it('should handle custom patterns file name', async () => {
|
||||||
// No .git directory for this test
|
// No .git directory for this test
|
||||||
await createTestFile('.geminiignore', 'temp/\n*.tmp');
|
await createTestFile('.qwenignore', 'temp/\n*.tmp');
|
||||||
|
|
||||||
parser.loadPatterns('.geminiignore');
|
parser.loadPatterns('.qwenignore');
|
||||||
expect(parser.getPatterns()).toEqual(['temp/', '*.tmp']);
|
expect(parser.getPatterns()).toEqual(['temp/', '*.tmp']);
|
||||||
expect(parser.isIgnored(path.join('temp', 'file.txt'))).toBe(true);
|
expect(parser.isIgnored(path.join('temp', 'file.txt'))).toBe(true);
|
||||||
expect(parser.isIgnored(path.join('src', 'file.tmp'))).toBe(true);
|
expect(parser.isIgnored(path.join('src', 'file.tmp'))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should initialize without errors when no .geminiignore exists', () => {
|
it('should initialize without errors when no .qwenignore exists', () => {
|
||||||
expect(() => parser.loadPatterns('.geminiignore')).not.toThrow();
|
expect(() => parser.loadPatterns('.qwenignore')).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user