Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"metadata": {
"description": "TapTap Claude Code 插件库 - 提供开发工作流自动化插件",
"version": "0.1.23",
"version": "0.1.24",
"pluginRoot": "./plugins"
},
"plugins": [
Expand Down Expand Up @@ -38,7 +38,7 @@
"name": "sync",
"source": "./plugins/sync",
"description": "项目配置同步插件,提供 MCP、LSP 和开发环境配置同步功能",
"version": "0.1.19",
"version": "0.1.20",
"author": {
"name": "TapTap AI Team"
},
Expand Down
109 changes: 109 additions & 0 deletions .claude/skills/clean-codex-statusline/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: clean-codex-statusline
description: 清理本地 Codex statusline 配置(codex-status 脚本、zsh hooks、tmux status-left、iTerm2 Status Bar、缓存)
---

## 执行流程

按顺序执行以下清理步骤,每步都检查是否存在再删除。

### 步骤 1:删除 codex-status 脚本

```bash
rm -f ~/.local/bin/codex-status && echo "✅ codex-status 已删除" || echo "⏭️ 不存在"
```

### 步骤 2:清理 zsh hooks

检查 `~/.zshrc.local` 中是否有 codex-statusline 标记块,有则删除:

```bash
if grep -q "codex-statusline BEGIN" ~/.zshrc.local 2>/dev/null; then
sed '/# >>> codex-statusline BEGIN >>>/,/# <<< codex-statusline END <<</d' ~/.zshrc.local > ~/.zshrc.local.tmp && mv ~/.zshrc.local.tmp ~/.zshrc.local
echo "✅ zsh hooks 已清理"
else
echo "⏭️ 无 zsh hooks"
fi
```

### 步骤 3:重置 tmux status-left

如果当前在 tmux 中,重置 status bar 为默认值:

```bash
if [ -n "${TMUX:-}" ]; then
tmux set -g status-left "[#S]" 2>/dev/null
tmux set -gu window-status-format 2>/dev/null
tmux set -gu window-status-current-format 2>/dev/null
tmux set -gu status-right 2>/dev/null
echo "✅ tmux status bar 已重置"
else
echo "⏭️ 不在 tmux 中,跳过"
fi
```

### 步骤 4:清理 iTerm2 Status Bar

仅 macOS 执行。**必须通过 osascript 操作运行中的 iTerm2**(直接改 plist 会被 iTerm2 退出时覆盖):

```bash
python3 -c "
import subprocess, plistlib, sys

# 通过 defaults export/import 操作(走 cfprefsd,不会被 iTerm2 退出时覆盖)
result = subprocess.run(['defaults', 'export', 'com.googlecode.iterm2', '-'], capture_output=True)
if result.returncode != 0:
print('⏭️ iTerm2 配置不存在')
sys.exit(0)

data = plistlib.loads(result.stdout)
bookmarks = data.get('New Bookmarks', [])
changed = False
for b in bookmarks:
layout = b.get('Status Bar Layout', {})
comps = layout.get('components', [])
new_comps = [c for c in comps if 'codex_status' not in str(c.get('configuration', {}).get('knobs', {}).get('expression', ''))]
if len(new_comps) != len(comps):
layout['components'] = new_comps
changed = True
if not new_comps and b.get('Show Status Bar'):
b['Show Status Bar'] = False
changed = True

if changed:
xml = plistlib.dumps(data)
result = subprocess.run(['defaults', 'import', 'com.googlecode.iterm2', '-'], input=xml, capture_output=True)
if result.returncode == 0:
print('✅ iTerm2 codex_status 组件已清除(Cmd+Q 重启 iTerm2 生效)')
else:
print('❌ iTerm2 配置写入失败')
sys.exit(1)
else:
print('⏭️ iTerm2 无 codex_status 组件')
"
```

### 步骤 5:清理缓存

```bash
rm -rf ~/.cache/codex-status && echo "✅ 缓存已清理" || echo "⏭️ 不存在"
```

### 步骤 6:输出结果

汇总报告并提示。**必须包含以下完整提示,不可省略:**

```
✅ Codex statusline 已完全清理

清理项目:
- ~/.local/bin/codex-status
- ~/.zshrc.local codex-statusline 块
- tmux status bar
- iTerm2 Status Bar codex_status 组件
- ~/.cache/codex-status/

提示:
- 新开终端窗口使 zsh 变更生效
- 如需重新安装:/sync:codex-statusline
```
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 0.1.24 — Codex statusline fixes

### Sync Plugin (0.1.20)

- Fixed context usage showing 100% by using `last_token_usage.input_tokens` instead of cumulative `total_token_usage.total_tokens`
- Fixed cross-instance context usage contamination by matching sessions via filename creation timestamp
- Fixed tmux normal mode statusline not showing due to `_is_iterm2` incorrectly returning true (inherited `TERM_PROGRAM`)
- Added `_is_tmux_cc()` to properly distinguish tmux -CC from normal tmux mode
- Fixed tmux -CC mode "Unrecognized command from tmux" error by wrapping SetUserVar with tmux passthrough
- Added `_iterm2_escape()` helper for automatic tmux passthrough wrapping
- Auto-configure `allow-passthrough on` in tmux.conf (prefers `.tmux.conf.local` for framework compatibility)
- Switched iTerm2 plist operations from direct file I/O to `defaults export/import` (cfprefsd) to prevent running iTerm2 from overwriting changes
- Added `cleanup_iterm2()` function for proper Status Bar removal
- Fixed zsh hooks update detection using shasum hash comparison instead of string equality
- Added `/clean-codex-statusline` skill for complete statusline cleanup

### Marketplace

- Bumped version from 0.1.23 to 0.1.24
- Updated sync plugin to version 0.1.20

## 0.1.23 — Codex compatibility

### Sync Plugin (0.1.19)
Expand Down
2 changes: 1 addition & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ One-click configuration for MCP, auto-update, and Cursor synchronization:
| ------- | ------- | ---------------------------------------------------------------------------------------------------- |
| spec | 0.1.4 | Spec-Driven Development workflow plugin |
| git | 0.1.12 | Git workflow automation plugin (commit/push/MR + dual-mode code review + remote platform ops) |
| sync | 0.1.19 | Dev environment config sync plugin (MCP + LSP + Hooks + Cursor + Claude Skills) |
| sync | 0.1.20 | Dev environment config sync plugin (MCP + LSP + Hooks + Cursor + Claude Skills) |
| quality | 0.0.4 | AI-powered code quality plugin (9 parallel Agents: Bug detection, code quality, security, performance) |


Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ mkdir -p .claude && echo '{
| ------- | ----- | ----------------------------------------------------------------- |
| spec | 0.1.4 | Spec-Driven Development 工作流插件 |
| git | 0.1.12 | Git 工作流自动化插件(提交/推送/MR + 自动代码审查 + 远程平台操作) |
| sync | 0.1.19 | 开发环境配置同步插件(MCP + LSP + Hooks + Cursor + Claude Skills) |
| sync | 0.1.20 | 开发环境配置同步插件(MCP + LSP + Hooks + Cursor + Claude Skills) |
| quality | 0.0.4 | AI 驱动的代码质量检查插件(9 个并行 Agent,支持 Bug 检测、代码质量、安全检查、性能分析) |


Expand Down
2 changes: 1 addition & 1 deletion plugins/sync/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sync",
"description": "项目配置同步插件,提供 MCP、LSP 和开发环境配置同步功能",
"version": "0.1.19",
"version": "0.1.20",
"author": {
"name": "TapTap AI Team"
}
Expand Down
1 change: 1 addition & 0 deletions plugins/sync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ chmod +x .githooks/pre-commit

## 版本历史

- **v0.1.20** - 修复 context usage 显示 100% 问题(改用 last_token_usage);修复多实例 context 串扰;修复 tmux 普通模式无 statusline(_is_tmux_cc 区分 -CC 模式);修复 tmux -CC 报错(passthrough 包裹);iTerm2 配置改用 defaults export/import(防止被覆盖);zsh hooks 更新检测改用 hash 比较;新增 /clean-codex-statusline skill
- **v0.1.19** - 新增 codex-statusline(tmux + iTerm2);飞书 MCP 的 Codex 配置改为可选(--with-codex);hooks 迁移至 $HOME 级(Codex 兼容);移除 sequential-thinking MCP;新增 plugin-status skill
- **v0.1.17** - skills-sync 新增 review-rules 模板同步(不覆盖项目已有规则)
- **v0.1.16** - review-checklist 不覆盖项目自定义版本;修正覆盖策略文档;修复 4 个 hook 脚本缺少可执行权限;Cursor 模板新增 Pipeline Watch
Expand Down
85 changes: 68 additions & 17 deletions plugins/sync/scripts/codex-status
Original file line number Diff line number Diff line change
Expand Up @@ -351,20 +351,44 @@ def style(text: str, fg: str, bg: Optional[str] = None, bold: bool = False) -> s
return f"#[{','.join(attrs)}] {text} "


def setup_iterm2() -> int:
"""Auto-configure iTerm2 Status Bar with codex_status component for all profiles."""
def _iterm2_prefs_read() -> Optional[dict]:
"""Read iTerm2 preferences via 'defaults export' (works with running iTerm2)."""
import plistlib
result = subprocess.run(
["defaults", "export", "com.googlecode.iterm2", "-"],
capture_output=True,
)
if result.returncode != 0:
return None
try:
return plistlib.loads(result.stdout)
except Exception:
return None

plist_path = pathlib.Path.home() / "Library" / "Preferences" / "com.googlecode.iterm2.plist"
if not plist_path.exists():
return 1

def _iterm2_prefs_write(data: dict) -> bool:
"""Write iTerm2 preferences via 'defaults import' (works with running iTerm2)."""
import plistlib
try:
with open(plist_path, "rb") as f:
plist = plistlib.load(f)
xml = plistlib.dumps(data)
except Exception:
return False
result = subprocess.run(
["defaults", "import", "com.googlecode.iterm2", "-"],
input=xml,
capture_output=True,
)
return result.returncode == 0


def setup_iterm2() -> int:
"""Auto-configure iTerm2 Status Bar with codex_status component for all profiles."""
data = _iterm2_prefs_read()
if data is None:
return 1

bookmarks = data.get("New Bookmarks", [])

component = {
"class": "iTermStatusBarSwiftyStringComponent",
"configuration": {
Expand Down Expand Up @@ -410,12 +434,9 @@ def setup_iterm2() -> int:
}

changed = False
# Status Bar 位置设为底部(全局设置,0=top, 1=bottom)
if plist.get("StatusBarPosition") != 1:
plist["StatusBarPosition"] = 1
changed = True
data["StatusBarPosition"] = 1

for bookmark in plist.get("New Bookmarks", []):
for bookmark in bookmarks:
if not bookmark.get("Show Status Bar", False):
bookmark["Show Status Bar"] = True
changed = True
Expand All @@ -433,11 +454,41 @@ def setup_iterm2() -> int:
changed = True

if changed:
try:
with open(plist_path, "wb") as f:
plistlib.dump(plist, f)
print("[codex-status] iTerm2 Status Bar 已自动配置,重启 iTerm2 后生效")
except Exception:
if _iterm2_prefs_write(data):
print("[codex-status] iTerm2 Status Bar 已自动配置(Cmd+Q 重启 iTerm2 生效)")
else:
return 1
return 0


def cleanup_iterm2() -> int:
"""Remove codex_status component from iTerm2 Status Bar for all profiles."""
data = _iterm2_prefs_read()
if data is None:
return 0

bookmarks = data.get("New Bookmarks", [])
changed = False
for bookmark in bookmarks:
layout = bookmark.get("Status Bar Layout", {})
comps = layout.get("components", [])
new_comps = [
c for c in comps
if "codex_status" not in str(
c.get("configuration", {}).get("knobs", {}).get("expression", "")
)
]
if len(new_comps) != len(comps):
layout["components"] = new_comps
changed = True
if not new_comps and bookmark.get("Show Status Bar"):
bookmark["Show Status Bar"] = False
changed = True

if changed:
if _iterm2_prefs_write(data):
print("[codex-status] iTerm2 codex_status 已清除(Cmd+Q 重启 iTerm2 生效)")
else:
return 1
return 0

Expand Down
32 changes: 25 additions & 7 deletions plugins/sync/scripts/codex-statusline.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,39 @@ codex_status_active_file() {
print -r -- "$HOME/.cache/codex-status/${state_key}.active"
}

# 检测是否在 iTerm2 环境(包括 tmux -CC 模式
# 检测是否在 iTerm2 环境(包括 tmux 内继承的 iTerm2 环境
_is_iterm2() {
[[ "${TERM_PROGRAM:-}" == "iTerm.app" || -n "${ITERM_SESSION_ID:-}" ]] && return 0
# tmux -CC 模式:client_control_mode=1 表示 iTerm2 tmux 集成
[[ -n "${TMUX:-}" ]] && [[ "$(tmux display-message -p '#{client_control_mode}' 2>/dev/null)" == "1" ]] && return 0
[[ -n "${ITERM_PROFILE:-}" ]] && return 0
return 1
}

# 检测是否在 tmux -CC(iTerm2 控制模式)
_is_tmux_cc() {
[[ -n "${TMUX:-}" ]] || return 1
[[ "$(tmux display-message -p '#{client_control_mode}' 2>/dev/null)" == "1" ]] && return 0
return 1
}

# 发送 iTerm2 转义序列(tmux 内自动用 passthrough 包裹)
_iterm2_escape() {
local seq="$1"
local target="${2:-/dev/tty}"
if [[ -n "${TMUX:-}" ]]; then
# tmux passthrough: \ePtmux;\e<seq>\e\\
printf '\033Ptmux;\033%s\033\\' "$seq" > "$target" 2>/dev/null
else
printf '%s' "$seq" > "$target" 2>/dev/null
fi
}

# iTerm2: 通过 SetUserVar 写入 status bar 数据(底部)
codex_iterm2_set_user_var() {
_is_iterm2 || return 0
local val="${1:-}"
local encoded
encoded="$(printf '%s' "$val" | base64 | tr -d '\r\n')"
printf '\033]1337;SetUserVar=%s=%s\a' "codex_status" "$encoded" > /dev/tty 2>/dev/null
_iterm2_escape "$(printf '\033]1337;SetUserVar=%s=%s\a' "codex_status" "$encoded")"
}

# 后台轮询更新 iTerm2 status bar(codex 运行期间)
Expand All @@ -48,11 +66,11 @@ codex_iterm2_watch() {
st="$("$HOME/.local/bin/codex-status" --plain --state-key="$sk" "$wd" "codex" "" "$pid" 2>/dev/null)" || true
if [[ -n "$st" ]]; then
encoded="$(printf '%s' "$st" | base64 | tr -d '\r\n')"
printf '\033]1337;SetUserVar=%s=%s\a' "codex_status" "$encoded" > "$tty_dev" 2>/dev/null
_iterm2_escape "$(printf '\033]1337;SetUserVar=%s=%s\a' "codex_status" "$encoded")" "$tty_dev"
fi
sleep 5
done
printf '\033]1337;SetUserVar=%s=%s\a' "codex_status" "" > "$tty_dev" 2>/dev/null
_iterm2_escape "$(printf '\033]1337;SetUserVar=%s=%s\a' "codex_status" "")" "$tty_dev"
) &
) 2>/dev/null
}
Expand All @@ -70,7 +88,7 @@ codex_iterm2_auto_setup() {
codex_tmux_apply_status() {
[[ -n "$TMUX" ]] || return 0
# tmux -CC 模式下不设 status-left(用 iTerm2 Status Bar 代替)
_is_iterm2 && return 0
_is_tmux_cc && return 0
command -v tmux >/dev/null 2>&1 || return 0
tmux set -g status-left '#[fg=#1f2335,bg=#7aa2f7,bold] TMUX #[default] #(~/.local/bin/codex-status --state-key="#{pane_id}" "#{pane_current_path}" "#{pane_current_command}" "#{pane_title}" "#{pane_pid}")' >/dev/null 2>&1
tmux set -g window-status-format '' >/dev/null 2>&1
Expand Down
Loading
Loading