Claude Code v2.1.97:Focus View 聚焦瀏覽與 Status Line 即時刷新

之前寫過 OSC 52 剪貼簿亂碼的修復,裡面提到設定 CLAUDE_CODE_NO_FLICKER=1 可以解決問題。那時候我只把它當作一個環境變數 workaround,沒有深入研究 NO_FLICKER 模式本身能做什麼。

上週更新到 v2.1.97 之後,changelog 裡出現了兩行讓我去 docs 認真翻了一遍的新東西:

• Added focus view toggle (Ctrl+O) in NO_FLICKER mode showing prompt,
  one-line tool summary with edit diffstats, and final response
• Added refreshInterval status line setting to re-run the status line
  command every N seconds

這兩個功能搭在一起,基本上把 NO_FLICKER 模式從「解決閃爍的替代方案」升級成「值得主動開啟的工作環境」。


NO_FLICKER 模式快速回顧

先簡單說一下前提。NO_FLICKER 模式(也叫全螢幕渲染模式)需要 v2.1.89 以上,啟用方式就是設環境變數:

# 加到 .zshrc 或 .bashrc 讓它永遠生效
export CLAUDE_CODE_NO_FLICKER=1

它使用虛擬 viewport 渲染,只更新實際發生變化的字元和行,而不是重繪整個畫面,所以在長 Session 裡記憶體使用比較穩定。

唯一不習慣的可能是我經常在閱讀終端機內容時會用滑鼠一直亂選取文字,在 NO_FLICKER 下會變成複製,就會複製一堆文字洗掉我剪貼簿的內容,不過這點倒是可以到 /config 中關閉功能

❯ Copy on select  改 false 關閉選取及複製

Focus View:Ctrl+O 的三段循環

