#!/usr/bin/env bash
# cc-tmux インストーラ(T008/T016/T037)。
# 参照: contracts/hooks.md, contracts/tmux-display.md, quickstart.md
#
# cc-tmux-install --install フック登録 + tmux 表示設定の追記
# cc-tmux-install --uninstall フック削除 + tmux 設定除去 + 既定表示へ復元
# cc-tmux-install --help
#
# settings.json は ~/.claude/settings.json(--project で .claude/settings.json)。
set -u
CC_DIR=$(cd "$(dirname "$0")/.." && pwd)
HOOK_CMD="$CC_DIR/bin/cc-tmux-hook"
TMUX_SNIPPET="$CC_DIR/tmux/cc-tmux.tmux"
EVENTS="SessionStart UserPromptSubmit PreToolUse PreCompact Stop SessionEnd"
MARK_BEGIN="# >>> cc-tmux >>>"
MARK_END="# <<< cc-tmux <<<"
usage() {
cat <<EOF
cc-tmux-install — Claude Code の busy/idle を tmux タブへ表示する統合をインストール
使い方:
cc-tmux-install --install [--project]
cc-tmux-install --uninstall [--project]
オプション:
--install フック登録と tmux 設定追記を行う
--uninstall フック・tmux 設定を除去し既定表示へ戻す
--project ~/.claude ではなくカレントの .claude/settings.json を対象にする
--help このヘルプ
EOF
}
settings_path() {
if [ "${PROJECT_SCOPE:-0}" = "1" ]; then
printf '%s/.claude/settings.json' "$(pwd)"
else
printf '%s/.claude/settings.json' "$HOME"
fi
}
require_jq() {
command -v jq >/dev/null 2>&1 || { echo "エラー: jq が必要です。" >&2; exit 1; }
}
# settings.json へ 6 イベントのフックをマージ(冪等)。
install_hooks() {
require_jq
_sf=$(settings_path)
mkdir -p "$(dirname "$_sf")"
[ -f "$_sf" ] || printf '{}\n' > "$_sf"
_group=$(jq -n --arg cmd "$HOOK_CMD" \
'{hooks: [{type: "command", command: $cmd}]}')
_tmp="$_sf.tmp.$$"
jq --arg cmd "$HOOK_CMD" --argjson group "$_group" --arg events "$EVENTS" '
reduce ($events | split(" ")[]) as $ev (.;
.hooks = (.hooks // {})
| .hooks[$ev] = (.hooks[$ev] // [])
| if any(.hooks[$ev][]?; (.hooks // []) | any(.command == $cmd))
then .
else .hooks[$ev] += [$group]
end
)
' "$_sf" > "$_tmp" && mv -f "$_tmp" "$_sf" || { rm -f "$_tmp"; echo "エラー: settings.json 更新失敗" >&2; exit 1; }
echo "フック登録: $_sf"
}
# settings.json から自身のフックを除去。
uninstall_hooks() {
require_jq
_sf=$(settings_path)
[ -f "$_sf" ] || { echo "settings.json なし(スキップ): $_sf"; return 0; }
_tmp="$_sf.tmp.$$"
jq --arg cmd "$HOOK_CMD" --arg events "$EVENTS" '
reduce ($events | split(" ")[]) as $ev (.;
if (.hooks[$ev]? != null)
then .hooks[$ev] = ([.hooks[$ev][] | select(((.hooks // []) | any(.command == $cmd)) | not)])
| (if (.hooks[$ev] | length) == 0 then del(.hooks[$ev]) else . end)
else . end
)
| (if (.hooks? != null and (.hooks | length) == 0) then del(.hooks) else . end)
' "$_sf" > "$_tmp" && mv -f "$_tmp" "$_sf" || { rm -f "$_tmp"; echo "エラー: settings.json 更新失敗" >&2; exit 1; }
echo "フック除去: $_sf"
}
# ~/.tmux.conf にマーカー付きで表示設定を追記(冪等)。
install_tmux() {
_conf="$HOME/.tmux.conf"
[ -f "$_conf" ] || : > "$_conf"
if grep -qF "$MARK_BEGIN" "$_conf" 2>/dev/null; then
echo "tmux 設定: 既に追記済み(スキップ)"
else
{
printf '\n%s\n' "$MARK_BEGIN"
printf 'run-shell '\''%s'\''\n' "$TMUX_SNIPPET"
printf '%s\n' "$MARK_END"
} >> "$_conf"
echo "tmux 設定追記: $_conf"
fi
if [ -n "${TMUX:-}" ]; then
tmux source-file "$_conf" 2>/dev/null && echo "tmux 設定を再読込しました"
fi
}
# ~/.tmux.conf からマーカーブロックを除去し、既定表示へ復元。
uninstall_tmux() {
_conf="$HOME/.tmux.conf"
if [ -f "$_conf" ] && grep -qF "$MARK_BEGIN" "$_conf" 2>/dev/null; then
_tmp="$_conf.tmp.$$"
# マーカー間(マーカー含む)を削除。
awk -v b="$MARK_BEGIN" -v e="$MARK_END" '
$0==b {skip=1; next}
$0==e {skip=0; next}
skip!=1 {print}
' "$_conf" > "$_tmp" && mv -f "$_tmp" "$_conf"
echo "tmux 設定除去: $_conf"
else
echo "tmux 設定なし(スキップ)"
fi
# 実行中なら既定の window-status-format へ戻す。
if [ -n "${TMUX:-}" ]; then
tmux set-option -gu window-status-format 2>/dev/null
tmux set-option -gu window-status-current-format 2>/dev/null
tmux set-option -gu status-interval 2>/dev/null
tmux set-option -gu @cc_tmux_fmt 2>/dev/null # プラグインの遅延適用センチネルも掃除
# 既存ウィンドウの残存ユーザーオプションを掃除。
for _w in $(tmux list-windows -F '#{window_id}' 2>/dev/null); do
tmux set-option -w -t "$_w" -u @cc_state 2>/dev/null
tmux set-option -w -t "$_w" -u @cc_spin 2>/dev/null
done
tmux refresh-client -S 2>/dev/null
echo "tmux 既定表示へ復元しました"
fi
}
ACTION=""
PROJECT_SCOPE=0
for arg in "$@"; do
case "$arg" in
--install) ACTION="install" ;;
--uninstall) ACTION="uninstall" ;;
--project) PROJECT_SCOPE=1 ;;
--help|-h) usage; exit 0 ;;
*) echo "不明な引数: $arg" >&2; usage; exit 1 ;;
esac
done
case "$ACTION" in
install)
install_hooks
install_tmux
echo "完了: cc-tmux を有効化しました。"
;;
uninstall)
uninstall_hooks
uninstall_tmux
echo "完了: cc-tmux を無効化しました。"
;;
*)
usage; exit 1 ;;
esac