| #!/usr/bin/env bash | | | | | | | | | | | | | | | set -euo pipefail | | | | HERDR_BIN="${HERDR_BIN:-herdr}" | | | | TABS=( | | "π€ agent" | | "π editor" | | "πΏ changes" | | "π diff" | | "π run" | | "π₯οΈ term" | | ) | | | | | | | if [ -t 1 ]; then | | BOLD="$(printf '\033[1m')" | | DIM="$(printf '\033[2m')" | | RED="$(printf '\033[31m')" | | GREEN="$(printf '\033[32m')" | | YELLOW="$(printf '\033[33m')" | | BLUE="$(printf '\033[34m')" | | MAGENTA="$(printf '\033[35m')" | | CYAN="$(printf '\033[36m')" | | RESET="$(printf '\033[0m')" | | else | | BOLD="" | | DIM="" | | RED="" | | GREEN="" | | YELLOW="" | | BLUE="" | | MAGENTA="" | | CYAN="" | | RESET="" | | fi | | | | say() { | | printf '%b\n' "$" | | } | | | | die() { | | say "${RED}π₯ error:${RESET} $" >&2 | | exit 1 | | } | | | | ok() { | | say "${GREEN}β${RESET} $" | | } | | | | info() { | | say "${CYAN}β${RESET} $" | | } | | | | warn() { | | say "${YELLOW}β ${RESET} $*" | | } | | | | | | | need_cmd() { | | command -v "$1" >/dev/null 2>&1 || die "missing command: $1" | | } | | | | repo_root() { | | git rev-parse --show-toplevel 2>/dev/null | | } | | | | workspace_name_for_repo() { | | local root="$1" | | local repo parent | | | | repo="$(basename "$root")" | | parent="$(basename "$(dirname "$root")")" | | | | | | | echo "$parent/$repo" | | } | | | | workspace_id_by_label() { | | local label="$1" | | local raw id | | | | raw="$($HERDR_BIN workspace list 2>/dev/null || true)" | | [ -n "$raw" ] || return 1 | | | | id="$(printf '%s\n' "$raw" | jq -er --arg label "$label" ' | | def items: | | if type == "array" then . | | elif type == "object" then (.result.workspaces // .workspaces // .result // []) | | else [] end; | | | | items[] | | | select(type == "object") | | | select((.label // .name // .title) == $label) | | | (.workspace_id // .id) | | | select(. != null and . != "") | | ' 2>/dev/null | head -n1 || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | | id="$(printf '%s\n' "$raw" | | | awk -v want="$label" ' | | index($0, want) { | | for (i = 1; i <= NF; i++) { | | if ($i ~ /^w[[:alnum:]]+$/ || $i ~ /[1]+(:[0-9]+)?(-[0-9]+)?$/) { | | print $i | | found = 1 | | exit 0 | | } | | } | | } | | END { if (!found) exit 1 } | | ' || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | return 1 | | } | | | | tab_id_by_label() { | | local workspace_id="$1" | | local label="$2" | | local raw id | | | | raw="$($HERDR_BIN tab list --workspace "$workspace_id" 2>/dev/null || true)" | | [ -n "$raw" ] || return 1 | | | | id="$(printf '%s\n' "$raw" | jq -er --arg label "$label" ' | | def items: | | if type == "array" then . | | elif type == "object" then (.result.tabs // .tabs // .result // []) | | else [] end; | | | | items[] | | | select(type == "object") | | | select((.label // .name // .title) == $label) | | | (.tab_id // .id) | | | select(. != null and . != "") | | ' 2>/dev/null | head -n1 || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | | id="$(printf '%s\n' "$raw" | | | awk -v want="$label" ' | | index($0, want) { | | for (i = 1; i <= NF; i++) { | | if ($i ~ /^w[[:alnum:]]+:t[[:alnum:]]+$/ || $i ~ /[2]+:[0-9]+$/ || $i ~ /[3]+$/) { | | print $i | | found = 1 | | exit 0 | | } | | } | | } | | END { if (!found) exit 1 } | | ' || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | return 1 | | } | | initial_tab_id() { | | local workspace_id="$1" | | local raw id | | | | raw="$($HERDR_BIN tab list --workspace "$workspace_id" 2>/dev/null || true)" | | [ -n "$raw" ] || return 1 | | | | id="$(printf '%s\n' "$raw" | jq -er ' | | def items: | | if type == "array" then . | | elif type == "object" then (.result.tabs // .tabs // .result // []) | | else [] end; | | | | items[] | | | select(type == "object") | | | select((.label // .name // .title) == "1" or (.label // .name // .title) == "") | | | (.tab_id // .id) | | | select(. != null and . != "") | | ' 2>/dev/null | head -n1 || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | return 1 | | } | | | | pane_id_by_tab_id() { | | local workspace_id="$1" | | local tab_id="$2" | | local raw id | | | | raw="$($HERDR_BIN pane list --workspace "$workspace_id" --tab "$tab_id" 2>/dev/null || true)" | | [ -n "$raw" ] || return 1 | | | | id="$(printf '%s\n' "$raw" | jq -er ' | | def items: | | if type == "array" then . | | elif type == "object" then (.result.panes // .panes // .result // []) | | else [] end; | | | | items[] | | | select(type == "object") | | | (.pane_id // .id) | | | select(. != null and . != "") | | ' 2>/dev/null | head -n1 || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | | id="$(printf '%s\n' "$raw" | | | awk ' | | { | | for (i = 1; i <= NF; i++) { | | if ($i ~ /^w[[:alnum:]]+:t[[:alnum:]]+:p[[:alnum:]]+$/ || $i ~ /[4]+-[0-9]+$/ || $i ~ /[5]+$/) { | | print $i | | found = 1 | | exit 0 | | } | | } | | } | | END { if (!found) exit 1 } | | ' || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | return 1 | | } | | | | pane_id_from_create_tab_response() { | | local raw="$1" | | local id | | [ -n "$raw" ] || return 1 | | | | id="$(printf '%s\n' "$raw" | jq -er ' | | def pane_id_from($x): | | if ($x | type) == "object" then ($x.pane_id // $x.id // empty) | | else empty end; | | | | . as $root | | | (.result // {}) as $result | | | ( | | pane_id_from($result.root_pane), | | pane_id_from($result.pane), | | pane_id_from($result.active_pane), | | pane_id_from($result.created_pane), | | pane_id_from($root.root_pane), | | pane_id_from($root.pane), | | ($result.panes // $result.tab.panes // $root.panes // $root.tab.panes // [] | .[]? | pane_id_from(.)) | | ) | | | select(. != null and . != "") | | ' 2>/dev/null | head -n1 || true)" | | | | if [ -n "$id" ]; then | | printf '%s\n' "$id" | | return 0 | | fi | | | | return 1 | | } | | | | | | | create_workspace() { | | local label="$1" | | local cwd="$2" | | | | "$HERDR_BIN" workspace create --cwd "$cwd" --label "$label" | | } | | | | focus_workspace() { | | local workspace_id="$1" | | "$HERDR_BIN" workspace focus "$workspace_id" | | } | | | | create_tab() { | | local workspace_id="$1" | | local label="$2" | | | | "$HERDR_BIN" tab create --workspace "$workspace_id" --label "$label" --no-focus | | } | | rename_tab() { | | local tab_id="$1" | | local label="$2" | | | | "$HERDR_BIN" tab rename "$tab_id" "$label" | | } | | | | close_tab() { | | local tab_id="$1" | | | | "$HERDR_BIN" tab close "$tab_id" | | } | | | | run_in_pane() { | | local pane_id="$1" | | local command="$2" | | | | "$HERDR_BIN" pane run "$pane_id" "$command" | | } | | | | split_pane_horizontal() { | | local pane_id="$1" | | local output="" | | | | | if output="$($HERDR_BIN pane split "$pane_id" --direction down --no-focus 2>&1)"; then | | return 0 | | fi | | | | if output="$($HERDR_BIN pane split --pane "$pane_id" --direction down --no-focus 2>&1)"; then | | return 0 | | fi | | | | if output="$($HERDR_BIN pane split "$pane_id" down 2>&1)"; then | | return 0 | | fi | | | | warn "could not split runner pane horizontally: $output" | | return 1 | | } | | | | shell_command() { | | local root="$1" | | local label="$2" | | | | printf "cd '%s' && clear && printf 'π %%s\nπ %%s\n\n' '%s' '%s' && exec %s" \ | | "$root" "$label" "$root" "${SHELL:-/bin/bash}" | | } | | | | omp_command() { | | local root="$1" | | local label="$2" | | | | if command -v omp >/dev/null 2>&1; then | | printf "cd '%s' && omp" "$root" | | else | | printf "cd '%s' && clear && printf 'π§ %%s\nπ %%s\n\nβ omp not found in PATH\n\n' '%s' '%s' && exec %s" \ | | "$root" "$label" "$root" "${SHELL:-/bin/bash}" | | fi | | } | | | | editor_command() { | | local root="$1" | | | | if command -v nvim >/dev/null 2>&1; then | | printf "cd '%s' && nvim ." "$root" | | elif command -v vim >/dev/null 2>&1; then | | printf "cd '%s' && vim ." "$root" | | else | | printf "cd '%s' && clear && printf 'π editor\nπ %%s\n\nβ nvim not found in PATH\n\n' '%s' && exec %s" \ | | "$root" "$root" "${SHELL:-/bin/bash}" | | fi | | } | | | | git_command() { | | local root="$1" | | | | if command -v lazygit >/dev/null 2>&1; then | | printf "cd '%s' && lazygit" "$root" | | else | | printf "cd '%s' && git status && exec %s" "$root" "${SHELL:-/bin/bash}" | | fi | | } | | | | livediff_command() { | | local root="$1" | | local label="$2" | | | | if command -v livediff >/dev/null 2>&1; then | | printf "cd '%s' && livediff" "$root" | | else | | printf "cd '%s' && clear && printf 'π %%s\nπ %%s\n\nβ livediff not found in PATH\n\n' '%s' '%s' && exec %s" \ | | "$root" "$label" "$root" "${SHELL:-/bin/bash}" | | fi | | } | | | | | | | main() { | | need_cmd git | | need_cmd jq | | need_cmd "$HERDR_BIN" | | | | local root workspace workspace_id created="false" | | | | root="$(repo_root)" || die "not inside a git repository" | | workspace="$(workspace_name_for_repo "$root")" | | | | say | | say "${BOLD}${MAGENTA}π herd${RESET} ${DIM}summoning repo workspace${RESET}" | | say "${DIM}ββββββββββββββββββββββββββββββββββββββββ${RESET}" | | say "${BLUE}repo:${RESET} $root" | | say "${BLUE}workspace:${RESET} $workspace" | | say | | | | if workspace_id="$(workspace_id_by_label "$workspace" 2>/dev/null)"; then | | ok "workspace exists ${DIM}#$workspace_id${RESET}" | | else | | info "creating workspace" | | create_workspace "$workspace" "$root" >/dev/null | | created="true" | | | | workspace_id="$(workspace_id_by_label "$workspace" 2>/dev/null || true)" | | if [ -z "$workspace_id" ]; then | | warn "workspace created, but could not resolve its id from HerdR" | | warn "using workspace label as fallback: $workspace" | | workspace_id="$workspace" | | fi | | | | ok "workspace created ${DIM}#$workspace_id${RESET}" | | fi | | | | say | | | | local tab tab_id pane_id command response initial_tab | | initial_tab="$(initial_tab_id "$workspace_id" 2>/dev/null || true)" | | | | for tab in "${TABS[@]}"; do | | info "creating tab: ${BOLD}$tab${RESET}" | | response="$(create_tab "$workspace_id" "$tab")" | | pane_id="$(pane_id_from_create_tab_response "$response" 2>/dev/null || true)" | | | | tab_id="$(tab_id_by_label "$workspace_id" "$tab" 2>/dev/null || true)" | | if [ -z "$tab_id" ]; then | | warn "tab created, but could not resolve its id: $tab" | | fi | | | | if [ -z "$pane_id" ] && [ -n "$tab_id" ]; then | | pane_id="$(pane_id_by_tab_id "$workspace_id" "$tab_id" 2>/dev/null || true)" | | fi | | | | if [ -z "$pane_id" ]; then | | warn "tab created, but could not resolve root pane: $tab" | | continue | | fi | | | | command="" | | case "$tab" in | | "π€ agent") | | command="$(omp_command "$root" "$tab")" | | ;; | | "π editor") | | command="$(editor_command "$root")" | | ;; | | "πΏ changes") | | command="$(git_command "$root")" | | ;; | | "π diff") | | command="$(livediff_command "$root" "$tab")" | | ;; | | "π run") | | split_pane_horizontal "$pane_id" || true | | ;; | | *) | | | command="" | | ;; | | esac | | | | if [ -n "$command" ]; then | | run_in_pane "$pane_id" "$command" | | fi | | ok "tab ready: ${BOLD}$tab${RESET}" | | | | done | | | | if [ -n "$initial_tab" ]; then | | if close_tab "$initial_tab" >/dev/null 2>&1; then | | ok "initial tab removed" | | else | | warn "could not remove initial tab: $initial_tab" | | fi | | fi | | | | say | | info "focusing workspace" | | focus_workspace "$workspace_id" | | | | say | | if [ "$created" = "true" ]; then | | say "${GREEN}β¨ herd assembled.${RESET}" | | else | | say "${GREEN}β¨ herd restored.${RESET}" | | fi | | say | | } | | | | main "$@" |
OGX: An Open-Source, Vendor-Neutral Generative AI Application Server