qwen-code/packages/vscode-ide-companion
Shaojin Wen afbb5e71db
fix(cli): rework session recap rendering and add blur threshold setting (#3482)
* feat(cli): make recap away-threshold configurable

The 5-minute blur threshold was hard-coded. Confirmed from Claude
Code's own binary (v2.1.113) that 5 minutes is their default as well
(and that they shift to 60 minutes when 1h prompt-cache is active) —
so the default stays, but expose it as `general.sessionRecapAway
ThresholdMinutes` for users who briefly alt-tab often and don't want
recaps piling up, or who want to lower it for testing.

Non-positive / unset values fall back to the 5-minute default, so
dropping the key has the same behavior as before.

* fix(core): align recap prompt with Claude Code (1-2 sentences, ≤40 words)

The earlier "exactly one sentence, 80-char cap" was an over-correction
to a single in-the-moment ask. Going back to it: the natural shape of
"current task + next action" is two clauses, and forcing them into a
single sentence either crams them with a semicolon or drops the next
action entirely on complex sessions.

Adopt Claude Code's prompt verbatim (extracted from the v2.1.113
binary): "under 40 words, 1-2 plain sentences, no markdown. Lead with
the overall goal and current task, then the one next action. Skip
root-cause narrative, fix internals, secondary to-dos, and em-dash
tangents." Add a Chinese-budget note (~80 chars) and keep the
<recap>...</recap> wrapping that protects against reasoning-model
preambles leaking into the UI.

The sticky banner already re-measures controls height when the
recap toggles, so a 2-line render lays out cleanly.

Sweep "one-line" out of user-facing copy (settings description,
slash-command description, feature docs, design doc) so the
documentation matches the new shape.

* fix(cli): restore "one-line" in user-facing recap copy

Verified from the Claude Code v2.1.113 binary that the slash-command
description IS literally "Generate a one-line session recap now" even
though the underlying prompt allows 1-2 sentences. Claude Code is
deliberately setting a tighter user expectation than the prompt
guarantees, which keeps the surface feel "glanceable".

Mirror that asymmetry: keep the prompt at 1-2 sentences (the previous
commit) for behavioral parity, but put "one-line" back in the user-
visible copy (slash-command description, settings description, user
docs). Internal design doc keeps the accurate "1-2 sentence" wording.

* fix(cli): render recap inline in history to match Claude Code

Earlier I read the user's complaint that the recap "scrolled away" as
"the recap should be sticky above the input box," and built a sticky
banner accordingly. Disassembly of the Claude Code v2.1.113 binary
shows the actual behavior is the opposite: their away_summary is a
plain `type:"system", subtype:"away_summary"` message dispatched
through the standard message renderer (no Static, no anchor, no
flexbox pinning) — it scrolls with the conversation like every other
system message.

Tear out the sticky-banner machinery so recap matches that:

- Recap is back in the `HistoryItemWithoutId` union and `addItem`'d
  into history (both from `/recap` and from auto-trigger), so it
  serializes into session saves and behaves like every other history
  item — no special clear paths, no resume-wrapper, no layout-effect
  re-measure dance.
- `useAwaySummary` takes `addItem` again instead of a setter callback.
- `AwayRecapMessage` renders the way Claude Code does: a 2-column
  gutter with `※`, then bold "recap: " and italic content, all in
  dim color. Drop the prior `StatusMessage`-shaped layout that fused
  prefix and label into "※ recap:".
- Remove the AppContainer plumbing, the slashCommandProcessor state,
  the UIStateContext fields, the DefaultAppLayout / ScreenReader
  placement blocks, the test-utils mocks, and the noninteractive
  stub. Restore `useResumeCommand.handleResume` to a void return
  since callers no longer need the success boolean.

Sweep the design doc so the architecture diagram, files table, and
hook deps reflect the inline-history flow.

* fix(cli): dedupe back-to-back auto-recaps with no new user turns between

Two consecutive blur cycles, each over the threshold but with no new
user activity in between, would each fire their own auto-recap and
add two near-duplicate entries to history (same task, slightly
different wording from temperature-driven LLM variance). Reported
case: leaving the terminal twice while a /review of one PR was
still on screen produced two recaps both about that same review.

Add a `shouldFireRecap` gate before kicking off the LLM call:

- Need at least 3 user messages in history total (don't fire on a
  near-empty session).
- If a previous away_recap is already in history, need at least 2
  new user messages since that one before another can fire.

Same shape as Claude Code's `Ic1` gate (`Sc1=3`, `Rc1=2`). Read
history through a ref so this isn't in the effect's deps and the
effect doesn't re-run on every message.

* fix(cli): type useResumeCommand.handleResume as Promise<void>

Per gemini review on #3482: the interface declared this as `() => void`
but the implementation is `async` and returns `Promise<void>`. The
mismatch silently lost the chainable promise — tests had to launder
it through `as unknown as Promise<void> | undefined` just to await.

Tighten the interface to `Promise<void>` and drop the cast in the
"closes the dialog immediately" test.

* fix(cli): persist auto-fired recap to chat recording so /resume keeps it

