fix(gitea): 寫入前先確認
This commit is contained in:
@@ -31,20 +31,20 @@ gitea.sh hash-id <text> # 產生 8 碼大寫 SHA-1;
|
||||
gitea.sh wiki-repo <TYPE> # 解析頁面類型的 wiki 位置(TYPE = QUESTION / PLAN / ANALYZE / DELIVER / MAINTAIN / REPO / LOG / LEARN / ERROR / CHECK / REPORT / SKILLSET)
|
||||
gitea.sh wiki-list <owner>/<repo>
|
||||
gitea.sh wiki-get <owner>/<repo> <page> # 不存在 exit 4
|
||||
gitea.sh wiki-put <owner>/<repo> <page> <file> # 自動判斷新建或更新
|
||||
gitea.sh wiki-put <owner>/<repo> <page> <file> # 自動判斷新建或更新;會先要求確認
|
||||
gitea.sh wiki-url <owner>/<repo> <page> # 印出 wiki 頁絕對網址(取自 API 的 html_url);跨存取庫連結用
|
||||
gitea.sh pr-create <owner>/<repo> <head> <base> <title> <body-file>
|
||||
gitea.sh pr-create <owner>/<repo> <head> <base> <title> <body-file> # 會先要求確認
|
||||
gitea.sh pr-status <owner>/<repo> <pr-index> # 印出 {state} {merged} {mergeable}
|
||||
gitea.sh pr-get <owner>/<repo> <pr-index> # 印出 PR 的標題、base 分支與描述,供呼叫端比對有沒有差
|
||||
# 前三行固定 title、base、body 三個標記,第 4 行起是描述原文
|
||||
gitea.sh pr-edit <owner>/<repo> <pr-index> <title> <body-file>
|
||||
gitea.sh pr-edit <owner>/<repo> <pr-index> <title> <body-file> # 會先要求確認
|
||||
# 更新 PR 的標題與描述;描述從檔案讀,裝得下多行
|
||||
gitea.sh pr-comments <owner>/<repo> <pr-index> # 印出所有留言(issue 留言、審查評語、行內留言),第三欄帶 #id,依時間排序
|
||||
gitea.sh comment-reply <owner>/<repo> <pr-index> <issue|review|inline> <comment-id> <body-file>
|
||||
gitea.sh comment-reply <owner>/<repo> <pr-index> <issue|review|inline> <comment-id> <body-file> # 會先要求確認
|
||||
# 回覆本輪處理過的 PR 留言;inline 走 review comment reply,其餘補一則 PR 留言
|
||||
gitea.sh pr-depend <owner>/<repo> <pr-index> <dep-owner>/<dep-repo> <dep-index>
|
||||
gitea.sh pr-depend <owner>/<repo> <pr-index> <dep-owner>/<dep-repo> <dep-index> # 會先要求確認
|
||||
# 把 PR 掛上前置 PR 依賴;依賴未關閉前 Gitea 會阻擋合併
|
||||
gitea.sh repo-set <owner>/<repo> <description> [website] # 設定 repo 描述與網頁
|
||||
gitea.sh repo-set <owner>/<repo> <description> [website] # 會先要求確認
|
||||
gitea.sh markdown <file> # markdown 檔渲染成 HTML 片段(走 /markdown/raw)
|
||||
gitea.sh api <METHOD> <path> [json-file]
|
||||
hash-id <text> # 與 gitea.sh hash-id 相同
|
||||
@@ -65,7 +65,7 @@ pr-watch.sh <owner>/<repo> <pr-index> [state-file]
|
||||
gitea-link.sh parse <url> # 解析 wiki 或議題連結;不是這兩種就 exit 3(呼叫端據此中止)
|
||||
issue.sh labels|label-ids|projects <owner>/<repo>
|
||||
issue.sh title|body|labels-of <owner>/<repo> <index>
|
||||
issue.sh create <owner>/<repo> <title> <body-file> [--labels <ids>] [--milestone <id>]
|
||||
issue.sh create <owner>/<repo> <title> <body-file> [--labels <ids>] [--milestone <id>] # 會先要求確認
|
||||
html-style.sh get|set|unset|list|layouts|styles # 種類對版型與風格的設定
|
||||
html-render.sh --markdown <檔案> --title <標題> --out <輸出檔> [--layout] [--style] [--subtitle] [--source-url]
|
||||
```
|
||||
|
||||
@@ -11,7 +11,7 @@ The wiki link is the only input. Everything else — repository, page name, host
|
||||
|
||||
1. **Link gate.** Run `tools/gitea-link.sh parse {url}` on the link the user gave. Exit 3, no link in the request, or `kind=issue` (this skill reads wiki pages, not issues) all mean the same thing: **stop and report which one it was**. Never ask for a repository name instead, and never fall back to the working directory's remote — a page written into the wrong repository's issue tracker is public and hard to take back. Completion condition: `kind=wiki`, and `repo`, `page` and `host` are known.
|
||||
2. Read the page with `jsc-gitea:wiki` (`wiki-get {repo} {page}`). Exit 4 means the page does not exist — stop and report the page name. Take the page's absolute URL from `wiki-url` in the same pass; it goes into the issue body. Completion condition: the page's markdown and its absolute URL are both in hand.
|
||||
3. **Draft the issue — this step MUST run as a sub agent.** Title: the page's first heading, or the page name when it has none. Body: the page content in Traditional Chinese, opening with a 「來源:{絕對網址}」 line so the issue points back at the wiki. Convert `[[display|page]]` links to absolute URLs (`wiki-url`), because `[[...]]` resolves only inside a wiki. Drop personal data — an issue is read by more people than a wiki page. Completion condition: title and body file exist, the body carries the source line, and no `[[...]]` link is left in it.
|
||||
3. **Draft the issue — this step MUST run as a sub agent.** Title: the page's first heading, or the page name when it has none. Body: the page content in Traditional Chinese, opening with a 「來源:{絕對網址}」 line so the issue points back at the wiki. Convert `[[display|page]]` links to absolute URLs (`wiki-url`), because `[[...]]` resolves only inside a wiki. Drop personal data — an issue is read by more people than a wiki page. Write `issue.sh create` 前先確認,因為建立議題本身也會要求確認。Completion condition: title and body file exist, the body carries the source line, and no `[[...]]` link is left in it.
|
||||
4. **Labels come from what the repository already has.** Run `tools/issue.sh labels {repo}`, propose the fitting ones with a reason each, and confirm per `jsc-ask:ask` rules — every option states its impact scope (a label drives filters and board rules, so a wrong one routes the work to the wrong queue). Turn the confirmed names into ids with `tools/issue.sh label-ids`. An empty label list, or nothing fitting: ask whether to create the issue with no label, and record that answer. **Never invent a label that the repository does not have.** Completion condition: the user has confirmed a label set — possibly empty — and its ids are resolved.
|
||||
5. **Project board.** Run `tools/issue.sh projects {repo}`. Exit 3 means this Gitea has no board API: say so plainly, and hand the user the board URL the script printed so they can drag the issue in themselves. A board list comes back: let the user pick one per `jsc-ask:ask` rules, attach it, and report the failure verbatim if the attach call is refused. Completion condition: the issue is either attached to a board, or the report states in one line that the board link is still outstanding and who has to do it.
|
||||
6. Create the issue: `tools/issue.sh create {repo} {title} {body-file} [--labels {ids}]`. Report the `index=` and `url=` it prints. Completion condition: the issue URL is reported to the user, together with the labels applied and the board status from step 5.
|
||||
|
||||
@@ -21,7 +21,7 @@ Different page types can live in different `{owner}/{repo}` repos, classified by
|
||||
| --- | --- |
|
||||
| list pages | `tools/gitea.sh wiki-list {owner}/{repo}` |
|
||||
| read page | `tools/gitea.sh wiki-get {owner}/{repo} {page}` (exit 4 when missing) |
|
||||
| write page | write the content to a temp file first, then `tools/gitea.sh wiki-put {owner}/{repo} {page} {file}` (creates or updates automatically) |
|
||||
| write page | 先寫入暫存檔,再呼叫 `tools/gitea.sh wiki-put {owner}/{repo} {page} {file}`(先確認,再建立或更新) |
|
||||
| page URL | `tools/gitea.sh wiki-url {owner}/{repo} {page}` — the page's absolute URL, taken from the API's `html_url` (exit 4 when the page is missing) |
|
||||
|
||||
When writing a page, link same-type pages with the `[[display|page]]` form (display text on the LEFT) and cross-type pages with the absolute URL from `wiki-url`, because `[[...]]` resolves only inside one wiki. Full rules and the direction trap: `references/wiki-links.md`.
|
||||
@@ -30,7 +30,7 @@ When writing a page, link same-type pages with the `[[display|page]]` form (disp
|
||||
|
||||
1. Page names must follow the wiki naming table in the skill guidelines (see `jsc-meta/references/guidelines.md`).
|
||||
2. Use `tools/hash-id` for `{HASH}` values. It returns the first 8 uppercase SHA-1 hex chars, or `H` plus the first 7 chars when the raw hash starts with `0-9`, `A`, `B`, or `C`.
|
||||
3. To update a contents page (`*_CONTENTS`): `wiki-get` it first, apply the template to append or modify, then `wiki-put` the whole page back. Never overwrite entries owned by others.
|
||||
3. To update a contents page (`*_CONTENTS`): `wiki-get` it first, apply the template to append or modify, then `wiki-put` the whole page back(寫入前會先確認)。不要覆寫別人的列。
|
||||
4. Write all wiki content in UTF-8 Traditional Chinese, per the STE100 output rule.
|
||||
5. Prefer visual forms for page content: use mermaid diagrams (flowchart, sequence, gantt, pie) and markdown tables wherever the information allows. Prose is capped at 3 sentences per section, and a sentence stays only when neither a mermaid diagram nor a markdown table can carry the same information.
|
||||
6. `tools/gitea.sh` retries once with the tea CLI login token when `GITEA_TOKEN` is missing or the response is 401/403. Report a failure only after that retry also fails.
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
set -eu
|
||||
|
||||
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
confirm_write() {
|
||||
sh "$script_dir/write-confirm.sh" "$1" "$2"
|
||||
}
|
||||
|
||||
resolve_wiki_repo() { # TYPE -> JSC_WIKI_REPO_{TYPE} -> JSC_WIKI_REPO
|
||||
type=$(printf '%s' "${1:?TYPE required}" | tr a-z A-Z)
|
||||
@@ -190,6 +193,7 @@ sys.stdout.write(json.load(sys.stdin).get("html_url") or "")
|
||||
printf '%s\n' "$url" ;;
|
||||
wiki-put)
|
||||
or="${1:?owner/repo required}"; page="${2:?page required}"; file="${3:?content file required}"
|
||||
confirm_write "寫入 wiki 頁" "$page"
|
||||
tmp=$(mktemp)
|
||||
python3 -c '
|
||||
import json,sys,base64
|
||||
@@ -207,6 +211,7 @@ print(json.dumps({"title":title,"content_base64":base64.b64encode(content).decod
|
||||
pr-create)
|
||||
or="${1:?owner/repo required}"; head="${2:?head required}"; base="${3:?base required}"
|
||||
title="${4:?title required}"; body_file="${5:?body file required}"
|
||||
confirm_write "建立 PR" "$or#$title"
|
||||
tmp=$(mktemp)
|
||||
python3 -c '
|
||||
import json,sys
|
||||
@@ -249,6 +254,7 @@ sys.stdout.write(p.get("body") or "")
|
||||
or="${1:?owner/repo required}"; idx="${2:?pr index required}"
|
||||
title="${3:?title required}"; body_file="${4:?body file required}"
|
||||
[ -f "$body_file" ] || { echo "找不到描述檔: $body_file" >&2; exit 2; }
|
||||
confirm_write "更新 PR" "$or#$idx"
|
||||
tmp=$(mktemp)
|
||||
python3 -c '
|
||||
import json,sys
|
||||
@@ -301,6 +307,7 @@ for c in d:
|
||||
kind="${3:?kind required}"; cid="${4:?comment id required}"; body_file="${5:?body file required}"
|
||||
[ -f "$body_file" ] || { echo "找不到回覆檔: $body_file" >&2; exit 2; }
|
||||
case "$kind" in issue|review|inline) ;; *) echo "kind must be issue, review, or inline" >&2; exit 2 ;; esac
|
||||
confirm_write "回覆留言" "$or#$idx/$kind#$cid"
|
||||
tmp=$(mktemp)
|
||||
python3 -c '
|
||||
import json,sys
|
||||
@@ -320,6 +327,7 @@ print(json.dumps({"body":open(sys.argv[1],encoding="utf-8").read()}))
|
||||
pr-depend)
|
||||
or="${1:?owner/repo required}"; idx="${2:?pr index required}"
|
||||
dep_or="${3:?dep owner/repo required}"; dep_idx="${4:?dep index required}"
|
||||
confirm_write "設定 PR 依賴" "$or#$idx -> $dep_or#$dep_idx"
|
||||
tmp=$(mktemp)
|
||||
python3 -c '
|
||||
import json,sys
|
||||
@@ -333,6 +341,7 @@ print(json.dumps({"owner":o,"repo":r,"index":int(sys.argv[2])}))
|
||||
echo "OK $or#$idx depends on $dep_or#$dep_idx" ;;
|
||||
repo-set)
|
||||
or="${1:?owner/repo required}"; desc="${2:?description required}"; site="${3:-}"
|
||||
confirm_write "更新 repo 資訊" "$or"
|
||||
tmp=$(mktemp)
|
||||
python3 -c '
|
||||
import json,sys
|
||||
|
||||
@@ -133,6 +133,10 @@ for l in json.load(sys.stdin).get("labels") or []:
|
||||
*) echo "[jsc][議題][ERR]:不認得的選項「$1」。" >&2; usage ;;
|
||||
esac
|
||||
done
|
||||
confirm_target="議題「$title」"
|
||||
[ -n "$labels" ] && confirm_target="$confirm_target,標籤:$labels"
|
||||
[ -n "$milestone" ] && confirm_target="$confirm_target,里程碑:$milestone"
|
||||
sh "$script_dir/write-confirm.sh" "建立議題" "$confirm_target"
|
||||
payload=$(mktemp)
|
||||
trap 'rm -f "$payload"' EXIT
|
||||
python3 -c '
|
||||
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env sh
|
||||
# write-confirm.sh — Gitea 寫入前的人工確認。
|
||||
#
|
||||
# 為什麼要有這支腳本:wiki 與議題都是對外寫入。先確認,才能避免把
|
||||
# 錯頁、錯內容、錯標籤直接送出去。
|
||||
#
|
||||
# 用法:
|
||||
# write-confirm.sh <動作> <目標>
|
||||
#
|
||||
# 規則:
|
||||
# - JSC_GITEA_CONFIRM=yes:直接放行。
|
||||
# - JSC_GITEA_CONFIRM=no:直接拒絕。
|
||||
# - 互動式執行:要求輸入「確認」。
|
||||
# - 沒有互動終端:拒絕,避免默默寫出錯資料。
|
||||
set -eu
|
||||
|
||||
action="${1:-}"
|
||||
target="${2:-}"
|
||||
|
||||
[ -n "$action" ] || { echo '[jsc][Gitea][ERR]:缺少動作名稱。' >&2; exit 2; }
|
||||
[ -n "$target" ] || { echo '[jsc][Gitea][ERR]:缺少目標名稱。' >&2; exit 2; }
|
||||
|
||||
case "${JSC_GITEA_CONFIRM:-}" in
|
||||
yes|YES|1|true|TRUE)
|
||||
exit 0 ;;
|
||||
no|NO|0|false|FALSE)
|
||||
echo "[jsc][Gitea][ERR]:已取消寫入「$target」。" >&2
|
||||
exit 2 ;;
|
||||
esac
|
||||
|
||||
if [ -t 0 ]; then
|
||||
printf '[jsc][Gitea] 即將%s「%s」。輸入「確認」繼續:' "$action" "$target" >&2
|
||||
IFS= read -r answer || exit 2
|
||||
case "$answer" in
|
||||
確認)
|
||||
exit 0 ;;
|
||||
*)
|
||||
echo "[jsc][Gitea][ERR]:已取消寫入「$target」。" >&2
|
||||
exit 2 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo "[jsc][Gitea][ERR]:寫入「$target」需要先確認;請改用互動式執行,或先設 JSC_GITEA_CONFIRM=yes。" >&2
|
||||
exit 2
|
||||
Reference in New Issue
Block a user