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>
This commit is contained in:
parent
773632562e
commit
e38d313db2
17 changed files with 2925 additions and 147 deletions
131
modules/dev-env/scripts/tmux-launch.sh
Normal file
131
modules/dev-env/scripts/tmux-launch.sh
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#!/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
|
||||
Reference in a new issue