Files
jiantw83 89463cd263 docs(wiki): 同步目錄頁條列格式的敘述與工具用法
README 的工具用法、技能行為清單、連結規則與 wiki 技能本文,全部改寫成
目錄頁的區塊格式:參數名從整列改成整個區塊、key-col 的用途縮回只給轉檔
用、補上取標題與換引言的判準,並登錄新增的驗證腳本。

文件與工具講的不是同一件事,呼叫端就會照舊敘述傳整列的表格文字進去,寫出
半表格半條列的頁面。key-col 的語意變動最容易誤解——它從「要換掉哪一欄」
變成「轉檔時哪一欄持有身分」,敘述不改就會被填成別的欄位。

目錄頁條列、內容頁維持圖表優先,這個區分在每一份文件裡都寫明,避免把改版
範圍誤讀成整個 wiki。結束碼說明一併對回工具現況。

功能範圍:目錄頁版面改版的文件同步。
2026-09-02 17:22:29 +08:00

206 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# jsc-gitea — Gitea 操作
jsc 技能組的 gitea domain:Gitea API 的統一入口。所有 jsc 技能需要操作 gitea(wiki、repo、PR)時,一律經由本 domain 的工具或技能,不可自行拼 API 呼叫。
## 安裝、更新、移除
Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安裝 token 為 `jsc-gitea@jsc`。每個指令一行:
| CLI | 安裝 | 更新 | 移除 |
| --- | --- | --- | --- |
| claude | `claude plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && claude plugin install jsc-gitea@jsc` | `claude plugin marketplace update jsc && claude plugin update jsc-gitea@jsc` | `claude plugin uninstall jsc-gitea@jsc` |
| codex | `codex plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && codex plugin add jsc-gitea@jsc` | `codex plugin marketplace upgrade jsc` | `codex plugin remove jsc-gitea@jsc` |
| copilot | `copilot plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && copilot plugin install jsc-gitea@jsc` | `copilot plugin marketplace update jsc && copilot plugin update jsc-gitea@jsc` | `copilot plugin uninstall jsc-gitea@jsc` |
| antigravity | `git clone https://gitea.jsc.idv.tw/plugins/gitea.git ~/plugins/gitea && agy plugin install ~/plugins/gitea` | `git -C ~/plugins/gitea pull && agy plugin uninstall jsc-gitea && agy plugin install ~/plugins/gitea` | `agy plugin uninstall jsc-gitea` |
| kiro | `kiro-cli plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && kiro-cli plugin install jsc-gitea@jsc` | `kiro-cli plugin marketplace update jsc && kiro-cli plugin update jsc-gitea@jsc` | `kiro-cli plugin uninstall jsc-gitea@jsc` |
> antigravity 不支援 gitea URL 安裝,改用本地 clone 路徑。批次操作五個 CLI:使用 `/jsc-cli:deploy`。
> 舊入口 `plugins/jsc` 已移除,marketplace 正本移到 `plugins/meta`。marketplace 名稱仍是 `jsc`(取自 marketplace.json 的 `name` 欄位,與存取庫名無關),安裝 token 不變;已從舊入口安裝過的人先執行 `claude plugin marketplace remove jsc`,再依上表重新 add。
## 工具
`tools/gitea.sh`(POSIX shell + curl):
```
gitea.sh owners # 列出可讀取的 owner
gitea.sh repos <owner> # 列出 owner 的 repo 全名
gitea.sh default-branch <owner>/<repo>
gitea.sh clone-url <owner>/<repo>
gitea.sh hash-id <text> # 產生完整 40 碼大寫 SHA-1
gitea.sh wiki-repo <TYPE> # 解析頁面類型的 wiki 位置(TYPE = QUESTION / PLAN / ANALYZE / DELIVER / MAINTAIN / REPO / LOG / LEARN / ERROR / CHECK / REPORT / SKILLSET / TOOLING / MONITOR / CONTENTS)
# 所有 *_CONTENTS 頁一律走 CONTENTS,內容頁走自己的型別
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-delete <owner>/<repo> <page> # 刪除 wiki 頁;與 wiki-put 走同一道確認,頁不存在 exit 4
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-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-of-branch <owner>/<repo> <branch> # 印出該分支目前開啟中的 PR(比對 head.ref)
# 第 1 行 number,接著 title、base、body 三個標記,第 5 行起是描述原文
# 結束碼 0=找到、2=用法錯誤、3=該分支沒有開啟中的 PR、4=API 失敗
# 「沒有 PR」用 3 不用 4:混用會把金鑰失效讀成沒開過 PR,接著開出重複的 PR
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> # 會先要求確認
# 回覆本輪處理過的 PR 留言;inline 走 review comment reply,其餘補一則 PR 留言
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] # 會先要求確認
gitea.sh markdown <file> # markdown 檔渲染成 HTML 片段(走 /markdown/raw)
gitea.sh api <METHOD> <path> [json-file]
# 全腳本共用結束碼: 0=成功、1=api 子命令請求失敗、2=用法錯誤
# 3=wiki-repo 沒設定或 pr-of-branch 查無 PR、4=找不到(404)與 PR 系列 API 失敗
# 5=wiki 頁沒有 html_url、7=金鑰失效或權限不足(401/403)、8=其他 API 失敗
# 7 與 8 一定要跟 4 分開:認證失敗若被讀成「頁面不存在」,
# 附加寫入就會變成整頁覆蓋,舊紀錄直接消失
hash-id <text> # 與 gitea.sh hash-id 相同
# 結束碼 0=成功、1=沒有 sha1sum 也沒有 shasum、2=沒給文字或給了空字串
page-name.sh regex | check <page> # 頁名樣式的唯一正本
# 合法頁名 {型別}_(CONTENTS|8 碼|H 加 7 碼|40 碼大寫十六進位)
# 8 碼與 H 加 7 碼留給尚未遷移的舊頁;舊演算法多數情況會加 H,兩種都要收
# 前綴只收十四種內容型別。CONTENTS 只解存取庫,沒有 CONTENTS_CONTENTS 這一頁
# 結束碼 0=合法、1=不合法、2=用法錯誤
wiki-contents.sh upsert <TYPE> <key-col> <key> <entry-file> [template-file]
# 目錄頁的區塊 upsert:解 CONTENTS 存取庫、讀舊頁、換掉「## {key}」那一塊或附加到頁尾、整頁寫回
# 目錄頁一筆一個 H2 區塊:標題就是內容頁頁名,欄位是底下一層條列「- {欄位名}:{值}」
# entry-file 放整個 H2 區塊;舊頁還是表格時先整頁轉成區塊,再做 upsert
# key-col 只給轉檔用:舊表格裡持有身分那一欄的序號,1 起算,頁面已是條列就忽略
# 轉檔的 H2 標題只看那一格:有連結取網址最後一段路徑(百分號編碼先解碼),沒連結取純文字
# 連結文字常常是工作包或計畫名稱不是頁名;拿它當標題會跟呼叫端的鍵對不上,同一筆長出第二個區塊
# 轉檔那一次有給範本,就連 H1 與「>」引言一起換成範本那一份:只搬表格不動散文,舊引言會一直講「一列一筆」
# 頁面已是條列就不動引言,那時只是更新自己那一筆;沒給範本也保留舊引言,沒有正本可換
# 用範本建新頁時剝掉示範區塊,只留 H1 與引言,正式頁上不留佔位的死紀錄
# 結束碼 0=已更新或已新增、1=組不出頁面內容或寫入失敗、2=用法錯誤、3=CONTENTS 存取庫未設定
# 4=頁不存在且沒給範本、7=金鑰失效或權限不足、8=其他 API 失敗
# 只有 4 才准建新頁;7 與 8 一律中止,不得當成「頁面不存在」
wiki-contents.sh format <key-col> <key> <entry-file> <old-file> <new-file> [template-file|--fresh]
# 同一份轉檔與 upsert 判斷,只讀寫檔案、不碰 API,供離線驗證用
# 第六個參數給 --fresh 是「old-file 就是範本」,給路徑則等同 upsert 的範本檔
migrate-wiki.sh [--apply] [--key <候選鍵>]... # 把舊頁搬到新規則:目錄頁換存取庫、內容頁換頁名
# 只做正推配對,配不上的一律列成孤兒,不猜;不帶 --apply 只印對照表
# 寫目的地之前先讀:只有 4 才准寫,0 列成需人工確認且不覆蓋,7 與 8 中止
# 連結改寫只動被搬的頁;沒被搬的引用方另列一節,交給人改
# 結束碼 0=全部搬完、1=有頁搬移失敗、2=用法錯誤、3=有需人工處理的項目
repo-sync.sh <owner>/<repo> [target-dir] # 同步單一存取庫;印出 cloned、updated、dirty {分支} 或 failed {原因}
# 基準分支的優先序只在這支腳本裡;dirty 會把解析好的分支帶出來當 PR 的 base
check-wiki-rules.sh # 驗證 wiki repo 解析、hash-id 與頁名樣式規則
check-contents-format.sh # 驗證目錄頁的區塊轉檔與 upsert 規則;全走 format 子命令,不打 API
link-check.sh <網址>... # 連結寫進文件之前先驗證連得到;也吃標準輸入,一行一個
# 每個網址一行「{OK|DEAD|SKIP}<TAB>{網址}<TAB>{說明}」
# wiki 頁與議題轉成 API 查,其他 Gitea 網址帶金鑰 HEAD,外部網址不帶金鑰 HEAD
# Gitea 一律走 API:私有存取庫的網頁網址對未登入請求一律回 404
# 結束碼 0=全部連得到、1=有連不到、2=沒給網址、3=有 Gitea 網址但 GITEA_HOST 未設定
# 7=Gitea 認證失敗(401/403)
# 7 一定要與 1 分開:金鑰失效與「頁不存在」難分辨,混用會把還在的頁整批判成死連結
pr-watch.sh <owner>/<repo> <pr-index> [state-file]
# 盯著一支 PR,直到它合併或關閉,不自動逾時退場
# 退出碼 0 = 已合併或關閉、10 = 有新留言要接手、2 = 參數錯誤、3 = 查不到該 PR
# 已回報過的留言記在狀態檔,預設 $JSC_HOME/pr-watch/{owner}-{repo}-{index}.seen
```
`pr-watch.sh` 的退出碼 10 是設計重點:腳本只負責偵測,決策交回呼叫端。收到 10 就把印出來的留言丟進決策樹,處理完再重新盯一次。
議題與 HTML 產出:
```
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 show <owner>/<repo> <index> # 一次拿齊標題、標籤與正文,只打一次 API
# 四段固定格式:title、labels、body 標記,第 4 行起是正文
issue.sh create <owner>/<repo> <title> <body-file> [--labels <ids>] [--milestone <id>] # 會先要求確認
html-style.sh get|set|unset|list|layouts|styles # 種類對版型與風格的設定
html-style.sh key wiki <頁名> # 推導種類:取第一個底線前的字首
html-style.sh key issue <owner>/<repo> <編號> [--labels <名稱>[,<名稱>]]
# 推導種類:依序試每個標籤,第一個設定過的勝出,都沒有就回 ISSUE:DEFAULT
# 輸出一行「{種類}<TAB>{依據}」;結束碼 1=取不到標籤
html-render.sh --markdown <檔案> --title <標題> --out <輸出檔> [--layout] [--style] [--subtitle] [--source-url]
```
## 參考資料
- `references/wiki-links.md`:連結規則。規則 A:一律寫成 `[文字](絕對網址)`,網址取自 `wiki-url`,只有這一種寫法。規則 B:連結寫進文件之前先過 `link-check.sh`,結束碼 0 才寫入。
## HTML 範本
版型(`templates/html/layout/*.html`)決定內容怎麼排,風格(`templates/html/style/*.css`)決定看起來長怎樣。兩者自由搭配,六乘五共三十種。
| 版型 | 內容排法 |
| --- | --- |
| `report` | 左側目錄加章節內文,長文件用 |
| `slide` | 一個 `##` 一張投影片,鍵盤左右鍵翻頁 |
| `dashboard` | 每個 `##` 一張卡片並排 |
| `spec` | 表格表頭固定、程式碼區塊放大,API 文件用 |
| `timeline` | 每個 `##` 一個節點串成一條線 |
| `onepager` | 窄欄單頁,印出來剛好一頁 |
| 風格 | 視覺 |
| --- | --- |
| `minimal` | 白底細線、無襯線,資訊密度優先 |
| `corporate` | 深藍主色、表頭反白,正式對外 |
| `dark` | 深底亮字 |
| `print` | 襯線字、A4 邊界,列印或轉 PDF |
| `vivid` | 高彩度、圓角卡片、漸層標題 |
哪一種頁面套哪一組,由 `html-style.sh` 的設定決定:專案的 `./.jsc/html-styles` 優先,其次 `$JSC_HOME/html-styles.conf`,種類對不到就退 `DEFAULT`,再對不到才用內建的 `report`/`minimal`。設定的 key 是 `WIKI:{頁名前綴}`、`ISSUE:{標籤名}` 或 `DEFAULT`。
自訂範本:版型放進 `templates/html/layout/`,風格放進 `templates/html/style/`,檔案第一行寫一句繁中說明——那句話就是技能問使用者時顯示的選項說明。版型檔可用的佔位有 `{{TITLE}}`、`{{SUBTITLE}}`、`{{CONTENT}}`、`{{BASE}}`、`{{BASE_JS}}`、`{{STYLE}}`、`{{SOURCE}}`、`{{GENERATED}}`、`{{LAYOUT}}`、`{{STYLE_NAME}}`。
## Skills 目錄
呼叫方式:Claude / Antigravity `/jsc-gitea:{name}`;Codex `${name}`;Copilot / Kiro 描述需求自動觸發。
<!-- JSC-SKILLS:START -->
### `wiki`
Gitea wiki 頁讀寫的統一入口:依頁面類型(QUESTION / PLAN / ANALYZE / DELIVER / MAINTAIN / REPO / LOG / LEARN / ERROR / CHECK / REPORT / SKILLSET / TOOLING / MONITOR / CONTENTS)解析 wiki 所在的 `{owner}/{repo}`,先讀對應的 `JSC_WIKI_REPO_{TYPE}`,再退回 `JSC_WIKI_REPO`,不同類型不可互相代用。所有 `*_CONTENTS` 頁一律走 `CONTENTS` 這個型別,內容頁走自己的型別;目錄頁的區塊 upsert 交給 `tools/wiki-contents.sh`,一筆紀錄一個 H2 區塊,標題就是內容頁頁名,欄位是底下一層條列。內容頁的內容以圖表優先(mermaid 圖、markdown 表格),純文字每節最多三句;目錄頁不放表格。
### `repo-sync`
存取庫批次同步:列出 owner → 使用者選擇 → 各存取庫併行(一個 repo 一個 sub agent)呼叫 `tools/repo-sync.sh` clone 或更新;回報 `dirty {分支}` 的存取庫交給 `jsc-git:pr`,base 直接用腳本帶出來的那個分支;PR 依 `jsc-meta/references/pr-report.md` 集中成表。
### `html-export`
把一頁 wiki 或一筆議題輸出成單一 HTML 檔:解析連結 → 判斷種類 → 查該種類的版型與風格 → 用 Gitea 自己的 markdown 渲染出圖。CSS 與腳本全部內嵌,檔案拿到哪裡都打得開。**沒有連結就直接中止**,不猜存取庫、不猜頁名、不猜議題編號。
### `html-style`
設定「哪一種 wiki 頁或議題,出 HTML 時用哪一種版型與風格」:六種版型與五種風格全部列給使用者選,再寫進專案的 `.jsc/html-styles` 或全域的 `$JSC_HOME/html-styles.conf`。`html-export` 讀的就是這份設定。
### `wiki-to-issue`
把一頁 wiki 轉成同一個存取庫的議題:讀頁面 → sub agent 起草標題與正文(開頭附來源連結)→ 從既有標籤挑合適的 → 關聯專案看板 → 建立議題。標籤只從存取庫既有的挑,不自己發明;站台沒有看板 API 時據實回報請使用者手動拖,不假裝關聯成功。**沒有連結就直接中止**。
<!-- JSC-SKILLS:END -->
## 環境變數
| 變數 | 用途 | 未設定時 |
| --- | --- | --- |
| `GITEA_HOST` | Gitea 站台(可省略 scheme,預設 https) | 詢問使用者 |
| `GITEA_TOKEN` | Gitea API token;缺少或遇 401/403 時自動退回 tea CLI 登入 token | 詢問使用者 |
| `JSC_WIKI_REPO_{TYPE}` | 各類型內容頁的 `{owner}/{repo}`;TYPE = QUESTION / PLAN / ANALYZE / DELIVER / MAINTAIN / REPO / LOG / LEARN / ERROR / CHECK / REPORT | 退回 `JSC_WIKI_REPO`,不做跨類型代用 |
| `JSC_WIKI_REPO_SKILLSET` | `SKILLSET_{HASH}`(技能組異動報告)的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO`,不做跨類型代用 |
| `JSC_WIKI_REPO_TOOLING` | `TOOLING_{HASH}`(技能盤點)的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO`,不做跨類型代用 |
| `JSC_WIKI_REPO_MONITOR` | `MONITOR_{HASH}`(助理巡檢監控)的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO`,不做跨類型代用 |
| `JSC_WIKI_REPO_CONTENTS` | 全部目錄頁(各型別的 `*_CONTENTS`)共用的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO`,不退回各型別的變數 |
| `JSC_WIKI_REPO` | 共用預設的 wiki `{owner}/{repo}` | 詢問使用者 |
| `JSC_HOME` | `pr-watch.sh` 狀態檔的根目錄 | 預設 `~/.jsc` |
| `JSC_PR_WATCH_INTERVAL` | `pr-watch.sh` 的輪詢間隔秒數(正整數) | 預設 60 |
## Hash 規則
`{HASH}` 一律由 `tools/hash-id` 產生:完整 40 碼大寫十六進位,不截短、不加前綴。頁名合不合規則交給 `tools/page-name.sh check` 判,不要另外寫一份樣式。各頁型的雜湊來源,唯一來源是 `jsc-meta` 的 [`references/guidelines.md`](https://gitea.jsc.idv.tw/plugins/meta/src/branch/master/references/guidelines.md)「Wiki 頁命名總表」,這裡不再複述一份。
## 相關 domain
- [`jsc-ask`](https://gitea.jsc.idv.tw/plugins/ask):wiki 位置未設定時的決策樹詢問
- [`jsc-git`](https://gitea.jsc.idv.tw/plugins/git):repo-sync 的 commit 與 PR