mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-26 03:29:16 +00:00
Compare commits
19 Commits
docs-byYij
...
mingholy/f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25d9c4f1a7 | ||
|
|
850c52dc79 | ||
|
|
61e378644e | ||
|
|
bd3bdd82ea | ||
|
|
fc58291c5c | ||
|
|
633148b257 | ||
|
|
8130020277 | ||
|
|
07fb6faf5f | ||
|
|
1956507d90 | ||
|
|
52faa0da5c | ||
|
|
87f1dd9061 | ||
|
|
5d94763581 | ||
|
|
5bd1822b7d | ||
|
|
65392a057d | ||
|
|
3b9d38a325 | ||
|
|
bf905dcc17 | ||
|
|
95d3e5b744 | ||
|
|
6d3cf4cd98 | ||
|
|
68295d0bbf |
@@ -20,9 +20,9 @@ You can update your `.qwenignore` file at any time. To apply the changes, you mu
|
||||
|
||||
## How to use `.qwenignore`
|
||||
|
||||
| Step | Description |
|
||||
| ---------------------- | ------------------------------------------------------------ |
|
||||
| **Enable .qwenignore** | Create a file named `.qwenignore` in your project root directory |
|
||||
| Step | Description |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------- |
|
||||
| **Enable .qwenignore** | Create a file named `.qwenignore` in your project root directory |
|
||||
| **Add ignore rules** | Open `.qwenignore` file and add paths to ignore, example: `/archive/` or `apikeys.txt` |
|
||||
|
||||
### `.qwenignore` examples
|
||||
|
||||
@@ -50,13 +50,14 @@ Settings are organized into categories. All settings should be placed within the
|
||||
|
||||
#### general
|
||||
|
||||
| Setting | Type | Description | Default |
|
||||
| ------------------------------- | ------- | ------------------------------------------ | ----------- |
|
||||
| `general.preferredEditor` | string | The preferred editor to open files in. | `undefined` |
|
||||
| `general.vimMode` | boolean | Enable Vim keybindings. | `false` |
|
||||
| `general.disableAutoUpdate` | boolean | Disable automatic updates. | `false` |
|
||||
| `general.disableUpdateNag` | boolean | Disable update notification prompts. | `false` |
|
||||
| `general.checkpointing.enabled` | boolean | Enable session checkpointing for recovery. | `false` |
|
||||
| Setting | Type | Description | Default |
|
||||
| ------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------- | ----------- |
|
||||
| `general.preferredEditor` | string | The preferred editor to open files in. | `undefined` |
|
||||
| `general.vimMode` | boolean | Enable Vim keybindings. | `false` |
|
||||
| `general.disableAutoUpdate` | boolean | Disable automatic updates. | `false` |
|
||||
| `general.disableUpdateNag` | boolean | Disable update notification prompts. | `false` |
|
||||
| `general.gitCoAuthor` | boolean | Automatically add a Co-authored-by trailer to git commit messages when commits are made through Qwen Code. | `true` |
|
||||
| `general.checkpointing.enabled` | boolean | Enable session checkpointing for recovery. | `false` |
|
||||
|
||||
#### output
|
||||
|
||||
|
||||
@@ -140,8 +140,6 @@ The theme file must be a valid JSON file that follows the same structure as a cu
|
||||
|
||||
### Example Custom Theme
|
||||
|
||||
|
||||
|
||||
<img src="https://gw.alicdn.com/imgextra/i1/O1CN01Em30Hc1jYXAdIgls3_!!6000000004560-2-tps-1009-629.png" alt=" " style="zoom:100%;text-align:center;margin: 0 auto;" />
|
||||
|
||||
### Using Your Custom Theme
|
||||
@@ -150,15 +148,13 @@ The theme file must be a valid JSON file that follows the same structure as a cu
|
||||
- Or, set it as the default by adding `"theme": "MyCustomTheme"` to the `ui` object in your `settings.json`.
|
||||
- Custom themes can be set at the user, project, or system level, and follow the same [configuration precedence](./configuration.md) as other settings.
|
||||
|
||||
|
||||
|
||||
## Themes Preview
|
||||
|
||||
| Dark Theme | Preview | Light Theme | Preview |
|
||||
| :-: | :-: | :-: | :-: |
|
||||
| ANSI | <img src="https://gw.alicdn.com/imgextra/i2/O1CN01ZInJiq1GdSZc9gHsI_!!6000000000645-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | ANSI Light | <img src="https://gw.alicdn.com/imgextra/i2/O1CN01IiJQFC1h9E3MXQj6W_!!6000000004234-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Atom OneDark | <img src="https://gw.alicdn.com/imgextra/i2/O1CN01Zlx1SO1Sw21SkTKV3_!!6000000002310-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | Ayu Light | <img src="https://gw.alicdn.com/imgextra/i3/O1CN01zEUc1V1jeUJsnCgQb_!!6000000004573-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Ayu | <img src="https://gw.alicdn.com/imgextra/i3/O1CN019upo6v1SmPhmRjzfN_!!6000000002289-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> | Default Light | <img src="https://gw.alicdn.com/imgextra/i4/O1CN01RHjrEs1u7TXq3M6l3_!!6000000005990-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Default | <img src="https://gw.alicdn.com/imgextra/i4/O1CN016pIeXz1pFC8owmR4Q_!!6000000005330-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | GitHub Light | <img src="https://gw.alicdn.com/imgextra/i4/O1CN01US2b0g1VETCPAVWLA_!!6000000002621-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Dracula | <img src="https://gw.alicdn.com/imgextra/i4/O1CN016htnWH20c3gd2LpUR_!!6000000006869-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | Google Code | <img src="https://gw.alicdn.com/imgextra/i1/O1CN01Ng29ab23iQ2BuYKz8_!!6000000007289-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| GitHub | <img src="https://gw.alicdn.com/imgextra/i4/O1CN01fFCRda1IQIQ9qDNqv_!!6000000000887-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> | Xcode | <img src="https://gw.alicdn.com/imgextra/i1/O1CN010E3QAi1Huh5o1E9LN_!!6000000000818-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Dark Theme | Preview | Light Theme | Preview |
|
||||
| :----------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| ANSI | <img src="https://gw.alicdn.com/imgextra/i2/O1CN01ZInJiq1GdSZc9gHsI_!!6000000000645-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | ANSI Light | <img src="https://gw.alicdn.com/imgextra/i2/O1CN01IiJQFC1h9E3MXQj6W_!!6000000004234-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Atom OneDark | <img src="https://gw.alicdn.com/imgextra/i2/O1CN01Zlx1SO1Sw21SkTKV3_!!6000000002310-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | Ayu Light | <img src="https://gw.alicdn.com/imgextra/i3/O1CN01zEUc1V1jeUJsnCgQb_!!6000000004573-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Ayu | <img src="https://gw.alicdn.com/imgextra/i3/O1CN019upo6v1SmPhmRjzfN_!!6000000002289-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> | Default Light | <img src="https://gw.alicdn.com/imgextra/i4/O1CN01RHjrEs1u7TXq3M6l3_!!6000000005990-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Default | <img src="https://gw.alicdn.com/imgextra/i4/O1CN016pIeXz1pFC8owmR4Q_!!6000000005330-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | GitHub Light | <img src="https://gw.alicdn.com/imgextra/i4/O1CN01US2b0g1VETCPAVWLA_!!6000000002621-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| Dracula | <img src="https://gw.alicdn.com/imgextra/i4/O1CN016htnWH20c3gd2LpUR_!!6000000006869-2-tps-1140-934.png" style="zoom:30%;text-align:center;margin: 0 auto;" /> | Google Code | <img src="https://gw.alicdn.com/imgextra/i1/O1CN01Ng29ab23iQ2BuYKz8_!!6000000007289-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
| GitHub | <img src="https://gw.alicdn.com/imgextra/i4/O1CN01fFCRda1IQIQ9qDNqv_!!6000000000887-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> | Xcode | <img src="https://gw.alicdn.com/imgextra/i1/O1CN010E3QAi1Huh5o1E9LN_!!6000000000818-2-tps-1140-934.png" alt=" " style="zoom:30%;text-align:center;margin: 0 auto;" /> |
|
||||
|
||||
@@ -84,12 +84,12 @@ This guide provides solutions to common issues and debugging tips, including top
|
||||
|
||||
The Qwen Code uses specific exit codes to indicate the reason for termination. This is especially useful for scripting and automation.
|
||||
|
||||
| Exit Code | Error Type | Description |
|
||||
| --------- | -------------------------- | ------------------------------------------------------------ |
|
||||
| 41 | `FatalAuthenticationError` | An error occurred during the authentication process. |
|
||||
| 42 | `FatalInputError` | Invalid or missing input was provided to the CLI. (non-interactive mode only) |
|
||||
| 44 | `FatalSandboxError` | An error occurred with the sandboxing environment (e.g. Docker, Podman, or Seatbelt). |
|
||||
| 52 | `FatalConfigError` | A configuration file (`settings.json`) is invalid or contains errors. |
|
||||
| Exit Code | Error Type | Description |
|
||||
| --------- | -------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| 41 | `FatalAuthenticationError` | An error occurred during the authentication process. |
|
||||
| 42 | `FatalInputError` | Invalid or missing input was provided to the CLI. (non-interactive mode only) |
|
||||
| 44 | `FatalSandboxError` | An error occurred with the sandboxing environment (e.g. Docker, Podman, or Seatbelt). |
|
||||
| 52 | `FatalConfigError` | A configuration file (`settings.json`) is invalid or contains errors. |
|
||||
| 53 | `FatalTurnLimitedError` | The maximum number of conversational turns for the session was reached. (non-interactive mode only) |
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
14
package-lock.json
generated
14
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
@@ -17501,7 +17501,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"@google/genai": "1.16.0",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
@@ -17616,7 +17616,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@qwen-code/qwen-code-core",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@google/genai": "1.16.0",
|
||||
@@ -17757,7 +17757,7 @@
|
||||
},
|
||||
"packages/sdk-typescript": {
|
||||
"name": "@qwen-code/sdk",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.4"
|
||||
@@ -20186,7 +20186,7 @@
|
||||
},
|
||||
"packages/test-utils": {
|
||||
"name": "@qwen-code/qwen-code-test-utils",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
@@ -20198,7 +20198,7 @@
|
||||
},
|
||||
"packages/vscode-ide-companion": {
|
||||
"name": "qwen-code-vscode-ide-companion",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"license": "LICENSE",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.15.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
@@ -13,7 +13,7 @@
|
||||
"url": "git+https://github.com/QwenLM/qwen-code.git"
|
||||
},
|
||||
"config": {
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.5.0"
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.5.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env node scripts/start.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Qwen Code",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -33,7 +33,7 @@
|
||||
"dist"
|
||||
],
|
||||
"config": {
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.5.0"
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/genai": "1.16.0",
|
||||
|
||||
@@ -1002,6 +1002,7 @@ export async function loadCliConfig(
|
||||
enableToolOutputTruncation: settings.tools?.enableToolOutputTruncation,
|
||||
eventEmitter: appEvents,
|
||||
useSmartEdit: argv.useSmartEdit ?? settings.useSmartEdit,
|
||||
gitCoAuthor: settings.general?.gitCoAuthor,
|
||||
output: {
|
||||
format: outputSettingsFormat,
|
||||
},
|
||||
|
||||
@@ -581,7 +581,7 @@ function extensionConsentString(extensionConfig: ExtensionConfig): string {
|
||||
}
|
||||
if (extensionConfig.contextFileName) {
|
||||
output.push(
|
||||
`This extension will append info to your gemini.md context using ${extensionConfig.contextFileName}`,
|
||||
`This extension will append info to your QWEN.md context using ${extensionConfig.contextFileName}`,
|
||||
);
|
||||
}
|
||||
if (extensionConfig.excludeTools) {
|
||||
|
||||
@@ -147,6 +147,16 @@ const SETTINGS_SCHEMA = {
|
||||
description: 'Disable update notification prompts.',
|
||||
showInDialog: false,
|
||||
},
|
||||
gitCoAuthor: {
|
||||
type: 'boolean',
|
||||
label: 'Git Co-Author',
|
||||
category: 'General',
|
||||
requiresRestart: false,
|
||||
default: true,
|
||||
description:
|
||||
'Automatically add a Co-authored-by trailer to git commit messages when commits are made through Qwen Code.',
|
||||
showInDialog: false,
|
||||
},
|
||||
checkpointing: {
|
||||
type: 'object',
|
||||
label: 'Checkpointing',
|
||||
@@ -284,7 +294,7 @@ const SETTINGS_SCHEMA = {
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description:
|
||||
'Show Gemini CLI status and thoughts in the terminal window title',
|
||||
'Show Qwen Code status and thoughts in the terminal window title',
|
||||
showInDialog: true,
|
||||
},
|
||||
hideTips: {
|
||||
@@ -312,7 +322,7 @@ const SETTINGS_SCHEMA = {
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description:
|
||||
'Hide the context summary (GEMINI.md, MCP servers) above the input.',
|
||||
'Hide the context summary (QWEN.md, MCP servers) above the input.',
|
||||
showInDialog: true,
|
||||
},
|
||||
footer: {
|
||||
@@ -518,7 +528,7 @@ const SETTINGS_SCHEMA = {
|
||||
category: 'Model',
|
||||
requiresRestart: false,
|
||||
default: undefined as string | undefined,
|
||||
description: 'The Gemini model to use for conversations.',
|
||||
description: 'The model to use for conversations.',
|
||||
showInDialog: false,
|
||||
},
|
||||
maxSessionTurns: {
|
||||
|
||||
@@ -379,8 +379,8 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
// Set no relaunch in tests since process spawning causing issues in tests
|
||||
originalEnvNoRelaunch = process.env['GEMINI_CLI_NO_RELAUNCH'];
|
||||
process.env['GEMINI_CLI_NO_RELAUNCH'] = 'true';
|
||||
originalEnvNoRelaunch = process.env['QWEN_CODE_NO_RELAUNCH'];
|
||||
process.env['QWEN_CODE_NO_RELAUNCH'] = 'true';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if (!(process.stdin as any).setRawMode) {
|
||||
@@ -402,9 +402,9 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
afterEach(() => {
|
||||
// Restore original env variables
|
||||
if (originalEnvNoRelaunch !== undefined) {
|
||||
process.env['GEMINI_CLI_NO_RELAUNCH'] = originalEnvNoRelaunch;
|
||||
process.env['QWEN_CODE_NO_RELAUNCH'] = originalEnvNoRelaunch;
|
||||
} else {
|
||||
delete process.env['GEMINI_CLI_NO_RELAUNCH'];
|
||||
delete process.env['QWEN_CODE_NO_RELAUNCH'];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ function getNodeMemoryArgs(isDebugMode: boolean): string[] {
|
||||
);
|
||||
}
|
||||
|
||||
if (process.env['GEMINI_CLI_NO_RELAUNCH']) {
|
||||
if (process.env['QWEN_CODE_NO_RELAUNCH']) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -635,8 +635,8 @@ export default {
|
||||
'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.':
|
||||
'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.',
|
||||
"Error adding '{{path}}': {{error}}": "Error adding '{{path}}': {{error}}",
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}':
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}',
|
||||
'Successfully added QWEN.md files from the following directories if there are:\n- {{directories}}':
|
||||
'Successfully added QWEN.md files from the following directories if there are:\n- {{directories}}',
|
||||
'Error refreshing memory: {{error}}': 'Error refreshing memory: {{error}}',
|
||||
'Successfully added directories:\n- {{directories}}':
|
||||
'Successfully added directories:\n- {{directories}}',
|
||||
|
||||
@@ -601,8 +601,8 @@ export default {
|
||||
'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.':
|
||||
'/directory add 命令在限制性沙箱配置文件中不受支持。请改为在启动会话时使用 --include-directories。',
|
||||
"Error adding '{{path}}': {{error}}": "添加 '{{path}}' 时出错:{{error}}",
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}':
|
||||
'如果存在,已成功从以下目录添加 GEMINI.md 文件:\n- {{directories}}',
|
||||
'Successfully added QWEN.md files from the following directories if there are:\n- {{directories}}':
|
||||
'如果存在,已成功从以下目录添加 QWEN.md 文件:\n- {{directories}}',
|
||||
'Error refreshing memory: {{error}}': '刷新内存时出错:{{error}}',
|
||||
'Successfully added directories:\n- {{directories}}':
|
||||
'成功添加目录:\n- {{directories}}',
|
||||
|
||||
@@ -130,7 +130,7 @@ export const directoryCommand: SlashCommand = {
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: t(
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}',
|
||||
'Successfully added QWEN.md files from the following directories if there are:\n- {{directories}}',
|
||||
{
|
||||
directories: added.join('\n- '),
|
||||
},
|
||||
|
||||
@@ -89,7 +89,7 @@ describe('restoreCommand', () => {
|
||||
).toEqual({
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: 'Could not determine the .gemini directory path.',
|
||||
content: 'Could not determine the .qwen directory path.',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ async function restoreAction(
|
||||
return {
|
||||
type: 'message',
|
||||
messageType: 'error',
|
||||
content: 'Could not determine the .gemini directory path.',
|
||||
content: 'Could not determine the .qwen directory path.',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ export function PermissionsModifyTrustDialog({
|
||||
{needsRestart && (
|
||||
<Box marginLeft={1} marginTop={1}>
|
||||
<Text color={theme.status.warning}>
|
||||
To apply the trust changes, Gemini CLI must be restarted. Press
|
||||
To apply the trust changes, Qwen Code must be restarted. Press
|
||||
'r' to restart CLI now.
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
@@ -115,7 +115,7 @@ describe('relaunchAppInChildProcess', () => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
process.env = { ...originalEnv };
|
||||
delete process.env['GEMINI_CLI_NO_RELAUNCH'];
|
||||
delete process.env['QWEN_CODE_NO_RELAUNCH'];
|
||||
|
||||
process.execArgv = [...originalExecArgv];
|
||||
process.argv = [...originalArgv];
|
||||
@@ -145,9 +145,9 @@ describe('relaunchAppInChildProcess', () => {
|
||||
stdinResumeSpy.mockRestore();
|
||||
});
|
||||
|
||||
describe('when GEMINI_CLI_NO_RELAUNCH is set', () => {
|
||||
describe('when QWEN_CODE_NO_RELAUNCH is set', () => {
|
||||
it('should return early without spawning a child process', async () => {
|
||||
process.env['GEMINI_CLI_NO_RELAUNCH'] = 'true';
|
||||
process.env['QWEN_CODE_NO_RELAUNCH'] = 'true';
|
||||
|
||||
await relaunchAppInChildProcess(['--test'], ['--verbose']);
|
||||
|
||||
@@ -156,9 +156,9 @@ describe('relaunchAppInChildProcess', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when GEMINI_CLI_NO_RELAUNCH is not set', () => {
|
||||
describe('when QWEN_CODE_NO_RELAUNCH is not set', () => {
|
||||
beforeEach(() => {
|
||||
delete process.env['GEMINI_CLI_NO_RELAUNCH'];
|
||||
delete process.env['QWEN_CODE_NO_RELAUNCH'];
|
||||
});
|
||||
|
||||
it('should construct correct node arguments from execArgv, additionalNodeArgs, script, additionalScriptArgs, and argv', () => {
|
||||
|
||||
@@ -27,7 +27,7 @@ export async function relaunchAppInChildProcess(
|
||||
additionalNodeArgs: string[],
|
||||
additionalScriptArgs: string[],
|
||||
) {
|
||||
if (process.env['GEMINI_CLI_NO_RELAUNCH']) {
|
||||
if (process.env['QWEN_CODE_NO_RELAUNCH']) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export async function relaunchAppInChildProcess(
|
||||
...additionalScriptArgs,
|
||||
...scriptArgs,
|
||||
];
|
||||
const newEnv = { ...process.env, GEMINI_CLI_NO_RELAUNCH: 'true' };
|
||||
const newEnv = { ...process.env, QWEN_CODE_NO_RELAUNCH: 'true' };
|
||||
|
||||
// The parent process should not be reading from stdin while the child is running.
|
||||
process.stdin.pause();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code-core",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Qwen Code Core",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -287,7 +287,7 @@ export interface ConfigParameters {
|
||||
contextFileName?: string | string[];
|
||||
accessibility?: AccessibilitySettings;
|
||||
telemetry?: TelemetrySettings;
|
||||
gitCoAuthor?: GitCoAuthorSettings;
|
||||
gitCoAuthor?: boolean;
|
||||
usageStatisticsEnabled?: boolean;
|
||||
fileFiltering?: {
|
||||
respectGitIgnore?: boolean;
|
||||
@@ -534,9 +534,9 @@ export class Config {
|
||||
useCollector: params.telemetry?.useCollector,
|
||||
};
|
||||
this.gitCoAuthor = {
|
||||
enabled: params.gitCoAuthor?.enabled ?? true,
|
||||
name: params.gitCoAuthor?.name ?? 'Qwen-Coder',
|
||||
email: params.gitCoAuthor?.email ?? 'qwen-coder@alibabacloud.com',
|
||||
enabled: params.gitCoAuthor ?? true,
|
||||
name: 'Qwen-Coder',
|
||||
email: 'qwen-coder@alibabacloud.com',
|
||||
};
|
||||
this.usageStatisticsEnabled = params.usageStatisticsEnabled ?? true;
|
||||
|
||||
|
||||
@@ -151,8 +151,7 @@ describe('BaseLlmClient', () => {
|
||||
contents: defaultOptions.contents,
|
||||
config: {
|
||||
abortSignal: defaultOptions.abortSignal,
|
||||
temperature: 0,
|
||||
topP: 1,
|
||||
topP: 0.8,
|
||||
tools: [
|
||||
{
|
||||
functionDeclarations: [
|
||||
@@ -189,7 +188,7 @@ describe('BaseLlmClient', () => {
|
||||
expect.objectContaining({
|
||||
config: expect.objectContaining({
|
||||
temperature: 0.8,
|
||||
topP: 1, // Default should remain if not overridden
|
||||
topP: 0.8, // Default should remain if not overridden
|
||||
topK: 10,
|
||||
tools: expect.any(Array),
|
||||
}),
|
||||
|
||||
@@ -66,8 +66,7 @@ export interface GenerateJsonOptions {
|
||||
export class BaseLlmClient {
|
||||
// Default configuration for utility tasks
|
||||
private readonly defaultUtilityConfig: GenerateContentConfig = {
|
||||
temperature: 0,
|
||||
topP: 1,
|
||||
topP: 0.8,
|
||||
};
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -2310,7 +2310,7 @@ ${JSON.stringify(
|
||||
abortSignal,
|
||||
systemInstruction: getCoreSystemPrompt(''),
|
||||
temperature: 0.5,
|
||||
topP: 1,
|
||||
topP: 0.8,
|
||||
},
|
||||
contents,
|
||||
},
|
||||
|
||||
@@ -94,8 +94,7 @@ const MAX_TURNS = 100;
|
||||
export class GeminiClient {
|
||||
private chat?: GeminiChat;
|
||||
private readonly generateContentConfig: GenerateContentConfig = {
|
||||
temperature: 0,
|
||||
topP: 1,
|
||||
topP: 0.8,
|
||||
};
|
||||
private sessionTurnCount = 0;
|
||||
|
||||
|
||||
@@ -608,6 +608,36 @@ describe('ShellTool', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle git commit with combined short flags like -am', async () => {
|
||||
const command = 'git commit -am "Add feature"';
|
||||
const invocation = shellTool.build({ command, is_background: false });
|
||||
const promise = invocation.execute(mockAbortSignal);
|
||||
|
||||
resolveExecutionPromise({
|
||||
rawOutput: Buffer.from(''),
|
||||
output: '',
|
||||
exitCode: 0,
|
||||
signal: null,
|
||||
error: null,
|
||||
aborted: false,
|
||||
pid: 12345,
|
||||
executionMethod: 'child_process',
|
||||
});
|
||||
|
||||
await promise;
|
||||
|
||||
expect(mockShellExecutionService).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>',
|
||||
),
|
||||
expect.any(String),
|
||||
expect.any(Function),
|
||||
mockAbortSignal,
|
||||
false,
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('should not modify non-git commands', async () => {
|
||||
const command = 'npm install';
|
||||
const invocation = shellTool.build({ command, is_background: false });
|
||||
@@ -768,6 +798,69 @@ describe('ShellTool', () => {
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('should add co-author when git commit is prefixed with cd command', async () => {
|
||||
const command = 'cd /tmp/test && git commit -m "Test commit"';
|
||||
const invocation = shellTool.build({ command, is_background: false });
|
||||
const promise = invocation.execute(mockAbortSignal);
|
||||
|
||||
resolveExecutionPromise({
|
||||
rawOutput: Buffer.from(''),
|
||||
output: '',
|
||||
exitCode: 0,
|
||||
signal: null,
|
||||
error: null,
|
||||
aborted: false,
|
||||
pid: 12345,
|
||||
executionMethod: 'child_process',
|
||||
});
|
||||
|
||||
await promise;
|
||||
|
||||
expect(mockShellExecutionService).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>',
|
||||
),
|
||||
expect.any(String),
|
||||
expect.any(Function),
|
||||
mockAbortSignal,
|
||||
false,
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('should add co-author to git commit with multi-line message', async () => {
|
||||
const command = `git commit -m "Fix bug
|
||||
|
||||
This is a detailed description
|
||||
spanning multiple lines"`;
|
||||
const invocation = shellTool.build({ command, is_background: false });
|
||||
const promise = invocation.execute(mockAbortSignal);
|
||||
|
||||
resolveExecutionPromise({
|
||||
rawOutput: Buffer.from(''),
|
||||
output: '',
|
||||
exitCode: 0,
|
||||
signal: null,
|
||||
error: null,
|
||||
aborted: false,
|
||||
pid: 12345,
|
||||
executionMethod: 'child_process',
|
||||
});
|
||||
|
||||
await promise;
|
||||
|
||||
expect(mockShellExecutionService).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>',
|
||||
),
|
||||
expect.any(String),
|
||||
expect.any(Function),
|
||||
mockAbortSignal,
|
||||
false,
|
||||
{},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -334,13 +334,14 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
||||
private addCoAuthorToGitCommit(command: string): string {
|
||||
// Check if co-author feature is enabled
|
||||
const gitCoAuthorSettings = this.config.getGitCoAuthor();
|
||||
|
||||
if (!gitCoAuthorSettings.enabled) {
|
||||
return command;
|
||||
}
|
||||
|
||||
// Check if this is a git commit command
|
||||
const gitCommitPattern = /^git\s+commit/;
|
||||
if (!gitCommitPattern.test(command.trim())) {
|
||||
// Check if this is a git commit command (anywhere in the command, e.g., after "cd /path &&")
|
||||
const gitCommitPattern = /\bgit\s+commit\b/;
|
||||
if (!gitCommitPattern.test(command)) {
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -349,15 +350,27 @@ export class ShellToolInvocation extends BaseToolInvocation<
|
||||
|
||||
Co-authored-by: ${gitCoAuthorSettings.name} <${gitCoAuthorSettings.email}>`;
|
||||
|
||||
// Handle different git commit patterns
|
||||
// Match -m "message" or -m 'message'
|
||||
const messagePattern = /(-m\s+)(['"])((?:\\.|[^\\])*?)(\2)/;
|
||||
const match = command.match(messagePattern);
|
||||
// Handle different git commit patterns:
|
||||
// Match -m "message" or -m 'message', including combined flags like -am
|
||||
// Use separate patterns to avoid ReDoS (catastrophic backtracking)
|
||||
//
|
||||
// Pattern breakdown:
|
||||
// -[a-zA-Z]*m matches -m, -am, -nm, etc. (combined short flags)
|
||||
// \s+ matches whitespace after the flag
|
||||
// [^"\\] matches any char except double-quote and backslash
|
||||
// \\. matches escape sequences like \" or \\
|
||||
// (?:...|...)* matches normal chars or escapes, repeated
|
||||
const doubleQuotePattern = /(-[a-zA-Z]*m\s+)"((?:[^"\\]|\\.)*)"/;
|
||||
const singleQuotePattern = /(-[a-zA-Z]*m\s+)'((?:[^'\\]|\\.)*)'/;
|
||||
const doubleMatch = command.match(doubleQuotePattern);
|
||||
const singleMatch = command.match(singleQuotePattern);
|
||||
const match = doubleMatch ?? singleMatch;
|
||||
const quote = doubleMatch ? '"' : "'";
|
||||
|
||||
if (match) {
|
||||
const [fullMatch, prefix, quote, existingMessage, closingQuote] = match;
|
||||
const [fullMatch, prefix, existingMessage] = match;
|
||||
const newMessage = existingMessage + coAuthor;
|
||||
const replacement = prefix + quote + newMessage + closingQuote;
|
||||
const replacement = prefix + quote + newMessage + quote;
|
||||
|
||||
return command.replace(fullMatch, replacement);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/sdk",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "TypeScript SDK for programmatic access to qwen-code CLI",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code-test-utils",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"main": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "qwen-code-vscode-ide-companion",
|
||||
"displayName": "Qwen Code Companion",
|
||||
"description": "Enable Qwen Code with direct access to your VS Code workspace.",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"publisher": "qwenlm",
|
||||
"icon": "assets/icon.png",
|
||||
"repository": {
|
||||
|
||||
@@ -67,7 +67,7 @@ const env = {
|
||||
if (process.env.DEBUG) {
|
||||
// If this is not set, the debugger will pause on the outer process rather
|
||||
// than the relaunched process making it harder to debug.
|
||||
env.GEMINI_CLI_NO_RELAUNCH = 'true';
|
||||
env.QWEN_CODE_NO_RELAUNCH = 'true';
|
||||
}
|
||||
// Use process.cwd() to inherit the working directory from launch.json cwd setting
|
||||
// This allows debugging from a specific directory (e.g., .todo)
|
||||
|
||||
Reference in New Issue
Block a user