feat(bin): add new scripts for managing Claude profiles and sessions.

This commit is contained in:
David Ibia
2025-11-09 14:09:30 +01:00
parent eb766854e0
commit e34f495368
4 changed files with 206 additions and 0 deletions

2
.local/bin/brave-debug Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
/Applications/Brave\ Browser.app/Contents/MacOS/Brave\ Browser --remote-debugging-port=9222 --user-data-dir=/tmp/brave-debug "$@"

15
.local/bin/cl Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
function usecl() {
# Inside tmux: launch Claude with the session's profile
if [[ -n "${TMUX:-}" ]]; then
~/.local/bin/claude-tmux run "$@"
else
# Not in tmux: pick or create a session, attach, and launch Claude there
~/.local/bin/claude-tmux pick
fi
}
usecl "$@"

173
.local/bin/claude-tmux Executable file
View File

@@ -0,0 +1,173 @@
#!/usr/bin/env bash
# tmux-aware Claude profile helper
# Works in bash/zsh. No external deps except optional fzf and tmux.
set -euo pipefail
# Optional: set a directory to copy as a template when new profiles are created.
# Default: if ~/.claude exists it will be copied; otherwise create an empty dir.
CLAUDE_TEMPLATE_DIR="${CLAUDE_TEMPLATE_DIR:-}"
bin_exists() { command -v "$1" >/dev/null 2>&1; }
tmux_session_name() {
if [[ -n "${TMUX:-}" ]] && bin_exists tmux; then
tmux display-message -p '#S'
else
printf ''
fi
}
sanitize_session() {
# lowercase, spaces->-, keep alnum . _ : -
printf '%s' "$1" \
| tr '[:upper:] ' '[:lower:]-' \
| tr -cd '[:alnum:]._:-'
}
profile_dir_for_session() {
local s="$1"
case "$s" in
""|"default"|"personal"|"main") printf '%s\n' "$HOME/.claude" ;;
*) printf '%s\n' "$HOME/.claude-$(sanitize_session "$s")" ;;
esac
}
ensure_profile_dir() {
local dir="$1"
if [[ -d "$dir" ]]; then
return 0
fi
mkdir -p "$dir"
# Copy from template if provided, else from ~/.claude if present
local from="${CLAUDE_TEMPLATE_DIR:-}"
if [[ -z "$from" && -d "$HOME/.claude" ]]; then
from="$HOME/.claude"
fi
if [[ -n "$from" && -d "$from" ]]; then
# Copy only if empty
if [[ -z "$(ls -A "$dir")" ]]; then
cp -a "$from"/. "$dir"/
fi
fi
}
run_claude_with_profile() {
local dir="$1"; shift || true
if ! bin_exists claude; then
printf 'claude-tmux: "claude" binary not found in PATH\n' >&2
exit 127
fi
ensure_profile_dir "$dir"
CLAUDE_CONFIG_DIR="$dir" command claude "$@"
}
fzf_pick_session() {
local list new_label sel
if ! bin_exists tmux; then
printf 'claude-tmux: tmux not installed\n' >&2
return 1
fi
new_label="[new session]"
# Gather sessions, newest first
list="$(tmux list-sessions -F '#{session_last_attached} #{session_name}' 2>/dev/null \
| sort -rn | awk '{ $1=""; sub(/^ /,""); print }')"
if bin_exists fzf; then
sel="$(printf '%s\n%s\n' "$new_label" "$list" | fzf --prompt='tmux session > ' --height=40% --reverse)"
else
printf '%s\n%s\n' "$new_label" "$list"
printf 'Pick a session (type exact name or "%s"): ' "$new_label" >&2
read -r sel
fi
printf '%s' "$sel"
}
create_and_launch_in_session() {
local name="$1" dir cmd
dir="$(profile_dir_for_session "$name")"
ensure_profile_dir "$dir"
# Start a session running Claude with the sessions profile
cmd="CLAUDE_CONFIG_DIR='${dir}' claude"
if tmux has-session -t "$name" 2>/dev/null; then
# Session exists: send keys and attach
tmux send-keys -t "$name" "$cmd" C-m
exec tmux attach -t "$name"
else
exec tmux new-session -s "$name" "$cmd"
fi
}
attach_and_launch_in_existing_session() {
local name="$1" dir cmd
dir="$(profile_dir_for_session "$name")"
ensure_profile_dir "$dir"
cmd="CLAUDE_CONFIG_DIR='${dir}' claude"
tmux send-keys -t "$name" "$cmd" C-m
exec tmux attach -t "$name"
}
# Subcommands:
# ensure <session> ensure profile dir exists for session
# dir <session> print profile dir for session
# run [args...] run claude for current tmux session (inside tmux)
# pick fzf picker to choose or create a session and launch claude
# hook-ensure #{session_name} for tmux hooks
case "${1:-}" in
ensure)
shift; sess="${1:-}"
if [[ -z "$sess" ]]; then printf 'usage: claude-tmux ensure <session>\n' >&2; exit 2; fi
ensure_profile_dir "$(profile_dir_for_session "$sess")"
;;
dir)
shift; sess="${1:-}"
if [[ -z "$sess" ]]; then printf 'usage: claude-tmux dir <session>\n' >&2; exit 2; fi
profile_dir_for_session "$sess"
;;
run)
shift
sess="$(tmux_session_name)"
if [[ -z "$sess" ]]; then
printf 'claude-tmux: not inside tmux. Use "claude-tmux pick" or run inside a session.\n' >&2
exit 2
fi
run_claude_with_profile "$(profile_dir_for_session "$sess")" "$@"
;;
pick)
shift
sel="$(fzf_pick_session)"
if [[ -z "$sel" ]]; then exit 130; fi
if [[ "$sel" == "[new session]" ]]; then
printf 'New tmux session name: ' >&2
read -r newname
if [[ -z "$newname" ]]; then printf 'Empty name. Aborting.\n' >&2; exit 2; fi
create_and_launch_in_session "$newname"
else
attach_and_launch_in_existing_session "$sel"
fi
;;
hook-ensure)
# For tmux hooks like session-created / session-renamed
shift
sess="${1:-}"
if [[ -n "$sess" ]]; then
ensure_profile_dir "$(profile_dir_for_session "$sess")"
fi
;;
*)
cat <<'EOF'
claude-tmux: tmux-aware Claude profile helper
Usage:
claude-tmux run Run Claude for the current tmux session
claude-tmux pick Pick or create a tmux session with fzf, launch Claude, attach
claude-tmux ensure <session> Ensure a Claude profile exists for <session>
claude-tmux dir <session> Print the Claude profile dir for <session>
claude-tmux hook-ensure <name> For tmux hooks (session-created / session-renamed)
Env:
CLAUDE_TEMPLATE_DIR Directory to copy into new profiles (optional)
EOF
;;
esac

16
.local/bin/cldir Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
function usecldir() {
# Optional convenience: quickly print the profile dir for this session
if [[ -n "${TMUX:-}" ]]; then
local s
s="$(tmux display-message -p '#S')"
~/.local/bin/claude-tmux dir "$s"
else
echo "$HOME/.claude"
fi
}
usecldir "$@"