This repository has been archived on 2026-06-22. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
lnbits-sensei/modules/dev-env/scripts/tmux-launch.sh
Padreug e38d313db2 feat(dev-env): backport matured dev-env implementation from /etc/nixos
Replace the stub dev-env with the real, working implementation that grew
in the reference machine config — de-identified for the public scaffold.

Nix layer:
- options.nix: full project schema (url/upstream/fork/category/
  worktreeRoot/worktrees{branch,path,remote}/isClone/deployFlakeInput),
  deploy.targets, github.forkUser, writeDirenvHints. Drops the
  forgejo-URL block + deploy-flake auto-derivation (incoherent in a
  scaffold that uses explicit per-project urls).
- lib.nix: mkProject + worktreePath/bareRepoPath/projectRemotes,
  generalized to the explicit-url model (origin falls back to upstream).
- config.nix: renders /etc/dev-env/{config.sh,projects.json,
  tmux-sessions.json}, installs helpers via writeShellScriptBin, loads
  shell functions into interactive shells, wires the git pre-commit hook.

Scripts (config-driven, read /etc/dev-env at runtime):
- bootstrap.sh, nav.sh, worktree.sh, pr-helpers.sh, rebase.sh,
  status.sh, deploy.sh, regtest.sh, tmux-launch.sh.
- Stripped aiolabs/forgejo/bitspire/lamassu/webapp hardcoding; the
  github-fork remote is renamed 'fork' to match git.remotes vocabulary.
- Removes the dev.sh stub (the matured impl uses discrete commands +
  shell functions, not a unified 'dev' CLI).

presets/example.nix: a worked, generic project list replacing the
identity-specific aiolabs preset. tests/smoke.nix + flake checks
exercise the schema; 'nix flake check' is green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:18:49 +02:00

131 lines
4.2 KiB
Bash

#!/usr/bin/env bash
# dev-tm: launch a declared tmux session
#
# Reads /etc/dev-env/tmux-sessions.json (rendered by config.nix) and
# either attaches to an existing session or creates one with the
# declared windows. Window cwds are resolved relative to $DEV_ROOT.
#
# This is a single generic launcher; the window layouts come from Nix
# (or a runtime override at ~/.config/dev-env/tmux-sessions.json).
set -euo pipefail
if [[ -r /etc/dev-env/config.sh ]]; then
# shellcheck disable=SC1091
source /etc/dev-env/config.sh
fi
DEV_ROOT="${DEV_ROOT:-$HOME/dev}"
# Prefer a user override if present
SESSIONS_JSON=""
if [[ -r "$HOME/.config/dev-env/tmux-sessions.json" ]]; then
SESSIONS_JSON="$HOME/.config/dev-env/tmux-sessions.json"
elif [[ -r /etc/dev-env/tmux-sessions.json ]]; then
SESSIONS_JSON=/etc/dev-env/tmux-sessions.json
else
echo "No tmux-sessions.json found" >&2
exit 1
fi
usage() {
cat <<EOF
dev-tm — declarative tmux session launcher
USAGE:
dev-tm list available sessions
dev-tm <session> start or attach to <session>
dev-tm -k <session> kill session
dev-tm -k all kill all dev sessions
dev-tm -l list available sessions
EOF
}
list_sessions() {
echo "Defined sessions (from $SESSIONS_JSON):"
jq -r 'keys[]' "$SESSIONS_JSON" | sed 's/^/ /'
echo ""
echo "Active tmux sessions:"
tmux list-sessions 2>/dev/null | sed 's/^/ /' || echo " (none)"
}
resolve_path() {
local p="$1"
[[ -z "$p" || "$p" == "null" ]] && { echo "$DEV_ROOT"; return; }
[[ "$p" = /* ]] && { echo "$p"; return; }
echo "$DEV_ROOT/$p"
}
start_session() {
local name="$1"
local session_name="dev-$name"
if tmux has-session -t "$session_name" 2>/dev/null; then
tmux attach-session -t "$session_name"
return
fi
local session_cwd
session_cwd="$(resolve_path "$(jq -r --arg s "$name" '.[$s].cwd // empty' "$SESSIONS_JSON")")"
local nwindows
nwindows="$(jq --arg s "$name" '.[$s].windows | length' "$SESSIONS_JSON")"
if (( nwindows == 0 )); then
echo "Session '$name' has no windows defined" >&2
exit 1
fi
# First window
local first_name first_cwd first_cmd
first_name="$(jq -r --arg s "$name" '.[$s].windows[0].name' "$SESSIONS_JSON")"
first_cwd="$(resolve_path "$(jq -r --arg s "$name" '.[$s].windows[0].cwd // empty' "$SESSIONS_JSON")")"
first_cmd="$(jq -r --arg s "$name" '.[$s].windows[0].cmd // empty' "$SESSIONS_JSON")"
tmux new-session -d -s "$session_name" -n "$first_name" -c "$first_cwd"
[[ -n "$first_cmd" && "$first_cmd" != "null" ]] && \
tmux send-keys -t "$session_name:0" "$first_cmd" C-m
# Remaining windows
for ((i = 1; i < nwindows; i++)); do
local wn wcwd wcmd
wn="$(jq -r --arg s "$name" --argjson i "$i" '.[$s].windows[$i].name' "$SESSIONS_JSON")"
wcwd="$(resolve_path "$(jq -r --arg s "$name" --argjson i "$i" '.[$s].windows[$i].cwd // empty' "$SESSIONS_JSON")")"
wcmd="$(jq -r --arg s "$name" --argjson i "$i" '.[$s].windows[$i].cmd // empty' "$SESSIONS_JSON")"
tmux new-window -t "$session_name" -n "$wn" -c "$wcwd"
[[ -n "$wcmd" && "$wcmd" != "null" ]] && \
tmux send-keys -t "$session_name:$i" "$wcmd" C-m
done
tmux select-window -t "$session_name:0"
tmux attach-session -t "$session_name"
}
kill_session() {
local target="$1"
if [[ "$target" == "all" ]]; then
tmux list-sessions -F '#{session_name}' 2>/dev/null \
| grep '^dev-' \
| xargs -r -n1 tmux kill-session -t \
|| echo "No dev sessions to kill"
return
fi
tmux kill-session -t "dev-$target" 2>/dev/null || echo "Session 'dev-$target' not found"
}
# --- entry ---
case "${1:-}" in
-h|--help) usage ;;
-l|--list|"") list_sessions ;;
-k|--kill)
[[ -z "${2:-}" ]] && { echo "Usage: dev-tm -k <session|all>"; exit 1; }
kill_session "$2"
;;
*)
if ! jq -e --arg s "$1" 'has($s)' "$SESSIONS_JSON" >/dev/null; then
echo "Unknown session: $1" >&2
list_sessions
exit 1
fi
start_session "$1"
;;
esac