Skip to content

Instantly share code, notes, and snippets.

@parallaxisjones
Last active April 25, 2025 17:36
Show Gist options
  • Save parallaxisjones/872ad411fa0c3d9fe5c1dc67a9dedb14 to your computer and use it in GitHub Desktop.
Save parallaxisjones/872ad411fa0c3d9fe5c1dc67a9dedb14 to your computer and use it in GitHub Desktop.

Revisions

  1. parallaxisjones revised this gist Apr 25, 2025. 1 changed file with 95 additions and 32 deletions.
    127 changes: 95 additions & 32 deletions cody_chat_md.sh
    Original file line number Diff line number Diff line change
    @@ -1,37 +1,81 @@
    #!/bin/bash

    # Define log directory
    ################################################################################
    # chat.sh — A wrapper around the Cody CLI to log chat sessions.
    #
    # Setup:
    # 1. Install the Cody CLI via npm:
    # npm install -g @cody/cli
    # 2. Authenticate through your company portal:
    # Visit your MyApps portal and complete the login flow for Cody.
    # 3. Generate a new API token in the portal and copy it.
    # 4. Export the token as an environment variable:
    # export CODY_AUTH_TOKEN="<your_token>"
    # Or pass it directly to the CLI:
    # cody chat --token "$CODY_AUTH_TOKEN" ...
    #
    # Usage:
    # chat.sh [options] [initial_message]
    #
    # Options:
    # -C, --dir <directory> Change to <directory> before starting chat.
    # --session <name> Use <name> (sanitized) as the session logfile.
    # initial_message Send this as the first message to Cody.
    # --token <token> Pass your API token explicitly for this session.
    #
    # If no session name is provided, a timestamped file will be created under:
    # $HOME/dev/chat/log/chat_<YYYYMMDD_HHMMSS>.md
    #
    # In piped mode (echo "hello" | chat.sh), stdin is read as the initial message
    # and the script exits after one interaction. Otherwise it launches an
    # interactive loop; type `exit` to quit.
    ################################################################################

    # Define log directory and ensure it exists
    LOG_DIR="$HOME/dev/chat/log"
    mkdir -p "$LOG_DIR"

    # Initialize variables
    WORKING_DIR=""
    SESSION_NAME=""
    INITIAL_MESSAGE=""
    CONTEXT_ARGS=()
    WORKING_DIR="" # Optional: Change to this directory before chat
    SESSION_NAME="" # Optional: Custom session name (sanitized)
    INITIAL_MESSAGE="" # Optional: First message to send to Cody
    TOKEN_PARAM=() # Optional: --token flag for CLI
    CONTEXT_ARGS=() # Will hold --context-file if context.md exists

    # Function to sanitize session name for filename
    # -------------------------------------------------------------------------------
    # sanitize_filename: strip out all but alphanumeric, dash, underscore; lower-case
    # -------------------------------------------------------------------------------
    sanitize_filename() {
    echo "$1" | tr -cd '[:alnum:]_-' | tr '[:upper:]' '[:lower:]'
    }

    # -------------------------------------------------------------------------------
    # Parse command-line arguments
    # -------------------------------------------------------------------------------
    while [[ $# -gt 0 ]]; do
    case "$1" in
    -C|--dir)
    # Change working directory before chat
    shift
    if [[ -d "$1" ]]; then
    WORKING_DIR="$1"
    else
    echo "Error: Directory '$1' does not exist."
    echo "Error: Directory '$1' does not exist." >&2
    exit 1
    fi
    ;;
    --session)
    # Provide a custom session name for logfile
    shift
    SESSION_NAME=$(sanitize_filename "$1")
    ;;
    --token)
    # Pass API token explicitly for this run
    shift
    TOKEN_PARAM=(--token "$1")
    ;;
    *)
    # Anything else is treated as (part of) the initial message
    if [[ -z "$INITIAL_MESSAGE" ]]; then
    INITIAL_MESSAGE="$1"
    else
    @@ -42,65 +86,84 @@ while [[ $# -gt 0 ]]; do
    shift
    done

    # Change to the specified working directory if provided
    # -------------------------------------------------------------------------------
    # Change to the specified working directory, if requested
    # -------------------------------------------------------------------------------
    if [[ -n "$WORKING_DIR" ]]; then
    cd "$WORKING_DIR" || exit 1
    cd "$WORKING_DIR" || { echo "Failed to cd to '$WORKING_DIR'" >&2; exit 1; }
    fi

    # Determine log file path
    # -------------------------------------------------------------------------------
    # Determine the logfile path
    # -------------------------------------------------------------------------------
    if [[ -n "$SESSION_NAME" ]]; then
    # Use sanitized session name
    LOG_FILE="$LOG_DIR/${SESSION_NAME}.md"
    else
    # Fallback to timestamped name
    TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
    LOG_FILE="$LOG_DIR/chat_$TIMESTAMP.md"
    fi

    # Check for context.md in the current directory
    # -------------------------------------------------------------------------------
    # If there's a context.md file, pass it to Cody for continuity
    # -------------------------------------------------------------------------------
    CONTEXT_FILE="./context.md"
    if [[ -f "$CONTEXT_FILE" ]]; then
    CONTEXT_ARGS=(--context-file "$CONTEXT_FILE")
    fi

    # Function to process and log messages
    # -------------------------------------------------------------------------------
    # process_message: send USER_INPUT to Cody, log both sides, and display response
    # -------------------------------------------------------------------------------
    process_message() {
    local USER_INPUT="$1"
    echo "### You" >> "$LOG_FILE"
    echo "$USER_INPUT" >> "$LOG_FILE"
    echo "" >> "$LOG_FILE"

    # Get Cody's response
    CODY_RESPONSE=$(cody chat "${CONTEXT_ARGS[@]}" -m "$USER_INPUT")
    # Log user's message
    {
    echo "### You"
    echo "$USER_INPUT"
    echo ""
    } >> "$LOG_FILE"

    # Invoke Cody CLI
    CODY_RESPONSE=$(cody chat "${CONTEXT_ARGS[@]}" "${TOKEN_PARAM[@]}" -m "$USER_INPUT")

    echo "### Cody" >> "$LOG_FILE"
    echo "$CODY_RESPONSE" >> "$LOG_FILE"
    echo "" >> "$LOG_FILE"
    # Log Cody's reply
    {
    echo "### Cody"
    echo "$CODY_RESPONSE"
    echo ""
    } >> "$LOG_FILE"

    # Display Cody's response
    echo -e "Cody: $CODY_RESPONSE\n"
    # Print Cody's reply to the console
    echo -e "Cody: $CODY_RESPONSE
    "
    }

    # If there's data on STDIN (i.e. piped input), read it as the initial message
    # -------------------------------------------------------------------------------
    # Handle piped input: read stdin as the initial message and exit
    # -------------------------------------------------------------------------------
    if [ ! -t 0 ]; then
    PIPE_INPUT=$(cat)
    if [[ -n "$PIPE_INPUT" ]]; then
    # merge with any - positional args
    if [[ -n "$INITIAL_MESSAGE" ]]; then
    INITIAL_MESSAGE="$INITIAL_MESSAGE $PIPE_INPUT"
    else
    INITIAL_MESSAGE="$PIPE_INPUT"
    fi
    # Merge piped text with any positional initial message
    INITIAL_MESSAGE="${INITIAL_MESSAGE:+$INITIAL_MESSAGE }$PIPE_INPUT"
    process_message "$INITIAL_MESSAGE"
    fi
    # in piped mode, exit after processing
    exit 0
    fi

    # Process the initial message if provided via args
    # -------------------------------------------------------------------------------
    # If an initial message was provided via args, send it now
    # -------------------------------------------------------------------------------
    if [[ -n "$INITIAL_MESSAGE" ]]; then
    process_message "$INITIAL_MESSAGE"
    fi

    # Start interactive chat session
    # -------------------------------------------------------------------------------
    # Launch interactive chat loop
    # -------------------------------------------------------------------------------
    echo "Starting Cody chat session. Type 'exit' to end."
    while true; do
    read -rp "You: " USER_INPUT
  2. parallaxisjones renamed this gist Apr 25, 2025. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. parallaxisjones created this gist Apr 25, 2025.
    112 changes: 112 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,112 @@
    #!/bin/bash

    # Define log directory
    LOG_DIR="$HOME/dev/chat/log"
    mkdir -p "$LOG_DIR"

    # Initialize variables
    WORKING_DIR=""
    SESSION_NAME=""
    INITIAL_MESSAGE=""
    CONTEXT_ARGS=()

    # Function to sanitize session name for filename
    sanitize_filename() {
    echo "$1" | tr -cd '[:alnum:]_-' | tr '[:upper:]' '[:lower:]'
    }

    # Parse command-line arguments
    while [[ $# -gt 0 ]]; do
    case "$1" in
    -C|--dir)
    shift
    if [[ -d "$1" ]]; then
    WORKING_DIR="$1"
    else
    echo "Error: Directory '$1' does not exist."
    exit 1
    fi
    ;;
    --session)
    shift
    SESSION_NAME=$(sanitize_filename "$1")
    ;;
    *)
    if [[ -z "$INITIAL_MESSAGE" ]]; then
    INITIAL_MESSAGE="$1"
    else
    INITIAL_MESSAGE="$INITIAL_MESSAGE $1"
    fi
    ;;
    esac
    shift
    done

    # Change to the specified working directory if provided
    if [[ -n "$WORKING_DIR" ]]; then
    cd "$WORKING_DIR" || exit 1
    fi

    # Determine log file path
    if [[ -n "$SESSION_NAME" ]]; then
    LOG_FILE="$LOG_DIR/${SESSION_NAME}.md"
    else
    TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
    LOG_FILE="$LOG_DIR/chat_$TIMESTAMP.md"
    fi

    # Check for context.md in the current directory
    CONTEXT_FILE="./context.md"
    if [[ -f "$CONTEXT_FILE" ]]; then
    CONTEXT_ARGS=(--context-file "$CONTEXT_FILE")
    fi

    # Function to process and log messages
    process_message() {
    local USER_INPUT="$1"
    echo "### You" >> "$LOG_FILE"
    echo "$USER_INPUT" >> "$LOG_FILE"
    echo "" >> "$LOG_FILE"

    # Get Cody's response
    CODY_RESPONSE=$(cody chat "${CONTEXT_ARGS[@]}" -m "$USER_INPUT")

    echo "### Cody" >> "$LOG_FILE"
    echo "$CODY_RESPONSE" >> "$LOG_FILE"
    echo "" >> "$LOG_FILE"

    # Display Cody's response
    echo -e "Cody: $CODY_RESPONSE\n"
    }

    # If there's data on STDIN (i.e. piped input), read it as the initial message
    if [ ! -t 0 ]; then
    PIPE_INPUT=$(cat)
    if [[ -n "$PIPE_INPUT" ]]; then
    # merge with any - positional args
    if [[ -n "$INITIAL_MESSAGE" ]]; then
    INITIAL_MESSAGE="$INITIAL_MESSAGE $PIPE_INPUT"
    else
    INITIAL_MESSAGE="$PIPE_INPUT"
    fi
    process_message "$INITIAL_MESSAGE"
    fi
    # in piped mode, exit after processing
    exit 0
    fi

    # Process the initial message if provided via args
    if [[ -n "$INITIAL_MESSAGE" ]]; then
    process_message "$INITIAL_MESSAGE"
    fi

    # Start interactive chat session
    echo "Starting Cody chat session. Type 'exit' to end."
    while true; do
    read -rp "You: " USER_INPUT
    if [[ "$USER_INPUT" == "exit" ]]; then
    echo "Chat session ended."
    break
    fi
    process_message "$USER_INPUT"
    done