v2.1.97 之前,NO_FLICKER 模式的 Ctrl+O 只有兩個狀態:正常提示畫面,以及一個 less 風格的 Transcript 模式(可以用 / 搜尋、用 [ 把整段對話傾倒回終端機 scrollback buffer)。

現在 Ctrl+O 變成三段循環:

按下次數狀態顯示內容
第 0 次正常模式完整的即時串流輸出
第 1 次Transcript 模式less 風格導覽,支援搜尋
第 2 次Focus View只顯示最後一輪問答精華
第 3 次回到正常模式

Focus View 的顯示內容被刻意壓縮成三部分:

  1. 你的最後一則提示
  2. 一行工具呼叫摘要(含編輯統計,例如「修改了 3 個檔案,新增 47 行,刪除 12 行」)
  3. Claude 的最終回應

對 Session 跑了一兩個小時、對話捲軸很長的情況特別有用——你不需要知道過程中 Claude 嘗試了什麼、改了哪裡又改回來,只需要確認「我問了什麼、做了什麼」。

TIP — Claude 也知道你在看 Focus View

開啟 Focus View 之後,Claude 會感知到當前的渲染模式,因此它的最終回應會傾向寫得更獨立、更完整——因為它知道你只會看到最後那一段,不會看到前面的推理過程。

Transcript 模式的隱藏功能

順帶記錄一下 Transcript 模式(Ctrl+O 第一段)裡的 [ 快捷鍵:按下它會把完整對話記錄以展開格式傾倒回終端機的 native scrollback buffer。如果你用的是 tmux 或有無限 scrollback 的終端機,這個方式可以讓你之後用一般方式往上捲瀏覽整段歷史,不用停在 less 介面裡。


Status Line refreshInterval:讓狀態列活起來

Status Line 是 Claude Code 底部那一行可以自訂的狀態顯示,透過 .claude/settings.json 設定一個 shell 命令,它讀取 JSON session 資料後輸出要顯示的文字。

在 v2.1.97 之前,這個命令只在「事件觸發時」執行,也就是每次 Claude 說完話、呼叫工具時才更新。如果 Claude 正在長時間思考,狀態列就靜止在那邊。

現在多了一個 refreshInterval 欄位:

{
  "statusLine": {
    "type": "command",
    "command": "bash \"$HOME/.claude/statusline.sh\"",
    "refreshInterval": 10
  }
}

refreshInterval 的單位是秒(最小值是 1),它讓你的狀態列命令每隔 N 秒就重新執行一次,不管 Claude 有沒有在動。

我的 Status Line 設定

我自己用的是一個 RPG 風格的狀態列:把當前目錄、git branch、Context Window、5 小時與 7 天用量限制都壓在一行,每個區塊用「愛心血條」呈現剩餘量,並依百分比切換綠/黃/紅交通燈配色。

#!/usr/bin/env bash
# Claude Code RPG-style Status Line

input=$(cat)

# Ensure jq is on PATH (winget install location fallback)
command -v jq &>/dev/null || export PATH="$HOME/bin:$PATH"

# ── Working dir + Git branch ─────────────────────────────────────────────────
cwd=$(echo "$input" | jq -r '.cwd // .workspace.current_dir // .workspace.project_dir // empty')
[ -z "$cwd" ] && cwd="$PWD"
cwd_base=$(basename "$cwd")

git_branch=""
if command -v git &>/dev/null; then
  git_branch=$(git -C "$cwd" -c gc.auto=0 symbolic-ref --short HEAD 2>/dev/null || \
               git -C "$cwd" -c gc.auto=0 rev-parse --short HEAD 2>/dev/null || true)
fi

# ── Context Window 與 Rate Limits ────────────────────────────────────────────
ctx_used=$(echo "$input"      | jq -r '.context_window.used_percentage      // empty')
ctx_remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')
five_pct=$(echo "$input"   | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at       // empty')
week_pct=$(echo "$input"   | jq -r '.rate_limits.seven_day.used_percentage // empty')
week_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at       // empty')

# ── 交通燈配色(依 used % 切換綠/黃/紅) ───────────────────────────────────
traffic_color() {
  local pct="${1:-0}"; pct=${pct%.*}
  if   (( pct >= 80 )); then printf '\033[0;31m'
  elif (( pct >= 50 )); then printf '\033[0;33m'
  else printf '\033[0;32m'
  fi
}

# ── 愛心血條(5 顆心,剩餘量越少心越少) ──────────────────────────────────────
heart_bar() {
  local pct="${1:-0}"; pct=${pct%.*}
  local total=5
  local full=$(( (100 - pct + 10) / 20 ))
  (( full > total )) && full=$total
  (( full < 0 )) && full=0
  local empty=$(( total - full ))
  local col; col=$(traffic_color "$pct")
  local bar="" empty_bar="" i
  for (( i=0; i<full;  i++ )); do bar+="♥"; done
  for (( i=0; i<empty; i++ )); do empty_bar+="♥"; done
  printf '%s%s\033[2;37m%s\033[0m' "$col" "$bar" "$empty_bar"
}

fmt_reset() {
  local epoch="$1"
  [ -z "$epoch" ] && { printf '??:??'; return; }
  date -d "@${epoch}" "+%H:%M" 2>/dev/null || date -r "${epoch}" "+%H:%M" 2>/dev/null || printf '??:??'
}

# ── 組裝(cwd · branch │ CTX ♥♥♥♥♥ │ 5h ♥♥♥♥♥ ↺ 14:30 │ 7d ♥♥♥♥♥ ↺ ...) ─────
# (省略組裝細節,完整版見我的 dotfiles)

成品看起來大致像這樣:

xxx  master │ CTX ♥♥♥♥♥ 82% left │ 5h ♥♥♥♥♡ 24% used ↺ 18:00 │ 7d ♥♥♥♥♡ 31% used ↺ 04/19

搭配 "refreshInterval": 10 之後,就算 Claude 沉默著跑一個長任務,血條和到期時間也會持續刷新,讓我隨時知道 Context、5 小時與 7 天額度大概還剩多少。

NOTE — refreshInterval 的適用場景

官方文件建議在以下情況使用 refreshInterval:

  • 狀態列顯示時間(clock)或其他時間相關資料
  • 使用 Sub-agents 時,背景子代理改變了 git 狀態或其他外部狀態,主 session 需要感知

如果你的狀態列純粹顯示 session 內的資料(model 名稱、token 數),其實不需要設定 refreshInterval,只在事件觸發時更新就夠了。


兩個功能搭在一起的使用方式

我目前的習慣是這樣:

  1. 平時CLAUDE_CODE_NO_FLICKER=1,正常模式,Status Line 顯示 context 用量
  2. 跑長任務時(例如讓 Claude 寫一整個功能):切到 Focus View(Ctrl+O x2),這樣 Claude 跑完之後只看到任務總結,不會被中間過程淹沒
  3. 需要回查過程:切到 Transcript 模式(Ctrl+O x1),用 / 搜尋特定關鍵字

refreshInterval 在背景靜靜更新 context 百分比,讓我知道這個任務大概吃掉多少預算。


個人觀點

Focus View 解決的問題很實際:Claude Code 的 Session 跑長了之後,中間的工具呼叫輸出量非常驚人,往上捲找「我剛才說了什麼、Claude 最後回了什麼」相當費力。現在一鍵切換就能看到精華。

refreshInterval 的意義則更偏「完整性」——以前 Status Line 是靜態的,有一種設了但沒設的感覺;現在它真的會動了,作為狀態監控的角色更到位。

這兩個功能都不是什麼革命性的東西,但它們讓 NO_FLICKER 模式從「修 bug 的設定」變成「我主動想開啟的工作環境」,這算是一個不小的心態轉變。


資料來源

留言