tmuxclihook 0.3.3 → 0.3.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmuxclihook",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "交互式 TUI 安装器:环境侦测、AI CLI 侦测、tmux-ai-status hooks 装/卸/修、TPM 软链校验",
5
5
  "type": "module",
6
6
  "bin": {
@@ -72,10 +72,7 @@ _CLAUDE_JQ_MERGE='
72
72
  .hooks[]
73
73
  | select(.command | contains("tmux-powerline-claude-status") | not)
74
74
  | select(.command | contains("tmux-claude-status") | not)
75
- | select(
76
- (.command | contains("tmux-ai-status") | not)
77
- or (.command | startswith($dev_script))
78
- )
75
+ | select(.command | contains("tmux-ai-status") | not)
79
76
  ]
80
77
  | select(.hooks | length > 0)
81
78
  )
@@ -98,7 +95,7 @@ _CLAUDE_JQ_STRIP='
98
95
  .hooks |= if . then
99
96
  [. | to_entries[] |
100
97
  .value |= [
101
- .[] | .hooks = [.hooks[] | select(.command | startswith($hook_script) | not)]
98
+ .[] | .hooks = [.hooks[] | select(.command | contains("tmux-ai-status") | not)]
102
99
  | select(.hooks | length > 0)
103
100
  ]
104
101
  | select(.value | length > 0)
@@ -107,13 +104,12 @@ _CLAUDE_JQ_STRIP='
107
104
  '
108
105
 
109
106
  _claude_apply_merge() { # $1=输入 JSON 文件 → stdout 变换后全文档
110
- jq --arg dev_script "${_LIB_DIR}/tmux-ai-status" \
111
- --arg tool_cmd "${_LIB_DIR}/tmux-ai-status claude" \
107
+ jq --arg tool_cmd "${_LIB_DIR}/tmux-ai-status claude" \
112
108
  "$_CLAUDE_JQ_MERGE" "$1"
113
109
  }
114
110
 
115
111
  _claude_apply_strip() { # $1=输入 JSON 文件 → stdout 变换后全文档
116
- jq --arg hook_script "${_LIB_DIR}/tmux-ai-status" "$_CLAUDE_JQ_STRIP" "$1"
112
+ jq "$_CLAUDE_JQ_STRIP" "$1"
117
113
  }
118
114
 
119
115
  _claude_count_registered() { # $1=输入 JSON 文件 → stdout 事件数(jq 失败时为空)
@@ -187,18 +183,41 @@ ON CONFLICT(key) DO UPDATE SET value = json_patch(settings.value, json($(_sqlquo
187
183
  }
188
184
 
189
185
  # 完整性检查:cc-switch 模式查通用配置;否则查 hooks 配置文件。
190
- # 10 个事件都注册了本插件 hook 才算完整;缺失(外部覆盖)→ 返回 1 触发自修复。
186
+ # 三要素:10 事件计数 + 每个事件至少一条条目的脚本文件存活(test -x)。
187
+ # 计数齐但脚本死(npm 包卸载/volta 升级换路径,含部分事件死)→ missing → 自修复重装收敛。
188
+ # 存活提取内联在本函数(jq + test),不依赖 lib-install-hooks.sh——本函数同时被
189
+ # 事件路径(lib-tmux-ai-status.sh)与 install wrapper(lib-install-hooks.sh)两个上下文调用。
191
190
  adapter_check_integrity() {
192
- local registered tmp
191
+ local src registered ev p ok_events=""
193
192
  if _ccswitch_active; then
194
- _ccswitch_dump_common tmp || return 1
195
- registered=$(_claude_count_registered "$tmp")
196
- rm -f "$tmp"
193
+ _ccswitch_dump_common src || return 1
197
194
  else
198
195
  [ -f "$ADAPTER_HOOKS_FILE" ] || return 1
199
- registered=$(_claude_count_registered "$ADAPTER_HOOKS_FILE")
196
+ src="$ADAPTER_HOOKS_FILE"
197
+ fi
198
+ registered=$(_claude_count_registered "$src")
199
+ if [ "${registered:-0}" -ge 10 ]; then
200
+ while IFS=$'\t' read -r ev p; do
201
+ if [ -n "$ev" ] && [ -x "$p" ]; then
202
+ case ",$ok_events," in *",$ev,"*) ;; *) ok_events="$ok_events,$ev" ;; esac
203
+ fi
204
+ done < <(jq -r '.hooks as $h |
205
+ ["SessionStart","SessionEnd","UserPromptSubmit","PreToolUse","PostToolUse",
206
+ "PostToolUseFailure","PermissionRequest","Notification","Stop","StopFailure"] as $events |
207
+ $events[] as $e |
208
+ [$h[$e][]?.hooks[]?.command // empty
209
+ | select(contains("tmux-ai-status")) | split(" ")[0]] as $scripts |
210
+ select(($scripts | length) > 0) |
211
+ $scripts[] | "\($e)\t\(.)"' "$src" 2>/dev/null)
200
212
  fi
201
- [ "${registered:-0}" -ge 10 ]
213
+ if [ "$src" != "$ADAPTER_HOOKS_FILE" ]; then
214
+ rm -f "$src"
215
+ fi
216
+ [ "${registered:-0}" -ge 10 ] || return 1
217
+ for ev in SessionStart SessionEnd UserPromptSubmit PreToolUse PostToolUse PostToolUseFailure PermissionRequest Notification Stop StopFailure; do
218
+ case ",$ok_events," in *",$ev,"*) ;; *) return 1 ;; esac
219
+ done
220
+ return 0
202
221
  }
203
222
 
204
223
  # 安装:合并式更新,保留他人(masko 等)注册的 hook。cc-switch 模式只写库
@@ -233,6 +252,7 @@ adapter_uninstall_hooks() {
233
252
  _install_require_jq
234
253
  if _ccswitch_active; then
235
254
  local tmp stripped cur_hooks final_hooks patch managed top_patch
255
+ _ccswitch_warn_gui
236
256
  _ccswitch_dump_common tmp || return 1
237
257
  cur_hooks=$(jq -c '.hooks // {}' "$tmp")
238
258
  # 已无本插件条目 → no-op(否则会把保留的他人 hook 重写一遍)
@@ -36,14 +36,38 @@ ADAPTER_PERMISSION_PRE_TOOL_NAMES="request_permissions"
36
36
  # 自修复/TUI 调用的安装脚本
37
37
  ADAPTER_INSTALLER="${_LIB_DIR}/install-codex-hooks.sh"
38
38
 
39
- # 完整性检查:hooks.json 是否含 6 个本插件 command(0.144+)。
39
+ # 完整性计数:6 个事件中注册了含 tmux-ai-status codex 的 command 的事件数(按事件,
40
+ # 非扁平总数——重复+缺失的组合在扁平计数下会假阳性)。
41
+ _CODEX_JQ_COUNT='
42
+ .hooks as $h |
43
+ ["SessionStart","UserPromptSubmit","PreToolUse","PermissionRequest","PostToolUse","Stop"]
44
+ | map(select([$h[.][]?.hooks[]?.command // empty] | any(contains("tmux-ai-status codex"))))
45
+ | length
46
+ '
47
+
48
+ # 完整性检查:6 事件计数 + 每个事件至少一条条目的脚本文件存活(test -x)。
49
+ # 跨安装源路径无关(contains);脚本死路径(npm 包卸载/volta 换路径,含部分事件死)
50
+ # → missing → install 收敛(no-op 门禁随之放行,接受一次 re-trust 代价换功能恢复)。
40
51
  adapter_check_integrity() {
41
52
  [ -f "$ADAPTER_HOOKS_FILE" ] || return 1
42
- local n
43
- n=$(jq '[.hooks[]?[]?.hooks[]?.command // empty
44
- | select(contains("tmux-ai-status codex"))] | length' \
45
- "$ADAPTER_HOOKS_FILE" 2>/dev/null)
46
- [ "${n:-0}" -ge 6 ]
53
+ local n ev p ok_events=""
54
+ n=$(jq "$_CODEX_JQ_COUNT" "$ADAPTER_HOOKS_FILE" 2>/dev/null)
55
+ [ "${n:-0}" -ge 6 ] || return 1
56
+ while IFS=$'\t' read -r ev p; do
57
+ if [ -n "$ev" ] && [ -x "$p" ]; then
58
+ case ",$ok_events," in *",$ev,"*) ;; *) ok_events="$ok_events,$ev" ;; esac
59
+ fi
60
+ done < <(jq -r '.hooks as $h |
61
+ ["SessionStart","UserPromptSubmit","PreToolUse","PermissionRequest","PostToolUse","Stop"] as $events |
62
+ $events[] as $e |
63
+ [$h[$e][]?.hooks[]?.command // empty
64
+ | select(contains("tmux-ai-status codex")) | split(" ")[0]] as $scripts |
65
+ select(($scripts | length) > 0) |
66
+ $scripts[] | "\($e)\t\(.)"' "$ADAPTER_HOOKS_FILE" 2>/dev/null)
67
+ for ev in SessionStart UserPromptSubmit PreToolUse PermissionRequest PostToolUse Stop; do
68
+ case ",$ok_events," in *",$ev,"*) ;; *) return 1 ;; esac
69
+ done
70
+ return 0
47
71
  }
48
72
 
49
73
  # Codex 6 事件(全部同步——0.144 静默跳过 async=true 的 hook)
@@ -73,11 +97,17 @@ _codex_read_existing() {
73
97
  }
74
98
 
75
99
  # 安装:改写 hooks.json(剥离旧 managed group 后为每事件追加本插件 group),保留他人 hook。
100
+ # no-op if valid:事件齐全且脚本存活时不改写——重写即 trusted_hash 失效(command 路径
101
+ # 变化 → codex 启动要重新 Trust all),跨安装源重复安装因此保持既有授信。
76
102
  # 清理旧 hooks.toml(0.144 不再读取)。trust 无法在 bash 复现,靠用户首启 codex TUI 授信。
77
103
  adapter_install_hooks() {
78
104
  _install_require_jq
79
105
  mkdir -p "$(dirname "$ADAPTER_HOOKS_FILE")" 2>/dev/null || true
80
106
  [ -f "$_CODEX_LEGACY_TOML" ] && rm -f "$_CODEX_LEGACY_TOML" && echo "移除旧 hooks.toml(0.144 不再读取)"
107
+ if adapter_check_integrity; then
108
+ echo "Codex hooks already installed and valid at $ADAPTER_HOOKS_FILE (no-op, trust preserved)"
109
+ return 0
110
+ fi
81
111
  local hook_script="${_LIB_DIR}/tmux-ai-status"
82
112
  local new_json
83
113
  new_json=$(_codex_read_existing | _codex_strip_managed | jq \
@@ -39,11 +39,17 @@ ADAPTER_INSTALLER="${_LIB_DIR}/install-opencode-hooks.sh"
39
39
 
40
40
  _OPENCODE_MARKER="tmux-ai-status (managed by tmux-ai-hooks-status)"
41
41
 
42
- # 完整性检查:plugin 文件存在且含本插件标记 + 指向当前仓库的 hook 脚本路径。
42
+ # 完整性检查:plugin 文件存在 + 本插件标记 + 结构指纹 + HOOK_SCRIPT 指向的脚本存活。
43
+ # 路径无关(不比对当前 _LIB_DIR——跨安装源的合法 plugin 同样有效);
44
+ # 脚本死路径(npm 包卸载/换路径)→ missing → 重装收敛。
43
45
  adapter_check_integrity() {
44
46
  [ -f "$ADAPTER_HOOKS_FILE" ] || return 1
45
47
  grep -q "$_OPENCODE_MARKER" "$ADAPTER_HOOKS_FILE" 2>/dev/null || return 1
46
- grep -q "${_LIB_DIR}/tmux-ai-status" "$ADAPTER_HOOKS_FILE" 2>/dev/null || return 1
48
+ local script_path
49
+ script_path=$(sed -n 's/^const HOOK_SCRIPT = "\(.*\)"$/\1/p' "$ADAPTER_HOOKS_FILE" 2>/dev/null | head -n 1)
50
+ if [ -z "$script_path" ] || [ ! -x "$script_path" ]; then
51
+ return 1
52
+ fi
47
53
  grep -q 'case "permission.asked"' "$ADAPTER_HOOKS_FILE" 2>/dev/null || return 1
48
54
  grep -q 'case "question.asked"' "$ADAPTER_HOOKS_FILE" 2>/dev/null || return 1
49
55
  grep -q 'case "permission.replied"' "$ADAPTER_HOOKS_FILE" 2>/dev/null || return 1
@@ -142,7 +148,12 @@ EOF
142
148
  }
143
149
 
144
150
  # 安装:写出/覆盖 plugin 文件。整文件替换(非合并)——同目录下他人 plugin 文件不受影响。
151
+ # no-op if valid:文件完整且 HOOK_SCRIPT 存活时不重写(避免跨安装源无谓覆盖)。
145
152
  adapter_install_hooks() {
153
+ if adapter_check_integrity; then
154
+ echo "opencode plugin already installed and valid at $ADAPTER_HOOKS_FILE (no-op)"
155
+ return 0
156
+ fi
146
157
  mkdir -p "$(dirname "$ADAPTER_HOOKS_FILE")" 2>/dev/null || true
147
158
  local hook_script="${_LIB_DIR}/tmux-ai-status"
148
159
  local content
@@ -1,11 +1,13 @@
1
1
  #!/bin/bash
2
2
  # install-claude-hooks.sh — Claude Code hooks 安装/卸载/检查 wrapper
3
- # 用法: install-claude-hooks.sh [uninstall|check]
3
+ # 用法: install-claude-hooks.sh [install|uninstall|check|auto]
4
4
  #
5
5
  # 薄 wrapper:source 公共骨架 + claude adapter,dispatch 到 adapter_install_hooks /
6
6
  # adapter_uninstall_hooks。实际逻辑在 scripts/adapters/claude.sh。
7
7
  # check:输出 ok/missing(exit 0/1),供 TUI 侦测在 cc-switch 模式下走 bash 侧
8
8
  # 完整性判定(sqlite 真源),与非 cc-switch 的文件判定共用同一真相。
9
+ # auto:tmux 入口加载时的自动安装——存在卸载意图标记(suppressed-claude)时不装。
10
+ # 显式 uninstall 成功写标记、显式 install 成功清标记(见 lib-install-hooks.sh)。
9
11
 
10
12
  set -o errexit
11
13
  set -o pipefail
@@ -14,15 +16,28 @@ _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
14
16
  source "${_LIB_DIR}/lib-install-hooks.sh"
15
17
  source "${_LIB_DIR}/adapters/claude.sh"
16
18
 
17
- if [ "${1:-install}" = "uninstall" ]; then
18
- adapter_uninstall_hooks
19
- elif [ "${1:-}" = "check" ]; then
20
- if adapter_check_integrity; then
21
- echo ok
22
- else
23
- echo missing
24
- exit 1
25
- fi
26
- else
27
- adapter_install_hooks
28
- fi
19
+ case "${1:-install}" in
20
+ uninstall)
21
+ adapter_uninstall_hooks
22
+ _hooks_suppress_write claude
23
+ ;;
24
+ check)
25
+ if adapter_check_integrity; then
26
+ echo ok
27
+ else
28
+ echo missing
29
+ exit 1
30
+ fi
31
+ ;;
32
+ auto)
33
+ if [ -f "$(_hooks_suppress_file claude)" ]; then
34
+ exit 0
35
+ fi
36
+ adapter_install_hooks
37
+ _hooks_suppress_clear claude
38
+ ;;
39
+ *)
40
+ adapter_install_hooks
41
+ _hooks_suppress_clear claude
42
+ ;;
43
+ esac
@@ -1,9 +1,11 @@
1
1
  #!/bin/bash
