Last active
June 26, 2025 06:29
-
-
Save 0x4007/35ef0327725d28f303cbf2bacd234766 to your computer and use it in GitHub Desktop.
Perplexity search `?` and Claude `??` for terminal intelligence. Also `git init` will automatically create a new GitHub repository.
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/env bash | |
| # Function to query Perplexity API with session-based conversation history | |
| perplexity_chat() { | |
| # Check if API key is set | |
| if [ -z "$PERPLEXITY_API_KEY" ]; then | |
| echo "Error: PERPLEXITY_API_KEY environment variable is not set" | |
| return 1 | |
| fi | |
| # Check if input is provided | |
| if [ $# -eq 0 ]; then | |
| echo "Usage: perplexity_chat <your question>" | |
| return 1 | |
| fi | |
| # Combine all arguments into a single prompt | |
| local prompt="$*" | |
| # Create session directory if it doesn't exist | |
| local session_dir="$HOME/.perplexity_sessions" | |
| mkdir -p "$session_dir" | |
| # Generate unique session ID with fallback options | |
| local session_id | |
| if [ -n "$TERM_SESSION_ID" ]; then | |
| # Use terminal session ID (best for VSCode and modern terminals) | |
| session_id=$(echo "$TERM_SESSION_ID" | tr ':' '_') | |
| elif [ -n "$BASHPID" ]; then | |
| # Fallback to bash process ID | |
| session_id="$BASHPID" | |
| else | |
| # Final fallback to current shell PID | |
| session_id="$$" | |
| fi | |
| local session_file="$session_dir/session_${session_id}.json" | |
| # Initialize session file if it doesn't exist | |
| if [ ! -f "$session_file" ]; then | |
| echo '{"messages": []}' > "$session_file" | |
| fi | |
| # Load existing conversation history | |
| local existing_messages | |
| existing_messages=$(cat "$session_file" | jq -r '.messages') | |
| # Build messages array with system message, history, and current user message | |
| local timestamp | |
| timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
| local messages_array | |
| messages_array=$(jq -n \ | |
| --argjson existing "$existing_messages" \ | |
| --arg content "$prompt" \ | |
| --arg timestamp "$timestamp" \ | |
| '[ | |
| { "role": "system", "content": "Be precise and concise." } | |
| ] + $existing + [ | |
| { "role": "user", "content": $content, "timestamp": $timestamp } | |
| ]') | |
| local json_request | |
| json_request=$(jq -n \ | |
| --argjson messages "$messages_array" \ | |
| '{ | |
| "model": "sonar", | |
| "messages": $messages, | |
| "max_tokens": 1024, | |
| "temperature": 0.7, | |
| "top_p": 0.9, | |
| "stream": false | |
| }') | |
| echo "Sending request to Perplexity API..." | |
| local json_response | |
| json_response=$(curl --silent \ | |
| --request POST \ | |
| --url https://api.perplexity.ai/chat/completions \ | |
| --header 'accept: application/json' \ | |
| --header "authorization: Bearer $PERPLEXITY_API_KEY" \ | |
| --header 'content-type: application/json' \ | |
| --data "$json_request") | |
| # Check if the response contains an error | |
| if echo "$json_response" | jq -e '.error' >/dev/null; then | |
| echo "API Error:" | |
| echo "$json_response" | jq '.error' | |
| return 1 | |
| fi | |
| # Check if the response is valid JSON with the expected structure | |
| if ! echo "$json_response" | jq -e '.choices[0].message.content' >/dev/null; then | |
| echo "Invalid API response structure:" | |
| echo "$json_response" | |
| return 1 | |
| fi | |
| # Print the full response in debug mode | |
| if [ "$PERPLEXITY_DEBUG" = "true" ]; then | |
| echo "Full API response:" | |
| echo "$json_response" | jq '.' | |
| echo "" | |
| fi | |
| # Extract and print the answer | |
| local answer | |
| answer=$(echo "$json_response" | jq -r '.choices[0].message.content') | |
| # Print answer in bright white | |
| echo -e "\033[97m$answer\033[0m" | |
| echo "" | |
| # Extract and print citations as footnotes, if any | |
| local citations_count | |
| citations_count=$(echo "$json_response" | jq '.citations | length') | |
| if [ "$citations_count" -gt 0 ]; then | |
| echo "References:" | |
| echo "$json_response" | jq -r '.citations[]' | nl -w1 -s'. ' | |
| echo "" | |
| fi | |
| # Save the conversation to session file | |
| local response_timestamp | |
| response_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
| # Add both user message and assistant response to session history | |
| local updated_messages | |
| updated_messages=$(cat "$session_file" | jq \ | |
| --arg user_content "$prompt" \ | |
| --arg user_timestamp "$timestamp" \ | |
| --arg assistant_content "$answer" \ | |
| --arg assistant_timestamp "$response_timestamp" \ | |
| '.messages += [ | |
| { "role": "user", "content": $user_content, "timestamp": $user_timestamp }, | |
| { "role": "assistant", "content": $assistant_content, "timestamp": $assistant_timestamp } | |
| ]') | |
| echo "$updated_messages" > "$session_file" | |
| } | |
| # --- Automatic GitHub Repo Creation on 'git init' --- | |
| git() { | |
| # Store the original arguments | |
| local args=("$@") | |
| # Check if the first argument is 'init' | |
| if [[ "${args[0]}" == "init" ]]; then | |
| echo "--- Intercepting 'git init'..." >&2 | |
| local target_dir_arg="" | |
| # Attempt to find a directory argument for 'git init' | |
| # This is a simplified check; 'git init' itself has more complex parsing. | |
| # We assume if there's a non-option argument after 'init', it's the directory. | |
| if [[ ${#args[@]} -gt 1 ]]; then | |
| for ((i=1; i<${#args[@]}; i++)); do | |
| if [[ ! "${args[$i]}" =~ ^- ]]; then | |
| # Found a potential directory argument | |
| # Take the last non-option argument as the directory | |
| target_dir_arg="${args[$i]}" | |
| fi | |
| done | |
| fi | |
| # Execute the original git init command | |
| command git "${args[@]}" | |
| local init_status=$? | |
| # Proceed only if 'git init' was successful | |
| if [[ $init_status -eq 0 ]]; then | |
| echo "--- 'git init' successful." >&2 | |
| # Determine the repository name and source path | |
| local repo_name | |
| local source_path | |
| local current_dir_abs | |
| current_dir_abs=$(pwd -P) # Get the physical current working directory | |
| if [[ -n "$target_dir_arg" ]]; then | |
| # If a directory was specified for git init (e.g., git init my-project) | |
| # Ensure target_dir_arg is treated as relative to the current_dir_abs if it's not absolute | |
| if [[ "$target_dir_arg" == /* ]]; then # Absolute path | |
| source_path="$target_dir_arg" | |
| else # Relative path | |
| source_path="$current_dir_abs/$target_dir_arg" | |
| fi | |
| repo_name=$(basename "$target_dir_arg") | |
| else | |
| # If 'git init' was run in the current directory (git init) | |
| source_path="$current_dir_abs" | |
| repo_name=$(basename "$current_dir_abs") | |
| fi | |
| # Normalize source_path to be an absolute path to avoid ambiguity for 'gh' | |
| # Although 'gh' with --source=. usually works fine from within the repo dir. | |
| # For 'gh repo create --source <path>', an absolute path is safer if not cd'ing. | |
| # However, 'gh repo create --source=.' is often run from within the new repo dir. | |
| # If 'git init newdir' was run, we should conceptually operate 'within' newdir | |
| # or explicitly tell gh where 'newdir' is. | |
| # The `gh repo create --source` path should be the directory containing the .git folder. | |
| # The `repo_name` is just the name for GitHub. | |
| echo "--- Repo name will be: $repo_name" >&2 | |
| echo "--- Source path for GitHub repo: $source_path" >&2 | |
| # Determine GitHub target (organization detection for ~/repos/) | |
| local github_target="$repo_name" # Default to personal repo | |
| # Check if we're inside ~/repos/ | |
| if [[ "$source_path" == "$HOME/repos/"* ]]; then | |
| # Extract the relative path from ~/repos/ | |
| local relative_path="${source_path#$HOME/repos/}" | |
| # Get the first directory component (organization name) | |
| local org_name="${relative_path%%/*}" | |
| # If there's actually an org directory (not directly in ~/repos/) | |
| if [[ -n "$org_name" && "$org_name" != "$relative_path" ]]; then | |
| github_target="$org_name/$repo_name" | |
| echo "--- Detected organization: $org_name" >&2 | |
| else | |
| echo "--- In ~/repos/ root, defaulting to personal account" >&2 | |
| fi | |
| fi | |
| # Check if gh is available and logged in | |
| if command -v gh >/dev/null && gh auth status >/dev/null 2>&1; then | |
| echo "--- Attempting to create private GitHub repo '$github_target' and set remote 'origin'..." >&2 | |
| # Create the GitHub repo. | |
| # --source="$source_path" tells gh where the local repository files are. | |
| # --remote=origin tells gh to set the local 'origin' remote to the new repo. | |
| # 'gh' will typically run 'git -C <source_path> remote add origin <url>' | |
| if gh repo create "$github_target" --private --source="$source_path" --remote=origin; then | |
| echo "--- Successfully created private GitHub repo '$github_target' and configured remote 'origin'." >&2 | |
| echo "--- Your local repository is initialized and connected to GitHub." >&2 | |
| echo "--- You can now add, commit, and then push your changes (e.g., git add . && git commit -m 'Initial commit' && git push -u origin main)." >&2 | |
| else | |
| # gh repo create can fail for various reasons: | |
| # 1. Repo with the same name already exists on GitHub. | |
| # 2. Permissions issues with 'gh' or GitHub. | |
| # 3. Network issues. | |
| # 4. '--source' path doesn't exist or isn't a git repo (shouldn't happen if 'git init' succeeded). | |
| echo "--- NOTICE: Failed to automatically create GitHub repo '$github_target' or set remote." >&2 | |
| echo "--- This could be because:" >&2 | |
| echo " 1. The repository '$github_target' already exists on your GitHub account." >&2 | |
| echo " 2. 'gh' encountered an error (e.g., authentication, permissions, network)." >&2 | |
| echo " 3. The local remote 'origin' might already exist and point elsewhere, and 'gh' chose not to overwrite it (check 'gh' output)." >&2 | |
| echo "--- Please review any messages from 'gh' above." >&2 | |
| echo "--- Your local repository was initialized. You may need to create the repo on GitHub and/or set the remote 'origin' manually." >&2 | |
| # Example manual commands: | |
| # git remote add origin [email protected]:YOUR_USERNAME/$repo_name.git | |
| # gh repo create YOUR_USERNAME/$repo_name --private (if it doesn't exist yet) | |
| fi | |
| else | |
| echo "--- 'gh' command not found or user not logged in. Cannot automatically create GitHub repo." >&2 | |
| echo "--- Your local repository was initialized. Please create the repo on GitHub and add the remote manually." >&2 | |
| echo "--- Example: git remote add origin [email protected]:YOUR_USERNAME/$repo_name.git" >&2 | |
| fi | |
| # 'git init' itself was successful, so return 0 for the git command part. | |
| # The GitHub automation is an enhancement. | |
| return 0 | |
| else | |
| echo "--- 'git init' command failed with status $init_status." >&2 | |
| return $init_status # Return the error status from 'git init' | |
| fi | |
| else | |
| # Not a 'git init' command, just execute the original git command | |
| command git "$@" | |
| fi | |
| } | |
| # --- End Automatic GitHub Repo Creation --- | |
| alias ?='perplexity_chat' | |
| alias ??='plz' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment