@qwen-code/qwen-code 0.15.11 → 0.15.12-preview.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/bundled/qc-helper/docs/_meta.ts +2 -1
- package/bundled/qc-helper/docs/configuration/settings.md +6 -1
- package/bundled/qc-helper/docs/features/commands.md +5 -6
- package/bundled/qc-helper/docs/features/hooks.md +299 -1
- package/bundled/qc-helper/docs/features/language.md +23 -16
- package/bundled/qc-helper/docs/features/mcp.md +56 -0
- package/bundled/qc-helper/docs/qwen-serve.md +276 -0
- package/cli.js +46120 -27027
- package/locales/ca.js +0 -20
- package/locales/de.js +14 -19
- package/locales/en.js +13 -19
- package/locales/fr.js +13 -19
- package/locales/ja.js +12 -19
- package/locales/pt.js +13 -19
- package/locales/ru.js +13 -19
- package/locales/zh-TW.js +159 -164
- package/locales/zh.js +17 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -428,12 +428,13 @@ and adjust it to the context length configured on your local server.
|
|
|
428
428
|
|
|
429
429
|
## Usage
|
|
430
430
|
|
|
431
|
-
As an open-source terminal agent, you can use Qwen Code in
|
|
431
|
+
As an open-source terminal agent, you can use Qwen Code in five primary ways:
|
|
432
432
|
|
|
433
433
|
1. Interactive mode (terminal UI)
|
|
434
434
|
2. Headless mode (scripts, CI)
|
|
435
435
|
3. IDE integration (VS Code, Zed)
|
|
436
436
|
4. SDKs (TypeScript, Python, Java)
|
|
437
|
+
5. Daemon mode — `qwen serve` exposes ACP over HTTP+SSE so multiple clients share one agent (experimental)
|
|
437
438
|
|
|
438
439
|
#### Interactive mode
|
|
439
440
|
|
|
@@ -461,6 +462,20 @@ Use Qwen Code inside your editor (VS Code, Zed, and JetBrains IDEs):
|
|
|
461
462
|
- [Use in Zed](https://qwenlm.github.io/qwen-code-docs/en/users/integration-zed/)
|
|
462
463
|
- [Use in JetBrains IDEs](https://qwenlm.github.io/qwen-code-docs/en/users/integration-jetbrains/)
|
|
463
464
|
|
|
465
|
+
#### Daemon mode (`qwen serve`, experimental)
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
cd your-project/
|
|
469
|
+
qwen serve
|
|
470
|
+
# → qwen serve listening on http://127.0.0.1:4170 (mode=http-bridge)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
Run Qwen Code as a local HTTP daemon so IDE plugins, web UIs, CI scripts and custom CLIs all share **one** agent session over HTTP+SSE — instead of each spawning their own subprocess. Loopback bind has no auth by default (set `QWEN_SERVER_TOKEN` to enable bearer auth even on loopback); remote binds (`--hostname 0.0.0.0`) **require** a token — boot refuses without one. See:
|
|
474
|
+
|
|
475
|
+
- [Daemon mode user guide](https://qwenlm.github.io/qwen-code-docs/en/users/qwen-serve)
|
|
476
|
+
- [HTTP protocol reference](https://qwenlm.github.io/qwen-code-docs/en/developers/qwen-serve-protocol)
|
|
477
|
+
- [DaemonClient TypeScript quickstart](https://qwenlm.github.io/qwen-code-docs/en/developers/examples/daemon-client-quickstart)
|
|
478
|
+
|
|
464
479
|
#### SDKs
|
|
465
480
|
|
|
466
481
|
Build on top of Qwen Code with the available SDKs:
|
|
@@ -13,7 +13,8 @@ export default {
|
|
|
13
13
|
'integration-vscode': 'Visual Studio Code',
|
|
14
14
|
'integration-zed': 'Zed IDE',
|
|
15
15
|
'integration-jetbrains': 'JetBrains IDEs',
|
|
16
|
-
'integration-github-action': '
|
|
16
|
+
'integration-github-action': 'GitHub Actions',
|
|
17
|
+
'qwen-serve': 'Daemon mode (qwen serve)',
|
|
17
18
|
'Code with Qwen Code': {
|
|
18
19
|
type: 'separator',
|
|
19
20
|
title: 'Code with Qwen Code', // Title is optional
|
|
@@ -583,11 +583,16 @@ For authentication-related variables (like `OPENAI_*`) and the recommended `.qwe
|
|
|
583
583
|
| `SEATBELT_PROFILE` | (macOS specific) Switches the Seatbelt (`sandbox-exec`) profile on macOS. | `permissive-open`: (Default) Restricts writes to the project folder (and a few other folders, see `packages/cli/src/utils/sandbox-macos-permissive-open.sb`) but allows other operations. `strict`: Uses a strict profile that declines operations by default. `<profile_name>`: Uses a custom profile. To define a custom profile, create a file named `sandbox-macos-<profile_name>.sb` in your project's `.qwen/` directory (e.g., `my-project/.qwen/sandbox-macos-custom.sb`). |
|
|
584
584
|
| `DEBUG` or `DEBUG_MODE` | (often used by underlying libraries or the CLI itself) Set to `true` or `1` to enable verbose debug logging, which can be helpful for troubleshooting. | **Note:** These variables are automatically excluded from project `.env` files by default to prevent interference with the CLI behavior. Use `.qwen/.env` files if you need to set these for Qwen Code specifically. |
|
|
585
585
|
| `NO_COLOR` | Set to any value to disable all color output in the CLI. | |
|
|
586
|
+
| `FORCE_HYPERLINK` | Override the OSC 8 clickable-link detection in the markdown renderer. Set to `1` (or any non-zero value, or empty string) to force-enable, `0` to force-disable. Honors `NO_COLOR` / `QWEN_DISABLE_HYPERLINKS` opt-outs above it. | Use this to opt into OSC 8 inside `tmux` / GNU `screen` (auto-detection refuses by default because the host terminal's capabilities are hidden behind the multiplexer). Requires `set -g allow-passthrough on` on tmux 3.3+. Also enables Hyper, which isn't auto-detected. |
|
|
587
|
+
| `QWEN_DISABLE_HYPERLINKS` | Set to `1` to hard-disable OSC 8 clickable hyperlinks in the markdown renderer even on terminals that auto-detect as capable. | Useful when a terminal advertises support but breaks on long URLs, or when piping output through an intermediary that mangles escape sequences. The renderer falls back to plain `label (url)` rendering. |
|
|
586
588
|
| `CLI_TITLE` | Set to a string to customize the title of the CLI. | |
|
|
587
589
|
| `CODE_ASSIST_ENDPOINT` | Specifies the endpoint for the code assist server. | This is useful for development and testing. |
|
|
588
590
|
| `QWEN_CODE_MAX_OUTPUT_TOKENS` | Overrides the default maximum output tokens per response. When not set, Qwen Code uses an adaptive strategy: starts with 8K tokens and automatically retries with 64K if the response is truncated. Set this to a specific value (e.g., `16000`) to use a fixed limit instead. | Takes precedence over the capped default (8K) but is overridden by `samplingParams.max_tokens` in settings. Disables automatic escalation when set. Example: `export QWEN_CODE_MAX_OUTPUT_TOKENS=16000` |
|
|
589
591
|
| `QWEN_CODE_UNATTENDED_RETRY` | Set to `true` or `1` to enable persistent retry mode. When enabled, transient API capacity errors (HTTP 429 Rate Limit and 529 Overloaded) are retried indefinitely with exponential backoff (capped at 5 minutes per retry) and heartbeat keepalives every 30 seconds on stderr. | Designed for CI/CD pipelines and background automation where long-running tasks should survive temporary API outages. Must be set explicitly — `CI=true` alone does **not** activate this mode. See [Headless Mode](../features/headless#persistent-retry-mode) for details. Example: `export QWEN_CODE_UNATTENDED_RETRY=1` |
|
|
590
|
-
| `QWEN_CODE_PROFILE_STARTUP` | Set to `1` to enable startup performance profiling. Writes a JSON timing report to `~/.qwen/startup-perf/` with per-phase durations. | Only active inside the sandbox child process. Zero overhead when not set. Example: `export QWEN_CODE_PROFILE_STARTUP=1`
|
|
592
|
+
| `QWEN_CODE_PROFILE_STARTUP` | Set to `1` to enable startup performance profiling. Writes a JSON timing report to `~/.qwen/startup-perf/` with per-phase durations. | Only active inside the sandbox child process (or with `QWEN_CODE_PROFILE_STARTUP_OUTER=1`). Zero overhead when not set. Example: `export QWEN_CODE_PROFILE_STARTUP=1` |
|
|
593
|
+
| `QWEN_CODE_PROFILE_STARTUP_OUTER` | Set to `1` together with `QWEN_CODE_PROFILE_STARTUP=1` to also collect a startup profile in the outer (pre-sandbox) process. Outer-process reports get an `outer-` filename prefix to keep them distinct from the sandbox child's report. | Off by default — only the sandbox child collects, to avoid duplicate reports. Useful for local development where the cli isn't relaunched into a sandbox. |
|
|
594
|
+
| `QWEN_CODE_PROFILE_STARTUP_NO_HEAP` | Set to `1` together with `QWEN_CODE_PROFILE_STARTUP=1` to skip the per-checkpoint `process.memoryUsage()` snapshots. Useful when measuring the profiler's own Heisenberg overhead. | Off by default. Heap snapshots cost ~50 µs each (well below 1% of total startup) so most users should leave this alone. |
|
|
595
|
+
| `QWEN_CODE_LEGACY_MCP_BLOCKING` | Set to `1` to restore the pre-progressive-MCP behavior where `Config.initialize()` waits synchronously for every configured MCP server's discover handshake before returning. | Off by default. Modern qwen-code lets MCP servers come online in the background while the UI is already interactive; the model sees each batch of new tools within ~16 ms of the server settling. This flag is kept as a rollback escape hatch for ≥ 1 release. Example: `export QWEN_CODE_LEGACY_MCP_BLOCKING=1` |
|
|
591
596
|
|
|
592
597
|
When both user-level `.env` files define the same variable, the Qwen-specific
|
|
593
598
|
file wins: `<QWEN_HOME>/.env` (or `~/.qwen/.env` when `QWEN_HOME` is unset) is
|
|
@@ -45,12 +45,11 @@ Commands for adjusting interface appearance and work environment.
|
|
|
45
45
|
|
|
46
46
|
Commands specifically for controlling interface and output language.
|
|
47
47
|
|
|
48
|
-
| Command | Description
|
|
49
|
-
| --------------------- |
|
|
50
|
-
| `/language` | View or change language settings
|
|
51
|
-
| → `ui [language]` | Set UI interface language
|
|
52
|
-
| → `output [language]` | Set LLM output language
|
|
53
|
-
| → `translate on/off` | Toggle AI translation for dynamic slash command descriptions (default: off) | `/language translate on` |
|
|
48
|
+
| Command | Description | Usage Examples |
|
|
49
|
+
| --------------------- | -------------------------------- | -------------------------- |
|
|
50
|
+
| `/language` | View or change language settings | `/language` |
|
|
51
|
+
| → `ui [language]` | Set UI interface language | `/language ui zh-CN` |
|
|
52
|
+
| → `output [language]` | Set LLM output language | `/language output Chinese` |
|
|
54
53
|
|
|
55
54
|
- Available built-in UI languages: `zh-CN` (Simplified Chinese), `en-US` (English), `ru-RU` (Russian), `de-DE` (German), `ja-JP` (Japanese), `pt-BR` (Portuguese - Brazil), `fr-FR` (French), `ca-ES` (Catalan)
|
|
56
55
|
- Output language examples: `Chinese`, `English`, `Japanese`, etc.
|
|
@@ -30,13 +30,14 @@ Hooks are user-defined scripts or programs that are automatically executed by Qw
|
|
|
30
30
|
|
|
31
31
|
## Hook Types
|
|
32
32
|
|
|
33
|
-
Qwen Code supports
|
|
33
|
+
Qwen Code supports four hook executor types:
|
|
34
34
|
|
|
35
35
|
| Type | Description |
|
|
36
36
|
| :--------- | :--------------------------------------------------------------------------------------------- |
|
|
37
37
|
| `command` | Execute a shell command. Receives JSON via `stdin`, returns results via `stdout`. |
|
|
38
38
|
| `http` | Send JSON as a `POST` request body to a specified URL. Returns results via HTTP response body. |
|
|
39
39
|
| `function` | Directly call a registered JavaScript function (session-level hooks only). |
|
|
40
|
+
| `prompt` | Use an LLM to evaluate hook input and return a decision. |
|
|
40
41
|
|
|
41
42
|
### Command Hooks
|
|
42
43
|
|
|
@@ -134,6 +135,102 @@ Function hooks directly call registered JavaScript/TypeScript functions. They ar
|
|
|
134
135
|
|
|
135
136
|
**Note**: For most use cases, use **command hooks** or **HTTP hooks** instead, which can be configured in settings files.
|
|
136
137
|
|
|
138
|
+
### Prompt Hooks
|
|
139
|
+
|
|
140
|
+
Prompt hooks use an LLM to evaluate hook input and return a decision. This is useful for making intelligent decisions based on context, such as determining whether to allow or block an operation.
|
|
141
|
+
|
|
142
|
+
**How it works:**
|
|
143
|
+
|
|
144
|
+
1. The hook input JSON is injected into your prompt using the `$ARGUMENTS` placeholder
|
|
145
|
+
2. The prompt is sent to an LLM (default: your current model)
|
|
146
|
+
3. The LLM returns a JSON response with the decision
|
|
147
|
+
4. Qwen Code processes the decision and continues or blocks execution accordingly
|
|
148
|
+
|
|
149
|
+
**Configuration:**
|
|
150
|
+
|
|
151
|
+
| Field | Type | Required | Description |
|
|
152
|
+
| :-------------- | :--------- | :------- | :-------------------------------------------------- |
|
|
153
|
+
| `type` | `"prompt"` | Yes | Hook type |
|
|
154
|
+
| `prompt` | `string` | Yes | Prompt sent to LLM. Use `$ARGUMENTS` for hook input |
|
|
155
|
+
| `model` | `string` | No | Model to use (defaults to your current model) |
|
|
156
|
+
| `timeout` | `number` | No | Timeout in seconds, default 30 |
|
|
157
|
+
| `name` | `string` | No | Hook name (for logging) |
|
|
158
|
+
| `description` | `string` | No | Hook description |
|
|
159
|
+
| `statusMessage` | `string` | No | Status message displayed during execution |
|
|
160
|
+
|
|
161
|
+
**Response Format:**
|
|
162
|
+
|
|
163
|
+
The LLM must return JSON with the following structure:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"ok": true,
|
|
168
|
+
"reason": "Explanation of the decision",
|
|
169
|
+
"additionalContext": "Optional context to inject into the conversation"
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
| Field | Description |
|
|
174
|
+
| :------------------ | :------------------------------------------------------------------------- |
|
|
175
|
+
| `ok` | `true` to allow/continue, `false` to block/stop |
|
|
176
|
+
| `reason` | Required when `ok` is `false`. Shown to the model to explain the block |
|
|
177
|
+
| `additionalContext` | Optional. Additional context to inject into the conversation when allowing |
|
|
178
|
+
|
|
179
|
+
**Supported Events:**
|
|
180
|
+
|
|
181
|
+
Prompt hooks can be used with most hook events, including:
|
|
182
|
+
|
|
183
|
+
- `PreToolUse` - Evaluate whether to allow a tool call
|
|
184
|
+
- `PostToolUse` - Evaluate tool results and potentially inject context
|
|
185
|
+
- `Stop` - Determine whether to continue or stop
|
|
186
|
+
- `SubagentStop` - Evaluate subagent results
|
|
187
|
+
- `UserPromptSubmit` - Evaluate or enrich user prompts
|
|
188
|
+
|
|
189
|
+
**Example: Stop Hook**
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"hooks": {
|
|
194
|
+
"Stop": [
|
|
195
|
+
{
|
|
196
|
+
"hooks": [
|
|
197
|
+
{
|
|
198
|
+
"type": "prompt",
|
|
199
|
+
"prompt": "You are evaluating whether Qwen Code should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
|
|
200
|
+
"timeout": 30
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
When `ok` is `false`, Qwen Code will continue working and use the `reason` as context for the next response.
|
|
210
|
+
|
|
211
|
+
**Example: PreToolUse Hook**
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"hooks": {
|
|
216
|
+
"PreToolUse": [
|
|
217
|
+
{
|
|
218
|
+
"matcher": "Bash",
|
|
219
|
+
"hooks": [
|
|
220
|
+
{
|
|
221
|
+
"type": "prompt",
|
|
222
|
+
"prompt": "Evaluate this tool call for security concerns. Tool input: $ARGUMENTS\n\nCheck for:\n- Dangerous commands (rm -rf, curl | sh, etc.)\n- Unauthorized access attempts\n- Data exfiltration patterns\n\nRespond with {\"ok\": true} if safe, or {\"ok\": false, \"reason\": \"concern\"} if blocked.",
|
|
223
|
+
"model": "sonnet",
|
|
224
|
+
"timeout": 30,
|
|
225
|
+
"name": "security-evaluator"
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
137
234
|
## Hook Events
|
|
138
235
|
|
|
139
236
|
Hooks fire at specific points during a Qwen Code session. Different events support different matchers to filter trigger conditions.
|
|
@@ -152,6 +249,8 @@ Hooks fire at specific points during a Qwen Code session. Different events suppo
|
|
|
152
249
|
| `PreCompact` | Before conversation compaction | Trigger (`manual`, `auto`) |
|
|
153
250
|
| `Notification` | When notifications are sent | Type (`permission_prompt`, `idle_prompt`, `auth_success`) |
|
|
154
251
|
| `PermissionRequest` | When permission dialog is shown | Tool name |
|
|
252
|
+
| `TodoCreated` | When a new todo item is created | None (always fires) |
|
|
253
|
+
| `TodoCompleted` | When a todo item is marked as completed | None (always fires) |
|
|
155
254
|
|
|
156
255
|
### Matcher Patterns
|
|
157
256
|
|
|
@@ -165,6 +264,7 @@ Hooks fire at specific points during a Qwen Code session. Different events suppo
|
|
|
165
264
|
| Session Events | `SessionEnd` | ✅ Regex | Reason: `clear`, `logout`, `prompt_input_exit`, etc. |
|
|
166
265
|
| Notification Events | `Notification` | ✅ Exact match | Type: `permission_prompt`, `idle_prompt`, `auth_success` |
|
|
167
266
|
| Compact Events | `PreCompact` | ✅ Exact match | Trigger: `manual`, `auto` |
|
|
267
|
+
| Todo Events | `TodoCreated`, `TodoCompleted` | ❌ No | N/A |
|
|
168
268
|
| Prompt Events | `UserPromptSubmit` | ❌ No | N/A |
|
|
169
269
|
| Stop Events | `Stop` | ❌ No | N/A |
|
|
170
270
|
|
|
@@ -754,6 +854,204 @@ Hook output supports three categories of fields:
|
|
|
754
854
|
}
|
|
755
855
|
```
|
|
756
856
|
|
|
857
|
+
#### TodoCreated
|
|
858
|
+
|
|
859
|
+
**Purpose**: Executed when a new todo item is created via the `todo_write` tool. Allows validation, logging, or blocking of todo creation.
|
|
860
|
+
|
|
861
|
+
Todo hooks run in two phases:
|
|
862
|
+
|
|
863
|
+
- `validation`: runs before persistence. Use this phase for validation only; returning `block` or `deny` prevents the write.
|
|
864
|
+
- `postWrite`: runs after persistence. Use this phase for side effects such as logging or syncing; `block` or `deny` is ignored in this phase.
|
|
865
|
+
|
|
866
|
+
**Event-specific fields**:
|
|
867
|
+
|
|
868
|
+
```json
|
|
869
|
+
{
|
|
870
|
+
"todo_id": "unique identifier for the todo item",
|
|
871
|
+
"todo_content": "content/description of the todo item",
|
|
872
|
+
"todo_status": "pending | in_progress | completed",
|
|
873
|
+
"all_todos": "array of all todo items in the current list",
|
|
874
|
+
"phase": "validation | postWrite"
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
**Output Options**:
|
|
879
|
+
|
|
880
|
+
- `decision`: "allow", "block", or "deny"
|
|
881
|
+
- `reason`: human-readable explanation for the decision (required when blocking)
|
|
882
|
+
|
|
883
|
+
**Blocking Behavior**:
|
|
884
|
+
|
|
885
|
+
During the `validation` phase, when `decision` is `block` or `deny` (exit code 2), todo creation is prevented. The todo list remains unchanged, and the reason is provided as feedback to the model.
|
|
886
|
+
|
|
887
|
+
During the `postWrite` phase, the todo has already been persisted. Hooks may still return output, but `block` / `deny` does not undo the write and should not be used for validation.
|
|
888
|
+
|
|
889
|
+
**Example Output (Allow)**:
|
|
890
|
+
|
|
891
|
+
```json
|
|
892
|
+
{
|
|
893
|
+
"decision": "allow",
|
|
894
|
+
"reason": "Todo content validated successfully"
|
|
895
|
+
}
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
**Example Output (Block)**:
|
|
899
|
+
|
|
900
|
+
```json
|
|
901
|
+
{
|
|
902
|
+
"decision": "block",
|
|
903
|
+
"reason": "Todo content too short. Minimum 5 characters required."
|
|
904
|
+
}
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
**Example Hook Script**:
|
|
908
|
+
|
|
909
|
+
```bash
|
|
910
|
+
#!/bin/bash
|
|
911
|
+
# ~/.qwen/hooks/todo-validator.sh
|
|
912
|
+
# Validates todo content before creation
|
|
913
|
+
|
|
914
|
+
INPUT=$(cat)
|
|
915
|
+
CONTENT=$(echo "$INPUT" | jq -r '.todo_content')
|
|
916
|
+
|
|
917
|
+
# Check minimum length
|
|
918
|
+
if [ ${#CONTENT} -lt 5 ]; then
|
|
919
|
+
echo '{"decision": "block", "reason": "Todo content must be at least 5 characters"}'
|
|
920
|
+
exit 2
|
|
921
|
+
fi
|
|
922
|
+
|
|
923
|
+
# Block test-related todos
|
|
924
|
+
if [[ "$CONTENT" =~ "test" ]]; then
|
|
925
|
+
echo '{"decision": "block", "reason": "Test todos are not allowed in production"}'
|
|
926
|
+
exit 2
|
|
927
|
+
fi
|
|
928
|
+
|
|
929
|
+
echo '{"decision": "allow"}'
|
|
930
|
+
exit 0
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
**Example Configuration**:
|
|
934
|
+
|
|
935
|
+
```json
|
|
936
|
+
{
|
|
937
|
+
"hooks": {
|
|
938
|
+
"TodoCreated": [
|
|
939
|
+
{
|
|
940
|
+
"hooks": [
|
|
941
|
+
{
|
|
942
|
+
"type": "command",
|
|
943
|
+
"command": "$HOME/.qwen/hooks/todo-validator.sh",
|
|
944
|
+
"name": "todo-validator",
|
|
945
|
+
"timeout": 5000
|
|
946
|
+
}
|
|
947
|
+
]
|
|
948
|
+
}
|
|
949
|
+
]
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
#### TodoCompleted
|
|
955
|
+
|
|
956
|
+
**Purpose**: Executed when a todo item is marked as completed. Allows validation, logging, or blocking of todo completion.
|
|
957
|
+
|
|
958
|
+
Todo hooks run in two phases:
|
|
959
|
+
|
|
960
|
+
- `validation`: runs before persistence. Use this phase for validation only; returning `block` or `deny` prevents the write.
|
|
961
|
+
- `postWrite`: runs after persistence. Use this phase for side effects such as logging or syncing; `block` or `deny` is ignored in this phase.
|
|
962
|
+
|
|
963
|
+
**Event-specific fields**:
|
|
964
|
+
|
|
965
|
+
```json
|
|
966
|
+
{
|
|
967
|
+
"todo_id": "unique identifier for the todo item",
|
|
968
|
+
"todo_content": "content/description of the todo item",
|
|
969
|
+
"previous_status": "pending | in_progress (status before completion)",
|
|
970
|
+
"all_todos": "array of all todo items in the current list",
|
|
971
|
+
"phase": "validation | postWrite"
|
|
972
|
+
}
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
**Output Options**:
|
|
976
|
+
|
|
977
|
+
- `decision`: "allow", "block", or "deny"
|
|
978
|
+
- `reason`: human-readable explanation for the decision (required when blocking)
|
|
979
|
+
|
|
980
|
+
**Blocking Behavior**:
|
|
981
|
+
|
|
982
|
+
During the `validation` phase, when `decision` is `block` or `deny` (exit code 2), todo completion is prevented. The todo item remains in its previous status, and the reason is provided as feedback to the model.
|
|
983
|
+
|
|
984
|
+
During the `postWrite` phase, the todo has already been persisted. Hooks may still return output, but `block` / `deny` does not undo the write and should not be used for validation.
|
|
985
|
+
|
|
986
|
+
**Example Output (Allow)**:
|
|
987
|
+
|
|
988
|
+
```json
|
|
989
|
+
{
|
|
990
|
+
"decision": "allow",
|
|
991
|
+
"reason": "Todo completion approved"
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
**Example Output (Block)**:
|
|
996
|
+
|
|
997
|
+
```json
|
|
998
|
+
{
|
|
999
|
+
"decision": "block",
|
|
1000
|
+
"reason": "Cannot complete this todo until dependent tasks are finished."
|
|
1001
|
+
}
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
**Example Hook Script**:
|
|
1005
|
+
|
|
1006
|
+
```bash
|
|
1007
|
+
#!/bin/bash
|
|
1008
|
+
# ~/.qwen/hooks/todo-completion-validator.sh
|
|
1009
|
+
# Validates todo completion conditions
|
|
1010
|
+
|
|
1011
|
+
INPUT=$(cat)
|
|
1012
|
+
TODO_ID=$(echo "$INPUT" | jq -r '.todo_id')
|
|
1013
|
+
ALL_TODOS=$(echo "$INPUT" | jq -r '.all_todos')
|
|
1014
|
+
|
|
1015
|
+
# Check if there are incomplete dependent todos (example logic)
|
|
1016
|
+
INCOMPLETE_COUNT=$(echo "$ALL_TODOS" | jq '[.[] | select(.status != "completed")] | length')
|
|
1017
|
+
|
|
1018
|
+
if [ "$INCOMPLETE_COUNT" -gt 5 ]; then
|
|
1019
|
+
echo '{"decision": "block", "reason": "Too many incomplete todos. Complete other tasks first."}'
|
|
1020
|
+
exit 2
|
|
1021
|
+
fi
|
|
1022
|
+
|
|
1023
|
+
echo '{"decision": "allow"}'
|
|
1024
|
+
exit 0
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
**Example Configuration**:
|
|
1028
|
+
|
|
1029
|
+
```json
|
|
1030
|
+
{
|
|
1031
|
+
"hooks": {
|
|
1032
|
+
"TodoCompleted": [
|
|
1033
|
+
{
|
|
1034
|
+
"hooks": [
|
|
1035
|
+
{
|
|
1036
|
+
"type": "command",
|
|
1037
|
+
"command": "$HOME/.qwen/hooks/todo-completion-validator.sh",
|
|
1038
|
+
"name": "completion-validator",
|
|
1039
|
+
"timeout": 5000
|
|
1040
|
+
}
|
|
1041
|
+
]
|
|
1042
|
+
}
|
|
1043
|
+
]
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
**Use Cases**:
|
|
1049
|
+
|
|
1050
|
+
- **Logging**: Track todo creation and completion for audit or analytics
|
|
1051
|
+
- **Validation**: Enforce content quality standards (minimum length, required keywords)
|
|
1052
|
+
- **Workflow Control**: Block completion until prerequisites are met
|
|
1053
|
+
- **Integration**: Sync todos with external task management systems (Jira, Trello, etc.)
|
|
1054
|
+
|
|
757
1055
|
## Hook Configuration
|
|
758
1056
|
|
|
759
1057
|
Hooks are configured in Qwen Code settings, typically in `.qwen/settings.json` or user configuration files:
|
|
@@ -55,22 +55,6 @@ Detection priority:
|
|
|
55
55
|
3. System locale via JavaScript Intl API
|
|
56
56
|
4. Default: English
|
|
57
57
|
|
|
58
|
-
### Dynamic Command Translation
|
|
59
|
-
|
|
60
|
-
Dynamic slash command descriptions from skills, extensions, file commands, and
|
|
61
|
-
MCP prompts can be translated with AI. This is **off by default** to avoid
|
|
62
|
-
unexpected model calls, latency, and token usage.
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
/language translate status # Show current status
|
|
66
|
-
/language translate on # Enable AI translation for dynamic descriptions
|
|
67
|
-
/language translate off # Disable AI translation
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Use `/language translate cache refresh` to re-translate cached dynamic
|
|
71
|
-
descriptions after enabling translation, or `/language translate cache clear` to
|
|
72
|
-
remove cached translations.
|
|
73
|
-
|
|
74
58
|
## LLM Output Language
|
|
75
59
|
|
|
76
60
|
The LLM output language controls what language the AI assistant responds in, regardless of what language you type your questions in.
|
|
@@ -145,6 +129,29 @@ User directory takes precedence over built-in translations.
|
|
|
145
129
|
> Contributions are welcome! If you’d like to improve built-in translations or add new languages.
|
|
146
130
|
> For a concrete example, see [PR #1238: feat(i18n): add Russian language support](https://github.com/QwenLM/qwen-code/pull/1238).
|
|
147
131
|
|
|
132
|
+
### Maintaining `zh-TW` (Traditional Chinese for Taiwan)
|
|
133
|
+
|
|
134
|
+
`zh-TW` is **not** an automatic OpenCC s2t conversion of `zh.js` — it is a hand-maintained Taiwan-vocabulary translation. When adding or updating keys, please follow the conventions below.
|
|
135
|
+
|
|
136
|
+
The "CI enforced?" column indicates whether `npm run check-i18n` will fail the build on a violation. Rows marked **No** are style guidance enforced by review only — typically because the offending form has a legitimate non-UI meaning (`文件` can mean "document", `打開` is colloquially fine in Taiwan).
|
|
137
|
+
|
|
138
|
+
| Avoid | Use instead | CI enforced? | Reason |
|
|
139
|
+
| --------------------- | --------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| 文件 (file) | 檔案 | No | Taiwan term for filesystem files (but `文件` can legitimately mean "document") |
|
|
141
|
+
| 服務器 / 服务器 | 伺服器 | Yes | Taiwan term for "server" |
|
|
142
|
+
| 菜單 / 菜单 | 選單 | Yes | Taiwan term for "menu" |
|
|
143
|
+
| 鏈接 / 链接 | 連結 | Yes | Taiwan term for "link" (bare `鏈` is fine — e.g. 區塊鏈) |
|
|
144
|
+
| 打開 | 開啟 | No | Taiwan-preferred verb for "open" (UI); `打開` is colloquially common |
|
|
145
|
+
| 爲 / 啓 / 曆史 / 鏈接 | 為 / 啟 / 歷史 / 連結 | Yes | Variant Traditional forms from raw OpenCC s2t. Note: `曆` is context-dependent and correct in calendar terms (日曆, 農曆, 西曆); CI only flags the bigram `曆史`, not bare `曆`. |
|
|
146
|
+
|
|
147
|
+
If you are not a Traditional Chinese speaker and need to bootstrap a value, **do not paste raw OpenCC `s2t` output**: the default s2t profile emits variant Traditional characters (e.g. 爲, 啓) that Taiwan does not use, and never rewrites Mainland-Chinese vocabulary (服務器, 菜單). Prefer `s2twp.json` (Simplified → Taiwan with phrase mapping) as a starting point and then ask a Taiwan-Chinese speaker to review.
|
|
148
|
+
|
|
149
|
+
The `check-i18n` script (run in CI via `npm run check-i18n`) will fail the build if any of the CI-enforced substrings above end up in a `zh-TW` value. See `scripts/check-i18n.ts → ZH_TW_FORBIDDEN_PATTERNS` for the full list. If a translation legitimately needs to contain a CI-forbidden substring, add its key to `ZH_TW_ALLOWED_EXCEPTIONS` in the same file with a brief justification.
|
|
150
|
+
|
|
151
|
+
> [!note]
|
|
152
|
+
>
|
|
153
|
+
> The check uses plain substring matching, which does not understand Chinese word boundaries. A bigram pattern can therefore false-positive across compound-word boundaries — for example, `區塊鏈接口` (= `區塊鏈` + `接口`) contains the substring `鏈接` even though neither word is incorrect. If you hit a surprising CI failure of this kind, add the translation key to `ZH_TW_ALLOWED_EXCEPTIONS` rather than removing the pattern.
|
|
154
|
+
|
|
148
155
|
### Language Pack Format
|
|
149
156
|
|
|
150
157
|
```javascript
|
|
@@ -147,6 +147,62 @@ CLI:
|
|
|
147
147
|
qwen mcp add --transport sse sseServer http://localhost:8080/sse --timeout 30000
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
## Progressive availability and discovery timeouts
|
|
151
|
+
|
|
152
|
+
Qwen Code discovers MCP servers in the background after the UI is already
|
|
153
|
+
interactive. You see the cli's first prompt within a few hundred
|
|
154
|
+
milliseconds even when one of your MCP servers takes several seconds
|
|
155
|
+
(or never responds), and the model's tool list updates within roughly
|
|
156
|
+
one frame (~16 ms) of each server completing its discover handshake.
|
|
157
|
+
|
|
158
|
+
- **Interactive mode**: the UI appears immediately; an MCP status pill in
|
|
159
|
+
the bottom-right shows `N/M MCP servers ready` while discovery is in
|
|
160
|
+
flight. Sending a prompt before MCP finishes simply means the model
|
|
161
|
+
sees the tools that are ready _at that moment_; subsequent prompts see
|
|
162
|
+
more tools as servers come online.
|
|
163
|
+
- **Non-interactive mode** (`--prompt`, stream-json, ACP): the cli still
|
|
164
|
+
waits for MCP discovery to settle before sending the first prompt, so
|
|
165
|
+
scripted / piped invocations see the same complete tool set the
|
|
166
|
+
legacy synchronous behavior produced.
|
|
167
|
+
|
|
168
|
+
### Per-server `discoveryTimeoutMs`
|
|
169
|
+
|
|
170
|
+
Each MCP server gets a discovery-only timeout that caps how long the
|
|
171
|
+
initial handshake (`connect` + `tools/list` + `prompts/list` +
|
|
172
|
+
`resources/list`) is allowed to take. Defaults:
|
|
173
|
+
|
|
174
|
+
- **stdio servers**: 30 s
|
|
175
|
+
- **remote HTTP / SSE servers**: 5 s (network risk is higher)
|
|
176
|
+
|
|
177
|
+
Override per server when needed:
|
|
178
|
+
|
|
179
|
+
```jsonc
|
|
180
|
+
{
|
|
181
|
+
"mcpServers": {
|
|
182
|
+
"slow-stdio": {
|
|
183
|
+
"command": "node",
|
|
184
|
+
"args": ["./slow-server.js"],
|
|
185
|
+
"discoveryTimeoutMs": 60000,
|
|
186
|
+
},
|
|
187
|
+
"flaky-remote": {
|
|
188
|
+
"httpUrl": "https://example.com/mcp",
|
|
189
|
+
"discoveryTimeoutMs": 10000,
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The existing `timeout` field is **tool-call** timeout (used for each
|
|
196
|
+
`tools/call` request, default 10 minutes) and is unaffected by
|
|
197
|
+
`discoveryTimeoutMs` — a long-running tool invocation is not a startup
|
|
198
|
+
pathology.
|
|
199
|
+
|
|
200
|
+
### Rolling back progressive MCP
|
|
201
|
+
|
|
202
|
+
If you need the old synchronous behavior (cli waits for every MCP server
|
|
203
|
+
before showing any UI), set `QWEN_CODE_LEGACY_MCP_BLOCKING=1` in your
|
|
204
|
+
environment. This is kept as an escape hatch for at least one release.
|
|
205
|
+
|
|
150
206
|
## Safety and control
|
|
151
207
|
|
|
152
208
|
### Trust (skip confirmations)
|