Skip to main content
Glama
by 8b-is
manage.sh35.7 kB
#!/usr/bin/env bash # 🌳 Smart Tree Management Script - Because every tree needs a gardener! 🌳 set -euo pipefail # Colors for our fancy output if [[ -t 1 ]] && [[ "${NO_COLOR:-}" != "1" ]]; then RED=$'\033[0;31m' GREEN=$'\033[0;32m' YELLOW=$'\033[1;33m' BLUE=$'\033[0;34m' PURPLE=$'\033[0;35m' CYAN=$'\033[0;36m' NC=$'\033[0m' # No Color else RED='' GREEN='' YELLOW='' BLUE='' PURPLE='' CYAN='' NC='' fi # Project info PROJECT_NAME="Smart Tree (st)" PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BINARY_NAME="st" # Non-interactive mode flag NON_INTERACTIVE=${NON_INTERACTIVE:-false} # Emojis for fun (can be disabled) if [[ "${NO_EMOJI:-}" == "1" ]]; then TREE="[TREE]" ROCKET="[GO]" GEAR="[BUILD]" TEST="[TEST]" CLEAN="[CLEAN]" INFO="[INFO]" CHECK="[OK]" CROSS="[FAIL]" SPARKLE="[*]" else TREE="🌳" ROCKET="🚀" GEAR="⚙️" TEST="🧪" CLEAN="🧹" INFO="📊" CHECK="✅" CROSS="❌" SPARKLE="✨" fi # Helper functions print_header() { echo -e "\n${CYAN}${TREE} $1 ${TREE}${NC}\n" } print_success() { echo -e "${GREEN}${CHECK} $1${NC}" } print_error() { echo -e "${RED}${CROSS} $1${NC}" } print_info() { echo -e "${BLUE}${INFO} $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } # Ask yes/no question ask_yes_no() { local prompt="$1" local default="${2:-y}" if [[ "$NON_INTERACTIVE" == "true" ]]; then [[ "$default" == "y" ]] && return 0 || return 1 fi local response if [[ "$default" == "y" ]]; then read -p "$(echo -e "${CYAN}$prompt [Y/n]: ${NC}")" response [[ -z "$response" || "$response" =~ ^[Yy] ]] && return 0 || return 1 else read -p "$(echo -e "${CYAN}$prompt [y/N]: ${NC}")" response [[ "$response" =~ ^[Yy] ]] && return 0 || return 1 fi } # Show animated spinner spinner() { local pid=$1 local delay=0.1 local spinstr='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' while ps -p $pid > /dev/null 2>&1; do local temp=${spinstr#?} printf " [%c] " "$spinstr" local spinstr=$temp${spinstr%"$temp"} sleep $delay printf "\b\b\b\b\b\b" done printf " \b\b\b\b" } # Check if command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Build the project build() { local build_type="${1:-release}" local features="${2:-}" print_header "Building $PROJECT_NAME in $build_type mode ${GEAR}" cd "$PROJECT_DIR" local feature_flags="" if [[ -n "$features" ]]; then feature_flags="--features $features" print_info "Building with features: $features" fi if [[ "$build_type" == "release" ]]; then print_info "Optimizing for maximum speed... ${ROCKET}" if [[ "$NON_INTERACTIVE" == "true" ]]; then cargo build --release $feature_flags else cargo build --release $feature_flags & spinner $! fi print_success "Release build complete! Binary size: $(du -h target/release/$BINARY_NAME | cut -f1)" else print_info "Building debug version with all the debugging goodies..." cargo build $feature_flags print_success "Debug build complete!" fi } # Run the project run() { print_header "Running $PROJECT_NAME ${ROCKET}" cd "$PROJECT_DIR" # Default to current directory if no args provided if [[ $# -eq 0 ]]; then print_info "No arguments provided, analyzing current directory..." cargo run --release -- . else cargo run --release "$@" fi } # Run tests test() { print_header "Testing $PROJECT_NAME ${TEST}" cd "$PROJECT_DIR" print_info "Running unit tests..." cargo test print_info "Running clippy (our friendly neighborhood linter)..." cargo clippy -- -D warnings || print_warning "Clippy found some issues!" print_info "Checking formatting..." cargo fmt -- --check || print_warning "Code needs formatting! Run './manage.sh format' to fix." print_success "All tests passed! Your tree is healthy! ${TREE}" } # Format code format() { print_header "Formatting code ${SPARKLE}" cd "$PROJECT_DIR" cargo fmt print_success "Code formatted! Looking prettier than a bonsai tree! 🎋" } # Clean build artifacts clean() { print_header "Cleaning up ${CLEAN}" cd "$PROJECT_DIR" cargo clean print_success "All clean! Fresh as a spring forest! 🌱" } # Show project status status() { print_header "Project Status ${INFO}" cd "$PROJECT_DIR" echo -e "${PURPLE}Project:${NC} $PROJECT_NAME" echo -e "${PURPLE}Location:${NC} $PROJECT_DIR" echo -e "${PURPLE}Rust version:${NC} $(rustc --version)" echo -e "${PURPLE}Cargo version:${NC} $(cargo --version)" if [[ -f "target/release/$BINARY_NAME" ]]; then echo -e "${PURPLE}Release binary:${NC} $(du -h target/release/$BINARY_NAME | cut -f1)" echo -e "${PURPLE}Last modified:${NC} $(date -r target/release/$BINARY_NAME '+%Y-%m-%d %H:%M:%S')" else echo -e "${PURPLE}Release binary:${NC} Not built yet" fi echo -e "\n${PURPLE}Dependencies:${NC}" cargo tree --depth 1 | head -20 echo -e "\n${PURPLE}Git status:${NC}" if command_exists git && git rev-parse --git-dir > /dev/null 2>&1; then git status --short || echo " Clean working tree ${CHECK}" else echo " Not a git repository" fi } # Version management helpers bump_version() { print_header "Version Management 🔢" cd "$PROJECT_DIR" # Get current version from Cargo.toml current_version=$(grep "^version = " Cargo.toml | head -1 | cut -d'"' -f2) print_info "Current version: v$current_version" # Parse version components IFS='.' read -r major minor patch <<< "$current_version" # Increment based on argument or default to patch case "${1:-patch}" in major) new_version="$((major + 1)).0.0" ;; minor) new_version="$major.$((minor + 1)).0" ;; patch|*) new_version="$major.$minor.$((patch + 1))" ;; esac print_info "Bumping to: v$new_version" # Update Cargo.toml if [[ "$OSTYPE" == "darwin"* ]]; then sed -i '' "s/^version = \"$current_version\"/version = \"$new_version\"/" Cargo.toml else sed -i "s/^version = \"$current_version\"/version = \"$new_version\"/" Cargo.toml fi # Update CLAUDE.md if it exists if [[ -f "CLAUDE.md" ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then sed -i '' "s/v$current_version/v$new_version/g" CLAUDE.md else sed -i "s/v$current_version/v$new_version/g" CLAUDE.md fi print_success "Updated CLAUDE.md" fi # Clean up orphaned local tags print_info "Cleaning orphaned tags..." git tag -l | while read tag; do if ! git ls-remote --tags origin | grep -q "refs/tags/$tag$"; then print_warning "Removing local-only tag: $tag" git tag -d "$tag" >/dev/null 2>&1 fi done print_success "Version bumped to v$new_version! ${CHECK}" echo -e "\n${YELLOW}Next steps:${NC}" echo " 1. Build: ./manage.sh build" echo " 2. Test: ./manage.sh test" echo " 3. Commit: git add -A && git commit -m 'chore: bump version to v$new_version'" echo " 4. Tag: git tag -a v$new_version -m 'Version $new_version'" echo " 5. Push: git push origin main && git push origin v$new_version" } # Quick version bump and build quick_bump() { print_header "Quick Version Bump & Build 🚀" bump_version patch echo build release print_success "Ready to commit and push!" } # Run benchmarks bench() { print_header "Running Benchmarks 📈" cd "$PROJECT_DIR" print_info "Building optimized version..." cargo build --release print_info "Benchmarking on current directory..." time ./target/release/$BINARY_NAME . -m hex > /dev/null print_info "Benchmarking with compression..." time ./target/release/$BINARY_NAME . -m ai -z > /dev/null if [[ -d "/usr" ]]; then print_info "Benchmarking on /usr (large directory)..." time ./target/release/$BINARY_NAME /usr -m hex --depth 3 > /dev/null || true fi } # Install binary install() { print_header "Installing $PROJECT_NAME 🎯" cd "$PROJECT_DIR" local install_dir="${1:-/usr/local/bin}" print_info "Building release version..." cargo build --release if [[ -w "$install_dir" ]]; then cp "target/release/$BINARY_NAME" "$install_dir/" print_success "Installed to $install_dir/$BINARY_NAME" else print_warning "Need sudo access to install to $install_dir" sudo cp "target/release/$BINARY_NAME" "$install_dir/" print_success "Installed to $install_dir/$BINARY_NAME (with sudo)" fi print_info "You can now use '$BINARY_NAME' from anywhere! ${ROCKET}" } # Uninstall binary uninstall() { print_header "Uninstalling $PROJECT_NAME 😢" local install_dir="${1:-/usr/local/bin}" local binary_path="$install_dir/$BINARY_NAME" if [[ -f "$binary_path" ]]; then if [[ -w "$install_dir" ]]; then rm "$binary_path" else sudo rm "$binary_path" fi print_success "Uninstalled from $binary_path" else print_error "$BINARY_NAME not found in $install_dir" fi } # Create a new GitHub release release() { print_header "Creating a new GitHub release ${ROCKET}" local version="${1-}" if [[ -z "$version" ]]; then print_error "Version tag is required. Example: v1.0.0" exit 1 fi if ! command_exists gh; then print_error "GitHub CLI (gh) is not installed. Please install it to create releases." print_info "See: https://cli.github.com/" exit 1 fi if [[ -n "$(git status --porcelain)" ]]; then print_error "Your working directory is not clean. Please commit or stash your changes." git status --short exit 1 fi print_info "Creating release for version: $version" # Artifacts directory local artifact_dir="release_artifacts" rm -rf "$artifact_dir" mkdir -p "$artifact_dir" # Get target triple for artifact naming local target_triple target_triple=$(rustc -vV | grep "host:" | cut -d ' ' -f2) # --- Build standard version --- print_info "Building standard release for ${target_triple}..." build "release" "" # Determine artifact name based on platform local artifact_name local archive_ext if [[ "$target_triple" == *"windows"* ]]; then artifact_name="${BINARY_NAME}-${target_triple}.exe" archive_ext="zip" else artifact_name="${BINARY_NAME}-${target_triple}" archive_ext="tar.gz" fi # Copy binary to artifact directory cp "target/release/${BINARY_NAME}" "${artifact_dir}/${BINARY_NAME}" # Create archive if [[ "$archive_ext" == "zip" ]]; then # For Windows, include .exe in the archive mv "${artifact_dir}/${BINARY_NAME}" "${artifact_dir}/${BINARY_NAME}.exe" (cd "$artifact_dir" && zip -q "${artifact_name}.zip" "${BINARY_NAME}.exe") rm "${artifact_dir}/${BINARY_NAME}.exe" local standard_artifact_path="${artifact_dir}/${artifact_name}.zip" else # For Unix, create tar.gz (cd "$artifact_dir" && tar -czf "${artifact_name}.tar.gz" "${BINARY_NAME}") rm "${artifact_dir}/${BINARY_NAME}" local standard_artifact_path="${artifact_dir}/${artifact_name}.tar.gz" fi print_success "Standard artifact created: ${standard_artifact_path}" # Note: We only create one set of artifacts since MCP is a default feature # --- Build DXT package --- print_info "Building DXT package..." if [[ -f "dxt/build-dxt.sh" ]]; then (cd dxt && ./build-dxt.sh) if [[ -f "dxt/smart-tree.dxt" ]]; then cp "dxt/smart-tree.dxt" "${artifact_dir}/" local dxt_artifact_path="${artifact_dir}/smart-tree.dxt" print_success "DXT package created: ${dxt_artifact_path}" else print_warning "DXT build completed but smart-tree.dxt not found" local dxt_artifact_path="" fi else print_warning "DXT build script not found, skipping DXT package" local dxt_artifact_path="" fi # --- Create GitHub Release --- local release_title="Smart Tree ${version}" shift # remove version from args local release_notes="${*:-Release ${version}}" print_info "Creating GitHub release..." print_info "Title: $release_title" print_info "Notes: $release_notes" if [[ "$NON_INTERACTIVE" == "true" ]]; then # Create git tag print_info "Tagging and pushing version $version..." git tag "$version" git push origin "$version" print_info "Creating GitHub release and uploading artifacts..." # Note: This will only upload the artifact for the current platform # For multi-platform releases, you'll need to build on each platform or use CI/CD if [[ -n "$dxt_artifact_path" ]]; then gh release create "$version" "$standard_artifact_path" "$dxt_artifact_path" --title "$release_title" --notes "$release_notes" else gh release create "$version" "$standard_artifact_path" --title "$release_title" --notes "$release_notes" fi else echo -e "\n${YELLOW}Ready to create release. Review details above.${NC}" read -p "Do you want to proceed? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then print_warning "Release cancelled." rm -rf "$artifact_dir" exit 1 fi # Create git tag and push it print_info "Tagging version $version..." git tag "$version" git push origin "$version" print_success "Pushed tag $version to origin." print_info "Creating GitHub release and uploading artifacts..." # Note: This will only upload the artifact for the current platform # For multi-platform releases, you'll need to build on each platform or use CI/CD if [[ -n "$dxt_artifact_path" ]]; then gh release create "$version" "$standard_artifact_path" "$dxt_artifact_path" --title "$release_title" --notes "$release_notes" else gh release create "$version" "$standard_artifact_path" --title "$release_title" --notes "$release_notes" fi fi print_success "Release ${version} created successfully! ${TREE} ${SPARKLE}" rm -rf "$artifact_dir" } # Setup shell completions completions() { print_header "Setting up shell completions 🐚" cd "$PROJECT_DIR" # Check if st is already built and installed if ! command_exists st && [[ ! -f "./target/release/st" ]]; then print_info "Building release binary to generate completions..." cargo build --release fi # Use our enhanced setup script if [[ -f "$PROJECT_DIR/scripts/setup-completions.sh" ]]; then print_info "Running enhanced completion setup..." if [[ "$NON_INTERACTIVE" == "true" ]]; then # Non-interactive mode - skip prompts and use defaults yes "y" | bash "$PROJECT_DIR/scripts/setup-completions.sh" else bash "$PROJECT_DIR/scripts/setup-completions.sh" fi else # Fallback to basic method if setup script doesn't exist print_warning "Enhanced setup script not found, using basic method..." local shell_type shell_type="$(basename "$SHELL")" print_info "Detected shell: $shell_type" case "$shell_type" in bash) local completion_dir="$HOME/.bash_completion.d" mkdir -p "$completion_dir" print_info "Generating bash completions..." ./target/release/st --completions bash > "$completion_dir/_st" print_success "Bash completions installed!" print_info "Add 'source $completion_dir/_st' to your .bashrc" ;; zsh) local completion_dir="$HOME/.zsh/completions" mkdir -p "$completion_dir" print_info "Generating zsh completions..." ./target/release/st --completions zsh > "$completion_dir/_st" print_success "Zsh completions installed!" print_info "Add 'fpath=($completion_dir \$fpath)' to your .zshrc" ;; fish) local completion_dir="$HOME/.config/fish/completions" mkdir -p "$completion_dir" print_info "Generating fish completions..." ./target/release/st --completions fish > "$completion_dir/st.fish" print_success "Fish completions installed!" ;; *) print_warning "Unknown shell: $shell_type" print_info "Supported shells: bash, zsh, fish" print_info "Generate manually: st --completions <shell>" ;; esac fi } # Install/Uninstall man page manage_man_page() { print_header "Managing Man Page 📖" cd "$PROJECT_DIR" if ! command_exists pandoc; then print_error "pandoc is not installed. Please install it to continue." print_info "On Debian/Ubuntu: sudo apt-get install pandoc" print_info "On macOS (Homebrew): brew install pandoc" print_info "On Arch Linux: sudo pacman -S pandoc" exit 1 fi local man_dir="/usr/local/share/man/man1" local man_page_src="docs/st-cheetsheet.md" local man_page_dest="$man_dir/st.1" if [[ "$1" == "install" ]]; then print_info "Generating and installing man page from $man_page_src..." if [[ ! -d "$man_dir" ]]; then print_info "Creating man directory: $man_dir" sudo mkdir -p "$man_dir" fi # Use a temporary file for pandoc output before moving with sudo local temp_file temp_file=$(mktemp) pandoc "$man_page_src" -s -t man -o "$temp_file" print_info "Installing to $man_page_dest" sudo mv "$temp_file" "$man_page_dest" print_info "Updating man database..." sudo mandb print_success "Man page for 'st' installed. Try 'man st'!" elif [[ "$1" == "uninstall" ]]; then if [[ -f "$man_page_dest" ]]; then print_info "Uninstalling man page: $man_page_dest" sudo rm "$man_page_dest" print_info "Updating man database..." sudo mandb print_success "Man page for 'st' uninstalled." else print_warning "Man page not found at $man_page_dest. Nothing to do." fi else print_error "Unknown argument. Use 'install' or 'uninstall'." fi } # MCP server functions mcp_build() { print_header "Building $PROJECT_NAME (MCP included) 🤖" build release } mcp_run() { print_header "Running MCP server 🤖" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Binary not found. Building release version..." build release fi print_info "Starting MCP server on stdio..." print_info "Press Ctrl+C to stop" ./target/release/$BINARY_NAME --mcp } mcp_config() { print_header "MCP Configuration 🤖" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi ./target/release/$BINARY_NAME --mcp-config } mcp_tools() { print_header "MCP Tools Documentation 🤖" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi ./target/release/$BINARY_NAME --mcp-tools } # Claude Code Hooks functions hooks_list() { print_header "Claude Code Hooks Configuration 🎣" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi ./target/release/$BINARY_NAME --hooks-config status } hooks_enable() { print_header "Enabling Claude Code Hooks 🎣" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi ./target/release/$BINARY_NAME --hooks-config enable } hooks_disable() { print_header "Disabling Claude Code Hooks 🎣" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi ./target/release/$BINARY_NAME --hooks-config disable } hooks_test() { local test_input="${1:-test input}" print_header "Testing Claude Code Hook 🧪" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi print_info "Testing hook locally with input: '$test_input'" echo '{"prompt": "'"$test_input"'"}' | ./target/release/$BINARY_NAME --claude-user-prompt-submit } hooks_setup() { print_header "Setting up Claude Code Hooks 🎣" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi ./target/release/$BINARY_NAME --hooks-install } # Demo streaming feature demo_stream() { print_header "Demonstrating Streaming Mode ${ROCKET}" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi print_info "Streaming the current project directory in hex format..." print_info "Notice how output appears immediately as files are discovered!" echo "" ./target/release/$BINARY_NAME --stream -m hex . | head -20 echo "... (truncated for demo)" print_info "\nStreaming with AI format:" ./target/release/$BINARY_NAME --stream -m ai . | head -25 echo "... (truncated for demo)" print_success "Streaming is perfect for large directories! ${SPARKLE}" } # Demo search feature demo_search() { print_header "Demonstrating Search Feature 🔍" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi print_info "Searching for 'Scanner' in the source code..." ./target/release/$BINARY_NAME --search "Scanner" -m hex src | grep SEARCH || print_warning "No matches found" print_info "\nSearching for 'TODO' comments..." ./target/release/$BINARY_NAME --search "TODO" -m hex . | grep SEARCH || print_info "Good news! No TODOs found!" print_info "\nSearch works great with streaming too:" ./target/release/$BINARY_NAME --stream --search "fn" --type rs -m hex src | head -10 print_success "Search helps you find content quickly! ${SPARKLE}" } # Demo relations feature demo_relations() { print_header "Demonstrating Code Relations Feature 🔗" cd "$PROJECT_DIR" if [[ ! -f "target/release/$BINARY_NAME" ]]; then print_warning "Building release version first..." build release fi print_info "Analyzing relationships in src/ directory..." ./target/release/$BINARY_NAME -m relations src | head -30 echo "... (truncated for demo)" print_info "\nWith import filter:" ./target/release/$BINARY_NAME -m relations --relations-filter imports src | head -20 echo "... (truncated for demo)" print_info "\nFocusing on main.rs:" ./target/release/$BINARY_NAME -m relations --focus src/main.rs src | head -15 print_success "Relations feature provides semantic X-ray vision for codebases! ${SPARKLE}" } # Show usage examples examples() { print_header "Usage Examples ${SPARKLE}" cat << EOF ${CYAN}Basic usage:${NC} $BINARY_NAME # Analyze current directory $BINARY_NAME /path/to/dir # Analyze specific directory ${CYAN}Output modes:${NC} $BINARY_NAME -m hex # Hexadecimal format (AI-friendly) $BINARY_NAME -m json # JSON output $BINARY_NAME -m ai # AI-optimized format $BINARY_NAME -m digest # Super compact digest (hash + stats) $BINARY_NAME -m stats # Statistics only ${CYAN}Filtering:${NC} $BINARY_NAME --find "*.rs" # Find Rust files $BINARY_NAME --type rs # Only .rs files $BINARY_NAME --min-size 1M # Files larger than 1MB $BINARY_NAME --newer-than 2024-01-01 # Recent files ${CYAN}Options:${NC} $BINARY_NAME --no-emoji # Plain text output $BINARY_NAME --depth 3 # Limit depth $BINARY_NAME -z # Compress output ${CYAN}🆕 Streaming Mode:${NC} $BINARY_NAME --stream # Stream output as files are found $BINARY_NAME --stream -m hex /large # Great for huge directories $BINARY_NAME --stream -m ai # Real-time AI format output ${CYAN}🆕 File Content Search:${NC} $BINARY_NAME --search "TODO" # Find TODO in all text files $BINARY_NAME --type rs --search "fn" # Search for "fn" in Rust files $BINARY_NAME -m hex --search "error" # Hex output with search positions ${CYAN}🔗 Code Relations (NEW!):${NC} $BINARY_NAME -m relations # Analyze code relationships $BINARY_NAME -m relations --focus main.rs # Focus on specific file $BINARY_NAME -m relations --relations-filter imports # Show only imports ${CYAN}AI usage:${NC} AI_TOOLS=1 $BINARY_NAME # Auto AI mode + compression $BINARY_NAME -m digest # Quick digest for AI pre-check $BINARY_NAME -m ai -z | base64 -d # Decode compressed output ${CYAN}MCP (Model Context Protocol):${NC} $0 mcp-run # Run as MCP server $0 mcp-config # Show Claude Desktop config $0 mcp-tools # Show available MCP tools (20+) EOF } # Show help show_help() { cat << EOF ${CYAN}${TREE} Smart Tree Management Script ${TREE}${NC} ${YELLOW}Usage:${NC} $0 [command] [options] ${YELLOW}Commands:${NC} ${GREEN}build${NC} [debug|release] [features] Build the project ${GREEN}run${NC} [args...] Run st with arguments ${GREEN}test${NC} Run tests, linting, and format check ${GREEN}format${NC} Format code with rustfmt ${GREEN}clean${NC} Clean build artifacts ${GREEN}status${NC} Show project status ${GREEN}bench${NC} Run performance benchmarks ${GREEN}menu${NC} Launch interactive setup menu ${SPARKLE} ${GREEN}install${NC} [dir] Install binary (default: /usr/local/bin) ${GREEN}uninstall${NC} [dir] Uninstall binary ${GREEN}release${NC} <vX.Y.Z> [notes] Create a GitHub release ${GREEN}bump${NC} [major|minor|patch] Bump version (default: patch +0.0.1) ${GREEN}quick-bump${NC} Quick version bump + build 🚀 ${GREEN}completions${NC} Setup shell completions ${GREEN}man-install${NC} Generate and install the man page ${GREEN}man-uninstall${NC} Uninstall the man page ${GREEN}examples${NC} Show usage examples ${GREEN}demo-stream${NC} Demo streaming feature ${GREEN}demo-search${NC} Demo search feature ${GREEN}demo-relations${NC} Demo code relations feature 🔗 ${GREEN}rename-project${NC} <old> <new> Elegant project identity transition 🚗 ${GREEN}help${NC} Show this help message ${YELLOW}MCP Commands:${NC} ${GREEN}mcp-run${NC} Run as MCP server ${GREEN}mcp-config${NC} Show Claude Desktop configuration ${GREEN}mcp-tools${NC} Show available MCP tools (20+) ${YELLOW}Claude Code Hooks:${NC} ${GREEN}hooks-setup${NC} Interactive setup for Claude Code hooks ${GREEN}hooks-list${NC} List current hooks configuration ${GREEN}hooks-enable${NC} [type] Enable a specific hook (default: UserPromptSubmit) ${GREEN}hooks-disable${NC} [type] Disable a specific hook ${GREEN}hooks-test${NC} [type] [input] Test a hook with sample input ${YELLOW}Feedback System Commands:${NC} ${GREEN}feedback-build${NC} Build feedback system containers ${GREEN}feedback-run${NC} Run feedback worker locally ${GREEN}feedback-deploy${NC} [type] Deploy feedback system (local|hetzner|registry) ${GREEN}feedback-test${NC} Test feedback system ${GREEN}feedback-status${NC} Check feedback system health ${YELLOW}Environment Variables:${NC} ${PURPLE}NO_EMOJI=1${NC} Disable emojis in output ${PURPLE}NON_INTERACTIVE=true${NC} Disable interactive features ${YELLOW}Examples:${NC} $0 build # Build release version $0 run -- -m hex . # Run with hex output on current dir $0 test # Run all tests $0 release v1.0.0 "My first release!" # Create a new release $0 mcp-run # Start MCP server ${CYAN}Made with ${SPARKLE} and 🌳 by the Smart Tree team!${NC} EOF } # Feedback system functions feedback_build() { print_header "Building Feedback System Containers 🔨" cd "$PROJECT_DIR/feedback-worker" print_info "Building feedback API container..." docker build -t ghcr.io/8b-is/smart-tree-feedback-api:latest ../feedback-api/ print_info "Building feedback worker container..." docker build -t ghcr.io/8b-is/smart-tree-feedback-worker:latest . print_success "Feedback containers built successfully!" } feedback_run() { print_header "Running Feedback Worker Locally 🎸" cd "$PROJECT_DIR/feedback-worker" if [[ -z "${GITHUB_TOKEN:-}" ]]; then print_warning "GITHUB_TOKEN not set - worker will run without GitHub integration" fi print_info "Starting feedback system with docker-compose..." docker-compose up -d print_success "Feedback system running!" print_info " API: http://localhost:8422" print_info " Metrics: http://localhost:9090/metrics" print_info " Grafana: http://localhost:3000 (admin/admin)" } feedback_deploy() { local deploy_type="${1:-local}" print_header "Deploying Feedback System - Type: $deploy_type 🚀" cd "$PROJECT_DIR/feedback-worker" ./deploy.sh "$deploy_type" } feedback_test() { print_header "Testing Feedback System 🧪" cd "$PROJECT_DIR/feedback-worker" if ! command_exists python3; then print_error "Python 3 is required for testing" return 1 fi print_info "Running feedback system tests..." python3 test_worker.py } feedback_status() { print_header "Feedback System Status 📊" # Check API if curl -sf http://localhost:8422/health > /dev/null 2>&1; then print_success "API is healthy" curl -s http://localhost:8422/health | jq . || true else print_error "API is not responding" fi # Check worker metrics if curl -sf http://localhost:9090/metrics > /dev/null 2>&1; then print_success "Worker is healthy" echo " $(curl -s http://localhost:9090/metrics | grep -E '^feedback_processed_total' | head -1)" else print_error "Worker is not responding" fi # Check Redis if docker exec $(docker ps -qf "name=redis" 2>/dev/null) redis-cli ping > /dev/null 2>&1; then print_success "Redis is healthy" else print_error "Redis is not responding" fi # Check containers print_info "Running containers:" docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -E "(feedback|redis)" || echo " No feedback containers running" } # Main command dispatcher main() { if [[ $# -eq 0 ]]; then show_help exit 0 fi case "$1" in build) shift build "$@" ;; run) shift run "$@" ;; test) test ;; format|fmt) format ;; clean) clean ;; menu|setup) # Launch interactive setup menu print_header "Launching Interactive Setup Menu ${SPARKLE}" "$PROJECT_DIR/scripts/interactive_setup.sh" ;; status|info) status ;; bench|benchmark) bench ;; install) shift install "$@" ;; uninstall|remove) shift uninstall "$@" ;; release) shift release "$@" ;; bump) shift bump_version "$@" ;; quick-bump) quick_bump ;; completions|complete) completions ;; man-install) manage_man_page install ;; man-uninstall) manage_man_page uninstall ;; examples|ex) examples ;; mcp-build) print_info "MCP is now built-in! Just run 'build' instead." build release ;; mcp-run) mcp_run ;; mcp-config) mcp_config ;; mcp-tools) mcp_tools ;; hooks-setup) hooks_setup ;; hooks-list) hooks_list ;; hooks-enable) hooks_enable "${2:-UserPromptSubmit}" ;; hooks-disable) hooks_disable "${2:-UserPromptSubmit}" ;; hooks-test) hooks_test "${2:-test input}" ;; demo-stream) demo_stream ;; demo-search) demo_search ;; demo-relations) demo_relations ;; feedback-build) feedback_build ;; feedback-run) feedback_run ;; feedback-deploy) feedback_deploy "${@:2}" ;; feedback-test) feedback_test ;; feedback-status) feedback_status ;; rename-project) if [[ $# -lt 3 ]]; then print_error "Usage: $0 rename-project <old_name> <new_name>" exit 1 fi print_header "Project Rebranding Ritual 🚗" cd "$PROJECT_DIR" ./target/release/st --rename-project "$2" "$3" ;; help|h|-h|--help) show_help ;; *) print_error "Unknown command: $1" echo "" show_help exit 1 ;; esac } # Let's go! 🚀 main "$@"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server