feat(worklog): 日誌目錄頁改成一個日誌頁一個大標題區塊

日誌目錄頁的版面從 markdown 表格換成「大標題加條列」:一個日誌頁一個大標題
區塊,標題就是那個日誌頁的實際頁名,週五日期、條目數這些欄位改成標題底下的
一層條列。範本與 worklog 技能的寫入敘述、完成條件、退出碼說明一起跟上。

表格的欄位組合是整頁共用的,一頁上卻有很多存取庫各自的紀錄,每一輪只重寫
自己那一列。欄位一增減,舊列的格數與表頭就對不上,而目錄頁不能整頁覆蓋——
覆蓋等於刪掉別人的紀錄。條列一筆一個區塊,欄位各自獨立,加一條只動到自己
那一個區塊。

比對鍵從裸雜湊那一格改成大標題本身,標題寫成日誌頁的實際頁名。頁名只由
存取庫的擁有者與名稱決定,換主機位址、把日誌頁移到別的存取庫,或頁名編碼
有差,都動不到它;含網址的那一條連結照樣留著給人點,但不當鍵——拿它當鍵,
上面任一件事一變,這一輪的文字就跟上一輪不一樣,比不到既有那一筆就走附加,
同一個日誌頁多出第二個區塊,舊區塊從此再也更新不到。欄號那個參數只在舊
表格頁轉檔時用得到,頁面已經是條列就完全忽略它。

