Created
March 27, 2026 20:57
-
-
Save joeyparis/c7e7edaa82b12b2bfcada14eb834e643 to your computer and use it in GitHub Desktop.
Interactive fzf session picker for OpenCode - browse, preview, and resume sessions. Forked from PEMessage/a0f7f299291a6fda9955adf3b1ea54be with input validation hardening.
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
| #!/usr/bin/env bash | |
| set -eu | |
| export LC_ALL=C | |
| # Color support | |
| if [ -t 1 ]; then | |
| FFOP_COLORS="always" | |
| else | |
| FFOP_COLORS="never" | |
| fi | |
| # ANSI color codes | |
| if [ "$FFOP_COLORS" = "always" ]; then | |
| COLOR_ID='\033[1;36m' # Cyan bold | |
| COLOR_TITLE='\033[0m' # Default (no color) | |
| COLOR_TIME='\033[1;32m' # Green bold | |
| COLOR_RESET='\033[0m' | |
| COLOR_NONE='' | |
| FMT_ID='"\033[1;36m"' | |
| FMT_TITLE='"\033[0m"' | |
| FMT_TIME='"\033[1;32m"' | |
| FMT_RESET='"\033[0m"' | |
| FMT_NONE='""' | |
| else | |
| COLOR_ID='' | |
| COLOR_TITLE='' | |
| COLOR_TIME='' | |
| COLOR_RESET='' | |
| COLOR_NONE='' | |
| FMT_ID='""' | |
| FMT_TITLE='""' | |
| FMT_TIME='""' | |
| FMT_RESET='""' | |
| FMT_NONE='""' | |
| fi | |
| format_sessions() { | |
| awk -F'\t' -v home="$HOME" "{ | |
| path = \$2 | |
| gsub(home, \"~\", path) | |
| print $FMT_NONE \$1 $FMT_NONE \"\t\" $FMT_NONE path \"\t\" $FMT_TITLE \$3 $FMT_RESET \"\t\" $FMT_TIME \$4 $FMT_RESET | |
| }" | |
| } | |
| # Get sessions from database | |
| list_sessions() { | |
| opencode db "SELECT id, directory, title, datetime(time_updated / 1000, 'unixepoch') FROM session WHERE title NOT LIKE '%subagent)' ORDER BY time_updated DESC" | tail -n +2 | format_sessions | |
| } | |
| # Validate session ID format (UUID-like: hex chars and dashes) | |
| validate_session_id() { | |
| local id="$1" | |
| if ! [[ "$id" =~ ^[a-zA-Z0-9_-]+$ ]]; then | |
| echo "Invalid session ID format: $id" >&2 | |
| exit 1 | |
| fi | |
| } | |
| # Interactive selection with fzf | |
| interactive_select() { | |
| local preview_window | |
| if [ "${COLUMNS:-80}" -lt 80 ]; then | |
| preview_window="down:50%" | |
| else | |
| preview_window="right:50%" | |
| fi | |
| fzf --ansi \ | |
| --delimiter='\t' \ | |
| --with-nth="{3} {4} @{2}" \ | |
| --preview-window="$preview_window" \ | |
| --preview="$0 session-print {1}" \ | |
| --wrap=word \ | |
| --exit-0 \ | |
| --scheme history \ | |
| --bind 'ctrl-d:preview-half-page-down,ctrl-u:preview-half-page-up,ctrl-g:preview-bottom,ctrl-t:preview-top' \ | |
| --expect=alt-n \ | |
| --header-first \ | |
| --header="[New: Alt-n] [Preview Scroll: Ctrl-d/u] [Jump: Ctrl-g/t]" | |
| } | |
| expand_path() { | |
| local path="$1" | |
| if [[ "$path" == "~"* ]]; then | |
| path="${HOME}${path:1}" | |
| fi | |
| echo "$path" | |
| } | |
| cmd_session() { | |
| local selected | |
| selected="$(list_sessions | interactive_select)" | |
| if [ "$(echo "$selected" | head -n1)" = "alt-n" ] ; then | |
| echo "New opencode session" | |
| opencode | |
| exit 0 | |
| fi | |
| session_id="$(echo "$selected" | cut -f 1 -d $'\t')" | |
| directory="$(echo "$selected" | cut -f 2 -d $'\t')" | |
| if [ -n "$session_id" ]; then | |
| validate_session_id "$session_id" | |
| echo "Select session: $session_id" | |
| echo "Change dir to: $directory" | |
| cd "$(expand_path "$directory")" | |
| opencode -s "$session_id" | |
| else | |
| echo "No session selected" >&2 | |
| exit 1 | |
| fi | |
| } | |
| print_session() { | |
| local session_id="$1" | |
| validate_session_id "$session_id" | |
| RESET='\x1b[0m' | |
| AGENT_COLOR='\x1b[32m' | |
| USER_COLOR='\x1b[36m' | |
| META_COLOR='\x1b[33m' | |
| opencode db " | |
| SELECT data FROM part | |
| WHERE session_id='${session_id}' | |
| AND json_extract(data, '$.type') = 'text' | |
| AND (json_extract(data, '$.synthetic') IS NULL OR json_extract(data, '$.synthetic') = 0) | |
| ORDER BY time_updated | |
| " --format json | | |
| jq -r '.[] | .data | fromjson | if .time != null then "@Agent@: " + .text else "@User@: " + .text end' | | |
| awk -v reset="$RESET" \ | |
| -v agent_color="$AGENT_COLOR" \ | |
| -v user_color="$USER_COLOR" ' | |
| /^@Agent@:/ { | |
| sub(/^@Agent@:/, "") | |
| current_color = agent_color | |
| print reset "---" | |
| printf agent_color "Agent:" reset | |
| print agent_color $0 | |
| next | |
| } | |
| /^@User@:/ { | |
| sub(/^@User@:/, "") | |
| current_color = user_color | |
| print reset "---" | |
| printf user_color "User:" reset | |
| print user_color $0 | |
| next | |
| } | |
| { | |
| # For lines without prefix, use the current_color | |
| print current_color $0 reset | |
| } | |
| ' | |
| opencode db "SELECT * FROM session WHERE id='${session_id}'" --format=json | | |
| awk -v reset="$RESET" \ | |
| -v meta_color="$META_COLOR" ' | |
| { | |
| print meta_color $0 reset | |
| } | |
| ' # awk end | |
| } | |
| cmd_session_print() { | |
| local session_id="${1:-}" | |
| if [ -z "$session_id" ]; then | |
| echo "Usage: $0 session-print <session-id>" >&2 | |
| echo "Get session info from fzf: $0 session-print \$(opencode session | cut -f1)" >&2 | |
| exit 1 | |
| fi | |
| print_session "$session_id" | |
| } | |
| main() { | |
| local cmd="${1:-session}" | |
| case "$cmd" in | |
| session) | |
| cmd_session | |
| ;; | |
| session-print) | |
| cmd_session_print "${2:-}" | |
| ;; | |
| *) | |
| echo "Unknown command: $cmd" >&2 | |
| echo "Run '$0 help' for usage information" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment