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.
cody_chat_md.sh
#!/bin/bash
################################################################################
# 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="" # 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
# -------------------------------------------------------------------------------
# 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." >&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
INITIAL_MESSAGE="$INITIAL_MESSAGE $1"
fi
;;
esac
shift
done
# -------------------------------------------------------------------------------
# Change to the specified working directory, if requested
# -------------------------------------------------------------------------------
if [[ -n "$WORKING_DIR" ]]; then
cd "$WORKING_DIR" || { echo "Failed to cd to '$WORKING_DIR'" >&2; exit 1; }
fi
# -------------------------------------------------------------------------------
# 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
# -------------------------------------------------------------------------------
# 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
# -------------------------------------------------------------------------------
# process_message: send USER_INPUT to Cody, log both sides, and display response
# -------------------------------------------------------------------------------
process_message() {
local USER_INPUT="$1"
# 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")
# Log Cody's reply
{
echo "### Cody"
echo "$CODY_RESPONSE"
echo ""
} >> "$LOG_FILE"
# Print Cody's reply to the console
echo -e "Cody: $CODY_RESPONSE
"
}
# -------------------------------------------------------------------------------
# Handle piped input: read stdin as the initial message and exit
# -------------------------------------------------------------------------------
if [ ! -t 0 ]; then
PIPE_INPUT=$(cat)
if [[ -n "$PIPE_INPUT" ]]; then
# Merge piped text with any positional initial message
INITIAL_MESSAGE="${INITIAL_MESSAGE:+$INITIAL_MESSAGE }$PIPE_INPUT"
process_message "$INITIAL_MESSAGE"
fi
exit 0
fi
# -------------------------------------------------------------------------------
# If an initial message was provided via args, send it now
# -------------------------------------------------------------------------------
if [[ -n "$INITIAL_MESSAGE" ]]; then
process_message "$INITIAL_MESSAGE"
fi
# -------------------------------------------------------------------------------
# Launch interactive chat loop
# -------------------------------------------------------------------------------
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment