feat: show description for active setting in /settings dialog#4
Open
wenshao wants to merge 10 commits into
Open
feat: show description for active setting in /settings dialog#4wenshao wants to merge 10 commits into
wenshao wants to merge 10 commits into
Conversation
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>
…error output (QwenLM#3044) PR QwenLM#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.
…enLM#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
… activation (QwenLM#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>
…-detail-missing fix(cli): add 'detail' subcommand to /context command
…#3069) Compact mode confirmation dialog uses ProceedAlways for "Allow always" option, but persistPermissionOutcome() only handled ProceedAlwaysProject and ProceedAlwaysUser, causing the permission to never be saved. Now ProceedAlways is treated as project scope (same as ProceedAlwaysProject).
…M#3086) 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>
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>
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wenshao
pushed a commit
that referenced
this pull request
May 21, 2026
* feat(cli): per-turn /diff with interactive dialog (QwenLM#4272) `/diff` now opens an interactive dialog in TUI mode with: - Current (working tree vs HEAD) plus one entry per past user turn - ←/→ to switch source, ↑/↓ to select a file, Enter for hunks, Esc to close - File list paginates at 8 entries, with new/deleted/untracked/binary tags Per-turn diffs are computed by FileHistoryService.getTurnDiff(promptId), which compares the snapshot at the start of that turn against the next snapshot (or the live worktree for the most recent turn). Files the snapshotter failed to capture are skipped rather than rendered against a stale predecessor. Non-interactive and ACP modes keep the existing plain-text summary so pipes, logs, and remote transports are unchanged. * refactor(core): align getTurnDiff promptId lookup with findSnapshot Two small audit-driven cleanups, no behavior change in normal sessions: - Match findSnapshot's last-occurrence-wins semantics so /rewind and /diff agree if a promptId is ever reused (defensive — promptIds are unique per submission in practice). - Drop the redundant `?? undefined` in the fast-path skip; `?.` already short-circuits to undefined, so the extra coalesce was noise. * fix(cli): head-truncate file paths in diff dialog to keep layout intact Long absolute paths (~> 90 chars) previously overflowed the dialog and wrapped, shattering the file-list and detail-view alignment. Reserve a fixed budget for the tag/stats columns, head-truncate the path with a leading ellipsis so the basename — the part users actually read — is always visible. Also drop the dead MAX_FILES_FOR_DETAILS guard from currentToFiles: fetchGitDiff already bounds perFileStats at MAX_FILES (=50), and returns an empty map when the diff exceeds MAX_FILES_FOR_DETAILS upstream, so the 500-entry counter could never fire. * fix(diff): address review comments — backup-read safety, oversized cap, sanitization, Ctrl+C routing Five review-driven fixes; details inline on the PR. Core (getTurnDiff): - Treat unreadable backup files as "unavailable" (return null for the row) instead of coercing to '' and fabricating phantom hunks. Same guard for both before and after endpoints. - Cap structuredPatch input at MAX_DIFF_SIZE_BYTES so a single multi-MB file in history can no longer balloon TUI memory when /diff opens. Oversized rows still surface in the file list with best-effort line stats and a new `oversized` flag. CLI (DiffDialog): - Distinguish over-large dirty trees (filesCount > 0 but empty perFileStats) from a clean tree; the empty state now reports the capped file count and totals instead of claiming "Working tree is clean." - Render the `oversized` flag with an explicit "(oversized — diff omitted)" tag in the file list and a corresponding detail-view note. Sanitization (#4): - Move sanitizeFilenameForDisplay from diffCommand.ts into the shared textUtils module, apply it to every path rendered in DiffDialog (file rows, detail header, empty messages, DiffRenderer filename prop, generated unified-diff envelope), and keep raw paths for map lookups via a separate UnifiedFile.displayPath field. Ctrl+C routing (QwenLM#7): - Register isDiffDialogOpen / closeDiffDialog with useDialogClose so Ctrl+C dismisses the dialog through the centralized handleExit path, matching how the background-tasks dialog is wired. Drop the dialog's internal Ctrl+C handler to avoid double-fire that would close the dialog AND escalate to the exit prompt. Tests: 2 new core regression tests (unreadable backup, oversized cap) plus the existing 35 still pass. CLI tests for diff/slashCommand/ AppContainer paths unchanged at 148/148. * fix(diff): second review round — candidate scope, binary, concurrency, semantics Addresses 14 of 19 outstanding review comments. Per-thread detail will be replied on the PR. Correctness (P0): - Restrict getTurnDiff candidates to keys(target.trackedFileBackups). Files first tracked in turn N+1 no longer get phantom-attributed to turn N. Drop the now-redundant union with state.trackedFiles for the latest-turn case (makeSnapshot guarantees state.trackedFiles ⊆ keys(latest.trackedFileBackups)). - Add `beforeBackup !== undefined` guard to the fast-path skip so a future broadening of the candidate set can't silently collapse a newly created file as "unchanged". - Add binary detection via NUL-byte sniff (`looksBinary`, mirrors git's heuristic). New `TurnFileDiff.isBinary` flag short-circuits hunk generation; the dialog renders the existing italic "binary" marker instead of feeding raw bytes to DiffRenderer. - Cap per-turn concurrent file reads at MAX_TURN_DIFF_FILES=500 so a 500-file turn won't issue 1000+ simultaneous open()s and hit the process fd ceiling. UX / stability: - Stabilize the dialog's keypress handler with `useCallback(()=>..,[])` reading state via refs, eliminating subscribe/unsubscribe churn on every render. - Disentangle `isNewFile` (snapshot-derived, "added in this turn") from `isUntracked` (git "never tracked") in perFileToUnified so untracked files no longer get mislabeled as "(new)" — they could not be recovered by /rewind, and the wrong tag implied otherwise. - Reorder FileRow tag priority around the disentangled flags; remove duplicate "(binary)" tag (the stats column already shows it italic). - Drop the early-exit `useEffect` clamps for sourceIndex / fileIndex in favor of inline `Math.min` derivations; effect-based clamping caused an extra render frame that could look like a flicker in Ink. - Inner `cancelled` checks in useTurnDiffs reduce wasted disk I/O when the dialog is closed mid-load. - Guard hunksToUnifiedDiff against empty hunk arrays (would otherwise hand DiffRenderer a header-only string). - Surface "…and N more (showing first M)" indicator for the Current source when fetchGitDiff capped perFileStats at MAX_FILES. - useDiffData JSDoc clarifies the snapshot-at-open semantics; catch branches now console.debug the underlying error instead of swallowing silently. Tests: - 3 new core regression tests: deleted-during-turn detection, binary detection, and the cross-turn attribution boundary. fileHistoryService tests now at 40/40. Pending review comments (deferred): the lazy-load suggestions remain intentionally deferred per the earlier reply chain; the MAX_DIFF_SIZE cap landed in the prior round mitigated the underlying memory risk. * fix(diff): third review round — per-file isolation, ENOENT semantics, binary tail scan Six review-driven correctness fixes; details inline on the PR. Core: - `readEndpointContent` now distinguishes ENOENT (genuine deletion) from other read failures (EACCES/EISDIR/EBUSY/decoding) on the live worktree branch. Previously every failure collapsed to `exists:false` and produced a phantom delete hunk for files whose perms changed mid-session. - `computeTurnFileDiff` is wrapped in per-file try/catch so a single `structuredPatch` crash or transient read error can no longer poison the whole turn's `Promise.all` and silently erase every row. - `looksBinary` now scans both the head AND the tail of the string. The head-only scan could be defeated by an 8KB+ text prefix in front of a binary payload; the oversized cap (1 MB) bounds the work either way. - `getTurnDiff` calls the existing `findSnapshotIndex` helper instead of inlining a duplicate reverse-scan loop, so a future change to `findSnapshot`'s tie-break rules can't silently desync /rewind and /diff. UI: - Add `hasHunks` to `UnifiedFile` and gate Enter on it. Untracked files don't appear in `git diff HEAD` output, and capped/oversized turn entries have empty hunks — pressing Enter on those previously landed the user on a dead-end "No hunks available" screen. - Drop the misleading `total > MAX_LINES_PER_FILE` heuristic from `perFileToUnified`'s `truncated` flag. `s.truncated` (from `parseGitNumstat`) is the only authoritative source — the OR was conflating "untracked file too big to count" with "tracked file with many accurately-counted lines", incorrectly flagging the latter. Tests: - 1 new core regression test: live-worktree EISDIR failure must not be reported as a deletion. fileHistoryService tests now at 41/41. * fix(diff): fourth review round — diagnostics, paths, UX feedback - Deterministic candidate cap in getTurnDiff: sort trackedFileBackups keys before slicing at MAX_TURN_DIFF_FILES; emit debugLogger.warn when truncating so the dropped count is traceable. - Log unreadable before/after endpoints in computeTurnFileDiffUnsafe instead of dropping rows silently — backup corruption, permission flips and EISDIR now leave a trace. - Return trackingPath as TurnFileDiff.filePath (already repo-relative via maybeShortenFilePath) so per-turn rows match the Current source on narrow terminals. The internal absolute path is kept only for live-worktree I/O. - useDiffData: replace bare console.debug with createDebugLogger ('DiffDialog') to match project convention. - DiffDialog: show a transient warning-coloured hint in the footer when Enter lands on a binary / oversized / no-hunks row (cleared on the next navigation key) so the keypress isn't silently consumed. - useDialogClose: swap diff-dialog and background-tasks branches to match DialogManager render order — Ctrl+C now dismisses whichever dialog the user actually sees when both flags are open. - useTurnDiffs: sanitize previewOfUserItem via escapeAnsiCtrlCodes so prompt previews on the source tabs can't reach the terminal raw (matching the chat-history defense). - Tests: expect repo-relative filePath in getTurnDiff regression cases; add `warn` to the mocked debugLogger. Refs PR QwenLM#4277 review comments 3259062434, 3259062465, 3264541365, 3259062480, 3259062498, 3264541346, 3264541351. * fix(diff): fifth review round — OOM guard, concurrency cap, type safety - readEndpointContent now stats both worktree and backup paths before readFile and returns a `{ kind: 'oversized' }` sentinel when the file exceeds MAX_DIFF_SIZE_BYTES. computeTurnFileDiffUnsafe handles the sentinel without allocating, so a 2 GB write_file blob no longer lands in the Node heap just to be rejected downstream. - useTurnDiffs now batches `getTurnDiff` calls at TURN_CONCURRENCY = 4 instead of an unbounded Promise.all across every user turn. Prevents EMFILE on long sessions (worst case ~4000 fds vs. unbounded N × 1000). - Add `filesOmitted` to `TurnDiff.stats` and plumb it through the dialog's `hiddenFileCount` so per-turn rows now also surface "…and N more" when MAX_TURN_DIFF_FILES truncates the candidate list (matches the Current source's existing behavior). - Make isRealUserTurn a type predicate (`item is HistoryItem & HistoryItemUser`) so callers in useTurnDiffs drop both `as` casts — a future regression that loosens either side will now be caught by tsc rather than silently bypassing the narrowing. - Add trailing `.catch()` to the Promise.all chains in useDiffData and useTurnDiffs so a thrown setState during unmount doesn't propagate to Node 22+'s default unhandled-rejection terminator. Both branches log via createDebugLogger and unstick `loading`. - Tighten the comment above the diff/background-tasks branch in useDialogClose: the invariant is scoped to that pair, not a full mirror of DialogManager's render priority. - Add focused unit tests for sanitizeFilenameForDisplay (C0 controls, DEL + C1, multi-byte ANSI CSI, mixed crafted paths, clean passthrough) — security-relevant function previously untested. Refs PR QwenLM#4277 review comments 3265032536, 3265032548, 3265032551, 3265032556, 3265032560, 3265032569, 3265032574. * fix(diff): sixth review round — discriminated union, TOCTOU, tests - Refactor EndpointRead into a proper discriminated union with explicit `kind: 'ok' | 'unreadable' | 'oversized'`. Removes the six manual `as EndpointReadOk / as EndpointReadOversized` casts in computeTurnFileDiffUnsafe; branch narrowing is now driven by tsc. - Close the stat()-then-readFile() TOCTOU window. Replace the separate syscalls with `open()` + `fh.stat()` + `fh.readFile()` against a single file descriptor, so a concurrent write_file appending to the same path between calls can't grow past MAX_DIFF_SIZE_BYTES and slip the OOM guard. Shared helper readPathWithSizeGuard handles both worktree and backup endpoints (worktree ENOENT → absence, backup ENOENT → unreadable to match prior semantics). - Document filesOmitted as an upper bound on candidates dropped at the cap (some may have been unchanged; we can't know without paying the read the cap was specifically meant to avoid). Surface that in the dialog's truncation indicator: turn sources now read "…and up to N more (showing first M)" while Current keeps the exact wording. - Tests: 3 new fileHistoryService cases covering the live-worktree oversized branch (single-snapshot path), mixed-size endpoints (small before + oversized after) exercising the discriminated-union narrowing, and a baseline filesOmitted === 0 regression. 7 new renderHook tests for useTurnDiffs covering disabled / missing-service short-circuits, filtering of slash/no-promptId/empty-diff turns, most-recent-first ordering, per-turn error isolation, batch progression beyond TURN_CONCURRENCY, and the in-flight concurrency cap itself. Refs PR QwenLM#4277 review comments 3267108813, 3267108827, 3267108831, 3267108839, 3267108847.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
descriptionof the currently highlighted setting below the settings list in the/settingsdialogTest plan
/settingsand verify a description line appears below the settings list for the highlighted item🤖 Generated with Claude Code