Find a file
MikeWang0316tw 9b3aa524a1
fix(cli): stream long responses into scrollback to stop scroll-to-top lock (#6170)
* fix(cli): stream long responses into scrollback to stop scroll-to-top lock

## Problem

In non-VP (default) mode, scrolling up while the model streams a long reply —
especially one containing a markdown table — jumps the viewport to the very top
and locks it there until the response finishes (issue #5941).

Root cause: when the live (below-`<Static>`) frame grows taller than the
terminal, ink can no longer do its incremental cursor-up redraw and falls back
to clearing + repainting the whole frame from the top on every token. A markdown
table renders ~2 rows per data row (TableRenderer draws a separator between
every row), so #6081's source-line budget under-counted the rendered height and
the frame still overflowed for tables / wide CJK text.

## Fix

Incremental scrollback streaming + a rendered-height safety net:

- useGeminiStream: commit finished chunks of the streaming reply into `<Static>`
  (scrollback) so the pending live item stays short. The commit is
  rendered-height-aware (tables count double, wide/CJK lines wrap) and bounded by
  the live content-area height (threaded via `availableTerminalHeightRef`), with
  a reserve so it fires before the render-side clip. It commits in a `while` loop
  and splits only at `findLastSafeSplitPoint` boundaries (never inside a fenced
  code block).

- MarkdownDisplay: a rendered-height-aware slice of the pending preview as a last
  line of defence — it guarantees the live frame never exceeds the viewport
  regardless of how the stream is chunked (tables charged at ~2x; non-table lines
  charged their wrapped height). A completed table renders in full; a table still
  being written renders live and is clamped by TableRenderer's new `maxHeight`.

Result: long replies (and tables) flow smoothly into scrollback, tables draw
live, and the viewport never locks to the top.

Refs #5941, #6081

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): address review — share rendered-height estimator + guard edges

Follow-up to review feedback on the incremental-scrollback streaming fix:

- Extract a shared rendered-height estimator (`pendingRenderedHeight.ts`:
  `fitPendingSlice` / `estimateWrappedRows` / `isTableStart`) and use it from
  BOTH the useGeminiStream commit and the MarkdownDisplay safety-net slice, so
  the two agree on table (block: 2*dataRows + chrome) and wrap accounting
  instead of diverging.
- useGeminiStream: use a conservative content-area fallback (terminalHeight
  minus a composer reserve) when `availableTerminalHeightRef` is not yet
  populated, so a short terminal never commits with an over-large budget.
- MarkdownDisplay: allow the pending slice to keep 0 lines — a single very wide
  / CJK line that wraps past the budget now renders only the "generating more"
  cue instead of one oversized row that would bypass the height bound.
- Add missing `useCallback` deps (terminalWidth / terminalHeight /
  availableTerminalHeightRef) — fixes the CI ESLint failure.
- Tests: unit tests for the shared estimator (table detection, zero/negative
  width, CJK wrapping, cut-before / clamp / keptLines=0 boundaries) and for
  TableRenderer's `maxHeight` clamp (fit, clip+cue, vertical fallback, undefined
  passthrough).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): rename shared util to kebab-case to satisfy check-file lint

The new pendingRenderedHeight.{ts,test.ts} tripped the check-file/filename-naming-convention (KEBAB_CASE) ESLint rule on new files in packages/cli/src. Rename to pending-rendered-height.{ts,test.ts} and update imports.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): point imports at renamed pending-rendered-height module

The previous rename commit landed the file rename but not the importer edits
(a stale pathspec aborted the git add), leaving MarkdownDisplay, useGeminiStream
and the test importing the old ./pendingRenderedHeight.js path — a module-not-
found in CI. Update the imports to the kebab-case path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): drop unused eslint-disable directive on while(true)