Per yiliang114 review on #3482: the manual `/recap` path persists across
`/resume` because the slash-command processor records every output
history item via `chatRecorder.recordSlashCommand({ phase: 'result',
outputHistoryItems })`, but the auto path called `addItem` directly
and bypassed that recorder. The result was an asymmetry where users
who triggered recap manually saw it after `/resume`, while users whose
recap fired automatically lost it.

Mirror the manual recording from useAwaySummary's `.then` callback —
record only the `result` phase (not invocation, since we don't want
a fake `> /recap` user line replayed) with the away-recap item as the
single output. Wrapped in try/catch because recap is best-effort and
must never surface a failure to the user.

Add useAwaySummary.test.ts covering:
- the recording path is taken on a successful auto-trigger
- the dedup gate (`shouldFireRecap`) suppresses the LLM call entirely,
  including the recording, when no new user turns happened since the
  last recap

* fix(cli): cast recap item via spread to satisfy strict tsc --build

CI's `tsc --build` (stricter than local `tsc --noEmit`) rejected the
direct `item as Record<string, unknown>` cast: HistoryItemAwayRecap's
literal `type: 'away_recap'` field doesn't overlap with `unknown`,
TS2352. Use the `{ ...item } as Record<string, unknown>` spread
pattern that the rest of the codebase (arenaCommand,
slashCommandProcessor's serializer) already uses for the same
SlashCommandRecordPayload field.
2026-04-21 14:39:13 +08:00
..
.vscode pre-release commit 2025-07-22 23:26:01 +08:00
assets feat(vscode-ide-companion/layout): add sidebar view and simplify chat positioning 2026-03-07 00:30:40 +08:00
schemas fix(cli): rework session recap rendering and add blur threshold setting (#3482) 2026-04-21 14:39:13 +08:00
scripts Merge branch 'main' of https://github.com/QwenLM/qwen-code into feat/unified-ui-for-vscode-extension 2026-01-28 18:52:37 +08:00
src feat(vscode-ide-companion): support /insight command (#2593) 2026-04-20 10:02:18 +08:00
.vscodeignore feat: add JSON Schema validation for VS Code settings 2026-02-13 17:32:18 +08:00
development.md Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
esbuild.js feat: add wasm build config (#2985) 2026-04-09 14:21:00 +08:00
eslint.config.mjs fix(vscode-ide-companion): 修复 Tailwind 可重用组件类和 ESLint 配置, 调整 ChatHeader 按钮样式 2025-11-29 18:13:50 +08:00
LICENSE Upload VSIX of companion VS Code extension (#4241) 2025-07-15 18:44:03 +00:00
NOTICES.txt refactor(acp): migrate to @agentclientprotocol/sdk and clean up handlers 2026-03-06 21:57:41 +08:00
package.json chore(release): bump version to 0.14.5 (#3298) 2026-04-15 22:43:29 +08:00
postcss.config.js refactor(vscode): 重构消息排序和展示逻辑 2025-11-28 22:35:31 +08:00
README.md fix: update TOS link in VS Code extension README 2026-03-19 17:36:32 +08:00
tailwind.config.js feat(webui): add webview container and isolate styles for VSCode integration 2026-01-17 10:53:32 +08:00
tsconfig.json fix: upgrade @lydell/node-pty to 1.2.0-beta.10 to fix PTY FD leak 2026-04-01 07:55:56 +08:00
vitest.config.ts refactor(vscode-ide-companion): Refactoring the project structure and updating dependencies 2025-11-29 13:16:58 +08:00

Qwen Code Companion

Version VS Code Installs Open VSX Downloads Rating

Seamlessly integrate Qwen Code into Visual Studio Code with native IDE features and an intuitive chat interface. This extension bundles everything you need — no additional installation required.

Demo

Features

  • Native IDE experience: Dedicated Qwen Code Chat panel accessed via the Qwen icon in the editor title bar
  • Native diffing: Review, edit, and accept changes in VS Code's diff view
  • Auto-accept edits mode: Automatically apply Qwen's changes as they're made
  • File management: @-mention files or attach files and images using the system file picker
  • Conversation history & multiple sessions: Access past conversations and run multiple sessions simultaneously
  • Open file & selection context: Share active files, cursor position, and selections for more precise help

Requirements

  • Visual Studio Code 1.85.0 or newer (also works with Cursor, Windsurf, and other VS Code-based editors)

Quick Start

  1. Install from the VS Code Marketplace or Open VSX Registry

  2. Open the Chat panel using one of these methods:

    • Click the Qwen icon in the top-right corner of the editor
    • Run Qwen Code: Open from the Command Palette (Cmd+Shift+P / Ctrl+Shift+P)
  3. Start chatting — Ask Qwen to help with coding tasks, explain code, fix bugs, or write new features

Commands

Command Description
Qwen Code: Open Open the Qwen Code Chat panel
Qwen Code: Run Launch a classic terminal session with the bundled CLI
Qwen Code: Accept Current Diff Accept the currently displayed diff
Qwen Code: Close Diff Editor Close/reject the current diff

Feedback & Issues

Contributing

We welcome contributions! See our Contributing Guide for details on:

  • Setting up the development environment
  • Building and debugging the extension locally
  • Submitting pull requests

Terms of Service and Privacy Notice

By installing this extension, you agree to the Terms of Service.

License

Apache-2.0