2
- # install-codex-hooks.sh — Codex CLI hooks 安装/卸载 wrapper(需 codex ≥ 0.144)
3
- # 用法: install-codex-hooks.sh [uninstall]
2
+ # install-codex-hooks.sh — Codex CLI hooks 安装/卸载/检查 wrapper(需 codex ≥ 0.144)
3
+ # 用法: install-codex-hooks.sh [install|uninstall|check]
4
4
  #
5
5
  # 薄 wrapper:source 公共骨架 + codex adapter,dispatch 到 adapter_install_hooks /
6
6
  # adapter_uninstall_hooks。实际逻辑在 scripts/adapters/codex.sh。
7
+ # check:输出 ok/missing(exit 0/1),供 TUI 侦测走 bash 侧完整性判定。
8
+ # 显式 uninstall 成功写标记、显式 install 成功清标记(见 lib-install-hooks.sh)。
7
9
 
8
10
  set -o errexit
9
11
  set -o pipefail
@@ -12,8 +14,21 @@ _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
12
14
  source "${_LIB_DIR}/lib-install-hooks.sh"
13
15
  source "${_LIB_DIR}/adapters/codex.sh"
14
16
 
15
- if [ "${1:-install}" = "uninstall" ]; then
16
- adapter_uninstall_hooks
17
- else
18
- adapter_install_hooks
19
- fi
17
+ case "${1:-install}" in
18
+ uninstall)
19
+ adapter_uninstall_hooks
20
+ _hooks_suppress_write codex
21
+ ;;
22
+ check)
23
+ if adapter_check_integrity; then
24
+ echo ok
25
+ else
26
+ echo missing
27
+ exit 1
28
+ fi
29
+ ;;
30
+ *)
31
+ adapter_install_hooks
32
+ _hooks_suppress_clear codex
33
+ ;;
34
+ esac
@@ -1,9 +1,11 @@
1
1
  #!/bin/bash
