diff options
| author | yyamashita <yyamashita@hetzner.yyamashita.com> | 2026-05-17 11:02:19 +0900 |
|---|---|---|
| committer | yyamashita <yyamashita@hetzner.yyamashita.com> | 2026-05-17 11:02:42 +0900 |
| commit | b836174d5ad5e4ea36a5f456061a00862317375f (patch) | |
| tree | 96dab7747ccf0ca42b2f408f1fc74e34bf41fe0e /scripts/sync-claude-services.sh | |
| parent | e3ac39aeeb17ae97949b2e69969f1ce8a364b343 (diff) | |
Add Claude Code session management via post-receive hook
Root's post-receive hook now calls scripts/sync-claude-services.sh to
manage yyamashita's systemd user services on git push. Sessions are
configured in claude-code-sessions.txt (user:repo format).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'scripts/sync-claude-services.sh')
| -rwxr-xr-x | scripts/sync-claude-services.sh | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/scripts/sync-claude-services.sh b/scripts/sync-claude-services.sh new file mode 100755 index 0000000..a9a76fb --- /dev/null +++ b/scripts/sync-claude-services.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# サーバー側で root として実行し、各ユーザーの Claude Code systemd user service を同期する +set -euo pipefail + +APP_DIR="$(cd "$(dirname "$0")/.." && pwd)" +TEMPLATE_SRC="$APP_DIR/systemd/user/claude-code@.service" +SESSIONS_FILE="$APP_DIR/claude-code-sessions.txt" + +# sessions.txt をパースして user -> repos のマップを構築 +declare -A user_repos + +while IFS= read -r line; do + [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue + user="${line%%:*}" + repo="${line#*:}" + user_repos["$user"]+=" $repo" +done < "$SESSIONS_FILE" + +for user in "${!user_repos[@]}"; do + uid=$(id -u "$user" 2>/dev/null) || { echo "WARNING: user $user not found, skipping"; continue; } + runtime_dir="/run/user/$uid" + systemd_dir="/home/$user/.config/systemd/user" + + mkdir -p "$systemd_dir" + chown "$user:$user" "$systemd_dir" + + # テンプレートを更新(差分があれば) + if ! diff -q "$TEMPLATE_SRC" "$systemd_dir/claude-code@.service" >/dev/null 2>&1; then + echo "[$user] Updating claude-code@.service template" + cp "$TEMPLATE_SRC" "$systemd_dir/claude-code@.service" + chown "$user:$user" "$systemd_dir/claude-code@.service" + runuser -u "$user" -- env XDG_RUNTIME_DIR="$runtime_dir" DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \ + systemctl --user daemon-reload + fi + + # sessions.txt で指定されたリポジトリを enable & start + desired=() + for repo in ${user_repos[$user]}; do + [[ -z "$repo" ]] && continue + desired+=("$repo") + repo_path="/home/$user/workspaces/repos/$repo" + if [[ ! -d "$repo_path" ]]; then + echo "[$user] WARNING: $repo_path not found, skipping $repo" + continue + fi + runuser -u "$user" -- env XDG_RUNTIME_DIR="$runtime_dir" DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \ + systemctl --user enable "claude-code@${repo}.service" 2>/dev/null || true + if ! runuser -u "$user" -- env XDG_RUNTIME_DIR="$runtime_dir" DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \ + systemctl --user is-active "claude-code@${repo}.service" >/dev/null 2>&1; then + echo "[$user] Starting claude-code@${repo}.service" + runuser -u "$user" -- env XDG_RUNTIME_DIR="$runtime_dir" DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \ + systemctl --user start "claude-code@${repo}.service" || true + fi + done + + # sessions.txt にないが enabled になっているインスタンスを無効化 + while IFS= read -r unit; do + instance="${unit#claude-code@}" + instance="${instance%.service}" + if ! printf '%s\n' "${desired[@]}" | grep -qx "$instance"; then + echo "[$user] Disabling claude-code@${instance}.service (not in sessions.txt)" + runuser -u "$user" -- env XDG_RUNTIME_DIR="$runtime_dir" DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \ + systemctl --user disable --now "claude-code@${instance}.service" || true + fi + done < <(runuser -u "$user" -- env XDG_RUNTIME_DIR="$runtime_dir" DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \ + systemctl --user list-unit-files --plain --no-legend 'claude-code@*.service' 2>/dev/null \ + | awk '$2 == "enabled" {print $1}') +done + +echo "Claude Code session sync complete." |
