mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
Add new vt binary that supports both rust and go
This commit is contained in:
parent
ae270d66f8
commit
943410fc1c
7 changed files with 346 additions and 190 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -105,3 +105,9 @@ Workspace.xcworkspace/
|
||||||
|
|
||||||
# Sparkle private keys - NEVER commit these
|
# Sparkle private keys - NEVER commit these
|
||||||
private/
|
private/
|
||||||
|
|
||||||
|
# Built binaries (should be built during build process)
|
||||||
|
linux/vibetunnel
|
||||||
|
linux/vt
|
||||||
|
VibeTunnel/Resources/vt
|
||||||
|
VibeTunnel/Resources/vibetunnel
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@
|
||||||
B2C3D4E5F6A7B8C9D0E1F234 /* Build Web Frontend */,
|
B2C3D4E5F6A7B8C9D0E1F234 /* Build Web Frontend */,
|
||||||
A189466CB0AD49BEBE16B954 /* Build tty-fwd Universal Binary */,
|
A189466CB0AD49BEBE16B954 /* Build tty-fwd Universal Binary */,
|
||||||
C2D3E4F5A6B7C8D9E0F1A234 /* Build Go vibetunnel Universal Binary */,
|
C2D3E4F5A6B7C8D9E0F1A234 /* Build Go vibetunnel Universal Binary */,
|
||||||
|
D3E4F5A6B7C8D9E0F1A2B345 /* Build VT Universal Binary */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
|
@ -283,6 +284,29 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "# Build Go vibetunnel universal binary\necho \"Building Go vibetunnel universal binary...\"\n\n# Get the project directory\nPROJECT_DIR=\"${SRCROOT}\"\nLINUX_DIR=\"${PROJECT_DIR}/linux\"\nBUILD_SCRIPT=\"${LINUX_DIR}/build-universal.sh\"\n\n# Source Go environment\n[ -f \"$HOME/.profile\" ] && . \"$HOME/.profile\"\n[ -f \"$HOME/.zprofile\" ] && . \"$HOME/.zprofile\"\n\n# Check if go is available\nif ! command -v go &> /dev/null; then\n echo \"warning: go could not be found in PATH. Skipping Go binary build.\"\n echo \"PATH is: $PATH\"\n echo \"To enable Go server support, please install Go and ensure it's in your PATH\"\n # Create a dummy file so the build doesn't fail\n mkdir -p \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources\"\n touch \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/vibetunnel.disabled\"\n exit 0\nfi\n\nSOURCE_BINARY=\"${LINUX_DIR}/build/vibetunnel-universal\"\nDEST_BINARY=\"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/vibetunnel\"\n\n# Check if build script exists\nif [ ! -f \"${BUILD_SCRIPT}\" ]; then\n echo \"error: Build script not found at ${BUILD_SCRIPT}\"\n exit 1\nfi\n\n# Make build script executable\nchmod +x \"${BUILD_SCRIPT}\"\n\n# Change to linux directory and run build\ncd \"${LINUX_DIR}\"\n./build-universal.sh\n\n# Check if build succeeded\nif [ ! -f \"${SOURCE_BINARY}\" ]; then\n echo \"error: Universal binary not found at ${SOURCE_BINARY}\"\n exit 1\nfi\n\n# Create Resources directory if it doesn't exist\nmkdir -p \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources\"\n\n# Copy the binary\ncp \"${SOURCE_BINARY}\" \"${DEST_BINARY}\"\nchmod +x \"${DEST_BINARY}\"\n\n# Sign the binary\necho \"Signing Go vibetunnel binary...\"\ncodesign --force --sign - \"${DEST_BINARY}\"\n\necho \"Go vibetunnel universal binary copied and signed to ${DEST_BINARY}\"\n";
|
shellScript = "# Build Go vibetunnel universal binary\necho \"Building Go vibetunnel universal binary...\"\n\n# Get the project directory\nPROJECT_DIR=\"${SRCROOT}\"\nLINUX_DIR=\"${PROJECT_DIR}/linux\"\nBUILD_SCRIPT=\"${LINUX_DIR}/build-universal.sh\"\n\n# Source Go environment\n[ -f \"$HOME/.profile\" ] && . \"$HOME/.profile\"\n[ -f \"$HOME/.zprofile\" ] && . \"$HOME/.zprofile\"\n\n# Check if go is available\nif ! command -v go &> /dev/null; then\n echo \"warning: go could not be found in PATH. Skipping Go binary build.\"\n echo \"PATH is: $PATH\"\n echo \"To enable Go server support, please install Go and ensure it's in your PATH\"\n # Create a dummy file so the build doesn't fail\n mkdir -p \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources\"\n touch \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/vibetunnel.disabled\"\n exit 0\nfi\n\nSOURCE_BINARY=\"${LINUX_DIR}/build/vibetunnel-universal\"\nDEST_BINARY=\"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/vibetunnel\"\n\n# Check if build script exists\nif [ ! -f \"${BUILD_SCRIPT}\" ]; then\n echo \"error: Build script not found at ${BUILD_SCRIPT}\"\n exit 1\nfi\n\n# Make build script executable\nchmod +x \"${BUILD_SCRIPT}\"\n\n# Change to linux directory and run build\ncd \"${LINUX_DIR}\"\n./build-universal.sh\n\n# Check if build succeeded\nif [ ! -f \"${SOURCE_BINARY}\" ]; then\n echo \"error: Universal binary not found at ${SOURCE_BINARY}\"\n exit 1\nfi\n\n# Create Resources directory if it doesn't exist\nmkdir -p \"${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources\"\n\n# Copy the binary\ncp \"${SOURCE_BINARY}\" \"${DEST_BINARY}\"\nchmod +x \"${DEST_BINARY}\"\n\n# Sign the binary\necho \"Signing Go vibetunnel binary...\"\ncodesign --force --sign - \"${DEST_BINARY}\"\n\necho \"Go vibetunnel universal binary copied and signed to ${DEST_BINARY}\"\n";
|
||||||
};
|
};
|
||||||
|
D3E4F5A6B7C8D9E0F1A2B345 /* Build VT Universal Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"$(SRCROOT)/linux/cmd/vt/main.go",
|
||||||
|
"$(SRCROOT)/linux/go.mod",
|
||||||
|
"$(SRCROOT)/linux/build-vt-universal.sh",
|
||||||
|
);
|
||||||
|
name = "Build VT Universal Binary";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(BUILT_PRODUCTS_DIR)/$(CONTENTS_FOLDER_PATH)/Resources/vt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "#!/bin/bash\nset -e\n\necho \"Building VT universal binary...\"\n\n# Get the project directory\nPROJECT_DIR=\"${SRCROOT}\"\nLINUX_DIR=\"${PROJECT_DIR}/linux\"\n\n# Source Go environment\n[ -f \"$HOME/.profile\" ] && . \"$HOME/.profile\"\n[ -f \"$HOME/.zprofile\" ] && . \"$HOME/.zprofile\"\n\n# Check if go is available\nif ! command -v go &> /dev/null; then\n echo \"warning: go could not be found in PATH. Skipping VT binary build.\"\n echo \"PATH is: $PATH\"\n echo \"To enable VT CLI support, please install Go and ensure it's in your PATH\"\n # Don't fail the build, just skip VT\n exit 0\nfi\n\n# Build the VT binary\ncd \"$LINUX_DIR\"\n./build-vt-universal.sh \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/vt\"\n\n# Sign the binary\nif [ -f \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/vt\" ]; then\n echo \"Signing VT binary...\"\n codesign --force --sign - \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/vt\"\n echo \"VT binary built and signed successfully\"\nelse\n echo \"error: VT binary was not created\"\n exit 1\nfi\n";
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
|
|
||||||
|
|
@ -1,190 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# vt - VibeTunnel TTY Forward Wrapper
|
|
||||||
# This script wraps tty-fwd to enable VibeTunnel to see command output
|
|
||||||
|
|
||||||
# Function to find Claude executable in common locations
|
|
||||||
find_claude() {
|
|
||||||
local claude_paths=(
|
|
||||||
"$HOME/.claude/local/claude"
|
|
||||||
"$HOME/.claude/local/node_modules/.bin/claude"
|
|
||||||
"/opt/homebrew/bin/claude"
|
|
||||||
"/usr/local/bin/claude"
|
|
||||||
"/usr/bin/claude"
|
|
||||||
"$(which claude 2>/dev/null)"
|
|
||||||
)
|
|
||||||
|
|
||||||
for path in "${claude_paths[@]}"; do
|
|
||||||
if [[ -n "$path" && -x "$path" ]]; then
|
|
||||||
echo "$path"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Error: Claude executable not found in any of the following locations:" >&2
|
|
||||||
printf " %s\n" "${claude_paths[@]}" >&2
|
|
||||||
echo "Please ensure Claude is installed or specify the full path manually." >&2
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get the real path of this script, resolving any symlinks
|
|
||||||
SCRIPT_REAL_PATH="$(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null || greadlink -f "${BASH_SOURCE[0]}" 2>/dev/null || realpath "${BASH_SOURCE[0]}" 2>/dev/null)"
|
|
||||||
if [[ -z "$SCRIPT_REAL_PATH" ]]; then
|
|
||||||
# Fallback for systems without readlink -f, greadlink, or realpath
|
|
||||||
SCRIPT_REAL_PATH="${BASH_SOURCE[0]}"
|
|
||||||
while [[ -L "$SCRIPT_REAL_PATH" ]]; do
|
|
||||||
SCRIPT_REAL_PATH="$(readlink "$SCRIPT_REAL_PATH")"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the directory where this script is actually located (Resources folder)
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_REAL_PATH")" && pwd)"
|
|
||||||
|
|
||||||
# Path to tty-fwd executable in the same Resources directory
|
|
||||||
TTY_FWD="$SCRIPT_DIR/tty-fwd"
|
|
||||||
|
|
||||||
# Check if tty-fwd exists there, otherwise use the one from ../tty-fwd/target/debug/tty-fwd
|
|
||||||
if [[ ! -x "$TTY_FWD" ]]; then
|
|
||||||
TTY_FWD="$SCRIPT_DIR/../tty-fwd/target/debug/tty-fwd"
|
|
||||||
if [[ ! -x "$TTY_FWD" ]]; then
|
|
||||||
echo "Error: tty-fwd executable not found at $TTY_FWD" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle --claude option
|
|
||||||
if [[ "$1" == "--claude" ]]; then
|
|
||||||
shift
|
|
||||||
claude_path="$(find_claude)"
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Re-execute vt with claude and remaining arguments
|
|
||||||
exec "$0" "$claude_path" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle --claude-yolo option
|
|
||||||
if [[ "$1" == "--claude-yolo" ]]; then
|
|
||||||
shift
|
|
||||||
claude_path="$(find_claude)"
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Re-execute vt with claude --dangerously-skip-permissions and remaining arguments
|
|
||||||
exec "$0" "$claude_path" --dangerously-skip-permissions "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle --show-session-info option
|
|
||||||
if [[ "$1" == "--show-session-info" ]]; then
|
|
||||||
shift
|
|
||||||
exec "$TTY_FWD" --show-session-info "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle --show-session-id option
|
|
||||||
if [[ "$1" == "--show-session-id" ]]; then
|
|
||||||
shift
|
|
||||||
exec "$TTY_FWD" --show-session-id "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Handle --shell or -i option (launch current shell)
|
|
||||||
if [[ "$1" == "--shell" || "$1" == "-i" ]]; then
|
|
||||||
shift
|
|
||||||
# Execute current shell through tty-fwd
|
|
||||||
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
|
|
||||||
|
|
||||||
if [[ $# -eq 0 || "$1" == "--help" || "$1" == "-h" ]]; then
|
|
||||||
cat << 'EOF'
|
|
||||||
vt - VibeTunnel TTY Forward Wrapper
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
vt [command] [args...]
|
|
||||||
vt --claude [args...]
|
|
||||||
vt --claude-yolo [args...]
|
|
||||||
vt --shell [args...]
|
|
||||||
vt -i [args...]
|
|
||||||
vt --no-shell-wrap [command] [args...]
|
|
||||||
vt --show-session-info
|
|
||||||
vt --show-session-id
|
|
||||||
vt -S [command] [args...]
|
|
||||||
vt --help
|
|
||||||
|
|
||||||
DESCRIPTION:
|
|
||||||
This wrapper script allows VibeTunnel to see the output of commands by
|
|
||||||
forwarding TTY data through the tty-fwd 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.
|
|
||||||
|
|
||||||
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 --claude # Auto-locate and run Claude
|
|
||||||
vt --claude --help # Run Claude with --help option
|
|
||||||
vt --claude-yolo # Run Claude with --dangerously-skip-permissions
|
|
||||||
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
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
--claude Auto-locate Claude executable and run it
|
|
||||||
--claude-yolo Auto-locate Claude and run with --dangerously-skip-permissions
|
|
||||||
--shell, -i Launch current shell (equivalent to vt $SHELL)
|
|
||||||
--no-shell-wrap, -S Execute command directly without shell wrapper
|
|
||||||
--help, -h Show this help message and exit
|
|
||||||
--show-session-info Show current session info
|
|
||||||
--show-session-id Show current session ID only
|
|
||||||
|
|
||||||
NOTE:
|
|
||||||
This script automatically uses the tty-fwd executable bundled with
|
|
||||||
VibeTunnel from the Resources folder.
|
|
||||||
EOF
|
|
||||||
exit 0
|
|
||||||
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 "$TTY_FWD" -- "$user_shell" -i -c "$(printf '%q ' "$cmd" "$@")"
|
|
||||||
;;
|
|
||||||
bash)
|
|
||||||
# For bash, expand aliases in non-interactive mode
|
|
||||||
exec "$TTY_FWD" -- "$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 "$TTY_FWD" -- "$user_shell" -c "$(printf '%q ' "$cmd" "$@")"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# Resolve and execute the command
|
|
||||||
if [[ "$NO_SHELL_WRAP" == "true" ]]; then
|
|
||||||
# Execute directly without shell wrapper
|
|
||||||
exec "$TTY_FWD" -- "$@"
|
|
||||||
else
|
|
||||||
# Use shell wrapper to resolve aliases/functions/builtins
|
|
||||||
resolve_command "$@"
|
|
||||||
fi
|
|
||||||
36
linux/build-vt-universal.sh
Executable file
36
linux/build-vt-universal.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build universal vt binary for macOS
|
||||||
|
|
||||||
|
echo "Building vt universal binary..."
|
||||||
|
|
||||||
|
# Get the directory where this script is located
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# Build for x86_64
|
||||||
|
echo "Building vt for x86_64..."
|
||||||
|
GOOS=darwin GOARCH=amd64 go build -o vt-x86_64 ./cmd/vt
|
||||||
|
|
||||||
|
# Build for arm64
|
||||||
|
echo "Building vt for arm64..."
|
||||||
|
GOOS=darwin GOARCH=arm64 go build -o vt-arm64 ./cmd/vt
|
||||||
|
|
||||||
|
# Create universal binary
|
||||||
|
echo "Creating universal binary..."
|
||||||
|
lipo -create -output vt vt-x86_64 vt-arm64
|
||||||
|
|
||||||
|
# Clean up architecture-specific binaries
|
||||||
|
rm vt-x86_64 vt-arm64
|
||||||
|
|
||||||
|
# Make it executable
|
||||||
|
chmod +x vt
|
||||||
|
|
||||||
|
echo "vt universal binary built successfully at: $SCRIPT_DIR/vt"
|
||||||
|
|
||||||
|
# Copy to target location if provided
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
echo "Copying vt to $1"
|
||||||
|
cp vt "$1"
|
||||||
|
fi
|
||||||
1
linux/claude
Executable file
1
linux/claude
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
echo "Claude called with args: $@"
|
||||||
277
linux/cmd/vt/main.go
Normal file
277
linux/cmd/vt/main.go
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Version = "1.0.0"
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Debug incoming args
|
||||||
|
if os.Getenv("VT_DEBUG") != "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "VT Debug: args = %v\n", os.Args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle version flag only if it's the only argument
|
||||||
|
if len(os.Args) == 2 && (os.Args[1] == "--version" || os.Args[1] == "-v") {
|
||||||
|
fmt.Printf("vt version %s\n", Version)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get preferred server
|
||||||
|
server := getPreferredServer()
|
||||||
|
|
||||||
|
// Forward to appropriate server
|
||||||
|
var err error
|
||||||
|
switch server {
|
||||||
|
case "rust":
|
||||||
|
err = forwardToRustServer(os.Args[1:])
|
||||||
|
case "go":
|
||||||
|
err = forwardToGoServer(os.Args[1:])
|
||||||
|
default:
|
||||||
|
err = forwardToGoServer(os.Args[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// If the command exited with a specific code, preserve it
|
||||||
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||||
|
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
||||||
|
os.Exit(status.ExitStatus())
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "vt: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPreferredServer() string {
|
||||||
|
// Check environment variable first
|
||||||
|
if server := os.Getenv("VT_SERVER"); server != "" {
|
||||||
|
if server == "rust" || server == "go" {
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from config file
|
||||||
|
configPath := filepath.Join(os.Getenv("HOME"), ".vibetunnel", "config.json")
|
||||||
|
data, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return "go" // default
|
||||||
|
}
|
||||||
|
|
||||||
|
var config Config
|
||||||
|
if err := json.Unmarshal(data, &config); err != nil {
|
||||||
|
return "go" // default on parse error
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Server == "rust" || config.Server == "go" {
|
||||||
|
return config.Server
|
||||||
|
}
|
||||||
|
return "go" // default for invalid values
|
||||||
|
}
|
||||||
|
|
||||||
|
func forwardToGoServer(args []string) error {
|
||||||
|
// Find vibetunnel binary
|
||||||
|
vibetunnelPath := findVibetunnelBinary()
|
||||||
|
if vibetunnelPath == "" {
|
||||||
|
return fmt.Errorf("vibetunnel binary not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a special VT command
|
||||||
|
var finalArgs []string
|
||||||
|
if len(args) > 0 && isVTSpecialCommand(args[0]) {
|
||||||
|
// Translate special VT commands
|
||||||
|
finalArgs = translateVTToGoArgs(args)
|
||||||
|
} else {
|
||||||
|
// For regular commands, just prepend -- to tell vibetunnel to stop parsing
|
||||||
|
finalArgs = append([]string{"--"}, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug: print what we're executing
|
||||||
|
if os.Getenv("VT_DEBUG") != "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "VT Debug: executing %s with args: %v\n", vibetunnelPath, finalArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create command
|
||||||
|
cmd := exec.Command(vibetunnelPath, finalArgs...)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
// Run and return
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func isVTSpecialCommand(arg string) bool {
|
||||||
|
switch arg {
|
||||||
|
case "--claude", "--claude-yolo", "--shell", "-i",
|
||||||
|
"--no-shell-wrap", "-S", "--show-session-info", "--show-session-id":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func forwardToRustServer(args []string) error {
|
||||||
|
// Find tty-fwd binary
|
||||||
|
ttyFwdPath := findTtyFwdBinary()
|
||||||
|
if ttyFwdPath == "" {
|
||||||
|
return fmt.Errorf("tty-fwd binary not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create command with original args (tty-fwd already understands vt args)
|
||||||
|
cmd := exec.Command(ttyFwdPath, args...)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
|
// Run and return
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateVTToGoArgs(args []string) []string {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for special vt-only flags
|
||||||
|
switch args[0] {
|
||||||
|
case "--claude":
|
||||||
|
// Find Claude and run it with any additional arguments
|
||||||
|
claudePath := findClaude()
|
||||||
|
if claudePath != "" {
|
||||||
|
// Pass all remaining args to claude
|
||||||
|
result := []string{"--", claudePath}
|
||||||
|
if len(args) > 1 {
|
||||||
|
result = append(result, args[1:]...)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
// Fallback
|
||||||
|
result := []string{"--", "claude"}
|
||||||
|
if len(args) > 1 {
|
||||||
|
result = append(result, args[1:]...)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
case "--claude-yolo":
|
||||||
|
// Find Claude and run with permissions skip
|
||||||
|
claudePath := findClaude()
|
||||||
|
if claudePath != "" {
|
||||||
|
return []string{"--", claudePath, "--dangerously-skip-permissions"}
|
||||||
|
}
|
||||||
|
return []string{"--", "claude", "--dangerously-skip-permissions"}
|
||||||
|
|
||||||
|
case "--shell", "-i":
|
||||||
|
// Launch interactive shell
|
||||||
|
shell := os.Getenv("SHELL")
|
||||||
|
if shell == "" {
|
||||||
|
shell = "/bin/bash"
|
||||||
|
}
|
||||||
|
return []string{"--", shell, "-i"}
|
||||||
|
|
||||||
|
case "--no-shell-wrap", "-S":
|
||||||
|
// Direct execution without shell - skip the flag and pass rest
|
||||||
|
if len(args) > 1 {
|
||||||
|
return append([]string{"--"}, args[1:]...)
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
|
||||||
|
case "--show-session-info":
|
||||||
|
return []string{"--list-sessions"}
|
||||||
|
|
||||||
|
case "--show-session-id":
|
||||||
|
// This needs special handling - just pass through for now
|
||||||
|
return args
|
||||||
|
|
||||||
|
default:
|
||||||
|
// This shouldn't happen since we check isVTSpecialCommand first
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findVibetunnelBinary() string {
|
||||||
|
// Check common locations
|
||||||
|
paths := []string{
|
||||||
|
// App bundle location
|
||||||
|
"/Applications/VibeTunnel.app/Contents/Resources/vibetunnel",
|
||||||
|
// Development locations
|
||||||
|
"./vibetunnel",
|
||||||
|
"../vibetunnel",
|
||||||
|
"../../linux/vibetunnel",
|
||||||
|
// Installed location
|
||||||
|
"/usr/local/bin/vibetunnel",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find in PATH
|
||||||
|
if path, err := exec.LookPath("vibetunnel"); err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTtyFwdBinary() string {
|
||||||
|
// Check common locations
|
||||||
|
paths := []string{
|
||||||
|
// App bundle location
|
||||||
|
"/Applications/VibeTunnel.app/Contents/Resources/tty-fwd",
|
||||||
|
// Development locations
|
||||||
|
"./tty-fwd",
|
||||||
|
"../tty-fwd",
|
||||||
|
"../../tty-fwd/target/release/tty-fwd",
|
||||||
|
// Installed location
|
||||||
|
"/usr/local/bin/tty-fwd",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find in PATH
|
||||||
|
if path, err := exec.LookPath("tty-fwd"); err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func findClaude() string {
|
||||||
|
// Check common Claude installation paths
|
||||||
|
claudePaths := []string{
|
||||||
|
filepath.Join(os.Getenv("HOME"), ".claude", "local", "claude"),
|
||||||
|
"/opt/homebrew/bin/claude",
|
||||||
|
"/usr/local/bin/claude",
|
||||||
|
"/usr/bin/claude",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range claudePaths {
|
||||||
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try PATH
|
||||||
|
if path, err := exec.LookPath("claude"); err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
2
linux/test-vt.sh
Executable file
2
linux/test-vt.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
VT_DEBUG=1 ./vt claude --dangerously-skip-permissions
|
||||||
Loading…
Reference in a new issue