2
- # install-opencode-hooks.sh — opencode plugin 安装/卸载 wrapper
3
- # 用法: install-opencode-hooks.sh [uninstall]
2
+ # install-opencode-hooks.sh — opencode plugin 安装/卸载/检查 wrapper
3
+ # 用法: install-opencode-hooks.sh [install|uninstall|check]
4
4
  #
5
5
  # 薄 wrapper:source 公共骨架 + opencode adapter,dispatch 到 adapter_install_hooks /
6
6
  # adapter_uninstall_hooks。实际逻辑在 scripts/adapters/opencode.sh。
7
+ # check:输出 ok/missing(exit 0/1),供 TUI 侦测走 bash 侧完整性判定。
8
+ # 显式 uninstall 成功写标记、显式 install 成功清标记(见 lib-install-hooks.sh)。
7
9
 
8
10
  set -o errexit
9
11
  set -o pipefail
@@ -12,8 +14,21 @@ _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
12
14
  source "${_LIB_DIR}/lib-install-hooks.sh"
13
15
  source "${_LIB_DIR}/adapters/opencode.sh"
14
16
 
15
- if [ "${1:-install}" = "uninstall" ]; then
16
- adapter_uninstall_hooks
17
- else
18
- adapter_install_hooks
19
- fi
17
+ case "${1:-install}" in
18
+ uninstall)
19
+ adapter_uninstall_hooks
20
+ _hooks_suppress_write opencode
21
+ ;;
22
+ check)
23
+ if adapter_check_integrity; then
24
+ echo ok
25
+ else
26
+ echo missing
27
+ exit 1
28
+ fi
29
+ ;;
30
+ *)
31
+ adapter_install_hooks
32
+ _hooks_suppress_clear opencode
33
+ ;;
34
+ esac
@@ -24,3 +24,16 @@ _install_atomic_write() {
24
24
  printf '%s\n' "$content" > "$tmp"
25
25
  mv -f "$tmp" "$target"
26
26
  }
