feat(link): 連結一律寫成 [文字](絕對網址),寫入前先驗證連得到

取消 [[頁名]] 與 [[顯示文字|頁名]] 兩種同 wiki 寫法,不再分「同存取庫」與
「跨存取庫」兩條規則。那種寫法只在自己那個 wiki 內解析,寫錯不報錯,畫面上
看起來像普通文字或死連結,巡不到也修不了。

連結寫進頁面前先過 jsc-gitea 的 link-check.sh,結束碼 0 才寫。驗證一律走 API,
不看網頁狀態碼:私有存取庫的網頁網址對未登入請求一律回 404,拿狀態碼判會把
好連結判成壞的。認證失敗回 7,與死連結的 1 分開,免得金鑰一過期就把還在的頁
整批判死。
This commit is contained in:
2026-09-02 14:27:18 +08:00
parent e2a22b5408
commit 2c085d68ef
9 changed files with 62 additions and 23 deletions
+18 -4
View File
@@ -27,14 +27,16 @@ Rows 3, 4, 5 and 6 each hit a different source and none of them reads another's
| --- | --- | --- |
| 1 | Repository name | Parse `{owner}/{repo}` from `git remote get-url origin`. This is the code repo — never pass it to `wiki-url`, which takes the wiki-hosting repo |
| 2 | Branch name | `git branch --show-current` |
| 3 | Plan name | Absolute link to the plan page: `[PLAN_{HASH}](<url>)`. Resolve the hosting repo with `jsc-gitea/tools/gitea.sh wiki-repo PLAN`, then take `<url>` from `gitea.sh wiki-url <that repo> PLAN_{HASH}` — PLAN and LOG may live in different wiki repos, and `[[...]]` only resolves inside one wiki. `wiki-repo` exit 3 (no wiki repo configured for that type) or `wiki-url` exit 4 (page not found) → fill the literal 「無」 for this row and carry on; a `worklog` run triggered from `maintain` normally has no plan page. `wiki-url` exit 5 → stop and report that the page carries no `html_url`; never assemble the URL by hand. `wiki-url` exit 7 (token invalid or no permission, HTTP 401/403) or exit 8 (other API failure) → stop and report the token or API status; never fill 「無」, because that records a page that exists as a page that does not |
| 4 | Work package id | Absolute link to the work package heading: `[WP-xx](<url>#wp-xx)`. Resolve the hosting repo with `gitea.sh wiki-repo ANALYZE`, then take `<url>` from `gitea.sh wiki-url <that repo> ANALYZE_{HASH}`. A comment-fix round links to the same work package it belongs to. Same branching as row 3: `wiki-repo` exit 3 or `wiki-url` exit 4 → fill 「無」 and carry on; `wiki-url` exit 5 → stop and report that the page carries no `html_url`, never assemble the URL by hand; `wiki-url` exit 7 or 8 → stop and report the token or API status, never fill 「無」 |
| 3 | Plan name | Link to the plan page in the shape `[PLAN_{HASH}](<url>)`. Resolve the hosting repo with `jsc-gitea/tools/gitea.sh wiki-repo PLAN`, then take `<url>` from `gitea.sh wiki-url <that repo> PLAN_{HASH}` — never assemble it by hand, and never use the same-wiki `[[...]]` form: PLAN and LOG may live in different wiki repos, and `[[...]]` resolves inside one wiki only. `wiki-repo` exit 3 (no wiki repo configured for that type) or `wiki-url` exit 4 (page not found) → fill the literal 「無」 for this row and carry on; a `worklog` run triggered from `maintain` normally has no plan page. `wiki-url` exit 5 → stop and report that the page carries no `html_url`; never assemble the URL by hand. `wiki-url` exit 7 (token invalid or no permission, HTTP 401/403) or exit 8 (other API failure) → stop and report the token or API status; never fill 「無」, because that records a page that exists as a page that does not |
| 4 | Work package id | Link to the work package heading in the shape `[WP-xx](<url>#wp-xx)`. Resolve the hosting repo with `gitea.sh wiki-repo ANALYZE`, then take `<url>` from `gitea.sh wiki-url <that repo> ANALYZE_{HASH}`. A comment-fix round links to the same work package it belongs to. Same branching as row 3: `wiki-repo` exit 3 or `wiki-url` exit 4 → fill 「無」 and carry on; `wiki-url` exit 5 → stop and report that the page carries no `html_url`, never assemble the URL by hand; `wiki-url` exit 7 or 8 → stop and report the token or API status, never fill 「無」 |
| 5 | Elapsed time | `jsc-hooks/hooks/session-timer.sh report {session_id}` prints `{sid} {seconds}` and always exits 0. Convert the seconds to h/m and read it at the moment the task ends, so it counts only this task. `0` means the timer holds no start record for that session, not a task that took no time: fill the literal 「無資料」 and say the timer had no record. Never estimate the duration from the transcript |
| 6 | Token usage | `tools/token-usage.sh <cli> {session_id}` per CLI that ran; it prints `input<TAB>output`. Pass the same `{session_id}` as row 5 so the elapsed time and the token count describe one task. Fill `N/A` in both columns when it prints `N/A`; exit 2 means the CLI name is not one of claude / codex / copilot / antigravity / kiro, so fix the name and rerun |
| 7 | Task status | One of the literal values 「完成」, 「部分完成」, 「阻塞」 (with reason when blocked). Derive it from the session when the session shows it; otherwise ask via `jsc-ask:ask`, offering those three literals as the options and stating each option's impact scope (「完成」 closes the task, 「部分完成」 leaves the remainder open for the next run, 「阻塞」 records the blocker and hands it back to the operator) |
| 8 | Details and outputs | One line per changed file or produced page: what changed there and why. A round that changed nothing says what was tried and why it was dropped |
| 9 | Difficulties and resolutions | One pair per line. Ask via `jsc-ask:ask` when the session does not show them |
| 10 | PR target branch | Link to the PR page |
| 10 | PR target branch | Link to the PR page in the shape `[{base branch}]({PR URL})` |
Every link in an entry is text plus an absolute URL — `[{text}]({url})` — with wiki URLs coming from `gitea.sh wiki-url`. The same-wiki `[[...]]` form is out: it resolves inside one wiki only, and a link that fails that way looks like ordinary text on the page instead of reporting an error.
The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`, which prints the full 40-character uppercase SHA-1 of its input — no truncation to 8 characters and no prefix rewrite. A page name shortened by hand points at a page nobody else writes to.
@@ -65,10 +67,22 @@ The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`
| 7 | The key is invalid or lacks permission, so the old content is unknown. Stop and report the key problem, write nothing and create no page — a page created here would take the place of a log that is still on the server |
| 8 | Some other API failure. Stop and report that status, write nothing and create no page. Retry only after the API is back |
Before the write, hand every URL that `MERGED` carries — plan page, work package heading, PR page — to `jsc-gitea/tools/link-check.sh {url}...`. It prints one `{OK|DEAD|SKIP}<TAB>{url}<TAB>{note}` line per URL and resolves Gitea URLs through the API, because a private repo answers a logged-out web request with 404 and would fail a page that is there. Only exit 0 permits the write.
| Exit | Do |
| --- | --- |
| 0 | Every link answered. Write the entries |
| 1 | At least one link is DEAD. Write nothing, report the DEAD lines, and go to step 7 as a failure so the pending content survives |
| 2 | No URL reached the script. Pass the URLs and rerun |
| 3 | The list holds a Gitea URL but `GITEA_HOST` is unset. Set it and rerun; never skip the check |
| 7 | The Gitea token was rejected (HTTP 401/403). Stop and report the token problem. A rejected token makes live pages look missing, and one batch judged on that answer wipes out links that still work |
A failed write stops the run and goes to step 7 as a failure — never report the page as written when it was not. Done when every entry in `MERGED` is on `PAGE`, every entry that was already there is still there, and any 4 / 7 / 8 branch was followed as stated.
6. Update `CONTENTS` in the same pass, and let `jsc-gitea/tools/wiki-contents.sh` do the row work — never hand-edit the directory page.
`LOG_CONTENTS` lives in the CONTENTS wiki repo that `gitea.sh wiki-repo CONTENTS` resolves (`JSC_WIKI_REPO_CONTENTS`, then `JSC_WIKI_REPO`), which is **not** the LOG repo of step 1 and never falls back to it. Because the two pages sit in different wikis, the row's link to the log page is the absolute URL from `gitea.sh wiki-url <LOG repo> LOG_{HASH}` — `[[LOG_{HASH}]]` resolves only inside one wiki and would dead-link from here. `wiki-url` exit 4 means the step 5 write has not landed yet, so stop and rerun step 5 before this one; exit 5 means the page carries no `html_url`, so stop and report it and never assemble the URL by hand; exit 7 or 8 means the token or the API failed, so stop and report that status.
`LOG_CONTENTS` lives in the CONTENTS wiki repo that `gitea.sh wiki-repo CONTENTS` resolves (`JSC_WIKI_REPO_CONTENTS`, then `JSC_WIKI_REPO`), which is **not** the LOG repo of step 1 and never falls back to it. Because the two pages sit in different wikis, the row links the log page as `[LOG_{HASH}](<url>)`, with `<url>` from `gitea.sh wiki-url <LOG repo> LOG_{HASH}` — never the same-wiki `[[...]]` form, which resolves inside one wiki only and dead-links from here without reporting an error. `wiki-url` exit 4 means the step 5 write has not landed yet, so stop and rerun step 5 before this one; exit 5 means the page carries no `html_url`, so stop and report it and never assemble the URL by hand; exit 7 or 8 means the token or the API failed, so stop and report that status.
Put that URL through the step 5 `link-check.sh` gate before the upsert, with the same exit branches: only exit 0 writes the row, and a DEAD line stops the write and goes to step 7 as a failure.
Build one file holding the single row from `templates/log-contents.md` — the absolute link, the bare `{HASH}` of step 1, this week's Friday date from step 2, the entry count and the update time — then run: