Skip to content

Conversation

@blackrion
Copy link

问题描述

在 Windows 中文环境下,WeztermBackend 和 Iterm2Backend 的 subprocess 调用会因为默认使用 GBK 编码而导致解码失败:

UnicodeDecodeError: 'gbk' codec can't decode byte

这会导致:

  • ccb status 无法正常检查终端状态
  • is_alive() 方法失败
  • 创建终端窗格时出错

解决方案

为所有 subprocess.run 调用添加 encoding='utf-8'errors='replace' 参数,确保在 Windows 环境下使用 UTF-8 编码。

影响的方法

  • WeztermBackend.is_alive() - lib/terminal.py:316
  • WeztermBackend.create_pane() - lib/terminal.py:371
  • Iterm2Backend.is_alive() - lib/terminal.py:210
  • Iterm2Backend.create_pane() - lib/terminal.py:237

测试环境

  • ✅ Windows 11 with Chinese locale
  • ✅ WezTerm backend
  • ✅ 修复后 ccb status 和 session 管理正常工作

相关提交

这个修复补充了之前的 Windows 兼容性改进工作,与以下提交相关:

  • c35c096 fix(cask-w,gask-w): move setup_windows_encoding to module level
  • 6d9da2f fix(install.ps1): add UTF-8 BOM and encoding setup for PS5.1 compatibility
  • f8cf9cc fix(windows): add Windows compatibility fixes

bfly123 and others added 30 commits December 19, 2025 11:43
feat(terminal): add iTerm2 support via it2 CLI
Fix: Bridge process crash and message forwarding stability (macOS/tmux)
- Fix Python version check in install.ps1 (single call)
- Add lib/compat.py for Windows UTF-8 console encoding
- Add _find_claude_cmd() for Windows Claude CLI discovery
- Add encoding='utf-8' to subprocess.run calls
- Add error handling to WezTerm create_pane
- Add tmp/ to .gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Runtime config:
- Add lib/ccb_config.py for BackendEnv (wsl/windows) configuration
- Support .ccb-config.json and CCB_BACKEND_ENV env var
- Auto-inject WSL session paths for Windows+WSL scenarios
- Update terminal.py to force WSL launch when BackendEnv=wsl

Install confirmation:
- Add WSL environment confirmation in install.sh
- Add Windows environment confirmation in install.ps1
- Support -Yes flag and CCB_INSTALL_ASSUME_YES=1 to skip

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 新增 lib/session_utils.py 权限检查工具
- ccb: _write_*_session() 添加预检查和清晰错误提示
- codex_comm.py/gemini_comm.py: 异常时输出警告而非静默吞掉