reportUnusedDisableDirectives + --max-warnings 0 flags the no-constant-condition
disable as an unused directive (the rule doesn't flag while(true) here). Remove it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): unify table parsing in shared module + cover commit edge cases

Address the second review pass:

- Move splitMarkdownTableRow and the table regexes (TABLE_ROW_RE /
  TABLE_SEPARATOR_RE) into pending-rendered-height.ts as the single source of
  truth; MarkdownDisplay now imports them instead of keeping duplicate copies.
- isTableStart now also checks the separator's column count matches the header
  (mirroring the renderer's table detection) so the height estimator and the
  renderer agree on what is a table.
- Tests: shared-module coverage for splitMarkdownTableRow and the isTableStart
  column-count check; tighten the incremental-commit assertion (budget-relative,
  requires multiple commits); add coverage for the splitPoint<=0 loop-break
  guard and for the populated-availableTerminalHeightRef production path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): commit streaming chunks only at block boundaries (no split tables)

The incremental scrollback commit could cut a markdown table mid-way (e.g. when
the tail row was still streaming): the committed chunk kept the header+rows and
rendered as a table, but the continuation started with headerless `| ... |`
rows that render as raw text (visible orphaned rows below a table).

Only commit at a blank-line block boundary. A table (or list / code block) has
no internal blank line, so it is never split into a headerless continuation; a
still-streaming table stays pending — bounded in view by MarkdownDisplay's
clamp — until it is complete, then commits whole.

Tests: the oversized-commit test now uses blank-line-separated content and
asserts every committed chunk ends at a block boundary; add a regression test
that a streaming table taller than the budget is never committed as a headerless
fragment (its header stays with its rows in the pending item).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): don't treat code-fence content as a table in the height estimator

fitPendingSlice called isTableStart on every line regardless of fenced-code-
block state, so table-like lines inside a ``` block were charged as a table
(2*dataRows + chrome) while MarkdownDisplay renders them as code (one row each).
Track the code fence and charge fenced lines individually. Share CODE_FENCE_RE
from the module (MarkdownDisplay now imports it too) to keep a single source of
truth. Adds a unit test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): account for vertical-format table height + tilde code fences

Address the third review pass:

- (Critical) fitPendingSlice charged the horizontal table height (2*dataRows+5)
  only, but TableRenderer falls back to the vertical key-value format on a narrow
  terminal / when cells wrap tall, which is much taller for 3+ column tables.
  Charge the larger of the horizontal and vertical estimates (dataRows*colCount +
  separators + marginY), still capped by the clamp — under-charging could let a
  vertical-format table overflow the viewport and re-introduce the scroll lock.
- findLastSafeSplitPoint only recognised triple-backtick fences while the
  estimator's CODE_FENCE_RE also matches ~~~; a ~~~ block with an internal blank
  line could be split mid-block. isIndexInsideCodeBlock / findEnclosingCodeBlockStart
  now track both fence types (matching by fence character).
- Tests: vertical-format table cost, ~~~ fence tracking, inline math and
  multi-backtick spans in splitMarkdownTableRow, and a ~~~ split-safety case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): only charge vertical-format table height on a narrow terminal

The prior fix charged the max of the horizontal and vertical table estimates
unconditionally, which over-estimated a table's height on a wide terminal (where
it actually renders in the shorter horizontal format) and clipped small tables
early with a premature "generating more". Mirror TableRenderer's width-based
vertical decision (contentWidth < max(24, 6*colCount + 5)) and charge the format
it will actually render: horizontal when the terminal is wide enough, vertical
only when narrow — so a narrow-terminal vertical render still can't overflow and
lock, but a small table on a wide terminal is no longer clipped prematurely.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(cli): fix phantom code fences + read commit width from a live ref

Address the fourth review pass:

- (Critical) isIndexInsideCodeBlock / findEnclosingCodeBlockStart used
  indexOf('```', ...) which matches only the first three characters of a longer
  fence run, so a 4+ backtick/tilde fence was miscounted as two delimiters
  (phantom close-then-reopen). That could mark a blank line inside a code block
  as outside it, letting findLastSafeSplitPoint split mid-block and commit an
  unclosed code block to scrollback. findNextFence now returns the full run
  length, callers advance past the whole run, and a fence only closes a block
  opened with the same character and a run at least as long.
- The commit loop read height live from availableTerminalHeightRef but width
  from the render-time closure, so a mid-stream resize handled the two
  inconsistently. Pair a terminalWidthRef with the height ref and read both live.

