diff --git a/docs/users/configuration/settings.md b/docs/users/configuration/settings.md index 58f0543ef..76ab870ad 100644 --- a/docs/users/configuration/settings.md +++ b/docs/users/configuration/settings.md @@ -275,6 +275,7 @@ If you are experiencing performance issues with file searching (e.g., with `@` c | `tools.truncateToolOutputThreshold` | number | Truncate tool output if it is larger than this many characters. Applies to Shell, Grep, Glob, ReadFile and ReadManyFiles tools. | `25000` | Requires restart: Yes | | `tools.truncateToolOutputLines` | number | Maximum lines or entries kept when truncating tool output. Applies to Shell, Grep, Glob, ReadFile and ReadManyFiles tools. | `1000` | Requires restart: Yes | | `tools.autoAccept` | boolean | Controls whether the CLI automatically accepts and executes tool calls that are considered safe (e.g., read-only operations) without explicit user confirmation. If set to `true`, the CLI will bypass the confirmation prompt for tools deemed safe. | `false` | | +| `tools.experimental.skills` | boolean | Enable experimental Agent Skills feature | `false` | | #### mcp diff --git a/docs/users/features/skills.md b/docs/users/features/skills.md index 0387ff389..0e55644ab 100644 --- a/docs/users/features/skills.md +++ b/docs/users/features/skills.md @@ -11,12 +11,29 @@ This guide shows you how to create, use, and manage Agent Skills in **Qwen Code* ## Prerequisites - Qwen Code (recent version) -- Run with the experimental flag enabled: + +## How to enable + +### Via CLI flag ```bash qwen --experimental-skills ``` +### Via settings.json + +Add to your `~/.qwen/settings.json` or project's `.qwen/settings.json`: + +```json +{ + "tools": { + "experimental": { + "skills": true + } + } +} +``` + - Basic familiarity with Qwen Code ([Quickstart](../quickstart.md)) ## What are Agent Skills? diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 8dd09a238..da88654d2 100755 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -334,7 +334,7 @@ export async function parseArguments(settings: Settings): Promise { .option('experimental-skills', { type: 'boolean', description: 'Enable experimental Skills feature', - default: false, + default: settings.tools?.experimental?.skills ?? false, }) .option('channel', { type: 'string', @@ -874,11 +874,10 @@ export async function loadCliConfig( } }; - if ( - !interactive && - !argv.experimentalAcp && - inputFormat !== InputFormat.STREAM_JSON - ) { + // ACP mode check: must include both --acp (current) and --experimental-acp (deprecated). + // Without this check, edit, write_file, run_shell_command would be excluded in ACP mode. + const isAcpMode = argv.acp || argv.experimentalAcp; + if (!interactive && !isAcpMode && inputFormat !== InputFormat.STREAM_JSON) { switch (approvalMode) { case ApprovalMode.PLAN: case ApprovalMode.DEFAULT: diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 74b63a7b9..c98c79ffd 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -981,6 +981,27 @@ const SETTINGS_SCHEMA = { description: 'The number of lines to keep when truncating tool output.', showInDialog: true, }, + experimental: { + type: 'object', + label: 'Experimental', + category: 'Tools', + requiresRestart: true, + default: {}, + description: 'Experimental tool features.', + showInDialog: false, + properties: { + skills: { + type: 'boolean', + label: 'Skills', + category: 'Tools', + requiresRestart: true, + default: false, + description: + 'Enable experimental Agent Skills feature. When enabled, Qwen Code can use Skills from .qwen/skills/ and ~/.qwen/skills/.', + showInDialog: true, + }, + }, + }, }, }, diff --git a/packages/cli/src/i18n/locales/zh.js b/packages/cli/src/i18n/locales/zh.js index a1b9c2033..199ea572b 100644 --- a/packages/cli/src/i18n/locales/zh.js +++ b/packages/cli/src/i18n/locales/zh.js @@ -873,11 +873,11 @@ export default { 'Session Stats': '会话统计', 'Model Usage': '模型使用情况', Reqs: '请求数', - 'Input Tokens': '输入令牌', - 'Output Tokens': '输出令牌', + 'Input Tokens': '输入 token 数', + 'Output Tokens': '输出 token 数', 'Savings Highlight:': '节省亮点:', 'of input tokens were served from the cache, reducing costs.': - '的输入令牌来自缓存,降低了成本', + '从缓存载入 token ,降低了成本', 'Tip: For a full token breakdown, run `/stats model`.': '提示:要查看完整的令牌明细,请运行 `/stats model`', 'Model Stats For Nerds': '模型统计(技术细节)', diff --git a/packages/cli/src/utils/commentJson.test.ts b/packages/cli/src/utils/commentJson.test.ts index 4957b7497..fcf2501cd 100644 --- a/packages/cli/src/utils/commentJson.test.ts +++ b/packages/cli/src/utils/commentJson.test.ts @@ -8,7 +8,10 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import * as fs from 'node:fs'; import * as path from 'node:path'; import * as os from 'node:os'; -import { updateSettingsFilePreservingFormat } from './commentJson.js'; +import { + updateSettingsFilePreservingFormat, + applyUpdates, +} from './commentJson.js'; describe('commentJson', () => { let tempDir: string; @@ -180,3 +183,18 @@ describe('commentJson', () => { }); }); }); + +describe('applyUpdates', () => { + it('should apply updates correctly', () => { + const original = { a: 1, b: { c: 2 } }; + const updates = { b: { c: 3 } }; + const result = applyUpdates(original, updates); + expect(result).toEqual({ a: 1, b: { c: 3 } }); + }); + it('should apply updates correctly when empty', () => { + const original = { a: 1, b: { c: 2 } }; + const updates = { b: {} }; + const result = applyUpdates(original, updates); + expect(result).toEqual({ a: 1, b: {} }); + }); +}); diff --git a/packages/cli/src/utils/commentJson.ts b/packages/cli/src/utils/commentJson.ts index 9ea4d3f80..bf325d9af 100644 --- a/packages/cli/src/utils/commentJson.ts +++ b/packages/cli/src/utils/commentJson.ts @@ -38,7 +38,7 @@ export function updateSettingsFilePreservingFormat( fs.writeFileSync(filePath, updatedContent, 'utf-8'); } -function applyUpdates( +export function applyUpdates( current: Record, updates: Record, ): Record { @@ -50,6 +50,7 @@ function applyUpdates( typeof value === 'object' && value !== null && !Array.isArray(value) && + Object.keys(value).length > 0 && typeof result[key] === 'object' && result[key] !== null && !Array.isArray(result[key]) diff --git a/packages/vscode-ide-companion/README.md b/packages/vscode-ide-companion/README.md index 55f7da323..92eb830a6 100644 --- a/packages/vscode-ide-companion/README.md +++ b/packages/vscode-ide-companion/README.md @@ -1,6 +1,11 @@ # Qwen Code Companion -Seamlessly integrate [Qwen Code](https://github.com/QwenLM/qwen-code) into Visual Studio Code with native IDE features and an intuitive interface. This extension bundles everything you need to get started immediately. +[![Version](https://img.shields.io/visual-studio-marketplace/v/qwenlm.qwen-code-vscode-ide-companion)](https://marketplace.visualstudio.com/items?itemName=qwenlm.qwen-code-vscode-ide-companion) +[![VS Code Installs](https://img.shields.io/visual-studio-marketplace/i/qwenlm.qwen-code-vscode-ide-companion)](https://marketplace.visualstudio.com/items?itemName=qwenlm.qwen-code-vscode-ide-companion) +[![Open VSX Downloads](https://img.shields.io/open-vsx/dt/qwenlm/qwen-code-vscode-ide-companion)](https://open-vsx.org/extension/qwenlm/qwen-code-vscode-ide-companion) +[![Rating](https://img.shields.io/visual-studio-marketplace/r/qwenlm.qwen-code-vscode-ide-companion)](https://marketplace.visualstudio.com/items?itemName=qwenlm.qwen-code-vscode-ide-companion) + +Seamlessly integrate [Qwen Code](https://github.com/QwenLM/qwen-code) into Visual Studio Code with native IDE features and an intuitive chat interface. This extension bundles everything you need — no additional installation required. ## Demo @@ -11,7 +16,7 @@ Seamlessly integrate [Qwen Code](https://github.com/QwenLM/qwen-code) into Visua ## Features -- **Native IDE experience**: Dedicated Qwen Code sidebar panel accessed via the Qwen icon +- **Native IDE experience**: Dedicated Qwen Code Chat panel accessed via the Qwen icon in the editor title bar - **Native diffing**: Review, edit, and accept changes in VS Code's diff view - **Auto-accept edits mode**: Automatically apply Qwen's changes as they're made - **File management**: @-mention files or attach files and images using the system file picker @@ -20,73 +25,46 @@ Seamlessly integrate [Qwen Code](https://github.com/QwenLM/qwen-code) into Visua ## Requirements -- Visual Studio Code 1.85.0 or newer +- Visual Studio Code 1.85.0 or newer (also works with Cursor, Windsurf, and other VS Code-based editors) -## Installation +## Quick Start -1. Install from the VS Code Marketplace: https://marketplace.visualstudio.com/items?itemName=qwenlm.qwen-code-vscode-ide-companion +1. **Install** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=qwenlm.qwen-code-vscode-ide-companion) or [Open VSX Registry](https://open-vsx.org/extension/qwenlm/qwen-code-vscode-ide-companion) -2. Two ways to use - - Chat panel: Click the Qwen icon in the Activity Bar, or run `Qwen Code: Open` from the Command Palette (`Cmd+Shift+P` / `Ctrl+Shift+P`). - - Terminal session (classic): Run `Qwen Code: Run` to launch a session in the integrated terminal (bundled CLI). +2. **Open the Chat panel** using one of these methods: + - Click the **Qwen icon** in the top-right corner of the editor + - Run `Qwen Code: Open` from the Command Palette (`Cmd+Shift+P` / `Ctrl+Shift+P`) -## Development and Debugging +3. **Start chatting** — Ask Qwen to help with coding tasks, explain code, fix bugs, or write new features -To debug and develop this extension locally: +## Commands -1. **Clone the repository** +| Command | Description | +| -------------------------------- | ------------------------------------------------------ | +| `Qwen Code: Open` | Open the Qwen Code Chat panel | +| `Qwen Code: Run` | Launch a classic terminal session with the bundled CLI | +| `Qwen Code: Accept Current Diff` | Accept the currently displayed diff | +| `Qwen Code: Close Diff Editor` | Close/reject the current diff | - ```bash - git clone https://github.com/QwenLM/qwen-code.git - cd qwen-code - ``` +## Feedback & Issues -2. **Install dependencies** +- 🐛 [Report bugs](https://github.com/QwenLM/qwen-code/issues/new?template=bug_report.yml&labels=bug,vscode-ide-companion) +- 💡 [Request features](https://github.com/QwenLM/qwen-code/issues/new?template=feature_request.yml&labels=enhancement,vscode-ide-companion) +- 📖 [Documentation](https://qwenlm.github.io/qwen-code-docs/) +- 📋 [Changelog](https://github.com/QwenLM/qwen-code/releases) - ```bash - npm install - # or if using pnpm - pnpm install - ``` +## Contributing -3. **Start debugging** +We welcome contributions! See our [Contributing Guide](https://github.com/QwenLM/qwen-code/blob/main/CONTRIBUTING.md) for details on: - ```bash - code . # Open the project root in VS Code - ``` - - Open the `packages/vscode-ide-companion/src/extension.ts` file - - Open Debug panel (`Ctrl+Shift+D` or `Cmd+Shift+D`) - - Select **"Launch Companion VS Code Extension"** from the debug dropdown - - Press `F5` to launch Extension Development Host - -4. **Make changes and reload** - - Edit the source code in the original VS Code window - - To see your changes, reload the Extension Development Host window by: - - Pressing `Ctrl+R` (Windows/Linux) or `Cmd+R` (macOS) - - Or clicking the "Reload" button in the debug toolbar - -5. **View logs and debug output** - - Open the Debug Console in the original VS Code window to see extension logs - - In the Extension Development Host window, open Developer Tools with `Help > Toggle Developer Tools` to see webview logs - -## Build for Production - -To build the extension for distribution: - -```bash -npm run compile -# or -pnpm run compile -``` - -To package the extension as a VSIX file: - -```bash -npx vsce package -# or -pnpm vsce package -``` +- Setting up the development environment +- Building and debugging the extension locally +- Submitting pull requests ## Terms of Service and Privacy Notice By installing this extension, you agree to the [Terms of Service](https://github.com/QwenLM/qwen-code/blob/main/docs/tos-privacy.md). + +## License + +[Apache-2.0](https://github.com/QwenLM/qwen-code/blob/main/LICENSE) diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index be0f669e6..14ff4bcae 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -314,34 +314,32 @@ export async function activate(context: vscode.ExtensionContext) { 'cli.js', ).fsPath; const execPath = process.execPath; - const lowerExecPath = execPath.toLowerCase(); - const needsElectronRunAsNode = - lowerExecPath.includes('code') || - lowerExecPath.includes('electron'); - let qwenCmd: string; const terminalOptions: vscode.TerminalOptions = { name: `Qwen Code (${selectedFolder.name})`, cwd: selectedFolder.uri.fsPath, location, }; + let qwenCmd: string; + if (isWindows) { - // Use system Node via cmd.exe; avoid PowerShell parsing issues + // On Windows, try multiple strategies to find a Node.js runtime: + // 1. Check if VSCode ships a standalone node.exe alongside Code.exe + // 2. Check VSCode's internal Node.js in resources directory + // 3. Fall back to using Code.exe with ELECTRON_RUN_AS_NODE=1 const quoteCmd = (s: string) => `"${s.replace(/"/g, '""')}"`; const cliQuoted = quoteCmd(cliEntry); // TODO: @yiliang114, temporarily run through node, and later hope to decouple from the local node qwenCmd = `node ${cliQuoted}`; terminalOptions.shellPath = process.env.ComSpec; } else { + // macOS/Linux: All VSCode-like IDEs (VSCode, Cursor, Windsurf, etc.) + // are Electron-based, so we always need ELECTRON_RUN_AS_NODE=1 + // to run Node.js scripts using the IDE's bundled runtime. const quotePosix = (s: string) => `"${s.replace(/"/g, '\\"')}"`; const baseCmd = `${quotePosix(execPath)} ${quotePosix(cliEntry)}`; - if (needsElectronRunAsNode) { - // macOS Electron helper needs ELECTRON_RUN_AS_NODE=1; - qwenCmd = `ELECTRON_RUN_AS_NODE=1 ${baseCmd}`; - } else { - qwenCmd = baseCmd; - } + qwenCmd = `ELECTRON_RUN_AS_NODE=1 ${baseCmd}`; } const terminal = vscode.window.createTerminal(terminalOptions);