27
+
28
+ # --- 卸载意图标记(suppression marker)---
29
+ # 显式 uninstall 成功 → 写 suppressed-<tool>;显式 install 成功 → 清。
30
+ # 自动修复路径(_maybe_repair_hooks / 入口 auto / SessionStart 重装)见标记一律不装。
31
+ # ⚠️ _SUPPRESS_DIR 与 lib-tmux-ai-status.sh 中的定义保持一致(两处同步改)。
32
+ _SUPPRESS_DIR="${TMUX_AI_SUPPRESS_DIR:-${XDG_CONFIG_HOME:-${HOME}/.config}/tmuxclihook}"
33
+
34
+ _hooks_suppress_file() { printf '%s/suppressed-%s' "$_SUPPRESS_DIR" "$1"; }
35
+ _hooks_suppress_write() {
36
+ mkdir -p "$_SUPPRESS_DIR" 2>/dev/null || true
37
+ date +%s > "$(_hooks_suppress_file "$1")" 2>/dev/null || true
38
+ }
39
+ _hooks_suppress_clear() { rm -f "$(_hooks_suppress_file "$1")" 2>/dev/null || true; }
@@ -6,6 +6,8 @@
6
6
  _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
7
 
8
8
  _STATUS_DIR="${TMUX_AI_STATUS_DIR:-/tmp/ai-status}"
