diff --git a/skills/herdr-issue/SKILL.md b/skills/herdr-issue/SKILL.md index 8b1790f..f674c1b 100644 --- a/skills/herdr-issue/SKILL.md +++ b/skills/herdr-issue/SKILL.md @@ -9,7 +9,7 @@ description: "Run Gitea issues through Herdr: one Claude agent per issue in its ## 使用者身分 -Gitea 一律以 tea 的預設 login(`tea login list` 中 default 為 true 的那個)操作:`lib.sh` 會取出它並讓所有 tea 呼叫加上 `--login`,避免在 clone 裡 tea 依 remote URL 挑到別的帳號。`start.sh` 也會把該使用者的名稱與 email 設成 worktree 的 git commit 身分。要換人先 `tea login default `,或設 `HERDR_ISSUE_LOGIN`。 +Gitea 一律以 tea 的預設 login(`tea login list` 中 default 為 true 的那個)操作:`lib.sh` 會取出它並讓所有 tea 呼叫加上 `--login`,避免在 clone 裡 tea 依 remote URL 挑到別的帳號。`start.sh` 也會把該使用者的名稱與 email 設成 worktree 的 git commit 身分。git 走 HTTPS 的帳密由 `scripts/git-credential.sh`(git credential helper)提供,用同一個 login 的 token:腳本內的 git 自動套用,`start.sh` 也會把它寫進 clone 的本地設定(只對該 Gitea 主機),所以 agent 在 worktree 裡 push/fetch 不會再出現 `could not read Username`。要換人先 `tea login default `,或設 `HERDR_ISSUE_LOGIN`。 ## 語言規則 diff --git a/skills/herdr-issue/scripts/git-credential.sh b/skills/herdr-issue/scripts/git-credential.sh new file mode 100755 index 0000000..8f563f3 --- /dev/null +++ b/skills/herdr-issue/scripts/git-credential.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# git credential helper:用 tea 預設 login 的帳號與 token 回應 HTTPS 認證,避免 git 要互動輸入帳密 +# ("could not read Username ... No such device or address")。只處理 get,且只回應該 login 的主機。 +[ "${1:-}" = get ] || exit 0 +exec python3 -c ' +import os, sys +req = dict(l.split("=", 1) for l in sys.stdin.read().splitlines() if "=" in l) +cfg = os.path.join(os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser("~/.config"), "tea", "config.yml") +logins, cur = [], None +for line in open(cfg): + s = line.strip() + if s.startswith("- name:"): + cur = {"name": s.split(":", 1)[1].strip()}; logins.append(cur) + elif cur is not None and ":" in s: + k, v = s.split(":", 1) + if k in ("url", "token", "user", "default"): cur[k] = v.strip().strip("\"\x27") +want = os.environ.get("HERDR_ISSUE_LOGIN") +pick = next((l for l in logins if l["name"] == want), None) if want else None +pick = pick or next((l for l in logins if l.get("default") == "true"), None) +if not pick or not pick.get("token"): sys.exit(0) +host = pick["url"].split("://", 1)[-1].rstrip("/") +if req.get("host") != host: sys.exit(0) +print("username=" + pick["user"]); print("password=" + pick["token"]) +' diff --git a/skills/herdr-issue/scripts/lib.sh b/skills/herdr-issue/scripts/lib.sh index 5b2ce15..beb96e5 100755 --- a/skills/herdr-issue/scripts/lib.sh +++ b/skills/herdr-issue/scripts/lib.sh @@ -19,6 +19,10 @@ print(next((l['name'] for l in json.load(sys.stdin) if str(l.get('default')).low fi [ -n "$HERDR_ISSUE_LOGIN" ] || { echo "herdr-issue: tea 沒有預設 login,請先 tea login default " >&2; exit 1; } export HERDR_ISSUE_LOGIN + +# git 走 HTTPS 時沒有帳密又不能互動輸入會失敗,所以腳本內的 git 一律用 tea 預設 login 的 token(git-credential.sh)。 +export GIT_TERMINAL_PROMPT=0 +git() { command git -c credential.helper= -c "credential.helper=$SCRIPTS/git-credential.sh" "$@"; } # TLS/憑證錯誤多半是暫時的(連線被重置、代理、時鐘),遇到就重試幾次,不要讓輪詢中的腳本因此中斷; # 其他錯誤原樣回傳。不關閉憑證驗證。重試次數 HERDR_ISSUE_TLS_RETRIES(預設 5),間隔 3 秒。 tea() { diff --git a/skills/herdr-issue/scripts/start.sh b/skills/herdr-issue/scripts/start.sh index 6db3fa3..babf093 100755 --- a/skills/herdr-issue/scripts/start.sh +++ b/skills/herdr-issue/scripts/start.sh @@ -60,6 +60,11 @@ fi GIT_USER="$(command tea login list --output json | jq_py "print(next((l['user'] for l in d if l['name']=='$HERDR_ISSUE_LOGIN'),''))")" GIT_EMAIL="$(tea api "/user" | jq_py 'print(d.get("email") or "")' 2>/dev/null || true)" git -C "$CLONE" config extensions.worktreeConfig true +# agent 在 worktree 裡自己跑的 git(push、fetch)也要有帳密:把 helper 設到 clone 的本地設定(worktree 共用),只對這個主機生效 +GIT_HOST_URL="$(command tea login list --output json | jq_py "print(next((l['url'] for l in d if l['name']=='$HERDR_ISSUE_LOGIN'),''))")" +if [ -n "$GIT_HOST_URL" ]; then + git -C "$CLONE" config --local --replace-all "credential.$GIT_HOST_URL.helper" "$SCRIPTS/git-credential.sh" +fi git -C "$WT" config --worktree user.name "$GIT_USER" [ -z "$GIT_EMAIL" ] || git -C "$WT" config --worktree user.email "$GIT_EMAIL"