diff --git a/CHANGELOG.md b/CHANGELOG.md index ef124ca..c71f0f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [v0.6.1] - 2026-05-21 + +### Fixes + +- Add `-R, --repo OWNER/NAME` flag to `prs`, `issues`, and `checks` so agents can target any repo without first changing into a clone. Previously every PR / issue subcommand defaulted to `gh`'s cwd-based detection, which silently pointed at the wrong repo when the agent was running in a different working tree — leading to spurious 404s when looking up a PR in a different project. +- `checks -R OWNER/NAME` now falls back to that repo's default branch when `--branch` isn't given, instead of using the local current branch (which has no meaning cross-repo). + ## [v0.6.0] - 2026-05-21 ### Features diff --git a/bin/fledge-github-checks b/bin/fledge-github-checks index f7f19d1..df46fe4 100755 --- a/bin/fledge-github-checks +++ b/bin/fledge-github-checks @@ -8,6 +8,7 @@ set -euo pipefail BRANCH="" JSON=false +REPO_OVERRIDE="" while [ $# -gt 0 ]; do case "$1" in @@ -15,6 +16,10 @@ while [ $# -gt 0 ]; do BRANCH="${2:-}" shift 2 ;; + -R|--repo) + REPO_OVERRIDE="${2:-}" + shift 2 + ;; --json) JSON=true shift @@ -27,13 +32,15 @@ USAGE: fledge github checks [OPTIONS] OPTIONS: - -b, --branch Branch to check (default: current branch) - --json Output raw GitHub API response as JSON - -h, --help Show this help + -b, --branch Branch to check (default: current branch) + -R, --repo Target repo (default: current working repo) + --json Output raw GitHub API response as JSON + -h, --help Show this help EXAMPLES: fledge github checks fledge github checks --branch main + fledge github checks -R CorvidLabs/merlin --branch main fledge github checks --json | jq '.check_runs[].name' EOF exit 0 @@ -50,18 +57,34 @@ if ! command -v gh >/dev/null 2>&1; then exit 127 fi -if [ -z "$BRANCH" ]; then - BRANCH="$(git branch --show-current 2>/dev/null || true)" +# Resolve repo. When -R is set, use that directly; otherwise let gh +# detect from cwd. Branch defaults to the current local branch — that +# only makes sense when REPO_OVERRIDE is empty, but the user can still +# pass --branch explicitly for the cross-repo case. +if [ -n "$REPO_OVERRIDE" ]; then + REPO="$REPO_OVERRIDE" if [ -z "$BRANCH" ]; then - echo "fledge github checks: not on a branch (detached HEAD?). Use --branch ." >&2 - exit 65 + # Fall back to that repo's default branch when no --branch was passed. + BRANCH="$(gh repo view "$REPO" --json defaultBranchRef --jq '.defaultBranchRef.name' 2>/dev/null || true)" + if [ -z "$BRANCH" ]; then + echo "fledge github checks: could not determine default branch for $REPO. Use --branch ." >&2 + exit 65 + fi + fi +else + if [ -z "$BRANCH" ]; then + BRANCH="$(git branch --show-current 2>/dev/null || true)" + if [ -z "$BRANCH" ]; then + echo "fledge github checks: not on a branch (detached HEAD?). Use --branch ." >&2 + exit 65 + fi fi -fi -REPO="$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || true)" -if [ -z "$REPO" ]; then - echo "fledge github checks: could not detect GitHub repo. Run 'gh auth login' and ensure 'origin' points at a GitHub remote." >&2 - exit 1 + REPO="$(gh repo view --json nameWithOwner --jq .nameWithOwner 2>/dev/null || true)" + if [ -z "$REPO" ]; then + echo "fledge github checks: could not detect GitHub repo. Run 'gh auth login' and ensure 'origin' points at a GitHub remote, or pass -R OWNER/NAME." >&2 + exit 1 + fi fi DATA="$(gh api "repos/${REPO}/commits/${BRANCH}/check-runs" 2>/dev/null || true)" diff --git a/bin/fledge-github-issues b/bin/fledge-github-issues index a0eba1d..c187d95 100755 --- a/bin/fledge-github-issues +++ b/bin/fledge-github-issues @@ -15,6 +15,12 @@ BODY="" ASSIGNEE="" JSON=false INCLUDE_COMMENTS=false +REPO="" + +# Splice "${REPO_FLAGS[@]+...}" into each gh sub-call so it inherits +# the user's -R/--repo when set, or stays empty (gh falls back to its +# cwd detection) when not. +REPO_FLAGS=() # First positional arg can be a subcommand. if [ $# -gt 0 ] && [ "${1:0:1}" != "-" ]; then @@ -48,6 +54,7 @@ while [ $# -gt 0 ]; do -a|--assignee) ASSIGNEE="${2:-}"; shift 2;; --json) JSON=true; shift;; --comments) INCLUDE_COMMENTS=true; shift;; + -R|--repo) REPO="${2:-}"; shift 2;; -h|--help) cat <<'EOF' fledge github issues — manage GitHub issues via the gh CLI @@ -100,6 +107,12 @@ if ! command -v gh >/dev/null 2>&1; then exit 127 fi +# Expand --repo into the gh flag form (see fledge-github-prs for the +# rationale on the +-form expansion below). +if [ -n "$REPO" ]; then + REPO_FLAGS=(--repo "$REPO") +fi + case "$ACTION" in view|comment|close|reopen) if [ -z "$NUMBER" ]; then @@ -111,13 +124,13 @@ esac if [ "$ACTION" = "view" ]; then if [ "$JSON" = "true" ]; then - gh issue view "$NUMBER" --json number,title,state,author,body,labels,createdAt,updatedAt,url,assignees + gh issue view "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --json number,title,state,author,body,labels,createdAt,updatedAt,url,assignees else - gh issue view "$NUMBER" + gh issue view "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" fi if [ "$JSON" != "true" ] && [ "$INCLUDE_COMMENTS" = "true" ]; then printf '\n--- Comments ---\n' - gh issue view "$NUMBER" --comments + gh issue view "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --comments fi exit 0 fi @@ -128,26 +141,27 @@ if [ "$ACTION" = "comment" ]; then exit 64 fi if [ "$JSON" = "true" ]; then - URL="$(gh issue comment "$NUMBER" -b "$BODY")" + URL="$(gh issue comment "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" -b "$BODY")" printf '{"url":"%s"}\n' "$URL" else - gh issue comment "$NUMBER" -b "$BODY" + gh issue comment "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" -b "$BODY" fi exit 0 fi if [ "$ACTION" = "close" ]; then - gh issue close "$NUMBER" + gh issue close "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" exit 0 fi if [ "$ACTION" = "reopen" ]; then - gh issue reopen "$NUMBER" + gh issue reopen "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" exit 0 fi if [ "$ACTION" = "create" ]; then ARGS=() + [ -n "$REPO" ] && ARGS+=(--repo "$REPO") [ -n "$TITLE" ] && ARGS+=(--title "$TITLE") [ -n "$BODY" ] && ARGS+=(--body "$BODY") [ -n "$LABEL" ] && ARGS+=(--label "$LABEL") @@ -161,7 +175,9 @@ if [ "$ACTION" = "create" ]; then fi # list -ARGS=(--state "$STATE" --limit "$LIMIT") +ARGS=() +[ -n "$REPO" ] && ARGS+=(--repo "$REPO") +ARGS+=(--state "$STATE" --limit "$LIMIT") if [ -n "$LABEL" ]; then ARGS+=(--label "$LABEL"); fi if [ "$JSON" = "true" ]; then diff --git a/bin/fledge-github-prs b/bin/fledge-github-prs index 5e0c40b..450cadd 100755 --- a/bin/fledge-github-prs +++ b/bin/fledge-github-prs @@ -20,6 +20,12 @@ INCLUDE_DIFF=false INCLUDE_COMMENTS=false MERGE_METHOD="squash" REVIEW_KIND="" +REPO="" + +# When -R/--repo is set, every gh sub-call gets `--repo $REPO` +# appended via REPO_FLAGS. Empty when -R isn't set, so the gh CLI +# falls back to its normal cwd-based repo detection. +REPO_FLAGS=() # ANSI color codes BLUE=$'\033[0;34m' @@ -69,6 +75,7 @@ while [ $# -gt 0 ]; do --approve) REVIEW_KIND="approve"; shift;; --request-changes) REVIEW_KIND="request-changes"; shift;; --comment-review) REVIEW_KIND="comment"; shift;; + -R|--repo) REPO="${2:-}"; shift 2;; -h|--help) cat <<'EOF' fledge github prs — manage GitHub pull requests via the gh CLI @@ -141,6 +148,13 @@ if ! command -v gh >/dev/null 2>&1; then exit 127 fi +# Expand --repo into the gh flag form. Done once here so every action +# branch can splice "${REPO_FLAGS[@]+...}" into its gh invocation +# without re-checking $REPO. +if [ -n "$REPO" ]; then + REPO_FLAGS=(--repo "$REPO") +fi + # All non-list actions except 'create' need a number. case "$ACTION" in view|comment|review|merge|close|reopen) @@ -153,9 +167,9 @@ esac if [ "$ACTION" = "view" ]; then if [ "$JSON" = "true" ]; then - gh pr view "$NUMBER" --json number,title,state,author,body,labels,createdAt,updatedAt,url,baseRefName,headRefName,isDraft,mergeable,statusCheckRollup + gh pr view "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --json number,title,state,author,body,labels,createdAt,updatedAt,url,baseRefName,headRefName,isDraft,mergeable,statusCheckRollup else - gh pr view "$NUMBER" + gh pr view "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" fi # Optional appendices below the main view block. Each section is # gated by its own flag and separated by a blank line so the output @@ -164,11 +178,11 @@ if [ "$ACTION" = "view" ]; then # parsing concatenated streams. if [ "$JSON" != "true" ] && [ "$INCLUDE_COMMENTS" = "true" ]; then printf '\n--- Comments + Reviews ---\n' - gh pr view "$NUMBER" --comments + gh pr view "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --comments fi if [ "$JSON" != "true" ] && [ "$INCLUDE_DIFF" = "true" ]; then printf '\n--- Diff ---\n' - gh pr diff "$NUMBER" + gh pr diff "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" fi exit 0 fi @@ -181,10 +195,10 @@ if [ "$ACTION" = "comment" ]; then if [ "$JSON" = "true" ]; then # gh pr comment prints the comment URL to stdout when -b is used; # wrap that in a tiny JSON shape so callers can parse it uniformly. - URL="$(gh pr comment "$NUMBER" -b "$BODY")" + URL="$(gh pr comment "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" -b "$BODY")" printf '{"url":"%s"}\n' "$URL" else - gh pr comment "$NUMBER" -b "$BODY" + gh pr comment "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" -b "$BODY" fi exit 0 fi @@ -199,6 +213,7 @@ if [ "$ACTION" = "review" ]; then exit 64 fi ARGS=("$NUMBER") + [ -n "$REPO" ] && ARGS+=(--repo "$REPO") case "$REVIEW_KIND" in approve) ARGS+=(--approve);; request-changes) ARGS+=(--request-changes);; @@ -211,20 +226,20 @@ fi if [ "$ACTION" = "merge" ]; then case "$MERGE_METHOD" in - squash) gh pr merge "$NUMBER" --squash;; - merge) gh pr merge "$NUMBER" --merge;; - rebase) gh pr merge "$NUMBER" --rebase;; + squash) gh pr merge "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --squash;; + merge) gh pr merge "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --merge;; + rebase) gh pr merge "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --rebase;; esac exit 0 fi if [ "$ACTION" = "close" ]; then - gh pr close "$NUMBER" + gh pr close "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" exit 0 fi if [ "$ACTION" = "reopen" ]; then - gh pr reopen "$NUMBER" + gh pr reopen "$NUMBER" "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" exit 0 fi @@ -372,6 +387,7 @@ Output only the title and body. No preamble, no meta-commentary." # Build gh pr create argument list ARGS=() + [ -n "$REPO" ] && ARGS+=(--repo "$REPO") [ -n "$TITLE" ] && ARGS+=(--title "$TITLE") [ -n "$BODY" ] && ARGS+=(--body "$BODY") [ -n "$BASE" ] && ARGS+=(--base "$BASE") @@ -387,8 +403,8 @@ fi # list if [ "$JSON" = "true" ]; then - gh pr list --state "$STATE" --limit "$LIMIT" \ + gh pr list "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --state "$STATE" --limit "$LIMIT" \ --json number,title,state,author,createdAt,url,baseRefName,headRefName,isDraft,labels else - gh pr list --state "$STATE" --limit "$LIMIT" + gh pr list "${REPO_FLAGS[@]+"${REPO_FLAGS[@]}"}" --state "$STATE" --limit "$LIMIT" fi diff --git a/plugin.toml b/plugin.toml index 4852284..e22da9d 100644 --- a/plugin.toml +++ b/plugin.toml @@ -1,14 +1,14 @@ [plugin] name = "fledge-plugin-github" -version = "0.6.0" +version = "0.6.1" description = "GitHub commands for fledge — list/view/create/comment/review/merge PRs, list/view/create/comment/close issues, read repo files, view CI checks, and poll for daemon events via the gh CLI" author = "0xLeif" license = "MIT" [[commands]] name = "github" -description = "GitHub commands via the gh CLI. Subcommands: prs (list/view [--diff --comments]/create/comment -b BODY/review --approve|--request-changes|--comment-review -b BODY/merge /close /reopen ), issues (list/view [--comments]/create/comment -b BODY/close /reopen ), repo (view / file [--ref REF] [-R OWNER/NAME]), checks (CI status), poll (daemon event polling)." +description = "GitHub commands via the gh CLI. All subcommands accept -R OWNER/NAME to target any repo (the agent's working dir is otherwise used). Subcommands: prs (list/view [--diff --comments]/create/comment -b BODY/review --approve|--request-changes|--comment-review -b BODY/merge /close /reopen ), issues (list/view [--comments]/create/comment -b BODY/close /reopen ), repo (view / file [--ref REF]), checks (CI status), poll (daemon event polling)." binary = "bin/fledge-github" args = [ - { name = "args", type = "string", required = true, description = "Subcommand and options, e.g. 'prs view 208 --diff', 'prs comment 208 -b \"LGTM\"', 'issues create -t \"Bug\" -b \"...\"', 'repo file CHANGELOG.md -R CorvidLabs/merlin'" }, + { name = "args", type = "string", required = true, description = "Subcommand and options. Pass -R OWNER/NAME to target any repo without changing directory. Examples: 'prs view 5 -R CorvidLabs/corvid-verify --diff', 'prs comment 208 -b \"LGTM\"', 'issues create -R CorvidLabs/merlin -t \"Bug\" -b \"...\"', 'repo file CHANGELOG.md -R CorvidLabs/merlin'" }, ]