@mmmbuto/qwen-code-termux 0.16.1-termux → 0.18.0-termux
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 +79 -109
- package/bundled/new-app/SKILL.md +22 -0
- package/bundled/qc-helper/SKILL.md +29 -24
- package/bundled/qc-helper/docs/_meta.ts +1 -0
- package/bundled/qc-helper/docs/configuration/_meta.ts +0 -3
- package/bundled/qc-helper/docs/configuration/settings.md +37 -31
- package/bundled/qc-helper/docs/configuration/themes.md +39 -0
- package/bundled/qc-helper/docs/features/_meta.ts +1 -3
- package/bundled/qc-helper/docs/features/approval-mode.md +35 -35
- package/bundled/qc-helper/docs/features/auto-mode.md +54 -9
- package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/feishu.md +170 -0
- package/bundled/qc-helper/docs/features/commands.md +115 -35
- package/bundled/qc-helper/docs/features/followup-suggestions.md +2 -2
- package/bundled/qc-helper/docs/features/headless.md +32 -0
- package/bundled/qc-helper/docs/features/markdown-rendering.md +21 -1
- package/bundled/qc-helper/docs/features/memory.md +22 -5
- package/bundled/qc-helper/docs/features/scheduled-tasks.md +1 -1
- package/bundled/qc-helper/docs/features/status-line.md +168 -32
- package/bundled/qc-helper/docs/features/sub-agents.md +60 -0
- package/bundled/qc-helper/docs/features/worktree.md +345 -0
- package/bundled/qc-helper/docs/overview.md +4 -4
- package/bundled/qc-helper/docs/quickstart.md +4 -4
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +221 -0
- package/bundled/qc-helper/docs/qwen-serve.md +234 -24
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +16 -0
- package/bundled/qc-helper/docs/support/Uninstall.md +19 -1
- package/bundled/qc-helper/docs/support/troubleshooting.md +2 -1
- package/bundled/simplify/SKILL.md +123 -0
- package/chunks/agent-IDS4HMOX.js +56 -0
- package/chunks/agent-headless-5Q2EUSPS.js +50 -0
- package/chunks/{anthropicContentGenerator-SSGKR6DO.js → anthropicContentGenerator-2HBRNQ3B.js} +52 -9
- package/chunks/{askUserQuestion-PJWUUXKN.js → askUserQuestion-75TDJVK2.js} +45 -3
- package/chunks/{ca-UZ7BANMN.js → ca-BARBRL6N.js} +89 -5
- package/chunks/{chunk-GGNTZ2NH.js → chunk-2Y5SYSD3.js} +368 -597
- package/chunks/{chunk-2LA2TREA.js → chunk-3AA2DK35.js} +1448 -207
- package/chunks/{chunk-I2V5WXHJ.js → chunk-3AUHFMSK.js} +80 -38
- package/chunks/chunk-3DHXZ6EV.js +241 -0
- package/chunks/{chunk-PR4T27R7.js → chunk-3HTIVKZE.js} +42 -8
- package/chunks/chunk-3HX5LZ6R.js +1798 -0
- package/chunks/chunk-3PJXIDKI.js +2517 -0
- package/chunks/{chunk-MYAKAFEC.js → chunk-55ZMG67I.js} +7451 -3517
- package/chunks/{chunk-66CXYE4B.js → chunk-5IFG2VC4.js} +293 -242
- package/chunks/chunk-64WXLC72.js +98 -0
- package/chunks/{chunk-C6WMLUNB.js → chunk-72LDN5PP.js} +1 -1
- package/chunks/{chunk-F23NCRJ2.js → chunk-A7B4ISQP.js} +1 -1
- package/chunks/chunk-B7HXHOHU.js +393 -0
- package/chunks/{chunk-XEGHDASV.js → chunk-D3RHSPAS.js} +435 -540
- package/chunks/{chunk-XKS5KBFJ.js → chunk-EYENRK4D.js} +694 -384
- package/chunks/chunk-H6BD2ELD.js +36 -0
- package/chunks/{chunk-XP27SJMH.js → chunk-HR7SV7AY.js} +79 -48
- package/chunks/{chunk-D5NTAHYL.js → chunk-IDX6COTE.js} +7 -2
- package/chunks/{chunk-SHT4VJWU.js → chunk-IWKSG2AR.js} +2 -2
- package/chunks/chunk-J37FGIOA.js +1623 -0
- package/chunks/chunk-J5MDQKJL.js +2230 -0
- package/chunks/{chunk-USE2VQ5P.js → chunk-JTQAQBTV.js} +21 -0
- package/chunks/{chunk-NCTLV2NB.js → chunk-KQJMQJPI.js} +1 -1
- package/chunks/{chunk-5FBA5XC2.js → chunk-KRIHGKNA.js} +1 -1
- package/chunks/chunk-LD2XBG6Z.js +102 -0
- package/chunks/{chunk-MAY32HXD.js → chunk-M6VTDSVR.js} +3 -1
- package/chunks/chunk-MRO43B25.js +30 -0
- package/chunks/{chunk-N4WOREMD.js → chunk-NVFMZBX2.js} +43 -3
- package/chunks/chunk-OHEGWO4L.js +264 -0
- package/chunks/{chunk-K6O2NBMF.js → chunk-OQ7NJIY7.js} +4604 -6397
- package/chunks/chunk-QQDPRDVW.js +25 -0
- package/chunks/{chunk-KXZ4TJB4.js → chunk-SEGYWKIH.js} +1 -1
- package/chunks/chunk-SKBPNJEW.js +45 -0
- package/chunks/{chunk-4AOCVI6J.js → chunk-SNGELLWX.js} +52 -6
- package/chunks/{chunk-3OCRHZA3.js → chunk-TD4OPI4T.js} +56742 -44104
- package/chunks/{chunk-DQ4QTG7E.js → chunk-VV4F63BD.js} +11 -11
- package/chunks/chunk-XBY7E2FX.js +605 -0
- package/chunks/{chunk-JKMBWLFB.js → chunk-YILFYI5W.js} +48 -26
- package/chunks/chunk-YOGAOMYB.js +159 -0
- package/chunks/{chunk-QWSRH265.js → chunk-Z2Z3GUXZ.js} +777 -776
- package/chunks/{chunk-SDHRQFOS.js → chunk-ZTZ4DDQE.js} +2 -2
- package/chunks/computer-use-W2TYQNEE.js +825 -0
- package/chunks/contextCommand-6FGX3A7J.js +52 -0
- package/chunks/{cron-create-3ZBBN7WB.js → cron-create-APL5LU6I.js} +3 -3
- package/chunks/{cron-delete-NAGKKIIG.js → cron-delete-4SBJSCN4.js} +3 -3
- package/chunks/{cron-list-PAGRXNAI.js → cron-list-2AMGOMVO.js} +3 -3
- package/chunks/{de-V4IE2OOZ.js → de-YGKK2BC4.js} +89 -5
- package/chunks/{devtools-TWVXEJQB.js → devtools-FM6GJPYG.js} +2 -1
- package/chunks/{dist-4L54HRX2.js → dist-4LXD6L6X.js} +24 -5
- package/chunks/dist-H6ONXVLG.js +94146 -0
- package/chunks/{dist-XKWIWPWQ.js → dist-KAZ3SEBX.js} +1083 -3856
- package/chunks/{dist-BXDUQ2QY.js → dist-PK7DFCAW.js} +1 -1
- package/chunks/{edit-NVO3FOAK.js → edit-ZCEZC264.js} +30 -22
- package/chunks/{en-HGJ2SPLM.js → en-DHGYHIHX.js} +127 -6
- package/chunks/{enter-worktree-UEBG4WFC.js → enter-worktree-BBHCFCHG.js} +30 -20
- package/chunks/enterPlanMode-3M6KTD3B.js +158 -0
- package/chunks/{exit-worktree-UZ3MAQZN.js → exit-worktree-73YPIEQO.js} +27 -19
- package/chunks/exitPlanMode-TYZM6BAE.js +703 -0
- package/chunks/{fr-CJULI7ZX.js → fr-JXBKPJKQ.js} +89 -5
- package/chunks/{geminiContentGenerator-3UZFXGNT.js → geminiContentGenerator-7N2V3VW2.js} +8 -6
- package/chunks/{getMachineId-bsd-JXOSIJV2.js → getMachineId-bsd-4CASPIU4.js} +4 -4
- package/chunks/{getMachineId-darwin-TE4QRR42.js → getMachineId-darwin-HPQPEMZR.js} +4 -4
- package/chunks/{getMachineId-linux-S3OL52XK.js → getMachineId-linux-AUARKYHL.js} +3 -3
- package/chunks/{getMachineId-unsupported-DWUSBAPX.js → getMachineId-unsupported-S32ZDA2T.js} +3 -3
- package/chunks/{getMachineId-win-AAC5P3AP.js → getMachineId-win-4EFLHYIJ.js} +4 -4
- package/chunks/{glob-KNHSFFFG.js → glob-5XBCPQ2A.js} +27 -19
- package/chunks/{grep-LACWDZW4.js → grep-VIUU3A7X.js} +30 -19
- package/chunks/{ja-L7CHRQEW.js → ja-TGPZSP2B.js} +89 -5
- package/chunks/{keychain-token-storage-335UOLJ6.js → keychain-token-storage-6IU6ORQN.js} +3 -3
- package/chunks/{ls-AGXQOKSG.js → ls-JRGYIGLY.js} +4 -4
- package/chunks/{lsp-UDMUHNPA.js → lsp-SHMKFOAC.js} +3 -3
- package/chunks/{monitor-ETKWPJEH.js → monitor-6R4LIJL5.js} +40 -25
- package/chunks/{multipart-parser-3QWGTLK3.js → multipart-parser-AJ4WASWR.js} +2 -2
- package/chunks/{notebook-edit-QJJLPNYT.js → notebook-edit-5E7ULDVQ.js} +28 -20
- package/chunks/{openaiContentGenerator-CNNN424U.js → openaiContentGenerator-ZVHFKM3O.js} +17 -14
- package/chunks/{pt-M6JULLEQ.js → pt-TIBG6BIO.js} +89 -5
- package/chunks/{qwenContentGenerator-BOLCGK3R.js → qwenContentGenerator-B2VTVSPJ.js} +31 -23
- package/chunks/{qwenOAuth2-EEJGROP7.js → qwenOAuth2-2KCKWDCF.js} +6 -4
- package/chunks/read-file-GIT7BCDR.js +27 -0
- package/chunks/ripGrep-MWKFVYMS.js +48 -0
- package/chunks/{ru-QILM4HBC.js → ru-JBCHCK4L.js} +89 -5
- package/chunks/scheduler-5VOOYGBH.js +308 -0
- package/chunks/send-message-4QNWQJF4.js +244 -0
- package/chunks/{serve-OLSI7WSR.js → serve-MN6HZBWN.js} +14262 -7414
- package/chunks/shell-NQZQGFM2.js +56 -0
- package/chunks/{skill-D6YRHTTI.js → skill-WCFW4644.js} +145 -119
- package/chunks/{src-TMOD5X6F.js → src-7XL4G4DC.js} +88 -46
- package/chunks/{src-4QH4FZ6I.js → src-IHA6DTUV.js} +452 -62
- package/chunks/{syntheticOutput-5PVFDDJ4.js → syntheticOutput-YTYS2ZMQ.js} +4 -4
- package/chunks/task-create-MPORPYN6.js +19 -0
- package/chunks/task-list-R2YDYPZT.js +151 -0
- package/chunks/{task-stop-AJKPSR6R.js → task-stop-SYWJYBCM.js} +3 -3
- package/chunks/task-update-E4NSLKMQ.js +408 -0
- package/chunks/team-create-7R7KA5IP.js +314 -0
- package/chunks/team-delete-25OIWUPN.js +116 -0
- package/chunks/{todoWrite-VLAUG4CA.js → todoWrite-4YHMIF4X.js} +16 -5
- package/chunks/{tool-search-MZGHUUKD.js → tool-search-YBRVZCLI.js} +29 -11
- package/chunks/{tts-notification-K3X7X7MN.js → tts-notification-7SOEMQK4.js} +5 -4
- package/chunks/{web-fetch-OILB464A.js → web-fetch-MFIRHIHI.js} +5 -5
- package/chunks/workflow-5RIKVCIE.js +960 -0
- package/chunks/{write-file-BIQAA57V.js → write-file-DMQTJZOM.js} +32 -24
- package/chunks/{zh-PWL2NKY3.js → zh-7H5OQC4I.js} +135 -11
- package/chunks/{zh-TW-S3YGWICZ.js → zh-TW-P4IDHD3M.js} +128 -11
- package/cli.js +45402 -20570
- package/examples/agent/agents/diary.md +86 -0
- package/examples/agent/qwen-extension.json +5 -0
- package/examples/commands/commands/fs/grep-code.md +3 -0
- package/examples/commands/qwen-extension.json +5 -0
- package/examples/context/QWEN.md +8 -0
- package/examples/context/qwen-extension.json +5 -0
- package/examples/mcp-server/example.ts +60 -0
- package/examples/mcp-server/package.json +18 -0
- package/examples/mcp-server/qwen-extension.json +12 -0
- package/examples/mcp-server/tsconfig.json +13 -0
- package/examples/skills/qwen-extension.json +5 -0
- package/examples/skills/skills/synonyms/SKILL.md +48 -0
- package/examples/starter/QWEN.md +30 -0
- package/examples/starter/README.md +59 -0
- package/examples/starter/agents/diary.md +86 -0
- package/examples/starter/commands/writing/polish.md +13 -0
- package/examples/starter/example.ts +64 -0
- package/examples/starter/package.json +18 -0
- package/examples/starter/qwen-extension.json +12 -0
- package/examples/starter/skills/synonyms/SKILL.md +48 -0
- package/examples/starter/tsconfig.json +13 -0
- package/fzfWorker.js +1083 -0
- package/locales/ca.js +118 -5
- package/locales/de.js +117 -5
- package/locales/en.js +169 -7
- package/locales/fr.js +119 -5
- package/locales/ja.js +114 -5
- package/locales/pt.js +117 -5
- package/locales/ru.js +116 -5
- package/locales/zh-TW.js +161 -12
- package/locales/zh.js +169 -12
- package/package.json +4 -2
- package/scripts/postinstall.cjs +2 -1
- package/bundled/qc-helper/docs/features/checkpointing.md +0 -77
- package/chunks/agent-7ZN3CRHR.js +0 -48
- package/chunks/chunk-6PCB2DEF.js +0 -434
- package/chunks/chunk-EM6ETG2K.js +0 -60
- package/chunks/chunk-G7YTSRES.js +0 -150
- package/chunks/contextCommand-7IBASARL.js +0 -44
- package/chunks/exitPlanMode-PZAMWIRW.js +0 -227
- package/chunks/multipart-parser-IXGBIOIN.js +0 -384
- package/chunks/read-file-CCUEUFG2.js +0 -24
- package/chunks/ripGrep-TADOH2HK.js +0 -40
- package/chunks/send-message-YL44UZFC.js +0 -151
- package/chunks/shell-7KKKC5G7.js +0 -48
- package/chunks/src-IPWIHNMI.js +0 -1406
- package/chunks/undici-F6ZOXSS5.js +0 -8
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Run Qwen Code as a local HTTP daemon so multiple clients (IDE plugins, web UIs, CI scripts, custom CLIs) share one agent session over HTTP + Server-Sent Events instead of each spawning their own subprocess.
|
|
4
4
|
|
|
5
|
+
> **🚧 v0.16-alpha**: `qwen serve` first ships to npm in v0.16-alpha as **text-only chat / coding** with **local-only deployment**. Image / file attachments on the prompt path, containerized deployment (Docker / k8s / nginx reverse-proxy), and remote / multi-daemon hardening land in a follow-up patch when an enterprise pilot is committed. See [v0.16-alpha known limits](#v016-alpha-known-limits) for the full deferred list.
|
|
6
|
+
|
|
5
7
|
> **Status:** Stage 1 (experimental). The protocol surface is locked at the §04 routes table from issue [#3803](https://github.com/QwenLM/qwen-code/issues/3803). Stage 1.5 (`qwen --serve` flag — TUI co-hosts the same HTTP server) and Stage 2 (in-process refactor + `mDNS`/OpenAPI/WebSocket/Prometheus polish) are immediately downstream.
|
|
6
8
|
>
|
|
7
9
|
> **Scope honesty:** Stage 1 is sized for **developers prototyping clients against the protocol surface** and for **local single-user / small-team collaboration**. Production-grade multi-client / long-running / network-flaky workloads (mobile companions, IM bots reaching 1000+ chats) need Stage 1.5+ guarantees that aren't in this release. See [Stage 1.5+ runtime guarantees](#stage-15-runtime-guarantees) for the full gap list and #3803 for the convergence roadmap.
|
|
@@ -12,7 +14,40 @@ Run Qwen Code as a local HTTP daemon so multiple clients (IDE plugins, web UIs,
|
|
|
12
14
|
- **Reconnect-safe streaming** — SSE with `Last-Event-ID` reconnect lets a client drop and pick up exactly where it left off (within the ring's replay window).
|
|
13
15
|
- **First-responder permissions** — when the agent asks for permission to run a tool, every connected client sees the request; whichever client answers first wins.
|
|
14
16
|
- **One daemon, one workspace** — each `qwen serve` process binds to exactly one workspace at boot (per [#3803](https://github.com/QwenLM/qwen-code/issues/3803) §02). Multi-workspace deployments run one daemon per workspace on separate ports (or behind an orchestrator).
|
|
15
|
-
- **Remote runtime control** ([#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 17) — change a session's approval mode (`POST /session/:id/approval-mode`), toggle a tool per workspace (`POST /workspace/tools/:name/enable`), scaffold an empty `QWEN.md` (`POST /workspace/init`, mechanical only — does NOT call the model; for AI-fill, follow up with `POST /session/:id/prompt`),
|
|
17
|
+
- **Remote runtime control** ([#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 17) — change a session's approval mode (`POST /session/:id/approval-mode`), toggle a tool per workspace (`POST /workspace/tools/:name/enable`), scaffold an empty `QWEN.md` (`POST /workspace/init`, mechanical only — does NOT call the model; for AI-fill, follow up with `POST /session/:id/prompt`), restart a single MCP server with a budget pre-check (`POST /workspace/mcp/:server/restart`), or add/remove MCP servers at runtime without a daemon restart (`POST /workspace/mcp/servers`, `DELETE /workspace/mcp/servers/:name`). All strict-gated — configure `--token` first.
|
|
18
|
+
- **Session recap** ([#4175](https://github.com/QwenLM/qwen-code/issues/4175) follow-up) — fetch a one-sentence "where did I leave off" summary of an active session (`POST /session/:id/recap`). Wraps core's `generateSessionRecap` as a side-query against the fast model; pollutes neither the main chat history nor the SSE stream. Non-strict gate (same posture as `/prompt`); SDK helper `client.recapSession(sessionId)`.
|
|
19
|
+
- **Known limit — token-cost amplification:** the route is a pure-cost endpoint (each call is an LLM side-query, no state benefit) and the daemon has no per-route rate limit in v1. On a no-token loopback default a buggy or malicious local client can spam it to burn tokens. Configure `--token` (and optionally `--require-auth`) on shared dev hosts before exposing the daemon.
|
|
20
|
+
- **Concurrent recap safety:** two simultaneous `/recap` calls on the same session run two independent side-queries. `generateSessionRecap` reads a snapshot of the chat history via `GeminiClient.getChat().getHistory()` and feeds it to a separate `BaseLlmClient.generateText` call (via `runSideQuery`); it never appends to or mutates the session's `GeminiChat`. Safe to call from multiple clients without coordination.
|
|
21
|
+
|
|
22
|
+
## v0.16-alpha known limits
|
|
23
|
+
|
|
24
|
+
The first npm release of `qwen serve` (v0.16-alpha) is intentionally narrow — text-only chat / coding for developers running the daemon on their own machine. The list below makes the deferred surface explicit so adopters can plan around it; everything here is on the v0.16.x patch roadmap or a near-term follow-up release.
|
|
25
|
+
|
|
26
|
+
**Product surface — text-only:**
|
|
27
|
+
|
|
28
|
+
- ✅ Text prompts and text responses (chat, coding, tool calls, MCP integration)
|
|
29
|
+
- ❌ **Image / file attachments on the prompt path** — `MessageEmitter` currently only renders text; multimodal echo lands when an alpha target with image needs is committed (#4175 chiga0 #27 P0 item)
|
|
30
|
+
- ❌ **Streaming uploads** — same gating as multimodal
|
|
31
|
+
|
|
32
|
+
**Deployment surface — local-only:**
|
|
33
|
+
|
|
34
|
+
- ✅ Loopback (`127.0.0.1`, default) — no auth required, suitable for dev workstations
|
|
35
|
+
- ✅ Local launch via `systemd` / `launchd` / `nohup &` / `tmux` — see [Local launch templates](./qwen-serve-deploy-local.md)
|
|
36
|
+
- ✅ Bring-your-own bearer token via `QWEN_SERVER_TOKEN` env var ([Authentication](#authentication) for setup)
|
|
37
|
+
- ❌ **Containerized deployment** — Docker / Compose / Kubernetes / nginx reverse-proxy with TLS termination NOT in v0.16-alpha. Defers to v0.16.x once an enterprise pilot is committed (would otherwise rot from no-one-validating).
|
|
38
|
+
- ❌ **Multi-daemon coordination on one host** — `1 daemon = 1 workspace × N sessions` is enforced. Cross-host federation, instance-path token keying, and stale-token cleanup defer to v0.16.x.
|
|
39
|
+
- ❌ **Auto-generated daemon tokens** — alpha is BYO-token (one `openssl rand -hex 32` away). Auto-gen + token-store infrastructure defers to v0.16.x.
|
|
40
|
+
|
|
41
|
+
**Hardening — minimum viable for local single-user:**
|
|
42
|
+
|
|
43
|
+
- ✅ Boot-time security gate (refuses non-loopback bind without a token, [PR 15 / #4236](https://github.com/QwenLM/qwen-code/pull/4236))
|
|
44
|
+
- ✅ Mutation-route auth gate, session-scoped permission routing (Wave 4 PRs)
|
|
45
|
+
- ✅ MCP guardrails + multi-client permission coordination (F2 / F3)
|
|
46
|
+
- ⏸️ **Prompt absolute deadline + SSE writer idle timeout** — current AbortSignal + 15s heartbeat + `res.on('error')` cleanup is sufficient for local dev; explicit application-layer deadlines defer to v0.16.x once a remote / long-running scenario lands.
|
|
47
|
+
- ⏸️ **Rate limiting + observability + load test harness** — defers to v0.17 F4 Phase-1 scale instrumentation when 30-50 active sessions becomes a real target.
|
|
48
|
+
- ⏸️ **`--max-body-size` CLI flag** — daemon enforces `express.json({ limit: '10mb' })` by default which comfortably covers text-only prompts (model context windows are well under 10 MiB of chars). Tunable via flag in v0.16.x.
|
|
49
|
+
|
|
50
|
+
For the deeper "what we won't fix in Stage 1" enumeration (single-host session-state mutation model + N-parallel-sessions sharing one ACP child), see [Stage 1 scope boundaries](#stage-1-scope-boundaries--what-we-wont-fix-in-stage-15) below.
|
|
16
51
|
|
|
17
52
|
## Quickstart
|
|
18
53
|
|
|
@@ -42,7 +77,8 @@ The `workspaceCwd` field surfaces the bound workspace so clients can pre-flight
|
|
|
42
77
|
The daemon also exposes read-only runtime snapshots for client UIs:
|
|
43
78
|
`GET /workspace/mcp`, `GET /workspace/skills`, `GET /workspace/providers`,
|
|
44
79
|
`GET /workspace/env`, `GET /workspace/preflight`,
|
|
45
|
-
`GET /session/:id/context`,
|
|
80
|
+
`GET /session/:id/context`, `GET /session/:id/supported-commands`, and
|
|
81
|
+
`GET /session/:id/tasks`.
|
|
46
82
|
|
|
47
83
|
`GET /workspace/mcp`, `GET /workspace/skills`, and `GET /workspace/providers`
|
|
48
84
|
report the live ACP runtime and do not start the ACP child when idle; an
|
|
@@ -166,19 +202,20 @@ The token comparison is constant-time (SHA-256 + `crypto.timingSafeEqual`); 401
|
|
|
166
202
|
|
|
167
203
|
## CLI flags
|
|
168
204
|
|
|
169
|
-
| Flag | Default | Purpose
|
|
170
|
-
| ------------------------- | --------------- |
|
|
171
|
-
| `--port <n>` | `4170` | TCP port. `0` = OS-assigned ephemeral port.
|
|
172
|
-
| `--hostname <addr>` | `127.0.0.1` | Bind interface. Anything beyond loopback requires a token.
|
|
173
|
-
| `--token <str>` | — | Bearer token. Falls back to `QWEN_SERVER_TOKEN` env var (with leading/trailing whitespace stripped — handy for `$(cat token.txt)`).
|
|
174
|
-
| `--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.
|
|
175
|
-
| `--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).
|
|
176
|
-
| `--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.
|
|
177
|
-
| `--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.
|
|
178
|
-
| `--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`.
|
|
179
|
-
| `--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`.
|
|
180
|
-
| `--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.
|
|
181
|
-
| `--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.
|
|
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. |
|
|
182
219
|
|
|
183
220
|
> **Sizing the load knobs.** `--max-sessions` is the **new-child** cap.
|
|
184
221
|
> Three other layers also limit load — when sizing for a high-concurrency
|
|
@@ -218,7 +255,7 @@ The token comparison is constant-time (SHA-256 + `crypto.timingSafeEqual`); 401
|
|
|
218
255
|
- **`--hostname 0.0.0.0` requires a token** — boot refuses without one.
|
|
219
256
|
- **`LOOPBACK_BINDS` includes IPv6** — `::1` and `[::1]` count as loopback for the no-token rule.
|
|
220
257
|
- **Host header allowlist** — on **loopback** binds the daemon checks `Host:` matches `localhost:port` / `127.0.0.1:port` / `[::1]:port` / `host.docker.internal:port` (case-insensitive per RFC 7230 §5.4) to defend against DNS rebinding. **Non-loopback binds (`--hostname 0.0.0.0`) intentionally bypass the Host allowlist** — the operator has chosen the surface area, so the bearer-token gate is the sole authentication layer; reverse proxies / SNI / client cert pinning are the operator's responsibility, not the daemon's. If you need Host-based isolation on a non-loopback bind, terminate TLS + check Host at a front proxy.
|
|
221
|
-
- **CORS denies any browser Origin** — returns `403` JSON.
|
|
258
|
+
- **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.
|
|
222
259
|
- **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.
|
|
223
260
|
- **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.
|
|
224
261
|
- **Graceful shutdown** — SIGINT/SIGTERM drain the agent children before closing the listener (10s deadline per child).
|
|
@@ -234,11 +271,31 @@ The token comparison is constant-time (SHA-256 + `crypto.timingSafeEqual`); 401
|
|
|
234
271
|
> "alive" until Node's keepalive probes time out — typically ~2 hours
|
|
235
272
|
> on Linux defaults. On `--hostname 0.0.0.0` deployments behind such
|
|
236
273
|
> NATs, phantom SSE connections can accumulate and eventually hit the
|
|
237
|
-
> 256 `server.maxConnections` ceiling.
|
|
238
|
-
>
|
|
239
|
-
>
|
|
240
|
-
>
|
|
241
|
-
>
|
|
274
|
+
> 256 `server.maxConnections` ceiling.
|
|
275
|
+
>
|
|
276
|
+
> Set [`--writer-idle-timeout-ms <n>`](#deadlines-and-writer-idle-timeout)
|
|
277
|
+
> (issue [#4514](https://github.com/QwenLM/qwen-code/issues/4514) T2.9)
|
|
278
|
+
> to close the gap with an explicit application-level idle deadline:
|
|
279
|
+
> when no write has successfully flushed for `n` ms the daemon emits
|
|
280
|
+
> a terminal `client_evicted` frame with
|
|
281
|
+
> `reason: 'writer_idle_timeout'` and closes the stream. The flag is
|
|
282
|
+
> off by default to preserve the legacy contract — operators on
|
|
283
|
+
> networks that swallow RSTs should pick a value well above the 15s
|
|
284
|
+
> heartbeat interval (e.g. `60000`–`300000`) so legitimate idle
|
|
285
|
+
> connections aren't evicted while genuinely stuck writers are
|
|
286
|
+
> reaped promptly. Pre-flight `caps.features.includes('writer_idle_timeout')`
|
|
287
|
+
> from your SDK to confirm the daemon supports it.
|
|
288
|
+
|
|
289
|
+
### Deadlines and writer idle timeout
|
|
290
|
+
|
|
291
|
+
Issue [#4514](https://github.com/QwenLM/qwen-code/issues/4514) T2.9 ships two opt-in flags that close the long-running / remote-deployment gaps the 15s heartbeat + AbortSignal don't cover. Both are off by default — single-user loopback workflows stay bit-for-bit unchanged.
|
|
292
|
+
|
|
293
|
+
| Flag | Env var | Default | What it does |
|
|
294
|
+
| ------------------------------ | ----------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
295
|
+
| `--prompt-deadline-ms <n>` | `QWEN_SERVE_PROMPT_DEADLINE_MS` | unset | Server-side wallclock cap on a single `POST /session/:id/prompt`. On expiry the daemon aborts the prompt's AbortController and returns HTTP `504` with `{code:"prompt_deadline_exceeded", errorKind:"prompt_deadline_exceeded", deadlineMs:n}`. A per-prompt request body field `deadlineMs` can SHORTEN the effective deadline below the flag but never extend it. Capability tag (conditional): `prompt_absolute_deadline`. |
|
|
296
|
+
| `--writer-idle-timeout-ms <n>` | `QWEN_SERVE_WRITER_IDLE_TIMEOUT_MS` | unset | Per-SSE-connection idle deadline. When no write has SUCCESSFULLY flushed for `n` ms — neither a real event nor the 15s heartbeat — the daemon emits a terminal `client_evicted` frame with `data.reason = 'writer_idle_timeout'` (mirrored on `data.errorKind`) and closes the stream. **Pick a value comfortably above the 15s heartbeat** (e.g. `30000`–`300000`) so legitimate idle streams aren't evicted; values `< 15000` WILL evict otherwise-healthy idle connections before the first heartbeat fires (intentional only for tests / short-lived dev sessions). Capability tag (conditional): `writer_idle_timeout`. |
|
|
297
|
+
|
|
298
|
+
Both flags accept a positive integer in milliseconds; `0`, `NaN`, non-integer, or negative values are rejected at boot with a clear error message. CLI flag wins over env var; explicit `ServeOptions` field (embedded callers) wins over env. SDK consumers should pre-flight the matching capability tag before relying on either behavior — daemons predating this PR omit both tags and the request `deadlineMs` field is silently dropped.
|
|
242
299
|
|
|
243
300
|
## Multi-session & multi-workspace deployment
|
|
244
301
|
|
|
@@ -334,10 +391,10 @@ The Stage 1.5 plan describes TUI as an in-process EventBus subscriber. In practi
|
|
|
334
391
|
|
|
335
392
|
No TUI shell runs inside the daemon. The slash commands listed above **don't exist** in this mode — there's no terminal UI to issue them from. Session state is therefore:
|
|
336
393
|
|
|
337
|
-
- **Boot-time-frozen** for `approval-mode` / `memory` / `
|
|
338
|
-
- **Mutable over HTTP**
|
|
394
|
+
- **Boot-time-frozen** for `approval-mode` / `memory` / `agents` / `tools` allowlist / `auth` — all loaded from settings + disk when the daemon's `qwen --acp` child starts; immutable for the session's lifetime. Settings-defined MCP servers are likewise frozen at boot, but **runtime-added servers** (via `POST /workspace/mcp/servers`) can be added or removed without restart.
|
|
395
|
+
- **Mutable over HTTP** via `POST /session/:id/model` (publishes `model_switched`), `POST /workspace/mcp/servers` / `DELETE /workspace/mcp/servers/:name` (publishes `mcp_server_added` / `mcp_server_removed`), and permission votes (`POST /permission/:requestId`).
|
|
339
396
|
|
|
340
|
-
**Consequence:** remote clients in headless mode see the **full session state**. No TUI hides additional state; no drift is possible. If you want to change `approval-mode
|
|
397
|
+
**Consequence:** remote clients in headless mode see the **full session state**. No TUI hides additional state; no drift is possible. If you want to change `approval-mode`, restart the daemon with new settings. MCP servers can now be added/removed at runtime via the mutation routes (`POST /workspace/mcp/servers`, `DELETE /workspace/mcp/servers/:name`) — see [Runtime MCP server management](#runtime-mcp-server-management-issue-4514).
|
|
341
398
|
|
|
342
399
|
#### Mode 2 — Stage 1.5 `qwen --serve` co-hosted TUI (not in this PR)
|
|
343
400
|
|
|
@@ -424,8 +481,161 @@ const result = await flow.awaitCompletion({ signal: abortCtrl.signal });
|
|
|
424
481
|
|
|
425
482
|
**Cross-client take-over.** Two SDK clients on the same daemon that both `POST /workspace/auth/device-flow` for the same provider get the per-provider singleton: the first call starts a fresh IdP request and returns `attached: false`; the second call returns the EXISTING in-flight entry with `attached: true`. The take-over is recorded on the audit trail (under the second client's `X-Qwen-Client-Id`) but does NOT emit a separate event — both clients eventually observe the SAME `auth_device_flow_authorized` once the user finishes the IdP page. If your UI distinguishes "I started this" from "someone else's flow I joined", branch on the `attached` field returned by `start()`.
|
|
426
483
|
|
|
484
|
+
## Daemon log file
|
|
485
|
+
|
|
486
|
+
`qwen serve` writes a per-process diagnostic log to:
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
${QWEN_RUNTIME_DIR or ~/.qwen}/debug/daemon/serve-<pid>-<workspaceHash>.log
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
A `latest` symlink in the same directory always points at the current process's log, so `tail -f ~/.qwen/debug/daemon/latest` will follow whichever daemon is running.
|
|
493
|
+
|
|
494
|
+
The log captures lifecycle messages, route errors (with `route=` and `sessionId=` context), ACP child stderr, and — when `QWEN_SERVE_DEBUG=1` is set — extra bridge breadcrumbs. Lines that go to stderr today still go to stderr; the file log is **additive**, not a replacement.
|
|
495
|
+
|
|
496
|
+
### Disabling
|
|
497
|
+
|
|
498
|
+
Set `QWEN_DAEMON_LOG_FILE=0` (or `false`/`off`/`no`) to skip file logging entirely. Stderr output is unaffected.
|
|
499
|
+
|
|
500
|
+
### Relation to session debug logs
|
|
501
|
+
|
|
502
|
+
Session-scoped debug logs (`~/.qwen/debug/<sessionId>.txt` and the `~/.qwen/debug/latest` symlink) are independent. The daemon log lives in a sibling `daemon/` subdirectory; per-session debug semantics are unchanged by this feature.
|
|
503
|
+
|
|
504
|
+
### No rotation
|
|
505
|
+
|
|
506
|
+
The daemon log appends indefinitely. Rotate manually if it grows large. A future enhancement may add automatic rotation; track via [#4548](https://github.com/QwenLM/qwen-code/issues/4548) follow-ups.
|
|
507
|
+
|
|
508
|
+
## Runtime MCP server management (issue [#4514](https://github.com/QwenLM/qwen-code/issues/4514))
|
|
509
|
+
|
|
510
|
+
Add or remove MCP servers at runtime without restarting the daemon. Runtime entries live in an ephemeral overlay that **shadows** settings-defined servers of the same name; the underlying `settings.json` / `mcpServers` config is never written to.
|
|
511
|
+
|
|
512
|
+
**Pre-flight:** check `caps.features` for `mcp_server_runtime_mutation` before calling either route. Older daemons without this tag return `404`.
|
|
513
|
+
|
|
514
|
+
### `POST /workspace/mcp/servers` — add a runtime MCP server
|
|
515
|
+
|
|
516
|
+
Strict-gated (bearer token required). Connects the server immediately via the live `McpClientManager` and discovers its tools.
|
|
517
|
+
|
|
518
|
+
Request:
|
|
519
|
+
|
|
520
|
+
```json
|
|
521
|
+
{
|
|
522
|
+
"name": "my-server",
|
|
523
|
+
"config": {
|
|
524
|
+
"command": "npx",
|
|
525
|
+
"args": ["-y", "@my-org/mcp-server"]
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
`name` must be alphanumeric plus `_` and `-` (max 256 characters). `config` is the same MCP server configuration object used in `settings.json` `mcpServers` entries (transport-dependent fields: `command`/`args` for stdio, `url` for SSE/HTTP). Security-sensitive fields (`trust`, `env`, `cwd`, `oauth`, `headers`, `authProviderType`, `includeTools`, `excludeTools`, `type`) are stripped by the daemon and ignored.
|
|
531
|
+
|
|
532
|
+
Response (200) — success:
|
|
533
|
+
|
|
534
|
+
```json
|
|
535
|
+
{
|
|
536
|
+
"name": "my-server",
|
|
537
|
+
"transport": "stdio",
|
|
538
|
+
"replaced": false,
|
|
539
|
+
"shadowedSettings": false,
|
|
540
|
+
"toolCount": 3,
|
|
541
|
+
"originatorClientId": "client-1"
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
- `replaced: true` — a runtime entry with the same name already existed and the config fingerprint differs; old connection torn down, new one established. When the fingerprint matches (idempotent re-add), `replaced` is `false`.
|
|
546
|
+
- `shadowedSettings: true` — a settings-defined server with the same name exists; the runtime entry now shadows it. The settings entry is untouched and re-emerges if the runtime entry is later removed.
|
|
547
|
+
- `toolCount` — number of tools discovered on the newly connected server.
|
|
548
|
+
|
|
549
|
+
Response (200) — soft refuse (budget warning mode):
|
|
550
|
+
|
|
551
|
+
```json
|
|
552
|
+
{
|
|
553
|
+
"name": "my-server",
|
|
554
|
+
"skipped": true,
|
|
555
|
+
"reason": "budget_warning_only"
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
Returned when `--mcp-budget-mode=warn` and adding the server would exceed the configured `--mcp-client-budget`. The server is NOT connected. Callers should surface the budget pressure to the user.
|
|
560
|
+
|
|
561
|
+
Errors:
|
|
562
|
+
|
|
563
|
+
| Status | Code | When |
|
|
564
|
+
| ------ | ------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
565
|
+
| `400` | `invalid_server_name` | Name empty, exceeds 256 chars, or contains characters outside `[A-Za-z0-9_-]` |
|
|
566
|
+
| `400` | `missing_required_field` | `config` missing or not a non-null object |
|
|
567
|
+
| `400` | `invalid_client_id` | `X-Qwen-Client-Id` header present but not registered for this workspace |
|
|
568
|
+
| `400` | `invalid_config` | Config shape rejected by the MCP transport validator |
|
|
569
|
+
| `401` | `token_required` | No bearer token configured (strict gate) |
|
|
570
|
+
| `409` | `mcp_budget_would_exceed` | `--mcp-budget-mode=enforce` and budget is full |
|
|
571
|
+
| `502` | `mcp_server_spawn_failed` | Server process exited or timed out during connect; body carries `serverName`, `exitCode`, `stderr` |
|
|
572
|
+
| `503` | `acp_channel_unavailable` | No live ACP child (no session has been created yet) |
|
|
573
|
+
|
|
574
|
+
### `DELETE /workspace/mcp/servers/:name` — remove a runtime MCP server
|
|
575
|
+
|
|
576
|
+
Strict-gated. Disconnects the server and removes it from the runtime overlay. Idempotent — removing a name that was never added returns a skip response (not an error).
|
|
577
|
+
|
|
578
|
+
The `:name` path parameter is the URL-encoded server name.
|
|
579
|
+
|
|
580
|
+
Response (200) — success:
|
|
581
|
+
|
|
582
|
+
```json
|
|
583
|
+
{
|
|
584
|
+
"name": "my-server",
|
|
585
|
+
"removed": true,
|
|
586
|
+
"wasShadowingSettings": false,
|
|
587
|
+
"originatorClientId": "client-1"
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
- `wasShadowingSettings: true` — the removed runtime entry was shadowing a settings-defined server of the same name. That settings entry is now un-shadowed and will be used on next discovery/restart.
|
|
592
|
+
|
|
593
|
+
Response (200) — idempotent skip:
|
|
594
|
+
|
|
595
|
+
```json
|
|
596
|
+
{
|
|
597
|
+
"name": "ghost",
|
|
598
|
+
"skipped": true,
|
|
599
|
+
"reason": "not_present"
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Returned when the name was not in the runtime overlay (it may still exist in settings — settings entries cannot be removed via this route).
|
|
604
|
+
|
|
605
|
+
Errors:
|
|
606
|
+
|
|
607
|
+
| Status | Code | When |
|
|
608
|
+
| ------ | ------------------------- | ----------------------------------------------------------------------------- |
|
|
609
|
+
| `400` | `invalid_server_name` | Name empty, exceeds 256 chars, or contains characters outside `[A-Za-z0-9_-]` |
|
|
610
|
+
| `400` | `invalid_client_id` | `X-Qwen-Client-Id` header present but not registered for this workspace |
|
|
611
|
+
| `401` | `token_required` | No bearer token configured (strict gate) |
|
|
612
|
+
| `503` | `acp_channel_unavailable` | No live ACP child |
|
|
613
|
+
|
|
614
|
+
### Shadow semantics
|
|
615
|
+
|
|
616
|
+
Runtime entries form an ephemeral overlay on top of settings-defined MCP servers:
|
|
617
|
+
|
|
618
|
+
- **Adding** a runtime server with the same name as a settings entry **shadows** it — the runtime config takes precedence. The original settings entry is not modified.
|
|
619
|
+
- **Removing** a runtime server that was shadowing a settings entry **un-shadows** it — the settings-defined config becomes active again on next connection.
|
|
620
|
+
- **Daemon restart** loses all runtime entries. Only settings-defined servers survive across restarts. Runtime servers are session-lifetime scoped.
|
|
621
|
+
- **`GET /workspace/mcp`** reports the merged view — both settings-defined and runtime servers appear in the `servers[]` array. There is no wire-level distinction between the two origins in the snapshot today.
|
|
622
|
+
|
|
623
|
+
### Events
|
|
624
|
+
|
|
625
|
+
Both routes emit **workspace-scoped** SSE events (all active session buses receive them):
|
|
626
|
+
|
|
627
|
+
| Event | Emitted when | Payload fields |
|
|
628
|
+
| -------------------- | ------------------------------- | -------------------------------------------------------------------------------------- |
|
|
629
|
+
| `mcp_server_added` | `POST` succeeds (not skipped) | `name`, `transport`, `replaced`, `shadowedSettings`, `toolCount`, `originatorClientId` |
|
|
630
|
+
| `mcp_server_removed` | `DELETE` succeeds (not skipped) | `name`, `wasShadowingSettings`, `originatorClientId` |
|
|
631
|
+
|
|
632
|
+
Skipped responses (`budget_warning_only`, `not_present`) do NOT emit events.
|
|
633
|
+
|
|
634
|
+
Budget-related events from the existing `mcp_guardrail_events` surface (`mcp_budget_warning`, `mcp_child_refused_batch`) also fire when runtime additions cross the budget threshold.
|
|
635
|
+
|
|
427
636
|
## What's next
|
|
428
637
|
|
|
638
|
+
- **Setting up a long-running daemon?** [Local launch templates (systemd / launchd / nohup / tmux)](./qwen-serve-deploy-local.md) for v0.16-alpha (local-only).
|
|
429
639
|
- **Build a client?** See the [DaemonClient TypeScript quickstart](../developers/examples/daemon-client-quickstart.md) and the [HTTP protocol reference](../developers/qwen-serve-protocol.md).
|
|
430
640
|
- **Reading the source?** Bridge code lives at `packages/cli/src/serve/`; SDK client at `packages/sdk-typescript/src/daemon/`.
|
|
431
641
|
- **Tracking the roadmap?** Stage 1.5 / Stage 2 progress is tracked on issue [#3803](https://github.com/QwenLM/qwen-code/issues/3803).
|
|
@@ -67,6 +67,22 @@ This document lists the available keyboard shortcuts in Qwen Code.
|
|
|
67
67
|
| `1-9` | Select an item by its number. |
|
|
68
68
|
| (multi-digit) | For items with numbers greater than 9, press the digits in quick succession to select the corresponding item. |
|
|
69
69
|
|
|
70
|
+
## History scrollback
|
|
71
|
+
|
|
72
|
+
Active only when `ui.useTerminalBuffer` is enabled (Settings → UI → Virtualized History). In that mode conversation history is rendered inside an in-app viewport instead of the host terminal scrollback, so the keys below replace the terminal's native scroll.
|
|
73
|
+
|
|
74
|
+
| Shortcut | Description |
|
|
75
|
+
| --------------- | ---------------------------------------------------- |
|
|
76
|
+
| `Shift+Up` | Scroll history up one line. |
|
|
77
|
+
| `Shift+Down` | Scroll history down one line. |
|
|
78
|
+
| `PgUp` | Scroll history up one page (viewport height). |
|
|
79
|
+
| `PgDn` | Scroll history down one page (viewport height). |
|
|
80
|
+
| `Ctrl+Home` | Jump to the top of the conversation. |
|
|
81
|
+
| `Ctrl+End` | Jump to the bottom (and re-engage live auto-follow). |
|
|
82
|
+
| **Mouse wheel** | Scroll history (3 lines per tick). |
|
|
83
|
+
|
|
84
|
+
When `ui.useTerminalBuffer` is on, the terminal forwards mouse events to qwen-code so the wheel can drive the in-app viewport. As a side effect, **native click-and-drag text selection is consumed by the program** — hold `Shift` (or `Option` on macOS Terminal / iTerm) while dragging to bypass mouse capture and select text the usual way.
|
|
85
|
+
|
|
70
86
|
## IDE Integration
|
|
71
87
|
|
|
72
88
|
| Shortcut | Description |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Uninstall
|
|
2
2
|
|
|
3
|
-
Your uninstall method depends on how you
|
|
3
|
+
Your uninstall method depends on how you installed the CLI.
|
|
4
4
|
|
|
5
5
|
## Method 1: Using npx
|
|
6
6
|
|
|
@@ -40,3 +40,21 @@ npm uninstall -g @qwen-code/qwen-code
|
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
This command completely removes the package from your system.
|
|
43
|
+
|
|
44
|
+
## Method 3: Standalone Install
|
|
45
|
+
|
|
46
|
+
If you installed via the standalone installer (`curl ... | bash` or `irm ... | iex`), use the dedicated uninstall script.
|
|
47
|
+
|
|
48
|
+
**Linux / macOS**
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/uninstall-qwen-standalone.sh | bash
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Windows**
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/uninstall-qwen-standalone.ps1 | iex
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The uninstaller removes the standalone runtime, generated `qwen` wrapper, and installer-managed PATH changes. Your Qwen Code configuration (`~/.qwen`) is preserved by default.
|
|
@@ -37,7 +37,7 @@ This guide provides solutions to common issues and debugging tips, including top
|
|
|
37
37
|
## Frequently asked questions (FAQs)
|
|
38
38
|
|
|
39
39
|
- **Q: How do I update Qwen Code to the latest version?**
|
|
40
|
-
- A: If you installed it globally via `npm`, update it using the command `npm install -g @qwen-code/qwen-code@latest`. If you compiled it from source, pull the latest changes from the repository, and then rebuild using the command `npm run build`.
|
|
40
|
+
- A: If you installed Qwen Code with the standalone installer, rerun the standalone install command. If you installed it globally via `npm`, update it using the command `npm install -g @qwen-code/qwen-code@latest`. If you compiled it from source, pull the latest changes from the repository, and then rebuild using the command `npm run build`.
|
|
41
41
|
|
|
42
42
|
- **Q: Where are the Qwen Code configuration or settings files stored?**
|
|
43
43
|
- A: The Qwen Code configuration is stored in two `settings.json` files:
|
|
@@ -60,6 +60,7 @@ This guide provides solutions to common issues and debugging tips, including top
|
|
|
60
60
|
- **Cause:** The CLI is not correctly installed or it is not in your system's `PATH`.
|
|
61
61
|
- **Solution:**
|
|
62
62
|
The update depends on how you installed Qwen Code:
|
|
63
|
+
- If you installed `qwen` with the standalone installer, rerun the standalone install command and then open a new terminal.
|
|
63
64
|
- If you installed `qwen` globally, check that your `npm` global binary directory is in your `PATH`. You can update using the command `npm install -g @qwen-code/qwen-code@latest`.
|
|
64
65
|
- If you are running `qwen` from source, ensure you are using the correct command to invoke it (e.g. `node packages/cli/dist/index.js ...`). To update, pull the latest changes from the repository, and then rebuild using the command `npm run build`.
|
|
65
66
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: simplify
|
|
3
|
+
description: Review recent code changes for reuse, code quality, and efficiency, then directly apply straightforward cleanup improvements. Use when the user wants a post-implementation cleanup pass, pre-PR polish, or asks to simplify/refine recent changes. Invoke with `/simplify` or `/simplify <focus>`.
|
|
4
|
+
allowedTools:
|
|
5
|
+
- agent
|
|
6
|
+
- run_shell_command
|
|
7
|
+
- grep_search
|
|
8
|
+
- read_file
|
|
9
|
+
- write_file
|
|
10
|
+
- edit
|
|
11
|
+
- glob
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Simplify Recent Changes
|
|
15
|
+
|
|
16
|
+
You are running a structured cleanup workflow over recent code changes. Your goal is not just to comment on the code, but to safely improve it.
|
|
17
|
+
|
|
18
|
+
## Step 1: Identify the review scope
|
|
19
|
+
|
|
20
|
+
Determine which files and changes to review.
|
|
21
|
+
|
|
22
|
+
1. First inspect the current git state.
|
|
23
|
+
2. If there are staged changes, review against `HEAD` so both staged and unstaged tracked changes are included.
|
|
24
|
+
3. Otherwise review the current uncommitted diff.
|
|
25
|
+
4. If there is no git diff, fall back to `git ls-files --modified --others --exclude-standard` so the scope respects `.gitignore` (this keeps build output, `node_modules`, and other ignored paths out of the cleanup).
|
|
26
|
+
5. If that is still empty, fall back to files edited in this conversation.
|
|
27
|
+
6. If you still cannot identify a meaningful scope, stop and tell the user there are no recent changes to simplify.
|
|
28
|
+
|
|
29
|
+
Preferred commands:
|
|
30
|
+
|
|
31
|
+
- `git diff --name-only`
|
|
32
|
+
- `git diff --staged --name-only`
|
|
33
|
+
- `git diff HEAD --name-only`
|
|
34
|
+
- `git diff`
|
|
35
|
+
- `git diff HEAD`
|
|
36
|
+
- `git status --short`
|
|
37
|
+
|
|
38
|
+
Use `git diff HEAD` whenever staged changes exist. Otherwise use `git diff`.
|
|
39
|
+
|
|
40
|
+
## Step 2: Launch three review passes in parallel
|
|
41
|
+
|
|
42
|
+
Use the `agent` tool and launch all review passes in a single response so they run concurrently. Each pass must receive the same review scope and diff command. These passes are read-only: each one inspects and reports findings only and must not modify files — all edits happen later in Step 4.
|
|
43
|
+
|
|
44
|
+
Keep each review prompt short and focused. Do not paste the full diff into the prompt. Tell each pass to read the diff itself and inspect only files relevant to its findings.
|
|
45
|
+
|
|
46
|
+
### Pass 1: Code Reuse Review
|
|
47
|
+
|
|
48
|
+
Look for opportunities to reduce duplication and reuse existing code:
|
|
49
|
+
|
|
50
|
+
- existing utilities or helpers that should be reused
|
|
51
|
+
- duplicated logic introduced in new code
|
|
52
|
+
- inline logic that should delegate to an existing abstraction
|
|
53
|
+
- ad-hoc helpers for string, path, env, parsing, or type checks when a project utility already exists
|
|
54
|
+
|
|
55
|
+
### Pass 2: Code Quality Review
|
|
56
|
+
|
|
57
|
+
Look for maintainability issues:
|
|
58
|
+
|
|
59
|
+
- copy-paste variants that should be unified
|
|
60
|
+
- parameter sprawl or awkward APIs
|
|
61
|
+
- redundant state or indirection
|
|
62
|
+
- abstraction leaks
|
|
63
|
+
- stringly-typed code that should be modeled more clearly
|
|
64
|
+
- unnecessary nesting
|
|
65
|
+
- unnecessary comments that explain what instead of why
|
|
66
|
+
- naming or structure that does not match surrounding code
|
|
67
|
+
|
|
68
|
+
### Pass 3: Efficiency Review
|
|
69
|
+
|
|
70
|
+
Look for wasteful work and unnecessary overhead:
|
|
71
|
+
|
|
72
|
+
- repeated work that can be memoized, cached, or removed
|
|
73
|
+
- serial work that can be parallelized safely
|
|
74
|
+
- unnecessary scans, allocations, reads, or traversals
|
|
75
|
+
- hot-path blocking work
|
|
76
|
+
- redundant no-op updates
|
|
77
|
+
- overly broad operations when a narrower one would work
|
|
78
|
+
- existence-check patterns that introduce TOCTOU style waste or risk
|
|
79
|
+
|
|
80
|
+
## Step 3: Aggregate findings
|
|
81
|
+
|
|
82
|
+
Wait for all three passes to finish, then merge overlapping findings.
|
|
83
|
+
|
|
84
|
+
Prioritize fixes that are:
|
|
85
|
+
|
|
86
|
+
- low risk
|
|
87
|
+
- local in scope
|
|
88
|
+
- clearly aligned with existing project patterns
|
|
89
|
+
- easy to validate with tests or targeted commands
|
|
90
|
+
|
|
91
|
+
Do not force a cleanup if it would require speculative architectural changes.
|
|
92
|
+
|
|
93
|
+
## Step 4: Apply straightforward improvements
|
|
94
|
+
|
|
95
|
+
Directly implement safe cleanup improvements.
|
|
96
|
+
|
|
97
|
+
Examples of good automatic fixes:
|
|
98
|
+
|
|
99
|
+
- replace duplicated logic with an existing helper
|
|
100
|
+
- remove redundant code, but only after a repository-wide search confirms it has no remaining callers
|
|
101
|
+
- simplify conditionals or control flow
|
|
102
|
+
- tighten loops or repeated work
|
|
103
|
+
- reduce unnecessary state or wrapper code
|
|
104
|
+
- remove low-value comments
|
|
105
|
+
- align code with nearby conventions
|
|
106
|
+
|
|
107
|
+
Skip items that are uncertain, risky, or too invasive. Do not spend time debating rejected findings; simply move on.
|
|
108
|
+
|
|
109
|
+
## Step 5: Verify the cleanup
|
|
110
|
+
|
|
111
|
+
After making changes:
|
|
112
|
+
|
|
113
|
+
1. Run focused tests for the changed area when they exist.
|
|
114
|
+
2. Run the relevant project quality checks you can identify for the touched code.
|
|
115
|
+
3. If there are no applicable tests, at least run a targeted build, typecheck, or lint command that covers the edited files.
|
|
116
|
+
|
|
117
|
+
Prefer targeted verification over whole-repo commands unless the project only exposes repo-wide checks.
|
|
118
|
+
|
|
119
|
+
## Additional focus
|
|
120
|
+
|
|
121
|
+
If the user supplied extra instructions after `/simplify`, treat them as additional review focus and prioritize them alongside the default dimensions.
|
|
122
|
+
|
|
123
|
+
The raw user invocation appears below when present. Use it to extract any extra focus such as performance, duplication, rendering, API clarity, testability, or naming consistency.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
AgentTool,
|
|
5
|
+
TOOL_REGISTRY_REBUILT,
|
|
6
|
+
createApprovalModeOverride,
|
|
7
|
+
hasRebuiltToolRegistry,
|
|
8
|
+
rebuildToolRegistryOnOverride,
|
|
9
|
+
resolveSubagentApprovalMode
|
|
10
|
+
} from "./chunk-TD4OPI4T.js";
|
|
11
|
+
import "./chunk-K5PGHDBN.js";
|
|
12
|
+
import "./chunk-XBY7E2FX.js";
|
|
13
|
+
import "./chunk-SKBPNJEW.js";
|
|
14
|
+
import "./chunk-NVFMZBX2.js";
|
|
15
|
+
import "./chunk-O4PICXES.js";
|
|
16
|
+
import "./chunk-TW522KN6.js";
|
|
17
|
+
import "./chunk-3DHXZ6EV.js";
|
|
18
|
+
import "./chunk-J5MDQKJL.js";
|
|
19
|
+
import "./chunk-MLZQVCF3.js";
|
|
20
|
+
import "./chunk-LD2XBG6Z.js";
|
|
21
|
+
import "./chunk-OHEGWO4L.js";
|
|
22
|
+
import "./chunk-SNGELLWX.js";
|
|
23
|
+
import "./chunk-77WXWU44.js";
|
|
24
|
+
import "./chunk-A7B4ISQP.js";
|
|
25
|
+
import "./chunk-OQ7NJIY7.js";
|
|
26
|
+
import "./chunk-3PJXIDKI.js";
|
|
27
|
+
import "./chunk-UWCTAVOD.js";
|
|
28
|
+
import "./chunk-OFEVLU4C.js";
|
|
29
|
+
import "./chunk-3HTIVKZE.js";
|
|
30
|
+
import "./chunk-IDX6COTE.js";
|
|
31
|
+
import "./chunk-KQJMQJPI.js";
|
|
32
|
+
import "./chunk-D3RHSPAS.js";
|
|
33
|
+
import "./chunk-2Y5SYSD3.js";
|
|
34
|
+
import "./chunk-SEGYWKIH.js";
|
|
35
|
+
import "./chunk-64WXLC72.js";
|
|
36
|
+
import "./chunk-B7HXHOHU.js";
|
|
37
|
+
import "./chunk-EYENRK4D.js";
|
|
38
|
+
import "./chunk-M6VTDSVR.js";
|
|
39
|
+
import "./chunk-55ZMG67I.js";
|
|
40
|
+
import "./chunk-H6BD2ELD.js";
|
|
41
|
+
import "./chunk-5IFG2VC4.js";
|
|
42
|
+
import "./chunk-HR7SV7AY.js";
|
|
43
|
+
import "./chunk-ZERZSAZL.js";
|
|
44
|
+
import "./chunk-QN5NZ3UQ.js";
|
|
45
|
+
import "./chunk-BR4QREVK.js";
|
|
46
|
+
import "./chunk-Z2Z3GUXZ.js";
|
|
47
|
+
import "./chunk-A4BMJM77.js";
|
|
48
|
+
import "./chunk-J2S4EL5Y.js";
|
|
49
|
+
export {
|
|
50
|
+
AgentTool,
|
|
51
|
+
TOOL_REGISTRY_REBUILT,
|
|
52
|
+
createApprovalModeOverride,
|
|
53
|
+
hasRebuiltToolRegistry,
|
|
54
|
+
rebuildToolRegistryOnOverride,
|
|
55
|
+
resolveSubagentApprovalMode
|
|
56
|
+
};
|