mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-27 17:05:29 +00:00
fix(worktree): address PR #4174 round 5 findings
Finding #3256241831 (Nit, but awareness UX): the built-in `⎇` indicator used to disappear whenever `statusLineLines.length > 0`, on the assumption that the user's custom statusline rendered worktree itself. That assumption is unsafe — scripts written before Phase C don't know about `payload.worktree`, scripts can deliberately ignore the field, and partial scripts may render some fields but not worktree. In any of those cases the user sees no worktree UI while having an active worktree, risking destructive operations in the wrong cwd. New behavior: indicator shows by default regardless of statusline. Added an opt-out setting `ui.hideBuiltinWorktreeIndicator` (default false) for users whose custom statusline already renders worktree and want to avoid duplication. Finding #3256239608 (Nit): `fs.watch` in useWorktreeSession holds an inode handle to `chatsDir` at mount time. If the directory is deleted out-of-band (manual cleanup, antivirus quarantine, reset scripts) and recreated, the watcher does NOT re-attach to the new inode and the Footer indicator stops reacting to sidecar changes. Reviewer explicitly accepted this as a documented limitation rather than adding polling-fallback or error-event-handler complexity for an edge case that doesn't arise in normal use. Added a JSDoc block on the hook explaining the limitation and pointing to the future fix shapes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d4e921ae29
commit
80f9cb4958
3 changed files with 34 additions and 5 deletions
|
|
@ -652,6 +652,16 @@ const SETTINGS_SCHEMA = {
|
|||
description: 'Custom theme definitions.',
|
||||
showInDialog: false,
|
||||
},
|
||||
hideBuiltinWorktreeIndicator: {
|
||||
type: 'boolean',
|
||||
label: 'Hide Built-in Worktree Indicator',
|
||||
category: 'UI',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
description:
|
||||
'When true, the built-in `⎇ worktree-<branch> (<slug>)` line in the Footer is hidden. The worktree state is still surfaced to custom statusline scripts via the stdin payload (`worktree.{name, path, branch, original_cwd, original_branch}`). Keep at the default `false` unless your custom statusline renders the worktree itself — otherwise an active worktree silently has no UI affordance.',
|
||||
showInDialog: false,
|
||||
},
|
||||
hideWindowTitle: {
|
||||
type: 'boolean',
|
||||
label: 'Hide Window Title',
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { useStatusLine } from '../hooks/useStatusLine.js';
|
|||
import { useConfigInitMessage } from '../hooks/useConfigInitMessage.js';
|
||||
import { useUIState } from '../contexts/UIStateContext.js';
|
||||
import { useConfig } from '../contexts/ConfigContext.js';
|
||||
import { useSettings } from '../contexts/SettingsContext.js';
|
||||
import { useVimMode } from '../contexts/VimModeContext.js';
|
||||
import { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
import { GeminiSpinner } from './GeminiRespondingSpinner.js';
|
||||
|
|
@ -28,6 +29,7 @@ import { t } from '../../i18n/index.js';
|
|||
export const Footer: React.FC = () => {
|
||||
const uiState = useUIState();
|
||||
const config = useConfig();
|
||||
const settings = useSettings();
|
||||
const { vimEnabled, vimMode } = useVimMode();
|
||||
const { lines: statusLineLines, useThemeColors } = useStatusLine();
|
||||
const configInitMessage = useConfigInitMessage(uiState.isConfigInitialized);
|
||||
|
|
@ -158,12 +160,19 @@ export const Footer: React.FC = () => {
|
|||
{line}
|
||||
</Text>
|
||||
))}
|
||||
{/* Built-in worktree indicator. Hidden when the user has a custom
|
||||
statusline (their script already gets `worktree` in stdin payload
|
||||
and likely renders it itself). Also hidden during ctrl-quit
|
||||
warnings so they take precedence. */}
|
||||
{/* Built-in worktree indicator. Shown by default whenever a
|
||||
worktree is active so the user always has a UI affordance,
|
||||
even when a custom statusline is configured — their script
|
||||
may not render `payload.worktree` (written before Phase C,
|
||||
ignored by choice, or only rendering some fields), and
|
||||
silently hiding the indicator could let the user operate
|
||||
in the wrong cwd. Users who want the suppression behaviour
|
||||
(e.g. their statusline already renders worktree) can opt
|
||||
in via the `ui.hideBuiltinWorktreeIndicator` setting.
|
||||
Hidden during ctrl-quit warnings so they take precedence.
|
||||
(PR #4174 review #3256241831.) */}
|
||||
{uiState.activeWorktree &&
|
||||
statusLineLines.length === 0 &&
|
||||
!settings.merged.ui?.hideBuiltinWorktreeIndicator &&
|
||||
!uiState.ctrlCPressedOnce &&
|
||||
!uiState.ctrlDPressedOnce && (
|
||||
<Text dimColor wrap="truncate">
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@ import { readWorktreeSession } from '@qwen-code/qwen-code-core';
|
|||
* directory rather than the file directly because the file may not exist
|
||||
* yet when `enter_worktree` hasn't run. Directory watchers also catch
|
||||
* rename/delete events that file watchers miss.
|
||||
*
|
||||
* Known limitation: `fs.watch` holds an inode handle to `chatsDir` at
|
||||
* mount time. If the directory is deleted out-of-band (manual cleanup,
|
||||
* antivirus quarantine, reset scripts) and then recreated, the watcher
|
||||
* does NOT re-attach to the new inode — the Footer indicator stops
|
||||
* responding to sidecar changes until the session restarts. In normal
|
||||
* use `chatsDir` is stable for the session's lifetime; if rotation
|
||||
* becomes a real failure mode, add a polling fallback or listen for
|
||||
* `watcher.on('error')` and re-run `setupWatcher`. (PR #4174 review
|
||||
* #3256239608.)
|
||||
*/
|
||||
export function useWorktreeSession(config: Config): WorktreeSession | null {
|
||||
const [session, setSession] = useState<WorktreeSession | null>(null);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue