feat: 加入 herdr 技能並將 herdr-issue 併入為 gitea-issue #21

Merged
jiantw83 merged 2 commits from feat/herdr into main 2026-10-13 07:42:16 +00:00
14 changed files with 17 additions and 36 deletions
Showing only changes of commit 64c748922b - Show all commits
+1 -6
View File
@@ -18,12 +18,7 @@
{
"name": "herdr",
"source": "./plugins/herdr",
"description": "控制 Herdr 終端多工器(workspace、tab、pane、指令與其他 agent)的技能"
},
{
"name": "herdr-issue",
"source": "./plugins/herdr-issue",
"description": "透過 Herdr 讓 Claude agent 逐一實作 Gitea 議題(每個議題一個 worktree 與 tab)"
"description": "控制 Herdr 終端多工器(workspace、tab、pane、指令與其他 agent),並可透過 gitea-issue 技能逐一實作 Gitea 議題"
}
]
}
+2 -6
View File
@@ -6,8 +6,7 @@ JSC 自用 Claude Code mods。每個 mod 皆可單獨安裝、更新與移除。
| --- | --- |
| [statusbar](plugins/statusbar) | 輸入框上方單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟 |
| [companion](plugins/companion) | 小說角色陪伴:人設注入、語氣、心情與好感、互動記憶、主動關心與待辦,並可用 ingest skill 解析小說建立角色 |
| [herdr](plugins/herdr) | 控制 Herdr 終端多工器的技能(workspace、tab、pane、指令與其他 agent;需 Herdr) |
| [herdr-issue](plugins/herdr-issue) | 透過 Herdr 讓 Claude agent 逐一實作 Gitea 議題,每個議題一個 worktree 與 tab(skill,需 Herdr 與 tea) |
| [herdr](plugins/herdr) | 控制 Herdr 終端多工器的技能(workspace、tab、pane、指令與其他 agent;另含 gitea-issue 技能,逐一實作 Gitea 議題,需 Herdr 與 tea) |
## 安裝
@@ -18,7 +17,6 @@ claude plugin marketplace add https://gitea.jsc.idv.tw/jiantw83/jsc-marketplace.
claude plugin install statusbar@jsc-marketplace
claude plugin install companion@jsc-marketplace
claude plugin install herdr@jsc-marketplace
claude plugin install herdr-issue@jsc-marketplace
```
## 指令
@@ -26,7 +24,7 @@ claude plugin install herdr-issue@jsc-marketplace
- `/statusbar on | off | compact`:切換狀態列
- `/companion status | switch <角色> | off | setup | todo | quiet`:角色陪伴控制(`todo add <內容> [due=YYYY-MM-DDTHH:MM]`、`todo done <編號>`、`quiet [分鐘]`)
- `herdr` skill:提到 Herdr 時自動用於操作 pane、tab、workspace 與其他 agent
- `/herdr-issue:herdr-issue <議題連結>`:交給 Herdr 裡的 Claude agent 實作 Gitea 議題
- `/herdr:gitea-issue <議題連結>`:交給 Herdr 裡的 Claude agent 實作 Gitea 議題
## 更新
@@ -35,7 +33,6 @@ claude plugin marketplace update jsc-marketplace
claude plugin update statusbar@jsc-marketplace
claude plugin update companion@jsc-marketplace
claude plugin update herdr@jsc-marketplace
claude plugin update herdr-issue@jsc-marketplace
```
更新後需重新啟動 Claude Code 才會生效。
@@ -46,7 +43,6 @@ claude plugin update herdr-issue@jsc-marketplace
claude plugin uninstall statusbar@jsc-marketplace
claude plugin uninstall companion@jsc-marketplace
claude plugin uninstall herdr@jsc-marketplace
claude plugin uninstall herdr-issue@jsc-marketplace
claude plugin marketplace remove jsc-marketplace
```
@@ -1,10 +0,0 @@
{
"name": "herdr-issue",
"version": "0.0.1",
"description": "透過 Herdr 讓 Claude agent 逐一實作 Gitea 議題(每個議題一個 worktree 與 tab)",
"license": "MIT",
"skills": "./skills",
"author": {
"name": "JSC"
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "herdr",
"version": "0.0.1",
"description": "控制 Herdr 終端多工器(workspace、tab、pane、指令與其他 agent)的技能",
"version": "0.0.2",
"description": "控制 Herdr 終端多工器(workspace、tab、pane、指令與其他 agent),並可透過 gitea-issue 技能逐一實作 Gitea 議題",
"license": "MIT",
"skills": "./skills",
"author": {
@@ -1,11 +1,11 @@
---
name: herdr-issue
description: "Run Gitea issues through Herdr: one Claude agent per issue in its own worktree and tab, watch the issue to closure, then offer the next unblocked issues. Use only when the user runs /herdr-issue or explicitly asks to drive a Gitea issue or repo link with Herdr."
name: gitea-issue
description: "Run Gitea issues through Herdr: one Claude agent per issue in its own worktree and tab, watch the issue to closure, then offer the next unblocked issues. Use only when the user runs /herdr:gitea-issue or explicitly asks to drive a Gitea issue or repo link with Herdr."
---
# herdr-issue
# gitea-issue
把 Gitea 議題交給 Herdr 裡的 Claude agent 實作。所有確定性的工作都在 `scripts/` 裡,你只在「要做決定」的時刻出手。腳本都要在該 repo 的 clone 裡執行;`S` 代表 `~/.claude/skills/herdr-issue/scripts`。
把 Gitea 議題交給 Herdr 裡的 Claude agent 實作。所有確定性的工作都在 `scripts/` 裡,你只在「要做決定」的時刻出手。腳本都要在該 repo 的 clone 裡執行;`S` 代表 `~/.claude/skills/gitea-issue/scripts`。
## 使用者身分
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# herdr-issue 共用函式。每個腳本都 source 這個檔。
# gitea-issue 共用函式。每個腳本都 source 這個檔。
set -euo pipefail
LABEL="in-progress"
@@ -9,7 +9,7 @@ INTERVAL="${HERDR_ISSUE_INTERVAL:-300}"
MODEL="${HERDR_ISSUE_MODEL:-claude-sonnet-5-5}"
SCRIPTS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
die() { echo "herdr-issue: $*" >&2; exit 1; }
die() { echo "gitea-issue: $*" >&2; exit 1; }
# tea 的預設使用者。在 clone 裡 tea 會依 remote URL 挑第一個符合的 login(可能不是預設的),
# 所以明確取 default 那個 login,所有 tea 呼叫都加 --login。可用 HERDR_ISSUE_LOGIN 覆寫。
@@ -17,7 +17,7 @@ if [ -z "${HERDR_ISSUE_LOGIN:-}" ]; then
HERDR_ISSUE_LOGIN="$(tea login list --output json | python3 -c "import sys,json
print(next((l['name'] for l in json.load(sys.stdin) if str(l.get('default')).lower()=='true'),''))")"
fi
[ -n "$HERDR_ISSUE_LOGIN" ] || { echo "herdr-issue: tea 沒有預設 login,請先 tea login default <name>" >&2; exit 1; }
[ -n "$HERDR_ISSUE_LOGIN" ] || { echo "gitea-issue: tea 沒有預設 login,請先 tea login default <name>" >&2; exit 1; }
export HERDR_ISSUE_LOGIN
# 忽略所有 TLS 檢查:tea 的 insecure 只能寫在設定檔(沒有環境變數),所以把所有 login 設成 insecure: true(冪等);
@@ -39,7 +39,7 @@ tea() {
out="$(command tea "$1" --login "$HERDR_ISSUE_LOGIN" "${@:2}" 2>"$ef")" && rc=0 || rc=$?
err="$(cat "$ef")"
if [ "$rc" -eq 0 ] || ! grep -qiE 'tls|x509|certificate|handshake' <<<"$out$err"; then break; fi
echo "herdr-issue: tea 遇到 TLS/憑證錯誤(第 $try/$max 次),3 秒後重試" >&2
echo "gitea-issue: tea 遇到 TLS/憑證錯誤(第 $try/$max 次),3 秒後重試" >&2
rc=${rc/#0/1}; sleep 3
done
rm -f "$ef"
@@ -125,7 +125,7 @@ raw=sys.stdin.read()
try: d=json.loads(raw)
except Exception: d=None
if not isinstance(d,list):
sys.stderr.write('herdr-issue: 讀取 #$2 的依賴失敗:'+raw.strip()[:300]+'\n'); sys.exit(1)
sys.stderr.write('gitea-issue: 讀取 #$2 的依賴失敗:'+raw.strip()[:300]+'\n'); sys.exit(1)
for i in d:
if i.get('state')=='open':
r=(i.get('repository') or {}).get('full_name','')
@@ -38,7 +38,7 @@ def open_blockers(n):
try: d = json.loads(raw)
except Exception: d = None
if not isinstance(d, list):
sys.exit(f"herdr-issue: 讀取 #{n} 的依賴失敗:{raw.strip()[:300]}")
sys.exit(f"gitea-issue: 讀取 #{n} 的依賴失敗:{raw.strip()[:300]}")
out = []
for i in d:
if i.get("state") != "open": continue
@@ -77,7 +77,7 @@ PROMPT_ERR="$(mktemp)"
if PROMPT_OUT="$(herdr agent prompt "issue-$N" "$PROMPT" --wait --until working --until blocked --timeout 15000 2>"$PROMPT_ERR")"; then
rm -f "$PROMPT_ERR"
else
echo "herdr-issue: 送出提示詞後 agent 沒有反應,已回滾" >&2
echo "gitea-issue: 送出提示詞後 agent 沒有反應,已回滾" >&2
cat "$PROMPT_ERR" >&2; rm -f "$PROMPT_ERR"
rollback
exit 1
@@ -16,7 +16,7 @@ NOTIFIED=false
close_if_done() { # $1=X $2=label
[ "$(issue_state "$REPO" "$1")" = open ] || { echo skip; return; }
if [ "$(open_count_with_label "$REPO" "$2")" = 0 ]; then
tea comment "$1" --repo "$REPO" "底下的議題全部關閉,由 herdr-issue 自動關閉。" >/dev/null
tea comment "$1" --repo "$REPO" "底下的議題全部關閉,由 gitea-issue 自動關閉。" >/dev/null
tea issues close "$1" --repo "$REPO" >/dev/null
echo closed
else