mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
224 lines
No EOL
7.9 KiB
Bash
Executable file
224 lines
No EOL
7.9 KiB
Bash
Executable file
#!/bin/bash
|
|
# VibeTunnel CLI wrapper
|
|
|
|
# First, find the VibeTunnel app location
|
|
# Try standard locations first, but verify the binary exists
|
|
APP_PATH=""
|
|
for TRY_PATH in "/Applications/VibeTunnel.app" "$HOME/Applications/VibeTunnel.app"; do
|
|
if [ -d "$TRY_PATH" ] && [ -f "$TRY_PATH/Contents/Resources/vibetunnel" ]; then
|
|
APP_PATH="$TRY_PATH"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# If not found in standard locations with valid binary, search for it
|
|
if [ -z "$APP_PATH" ]; then
|
|
# First try DerivedData (for development)
|
|
for CANDIDATE in $(find ~/Library/Developer/Xcode/DerivedData -name "VibeTunnel.app" -type d 2>/dev/null | grep -v "\.dSYM" | grep -v "Index\.noindex"); do
|
|
if [ -f "$CANDIDATE/Contents/Resources/vibetunnel" ]; then
|
|
APP_PATH="$CANDIDATE"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# If still not found, use mdfind as last resort
|
|
if [ -z "$APP_PATH" ]; then
|
|
for CANDIDATE in $(mdfind -name "VibeTunnel.app" 2>/dev/null | grep -v "\.dSYM"); do
|
|
if [ -f "$CANDIDATE/Contents/Resources/vibetunnel" ]; then
|
|
APP_PATH="$CANDIDATE"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ -z "$APP_PATH" ]; then
|
|
echo "Error: VibeTunnel.app with vibetunnel binary not found anywhere on the system" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Execute vibetunnel from app bundle
|
|
VIBETUNNEL_BIN="$APP_PATH/Contents/Resources/vibetunnel"
|
|
if [ ! -f "$VIBETUNNEL_BIN" ]; then
|
|
echo "Error: vibetunnel binary not found in app bundle at $VIBETUNNEL_BIN" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Check if we're already inside a VibeTunnel session
|
|
if [ -n "$VIBETUNNEL_SESSION_ID" ]; then
|
|
# Special case: handle 'vt title' command inside a session
|
|
if [[ "$1" == "title" ]]; then
|
|
if [[ $# -lt 2 ]]; then
|
|
echo "Error: 'vt title' requires a title argument" >&2
|
|
echo "Usage: vt title <new title>" >&2
|
|
exit 1
|
|
fi
|
|
shift # Remove 'title' from arguments
|
|
TITLE="$*" # Get all remaining arguments as the title
|
|
|
|
# Use the vibetunnel binary's new --update-title flag
|
|
exec "$VIBETUNNEL_BIN" fwd --update-title "$TITLE" --session-id "$VIBETUNNEL_SESSION_ID"
|
|
# If exec fails, exit with error
|
|
exit 1
|
|
fi
|
|
|
|
echo "Error: Already inside a VibeTunnel session (ID: $VIBETUNNEL_SESSION_ID). Recursive VibeTunnel sessions are not supported." >&2
|
|
echo "If you need to run commands, use them directly without the 'vt' prefix." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Function to show help
|
|
show_help() {
|
|
cat << 'EOF'
|
|
vt - VibeTunnel TTY Forward Wrapper
|
|
|
|
USAGE:
|
|
vt [command] [args...]
|
|
vt --shell [args...]
|
|
vt -i [args...]
|
|
vt --no-shell-wrap [command] [args...]
|
|
vt -S [command] [args...]
|
|
vt title <new title> # Inside a VibeTunnel session only
|
|
vt --help
|
|
|
|
DESCRIPTION:
|
|
This wrapper script allows VibeTunnel to see the output of commands by
|
|
forwarding TTY data through the vibetunnel utility. When you run commands
|
|
through 'vt', VibeTunnel can monitor and display the command's output
|
|
in real-time.
|
|
|
|
By default, commands are executed through your shell to resolve aliases,
|
|
functions, and builtins. Use --no-shell-wrap to execute commands directly.
|
|
|
|
Inside a VibeTunnel session, use 'vt title' to update the session name.
|
|
|
|
EXAMPLES:
|
|
vt top # Watch top with VibeTunnel monitoring
|
|
vt python script.py # Run Python script with output forwarding
|
|
vt npm test # Run tests with VibeTunnel visibility
|
|
vt --shell # Launch current shell (equivalent to vt $SHELL)
|
|
vt -i # Launch current shell (short form)
|
|
vt -S ls -la # List files without shell alias resolution
|
|
vt title "My Project" # Update session title (inside session only)
|
|
|
|
OPTIONS:
|
|
--shell, -i Launch current shell (equivalent to vt $SHELL)
|
|
--no-shell-wrap, -S Execute command directly without shell wrapper
|
|
--title-mode <mode> Terminal title mode (none, filter, static, dynamic)
|
|
Default: none (dynamic for claude)
|
|
--help, -h Show this help message and exit
|
|
|
|
TITLE MODES:
|
|
none No title management - apps control their own titles
|
|
filter Block all title changes from applications
|
|
static Show working directory and command in title
|
|
dynamic Show directory, command, and live activity status (default for web UI)
|
|
|
|
NOTE:
|
|
This script automatically uses the vibetunnel executable bundled with
|
|
VibeTunnel from the app bundle.
|
|
EOF
|
|
|
|
# Show path and version info
|
|
echo
|
|
echo "VIBETUNNEL BINARY:"
|
|
echo " Path: $VIBETUNNEL_BIN"
|
|
if [ -f "$VIBETUNNEL_BIN" ]; then
|
|
# Extract version from the vibetunnel output
|
|
VERSION_INFO=$("$VIBETUNNEL_BIN" --version 2>&1 | grep "^VibeTunnel Server" | head -n 1)
|
|
BUILD_INFO=$("$VIBETUNNEL_BIN" --version 2>&1 | grep "^Built:" | head -n 1)
|
|
PLATFORM_INFO=$("$VIBETUNNEL_BIN" --version 2>&1 | grep "^Platform:" | head -n 1)
|
|
|
|
if [ -n "$VERSION_INFO" ]; then
|
|
echo " Version: ${VERSION_INFO#VibeTunnel Server }"
|
|
fi
|
|
if [ -n "$BUILD_INFO" ]; then
|
|
echo " ${BUILD_INFO}"
|
|
fi
|
|
if [ -n "$PLATFORM_INFO" ]; then
|
|
echo " ${PLATFORM_INFO}"
|
|
fi
|
|
else
|
|
echo " Status: Not found"
|
|
fi
|
|
}
|
|
|
|
# Function to resolve command through user's shell
|
|
resolve_command() {
|
|
local user_shell="${SHELL:-/bin/bash}"
|
|
local cmd="$1"
|
|
shift
|
|
|
|
local shell_name=$(basename "$user_shell")
|
|
|
|
# Always try through shell first to handle aliases, functions, and builtins
|
|
# The shell will fall back to PATH lookup if no alias/function exists
|
|
case "$shell_name" in
|
|
zsh)
|
|
# For zsh, we need interactive mode to get aliases
|
|
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$user_shell" -i -c "$(printf '%q ' "$cmd" "$@")"
|
|
;;
|
|
bash)
|
|
# For bash, expand aliases in non-interactive mode
|
|
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$user_shell" -c "shopt -s expand_aliases; source ~/.bashrc 2>/dev/null || source ~/.bash_profile 2>/dev/null || true; $(printf '%q ' "$cmd" "$@")"
|
|
;;
|
|
*)
|
|
# Generic shell handling
|
|
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$user_shell" -c "$(printf '%q ' "$cmd" "$@")"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Handle --help or -h option, or no arguments (show help)
|
|
if [[ $# -eq 0 || "$1" == "--help" || "$1" == "-h" ]]; then
|
|
show_help
|
|
exit 0
|
|
fi
|
|
|
|
# Handle 'vt title' command when not inside a session
|
|
if [[ "$1" == "title" ]]; then
|
|
echo "Error: 'vt title' can only be used inside a VibeTunnel session." >&2
|
|
echo "Start a session first with 'vt' or 'vt <command>'" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Handle --shell or -i option (launch current shell)
|
|
if [[ "$1" == "--shell" || "$1" == "-i" ]]; then
|
|
shift
|
|
# Execute current shell through vibetunnel
|
|
exec "$0" "${SHELL:-/bin/bash}" "$@"
|
|
fi
|
|
|
|
# Handle --no-shell-wrap or -S option
|
|
NO_SHELL_WRAP=false
|
|
if [[ "$1" == "--no-shell-wrap" || "$1" == "-S" ]]; then
|
|
NO_SHELL_WRAP=true
|
|
shift
|
|
fi
|
|
|
|
# Handle --title-mode option
|
|
TITLE_MODE_ARGS=""
|
|
if [[ "$1" == "--title-mode" && $# -gt 1 ]]; then
|
|
TITLE_MODE_ARGS="--title-mode $2"
|
|
shift 2
|
|
fi
|
|
|
|
# Check if we have arguments and if the first argument is not an option
|
|
if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
|
|
if [[ "$NO_SHELL_WRAP" == "true" ]]; then
|
|
# Execute directly without shell wrapper
|
|
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$@"
|
|
else
|
|
# Check if the first argument is a real binary
|
|
if which "$1" >/dev/null 2>&1; then
|
|
# It's a real binary, execute directly
|
|
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$@"
|
|
else
|
|
# Not a real binary, try alias resolution
|
|
resolve_command "$@"
|
|
fi
|
|
fi
|
|
else
|
|
# Run with fwd command (original behavior for options)
|
|
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$@"
|
|
fi |