@qwen-code/qwen-code 0.18.0 → 0.18.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.
Files changed (111) hide show
  1. package/bundled/loop/SKILL.md +2 -1
  2. package/bundled/qc-helper/docs/configuration/auth.md +1 -1
  3. package/bundled/qc-helper/docs/configuration/model-providers.md +12 -5
  4. package/bundled/qc-helper/docs/configuration/settings.md +30 -27
  5. package/bundled/qc-helper/docs/features/dual-output.md +37 -3
  6. package/bundled/qc-helper/docs/features/skills.md +29 -3
  7. package/bundled/qc-helper/docs/features/sub-agents.md +2 -1
  8. package/bundled/qc-helper/docs/qwen-serve.md +26 -18
  9. package/chunks/{agent-LOTJK6AH.js → agent-XT7NHZ5H.js} +21 -20
  10. package/chunks/{agent-headless-TU3EPMYU.js → agent-headless-LNRE63ZL.js} +21 -20
  11. package/chunks/{anthropicContentGenerator-2HBRNQ3B.js → anthropicContentGenerator-DCI26OQF.js} +4 -4
  12. package/chunks/{askUserQuestion-OGCMIBQM.js → askUserQuestion-ITYUTWLR.js} +2 -2
  13. package/chunks/{ca-BARBRL6N.js → ca-RK4QPLIX.js} +18 -1
  14. package/chunks/{chunk-ZTZ4DDQE.js → chunk-3NRO6NHX.js} +2 -2
  15. package/chunks/{chunk-IWAYOW5Q.js → chunk-6T7Y7USE.js} +6566 -4195
  16. package/chunks/{chunk-MFBBBTNY.js → chunk-7KPZFE5A.js} +1 -1
  17. package/chunks/{chunk-XV4HCEVI.js → chunk-A2ZIEEGJ.js} +9 -22
  18. package/chunks/{chunk-A7B4ISQP.js → chunk-B4ZF2KSI.js} +1 -1
  19. package/chunks/chunk-BJ5HQ23U.js +178 -0
  20. package/chunks/{chunk-LBP46COL.js → chunk-BXYRCW2C.js} +83 -15
  21. package/chunks/{chunk-OHEGWO4L.js → chunk-CPVI5J2L.js} +1 -1
  22. package/chunks/{chunk-R7ODSGTK.js → chunk-DHZREJTG.js} +2 -2
  23. package/chunks/{chunk-SEGYWKIH.js → chunk-FIQECJTQ.js} +1 -1
  24. package/chunks/{chunk-HR7SV7AY.js → chunk-HA2UEYZP.js} +6 -2
  25. package/chunks/{chunk-JTQAQBTV.js → chunk-HED55F43.js} +5 -1
  26. package/chunks/{chunk-HLPLOD42.js → chunk-HQUWWSSP.js} +1 -1
  27. package/chunks/{chunk-2Y5SYSD3.js → chunk-IDYDPBBN.js} +3 -3
  28. package/chunks/{chunk-3HTIVKZE.js → chunk-IQHSD7K5.js} +1 -1
  29. package/chunks/{chunk-LEJ42GNY.js → chunk-IS7UA4W3.js} +6 -6
  30. package/chunks/{chunk-B7HXHOHU.js → chunk-LXYWINWF.js} +1 -1
  31. package/chunks/{chunk-IDX6COTE.js → chunk-LYRSMKLS.js} +2 -2
  32. package/chunks/{chunk-M6VTDSVR.js → chunk-LYSND7KR.js} +9 -4
  33. package/chunks/{chunk-EYENRK4D.js → chunk-NNIYWQIS.js} +1 -1
  34. package/chunks/chunk-OMX7CUOE.js +356 -0
  35. package/chunks/{chunk-BIVG75CP.js → chunk-QILTEBWS.js} +1 -1
  36. package/chunks/{chunk-6YIUGZTC.js → chunk-RON7LFNH.js} +281 -132
  37. package/chunks/{chunk-3DHXZ6EV.js → chunk-SFRV6BGY.js} +6 -4
  38. package/chunks/{chunk-7BCMOPIM.js → chunk-WJ3SND6W.js} +31 -12
  39. package/chunks/{chunk-J5MDQKJL.js → chunk-WPTCDQN6.js} +2 -347
  40. package/chunks/{chunk-PL3MVCWD.js → chunk-XZTNBSMW.js} +11 -11
  41. package/chunks/{chunk-72LDN5PP.js → chunk-Y7KMDUEP.js} +1 -1
  42. package/chunks/{chunk-SNGELLWX.js → chunk-ZMIBJS45.js} +1 -1
  43. package/chunks/{chunk-XBY7E2FX.js → chunk-ZOFNJQNJ.js} +6 -4
  44. package/chunks/computer-use-4YX3JGBV.js +2052 -0
  45. package/chunks/{contextCommand-K347QT6O.js → contextCommand-KS2H7MW5.js} +23 -22
  46. package/chunks/cron-create-CAPUKK7I.js +184 -0
  47. package/chunks/{cron-delete-WKWSJZQA.js → cron-delete-G3KAR26Q.js} +27 -4
  48. package/chunks/{cron-list-B52XEXAZ.js → cron-list-ZA4ZIUS5.js} +39 -6
  49. package/chunks/{de-YGKK2BC4.js → de-FGPM4KW5.js} +18 -1
  50. package/chunks/{dist-KAZ3SEBX.js → dist-7YWFWOCJ.js} +1 -1
  51. package/chunks/{dist-4LXD6L6X.js → dist-VEGFONCF.js} +2 -2
  52. package/chunks/{dist-H6ONXVLG.js → dist-X4EXN7W6.js} +1 -1
  53. package/chunks/{dist-PK7DFCAW.js → dist-YLS6NI7H.js} +1 -1
  54. package/chunks/{edit-KU4PJGEX.js → edit-2ARPEO4B.js} +22 -21
  55. package/chunks/{en-DHGYHIHX.js → en-VP6XPGEC.js} +5 -2
  56. package/chunks/{enter-worktree-PPYIDCWI.js → enter-worktree-IXNXNAW5.js} +21 -20
  57. package/chunks/{enterPlanMode-5CZDMCB4.js → enterPlanMode-TAKAGAYP.js} +21 -20
  58. package/chunks/{exit-worktree-UY3CGHKC.js → exit-worktree-LHTRV7ML.js} +21 -20
  59. package/chunks/{exitPlanMode-3DN4QNSG.js → exitPlanMode-MK5UAITL.js} +71 -31
  60. package/chunks/{fr-JXBKPJKQ.js → fr-ATYBVCLT.js} +18 -1
  61. package/chunks/{geminiContentGenerator-7A6I2RWB.js → geminiContentGenerator-HFJIGO77.js} +4 -4
  62. package/chunks/{glob-OFNQSS52.js → glob-I2USLUSC.js} +21 -20
  63. package/chunks/{grep-6J2MSUM5.js → grep-WBIF7THR.js} +30 -26
  64. package/chunks/{ja-TGPZSP2B.js → ja-W2QEA2OI.js} +18 -1
  65. package/chunks/{keychain-token-storage-6IU6ORQN.js → keychain-token-storage-QSTRHKKL.js} +2 -2
  66. package/chunks/{ls-V3O6A5PT.js → ls-2R5RHLX5.js} +3 -3
  67. package/chunks/{lsp-G2OCIFUA.js → lsp-XKH6ZIAN.js} +2 -2
  68. package/chunks/{monitor-FKLHV423.js → monitor-WU7UFATU.js} +21 -20
  69. package/chunks/{notebook-edit-KTBYFKWG.js → notebook-edit-KUHYPXEM.js} +22 -21
  70. package/chunks/{openaiContentGenerator-L5KSWQY7.js → openaiContentGenerator-5PLHYJQL.js} +11 -11
  71. package/chunks/{pt-TIBG6BIO.js → pt-ZKEWJFBW.js} +18 -1
  72. package/chunks/{qwenContentGenerator-PYOXLMBW.js → qwenContentGenerator-TSKW73KY.js} +23 -22
  73. package/chunks/{qwenOAuth2-2KCKWDCF.js → qwenOAuth2-KK433U33.js} +4 -4
  74. package/chunks/{read-file-JQVRK4NU.js → read-file-VIPF2PS6.js} +8 -8
  75. package/chunks/{ripGrep-2L4LPNAJ.js → ripGrep-XLIZTYE7.js} +21 -20
  76. package/chunks/{ru-JBCHCK4L.js → ru-VEKTPJ74.js} +18 -1
  77. package/chunks/{scheduler-FGNXY4JQ.js → scheduler-O66SLJGU.js} +21 -20
  78. package/chunks/{send-message-SZFWNOCL.js → send-message-CTME7DXD.js} +2 -2
  79. package/chunks/{serve-N2IBLA3G.js → serve-BWOLYT62.js} +998 -278
  80. package/chunks/{shell-PTEG6UX4.js → shell-XE7UYKOO.js} +21 -20
  81. package/chunks/{skill-X4NTK4NH.js → skill-RZWM6XMC.js} +10 -10
  82. package/chunks/{src-GLLQ3R5W.js → src-L5P7K4MH.js} +42 -26
  83. package/chunks/{syntheticOutput-IKAY5F6X.js → syntheticOutput-ZJGSU7OQ.js} +3 -3
  84. package/chunks/{task-create-MQICOJFV.js → task-create-EE6JEM7G.js} +7 -6
  85. package/chunks/{task-list-RIHJCH32.js → task-list-EESYAC65.js} +6 -5
  86. package/chunks/{task-stop-FWZRFANS.js → task-stop-XZVCFFYY.js} +2 -2
  87. package/chunks/{task-update-2LHPXOYM.js → task-update-EIO4HNE3.js} +7 -6
  88. package/chunks/{team-create-2E4PF4KN.js → team-create-R2H7Y3SG.js} +21 -20
  89. package/chunks/{team-delete-DAUDQS4J.js → team-delete-A7LXPGV7.js} +6 -5
  90. package/chunks/{todoWrite-HTUACZES.js → todoWrite-VRKSGAWM.js} +4 -4
  91. package/chunks/{tool-search-KTVULRES.js → tool-search-USSQMTMS.js} +8 -8
  92. package/chunks/{web-fetch-CZ7LLKPE.js → web-fetch-GHAZUA54.js} +4 -4
  93. package/chunks/{workflow-L2ZUUDT2.js → workflow-5LNNLNUR.js} +503 -49
  94. package/chunks/{write-file-ZEB2JDYH.js → write-file-2I7HP24C.js} +22 -21
  95. package/chunks/{zh-7H5OQC4I.js → zh-OIXDDQHB.js} +5 -2
  96. package/chunks/{zh-TW-P4IDHD3M.js → zh-TW-6YFNCKTA.js} +5 -2
  97. package/cli-entry.js +19 -0
  98. package/cli.js +6547 -4938
  99. package/locales/ca.js +20 -2
  100. package/locales/de.js +21 -2
  101. package/locales/en.js +7 -4
  102. package/locales/fr.js +22 -2
  103. package/locales/ja.js +22 -2
  104. package/locales/pt.js +21 -2
  105. package/locales/ru.js +20 -2
  106. package/locales/zh-TW.js +6 -4
  107. package/locales/zh.js +6 -4
  108. package/package.json +4 -3
  109. package/chunks/chunk-SKBPNJEW.js +0 -45
  110. package/chunks/computer-use-3RH2DOM6.js +0 -825
  111. package/chunks/cron-create-YJL3KFWI.js +0 -140
