tmuxclihook 0.5.11 → 0.5.13
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
|
@@ -18,6 +18,15 @@ _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
|
18
18
|
source "${_LIB_DIR}/lib-install-hooks.sh"
|
|
19
19
|
source "${_LIB_DIR}/adapters/claude.sh"
|
|
20
20
|
|
|
21
|
+
# 子命令白名单:必须在取锁前校验——拼错的子命令不应先白等最多 10s 锁超时
|
|
22
|
+
case "${1:-install}" in
|
|
23
|
+
install|uninstall|check|auto) ;;
|
|
24
|
+
*)
|
|
25
|
+
echo "Usage: $0 [install|uninstall|check [--json]|auto]" >&2
|
|
26
|
+
exit 2
|
|
27
|
+
;;
|
|
28
|
+
esac
|
|
29
|
+
|
|
21
30
|
# 写路径互斥(check 只读不锁):临界区覆盖 adapter 调用 + suppress 标记读-改-写,
|
|
22
31
|
# 串行化 auto 与显式 uninstall 的标记 TOCTOU。失败语义见 _install_acquire_lock:
|
|
23
32
|
# 降级无锁(rc=2)继续;等待超时(rc=1)退出。
|
|
@@ -15,6 +15,15 @@ _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
|
15
15
|
source "${_LIB_DIR}/lib-install-hooks.sh"
|
|
16
16
|
source "${_LIB_DIR}/adapters/codex.sh"
|
|
17
17
|
|
|
18
|
+
# 子命令白名单:必须在取锁前校验——拼错的子命令不应先白等最多 10s 锁超时
|
|
19
|
+
case "${1:-install}" in
|
|
20
|
+
install|uninstall|check) ;;
|
|
21
|
+
*)
|
|
22
|
+
echo "Usage: $0 [install|uninstall|check [--json]]" >&2
|
|
23
|
+
exit 2
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
18
27
|
# 写路径互斥(check 只读不锁):见 _install_acquire_lock 头注释。
|
|
19
28
|
case "${1:-install}" in
|
|
20
29
|
check) ;;
|
|
@@ -15,6 +15,15 @@ _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
|
15
15
|
source "${_LIB_DIR}/lib-install-hooks.sh"
|
|
16
16
|
source "${_LIB_DIR}/adapters/opencode.sh"
|
|
17
17
|
|
|
18
|
+
# 子命令白名单:必须在取锁前校验——拼错的子命令不应先白等最多 10s 锁超时
|
|
19
|
+
case "${1:-install}" in
|
|
20
|
+
install|uninstall|check) ;;
|
|
21
|
+
*)
|
|
22
|
+
echo "Usage: $0 [install|uninstall|check [--json]]" >&2
|
|
23
|
+
exit 2
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
18
27
|
# 写路径互斥(check 只读不锁):见 _install_acquire_lock 头注释。
|
|
19
28
|
case "${1:-install}" in
|
|
20
29
|
check) ;;
|
|
@@ -666,6 +666,23 @@ _clear_pending() {
|
|
|
666
666
|
_release_lock
|
|
667
667
|
}
|
|
668
668
|
|
|
669
|
+
# pending 集合中是否有 N 秒内的条目(每行 "id tool ts")。用于区分「工具确实在
|
|
670
|
+
# 跑」与「泄漏/中断残留的旧条目」——并发 hook 抢锁超时会让 _remove_pending_id
|
|
671
|
+
# 静默放弃,集合可能长期残留陈旧 id(实测存在),不能只按非空判定活跃。
|
|
672
|
+
_pending_recent() { # $1=秒数 → 0=有新鲜条目
|
|
673
|
+
local max="${1:-10}" now f
|
|
674
|
+
now=$(date +%s)
|
|
675
|
+
for f in "$(_pending_pre_path)" "$(_pending_perm_path)"; do
|
|
676
|
+
[ -s "$f" ] || continue
|
|
677
|
+
if awk -v now="$now" -v max="$max" '
|
|
678
|
+
$3 ~ /^[0-9]+$/ && now - $3 <= max { found = 1; exit }
|
|
679
|
+
END { exit !found }' "$f" 2>/dev/null; then
|
|
680
|
+
return 0
|
|
681
|
+
fi
|
|
682
|
+
done
|
|
683
|
+
return 1
|
|
684
|
+
}
|
|
685
|
+
|
|
669
686
|
# 根据当前 pending-perm / pending-pre 派生 STATUS。结果写入全局 DERIVED
|
|
670
687
|
# return 0 = 派生出非空 STATUS, return 1 = 都空(事件需自行决定)
|
|
671
688
|
_derive_status_from_pending() {
|
|
@@ -942,13 +959,17 @@ _cleanup_stale_panes() {
|
|
|
942
959
|
# (tr -c 'A-Za-z0-9._-' '_'),无法从 key 反推 client → 反向枚举存活集比对。
|
|
943
960
|
# 实测关注:长期运行的 server 会累积已 detach 的 client 键(8 option / 4 存活)。
|
|
944
961
|
_prune_prev_sess_options() {
|
|
945
|
-
local alive=" " name key opt
|
|
962
|
+
local alive=" " name key opt clients opts
|
|
963
|
+
# 两次 tmux 查询都必须成功才剪枝:tmux 抖动(server 重启/连接失败)时
|
|
964
|
+
# list-clients 返回空会被误判为「无存活 client」→ 把全部键删光。
|
|
965
|
+
clients=$(tmux list-clients -F '#{client_name}' 2>/dev/null) || return 0
|
|
966
|
+
opts=$(tmux show-options -g 2>/dev/null) || return 0
|
|
946
967
|
while IFS= read -r name; do
|
|
947
968
|
[ -n "$name" ] || continue
|
|
948
969
|
key=$(printf '%s' "$name" | tr -c 'A-Za-z0-9._-' '_')
|
|
949
970
|
alive="$alive$key "
|
|
950
|
-
done
|
|
951
|
-
for opt in $(
|
|
971
|
+
done <<< "$clients"
|
|
972
|
+
for opt in $(printf '%s\n' "$opts" | awk '/^@ai_prev_sess_/{print $1}'); do
|
|
952
973
|
key="${opt#@ai_prev_sess_}"
|
|
953
974
|
case "$alive" in
|
|
954
975
|
*" $key "*) ;;
|
package/scripts/tmux-ai-status
CHANGED
|
@@ -80,20 +80,28 @@ _current_pane_status() {
|
|
|
80
80
|
|
|
81
81
|
# Notification「隐式」路径(idle_prompt / waiting for your input)的状态解析:
|
|
82
82
|
# 通知可能乱序晚到(async hook 无顺序保证),不能无条件降级为 idle '-'。
|
|
83
|
-
#
|
|
84
|
-
# pending-
|
|
83
|
+
# 判定顺序(⚠️ 不能颠倒):
|
|
84
|
+
# 1. live 审批态 !/? → 保持。审批等待期间 pending-pre 非空(PreToolUse 先于
|
|
85
|
+
# PermissionRequest),若先看 pending 会派生出 '>' 把 '!' 降级——违反
|
|
86
|
+
# 「审批态永不覆盖」
|
|
87
|
+
# 2. pending 派生出 !/? → 采用(codex/opencode 的审批集合;claude 不写 perm)
|
|
88
|
+
# 3. pending 派生出 '>' → **仅当存在 10s 内的新条目才可信**(并发 hook 抢锁
|
|
89
|
+
# 超时会让清理静默放弃,集合可能残留陈旧 id),否则视为残留
|
|
90
|
+
# 4. 其余 → '-'
|
|
85
91
|
# 显式重置消息(denied/cancelled/rejected)不走本函数——denial 携带「等待已结束」
|
|
86
92
|
# 语义,应无条件置 '-'。
|
|
87
93
|
_notification_implicit_status() {
|
|
88
|
-
if _derive_status_from_pending; then
|
|
89
|
-
printf '%s' "$DERIVED"
|
|
90
|
-
return
|
|
91
|
-
fi
|
|
92
94
|
local live
|
|
93
95
|
live=$(_current_pane_status)
|
|
94
96
|
case "$live" in
|
|
95
97
|
"!"|"?") printf '%s' "$live"; return ;;
|
|
96
98
|
esac
|
|
99
|
+
if _derive_status_from_pending; then
|
|
100
|
+
case "$DERIVED" in
|
|
101
|
+
"!"|"?") printf '%s' "$DERIVED"; return ;;
|
|
102
|
+
esac
|
|
103
|
+
if _pending_recent 10; then printf '%s' ">"; return; fi
|
|
104
|
+
fi
|
|
97
105
|
printf '%s' "-"
|
|
98
106
|
}
|
|
99
107
|
|
|
@@ -128,7 +128,7 @@ fi
|
|
|
128
128
|
# 全局 root 表绑定会覆盖用户既有 Escape 绑定——覆盖前保存 + 一次性告警
|
|
129
129
|
# (无法安全链式调用任意已有绑定,恢复需手动):
|
|
130
130
|
# tmux show-option -gv @claude_hooks_saved_bind_escape
|
|
131
|
-
_prev_esc=$(tmux list-keys -
|
|
131
|
+
_prev_esc=$(tmux list-keys -T root Escape 2>/dev/null || true)
|
|
132
132
|
case "$_prev_esc" in
|
|
133
133
|
""|*tmux-ai-esc*) ;;
|
|
134
134
|
*)
|