tmuxclihook 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmuxclihook",
3
- "version": "0.3.6",
3
+ "version": "0.4.0",
4
4
  "description": "交互式 TUI 安装器:环境侦测、AI CLI 侦测、tmux-ai-status hooks 装/卸/修、TPM 软链校验",
5
5
  "type": "module",
6
6
  "bin": {
@@ -112,6 +112,52 @@ _clear_pane_id() {
112
112
  [ -n "$SESSION_ID" ] && rm -f "$(_pane_dir)/pane-${SESSION_ID}"
113
113
  }
114
114
 
115
+ # --- cc-switch provider 标签 ---
116
+ # cc-switch(switch 命令)launch 时向 CLI 注入 CC_SWITCH_PROVIDER / CC_SWITCH_PROVIDER_ID,
117
+ # CLI 的 hooks 进程继承之;tmux-ai-status 入口把它们捕获进 pane option
118
+ # @ai_provider / @ai_provider_id。聚合侧在此读取并渲染彩色 provider 段。
119
+ # 颜色真源:~/.cc-switch/statusline-preferences.json(colors.claude / colors.codex
120
+ # 按 providerId 分桶)——与 cc-switch wrapper 状态栏标签同一真源,TUI `o` 改色
121
+ # 下一次 rebuild 即生效。显式值是 ANSI SGI 码(30-37/90-97),映射 tmux colourN
122
+ # (30-37 → 0-7,90-97 → 8-15);缺省 auto = FNV-1a(name)落在 cc-switch wrapper
123
+ # 同款 6 色 bright 调色板上。JS Math.imul 是 32 位截断乘;64 位精确积 & 0xFFFFFFFF
124
+ # 与之同余,纯 bash 可复刻(非 ASCII 名按字节遍历,与 JS 码点遍历 hash 可能不同,
125
+ # 只影响 auto 落点,非错误)。
126
+ _PROVIDER_PREFS_LINES=""
127
+ _PROVIDER_PREFS_LOADED=""
128
+ _provider_prefs_lines() {
129
+ if [ -z "$_PROVIDER_PREFS_LINES" ] && [ -z "$_PROVIDER_PREFS_LOADED" ]; then
130
+ _PROVIDER_PREFS_LOADED=1
131
+ local f="${HOME}/.cc-switch/statusline-preferences.json"
132
+ if [ -f "$f" ]; then
133
+ # claude/codex 两桶浅合并:providerId 是 uuid,跨桶不冲突
134
+ _PROVIDER_PREFS_LINES=$(jq -r '((.colors.claude // {}) + (.colors.codex // {})) | to_entries[] | "\(.key)=\(.value)"' "$f" 2>/dev/null)
135
+ fi
136
+ fi
137
+ printf '%s' "$_PROVIDER_PREFS_LINES"
138
+ }
139
+
140
+ _provider_tag_colour() {
141
+ local id="$1" name="$2" v=""
142
+ if [ -n "$id" ]; then
143
+ v=$(printf '%s\n' "$(_provider_prefs_lines)" | awk -F= -v id="$id" '$1==id{print $2; exit}')
144
+ fi
145
+ case "$v" in
146
+ 3[0-7]) echo $(( v - 30 )); return ;;
147
+ 9[0-7]) echo $(( v - 82 )); return ;;
148
+ esac
149
+ # auto: FNV-1a 32 位
150
+ local hash=2166136261 i ch cp
151
+ for ((i=0; i<${#name}; i++)); do
152
+ ch="${name:$i:1}"
153
+ printf -v cp '%d' "'$ch"
154
+ hash=$(( (hash ^ cp) * 16777619 & 4294967295 ))
155
+ done
156
+ case $(( hash % 6 )) in
157
+ 0) echo 96 ;; 1) echo 92 ;; 2) echo 93 ;; 3) echo 95 ;; 4) echo 94 ;; 5) echo 91 ;;
158
+ esac
159
+ }
160
+
115
161
  # --- 状态聚合 ---
116
162
  # 扫描所有 attached session 的 pane,读取 @ai_pane_status,写入 @ai_all_status
117
163
  #