@@ -56,7 +56,8 @@ Supported suffixes: `s` (seconds, rounded up to nearest minute, min 1), `m` (min
56
56
  - `cron`: the expression from the table above
57
57
  - `prompt`: the parsed prompt from above, verbatim (slash commands are passed through unchanged)
58
58
  - `recurring`: `true`
59
- 2. Briefly confirm: what's scheduled, the cron expression, the human-readable cadence, that recurring tasks auto-expire after 3 days, and that they can cancel sooner with CronDelete (include the job ID).
59
+ - `durable`: `true` if the user's language implies persistence ("keep doing this", "set this up permanently", "every day even after restart"). Otherwise omit (defaults to session-only).
60
+ 2. Briefly confirm: what's scheduled, the cron expression, the human-readable cadence, that recurring tasks auto-expire after 7 days, and that they can cancel sooner with CronDelete (include the job ID).
60
61
  3. **Then immediately execute the parsed prompt now** — don't wait for the first cron fire. If it's a slash command, invoke it via the Skill tool; otherwise act on it directly.
61
62
 
62
63
  ## Input
@@ -50,7 +50,7 @@ Alibaba Cloud Coding Plan is available in two regions:
50
50
 
51
51
  Enter `qwen` in the terminal to launch Qwen Code, then run the `/auth` command and select **Alibaba Cloud Coding Plan**. Choose your region, then enter your `sk-sp-xxxxxxxxx` key.
52
52
 
53
- After authentication, use the `/model` command to switch between all Alibaba Cloud Coding Plan supported models (including qwen3.5-plus, qwen3-coder-plus, qwen3-coder-next, qwen3-max, glm-4.7, and kimi-k2.5).
53
+ After authentication, use the `/model` command to switch between all Alibaba Cloud Coding Plan supported models (including qwen3.5-plus, qwen3.6-plus, qwen3.7-plus, qwen3-coder-plus, qwen3-coder-next, qwen3-max-2026-01-23, glm-5, glm-4.7, kimi-k2.5, and MiniMax-M2.5).
54
54
 
55
55
  ### Headless or scripted setup
56
56
 
@@ -299,11 +299,18 @@ Alibaba Cloud Coding Plan provides a pre-configured set of Qwen models optimized
299
299
 
300
300
  When you authenticate with an Alibaba Cloud Coding Plan API key using the `/auth` command, Qwen Code automatically configures the following models:
301
301
 
302
- | Model ID | Name | Description |
303
- | ---------------------- | -------------------- | -------------------------------------- |
304
- | `qwen3.5-plus` | qwen3.5-plus | Advanced model with thinking enabled |
305
- | `qwen3-coder-plus` | qwen3-coder-plus | Optimized for coding tasks |
306
- | `qwen3-max-2026-01-23` | qwen3-max-2026-01-23 | Latest max model with thinking enabled |
302
+ | Model ID | Name | Description |
303
+ | ---------------------- | -------------------- | --------------------------------------------------------- |
304
+ | `qwen3.5-plus` | qwen3.5-plus | Advanced model with thinking enabled |
305
+ | `qwen3.6-plus` | qwen3.6-plus | Latest model with thinking enabled (Pro subscribers only) |
306
+ | `qwen3.7-plus` | qwen3.7-plus | Advanced model with thinking enabled |
307
+ | `qwen3-coder-plus` | qwen3-coder-plus | Optimized for coding tasks |
308
+ | `qwen3-coder-next` | qwen3-coder-next | Experimental coding model |
309
+ | `qwen3-max-2026-01-23` | qwen3-max-2026-01-23 | Latest max model with thinking enabled |
310
+ | `glm-5` | glm-5 | GLM model with thinking enabled |
311
+ | `glm-4.7` | glm-4.7 | GLM model with thinking enabled |
312
+ | `kimi-k2.5` | kimi-k2.5 | Kimi model with thinking and vision/video support |
313
+ | `MiniMax-M2.5` | MiniMax-M2.5 | MiniMax model with thinking enabled |
307
314
 
308
315
  ### Setup
309
316
 
@@ -228,18 +228,19 @@ The `extra_body` field allows you to add custom parameters to the request body s
228
228
 
229
229
  #### context
230
230
 
231
- | Setting | Type | Description | Default |
232
- | -------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
233
- | `context.fileName` | string or array of strings | The name of the context file(s). | `undefined` |
234
- | `context.importFormat` | string | The format to use when importing memory. | `undefined` |
235
- | `context.includeDirectories` | array | Additional directories to include in the workspace context. Specifies an array of additional absolute or relative paths to include in the workspace context. Missing directories will be skipped with a warning by default. Paths can use `~` to refer to the user's home directory. This setting can be combined with the `--include-directories` command-line flag. | `[]` |
236
- | `context.loadFromIncludeDirectories` | boolean | Controls the behavior of the `/memory refresh` command. If set to `true`, `QWEN.md` files should be loaded from all directories that are added. If set to `false`, `QWEN.md` should only be loaded from the current directory. | `false` |
237
- | `context.fileFiltering.respectGitIgnore` | boolean | Respect .gitignore files when searching. | `true` |
238
- | `context.fileFiltering.respectQwenIgnore` | boolean | Respect .qwenignore files when searching. | `true` |
239
- | `context.fileFiltering.enableRecursiveFileSearch` | boolean | Whether to enable searching recursively for filenames under the current tree when completing `@` prefixes in the prompt. | `true` |
240
- | `context.fileFiltering.enableFuzzySearch` | boolean | When `true`, enables fuzzy search capabilities when searching for files. Set to `false` to improve performance on projects with a large number of files. | `true` |
241
- | `context.clearContextOnIdle.toolResultsThresholdMinutes` | number | Minutes of inactivity before clearing old tool result content. Use `-1` to disable. | `60` |
242
- | `context.clearContextOnIdle.toolResultsNumToKeep` | number | Number of most-recent compactable tool results to preserve when clearing. Floor at 1. | `5` |
231
+ | Setting | Type | Description | Default |
232
+ | ----------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
233
+ | `context.fileName` | string or array of strings | The name of the context file(s). | `undefined` |
234
+ | `context.importFormat` | string | The format to use when importing memory. | `undefined` |
235
+ | `context.includeDirectories` | array | Additional directories to include in the workspace context. Specifies an array of additional absolute or relative paths to include in the workspace context. Missing directories will be skipped with a warning by default. Paths can use `~` to refer to the user's home directory. This setting can be combined with the `--include-directories` command-line flag. | `[]` |
236
+ | `context.loadFromIncludeDirectories` | boolean | Controls the behavior of the `/memory refresh` command. If set to `true`, `QWEN.md` files should be loaded from all directories that are added. If set to `false`, `QWEN.md` should only be loaded from the current directory. | `false` |
237
+ | `context.fileFiltering.respectGitIgnore` | boolean | Respect .gitignore files when searching. | `true` |
238
+ | `context.fileFiltering.respectQwenIgnore` | boolean | Respect .qwenignore files when searching. | `true` |
239
+ | `context.fileFiltering.enableRecursiveFileSearch` | boolean | Whether to enable searching recursively for filenames under the current tree when completing `@` prefixes in the prompt. | `true` |
240
+ | `context.fileFiltering.enableFuzzySearch` | boolean | When `true`, enables fuzzy search capabilities when searching for files. Set to `false` to improve performance on projects with a large number of files. | `true` |
241
+ | `context.clearContextOnIdle.toolResultsThresholdMinutes` | number | Minutes of inactivity before clearing old tool result content. Use `-1` to disable the idle trigger. | `60` |
242
+ | `context.clearContextOnIdle.toolResultsNumToKeep` | number | Number of most-recent compactable tool results to preserve when clearing. Floor at 1. | `5` |
243
+ | `context.clearContextOnIdle.toolResultsTotalCharsThreshold` | number | Total compactable tool result output characters allowed in history before clearing oldest results. Use `-1` to disable the size trigger. This is a soft threshold: protected recent tool results may keep the total above it. | `500000` |
243
244
 
244
245
  #### Troubleshooting File Search Performance
245
246
 
@@ -251,21 +252,23 @@ If you are experiencing performance issues with file searching (e.g., with `@` c
251
252
 
252
253
  #### tools
253
254
 
254
- | Setting | Type | Description | Default | Notes |
255
- | ------------------------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
256
- | `tools.sandbox` | boolean or string | Sandbox execution environment (can be a boolean or a path string). | `undefined` | |
257
- | `tools.sandboxImage` | string | Sandbox image URI used by Docker/Podman when `--sandbox-image` and `QWEN_SANDBOX_IMAGE` are not set. | `undefined` | |
258
- | `tools.shell.enableInteractiveShell` | boolean | Use `node-pty` for an interactive shell experience. Fallback to `child_process` still applies. | `false` | |
259
- | `tools.core` | array of strings | **Deprecated.** Will be removed in next version. Use `permissions.allow` + `permissions.deny` instead. Restricts built-in tools to an allowlist. All tools not in the list are disabled. | `undefined` | |
260
- | `tools.exclude` | array of strings | **Deprecated.** Use `permissions.deny` instead. Tool names to exclude from discovery. Automatically migrated to the `permissions` format on first load. | `undefined` | |
261
- | `tools.allowed` | array of strings | **Deprecated.** Use `permissions.allow` instead. Tool names that bypass the confirmation dialog. Automatically migrated to the `permissions` format on first load. | `undefined` | |
262
- | `tools.approvalMode` | string | Sets the default approval mode for tool usage. | `default` | Possible values: `plan` (analyze only, do not modify files or execute commands), `default` (require approval before file edits or shell commands run), `auto-edit` (automatically approve file edits), `yolo` (automatically approve all tool calls) |
263
- | `tools.discoveryCommand` | string | Command to run for tool discovery. | `undefined` | |
264
- | `tools.callCommand` | string | Defines a custom shell command for calling a specific tool that was discovered using `tools.discoveryCommand`. 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 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). | `undefined` | |
265
- | `tools.useRipgrep` | boolean | Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance. | `true` | |
266
- | `tools.useBuiltinRipgrep` | boolean | Use the bundled ripgrep binary. When set to `false`, the system-level `rg` command will be used instead. This setting is only effective when `tools.useRipgrep` is `true`. | `true` | |
267
- | `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 |
268
- | `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 |
255
+ | Setting | Type | Description | Default | Notes |
256
+ | ------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
257
+ | `tools.sandbox` | boolean or string | Sandbox execution environment (can be a boolean or a path string). | `undefined` | |
258
+ | `tools.sandboxImage` | string | Sandbox image URI used by Docker/Podman when `--sandbox-image` and `QWEN_SANDBOX_IMAGE` are not set. | `undefined` | |
259
+ | `tools.shell.enableInteractiveShell` | boolean | Use `node-pty` for an interactive shell experience. Fallback to `child_process` still applies. | `false` | |
260
+ | `tools.core` | array of strings | **Deprecated.** Will be removed in next version. Use `permissions.allow` + `permissions.deny` instead. Restricts built-in tools to an allowlist. All tools not in the list are disabled. | `undefined` | |
261
+ | `tools.exclude` | array of strings | **Deprecated.** Use `permissions.deny` instead. Tool names to exclude from discovery. Automatically migrated to the `permissions` format on first load. | `undefined` | |
262
+ | `tools.allowed` | array of strings | **Deprecated.** Use `permissions.allow` instead. Tool names that bypass the confirmation dialog. Automatically migrated to the `permissions` format on first load. | `undefined` | |
263
+ | `tools.approvalMode` | string | Sets the default approval mode for tool usage. | `default` | Possible values: `plan` (analyze only, do not modify files or execute commands), `default` (require approval before file edits or shell commands run), `auto-edit` (automatically approve file edits), `yolo` (automatically approve all tool calls) |
264
+ | `tools.discoveryCommand` | string | Command to run for tool discovery. | `undefined` | |
265
+ | `tools.callCommand` | string | Defines a custom shell command for calling a specific tool that was discovered using `tools.discoveryCommand`. 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 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). | `undefined` | |
266
+ | `tools.useRipgrep` | boolean | Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance. | `true` | |
267
+ | `tools.useBuiltinRipgrep` | boolean | Use the bundled ripgrep binary. When set to `false`, the system-level `rg` command will be used instead. This setting is only effective when `tools.useRipgrep` is `true`. | `true` | |
268
+ | `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 |
269
+ | `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 |
270
+ | `tools.computerUse.enabled` | boolean | Enable the built-in Computer Use tools (cua-driver native desktop automation). When `true` (default), the `computer_use__*` tools are registered as deferred built-ins; the first invocation downloads the pinned, signed cua-driver binary into `~/.qwen/computer-use/` and walks through macOS Accessibility / Screen Recording permissions. | `true` | Requires restart: Yes |
271
+ | `tools.computerUse.maxImageDimension` | number | Longest-edge pixel cap applied to cua-driver screenshots (via `set_config`'s `max_image_dimension`). `-1` (default) keeps cua-driver's built-in default (1568); `0` disables resizing (full resolution); a positive value caps the longest edge. Lower caps cut vision-token cost at the expense of fine detail. | `-1` | Requires restart: Yes. Env override: `QWEN_COMPUTER_USE_MAX_IMAGE_DIMENSION` (a non-negative integer; takes precedence over this setting) |
269
272
 
270
273
  > [!note]
271
274
  >
@@ -199,10 +199,10 @@ wrappers that throw away stdout anyway.
199
199
 
200
200
  ## Quick start
201
201
 
202
- Run Qwen Code with all three channels enabled:
202
+ Run Qwen Code with both channels enabled using regular files:
203
203
 
204
204
  ```bash
205
- mkfifo /tmp/qwen-events.jsonl /tmp/qwen-input.jsonl
205
+ touch /tmp/qwen-events.jsonl /tmp/qwen-input.jsonl
206
206
  qwen \
207
207
  --json-file /tmp/qwen-events.jsonl \
208
208
  --input-file /tmp/qwen-input.jsonl
@@ -211,7 +211,7 @@ qwen \
211
211
  In a second terminal, tail the event stream:
212
212
 
213
213
  ```bash
214
- cat /tmp/qwen-events.jsonl
214
+ tail -f /tmp/qwen-events.jsonl
215
215
  ```
216
216
 
217
217
  In a third terminal, push a prompt into the running TUI:
@@ -223,6 +223,33 @@ echo '{"type":"submit","text":"Explain this repo"}' >> /tmp/qwen-input.jsonl
223
223
  The prompt appears in the TUI exactly as if the user typed it, and the
224
224
  streaming response is mirrored on `/tmp/qwen-events.jsonl`.
225
225
 
226
+ ### Using FIFOs (named pipes) for event output
227
+
228
+ FIFOs deliver lower latency than regular files (no disk I/O) and work
229
+ well when both sides are on the same host. The bridge opens FIFOs with
230
+ `O_RDWR | O_NONBLOCK`, so it **does not block** even if no reader is
231
+ connected yet — events are buffered in the kernel pipe buffer until a
232
+ reader attaches.
233
+
234
+ > **Note:** `--input-file` requires a regular file (not a FIFO) because
235
+ > the watcher relies on `stat.size` to detect new data, which is always
236
+ > 0 for FIFOs.
237
+
238
+ ```bash
239
+ mkfifo /tmp/qwen-events.jsonl
240
+ touch /tmp/qwen-input.jsonl
241
+ qwen \
242
+ --json-file /tmp/qwen-events.jsonl \
243
+ --input-file /tmp/qwen-input.jsonl
244
+ # TUI starts immediately — no need to start a reader first.
245
+
246
+ # In a second terminal, connect whenever ready:
247
+ cat /tmp/qwen-events.jsonl
248
+ ```
249
+
250
+ If no reader ever connects, the bridge auto-disables once the internal
251
+ buffer exceeds 1 MB. The TUI continues running normally.
252
+
226
253
  ## Output event schema
227
254
 
228
255
  Events are emitted as JSON Lines (one object per line). The schema is the same
@@ -325,6 +352,13 @@ polling — events are written synchronously as the TUI emits them.
325
352
  - **Consumer disconnect.** If the reader on the other side of the channel
326
353
  goes away (`EPIPE`), the bridge silently disables itself and the TUI
327
354
  keeps running. No retry.
355
+ - **FIFO buffer overflow.** When writing to a FIFO with no reader
356
+ attached, events buffer in the kernel pipe (~64 KB on Linux) and the
357
+ Node.js WriteStream. Once the pipe is full or the internal buffer
358
+ exceeds 1 MB, the bridge disables itself and closes the fd. No
359
+ `session_end` is emitted in this case — consumers should treat a
360
+ closed stream without `session_end` as an abnormal termination. The
361
+ TUI continues running normally.
328
362
  - **Adapter exception.** Any exception thrown while emitting an event is
329
363
  caught, logged, and disables the bridge. The TUI is never crashed by a
330
364
  dual-output failure.
@@ -118,9 +118,35 @@ Notes:
118
118
 
119
119
  - Globs are matched relative to the project root with [picomatch](https://github.com/micromatch/picomatch); files outside the project root never trigger activation.
120
120
  - A path-gated Skill **stays activated for the rest of the session** once a matching file is touched. A new session, or a `refreshCache` triggered by editing any Skill file, resets activations.
121
- - `paths:` only gates **model** discovery, and only at the SkillTool listing level. You can always invoke a path-gated Skill yourself via `/<skill-name>` or the `/skills` picker — that user path runs the Skill body regardless of activation state. The model side, however, stays gated until a matching file is touched: a slash invocation does **not** unlock model-side activation, so if you want the model to chain off your invocation (call `Skill { skill: ... }` itself), also access a file matching the skill's `paths:` first.
121
+ - `paths:` only gates **model** discovery, and only at the SkillTool listing level. Unless `user-invocable: false` is set, you can always invoke a path-gated Skill yourself via `/<skill-name>` or the `/skills` picker — that user path runs the Skill body regardless of activation state. The model side, however, stays gated until a matching file is touched: a slash invocation does **not** unlock model-side activation, so if you want the model to chain off your invocation (call `Skill { skill: ... }` itself), also access a file matching the skill's `paths:` first.
122
122
  - Combining `paths:` with `disable-model-invocation: true` is allowed but the gate has no effect — the Skill is hidden from the model regardless, so path activation never advertises it.
123
123
 
124
+ ### Optional: control user and model invocation
125
+
126
+ Skills are user-invocable by default. To hide a Skill from direct slash-command use while keeping it available for model invocation, set `user-invocable: false`:
127
+
128
+ ```yaml
129
+ ---
130
+ name: model-only-helper
131
+ description: Helper the model can call when appropriate
132
+ user-invocable: false
133
+ ---
134
+ ```
135
+
136
+ This removes the Skill from `/<skill-name>` invocation and `/skills` picker results. It does not hide the Skill from the model.
137
+
138
+ To hide a Skill from model invocation while keeping direct user invocation available, set `disable-model-invocation: true`:
139
+
140
+ ```yaml
141
+ ---
142
+ name: manual-helper
143
+ description: Helper you invoke manually
144
+ disable-model-invocation: true
145
+ ---
146
+ ```
147
+
148
+ You can combine both fields, but then the Skill is not reachable through the normal user or model invocation paths.
149
+
124
150
  ## Add supporting files
125
151
 
126
152
  Create additional files alongside `SKILL.md`:
@@ -170,9 +196,9 @@ To view available Skills, ask Qwen Code directly:
170
196
  What Skills are available?
171
197
  ```
172
198
 
173
- > **Heads up — model vs. user view.** Asking the model only surfaces Skills the model can currently see. If a Skill uses `paths:` (see "Optional: gate a Skill on file paths" above), it stays out of that listing until a matching file has been touched. The full set is always visible to you via the `/skills` slash command and on disk.
199
+ > **Heads up — model vs. user view.** Asking the model only surfaces Skills the model can currently see. If a Skill uses `paths:` (see "Optional: gate a Skill on file paths" above), it stays out of that listing until a matching file has been touched. The `/skills` slash command shows Skills you can invoke directly; Skills with `user-invocable: false` remain visible on disk and may still be visible to the model.
174
200
 
175
- Or browse the full list with the slash command (always shows every Skill, including path-gated ones that have not activated yet):
201
+ Or browse the user-invocable list with the slash command (including path-gated Skills that have not activated yet):
176
202
 
177
203
  ```text
178
204
  /skills
@@ -135,7 +135,7 @@ Subagents are configured using Markdown files with YAML frontmatter. This format
135
135
  name: agent-name
136
136
  description: Brief description of when and how to use this agent
137
137
  model: inherit # Optional: inherit, fast, modelId, or authType:modelId
138
- approvalMode: auto-edit # Optional: default, plan, auto-edit, yolo
138
+ approvalMode: auto-edit # Optional: default, plan, auto-edit, yolo, bubble
139
139
  tools: # Optional: allowlist of tools
140
140
  - tool1
141
141
  - tool2
@@ -202,6 +202,7 @@ Use the optional `approvalMode` frontmatter field to control how a subagent's to
202
202
  - `plan`: Analyze-only mode — the agent plans but does not execute changes
203
203
  - `auto-edit`: Tools are auto-approved without prompting (recommended for most agents)
204
204
  - `yolo`: All tools auto-approved, including potentially destructive ones
205
+ - `bubble`: Background-agent tool approvals are surfaced in the parent session
205
206
 
206
207
  If you omit this field, the subagent's permission mode is determined automatically:
207
208
 
@@ -73,6 +73,7 @@ curl http://127.0.0.1:4170/capabilities
73
73
  ```
74
74
 
75
75
  The `workspaceCwd` field surfaces the bound workspace so clients can pre-flight check + omit `cwd` on `POST /session`.
76
+ The `limits.maxPendingPromptsPerSession` field advertises the active per-session prompt admission cap; `null` means the cap is disabled.
76
77
 
77
78
  The daemon also exposes read-only runtime snapshots for client UIs:
78
79
  `GET /workspace/mcp`, `GET /workspace/skills`, `GET /workspace/providers`,
@@ -202,20 +203,21 @@ The token comparison is constant-time (SHA-256 + `crypto.timingSafeEqual`); 401
202
203
 
203
204
  ## CLI flags
204
205
 
205
- | Flag | Default | Purpose |
206
- | ------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
207
- | `--port <n>` | `4170` | TCP port. `0` = OS-assigned ephemeral port. |
208
- | `--hostname <addr>` | `127.0.0.1` | Bind interface. Anything beyond loopback requires a token. |
209
- | `--token <str>` | — | Bearer token. Falls back to `QWEN_SERVER_TOKEN` env var (with leading/trailing whitespace stripped — handy for `$(cat token.txt)`). |
210
- | `--require-auth` | `false` | Refuse to start without a bearer token, even on loopback. Hardens the `127.0.0.1` developer default for shared dev hosts / CI runners / multi-tenant workstations where any local user can hit the listener. Boots only with `--token` or `QWEN_SERVER_TOKEN` set; gates `/health` behind the bearer too. |
211
- | `--max-sessions <n>` | `20` | Cap on concurrent live sessions. New `POST /session` requests that would spawn a fresh child return `503` (with `Retry-After: 5`) when the cap is hit; attaches to existing sessions are NOT counted. Set to `0` to disable. Sized for single-user / small-team usage; raise it if your deployment has the RAM/FD headroom (~30–50 MB per session). |
212
- | `--workspace <path>` | `process.cwd()` | Absolute workspace path this daemon binds to (per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02 1 daemon = 1 workspace). `POST /session` requests with a mismatched `cwd` return `400 workspace_mismatch`. For multi-workspace deployments, run one `qwen serve` per workspace on separate ports. |
213
- | `--max-connections <n>` | `256` | Listener-level TCP connection cap (`server.maxConnections`). Bounds raw socket count irrespective of session count slow / phantom SSE clients get rejected at accept time once full. Raise alongside `--max-sessions` if your deployment expects many SSE subscribers per session. |
214
- | `--event-ring-size <n>` | `8000` | Per-session SSE replay ring depth (#3803 §02 target). Sets the backlog available to `GET /session/:id/events` with `Last-Event-ID: N`. Larger = more reconnect headroom at the cost of a few hundred KB extra RAM per session. SDK clients can additionally request a larger per-subscriber backlog cap on a specific subscription via `?maxQueued=N` (range `[16, 2048]`, default 256). Daemons also emit a non-terminal `slow_client_warning` SSE frame at 75% queue fill so clients can drain / reconnect before getting evicted. Pre-flight `caps.features.slow_client_warning`. |
215
- | `--mcp-client-budget <n>` | | Positive integer cap on live MCP clients **per ACP session** (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14 v1; PR 23 graduates this to per-workspace via the shared MCP pool). Combine with `--mcp-budget-mode`. When unset, no accounting-driven enforcement (but `GET /workspace/mcp` still reports `clientCount`). Distinct from claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE` which gates startup concurrency, not the total client count. Pre-flight `caps.features.mcp_guardrails`. |
216
- | `--mcp-budget-mode <m>` | `warn` / `off` | How `--mcp-client-budget` is enforced. `warn` (default when budget set): no refusal, snapshot's `budgets[0].status` flips to `warning` at ≥75% of budget. `enforce`: connects past the cap are refused, per-server cell shows `disabledReason: 'budget'`, deterministic by `mcpServers` declaration order. `off` (default when budget unset): pure observability. Boot rejects `enforce` without a budget. |
217
- | `--http-bridge` | `true` | Stage 1 mode: one `qwen --acp` child per daemon (bound to one workspace at boot, per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02); N sessions multiplex onto that child via ACP `newSession()`. Stage 2 native in-process becomes available later. |
218
- | `--allow-origin <pat>` | | T2.4 ([#4514](https://github.com/QwenLM/qwen-code/issues/4514)). Cross-origin allowlist for browser webui clients. Repeatable. Each value is `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended so `/health` and `/demo` are also bearer-gated, since both are pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo / query). **Subdomain wildcards (`https://*.example.com`) are intentionally unsupported** — list each subdomain explicitly, or use `*` with a configured token (and `--require-auth` for full hardening). Matched origins receive CORS response headers (`Access-Control-Allow-Origin`, `Vary: Origin`, methods, headers, max-age, and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as today's wall. `Origin: null` (sandboxed iframes, file:// docs) is always rejected, even under `*`. Pre-flight via `caps.features.allow_origin`. Loopback self-origin hits are unaffected. |
206
+ | Flag | Default | Purpose |
207
+ | --------------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
208
+ | `--port <n>` | `4170` | TCP port. `0` = OS-assigned ephemeral port. |
209
+ | `--hostname <addr>` | `127.0.0.1` | Bind interface. Anything beyond loopback requires a token. |
210
+ | `--token <str>` | — | Bearer token. Falls back to `QWEN_SERVER_TOKEN` env var (with leading/trailing whitespace stripped — handy for `$(cat token.txt)`). |
211
+ | `--require-auth` | `false` | Refuse to start without a bearer token, even on loopback. Hardens the `127.0.0.1` developer default for shared dev hosts / CI runners / multi-tenant workstations where any local user can hit the listener. Boots only with `--token` or `QWEN_SERVER_TOKEN` set; gates `/health` behind the bearer too. |
212
+ | `--max-sessions <n>` | `20` | Cap on concurrent live sessions. New `POST /session` requests that would spawn a fresh child return `503` (with `Retry-After: 5`) when the cap is hit; attaches to existing sessions are NOT counted. Set to `0` to disable. Sized for single-user / small-team usage; raise it if your deployment has the RAM/FD headroom (~30–50 MB per session). |
213
+ | `--max-pending-prompts-per-session <n>` | `5` | Per-session cap on prompts accepted by `POST /session/:id/prompt` but not yet settled, including queued prompts and the active prompt. The bridge rejects overflow synchronously with `503`, `Retry-After: 5`, and `code: "prompt_queue_full"` before returning a `promptId`. Set to `0` to disable. `branchSession` serializes on the same FIFO but does not count against this prompt cap. |
214
+ | `--workspace <path>` | `process.cwd()` | Absolute workspace path this daemon binds to (per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02 1 daemon = 1 workspace). `POST /session` requests with a mismatched `cwd` return `400 workspace_mismatch`. For multi-workspace deployments, run one `qwen serve` per workspace on separate ports. |
215
+ | `--max-connections <n>` | `256` | Listener-level TCP connection cap (`server.maxConnections`). Bounds raw socket count irrespective of session count slow / phantom SSE clients get rejected at accept time once full. Raise alongside `--max-sessions` if your deployment expects many SSE subscribers per session. |
216
+ | `--event-ring-size <n>` | `8000` | Per-session SSE replay ring depth (#3803 §02 target). Sets the backlog available to `GET /session/:id/events` with `Last-Event-ID: N`. Larger = more reconnect headroom at the cost of a few hundred KB extra RAM per session. SDK clients can additionally request a larger per-subscriber backlog cap on a specific subscription via `?maxQueued=N` (range `[16, 2048]`, default 256). Daemons also emit a non-terminal `slow_client_warning` SSE frame at 75% queue fill so clients can drain / reconnect before getting evicted. Pre-flight `caps.features.slow_client_warning`. |
217
+ | `--mcp-client-budget <n>` | | Positive integer cap on live MCP clients **per ACP session** (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14 v1; PR 23 graduates this to per-workspace via the shared MCP pool). Combine with `--mcp-budget-mode`. When unset, no accounting-driven enforcement (but `GET /workspace/mcp` still reports `clientCount`). Distinct from claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE` which gates startup concurrency, not the total client count. Pre-flight `caps.features.mcp_guardrails`. |
218
+ | `--mcp-budget-mode <m>` | `warn` / `off` | How `--mcp-client-budget` is enforced. `warn` (default when budget set): no refusal, snapshot's `budgets[0].status` flips to `warning` at ≥75% of budget. `enforce`: connects past the cap are refused, per-server cell shows `disabledReason: 'budget'`, deterministic by `mcpServers` declaration order. `off` (default when budget unset): pure observability. Boot rejects `enforce` without a budget. |
219
+ | `--http-bridge` | `true` | Stage 1 mode: one `qwen --acp` child per daemon (bound to one workspace at boot, per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02); N sessions multiplex onto that child via ACP `newSession()`. Stage 2 native in-process becomes available later. |
220
+ | `--allow-origin <pat>` | — | T2.4 ([#4514](https://github.com/QwenLM/qwen-code/issues/4514)). Cross-origin allowlist for browser webui clients. Repeatable. Each value is `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended so `/health` and `/demo` are also bearer-gated, since both are pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo / query). **Subdomain wildcards (`https://*.example.com`) are intentionally unsupported** — list each subdomain explicitly, or use `*` with a configured token (and `--require-auth` for full hardening). Matched origins receive CORS response headers (`Access-Control-Allow-Origin`, `Vary: Origin`, methods, headers, max-age, and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as today's wall. `Origin: null` (sandboxed iframes, file:// docs) is always rejected, even under `*`. Pre-flight via `caps.features.allow_origin`. Loopback self-origin hits are unaffected. |
219
221
 
220
222
  > **Sizing the load knobs.** `--max-sessions` is the **new-child** cap.
221
223
  > Three other layers also limit load — when sizing for a high-concurrency
@@ -226,14 +228,19 @@ The token comparison is constant-time (SHA-256 + `crypto.timingSafeEqual`); 401
226
228
  > - **per-session subscribers**: the EventBus caps SSE subscribers at
227
229
  > 64 per session by default; the 65th client gets a terminal
228
230
  > `stream_error` and is closed.
231
+ > - **per-session prompt admissions**:
232
+ > `--max-pending-prompts-per-session=5` bounds queued + active prompts
233
+ > accepted for one session. Overflow gets `503` with `Retry-After: 5`.
229
234
  > - **per-subscriber backlog**: a 256-frame queue per SSE client; an
230
235
  > over-capacity client gets a terminal `client_evicted` frame and is
231
236
  > closed (one slow consumer can't pin the daemon).
232
237
  >
233
- > The four caps interact: `--max-sessions × 64 subscribers × 256 frames`
234
- > is the worst-case in-flight memory at the EventBus layer. Default
235
- > sizing assumes single-user / small-team load; raise progressively
236
- > (and watch RSS) for multi-tenant deployments.
238
+ > These caps interact: `--max-sessions × 64 subscribers × 256 frames`
239
+ > is the worst-case in-flight memory at the EventBus layer, while
240
+ > `--max-sessions × --max-pending-prompts-per-session` bounds accepted
241
+ > prompt work at the admission layer. Default sizing assumes single-user /
242
+ > small-team load; raise progressively (and watch RSS) for multi-tenant
243
+ > deployments.
237
244
 
238
245
  > **MCP client guardrails (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14).** A workspace declaring 30 MCP servers in `mcpServers` will start 30 clients with no upstream cap unless you set one. `--mcp-client-budget=N` caps the live MCP client count; `--mcp-budget-mode={enforce,warn,off}` chooses the behavior. Default is `warn` when a budget is set (snapshot surfaces the warning but no client is refused — useful for measuring real-world fanout before flipping on enforcement). Refused servers under `enforce` mode get `disabledReason: 'budget'` on their per-server cell, and the `budgets[0]` cell shows `status: 'error'` + `errorKind: 'budget_exhausted'`. Slot reservation is by server name and survives reconnects / discovery timeouts — a refused server can't take a slot from a healthy one.
239
246
  >
@@ -258,6 +265,7 @@ The token comparison is constant-time (SHA-256 + `crypto.timingSafeEqual`); 401
258
265
  - **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` and `/demo` remain pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the `/demo` page) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
259
266
  - **Spawned `qwen --acp` child inherits the daemon's environment** with one explicit scrub: `QWEN_SERVER_TOKEN` is removed before the child starts (the daemon's own bearer; the agent doesn't need it). Everything else — `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `QWEN_*` / `DASHSCOPE_API_KEY` / your custom `modelProviders[].envKey` / etc. — passes through, because the agent legitimately needs those to authenticate to the LLM. **This is intentional, not a sandbox.** The agent runs as the same UID with shell-tool access, so anything in `~/.bashrc` / `~/.aws/credentials` / `~/.npmrc` is reachable by prompt injection regardless. The env passthrough is not the security boundary; the user-as-trust-root is. Don't run `qwen serve` under an identity that has env-resident credentials you wouldn't trust the agent with.
260
267
  - **Per-subscriber bounded SSE queues** — a slow client that overflows its queue gets a `client_evicted` terminal frame and is closed; one stuck consumer can't pin the daemon.
268
+ - **Per-session prompt admission cap** — defaults to 5 accepted-but-unsettled prompts per session. A buggy client cannot enqueue unbounded prompt promises or temporary SSE waits for one session.
261
269
  - **Graceful shutdown** — SIGINT/SIGTERM drain the agent children before closing the listener (10s deadline per child).
262
270
 
263
271
  > ⚠️ **Stage 1 known gap — permissions are daemon-global, not per-session (BUy4H).** `pendingPermissions` lives at daemon scope; any client holding the bearer token can vote on any `requestId` for any session it can see (and SSE `permission_request` events carry the requestId in their payload). This is acceptable under the single-user / small-team trust model where every authenticated client is the same human or collaborators they trust. Stage 1.5 will move to `POST /session/:id/permission/:requestId` + session-scoped pending map + per-client identity (must-have #3 from the downstream review); until then, don't run `qwen serve` behind a bearer shared with untrusted parties.
@@ -7,39 +7,40 @@ import {
7
7
  hasRebuiltToolRegistry,
8
8
  rebuildToolRegistryOnOverride,
9
9
  resolveSubagentApprovalMode
10
- } from "./chunk-IWAYOW5Q.js";
10
+ } from "./chunk-6T7Y7USE.js";
11
11
  import "./chunk-K5PGHDBN.js";
12
- import "./chunk-SKBPNJEW.js";
13
- import "./chunk-HLPLOD42.js";
12
+ import "./chunk-HQUWWSSP.js";
14
13
  import "./chunk-O4PICXES.js";
15
14
  import "./chunk-TW522KN6.js";
16
- import "./chunk-3DHXZ6EV.js";
17
- import "./chunk-XBY7E2FX.js";
18
- import "./chunk-J5MDQKJL.js";
15
+ import "./chunk-BJ5HQ23U.js";
16
+ import "./chunk-SFRV6BGY.js";
17
+ import "./chunk-ZOFNJQNJ.js";
18
+ import "./chunk-WPTCDQN6.js";
19
+ import "./chunk-OMX7CUOE.js";
19
20
  import "./chunk-MLZQVCF3.js";
20
21
  import "./chunk-LD2XBG6Z.js";
21
- import "./chunk-OHEGWO4L.js";
22
- import "./chunk-SNGELLWX.js";
22
+ import "./chunk-CPVI5J2L.js";
23
+ import "./chunk-ZMIBJS45.js";
23
24
  import "./chunk-77WXWU44.js";
24
- import "./chunk-A7B4ISQP.js";
25
- import "./chunk-6YIUGZTC.js";
25
+ import "./chunk-B4ZF2KSI.js";
26
+ import "./chunk-RON7LFNH.js";
26
27
  import "./chunk-3PJXIDKI.js";
27
28
  import "./chunk-UWCTAVOD.js";
28
29
  import "./chunk-OFEVLU4C.js";
29
- import "./chunk-3HTIVKZE.js";
30
- import "./chunk-IDX6COTE.js";
31
- import "./chunk-BIVG75CP.js";
32
- import "./chunk-XV4HCEVI.js";
33
- import "./chunk-2Y5SYSD3.js";
34
- import "./chunk-SEGYWKIH.js";
30
+ import "./chunk-IQHSD7K5.js";
31
+ import "./chunk-LYRSMKLS.js";
32
+ import "./chunk-QILTEBWS.js";
33
+ import "./chunk-A2ZIEEGJ.js";
34
+ import "./chunk-IDYDPBBN.js";
35
+ import "./chunk-FIQECJTQ.js";
35
36
  import "./chunk-64WXLC72.js";
36
- import "./chunk-B7HXHOHU.js";
37
- import "./chunk-EYENRK4D.js";
38
- import "./chunk-M6VTDSVR.js";
37
+ import "./chunk-LXYWINWF.js";
38
+ import "./chunk-NNIYWQIS.js";
39
+ import "./chunk-LYSND7KR.js";
39
40
  import "./chunk-55ZMG67I.js";
40
41
  import "./chunk-H6BD2ELD.js";
41
42
  import "./chunk-5IFG2VC4.js";
42
- import "./chunk-HR7SV7AY.js";
43
+ import "./chunk-HA2UEYZP.js";
43
44
  import "./chunk-ZERZSAZL.js";
44
45
  import "./chunk-QN5NZ3UQ.js";
45
46
  import "./chunk-BR4QREVK.js";