9
+ # 卸载意图标记目录(suppressed-<tool>)。⚠️ 与 lib-install-hooks.sh 中的定义保持一致(两处同步改)。
10
+ _SUPPRESS_DIR="${TMUX_AI_SUPPRESS_DIR:-${XDG_CONFIG_HOME:-${HOME}/.config}/tmuxclihook}"
9
11
  STATUS_COLOR="#F1FA8C"
10
12
 
11
13
  # --- 日志模块 ---
@@ -533,6 +535,10 @@ _check_hooks_integrity() {
533
535
  # 不依赖 SESSION_ID/EVENT,可被 _refresh 触发。60s 节流。
534
536
  # 安装器由 adapter 声明(ADAPTER_INSTALLER)。
535
537
  _maybe_repair_hooks() {
538
+ # 用户显式卸载意图(suppressed-<tool>)→ 不自动修复,尊重到显式安装为止。
539
+ if [ -f "${_SUPPRESS_DIR}/suppressed-${TOOL_ID:-claude}" ]; then
540
+ return 0
541
+ fi
536
542
  local marker="${_STATUS_DIR}/.hooks-repair-${TOOL_ID:-claude}-ts"
537
543
  local now
538
544
  now=$(date +%s)
@@ -178,8 +178,12 @@ case "$EVENT" in
178
178
  STATUS="-"
179
179
  _clear_pending
180
180
  if ! _check_hooks_integrity; then
181
- "${ADAPTER_INSTALLER}" >/dev/null 2>&1
182
- tmux display-message "⚠ ${TOOL_ID} hooks 已自动修复(检测到缺失)" 2>/dev/null || true
181
+ if [ -f "${_SUPPRESS_DIR}/suppressed-${TOOL_ID}" ]; then
182
+ _ai_log "REPAIR: suppressed by uninstall marker, skip (${TOOL_ID})"
183
+ else
184
+ "${ADAPTER_INSTALLER}" >/dev/null 2>&1
185
+ tmux display-message "⚠ ${TOOL_ID} hooks 已自动修复(检测到缺失)" 2>/dev/null || true
186
+ fi
183
187
  fi
184
188
  ;;
185
189
  SessionEnd)
@@ -45,6 +45,9 @@ function buildTools(scriptsDir) {
45
45
  installer: join(scriptsDir, 'install-codex-hooks.sh'),
46
46
  hookMarker: 'tmux-ai-status codex',
47
47
  minHookCount: 6,
48
+ // 无 cc-switch 真源(hooks.json 即文件真源),但统一走 wrapper check 以获得
49
+ // 脚本存活校验(死路径 → missing → repair 收敛),与 bash 侧同一份真相。
50
+ checkViaWrapper: true,
48
51
  },
49
52
  {
50
53
  id: 'opencode',
@@ -62,6 +65,9 @@ function buildTools(scriptsDir) {
62
65
  installer: join(scriptsDir, 'install-opencode-hooks.sh'),
63
66
  hookMarker: 'tmux-ai-status (managed by tmux-ai-hooks-status)',
64
67
  minHookCount: 1,
68
+ // 统一走 wrapper check:bash 侧含 HOOK_SCRIPT 存活校验(死路径 → missing →
69
+ // repair 收敛),JS 文件计数判不出死路径。
70
+ checkViaWrapper: true,
65
71
  },
66
72
  ];
67
73
  }
