Commit graph

2349 commits

Author SHA1 Message Date
tanzhenxin
56392c7397
fix: lazy-load channel plugins to eliminate DEP0040 startup warning (#3134)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* fix: lazy-load channel plugins to eliminate DEP0040 startup warning

Channel plugins (telegram/weixin/dingtalk) were eagerly imported at
module load time via channel-registry.ts, which transitively loaded
grammy → node-fetch@2 → whatwg-url@5 → require("punycode"), triggering
the DEP0040 deprecation warning on every CLI invocation (Node 22+).

Switch to dynamic import() so plugins are only loaded when a user
actually runs `qwen channel` subcommands.

* fix(channels): use cached promise in ensureBuiltins to prevent race condition

Replace boolean flag with a cached promise so concurrent callers
properly await the same initialization instead of seeing an empty
registry.
2026-04-11 17:04:43 +08:00
tanzhenxin
7219469285
fix(channels): apply proxy settings to channel start command (#3136)
`qwen channel start` never calls `loadCliConfig`, so the proxy
configured via `--proxy` or `HTTPS_PROXY`/`HTTP_PROXY` env vars
was not applied. This caused Telegram's `getMe` (and all other
channel HTTP traffic) to bypass the proxy entirely.

The fix has two parts:

1. Resolve proxy in `start.ts` bootstrap and call
   `setGlobalDispatcher(new ProxyAgent(...))` for native fetch()
   calls (file downloads, other channels). This mirrors the same
   pattern used by Config constructor in the main CLI path.

2. Thread the proxy URL through `ChannelBaseOptions` so adapters
   can configure their own HTTP clients. TelegramAdapter passes
   an `HttpsProxyAgent` to grammy's `baseFetchConfig.agent` since
   grammy uses node-fetch which ignores undici's global dispatcher.

Fixes #3122
2026-04-11 16:44:14 +08:00
Shaojin Wen
61ad9db9c1
feat(cli): queue input editing — pop queued messages for editing via ↑/ESC (#2871)
* feat(cli): add queue input editing via Up arrow key

Allow users to edit queued messages by pressing the Up arrow key when
the cursor is at the top of the input. All queued messages are popped
into the input field for revision before resubmission, reducing wasted
turns from incorrect queued instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add missing mocks for InputPrompt tests and attachment mode guard

- Add popAllQueuedMessages mock and messageQueue to UIState/UIActions
  mocks in InputPrompt.test.tsx to fix 25 test failures
- Add !isAttachmentMode guard to prevent queue pop from conflicting
  with attachment navigation
- Add single-message popAllMessages test case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address Copilot review - restrict to Up arrow, add tests, update docs

- Only trigger queue pop on NAVIGATION_UP (arrow key), not HISTORY_UP
  (Ctrl+P), preserving existing Ctrl+P history navigation behavior
- Update AsyncMessageQueue class docs to describe popLast() LIFO semantics
- Add InputPrompt tests: Up arrow pops queue, Up arrow falls back to
  history when queue empty, Ctrl+P not intercepted by queue pop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update fileoverview docs and make popAllMessages atomic via ref

- Update @fileoverview to describe FIFO+LIFO capability instead of
  "Simple FIFO queue"
- Use queueRef to make popAllMessages atomic, preventing duplicate
  pops from key auto-repeat before React re-renders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: sync queueRef in addMessage/clearQueue and fall through on null pop

- Update queueRef inside addMessage setter and clearQueue to keep ref
  in sync between renders, preventing stale reads after clearQueue
- When popAllQueuedMessages returns null (queue already cleared), fall
  through to normal history navigation instead of consuming the key

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove dead popLast() and align popAllMessages separator to \n\n

- Remove unused AsyncMessageQueue.popLast() (no production callers)
- Change popAllMessages join separator from \n to \n\n for consistency
  with getQueuedMessagesText and auto-submit behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use hook's drainQueue for mid-turn drain to prevent double-consumption race

The midTurnDrainRef previously used a separate messageQueueRef (synced
from React state), while popAllMessages uses the hook's internal
queueRef. If a tool completed between popAllMessages clearing queueRef
and React re-rendering, midTurnDrainRef would read stale data and
consume the same messages a second time.

Switching to the hook's drainQueue makes both paths read from the same
synchronous ref, eliminating the window for double consumption.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add missing popAllMessages mock and prepend branch test

Add popAllMessages to useMessageQueue mock in AppContainer tests.
Add test for prepending queued messages before existing input text.

* feat: add ESC trigger, cursor preservation, and progressive hint

- ESC pops queued messages before double-ESC clear logic
- Cursor stays at user's editing position after pop via moveToOffset
- Extract popQueueIntoInput helper to share logic between Up and ESC
- QueuedMessageDisplay hint hides after 3 empty→non-empty transitions

* test: add null-pop fallthrough test for queue race condition

Verify that when React state shows non-empty queue but the ref is
already drained (popAllQueuedMessages returns null), Up arrow falls
through to normal history navigation instead of getting stuck.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 14:38:32 +08:00
tanzhenxin
285a627886
fix(input): preserve tab characters in pasted content (#3045)
* fix(input): preserve tab characters in pasted content

Tab-separated data pasted from spreadsheets (e.g. Excel) was silently
lost through three interception layers: stripUnsafeCharacters filtered
tab as a C0 control char, TextInput consumed tab for autocomplete, and
InputPrompt consumed tab for suggestion acceptance.

- Add tab (0x09) to the preserve list in stripUnsafeCharacters
- Skip tab→autocomplete interception when key.paste is true
- Skip tab→suggestion-accept in InputPrompt when key.paste is true

* test: skip flaky AskUserQuestionDialog test on Windows

The "shows unanswered questions as (not answered) in Submit tab" test
fails intermittently on Windows CI due to arrow key navigation timing
issues in the ink test renderer.
2026-04-11 13:02:39 +08:00
tanzhenxin
6f693f1b71
fix(cli): check NEWLINE before SUBMIT in TextInput to fix multiline input (#3068) (#3094)
The `|| key.name === 'return'` fallback in TextInput matched every Return
keypress (Shift+Enter, Ctrl+Enter, etc.) and routed them all to the submit
path, making the NEWLINE handler dead code. Multiline inputs like the agent
creation description step could not insert newlines via keyboard.

Reorder checks so NEWLINE is evaluated first in multiline mode, and restrict
the broad return fallback to single-line inputs only.
2026-04-11 13:02:28 +08:00
Shaojin Wen
2ac099caaf
fix: prevent statusline script from corrupting settings.json (#3091)
* fix: prevent statusline script from corrupting settings.json

Some models generate shell commands with complex quoting (e.g. single-quote
escaping like '\'') that break JSON syntax when written to settings.json,
causing qwen-code to fail to start with a FatalConfigError.

This adds four layers of defense:

1. **Agent prompt** (builtin-agents.ts): Require commands using jq/pipes/quotes
   to be saved as script files instead of inline in settings.json. Mark examples
   as script-only to prevent models from copying them inline.

2. **Write validation** (commentJson.ts): Validate JSON output before writing
   to disk in updateSettingsFilePreservingFormat.

3. **Startup recovery** (settings.ts): When settings.json has invalid JSON,
   try .orig backup first, then degrade gracefully to empty settings instead
   of crashing. Rename corrupted file to .corrupted for manual recovery.
   Show warning to user via migrationWarnings.

4. **Test update** (settings.test.ts): Update test to verify graceful
   degradation behavior instead of expecting FatalConfigError.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review comments on statusline JSON corruption fix

1. Backup recovery now surfaces warning via migrationWarnings (reviewer: P2 correctness)
2. Corrupted file uses timestamped suffix to avoid overwriting (reviewer: P2 robustness)
3. Remove misleading underscore prefix on used catch variable (reviewer: P2 code quality)
4. updateSettingsFilePreservingFormat returns boolean (reviewer: P2 correctness)
5. Add 3 new tests: backup recovery, both-corrupted, rename-failure (reviewer: P2 testing)
6. Consistent shebang lines in agent prompt examples (reviewer: P3 nit)
7. Improve catch block error message for backup recovery (reviewer: P2 correctness)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: warningMsg says "renamed" even when rename fails

Move warningMsg construction after renameSync so the message accurately
reflects the outcome: "renamed to X" on success, "fix manually" on failure.
Add assertion to rename-failure test verifying the fallback message.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:55:18 +08:00
Shaojin Wen
ec1787b846
fix(cli): improve markdown table rendering in terminal (#2914)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* fix(cli): improve markdown table rendering in terminal

* fix(cli): restore theme colors and inline markdown rendering in tables

Improvements over previous commit:
- Restore theme.border.default color for table borders
- Restore theme.text.link color + bold for table headers
- Add renderMarkdownToAnsi() to render **bold**, `code`, *italic*,
  ~~strikethrough~~, <u>underline</u>, [links](url), and bare URLs
  as ANSI-styled text in table cells (mirrors RenderInline behavior)
- Use raw ANSI escape codes instead of chalk (chalk.level=0 in tests)
- Remove dead code: INLINE_MARKDOWN_REGEX, hasInlineMarkdown,
  ANSI_BOLD_START/END constants, unused vi/beforeEach in tests
- Update 8 snapshots to reflect themed output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address Copilot review comments on table rendering

- renderRowLines: normalize cells to exactly colCount (pad/truncate)
  to prevent undefined access when row has fewer cells than headers
- calculateMaxRowLines: iterate colCount instead of row.length to
  prevent undefined columnWidths access for extra cells
- tableSeparatorRegex: add (?=.*\|) lookahead to require at least one
  pipe character, preventing `---` (horizontal rule) from being
  mis-parsed as a table separator
- Add test: horizontal rule after pipe line is not a table separator

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address Copilot round-2 review on table rendering

- idealWidths: use getRenderedWidth() (markdown→ANSI→stripAnsi→stringWidth)
  instead of getPlainTextLength() so link URLs are accounted for in
  column width calculation
- calculateMaxRowLines: use getFormattedCellText() (same as renderRowLines)
  so vertical fallback decision matches actual rendered row height
- renderVerticalFormat: normalize row to colCount (pad/truncate) for
  consistency with horizontal format
- renderVerticalFormat: render markdown in labels via renderMarkdownToAnsi()
  instead of showing raw syntax
- Remove unused getCellPlainText helper and getPlainTextLength import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address Copilot round-3 review on table rendering

- Early return empty <Box /> when headers is empty (colCount === 0)
  to prevent malformed border output
- Always apply theme.text.link color to header cells regardless of
  ANSI content, matching original Ink implementation behavior
- Validate separator column count matches header column count before
  entering table mode, preventing mismatched separators like
  `| A | B |` followed by `|---|` from creating invalid tables
- Add test for column count mismatch detection
- Update 2 snapshots for consistent header link color

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address Copilot round-4 review on table rendering

- getMinWordWidth: use renderMarkdownToAnsi output so link URLs are
  included as unbreakable tokens in minimum column width calculation
- Remove now-unused stripInlineMarkdown function
- Header alignment: respect explicit alignment markers from separator;
  only default to center when no alignment is specified for the column
- Header color nesting: re-apply theme.text.link color after inner
  foreground resets (from inline code/links) to match Ink's nested
  color behavior where parent color is restored after child resets
- Add getColorCode() helper for extracting raw ANSI color escape

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address Copilot round-5 review on table rendering

- Apply theme.text.primary color to non-header cells and re-apply
  after inner foreground resets, matching header recolor behavior
- Use nullish coalescing (??) for vertical format labels so empty
  header strings are preserved instead of replaced with Column N

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): re-apply cell color after full ANSI reset (\x1b[0m)

Add recolorAfterResets() helper that handles both \x1b[39m (foreground
reset) and \x1b[0m (full SGR reset). Applies to both header and body
cells so mixed ANSI content keeps consistent theme coloring.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): apply recolorAfterResets to vertical format labels

Vertical fallback labels with inline markdown (code, URLs) now
re-apply link color after SGR resets, consistent with horizontal
header/body cell behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): apply primary color to vertical format values

Vertical fallback values now get theme.text.primary color with
recolorAfterResets, consistent with horizontal body cell styling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): preserve internal blank lines in wrapped cell content

wrapText now only trims trailing empty lines (wrap-ansi artifacts)
instead of filtering all empty lines, preserving intentional blank
lines within multi-paragraph cell content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): validate hex colors and deduplicate applyColor/getColorCode

- Add HEX_COLOR_RE validation; invalid hex like #ff00 or #gg0000
  now returns unchanged text instead of producing NaN in ANSI escapes
- Refactor applyColor to delegate to getColorCode, eliminating
  duplicated hex parsing logic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): precompute cell metrics and fix column width overflow

- Precompute per-cell rendered text, visible width, and min word width
  once via computeMetrics(), eliminating repeated renderMarkdownToAnsi
  calls across width calculation, max-row-lines check, and rendering
- Add post-pass in totalMin > availableWidth branch: shave wider
  columns until sum(columnWidths) <= availableWidth, preventing
  MIN_COLUMN_WIDTH floor from causing unnecessary vertical fallback
- Remove now-unused getMinWordWidth standalone function

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:10:01 +08:00
Lassana siby
9a636ef812
feat(i18n): add French (fr-FR) locale support (#3126)
* feat(i18n): add French (fr) locale translations

* fix translation key mismatch for 'Models: Qwen latest models'

fix translation key mismatch for 'Models: Qwen latest models'

Add missing trailing \n to the English lookup key so the French
translation is correctly matched by the i18n system.

Suggested by @wenshao in code review.

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* fix(i18n): fix translation key mismatch for 'Models: Qwen latest models'

* fix(schema): add fr to settings.schema.json language enum

* fix(i18n): remove duplicate key 'Models: Qwen latest models' in fr.js

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-04-11 11:07:01 +08:00
易良
81ccbb976c
fix(cli): prioritize slash command completions (#3104) 2026-04-11 11:04:58 +08:00
Shaojin Wen
4c67670ef0
feat: show description for active setting in /settings dialog (#3116)
* feat: show description for active setting in /settings dialog

Display the schema description of the currently highlighted setting
below the settings list, so users can understand what each option does
without needing to check external documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: update SettingsDialog snapshots for description display

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 10:45:54 +08:00
Shaojin Wen
a7771bbb93
feat: replace text input with model picker for Fast Model in /settings (#3120)
The Fast Model setting in the settings dialog previously used a plain text
input, making it hard for users to discover available models. This replaces
it with the same model picker dialog used by `/model --fast`, adds a `▸`
visual indicator for sub-dialog settings, and supports right arrow to open
and left arrow to return.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 10:38:02 +08:00
apophis
505be40f82
feat(cli): add CJK word segmentation with Intl.Segmenter (#2942) 2026-04-11 10:05:42 +08:00
Shaojin Wen
520f1e2420
fix: add --fast hint to /model description for discoverability (#3086)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
Add "(--fast for suggestion model)" to the /model command description
so users can discover the feature from the command list, since --fast
completion no longer appears on empty input.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:49:28 +08:00
pomelo
cf81ac47ff
Merge pull request #3042 from YuchenLiang00/fix/context-command-detail-missing
fix(cli): add 'detail' subcommand to /context command
2026-04-10 12:12:07 +08:00
Shaojin Wen
5482044e59
fix: improve /model --fast description clarity and prevent accidental activation (#3077)
Replace vague "background tasks" with specific "prompt suggestions and speculative
execution" in the --fast flag description across all i18n locales, docs, and VS Code
schema. Update example model name from qwen3.5-flash to qwen3-coder-flash. Also fix
completion logic to require a non-empty partial arg before suggesting --fast, preventing
Tab+Enter from accidentally entering fast model mode.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 12:09:46 +08:00
Shaojin Wen
746f67f436
refactor: rename verboseMode to compactMode for better UX clarity (#3075)
The "Compact Mode" label is more intuitive than "Verbose Mode" for users,
as it directly describes the default compact view experience. This change
inverts the boolean semantics (compactMode=false means show full output)
and exposes the setting in the /settings dialog (showInDialog: true).

- Rename ui.verboseMode → ui.compactMode with inverted default (false)
- Rename VerboseModeContext → CompactModeContext (file and exports)
- Rename TOGGLE_VERBOSE_MODE → TOGGLE_COMPACT_MODE in key bindings
- Update all consumer components with inverted logic
- Update i18n keys across 6 locales (verbose → compact)
- Update VS Code settings schema
- Add ui.compactMode documentation to settings.md
- Fix Ctrl+O description in keyboard-shortcuts.md
2026-04-10 11:55:50 +08:00
tanzhenxin
98a0f78c4b
fix(weixin): add missing iLink headers to QR code login and clean up error output (#3044)
PR #2943 fixed headers in buildHeaders() but the login flow in
waitForLogin() still used a hardcoded incomplete header object.
Reuse the shared buildHeaders() so all endpoints send consistent
iLink-App-Id and iLink-App-ClientVersion headers.

Also wrap channel.connect() in startSingle() with a try/catch so
configuration errors print a clean message instead of dumping the
yargs help text and a stack trace.
2026-04-10 11:36:02 +08:00
克竟
5947512a79 fix: prevent Shift+Tab from accepting prompt placeholder suggestion (#3051)
Add !key.shift guard to the Tab key handler for prompt suggestion
acceptance, so Shift+Tab only toggles approval mode without inserting
the placeholder text into the input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:18:09 +08:00
Edenman
4d2d4432d5
Merge pull request #2923 from QwenLM/feature/status-line-customization
Some checks are pending
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
feat(ui): add customizable status line with /statusline command
2026-04-09 19:23:08 +08:00
qqqys
8119b90433
Merge pull request #2932 from QwenLM/feat/review-skill-improvements
feat(review): enhance /review with deterministic analysis, autofix, and security hardening
2026-04-09 19:14:03 +08:00
wenshao
f25fc047f1 test: add comprehensive tests for useStatusLine hook and statuslineCommand
Cover config validation, command execution with exec options, stdin JSON
payload, stale generation rejection, debouncing, config removal, cleanup
on unmount, EPIPE handling, command hot-reload, all state change triggers
(token count, model, branch, vim toggle, file lines), and process management.
2026-04-09 15:50:41 +08:00
wenshao
36aadd7fa1 fix: restore i18n keys for 'Press Ctrl+O to show full tool output'
The previous commit reverted the code to use the original i18n key
but the locale files still had the renamed key, causing translations
to not resolve.
2026-04-09 15:07:33 +08:00
wenshao
55116f86e3 fix: revert verbose mode hint to original descriptive text
Restore "Press Ctrl+O to show full tool output" which is clearer
than "toggle verbose mode" per PR review feedback.
2026-04-09 14:42:33 +08:00
zhangxy-zju
9c0bbfba6c
feat(plan): add "Yes, restore previous mode" option when exiting plan mode (#3008)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* feat(plan): add "Yes, restore previous mode" option when exiting plan mode

When exiting plan mode, users previously had no way to restore their
original approval mode (e.g. YOLO). Add a new default option that
restores the pre-plan approval mode, with a dynamic label showing
which mode will be restored.

Closes #3002

* test: add fallback test for RestorePrevious when no prePlanMode recorded

* fix: handle RestorePrevious in telemetry and ACP mode notification

- Add RestorePrevious to telemetry decision mapping as ACCEPT
- Fix sendCurrentModeUpdateNotification to read actual mode for
  RestorePrevious instead of defaulting to 'default'

* test: add plan confirmation tests for RestorePrevious in permissionUtils
2026-04-09 14:25:38 +08:00
pikachu
3e8b3c688f
fix(cli): serialize subagent confirmation focus to prevent concurrent input conflicts (#2930)
* fix: serialize subagent confirmation focus to prevent concurrent input conflicts

When multiple subagents run in parallel and each triggers a confirmation
prompt, all prompts previously received keyboard focus simultaneously,
causing a single keypress to be dispatched to every active confirmation.

This change introduces a first-come-first-served focus lock mechanism:
- Track subagents with pending confirmations via a type guard
- Use a useRef-based lock so only one confirmation is focused at a time
- Automatically promote focus to the next pending subagent on resolution
- Show a waiting indicator on non-focused confirmations

Fixes #2929

* fix(cli): use dedicated prop for subagent approval waiting state

---------

Co-authored-by: 思晗 <housihan.hsh@alibaba-inc.com>
2026-04-09 14:24:59 +08:00
胡玮文
32e7b632b8
refactor: centralize IDE diff interaction in CoreToolScheduler (#2728)
- Move openDiff/confirmation handling from edit.ts and write-file.ts into
  CoreToolScheduler.openIdeDiffIfEnabled(), called after permission hooks
- Use structuredClone in buildInvocation to prevent params mutation leaking
  to LLM history (fixes #2709 token waste)
- Use confirmationDetails as single data source for IDE diff content,
  only rely on ModifyContext.createUpdatedParams() for parameter transform
- Skip inline modify when IDE content unchanged, preserving original tool
  params for multi-edit-on-same-file scenarios (mitigates #2702)
- Remove ideConfirmation field from ToolEditConfirmationDetails
- Remove dead resolveIdeDiffForOutcome from ACP Session.ts
- Fix memory tool scope fallback in createUpdatedParams

Closes #2709
Closes #2673
2026-04-09 14:20:48 +08:00
Shaojin Wen
d22b7e61ee
test: add tests for confirmation-bus, prompt-registry, and cli/core modules (#2272)
* test: add tests for confirmation-bus, prompt-registry, and cli/core modules

Add 42 new tests covering previously untested core modules:
- MessageBus: publish, subscribe/unsubscribe, request-response pattern (13 tests)
- PromptRegistry: register, dedup, query by server, clear, remove (11 tests)
- performInitialAuth: success, failure, no authType cases (3 tests)
- validateTheme: found, not found, no config cases (4 tests)
- initializeApp: i18n, auth, theme, IDE mode, auth dialog logic (11 tests)

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

* fix: improve test quality - copyright headers, env safety, cleanup

- Fix copyright headers from Google LLC to Qwen Code in all 5 test files
- Use vi.stubEnv() instead of manual process.env mutation in initializer test
- Add removeAllListeners() cleanup in message-bus debug test
- Add void prefix to un-awaited publish() calls in message-bus test
- Verify invoke reference preserved after prompt rename in prompt-registry test

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

* test(message-bus): add AbortSignal coverage for request()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 13:54:59 +08:00
YuchenLiang00
84f80201c7 fix(cli): add 'detail' subcommand to /context command
The /context command was missing the subcommand autocomplete feature
that other commands like /stats have. Now users can type '/context '
and see 'detail' as a suggestion in the dropdown.

- Added 'detail' subCommand to contextCommand with its own description
- Subcommand delegates to main action with 'detail' arg
- Added missing translation key for full description in zh.js
- Updated commands.md documentation

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-09 11:00:04 +08:00
tanzhenxin
e0aeee5414
chore: remove outdated pr-review skill (#3028)
* chore: remove outdated pr-review skill

The .qwen/skills/pr-review skill is outdated and no longer needed.
Also removes the dangling reference from terminal-capture skill.

* chore: add token-stats script to e2e-testing skill

* fix(test): remove flaky AskUserQuestionDialog Submit tab test

The "shows Submit tab for multiple questions" test fails on macOS CI
due to terminal width truncation causing "Submit answers" to render
as just "Submit".
2026-04-09 10:54:10 +08:00
wenshao
6de5c9e530 Merge remote-tracking branch 'origin/main' into feat/review-skill-improvements 2026-04-09 08:52:01 +08:00
wenshao
df3cfd1e83 fix(review): prepend YOUR_MODEL_ID declaration for model attribution
Some models (e.g., glm-5.1) ignore the {{model}} template in code
blocks and write their own footer without the model name. Fix:

1. BundledSkillLoader prepends YOUR_MODEL_ID="glm-5.1" as a top-level
   declaration at the start of the skill body — impossible to miss
2. SKILL.md references YOUR_MODEL_ID in footer instructions
3. Empty model → empty string (no "unknown" — prefer omission)
4. YOUR_MODEL_ID declaration only prepended when model is available

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 02:38:17 +08:00
Shaojin Wen
f208801b0e
fix(followup): prevent tool call UI leak and Enter accept buffer race (#2872)
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* fix(core): prevent followup suggestion input/output from appearing in tool call UI

The follow-up suggestion generation was leaking into the conversation UI
through three channels:

1. The forked query included tools in its generation config, allowing the
   model to produce function calls during suggestion generation. Fixed by
   setting `tools: []` in runForkedQuery's per-request config (kept in
   createForkedChat for speculation which needs tools).

2. logApiResponse and logApiError recorded suggestion API events to the
   chatRecordingService, causing them to appear in session JSONL files
   and the WebUI. Fixed by adding isInternalPromptId() guard that skips
   chatRecordingService for 'prompt_suggestion' and 'forked_query' IDs.
   uiTelemetryService.addEvent() is preserved so /stats still tracks
   suggestion token usage.

3. LoggingContentGenerator logged suggestion requests/responses to the
   OpenAI logger and telemetry pipeline. Fixed by skipping logApiRequest,
   buildOpenAIRequestForLogging, and logOpenAIInteraction for internal
   prompt IDs. _logApiResponse is preserved (for /stats) but its
   chatRecordingService path is filtered by fix #2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: deduplicate isInternalPromptId into shared export from loggers.ts

Address review feedback: extract isInternalPromptId() to a single
exported function in telemetry/loggers.ts and import it in
LoggingContentGenerator, eliminating the duplicate private method.

Also update loggingContentGenerator.test.ts mock to use importOriginal
so the real isInternalPromptId is available during tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: extract isInternalPromptId to shared utils, add tests

Address maintainer review feedback:

1. Move isInternalPromptId() to packages/core/src/utils/internalPromptIds.ts
   using a ReadonlySet for the ID registry. Adding new internal prompt IDs
   only requires changing one file. loggers.ts re-exports for compatibility,
   loggingContentGenerator.ts imports directly from utils.

2. Extract `tools: []` magic value to a frozen NO_TOOLS constant in
   forkedQuery.ts.

3. Add unit tests for isInternalPromptId: prompt_suggestion → true,
   forked_query → true, user_query → false, empty string → false.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address Copilot review — docs, stream optimization, tests

1. Update forkedQuery.ts module docs to reflect that runForkedQuery
   overrides tools: [] at the per-request level while createForkedChat
   retains the full generationConfig for speculation callers.

2. Propagate isInternal into loggingStreamWrapper to skip response
   collection and consolidation for internal prompts, avoiding
   unnecessary CPU/memory overhead.

3. Add logApiResponse chatRecordingService filter tests: verify
   prompt_suggestion/forked_query skip recording while normal IDs
   still record.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: deep-freeze NO_TOOLS, add internal prompt guard tests

Address Copilot review round 3:

1. Deep-freeze NO_TOOLS.tools array to prevent shared mutable state
   across forked query calls.

2. Add LoggingContentGenerator tests verifying that internal prompt IDs
   (prompt_suggestion, forked_query) skip logApiRequest and OpenAI
   interaction logging while preserving logApiResponse.

3. Add logApiError chatRecordingService filter tests matching the
   existing logApiResponse coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: reconcile createForkedChat JSDoc with module header

Clarify that createForkedChat retains the full generationConfig
(including tools) for speculation callers, while runForkedQuery
strips tools at the per-request level via NO_TOOLS.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: build errors and Copilot round 4 feedback

1. Fix NO_TOOLS type: Object.freeze produces readonly array incompatible
   with ToolUnion[]. Use Readonly<Pick<>> instead; spread in requestConfig
   already creates a fresh mutable copy per call.

2. Fix test missing required 'model' field in ContentGeneratorConfig.

3. Track firstResponseId/firstModelVersion in loggingStreamWrapper so
   _logApiResponse/_logApiError have accurate values even when full
   response collection is skipped for internal prompts.

4. Strengthen OpenAI logger test assertion: assert OpenAILogger was
   constructed (not guarded by if), then assert logInteraction was
   not called.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove dead Object.keys check, add streaming internal prompt test

1. Simplify runForkedQuery: requestConfig always has tools:[] from
   NO_TOOLS spread, so the Object.keys().length > 0 ternary is dead
   code. Pass requestConfig directly.

2. Add generateContentStream test for internal prompt IDs to match
   the existing generateContent coverage, ensuring the streaming
   wrapper also skips logApiRequest and OpenAI interaction logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent Enter accept from re-inserting suggestion into buffer

When accepting a followup suggestion via Enter, accept() queued
buffer.insert(suggestion) in a microtask that executed after
handleSubmitAndClear had already cleared the buffer, leaving the
suggestion text stuck in the input.

Add skipOnAccept option to accept() so the Enter path bypasses the
onAccept callback. Also add runForkedQuery unit tests verifying
tools: [] is passed in per-request config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(core): add speculation to internal IDs, fix logToolCall filtering, improve suggestion prompt

- Add 'speculation' to INTERNAL_PROMPT_IDS so speculation API traffic
  and tool calls are hidden from chat recordings and tool call UI
- Add isInternalPromptId check to logToolCall() for consistency with
  logApiError/logApiResponse
- Improve SUGGESTION_PROMPT: prioritize assistant's last few lines and
  extract actionable text from explicit tips (e.g. "Tip: type X")
- Fix garbled unicode in prompt text
- Update design docs and user docs to reflect changes
- Add test coverage for all new behavior

* fix(core): deep-freeze NO_TOOLS, add speculation to loggingContentGenerator tests

- Object.freeze NO_TOOLS and its tools array to prevent runtime mutation
- Add 'speculation' to loggingContentGenerator internal prompt ID tests
  for consistency with loggers.test.ts and internalPromptIds.ts

* fix(core): fix NO_TOOLS Object.freeze type error

Use `as const` with type assertion to satisfy TypeScript while keeping
runtime immutability via Object.freeze.

* refactor(core): remove unused isInternalPromptId re-export from loggers.ts

All consumers import directly from utils/internalPromptIds.js.
The re-export was dead code with no importers.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:07:03 +08:00
wenshao
3364cf880f Merge remote-tracking branch 'origin/main' into feat/review-skill-improvements 2026-04-08 23:09:01 +08:00
chinesepowered
5a5a175f00
fix(ui): Remove dead dirs state and unused hook parameter from InputPrompt (#2891)
* fix(ui): prevent useEffect from running every render in InputPrompt

getDirectories() returns a new array reference each call, causing the
useEffect dependency check to fail on every render. Move the call
inside the effect body and use stable dependencies [config, dirs] so
the effect only re-runs when they actually change.

* fix(ui): use serialized dep key for directory change detection

Move from [config, dirs] deps (both stable refs that miss external
changes) to a dirKey string (join of current directories). This
preserves the perf fix (no new array ref in deps) while still
detecting directory additions/removals from /add-dir etc.

* refactor(cli): remove unused dirs state from InputPrompt

The dirs parameter passed to useCommandCompletion() was never read
inside that hook, making the dirs state and sync effect in InputPrompt
dead code. Remove the parameter, the state, the effect, and all test
call-site args.
2026-04-08 22:18:22 +08:00
wenshao
2a28132fed fix(footer): suppress hint when status line active, hide on exit prompts
- Hide "? for shortcuts" when a custom status line is configured
  (status line already occupies the top row, hint is redundant)
- Hide status line during Ctrl+C/D exit prompts to keep footer
  at one row during exit flow
- Matches upstream Claude Code suppressHint + exitMessage behavior
2026-04-08 21:03:21 +08:00
wenshao
63a14ae909 fix(footer): remove Box wrapper from indicators for proper truncation
AutoAcceptIndicator and ShellModeIndicator returned Box>Text, which
prevented the parent Text wrap="truncate" from working (ink cannot
nest Box inside Text). Change both to return plain Text elements
so the footer's truncation applies correctly on narrow terminals.
2026-04-08 20:59:19 +08:00
wenshao
50bf5cc72d fix(footer): truncate hints/mode row to prevent extra lines
Wrap leftBottomContent in Text with wrap="truncate" so the
hints/mode row stays on a single line, matching upstream behavior.
This guarantees the footer is at most 2 rows (status line + hints).
2026-04-08 20:57:03 +08:00
wenshao
cf879f0b58 refactor(footer): match upstream layout — status line + hints coexist
Restructure footer to match Claude Code's layout:
- Left column: status line (top, truncated) + hints/mode (bottom)
- Both rows coexist instead of being mutually exclusive
- Status line uses wrap="truncate" to guarantee single line
- Approval mode returns to the hints row (inline, not separate row)
- Left column uses flexShrink for narrow terminals
2026-04-08 20:54:07 +08:00
wenshao
f9b88c8f8e fix(footer): use wrap instead of truncate for status line text
Allow status line text to wrap to the next line when the terminal
is too narrow, preserving complete information instead of truncating.
2026-04-08 20:48:45 +08:00
wenshao
eaaa55389b fix(footer): prevent status line from pushing right items off screen
Add flexGrow/flexShrink to left section so it takes available space
but yields to right items. Add flexShrink={0} to right section so
context usage, verbose, sandbox indicators are never compressed.
Add overflow="hidden" to left section for clean truncation.
2026-04-08 20:44:47 +08:00
wenshao
a1c33cdb5e refactor(status-line): remove padding config
The status line is now inlined in the footer's left section,
so horizontal padding is no longer applicable. Remove padding
from StatusLineConfig, settings schema, JSON schema, and docs.
2026-04-08 20:24:33 +08:00
wenshao
7804946970 refactor(footer): inline status line in footer left section
Move status line from a dedicated row below the footer into the
footer's left section, replacing "? for shortcuts" when active.
High-priority messages (Ctrl+C/D, Esc, vim INSERT, shell mode)
still override the status line.

Move approval mode indicator to a separate row below the footer,
shown only when mode is non-default. This eliminates the empty
gap in default mode and matches upstream layout.
2026-04-08 20:18:06 +08:00
wenshao
841eb3c70c fix: address reviewer feedback — stdin error logging, JSON schema, i18n
- Log non-EPIPE stdin errors at debug level instead of silently
  swallowing them
- Add proper JSON schema properties for statusLine (type, command,
  padding) with enum, required, and additionalProperties constraints
- Add missing i18n entry for /statusline command description
2026-04-08 20:08:36 +08:00
qqqys
36482f04f7
fix(cli): fix csiUPrefix error in Linux/Wayland (#2995) 2026-04-08 19:08:51 +08:00
wenshao
55b1ab174d fix(status-line): derive remaining_percentage from used and reject empty commands
- Compute remaining_percentage as round(100 - used) to guarantee
  used + remaining always sums to exactly 100.0
- Reject empty or whitespace-only command strings in config validation
2026-04-08 18:58:06 +08:00
pomelo
1e87388ffd
feat: add qwen3.6-plus model to ModelStudio Coding Plan (#3015)
- Add qwen3.6-plus to both China and Global/Intl regions as the first
  model in the Coding Plan template (1M context, enable_thinking)
- Set qwen3.6-plus as the new default MAINLINE_CODER_MODEL
- Add image+video input modality support for qwen3.6-plus

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-08 18:57:07 +08:00
wenshao
0be4d32cb0 Merge remote-tracking branch 'origin/main' into feature/status-line-customization 2026-04-08 18:50:10 +08:00
wenshao
520ed4e040 fix: address audit findings across status-line and verbose-mode features
- useStatusLine: clamp used/remaining percentage to [0,100], track
  totalLinesRemoved as trigger, clean up debounceRef on unmount
- AppContainer: use drainQueue from useMessageQueue instead of manual
  messageQueueRef to avoid stale-ref reads between renders
- builtin-agents: add WRITE_FILE tool to statusline-setup agent, improve
  PS1 parsing instructions (unquoted assignments, \[/\]/\e escapes),
  strip ANSI colors, remove unreachable symlink instruction
- CompactToolGroupDisplay: fix misleading hint "show full tool output"
  to "toggle verbose mode" across all 6 locales
- AppContainer.test: add missing drainQueue mock
2026-04-08 18:45:44 +08:00
wenshao
c36953816c fix(test): add missing metrics and model fields to Footer test mock
useStatusLine hook accesses sessionStats.metrics.tools.totalCalls,
sessionStats.metrics.files.totalLinesAdded, and currentModel which
were missing from the mock UIState, causing a TypeError crash during
render and making 4 Footer tests fail in CI.
2026-04-08 18:28:40 +08:00
tanzhenxin
d9a1275913
Merge pull request #2954 from QwenLM/fix/disable-followup-suggestions-default
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
fix(cli): disable follow-up suggestions by default
2026-04-08 18:02:00 +08:00