用户遇到权限问题时将看到具体原因和修复命令

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Windows 用户必须使用原生 exe 安装 WezTerm,即使使用 WSL 也是如此

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use command argument instead of stdin for text and enter
- Add fallback sequence: \r -> \n -> \r\n -> stdin
- Set default enter delay to 0.01s for TUI compatibility
- Also strip \n from text before sending
- Update AI collaboration rules in install.sh

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use run_in_background=true for non-blocking execution
- Add TaskOutput usage for retrieving results
- Update workflow documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CCB_CONFIG_START/END markers to isolate ccb config
- Install: update existing block or append new one
- Uninstall: only remove marked block, preserve user content
- Keep backward compatibility with legacy rules

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Check all candidate directories instead of just the first one
- Remove commands from ~/.claude, ~/.config/claude, ~/.local/share/claude

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert all Chinese strings to English across:
- lib/*.py (5 files): docstrings, comments, error messages
- ccb: CLI help text and status messages
- bin/* (8 files): script descriptions and error messages
- commands/*.md (8 files): skill definitions
- install.sh/install.ps1: prompts and messages
- CLAUDE.md: project instructions

Intentionally unchanged:
- README.md: stays bilingual
- install.sh legacy regex: matches old Chinese rules for cleanup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Calculate project hash directly (sha256 of cwd) instead of relying
on stored value. Check if session-*.json files exist in
~/.gemini/tmp/<hash>/chats/ before using --resume flag.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Windows PowerShell 5.x has poor UTF-8 emoji support, causing parse errors.
Replace ❌→[ERROR], ✓→[OK], ⚠️→[WARNING]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement i18n system supporting Chinese and English:
- Add lib/i18n.py with language detection and message dictionary
- Language detection priority: CCB_LANG env > system locale > default en
- Update ccb, bin/*, lib/codex_comm.py, lib/gemini_comm.py
- Add i18n functions to install.sh and install.ps1

Usage: Set CCB_LANG=zh for Chinese, CCB_LANG=en for English,
or leave unset for auto-detection based on system locale.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add flush=True to print statements in codex_comm.py and gemini_comm.py
  to ensure immediate output in non-interactive/background mode
- Add early "🚀 cask-w/gask-w started" message before initialization
  so Claude can detect process started and return immediately

This should improve stability when using run_in_background=true.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add /cask-w and /gask-w to the fast path triggers in CLAUDE.md config,
so Claude will immediately call bash without going through skill system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Optimizations:
- Move imports after startup signal for faster first output
- Add lazy_init parameter to CodexCommunicator and GeminiCommunicator
- Defer log reader creation and health check until actually needed
- Skip Windows encoding setup on Linux

Performance improvement:
- Startup to first output: 38-40ms -> 24-27ms (35-40% faster)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove timeout=0 parameter from ask_sync calls
- Use lazy imports for better startup performance
- Simplify error output format
- Use raise SystemExit instead of sys.exit

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change behavior to STOP immediately after sending to Codex/Gemini
instead of continuing with other work in background.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- cask-w/gask-w now return immediately after sending
- Background process waits for reply (up to 5 min)
- Reply cached in ~/.cache/ccb/ for cpend/gpend to read
- cpend/gpend check cache first before querying session

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Prevents parent process from blocking on child stdout/stderr.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Simplify cask-w/gask-w to pure synchronous wait (no fork)
- Use Claude Code's run_in_background=true for async execution
- Fix _latest_log() to detect stale log file bindings
- Update skill configs to use background task + TaskOutput pattern
- Add pending_state save on timeout/interrupt for later retrieval

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add _send_message() and _generate_marker() to GeminiCommunicator
- Add marker_prefix to GeminiCommunicator.__init__
- Add save_pending_state() for timeout/interrupt recovery
- Use _send_message() instead of direct _send_via_terminal()
- Add KeyboardInterrupt handling
- Call _remember_gemini_session() after send and wait

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add retry loop (10 attempts) in capture_state() for transient JSONDecodeError
- Return msg_count=-1 to indicate unknown baseline instead of 0
- In _read_since(), establish stable baseline first when msg_count<0
- Add id/hash deduplication to avoid returning already-processed messages

Root cause: Gemini CLI writes session JSON in-place, causing transient
parse failures that reset msg_count to 0, leading to old messages being
returned as "new" replies.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change file open from text mode to binary mode ("rb")
- Use offset=-1 to indicate unknown baseline
- Establish baseline from EOF when offset unknown
- Start from EOF when switching log files to avoid replaying old content

Root cause: text mode seek/tell uses "cookie" values that don't equal
byte offsets, causing offset > st_size clamping to misposition and
return stale messages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ility

- Add UTF-8 BOM to file header
- Set $OutputEncoding, [Console]::OutputEncoding/InputEncoding to UTF-8
- Run chcp 65001 for consistent Chinese/emoji output on Windows PowerShell 5.1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Key changes:
- cask-w/gask-w now run in background mode, not blocking foreground work
- Fix codex_comm: use binary mode for consistent byte offset handling
- Fix gemini_comm: prevent returning stale messages on JSON parse failure
- Fix gask-w: align implementation with cask-w
- Fix install.ps1: add UTF-8 BOM for PowerShell 5.1 compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…oding

- Use utf-8-sig encoding when reading session files (tolerate BOM)
- Use utf-8 encoding when writing session files
- Refactor _get_latest_codex_session_id() to use _read_json_file()
- Add --restore as alias for --resume
- Support ccb -r as shortcut for ccb up -r

Root cause: Windows PowerShell 5.1 default encoding caused JSON parse
failure, making -r ignore .codex-session in current directory.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
bfly123 and others added 22 commits December 21, 2025 14:34
- Add Fix-PythonShebang function to replace python3 with python
- Generate .cmd and .bat wrappers for all scripts
- Wrappers try python first, fallback to py -3
- Fix relative path references in wrappers

This fixes "python3: No such file or directory" error on Windows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures UTF-8 encoding is configured before any emoji output on Windows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add _normalize_path_for_match() to handle Windows/WSL/MSYS path variations
- Add fallback scan in _get_latest_codex_session_id() when codex_session_id missing
- Validate work_dir match in _read_local_claude_session_id() to prevent cross-dir restore
- Store work_dir_norm in session files for reliable matching

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ss-dir restore

- Add _extract_session_work_dir_norm() helper for consistent work_dir extraction
- Validate work_dir in _get_latest_codex_session_id() before using cached codex_session_id
- Reject resume in _read_local_claude_session_id() when work_dir is missing (old files)
- Add work_dir check in cmd_restore() for codex_session_id

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add expanduser for ~ prefixed paths in _normalize_path_for_match()
- Absolutize relative paths against cwd for matching purposes
- Try multiple path forms (absolute, resolve, PWD) for Gemini hash lookup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…eply leakage

- Use utf-8-sig encoding for session file reads (handle Windows BOM)
- Validate pending_state is dict before accessing
- Use safe_write_session for atomic writes
- Check log_path exists before reading to avoid global fallback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- codex_comm: start from beginning when switching to new log file
  to avoid missing replies already written before detection
- gemini_comm: detect and return valid replies on first successful
  read when capture_state failed due to transient JSON writes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Display old and new version info: vX.X commit date
- Show "Updated: old → new" or "Already up to date: current"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move version reading before git check
- Works for tarball installs without .git directory

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GIT_COMMIT and GIT_DATE variables to ccb
- install.sh updates these variables from git info
- Works for tarball installs without .git directory

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comments were being included in parsed values

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Method 1: From local git repo
- Method 2: From CCB_GIT_COMMIT/CCB_GIT_DATE env vars
- Method 3: From GitHub API (fallback for tarball)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously _read_since returned the first gemini message with content,
which could be an intermediate status message when Gemini sends multiple
messages (tool calls → intermediate status → final reply).

Now it collects all gemini messages and returns the last one with content.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- codex_comm.py: Remove session_id_filter from _scan_latest() to always
  read the latest session file by mtime, fixing issue where old session
  replies were returned instead of new ones
- install.sh: Update CLAUDE.md config to use run_in_background=true and
  auto-cat output on bash-notification for cask-w/gask-w

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove ambiguous "STOP and wait for user input" instruction.
Now clearly states: wait for bash-notification, then cat output file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add cmd_version() to display current version info (version, commit, date)
- Add _get_remote_version_info() to check GitHub API for latest version
- Move _get_version_info() and _format_version_info() to global scope
- Support ccb -v, ccb --version, and ccb version subcommand

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use temp file instead of $(cat << 'HEREDOC') pattern to avoid
parsing bug with single quotes (e.g., "don't") on macOS Bash 3.2.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add LICENSE file with both English and Chinese explanations
of AGPL-3.0 terms and requirements.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Initialize ccb_tmpfile with empty string
- Add error handling for mktemp failure
- Use ${ccb_tmpfile:-} in trap to avoid unbound variable error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Simplify Claude resume logic by using --continue flag instead of
managing session IDs with --resume <session_id>.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add history check to prevent "No conversation found to continue"
error when no previous session exists for current directory.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
修复 WeztermBackend 和 Iterm2Backend 在 Windows 环境下的编码问题:
- 为所有 subprocess.run 调用添加 encoding='utf-8' 和 errors='replace' 参数
- 解决 UnicodeDecodeError: 'gbk' codec can't decode byte 错误
- 确保 WezTerm 和 iTerm2 的状态检查在 Windows 中文环境下正常工作

受影响的方法:
- WeztermBackend.is_alive()
- Iterm2Backend.is_alive()
- Iterm2Backend.create_pane()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants