#!/usr/bin/env bash # Minimal Gitea issue API wrapper for the agent loop (Claude side, Linux). # Token is read from a 0600 file and never echoed. Usage: gitea.sh [args] set -euo pipefail set +x GITEA_URL="${GITEA_URL:-https://git.copse.top}" GITEA_REPO="${GITEA_REPO:-root/Jyotisha}" TOKEN_FILE="${JYOTISHA_AGENT_TOKEN_FILE:-$HOME/.config/jyotisha-agent/gitea-token}" API="$GITEA_URL/api/v1/repos/$GITEA_REPO" _token() { [[ -r "$TOKEN_FILE" ]] || { echo "gitea.sh: token file missing: $TOKEN_FILE" >&2; exit 2; } tr -d '[:space:]' < "$TOKEN_FILE" } # _call METHOD PATH [JSON_BODY] — prints the response body; fails on HTTP >= 400 # without echoing request headers. _call() { local method="$1" path="$2" body="${3:-}" out code out="$(mktemp)" if [[ -n "$body" ]]; then code="$(curl -sS -o "$out" -w '%{http_code}' -X "$method" \ -H "Authorization: token $(_token)" -H 'Content-Type: application/json' \ --data-binary "$body" "$API$path")" else code="$(curl -sS -o "$out" -w '%{http_code}' -X "$method" \ -H "Authorization: token $(_token)" "$API$path")" fi if [[ "$code" -ge 400 ]]; then echo "gitea.sh: $method $path -> HTTP $code: $(head -c 300 "$out")" >&2 rm -f "$out" return 1 fi cat "$out" rm -f "$out" } cmd="${1:-}"; shift || true case "$cmd" in whoami) curl -sS -H "Authorization: token $(_token)" "$GITEA_URL/api/v1/user" | jq -r .login ;; label-id) # label-id NAME _call GET "/labels?limit=100" | jq -r --arg n "$1" '.[] | select(.name == $n) | .id' ;; ensure-label) # ensure-label NAME COLOR DESCRIPTION if [[ -z "$("$0" label-id "$1")" ]]; then _call POST "/labels" "$(jq -nc --arg n "$1" --arg c "$2" --arg d "$3" '{name:$n,color:$c,description:$d}')" | jq -r '"created \(.name)"' else echo "exists $1" fi ;; issues) # issues LABEL — open issues carrying LABEL, oldest first, as JSON array _call GET "/issues?state=open&type=issues&limit=50&labels=$(jq -rn --arg l "$1" '$l|@uri')" \ | jq -c 'sort_by(.created_at)' ;; issue) # issue N _call GET "/issues/$1" ;; labels) # labels N — label names on issue N, one per line _call GET "/issues/$1/labels" | jq -r '.[].name' ;; add-label) # add-label N NAME _call POST "/issues/$1/labels" "$(jq -nc --arg n "$2" '{labels:[$n]}')" >/dev/null ;; remove-label) # remove-label N NAME (no-op when absent) id="$("$0" label-id "$2")" [[ -n "$id" ]] && _call DELETE "/issues/$1/labels/$id" >/dev/null || true ;; comments) # comments N — JSON array _call GET "/issues/$1/comments" ;; comment) # comment N FILE — post FILE's content as a comment _call POST "/issues/$1/comments" "$(jq -Rsc '{body:.}' < "$2")" >/dev/null ;; create-issue) # create-issue TITLE FILE — prints the new issue number _call POST "/issues" "$(jq -Rsc --arg t "$1" '{title:$t, body:.}' < "$2")" | jq -r .number ;; close) # close N _call PATCH "/issues/$1" '{"state":"closed"}' >/dev/null ;; *) echo "usage: gitea.sh whoami|label-id|ensure-label|issues|issue|labels|add-label|remove-label|comments|comment|create-issue|close" >&2 exit 64 ;; esac