Created
March 6, 2025 02:39
-
-
Save cmdruid/f3835a7a900eeb281507d5d2fb98109f to your computer and use it in GitHub Desktop.
Used Grok 3 to write a command-line tool for using Grok on my codebase.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Configuration defaults | |
API_KEY="your-xai-api-key-here" # Default API key (overridden by config or env) | |
API_URL="https://api.x.ai/v1/chat/completions" | |
CODEBASE_FILE="/tmp/grok_codebase.txt" | |
SESSION_FILE="$PWD/grok_session_$(date +%Y%m%d_%H%M%S).txt" # Default in current directory | |
SOURCE_PATH="" | |
MODEL="grok-3-latest" # Default model | |
CONTEXT="" | |
CURRENT_DIR="$PWD" # Current working directory where script is executed | |
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Directory where script resides | |
CONFIG_FILE="" | |
# Function to display usage | |
usage() { | |
echo "Usage: $0 source_path [-s session_file] [-m model] [-c config_file]" | |
echo " source_path: Specify the source path or file to compact (required)" | |
echo " -s: Specify the session file to use (optional, defaults to a timestamped file in current directory)" | |
echo " -m: Specify the Grok model to use (optional, defaults to grok-3-latest)" | |
echo " -c: Specify a config file to use (optional, defaults to .grokconfig in current directory or script directory)" | |
exit 1 | |
} | |
# Function to load config file | |
load_config() { | |
local config_path="$1" | |
if [ -f "$config_path" ]; then | |
echo "Loading config from $config_path..." | |
while IFS='=' read -r key value; do | |
# Skip empty lines and comments | |
[[ -z "$key" || "$key" =~ ^# ]] && continue | |
# Remove leading/trailing whitespace | |
key=$(echo "$key" | xargs) | |
value=$(echo "$value" | xargs) | |
case "$key" in | |
API_KEY) [ -z "$API_KEY_SET" ] && API_KEY="$value";; | |
MODEL) [ -z "$MODEL_SET" ] && MODEL="$value";; | |
esac | |
done < "$config_path" | |
fi | |
} | |
# Parse command-line options (-s, -m, and -c are optional) | |
while getopts "s:m:c:" opt; do | |
case $opt in | |
s) SESSION_FILE="$CURRENT_DIR/$OPTARG";; | |
m) MODEL="$OPTARG"; MODEL_SET="1";; | |
c) CONFIG_FILE="$OPTARG";; | |
?) usage;; | |
esac | |
done | |
# Shift past the options to get positional arguments | |
shift $((OPTIND-1)) | |
# Check if source_path (first positional argument) is provided | |
if [ -z "$1" ]; then | |
echo "Error: source_path is required." | |
usage | |
fi | |
SOURCE_PATH="$1" | |
# Load config file: -c first, then current directory, then script directory | |
if [ -n "$CONFIG_FILE" ]; then | |
load_config "$CONFIG_FILE" | |
else | |
# Try current directory first | |
CONFIG_FILE="$CURRENT_DIR/.grokconfig" | |
if [ -f "$CONFIG_FILE" ]; then | |
load_config "$CONFIG_FILE" | |
else | |
# Fall back to script directory | |
CONFIG_FILE="$SCRIPT_DIR/.grokconfig" | |
load_config "$CONFIG_FILE" | |
fi | |
fi | |
# Ensure required tools are installed | |
command -v curl >/dev/null 2>&1 || { echo "curl is required but not installed. Please install it."; exit 1; } | |
command -v jq >/dev/null 2>&1 || { echo "jq is required for JSON parsing. Please install it."; exit 1; } | |
# Function to compact codebase with .grokignore support from current directory | |
compact_codebase() { | |
echo "Compacting codebase from $SOURCE_PATH into $CODEBASE_FILE..." | |
> "$CODEBASE_FILE" # Clear the file | |
local grokignore="$CURRENT_DIR/.grokignore" | |
local exclude_patterns=() | |
# Check .grokignore in the current directory (where the script is run) | |
if [ -f "$grokignore" ]; then | |
echo "Found .grokignore in $CURRENT_DIR, applying exclusions..." | |
while IFS= read -r line || [ -n "$line" ]; do | |
[[ -z "$line" || "$line" =~ ^# ]] && continue | |
exclude_patterns+=("-not" "-name" "$line") | |
done < "$grokignore" | |
fi | |
# Handle if SOURCE_PATH is a file or directory | |
if [ -f "$SOURCE_PATH" ]; then | |
# If it's a file, include it directly unless excluded | |
if [[ ! "$SOURCE_PATH" =~ .grokignore ]] && ! echo "$SOURCE_PATH" | grep -q -f "$grokignore" 2>/dev/null; then | |
echo "=== $SOURCE_PATH ===" >> "$CODEBASE_FILE" | |
cat "$SOURCE_PATH" >> "$CODEBASE_FILE" | |
echo -e "\n" >> "$CODEBASE_FILE" | |
fi | |
elif [ -d "$SOURCE_PATH" ]; then | |
# If it's a directory, use find with exclusions | |
find "$SOURCE_PATH" -type f -not -name ".grokignore" "${exclude_patterns[@]}" | while read -r file; do | |
echo "=== $file ===" >> "$CODEBASE_FILE" | |
cat "$file" >> "$CODEBASE_FILE" | |
echo -e "\n" >> "$CODEBASE_FILE" | |
done | |
else | |
echo "Error: $SOURCE_PATH is neither a file nor a directory." | |
exit 1 | |
fi | |
echo "Codebase compacted. Size: $(wc -l < "$CODEBASE_FILE") lines" | |
} | |
# Function to send query to Grok API | |
query_grok() { | |
local prompt="$1" | |
# Prepare the messages | |
local system_message="You are Grok 3, built by xAI. Analyze the provided codebase and assist with the user's question." | |
local user_message="Here's my codebase:\n$(cat "$CODEBASE_FILE")\n\nPrevious context: $CONTEXT\n\nQuestion: $prompt" | |
# Use jq to construct the JSON payload safely | |
local payload=$(jq -n \ | |
--arg system "$system_message" \ | |
--arg user "$user_message" \ | |
--arg model "$MODEL" \ | |
'{ | |
messages: [ | |
{role: "system", content: $system}, | |
{role: "user", content: $user} | |
], | |
model: $model, | |
stream: false, | |
temperature: 0 | |
}') | |
# Send request to Grok API | |
response=$(curl -s -X POST "$API_URL" \ | |
-H "Content-Type: application/json" \ | |
-H "Authorization: Bearer $API_KEY" \ | |
-d "$payload") | |
# Extract the response | |
answer=$(echo "$response" | jq -r '.choices[0].message.content' 2>/dev/null || echo "Error parsing response: $response") | |
echo "$answer" | |
# Update context with this interaction | |
CONTEXT="$CONTEXT\nUser: $prompt\nGrok: $answer" | |
# Save to session file | |
echo -e "=== $(date '+%Y-%m-%d %H:%M:%S') ===\nPrompt: $prompt\nResponse: $answer\n" >> "$SESSION_FILE" | |
} | |
# Function to load previous session | |
load_session() { | |
if [ -f "$SESSION_FILE" ]; then | |
echo "Loading previous session from $SESSION_FILE..." | |
CONTEXT=$(cat "$SESSION_FILE" | grep -v "^===") | |
fi | |
} | |
# Main loop | |
main() { | |
echo "Grok Codebase Query Tool" | |
echo "Source path/file: $SOURCE_PATH" | |
echo "Session file: $SESSION_FILE" | |
echo "Model: $MODEL" | |
echo "API Key: ${API_KEY:0:4}... (truncated for security)" | |
echo "Enter 'exit' to quit" | |
# Compact codebase once at start | |
compact_codebase | |
# Load previous session if exists | |
load_session | |
while true; do | |
echo -n "Enter your prompt: " | |
read -r prompt | |
if [ "$prompt" = "exit" ]; then | |
echo "Saving session and exiting..." | |
break | |
fi | |
if [ -z "$prompt" ]; then | |
echo "Please enter a non-empty prompt." | |
continue | |
fi | |
echo "Querying Grok..." | |
query_grok "$prompt" | |
echo | |
done | |
# Clean up temporary file | |
rm -f "$CODEBASE_FILE" | |
} | |
# Trap Ctrl+C to ensure cleanup | |
trap 'echo "Interrupted. Saving session..."; rm -f "$CODEBASE_FILE"; exit 0' INT | |
# Run the main function | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment