tmuxclihook 0.5.3 → 0.5.4
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 +1 -1
- package/scripts/lib-tmux-ai-status.sh +13 -3
- package/scripts/tmux-ai-monitor +32 -7
package/package.json
CHANGED
|
@@ -168,13 +168,20 @@ _provider_tag_colour() {
|
|
|
168
168
|
build_all_status() {
|
|
169
169
|
ALL=""
|
|
170
170
|
cur_sess=""
|
|
171
|
-
local _ai_names
|
|
171
|
+
local _ai_names _fmt _n
|
|
172
172
|
_ai_names=$(_collect_ai_process_names)
|
|
173
|
-
|
|
173
|
+
# 动态追加上 monitor 的 seen 标记(无 SessionEnd 工具的进程树探测结果)。
|
|
174
|
+
# switch/volta-shim 启动的 pane 前台命令不是 codex,必须靠该标记补 idle `-`。
|
|
175
|
+
_fmt="#{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}"
|
|
176
|
+
for _n in $_ai_names; do
|
|
177
|
+
_fmt="$_fmt|#{@ai_monitor_seen_$_n}"
|
|
178
|
+
done
|
|
179
|
+
while IFS='|' read -r pane_id session_name win_idx pane_idx claude_status _attached _created _entered cur_cmd prov_name prov_id _seen_flags; do
|
|
174
180
|
local pane_status="$claude_status"
|
|
175
181
|
if [ -z "$pane_status" ]; then
|
|
176
182
|
# 无显式状态:若前台是 AI 进程(codex 首个 turn 前空窗期),补 idle。
|
|
177
183
|
# 进程名集合从所有 adapter 汇总,前缀匹配(codex-aarch64-* 等)。
|
|
184
|
+
# 前台命令是 switch/volta-shim 时改为读 monitor 的进程树标记。
|
|
178
185
|
local _cmd_base _n _is_ai=0
|
|
179
186
|
_cmd_base=$(basename "$cur_cmd" 2>/dev/null)
|
|
180
187
|
for _n in $_ai_names; do
|
|
@@ -182,6 +189,9 @@ build_all_status() {
|
|
|
182
189
|
"$_n"|"$_n"-*|"$_n"_*) _is_ai=1; break ;;
|
|
183
190
|
esac
|
|
184
191
|
done
|
|
192
|
+
if [ "$_is_ai" = "0" ]; then
|
|
193
|
+
case "$_seen_flags" in *1*) _is_ai=1 ;; esac
|
|
194
|
+
fi
|
|
185
195
|
[ "$_is_ai" = "1" ] && pane_status="-" || continue
|
|
186
196
|
fi
|
|
187
197
|
local session_block="#[bg=#6272A4,fg=#F8F8F2] ${session_name} #[bg=default,fg=default]"
|
|
@@ -212,7 +222,7 @@ build_all_status() {
|
|
|
212
222
|
# 自指 switch 由 handler 的 per-client prev 对比滤除)
|
|
213
223
|
# ② session_created(无进入记录时回退创建序)。不用 session_last_attached——
|
|
214
224
|
# tmux 的 server_client_set_session 无条件刷新该时间戳(自指 switch 也算),污染排序。
|
|
215
|
-
done < <(tmux list-panes -a -F "
|
|
225
|
+
done < <(tmux list-panes -a -F "$_fmt" 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)
|
|
216
226
|
}
|
|
217
227
|
|
|
218
228
|
# --- Pending 集合管理(PreToolUse / PermissionRequest 配对)---
|
package/scripts/tmux-ai-monitor
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
# tmux-ai-monitor — tmux server 级单例监控器
|
|
3
3
|
#
|
|
4
4
|
# 部分 AI CLI(codex、opencode)没有 SessionEnd hook,退出无法主动清空状态;codex 的
|
|
5
|
-
# SessionStart 还会延迟到首个 turn
|
|
5
|
+
# SessionStart 还会延迟到首个 turn。本监控器每秒刷新:
|
|
6
6
|
# - 前台启动此类工具、尚无 hook 状态时,显示 idle `-`
|
|
7
|
-
# -
|
|
7
|
+
# - cc-switch 的 `switch` 启动时前台命令是 volta-shim/node 而非工具名,改为
|
|
8
|
+
# (每 N 个 tick)探测 launcher pane 的进程树来识别,并写 seen 标记供聚合补 `-`
|
|
9
|
+
# - 退出返回 shell(或进程树已无该工具)后,清除残留 pane 状态
|
|
8
10
|
# 泛化实现:扫描 adapters/*.sh 找出 ADAPTER_HAS_SESSION_END="false" 的工具及其
|
|
9
11
|
# ADAPTER_PROCESS_NAMES,逐个工具做生命周期检测——新增同类工具的 adapter 无需改本文件。
|
|
10
12
|
# `/new`(codex)等同工具内会话切换不改变前台进程,因此不会改写已有 `✓`。
|
|
@@ -15,6 +17,18 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
15
17
|
_ADAPTER_DIR="${SCRIPT_DIR}/adapters"
|
|
16
18
|
MODE="${1:-start}"
|
|
17
19
|
MONITOR_INTERVAL="${TMUX_AI_MONITOR_INTERVAL:-1}"
|
|
20
|
+
# 进程树探测节流:launcher pane 每 N 个 tick 做一次 BFS(run 循环内 _TICK 持续累加)。
|
|
21
|
+
_MONITOR_PROBE_EVERY=5
|
|
22
|
+
_MONITOR_TICK=0
|
|
23
|
+
|
|
24
|
+
# 常见 launcher:switch/volta/npm 系脚本在前台时,目标 CLI 位于其子进程树中,
|
|
25
|
+
# pane_current_command 不会直接等于 codex/opencode(cc-switch 的 switch 启动即如此)。
|
|
26
|
+
_is_launcher_command() {
|
|
27
|
+
case "$(basename "${1:-}" 2>/dev/null)" in
|
|
28
|
+
switch|volta|volta-shim|node|npx|pnpx|pnpm|yarn|bun|bunx|deno) return 0 ;;
|
|
29
|
+
esac
|
|
30
|
+
return 1
|
|
31
|
+
}
|
|
18
32
|
|
|
19
33
|
_tmux_server_pid() {
|
|
20
34
|
tmux display-message -p '#{pid}' 2>/dev/null
|
|
@@ -86,15 +100,16 @@ _pane_has_tool_process() {
|
|
|
86
100
|
return 1
|
|
87
101
|
}
|
|
88
102
|
|
|
89
|
-
# 对每个无 SessionEnd
|
|
90
|
-
#
|
|
91
|
-
# seen 标记按工具名区分(@ai_monitor_seen_<name
|
|
103
|
+
# 对每个无 SessionEnd 的工具名做生命周期检测:前台命令匹配或 launcher 进程树命中
|
|
104
|
+
# → 标记见过;曾标记但前台已切走且进程树也无该工具 → 清空 pane 状态(该工具已退出)。
|
|
105
|
+
# seen 标记按工具名区分(@ai_monitor_seen_<name>),避免多工具互相踩踏清理语义;
|
|
106
|
+
# 该标记同时是 build_all_status 给 launcher pane 补 idle `-` 的依据。
|
|
92
107
|
_monitor_no_session_end_lifecycle() {
|
|
93
108
|
local tools name pane_id current_command sanitized pane_dir
|
|
94
109
|
tools=$(_collect_no_session_end_tools)
|
|
95
110
|
[ -n "$tools" ] || return 0
|
|
96
111
|
for name in $tools; do
|
|
97
|
-
while IFS='|' read -r pane_id current_command seen; do
|
|
112
|
+
while IFS='|' read -r pane_id current_command seen attached; do
|
|
98
113
|
if [ -n "$current_command" ] && _is_tool_command "$(basename "$current_command" 2>/dev/null)" "$name"; then
|
|
99
114
|
[ "$seen" = "1" ] || tmux set-option -pt "$pane_id" "@ai_monitor_seen_${name}" 1 2>/dev/null || true
|
|
100
115
|
elif [ "$seen" = "1" ] && ! _pane_has_tool_process "$pane_id" "$name"; then
|
|
@@ -103,8 +118,17 @@ _monitor_no_session_end_lifecycle() {
|
|
|
103
118
|
sanitized="${pane_id//[^a-zA-Z0-9]/_}"
|
|
104
119
|
pane_dir="${_STATUS_DIR}/${sanitized}"
|
|
105
120
|
rm -rf "$pane_dir" 2>/dev/null
|
|
121
|
+
elif [ "$seen" != "1" ] \
|
|
122
|
+
&& [ "${attached:-0}" -gt 0 ] \
|
|
123
|
+
&& [ $((_MONITOR_TICK % _MONITOR_PROBE_EVERY)) -eq 0 ] \
|
|
124
|
+
&& _is_launcher_command "$current_command" \
|
|
125
|
+
&& _pane_has_tool_process "$pane_id" "$name"; then
|
|
126
|
+
# launcher(switch/volta-shim/node)启动:前台命令不是工具名,
|
|
127
|
+
# 但进程树里有。标记 seen 后 build_all_status 才会补 idle `-`,
|
|
128
|
+
# 工具退出时也才会走上面的清理分支(否则残留状态永不清)。
|
|
129
|
+
tmux set-option -pt "$pane_id" "@ai_monitor_seen_${name}" 1 2>/dev/null || true
|
|
106
130
|
fi
|
|
107
|
-
done < <(tmux list-panes -a -F "#{pane_id}|#{pane_current_command}|#{@ai_monitor_seen_${name}}" 2>/dev/null)
|
|
131
|
+
done < <(tmux list-panes -a -F "#{pane_id}|#{pane_current_command}|#{@ai_monitor_seen_${name}}|#{session_attached}" 2>/dev/null)
|
|
108
132
|
done
|
|
109
133
|
}
|
|
110
134
|
|
|
@@ -118,6 +142,7 @@ _monitor_tick() {
|
|
|
118
142
|
tmux set-option -g @ai_all_status "$ALL" 2>/dev/null || return 1
|
|
119
143
|
tmux refresh-client -S 2>/dev/null || true
|
|
120
144
|
fi
|
|
145
|
+
_MONITOR_TICK=$((_MONITOR_TICK + 1))
|
|
121
146
|
return 0
|
|
122
147
|
}
|
|
123
148
|
|