Tests: a 6-backtick fenced block is not split at its internal blank line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 11:40:00 +00:00
.github fix(ci): require maintainer-applied autofix/approved label for tier-1 fast-path (#6276) 2026-07-04 08:06:27 +00:00
.husky Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
.qwen fix(triage): strengthen PR gate with batch detection, problem existence check, and red flag patterns (#5723) 2026-07-03 16:38:37 +00:00
.vscode Merge branch 'main' into feat/sandbox-config-improvements 2026-03-06 14:38:39 +08:00
docs fix(core): give Stop-hook continuations a fresh per-turn tool-call budget; make the cap configurable (#6238) 2026-07-04 02:36:59 +00:00
docs-site Hide internal docs from docs site (#4357) 2026-06-01 15:55:14 +08:00
eslint-rules pre-release commit 2025-07-22 23:26:01 +08:00
integration-tests test(e2e): make fake OpenAI reachable from Docker sandbox (#6302) 2026-07-04 11:06:53 +00:00
packages fix(cli): stream long responses into scrollback to stop scroll-to-top lock (#6170) 2026-07-04 11:40:00 +00:00
patches fix(release): reduce npm package scan triggers (#6164) 2026-07-02 08:06:43 +00:00
scripts fix(ci): require maintainer-applied autofix/approved label for tier-1 fast-path (#6276) 2026-07-04 08:06:27 +00:00
.dockerignore fix(cli): skip stdin read for ACP mode 2026-03-27 11:47:01 +00:00
.editorconfig pre-release commit 2025-07-22 23:26:01 +08:00
.gitattributes feat(installer): add standalone hosted install and uninstall flow (#3828) 2026-05-21 11:57:10 +08:00
.gitignore feat(web-shell): add daemon UI support for vision model selection (#6209) 2026-07-03 04:31:11 +00:00
.npmrc chore: remove google registry 2025-08-08 20:45:54 +08:00
.nvmrc chore(deps): upgrade ink 6.2.3 → 7.0.2 + bump Node engine to 22 (#3860) 2026-05-11 17:29:50 +08:00
.prettierignore feat(acp): support /cd command in ACP sessions (#5903) 2026-06-27 14:47:40 +00:00
.prettierrc.json pre-release commit 2025-07-22 23:26:01 +08:00
.yamllint.yml feat(desktop): Add desktop app package with Qwen ACP SDK integration (#3778) 2026-06-11 21:57:20 +08:00
AGENTS.md fix(triage): strengthen PR gate with batch detection, problem existence check, and red flag patterns (#5723) 2026-07-03 16:38:37 +00:00
CHANGELOG.md chore(release): v0.19.6 (#6280) 2026-07-03 16:37:54 +00:00
CLAUDE.md docs: rewrite CLAUDE.md to point to AGENTS.md as authoritative source (#5138) 2026-06-15 15:23:26 +08:00
CONTRIBUTING.md docs: add provider preset governance policy to CONTRIBUTING.md (#5631) 2026-06-27 14:44:21 +00:00
Dockerfile chore(deps): upgrade ink 6.2.3 → 7.0.2 + bump Node engine to 22 (#3860) 2026-05-11 17:29:50 +08:00
esbuild.config.js fix(cli): add bootstrap fast paths (#6188) 2026-07-02 22:28:11 +00:00
eslint.config.js feat(mobile-mcp): vendor mobile-mcp with opt-in 0-1000 relative coordinates (#6235) 2026-07-03 08:50:27 +00:00
eslint.legacy-filenames.mjs refactor(cli): Finish serve kebab-case filenames (#5604) 2026-06-22 21:15:40 +08:00
LICENSE Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
Makefile feat: update docs 2025-12-22 21:11:33 +08:00
package-lock.json chore(release): v0.19.6 (#6280) 2026-07-03 16:37:54 +00:00
package.json chore(release): v0.19.6 (#6280) 2026-07-03 16:37:54 +00:00
README.md docs: Revamp README for clarity and focus (#5257) 2026-06-18 10:27:16 +08:00
SECURITY.md fix: update security vulnerability reporting channel 2026-02-24 14:22:47 +08:00
tsconfig.json # 🚀 Sync Gemini CLI v0.2.1 - Major Feature Update (#483) 2025-09-01 14:48:55 +08:00
vitest.config.ts feat(channel): add QQ Bot (QQ机器人) channel adapter (#5202) 2026-06-19 06:32:52 +08:00

npm version License Node.js Version Downloads

QwenLM%2Fqwen-code | Trendshift

The open-source AI coding agent that lives in your terminal.

中文 | Deutsch | français | 日本語 | Русский | Português (Brasil)

Why Qwen Code?

  • Agentic out of the box — Auto-Memory, Auto-Skills, SubAgents, Agent Teams, and MCP. Dynamic workflows, zero setup.
  • Open-source, inside and out — The framework and the Qwen models are open-source. They evolve together. No vendor lock-in.
  • Multi-protocol — Supports OpenAI, Anthropic, Gemini, and Qwen APIs. Any third-party provider or local model (Ollama / vLLM). Switch at runtime.
  • Beyond the terminal — IDE plugins, Desktop app, daemon mode, SDKs, and IM bots (Telegram / DingTalk / WeChat / Feishu).

Tip

Qwen Code is actively iterating on itself — using its own agent and models to file issues, submit PRs, review code, and run tests. Powered by the community, driven by AI.

Installation

Linux / macOS:

curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.sh | bash

Windows:

irm https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.ps1 | iex

Restart your terminal after installation to ensure environment variables take effect.

NPM / Homebrew

NPM (requires Node.js 22+):

npm install -g @qwen-code/qwen-code@latest

Homebrew (macOS / Linux):

brew install qwen-code

Quick Start

qwen          # Launch interactive terminal UI
# Inside the session:
/auth         # Configure your provider and API key

See the Authentication Guide and Settings Reference for detailed setup.

Qwen Code

How to Use Qwen Code

Mode Command Use Case
Interactive qwen Terminal UI with rich rendering, @file references, slash commands
Headless qwen -p "..." Scripts, CI/CD, batch processing — no UI
IDE VS Code, Zed, JetBrains
Desktop Qwen Code Desktop — GUI for macOS, Windows, Linux
Daemon qwen serve Shared agent session over HTTP+SSE (ACP). Multiple clients, one agent. (experimental) Docs
SDK TypeScript, Python, Java
IM Bot qwen channel Connect to Telegram, DingTalk, WeChat, or Feishu
SDK example (Python)
import asyncio

from qwen_code_sdk import is_sdk_result_message, query


async def main() -> None:
    result = query(
        "Summarize the repository layout.",
        {
            "cwd": "/path/to/project",
            "path_to_qwen_executable": "qwen",
        },
    )

    async for message in result:
        if is_sdk_result_message(message):
            print(message["result"])


asyncio.run(main())

Capabilities

If you know Claude Code, you already know Qwen Code — and then some. We've put significant effort into bringing Qwen Code to feature parity with Claude Code, improving both breadth and reliability across the board.

Feature Qwen Code Claude Code
SubAgents, Agent Teams, Dynamic Workflows
Auto-Memory, Auto-Skills, Hooks
Built-in Skills (/review, /batch, /loop, /bugfix…)
MCP, Plan Mode, LSP Integration
Auto Mode, Sandbox, Git Worktrees
Computer Use (desktop automation)
IDE Plugins (VS Code / JetBrains / Zed)
SDK
Headless Mode, Session Management
Open-source — model and framework
Multi-protocol (OpenAI / Anthropic / Gemini / Qwen + any provider)
Agent Arena (multi-model head-to-head on same task)
Daemon Mode — qwen serve (multi-client shared agent)
IM Channels (Telegram / DingTalk / WeChat / Feishu)

Ecosystem

  • Qwen Code Desktop — Official desktop app for macOS, Windows, and Linux

  • AionUi — A modern GUI for command-line AI tools including Qwen Code

  • Gemini CLI Desktop — A cross-platform desktop/web/mobile UI for Qwen Code

  • 🦞 Qwen Code Claw — Let other agents (Claude, Codex, etc.) delegate coding tasks to Qwen Code via ACP. Paste this prompt into your agent:

Use Qwen Code as a coding agent. First, fetch and read this skill reference:
https://raw.githubusercontent.com/QwenLM/qwen-code/refs/heads/main/.qwen/skills/qwen-code-claw/SKILL.md
Then follow the instructions inside to install, authenticate, and use Qwen Code via acpx for all coding tasks.

Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

Acknowledgments

This project was originally based on Google Gemini CLI v0.8.2. We gratefully acknowledge the Gemini CLI team's excellent work. Starting from Qwen Code v0.1, we stopped syncing with upstream and began independent development as a multi-protocol, multi-platform agent framework with deep integrations for Qwen models and beyond.