package/src/detect.js CHANGED
@@ -121,10 +121,11 @@ function hooksInstalled(tool) {
121
121
  }
122
122
  }
123
123
 
124
- // 异步判定:声明 checkViaWrapper 且 cc-switch db 存在时,走 bash wrapper check
125
- // (bash 侧按 sqlite 通用配置判定真源);否则回落本地文件计数。
124
+ // 异步判定:声明 checkViaWrapper 时走 bash wrapper check(cc-switch 模式在 bash 侧
125
+ // 按 sqlite 通用配置判定真源;所有 adapter check 均含脚本存活校验);未声明的工具
126
+ // 回落本地文件计数。
126
127
  async function hooksInstalledAsync(tool) {
127
- if (tool.checkViaWrapper && tool.ccSwitchDb && existsSync(tool.ccSwitchDb)) {
128
+ if (tool.checkViaWrapper && (!tool.ccSwitchDb || existsSync(tool.ccSwitchDb))) {
128
129
  try {
129
130
  const { stdout, exitCode } = await execa('bash', [tool.installer, 'check'], {
130
131
  reject: false,
@@ -58,8 +58,10 @@ if [ -z "$(tmux show-option -gv @claude_hooks_reload_registered 2>/dev/null)" ];
58
58
  fi
59
59
 
60
60
  # --- 自动注册 Claude hooks(幂等,每次插件加载时确保 hooks 存在)---
61
+ # auto 模式:用户显式卸载过(suppressed-claude 标记在)时静默跳过,尊重卸载意图;
62
+ # 显式安装(prefix+C-h / TUI)才会清除标记恢复自动守护。
61
63
  # 注:codex/opencode hooks 不自动安装(非人人安装),用 prefix+M-h / prefix+C-p 手动装。
62
- "${CURRENT_DIR}/scripts/install-claude-hooks.sh" >/dev/null 2>&1 || true
64
+ "${CURRENT_DIR}/scripts/install-claude-hooks.sh" auto >/dev/null 2>&1 || true
63
65
 
64
66
  # --- 启动 tmux server 级状态监控器 ---
65
67
  # Codex/opencode 均无 SessionEnd(codex 的 SessionStart 还延迟到首个 turn);