@@ -124,7 +170,7 @@ build_all_status() {
124
170
  cur_sess=""
125
171
  local _ai_names
126
172
  _ai_names=$(_collect_ai_process_names)
127
- while IFS='|' read -r pane_id session_name win_idx pane_idx claude_status _attached _created _entered cur_cmd; do
173
+ while IFS='|' read -r pane_id session_name win_idx pane_idx claude_status _attached _created _entered cur_cmd prov_name prov_id; do
128
174
  local pane_status="$claude_status"
129
175
  if [ -z "$pane_status" ]; then
130
176
  # 无显式状态:若前台是 AI 进程(codex 首个 turn 前空窗期),补 idle。
@@ -149,6 +195,12 @@ build_all_status() {
149
195
  status_block="#[bg=${STATUS_COLOR},fg=#282A36] ${pane_status} #[bg=default,fg=default]"
150
196
  fi
151
197
  local seg="${panel_block}${status_block}"
198
+ # cc-switch provider 段:有 @ai_provider 才显示(非 switch 启动的 pane 无此 option)
199
+ if [ -n "$prov_name" ]; then
200
+ local prov_colour
201
+ prov_colour=$(_provider_tag_colour "$prov_id" "$prov_name")
202
+ seg="${seg}#[fg=colour${prov_colour}][${prov_name}] #[fg=default]"
203
+ fi
152
204
  if [ "$session_name" != "$cur_sess" ]; then
153
205
  ALL="${ALL:+$ALL }${session_block}${seg}"
154
206
  cur_sess="$session_name"
@@ -160,7 +212,7 @@ build_all_status() {
160
212
  # 自指 switch 由 handler 的 per-client prev 对比滤除)
161
213
  # ② session_created(无进入记录时回退创建序)。不用 session_last_attached——
162
214
  # tmux 的 server_client_set_session 无条件刷新该时间戳(自指 switch 也算),污染排序。
163
- done < <(tmux list-panes -a -F "#{pane_id}|#{session_name}|#{window_index}|#{pane_index}|#{@ai_pane_status}|#{session_attached}|#{session_created}|#{@ai_entered_time}|#{pane_current_command}" 2>/dev/null | awk -F'|' -v OFS='|' '$6>0{if($8=="")$8=$7; print}' | sort -t'|' -k8,8n -k7,7n -k2,2 -k3,3n -k4,4n)
215
+ done < <(tmux list-panes -a -F "#{pane_id}|#{session_name}|#{window_index}|#{pane_index}|#{@ai_pane_status}|#{session_attached}|#{session_created}|#{@ai_entered_time}|#{pane_current_command}|#{@ai_provider}|#{@ai_provider_id}" 2>/dev/null | awk -F'|' -v OFS='|' '$6>0{if($8=="")$8=$7; print}' | sort -t'|' -k8,8n -k7,7n -k2,2 -k3,3n -k4,4n)
164
216
  }
165
217
 
166
218
  # --- Pending 集合管理(PreToolUse / PermissionRequest 配对)---
@@ -28,6 +28,22 @@ fi
28
28
  _save_pane_id
29
29
  _maybe_cleanup_stale
30
30
 
31
+ # cc-switch 注入的 provider 标签(launch env,CLI 的 hooks 进程继承)→
32
+ # per-pane option,供 build_all_status 聚合渲染。env 随 CLI 进程定死,幂等
33
+ # 重写无害;非 switch 启动(env 缺失)时显式清除残留,避免换 AI 进程后 pane
34
+ # 显示上一个 provider。
35
+ if [ -n "$TMUX_PANE" ]; then
36
+ if [ -n "$CC_SWITCH_PROVIDER" ]; then
37
+ tmux set-option -pt "$TMUX_PANE" @ai_provider "$CC_SWITCH_PROVIDER" 2>/dev/null || true
38
+ if [ -n "$CC_SWITCH_PROVIDER_ID" ]; then
39
+ tmux set-option -pt "$TMUX_PANE" @ai_provider_id "$CC_SWITCH_PROVIDER_ID" 2>/dev/null || true
40
+ fi
41
+ else
42
+ tmux set-option -pt "$TMUX_PANE" -u @ai_provider 2>/dev/null || true
43
+ tmux set-option -pt "$TMUX_PANE" -u @ai_provider_id 2>/dev/null || true
44
+ fi
45
+ fi
46
+
31
47
  _pane_loc=""
32
48
  if [ -n "$TMUX_PANE" ]; then
33
49
  _pane_loc=$(tmux display-message -pt "$TMUX_PANE" -p "#{session_name}:#{window_index}.#{pane_index}" 2>/dev/null)
@@ -211,7 +227,8 @@ case "$EVENT" in
211
227
  exit 0
212
228
  ;;
213
229
  _session-switched)
214
- # client-session-changed hook(入口传 #{hook_client_name}):attach 与 switch-client
230
+ # client-session-changed hook(入口传 #{hook_client},3.7c/3.8 均为触发
231
+ # client 名;注意不存在 #{hook_client_name} 变量,误用恒为空):attach 与 switch-client
215
232
  # 的共同汇聚点(tmux server_client_set_session),两种「进入」都能捕获。
216
233
  # 该 hook 自指 switch 也触发(源码无 old != s 守卫)→ 用 per-client 自维护的
217
234
  # 上次 session 对比过滤:cur != prev 才算「真进入」,自指(cur == prev)跳过。
@@ -75,7 +75,10 @@ fi
75
75
  # client-session-changed: attach 与 switch-client 的共同汇聚点 = 「进入」→ 记
76
76
  # @ai_entered_time(排序用:刚进入的 session 排最后;handler 内以 per-client
77
77
  # 上次 session 对比过滤自指 switch)+ 刷新聚合
78
- tmux set-hook -g client-session-changed "run-shell '${CURRENT_DIR}/scripts/tmux-ai-status claude _session-switched #{hook_client_name}'" 2>/dev/null || true
78
+ # 变量必须用 #{hook_client}(3.7c/3.8 均展开为触发 client 名)。不存在
79
+ # #{hook_client_name} 这个 format 变量——误用它恒展开为空,handler 的
80
+ # [ -n "$3" ] 守卫静默跳过,entered_time 从不写入,排序退化为 created 序。
81
+ tmux set-hook -g client-session-changed "run-shell '${CURRENT_DIR}/scripts/tmux-ai-status claude _session-switched #{hook_client}'" 2>/dev/null || true
79
82
  # 注:_refresh 与 TOOL_ID 无关(仅重建聚合 + 自修复 claude hooks),统一传 claude。
80
83
  tmux set-hook -g session-closed "run-shell '${CURRENT_DIR}/scripts/tmux-ai-status claude _refresh'"
81
84
  tmux set-hook -g client-detached "run-shell '${CURRENT_DIR}/scripts/tmux-ai-status claude _refresh'"