-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathtmux-assistant-resurrect.tmux
More file actions
executable file
·119 lines (102 loc) · 5.23 KB
/
tmux-assistant-resurrect.tmux
File metadata and controls
executable file
·119 lines (102 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env bash
# TPM plugin entry point for tmux-assistant-resurrect.
# TPM executes this script when the plugin is installed or tmux starts.
#
# This sets up:
# 1. tmux-resurrect + tmux-continuum settings
# 2. Post-save/restore hooks for assistant session tracking
# 3. Claude Code hooks in ~/.claude/settings.json
# 4. OpenCode session-tracker plugin in ~/.config/opencode/plugins/
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Limitation: hook commands use single-quoted paths (bash '${CURRENT_DIR}/...').
# If the plugin install path contains a single quote, the quoting breaks.
# This is unlikely in practice (TPM installs to ~/.tmux/plugins/).
# --- tmux settings ---
# Do NOT set @resurrect-capture-pane-contents here — that is the user's choice.
# If it is enabled, the post-save hook strips captured content for assistant panes
# (see strip_assistant_pane_contents in save-assistant-sessions.sh) so restore
# won't briefly flash stale TUI output before the assistant is resumed.
#
# Do NOT add assistants to @resurrect-processes — that would launch bare
# binaries (without session IDs) and the post-restore hook would then type
# resume commands into the running TUI. The hook handles all resuming.
tmux set-option -g @resurrect-hook-post-save-all "bash '${CURRENT_DIR}/scripts/save-assistant-sessions.sh'"
tmux set-option -g @resurrect-hook-post-restore-all "bash '${CURRENT_DIR}/scripts/restore-assistant-sessions.sh'"
# Respect user's @continuum-save-interval if already set
if [ -z "$(tmux show-option -gqv @continuum-save-interval)" ]; then
tmux set-option -g @continuum-save-interval '5'
fi
tmux set-option -g @continuum-restore 'on'
# --- Claude Code hooks ---
install_claude_hooks() {
local settings="$HOME/.claude/settings.json"
local track_cmd="bash '${CURRENT_DIR}/hooks/claude-session-track.sh'"
local cleanup_cmd="bash '${CURRENT_DIR}/hooks/claude-session-cleanup.sh'"
# Ensure file exists
if [ ! -f "$settings" ]; then
mkdir -p "$(dirname "$settings")"
echo '{}' > "$settings"
fi
# Skip if jq not available
if ! command -v jq >/dev/null 2>&1; then
return
fi
# Install SessionStart hook, refreshing stale paths if any exist.
# Skip only when the current command is present AND no stale copies remain.
local has_current_track has_stale_track
has_current_track=$(jq --arg cmd "$track_cmd" '[.hooks.SessionStart[]?.hooks[]? | select((.command // "") == $cmd)] | length' "$settings" 2>/dev/null || echo 0)
has_stale_track=$(jq --arg cmd "$track_cmd" '[.hooks.SessionStart[]?.hooks[]? | select(((.command // "") | contains("claude-session-track")) and ((.command // "") != $cmd))] | length' "$settings" 2>/dev/null || echo 0)
if [ "$has_current_track" = "0" ] || [ "$has_stale_track" != "0" ]; then
local tmp
tmp=$(mktemp)
jq --arg cmd "$track_cmd" '
.hooks //= {} |
.hooks.SessionStart //= [] |
# Drop any prior instance of this hook (different paths included).
.hooks.SessionStart |= map(
.hooks = ((.hooks // []) | map(select((.command // "") | contains("claude-session-track") | not)))
) |
# Drop entries whose hooks list became empty after the filter.
.hooks.SessionStart |= map(select((.hooks // []) | length > 0)) |
.hooks.SessionStart += [{
"matcher": "",
"hooks": [{"type": "command", "command": $cmd}]
}]
' "$settings" > "$tmp" && mv "$tmp" "$settings"
fi
# Install SessionEnd hook (same self-healing pattern as SessionStart).
local has_current_cleanup has_stale_cleanup
has_current_cleanup=$(jq --arg cmd "$cleanup_cmd" '[.hooks.SessionEnd[]?.hooks[]? | select((.command // "") == $cmd)] | length' "$settings" 2>/dev/null || echo 0)
has_stale_cleanup=$(jq --arg cmd "$cleanup_cmd" '[.hooks.SessionEnd[]?.hooks[]? | select(((.command // "") | contains("claude-session-cleanup")) and ((.command // "") != $cmd))] | length' "$settings" 2>/dev/null || echo 0)
if [ "$has_current_cleanup" = "0" ] || [ "$has_stale_cleanup" != "0" ]; then
local tmp
tmp=$(mktemp)
jq --arg cmd "$cleanup_cmd" '
.hooks //= {} |
.hooks.SessionEnd //= [] |
.hooks.SessionEnd |= map(
.hooks = ((.hooks // []) | map(select((.command // "") | contains("claude-session-cleanup") | not)))
) |
.hooks.SessionEnd |= map(select((.hooks // []) | length > 0)) |
.hooks.SessionEnd += [{
"matcher": "",
"hooks": [{"type": "command", "command": $cmd}]
}]
' "$settings" > "$tmp" && mv "$tmp" "$settings"
fi
}
# --- OpenCode plugin ---
install_opencode_plugin() {
local plugin_dir="$HOME/.config/opencode/plugins"
local plugin_file="$plugin_dir/session-tracker.js"
local source_file="${CURRENT_DIR}/hooks/opencode-session-track.js"
mkdir -p "$plugin_dir"
# Only update if not already correctly linked
if [ -L "$plugin_file" ] && [ "$(readlink "$plugin_file")" = "$source_file" ]; then
return
fi
ln -sf "$source_file" "$plugin_file"
}
# --- Run assistant hook installation ---
install_claude_hooks
install_opencode_plugin