範圍是工作日誌的目錄頁與 worklog 技能。
This commit is contained in:
2026-09-02 17:22:33 +08:00
parent dd64c0350e
commit fbfe424c39
2 changed files with 27 additions and 22 deletions
+14 -14
View File
@@ -1,6 +1,6 @@
---
name: worklog
description: Append one work-log entry to wiki LOG_{HASH} plus LOG_CONTENTS as soon as a task ends, where a task is one work package, one round of PR-comment fixes, or one standalone fix commit — one task, one entry, appended to the same page. Every entry carries the ten facts (repo, branch, plan link, work package link, elapsed time from session-timer, token usage per CLI, status, details, difficulties, PR target); HASH is the full 40-character uppercase SHA-1 of {owner}/{repo} and the work-week Friday drives the page content. LOG_{HASH} sits in the LOG wiki repo while LOG_CONTENTS sits in the separate CONTENTS repo, so the directory row goes through jsc-gitea/tools/wiki-contents.sh upsert and links the log page by its absolute wiki-url. Merge whatever tools/worklog-pending.sh holds for that HASH into the same write, then clear the pending area once that write succeeded. Trigger at the end of every such task in implement or maintain; not for planning notes.
description: Append one work-log entry to wiki LOG_{HASH} plus LOG_CONTENTS as soon as a task ends, where a task is one work package, one round of PR-comment fixes, or one standalone fix commit — one task, one entry, appended to the same page. Every entry carries the ten facts (repo, branch, plan link, work package link, elapsed time from session-timer, token usage per CLI, status, details, difficulties, PR target); HASH is the full 40-character uppercase SHA-1 of {owner}/{repo} and the work-week Friday drives the page content. LOG_{HASH} sits in the LOG wiki repo while LOG_CONTENTS sits in the separate CONTENTS repo, so the directory entry goes through jsc-gitea/tools/wiki-contents.sh upsert as one H2 block keyed by the page name LOG_{HASH}, with a bullet per field and the log page linked by its absolute wiki-url. Merge whatever tools/worklog-pending.sh holds for that HASH into the same write, then clear the pending area once that write succeeded. Trigger at the end of every such task in implement or maintain; not for planning notes.
---
# worklog — work log
@@ -47,7 +47,7 @@ The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`
- Hash: `jsc-gitea/tools/hash-id "{owner}/{repo}"` on the code repo from row 1. Exit 1 means this machine has no SHA-1 helper: stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash. Exit 2 means the input was empty, which happens when row 1 failed to parse `{owner}/{repo}`: fix row 1 and rerun, because the empty string has a valid SHA-1 and would file this entry on a page nobody reads.
Done when the hosting `{owner}/{repo}` and the full 40-character uppercase `{HASH}` are both known.
2. Run `tools/worklog-target.sh "{HASH}" all` and `tools/worklog-target.sh friday` in parallel. `all` prints `PAGE=LOG_{HASH}` and `CONTENTS=LOG_CONTENTS`; `friday` prints the Friday of the current work week as `yyyy-MM-dd`, which drives the page content and the row dates. Exit 2 means the arguments were rejected, so fix them and rerun. Exit 4 from `friday` means this machine's `date` does no date arithmetic: stop and report it, because a hand-picked Friday is exactly what goes wrong across a month or year boundary. Done when both page names and that Friday date are known.
2. Run `tools/worklog-target.sh "{HASH}" all` and `tools/worklog-target.sh friday` in parallel. `all` prints `PAGE=LOG_{HASH}` and `CONTENTS=LOG_CONTENTS`; `friday` prints the Friday of the current work week as `yyyy-MM-dd`, which drives the page content and the directory block's dates. Exit 2 means the arguments were rejected, so fix them and rerun. Exit 4 from `friday` means this machine's `date` does no date arithmetic: stop and report it, because a hand-picked Friday is exactly what goes wrong across a month or year boundary. Done when both page names and that Friday date are known.
3. Fill `templates/log-entry.md` with the ten facts of this one task and save it to a file. Done when that file holds exactly one entry.
4. Run `tools/worklog-pending.sh merge {HASH} {entry file}`. It prints `MERGED=` (pending content in time order, then this task's entry), `CLAIM=` (the pending files it took) and `PENDING=` (how many). Pending content was written by an earlier stage that ended without a work log, so it belongs in **this** write. `merge` also picks up the legacy `H` + first 7 characters directory of the same `{HASH}`, so pending content stored under the previous hash rule still reaches the wiki.
@@ -83,29 +83,29 @@ The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`
| 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.
6. Update `CONTENTS` in the same pass, and let `jsc-gitea/tools/wiki-contents.sh` do the block 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 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.
`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 日誌頁 bullet 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.
Put that URL through the step 5 `link-check.sh` gate before the upsert, with the same exit branches: only exit 0 writes the block, 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:
Build one file holding the single H2 block from `templates/log-contents.md` — the `## LOG_{HASH}` heading, a blank line, then one `- {欄位名}:{值}` bullet per field in the template's order: 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:
`jsc-gitea/tools/wiki-contents.sh upsert LOG 2 "{HASH}" {row file} templates/log-contents.md`
`jsc-gitea/tools/wiki-contents.sh upsert LOG 1 "LOG_{HASH}" {block file} templates/log-contents.md`
The key is column 2, the bare 40-character `{HASH}` with no link markup around it. Column 1 carries the same page as a link for a human to click, and that link is exactly what must not be the key: it embeds the host and the encoded page name, so one change of `GITEA_HOST`, one move of `JSC_WIKI_REPO_LOG`, or one difference in how Gitea encodes the page name makes this run's cell differ from the last run's, the match fails, the row is appended, and the same log page now owns two rows of which the older is never updated again. The bare hash depends only on `{owner}/{repo}`. The script reads the whole page, replaces the matching row and appends when none matches, so every row that belongs to another log page stays as it was.
The key is the H2 heading itself, the content page name `LOG_{HASH}`, and the 日誌頁 bullet carries that same page as a link for a human to click. That link is exactly what must not be the key: it embeds the host and the encoded page name, so one change of `GITEA_HOST`, one move of `JSC_WIKI_REPO_LOG`, or one difference in how Gitea encodes the page name makes this run's text differ from the last run's, the match fails, the block is appended, and the same log page now owns two blocks of which the older is never updated again. The page name depends only on `{owner}/{repo}`, so none of those three touches it. The `1` in the command is `<key-col>`, which the script uses only while the directory page is still an old markdown table — it names the column whose cell text becomes the H2 heading, and a page already in list shape ignores it. The script reads the whole page, replaces the matching block and appends when none matches, so every block that belongs to another log page stays as it was.
| Exit | Do |
| --- | --- |
| 0 | The row is in place. It prints `updated` or `added` plus the page it wrote — carry that word into the close-out |
| 1 | The write failed, or the directory page holds no markdown table. Stop and report it as a failed write, and go to step 7 as a failure |
| 2 | An argument was rejected (unknown type, key column, missing row file). Fix the argument and rerun this step; nothing was written |
| 0 | The block is in place. It prints `updated` or `added` plus the page it wrote — carry that word into the close-out |
| 1 | The page content could not be assembled, or the write failed. Stop and report it as a failed write, and go to step 7 as a failure. A page with no matching block is not this code: the block is appended instead |
| 2 | An argument was rejected (unknown type, key column, missing block file). Fix the argument and rerun this step; nothing was written |
| 3 | No CONTENTS wiki repo is configured. Stop and report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set, and go to step 7 as a failure. The log entry itself is on `PAGE` and stays there |
| 4 | The directory page is absent and the script received no template. The call above always passes one, so this code means `templates/log-contents.md` is not at that path — a partial plugin install, not a missing argument. Stop and report the path; rerunning the same command changes nothing. Reinstall the plugin, confirm the file is there, then rerun. A mistyped template path exits 2, not 4 |
| 7 | The key is invalid or lacks permission, so the other rows are unknown. Stop and report the key problem; the script wrote nothing, which is what keeps the other pages' rows alive |
| 7 | The key is invalid or lacks permission, so the other blocks are unknown. Stop and report the key problem; the script wrote nothing, which is what keeps the other pages' blocks alive |
| 8 | Some other API failure. Stop and report that status and retry only after the API is back |
Done when the run exited 0 and the row for `PAGE` carries this week's Friday date from step 2, or a non-zero code was reported and step 7 ran as a failure.
Done when the run exited 0 and the block for `PAGE` carries this week's Friday date from step 2, or a non-zero code was reported and step 7 ran as a failure.
7. Close the pending area on the result of steps 5 and 6: `tools/worklog-pending.sh commit {HASH} {CLAIM}` after both succeeded, or `tools/worklog-pending.sh abort {HASH} {CLAIM}` after either failed. `abort` keeps every pending file for the retry, so keep the entry file too and rerun from step 4.
| Exit | Do |
@@ -125,7 +125,7 @@ The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`
| --- | --- |
| `ok` | Steps 5 and 6 both wrote and step 7 cleared the pending area. `orphans` exit 4 stays `ok`: an orphan directory belongs to some other repository and changes nothing about this entry — carry its line count in `{detail}` so the count is on record even though the run passed |
| `blocked` | Nothing could be written and nothing was: `hash-id` exit 1 (no SHA-1 helper on this machine), `worklog-target.sh friday` exit 4 (no date arithmetic), `wiki-repo LOG` exit 3 (no LOG wiki repo configured), or `link-check.sh` exit 3 (`GITEA_HOST` unset) or exit 7 (token rejected). The gate stopped the run before a page was touched |
| `degraded` | The entry is on `LOG_{HASH}` but the close-out is short: `wiki-contents.sh upsert` returned non-zero so `LOG_CONTENTS` still carries the old row, or `worklog-pending.sh commit` exited 1 so the pending files survive a successful write and the next run merges them again |
| `degraded` | The entry is on `LOG_{HASH}` but the close-out is short: `wiki-contents.sh upsert` returned non-zero so `LOG_CONTENTS` still carries the old block, or `worklog-pending.sh commit` exited 1 so the pending files survive a successful write and the next run merges them again |
| `failed` | Nothing reached the wiki after the run started working: `link-check.sh` exit 1 stopped the write on a DEAD link, the `PAGE` read came back 7 or 8, or `worklog-pending.sh merge` exited 1 |
| `aborted` | The user stopped the run, or the trigger turned out not to hold — no task ended here, so there is no entry to write and none was attempted |