101 lines
3.6 KiB
Bash
Executable File
101 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
AGENT_NAME=${1:-${MOSAIC_AGENT_NAME:-}}
|
|
MOSAIC_TMUX_SOCKET=${MOSAIC_TMUX_SOCKET:-mosaic-factory}
|
|
MOSAIC_AGENT_RUNTIME=${MOSAIC_AGENT_RUNTIME:-pi}
|
|
MOSAIC_AGENT_WORKDIR=${MOSAIC_AGENT_WORKDIR:-$HOME}
|
|
MOSAIC_AGENT_COMMAND=${MOSAIC_AGENT_COMMAND:-}
|
|
|
|
if [ -z "$AGENT_NAME" ]; then
|
|
echo "ERROR: agent name argument or MOSAIC_AGENT_NAME is required" >&2
|
|
exit 64
|
|
fi
|
|
|
|
if ! command -v tmux >/dev/null 2>&1; then
|
|
echo "ERROR: tmux is required" >&2
|
|
exit 69
|
|
fi
|
|
|
|
if tmux -L "$MOSAIC_TMUX_SOCKET" has-session -t "=${AGENT_NAME}:0.0" 2>/dev/null; then
|
|
echo "Mosaic agent session already running: $AGENT_NAME on socket $MOSAIC_TMUX_SOCKET"
|
|
exit 0
|
|
fi
|
|
|
|
if [ -z "$MOSAIC_AGENT_COMMAND" ]; then
|
|
MOSAIC_AGENT_COMMAND="mosaic yolo $MOSAIC_AGENT_RUNTIME"
|
|
fi
|
|
|
|
# ── Derive a runtime-bin PATH prefix ─────────────────────────────────────────
|
|
# Precedence:
|
|
# 1. $MOSAIC_RUNTIME_BIN (explicit override)
|
|
# 2. $(npm config get prefix)/bin (if npm is on PATH)
|
|
# 3. Fallbacks: $HOME/.npm-global/bin and $HOME/.local/bin
|
|
#
|
|
# Only directories that already exist are included. The prefix is baked into
|
|
# the pane command regardless of what the LAUNCHER process's $PATH contains,
|
|
# because the tmux pane inherits the tmux SERVER environment (not this script's
|
|
# environment). A dir on the launcher's PATH may be absent from the server PATH,
|
|
# so every existing candidate must always be included. Dedup within the
|
|
# constructed prefix avoids listing the same dir twice.
|
|
_build_runtime_bin_prefix() {
|
|
local candidates=()
|
|
|
|
if [ -n "${MOSAIC_RUNTIME_BIN:-}" ]; then
|
|
candidates+=("$MOSAIC_RUNTIME_BIN")
|
|
fi
|
|
|
|
if command -v npm >/dev/null 2>&1; then
|
|
local npm_prefix
|
|
npm_prefix=$(npm config get prefix 2>/dev/null) || true
|
|
if [ -n "$npm_prefix" ]; then
|
|
candidates+=("${npm_prefix}/bin")
|
|
fi
|
|
fi
|
|
|
|
candidates+=("$HOME/.npm-global/bin")
|
|
candidates+=("$HOME/.local/bin")
|
|
|
|
local prefix=""
|
|
for dir in "${candidates[@]}"; do
|
|
[ -d "$dir" ] || continue
|
|
if [ -z "$prefix" ]; then
|
|
prefix="$dir"
|
|
else
|
|
case ":${prefix}:" in
|
|
*":${dir}:"*) ;; # already in our prefix — skip
|
|
*) prefix="${prefix}:${dir}" ;;
|
|
esac
|
|
fi
|
|
done
|
|
|
|
printf '%s' "$prefix"
|
|
}
|
|
|
|
MOSAIC_RUNTIME_BIN_PREFIX=$(_build_runtime_bin_prefix)
|
|
|
|
# ── Build the pane command ────────────────────────────────────────────────────
|
|
# The pane command must:
|
|
# - Export the augmented PATH so the runtime binary is found.
|
|
# - exec the agent command so the runtime is the pane's foreground process
|
|
# (makes `fleet ps` pane_current_command check reliable; no DRIFT false-positive).
|
|
#
|
|
# Quoting strategy: single-quote the inner shell snippet so that variable
|
|
# references in MOSAIC_AGENT_COMMAND are NOT expanded here — they expand inside
|
|
# the pane shell. However, MOSAIC_RUNTIME_BIN_PREFIX and PATH must be expanded
|
|
# NOW (in this script) because the pane shell inherits the tmux server
|
|
# environment, not this script's env.
|
|
#
|
|
# We build the snippet as a double-quoted here-string embedded in a printf call
|
|
# to avoid nested quoting problems.
|
|
|
|
if [ -n "$MOSAIC_RUNTIME_BIN_PREFIX" ]; then
|
|
PANE_SHELL_SNIPPET="export PATH=\"${MOSAIC_RUNTIME_BIN_PREFIX}:\${PATH}\"; exec ${MOSAIC_AGENT_COMMAND}"
|
|
else
|
|
PANE_SHELL_SNIPPET="exec ${MOSAIC_AGENT_COMMAND}"
|
|
fi
|
|
|
|
mkdir -p "$MOSAIC_AGENT_WORKDIR"
|
|
exec tmux -L "$MOSAIC_TMUX_SOCKET" new-session -d -s "$AGENT_NAME" -c "$MOSAIC_AGENT_WORKDIR" \
|
|
bash -c "$PANE_SHELL_SNIPPET"
|