feat(wiki): 體檢目錄頁改條列式版面,鍵改用體檢頁頁名
What:`templates/check-contents.md` 從 markdown 表格改成一台執行環境一個 H2 區塊,H2 標題就是那一台的體檢頁頁名 `CHECK_{HASH}`,原本的七個欄位改成標題底下一層 `- {欄位名}:{值}` 的條列,頁上不留任何表格。`skills/doctor/SKILL.md` 與 `skills/setup/SKILL.md` 對目錄頁的呼叫從 `wiki-contents.sh upsert CHECK 4 "{HASH}"` 改成 `upsert CHECK 1 "CHECK_{HASH}"`,`references/behaviors.md` 的關鍵步驟、完成條件與可驗證跡象,以及 `README.md` 的兩段技能敘述都跟著對齊。
Why:一列七格的表格,欄位一多就要橫向捲動,讀的人得先數欄位再對照表頭才知道哪一格是什麼;一筆一個 H2 區塊、每一條自己帶欄位名,掃過去就讀得懂。版面換成區塊之後鍵也得跟著換:表格時代的鍵是第 4 欄的裸 `HASH`,區塊沒有欄位可指,唯一能當鍵的是 H2 標題。key-col 與 key 沿用舊值會讓腳本比對不中,同一台機器每體檢一次就在頁尾多附一個區塊,舊區塊從此再也更新不到,而頁面看起來完全正常,錯得無聲無息。頁名只由 `{短主機名}/{登入帳號}` 決定,`GITEA_HOST` 換掉、`JSC_WIKI_REPO_CHECK` 搬到別的存取庫、Gitea 對頁名的編碼有差都動不到它,拿它當鍵比拿任何含網址的值都穩。
How:範本頁首的寫入語意從「一列」改寫成「一個區塊」,並補上四個參數的說明。第三個參數 `<key>` 收 H2 標題文字,也就是 `CHECK_{HASH}`;第四個參數收的是區塊檔而不是列檔,內容為 `## CHECK_{HASH}` 那一行、一個空行,再照範本的欄位順序每欄一條條列,`HASH` 那一欄照樣要寫,標題是鍵不代表欄位可以省,否則下一個讀的人讀不到。第二個參數 `1` 定位成 `<key-col>`,只在頁面還留著舊表格、需要自動轉檔時才用得到,指舊表格裡持有 `[CHECK_{HASH}](網址)` 的第 1 欄,轉檔時取那一格的文字當 H2 標題,頁面已經是條列格式就忽略它。「體檢頁」那一條維持 `[{文字}]({絕對網址})` 的人用連結寫法,H2 標題本身不放連結也不放網址。兩支技能的結束碼分流一併校正:`wiki-contents.sh` 的結束碼 1 從「寫入失敗」改寫成「組不出頁面內容或寫入失敗」,頁上找不到本機那一個區塊不算這一碼,腳本會改成附加。實際的轉檔與 upsert 邏輯都在 `jsc-gitea/tools/wiki-contents.sh`,這個存取庫只改敘述與範本。
Who:屬於「wiki 目錄頁改條列式呈現」這個需求落在 jsc-cli 的部分,也就是 `CHECK_CONTENTS` 這一型目錄頁的去表格化。內容頁維持圖表優先,不在這一輪範圍。
This commit is contained in:
+16
-12
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: doctor
|
||||
description: Health-check the execution environment in one pass and record the result, changing nothing. Four checks - plugin versions from jsc-hooks/hooks/version-guard.sh report, hook wiring from jsc-hooks/tools/wire-cli.sh status, settings from tools/scan-config.sh against tools/config-spec.tsv, and orphan variables. Report one findings table per check, build the 待修項目 table with tools/build-todo.sh, then write the whole run to wiki CHECK_{HASH} where HASH comes from {short hostname}/{user}; the page keeps only the latest run, while its CHECK_CONTENTS row is upserted through wiki-contents.sh into the contents repo. Use after installing or updating the skill set, when a skill fails on a settings or wiring problem, or before handing a machine over; not for applying fixes, which is jsc-cli:setup.
|
||||
description: Health-check the execution environment in one pass and record the result, changing nothing. Four checks - plugin versions from jsc-hooks/hooks/version-guard.sh report, hook wiring from jsc-hooks/tools/wire-cli.sh status, settings from tools/scan-config.sh against tools/config-spec.tsv, and orphan variables. Report one findings table per check, build the 待修項目 table with tools/build-todo.sh, then write the whole run to wiki CHECK_{HASH} where HASH comes from {short hostname}/{user}; the page keeps only the latest run, while its CHECK_CONTENTS block is upserted through wiki-contents.sh into the contents repo. Use after installing or updating the skill set, when a skill fails on a settings or wiring problem, or before handing a machine over; not for applying fixes, which is jsc-cli:setup.
|
||||
---
|
||||
|
||||
# doctor — execution environment health check
|
||||
@@ -115,21 +115,25 @@ user=${USER:-$(id -un 2>/dev/null || printf 'unknown')}
|
||||
|
||||
**`CHECK_{HASH}` — content page.** Repo: `jsc-gitea/tools/gitea.sh wiki-repo CHECK`. Write it through `jsc-gitea:wiki` and overwrite the whole page, because this page type keeps only the latest run of this one machine. Whole-page overwrite is correct here and forbidden on the page below.
|
||||
|
||||
**`CHECK_CONTENTS` — contents page, in the contents repo.** Repo: `gitea.sh wiki-repo CONTENTS`. Every contents page lives there now; it never falls back to `JSC_WIKI_REPO_CHECK`. Do not hand-edit it — write the row with
|
||||
**`CHECK_CONTENTS` — contents page, in the contents repo.** Repo: `gitea.sh wiki-repo CONTENTS`. Every contents page lives there now; it never falls back to `JSC_WIKI_REPO_CHECK`. It is an H1, a `>` preamble and one H2 block per machine — no markdown table anywhere on it. Do not hand-edit it — write the block with
|
||||
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert CHECK 4 "{HASH}" {row file} templates/check-contents.md`
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert CHECK 1 "CHECK_{HASH}" {block file} templates/check-contents.md`
|
||||
|
||||
The script reads the page back, replaces this machine's row or appends it, then writes the whole page. That keeps the rule in one place: one row per run, never a whole-page overwrite, never another machine's row — those rows are other people's records, and this run read them from nowhere else.
|
||||
The block file holds the whole H2 block: the `## CHECK_{HASH}` line, a blank line, then one bullet per field in the order `templates/check-contents.md` lists them, written as `- {欄位名}:{值}` with a full-width colon. Every field of the template gets a bullet, `HASH` included — the heading is the key, and a field only in the heading is a field the next reader cannot read.
|
||||
|
||||
**The key is column 4, the bare `HASH`.** `4` is the 1-based index of the `HASH` column in `templates/check-contents.md`, and the key is the exact string `hash-id` printed — 40 uppercase hex characters, not shortened, not prefixed, not wrapped in a link. The script compares the whole cell, so the key and that cell must match character for character.
|
||||
The script reads the page back, replaces this machine's block or appends it, then writes the whole page. That keeps the rule in one place: one block per run, never a whole-page overwrite, never another machine's block — those blocks are other people's records, and this run read them from nowhere else.
|
||||
|
||||
The key is the bare hash and not the link cell for a reason: a cell holding a URL changes whenever `GITEA_HOST` changes, whenever `JSC_WIKI_REPO_CHECK` moves to another repo, or whenever Gitea encodes the page name differently. The comparison then never matches, and every run appends another row for the same machine — silently, because the page still looks right.
|
||||
**The key is the H2 heading, `CHECK_{HASH}`.** It is the name of the content page this block points at: the literal `CHECK_` plus exactly what `hash-id` printed — 40 uppercase hex characters, not shortened, not otherwise prefixed, not wrapped in a link, no date appended. The script compares the whole heading text after trimming, so the key and that heading must match character for character.
|
||||
|
||||
Column 1 stays the human-facing link and is never the key. Write it as `[CHECK_{HASH}]({absolute URL})` — text plus link, the one link form this skill set uses. The URL comes from `gitea.sh wiki-url {CHECK repo} CHECK_{HASH}` and is never composed by hand. Fetch it after `CHECK_{HASH}` is written: `wiki-url` exits 4 on a page that does not exist yet.
|
||||
The page name is the key because it is the one value that does not move. It is decided by `{host}/{user}` alone, so it survives a changed `GITEA_HOST`, a `JSC_WIKI_REPO_CHECK` moved to another repo, and a different Gitea encoding of the page name — all of which change the URL. Key on anything holding a URL and the comparison never matches, so every run appends a second block for the same machine — silently, because the page still looks right.
|
||||
|
||||
`1` is `<key-col>`, and it only matters while a page is still the old markdown table: it is the 1-based index of the column that held the identity, the `[CHECK_{HASH}]({URL})` cell in column 1, whose text becomes the H2 heading when the script converts that table to blocks. On a page already in block form the script ignores it.
|
||||
|
||||
The `體檢頁` bullet stays the human-facing link and is never the key; the heading itself carries no link and no URL. Write the bullet as `[CHECK_{HASH}]({absolute URL})` — text plus link, the one link form this skill set uses. The URL comes from `gitea.sh wiki-url {CHECK repo} CHECK_{HASH}` and is never composed by hand. Fetch it after `CHECK_{HASH}` is written: `wiki-url` exits 4 on a page that does not exist yet.
|
||||
|
||||
A same-wiki link form resolves only inside its own wiki, and the two pages are no longer in the same one. It fails without an error, reading on screen as plain text or a dead link, so nobody finds it and nobody fixes it.
|
||||
|
||||
**Verify every link before writing it.** Collect every URL heading into `CHECK_{HASH}` or into the `CHECK_CONTENTS` row, then hand the whole list to `jsc-gitea/tools/link-check.sh`. It prints `{OK|DEAD|SKIP}<TAB>{URL}<TAB>{reason}` per line. Only exit 0 may be written.
|
||||
**Verify every link before writing it.** Collect every URL heading into `CHECK_{HASH}` or into the `CHECK_CONTENTS` block, then hand the whole list to `jsc-gitea/tools/link-check.sh`. It prints `{OK|DEAD|SKIP}<TAB>{URL}<TAB>{reason}` per line. Only exit 0 may be written.
|
||||
|
||||
| Exit | Meaning | Action |
|
||||
| --- | --- | --- |
|
||||
@@ -139,21 +143,21 @@ A same-wiki link form resolves only inside its own wiki, and the two pages are n
|
||||
| 3 | The list holds a Gitea URL but `GITEA_HOST` is unset | Skip both writes and put `GITEA_HOST` at the top of 待修項目. Never write without verifying |
|
||||
| 7 | Gitea authentication failed | Stop and report the key problem. This is not a dead link |
|
||||
|
||||
Exit 7 stays apart from exit 1 on purpose: with a dead key, Gitea's answer for a private repo looks the same as "page absent". Merge the two and one expired key marks every live page dead, and the rows pointing at them get rewritten or dropped.
|
||||
Exit 7 stays apart from exit 1 on purpose: with a dead key, Gitea's answer for a private repo looks the same as "page absent". Merge the two and one expired key marks every live page dead, and the blocks pointing at them get rewritten or dropped.
|
||||
|
||||
The script asks the API and never reads a web status code. A private repo's web URL answers 404 to a request with no credentials, so status codes turn good links into dead ones.
|
||||
|
||||
| Exit | Meaning | Action |
|
||||
| --- | --- | --- |
|
||||
| 0 | `updated` or `added` | Report which one it printed, with the repo and page it named |
|
||||
| 1 | Write failed | Nothing landed. Report it with the stderr, and keep 2.1's tables on screen |
|
||||
| 1 | The page content could not be built, or the write failed | Nothing landed. Report it with the stderr, and keep 2.1's tables on screen. A page with no block to replace is not this case: the script appends instead |
|
||||
| 2 | Usage error | Report it as a defect in this skill. Do not retry with guessed arguments. A `templates/check-contents.md` that is not on disk also lands here — then name the path the script looked for, confirm the plugin install is complete, and rerun |
|
||||
| 3 | No contents repo configured | Skip this write and put `JSC_WIKI_REPO_CONTENTS` at the top of 待修項目 |
|
||||
| 4 | Page absent and no template given | Unreachable the way this skill calls the script — the command above always passes `templates/check-contents.md`. A template that is not on disk comes back as exit 2, not 4. So treat a 4 as a malformed call: report it as a defect in this skill, name the command that produced it, and do not retry with guessed arguments |
|
||||
| 7 | Key invalid or no permission | Nothing was read and nothing written. Name the exit code and create nothing |
|
||||
| 8 | Any other API failure | Same as 7: the old rows are unknown, so name the exit code and create nothing |
|
||||
| 8 | Any other API failure | Same as 7: the old blocks are unknown, so name the exit code and create nothing |
|
||||
|
||||
Exits 7 and 8 never mean the page is missing. Writing a fresh template over a directory whose rows were never read wipes every other machine's row, with no merge and no backup behind it — which is exactly why the script creates a page only when its own read reported that page absent, and why it owns that branch instead of this prose.
|
||||
Exits 7 and 8 never mean the page is missing. Writing a fresh template over a directory whose blocks were never read wipes every other machine's block, with no merge and no backup behind it — which is exactly why the script creates a page only when its own read reported that page absent, and why it owns that branch instead of this prose.
|
||||
|
||||
`wiki-repo` exiting 3 means that page type has no wiki repo configured: `JSC_WIKI_REPO_CHECK` for the content page, `JSC_WIKI_REPO_CONTENTS` for the contents page. Print the tables, skip that one write, and put the unset variable at the top of 待修項目 — it is itself a finding, so a failed write never fails the health check. Any other non-zero exit from `wiki-repo`, `wiki-url`, `hash-id` or the wiki write is reported the same way: tables on screen, write skipped, exit code named.
|
||||
|
||||
|
||||
+15
-11
@@ -99,21 +99,25 @@ The two pages live in **two different wiki repos**. Resolve each one on its own.
|
||||
|
||||
Rewrite `CHECK_{HASH}` through `jsc-gitea:wiki` with the post-fix state, per `templates/check-page.md` — repo from `gitea.sh wiki-repo CHECK`. That page is a **content page** and keeps only the latest run, so this overwrites the pre-fix picture on purpose.
|
||||
|
||||
`CHECK_CONTENTS` is a **contents page**, it lives in the contents repo (`gitea.sh wiki-repo CONTENTS`, never a fallback to `JSC_WIKI_REPO_CHECK`), and it gets the opposite treatment. Write the row with
|
||||
`CHECK_CONTENTS` is a **contents page**, it lives in the contents repo (`gitea.sh wiki-repo CONTENTS`, never a fallback to `JSC_WIKI_REPO_CHECK`), and it gets the opposite treatment. It is an H1, a `>` preamble and one H2 block per machine — no markdown table anywhere on it. Write the block with
|
||||
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert CHECK 4 "{HASH}" {row file} templates/check-contents.md`
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert CHECK 1 "CHECK_{HASH}" {block file} templates/check-contents.md`
|
||||
|
||||
which reads the page back and refreshes this machine's row, or appends it when missing. Never overwrite the whole page, and never touch another machine's row.
|
||||
which reads the page back and refreshes this machine's block, or appends it when missing. Never overwrite the whole page, and never touch another machine's block.
|
||||
|
||||
**The key is column 4, the bare `HASH`.** `4` is the 1-based index of the `HASH` column in `templates/check-contents.md`, and the key is exactly what `hash-id` printed for `{host}/{user}` in step 1 — 40 uppercase hex characters, not shortened, not prefixed, not wrapped in a link. The script compares the whole cell, so the key and that cell must match character for character.
|
||||
The block file holds the whole H2 block: the `## CHECK_{HASH}` line, a blank line, then one bullet per field in the order `templates/check-contents.md` lists them, written as `- {欄位名}:{值}` with a full-width colon. Every field of the template gets a bullet, `HASH` included — the heading is the key, and a field only in the heading is a field the next reader cannot read.
|
||||
|
||||
A cell holding a URL would make a moving key: it changes with `GITEA_HOST`, with a move of `JSC_WIKI_REPO_CHECK` to another repo, and with Gitea's encoding of the page name. The comparison then never matches, and every run appends a second row for the same machine instead of updating it.
|
||||
**The key is the H2 heading, `CHECK_{HASH}`.** It is the name of the content page this block points at: the literal `CHECK_` plus exactly what `hash-id` printed for `{host}/{user}` in step 1 — 40 uppercase hex characters, not shortened, not otherwise prefixed, not wrapped in a link, no date appended. The script compares the whole heading text after trimming, so the key and that heading must match character for character.
|
||||
|
||||
Column 1 stays the human-facing link and is never the key. Write it as `[CHECK_{HASH}]({absolute URL})` — text plus link, the one link form this skill set uses. The URL comes from `gitea.sh wiki-url {CHECK repo} CHECK_{HASH}`, fetched after `CHECK_{HASH}` is rewritten, and is never composed by hand.
|
||||
A key holding a URL would be a moving key: the URL changes with `GITEA_HOST`, with a move of `JSC_WIKI_REPO_CHECK` to another repo, and with Gitea's encoding of the page name. The page name moves with none of them — `{host}/{user}` alone decides it. Key on the URL and the comparison never matches, so every run appends a second block for the same machine instead of updating it.
|
||||
|
||||
`1` is `<key-col>`, and it only matters while a page is still the old markdown table: it is the 1-based index of the column that held the identity, the `[CHECK_{HASH}]({URL})` cell in column 1, whose text becomes the H2 heading when the script converts that table to blocks. On a page already in block form the script ignores it.
|
||||
|
||||
The `體檢頁` bullet stays the human-facing link and is never the key; the heading itself carries no link and no URL. Write the bullet as `[CHECK_{HASH}]({absolute URL})` — text plus link, the one link form this skill set uses. The URL comes from `gitea.sh wiki-url {CHECK repo} CHECK_{HASH}`, fetched after `CHECK_{HASH}` is rewritten, and is never composed by hand.
|
||||
|
||||
A same-wiki link form resolves only inside its own wiki, and the two pages are no longer in the same one. It fails without an error, reading on screen as plain text or a dead link, so nobody finds it and nobody fixes it.
|
||||
|
||||
**Verify every link before writing it.** Collect every URL heading into `CHECK_{HASH}` or into the `CHECK_CONTENTS` row, then hand the whole list to `jsc-gitea/tools/link-check.sh`. It prints `{OK|DEAD|SKIP}<TAB>{URL}<TAB>{reason}` per line. Only exit 0 may be written.
|
||||
**Verify every link before writing it.** Collect every URL heading into `CHECK_{HASH}` or into the `CHECK_CONTENTS` block, then hand the whole list to `jsc-gitea/tools/link-check.sh`. It prints `{OK|DEAD|SKIP}<TAB>{URL}<TAB>{reason}` per line. Only exit 0 may be written.
|
||||
|
||||
| Exit | Meaning | Action |
|
||||
| --- | --- | --- |
|
||||
@@ -123,23 +127,23 @@ A same-wiki link form resolves only inside its own wiki, and the two pages are n
|
||||
| 3 | The list holds a Gitea URL but `GITEA_HOST` is unset | Skip both writes and report `GITEA_HOST` as still unfixed. Never write without verifying |
|
||||
| 7 | Gitea authentication failed | Stop and report the key problem. This is not a dead link |
|
||||
|
||||
Exit 7 stays apart from exit 1 on purpose: with a dead key, Gitea's answer for a private repo looks the same as "page absent". Merge the two and one expired key marks every live page dead, and the rows pointing at them get rewritten or dropped.
|
||||
Exit 7 stays apart from exit 1 on purpose: with a dead key, Gitea's answer for a private repo looks the same as "page absent". Merge the two and one expired key marks every live page dead, and the blocks pointing at them get rewritten or dropped.
|
||||
|
||||
The script asks the API and never reads a web status code. A private repo's web URL answers 404 to a request with no credentials, so status codes turn good links into dead ones.
|
||||
|
||||
| Exit | Action |
|
||||
| --- | --- |
|
||||
| 0 | Report the `updated` or `added` result with the repo and page it named |
|
||||
| 1 | Write failed and nothing landed. Report it with the stderr |
|
||||
| 1 | The page content could not be built, or the write failed, and nothing landed. Report it with the stderr. A page with no block to replace is not this case: the script appends instead |
|
||||
| 2 | Usage error. Report it as a defect in this skill; do not retry with guessed arguments. A `templates/check-contents.md` that is not on disk also lands here — then name the path the script looked for, confirm the plugin install is complete, and rerun |
|
||||
| 3 | No contents repo configured. Skip this write and report `JSC_WIKI_REPO_CONTENTS` as still unfixed |
|
||||
| 4 | Unreachable the way this skill calls the script — the command above always passes `templates/check-contents.md`, and a template that is not on disk comes back as exit 2. So treat a 4 as a malformed call: report it as a defect in this skill, name the command that produced it, and do not retry with guessed arguments |
|
||||
| 7 | Key invalid or no permission. Nothing was read or written; name the exit code and create nothing |
|
||||
| 8 | Any other API failure. Same as 7 |
|
||||
|
||||
Exits 7 and 8 never mean the page is missing: the whole-page overwrite that is correct for `CHECK_{HASH}` would here destroy every other machine's row, unread and unrecoverable. The script creates a page only when its own read reported that page absent, and it owns that branch.
|
||||
Exits 7 and 8 never mean the page is missing: the whole-page overwrite that is correct for `CHECK_{HASH}` would here destroy every other machine's block, unread and unrecoverable. The script creates a page only when its own read reported that page absent, and it owns that branch.
|
||||
|
||||
`gitea.sh wiki-url` has its own exits, and they are read before the upsert runs. Exit 4 means `CHECK_{HASH}` is not on the wiki yet, so rewrite that page first and fetch the URL again. Any other non-zero exit: name the exit code and stop — never hand-build the URL, because a guessed link goes into the row and points nowhere.
|
||||
`gitea.sh wiki-url` has its own exits, and they are read before the upsert runs. Exit 4 means `CHECK_{HASH}` is not on the wiki yet, so rewrite that page first and fetch the URL again. Any other non-zero exit: name the exit code and stop — never hand-build the URL, because a guessed link goes into the block and points nowhere.
|
||||
|
||||
No wiki repo configured, or any non-zero exit from `wiki-repo`, `hash-id`, `wiki-url` or the wiki write → report the tables on screen, say the record was skipped, and name the exit code.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user