Files
log/skills/report/SKILL.md
T
jiantw83 7d803245a5 fix(overwrite): 只有頁面真的不存在才建新頁
- What:worklog、learn、report 三支技能共六處讀取分流改寫,只有結束碼 4 才建新頁;
  結束碼 7 與 8 一律中止,一個字都不寫。三份目錄頁樣板補上寫入語意,明寫禁止整頁覆蓋、
  不得改動別人的列。usage-stats.sh 的參數護欄改成明確回傳結束碼 2。
- Why:原本把「讀失敗」與「頁面不存在」當成同一件事。金鑰失效時讀取回 7,技能卻讀成
  「這頁還沒有」,於是照樣板建一份新頁蓋回去。整份工作日誌會被這一筆條目取代,
  既有教訓會被清成空表,報表則產出一份說「這段期間沒有工作」的假數字。
  這些內容只活在 wiki 上,蓋掉就救不回來,所以這是本輪最要緊的一項。
- How:每一處讀取都先看結束碼再決定動作,並在技能文件裡列成表格:
  0 接在既有內容後面附加,4 才從樣板建頁,5 缺網址就中止,7 金鑰或權限問題就中止,
  8 其他 API 失敗就中止。目錄頁一律先讀整頁再改那一列。
  stats 也補上分流,參數錯誤不再被讀成「零次」。
- Who:worklog、learn、report、stats 四支技能的 wiki 讀寫與統計輸出。
2026-08-31 11:07:16 +08:00

8.6 KiB

name, description
name description
report Summarise work logs into a yearly, monthly, weekly or daily report. Resolve the period with tools/report-range.sh, resolve the template with tools/report-template.sh - a project's .jsc/templates/report-{period}.md wins over the skill's own copy - then read every log page listed in LOG_CONTENTS and keep the entries dated inside the range. Fill the template with real aggregates (entry count, repositories, elapsed time, token usage, blockers, carry-overs) and write it to wiki REPORT_{HASH}, hashed from {owner}/{repo}/{period}, appending the period as a new section. Use when someone asks for a work summary over a period; not for recording a single work package, which is jsc-log:worklog.

report — summarise work logs by period

Reading and aggregating the log pages MUST run as a sub agent: it reads every page in LOG_CONTENTS and only a handful of entries survive the date filter. Report content is written in Traditional Chinese (STE100).

1. Period

Ask for the period per the jsc-ask:ask rules when the caller did not name one: daily, weekly, monthly, yearly. Each option states what it covers.

Run tools/report-range.sh {period} [yyyy-MM-dd]. It prints {start}<TAB>{end}<TAB>{label}<TAB>{period}, both dates inclusive. The base date defaults to today; pass one to re-run an earlier period.

Exit Meaning Do
0 Range printed Read start, end and label out of the four fields
2 Period name or base date rejected Ask per the jsc-ask:ask rules which of the four periods was meant, or fix the yyyy-MM-dd base date, then rerun
4 This machine's date does no date arithmetic Stop and report that the range cannot be computed here. Never work the dates out by hand: week boundaries and month lengths are exactly where a hand-rolled range quietly loses a day

Done when start, end and label are known.

2. Resolve and collect

Run these four lines of work in parallel — none of them consumes another's output, and the log pages are the slow one:

  1. Template. tools/report-template.sh resolve {period} from the working directory prints {path}<TAB>{project|skill}.
  2. Log pages. jsc-gitea/tools/gitea.sh wiki-repo LOG, then read LOG_CONTENTS through jsc-gitea:wiki, then read every log page it lists, one sub agent per page.
  3. Lessons (yearly only). gitea.sh wiki-repo LEARN, then read LEARN_CONTENTS through jsc-gitea:wiki for the 全年教訓 section. Resolve JSC_WIKI_REPO_LEARN on its own: the LOG repo resolved in line 2 never stands in for it, and LOG and LEARN pages routinely live in different wiki repos. Other periods skip this line.
  4. Report repo. gitea.sh wiki-repo REPORT, so step 3 has its target ready.

Exit branches for the external calls above:

Call Exit Do
report-template.sh resolve 0 Use the path; name the project or skill source in the final report. project means the working directory holds .jsc/templates/report-{period}.md and that file wins — the same period rendered from two templates has to be traceable to the file that shaped it
report-template.sh resolve 2 Period name or start directory rejected. Rerun from the working directory with the period from step 1
report-template.sh resolve 3 Neither the project copy nor the skill's own copy exists. Stop and report that templates/report-{period}.md is missing from the plugin; do not invent a layout
gitea.sh wiki-repo LOG 3 Stop and report that no wiki repo is configured for LOG, naming JSC_WIKI_REPO_LOG and JSC_WIKI_REPO. Ask per the jsc-ask:ask rules, then rerun. Without log pages there is nothing to summarise
gitea.sh wiki-repo LEARN 3 Fill the 全年教訓 section with 無 and say the LEARN wiki repo is unset. The rest of the yearly report still stands
gitea.sh wiki-repo REPORT 3 Carry on collecting; step 3 handles the skipped write
gitea.sh wiki-repo any type 2 The page type was misspelled. Fix the argument and rerun
jsc-gitea:wiki read 4 The page is genuinely absent. Only this code lets LOG_CONTENTS or a listed log page count as zero entries; name it in the close-out
jsc-gitea:wiki read 7 The token is invalid or lacks permission. Stop and report the token problem. Counting this as zero entries publishes a report that says a period held no work when the work is sitting on a page nobody managed to read
jsc-gitea:wiki read 8 Some other API failure. Stop and report that status; a page that failed to load must never be counted as an empty page

Then aggregate. Save the collected page contents to files and run:

tools/log-aggregate.sh {start} {end} {page file} ...

It prints ENTRIES=, REPOS=, one REPO= line per repository, ELAPSED_MINUTES=, ELAPSED_ENTRIES=, ELAPSED_MISSING=, one TOKEN= line per CLI, TOKEN_MISSING= and one STATUS= line per status. It enforces the no-estimate rule in code: an entry with no 花費時間 stays out of the total and lands in ELAPSED_MISSING, and a range where nothing carried a time prints ELAPSED_MINUTES=無資料 rather than 0.

Exit Meaning Do
0 Aggregates printed Carry the printed values into the template unchanged. Never recompute or round them by hand
2 Dates rejected, or start later than end Rerun with the step 1 values
3 Zero entries inside the range; the zero-filled aggregate is still printed Produce the report anyway, with counts of 0 and a line naming the empty range. A silent "no report" cannot be told apart from a failure
4 A page file is unreadable Stop and report which file, rather than reporting a smaller total

Blockers and unfinished work packages come from the 任務狀態 and 遇到的困難與解決方式 parts of the surviving entries; the sub agent lists them verbatim.

Done when the template path, its source, the aggregate lines and the blocker list are all in hand.

3. Write

Follow the template's headings and tables exactly, including ones with no data: an empty section stated as 無 is information, a silently dropped section is not.

Write through jsc-gitea:wiki:

  • Repo: the REPORT repo from step 2, line 4.
  • Page: REPORT_ plus gitea.sh hash-id "{owner}/{repo}/{period}", where {owner}/{repo} is the REPORT wiki repo. Year, month, week and day each get their own page.
  • Read the page first and branch on the exit code the underlying gitea.sh wiki-get returned. Only exit 4 means the page is not there yet and may be built from scratch. On exit 0 the existing sections are in hand, so append into them. On exit 7 the token is invalid or lacks permission, and on exit 8 the API failed some other way: both leave the earlier periods unknown, so stop, report the status and write nothing — a page rebuilt on top of an unread read loses every period already on it.
  • Append this period as a new section, newest first. Rerunning the same period replaces that period's section only, leaving the other periods untouched.
  • Refresh the page's row in REPORT_CONTENTS from templates/report-contents.md: add the row if missing, otherwise refresh its 最新一期、期數 and 最後更新. Its read branches the same way — only exit 4 creates the directory page from the template, while 7 and 8 stop the run. Touch no row that belongs to another report page.
Call Exit Do
gitea.sh wiki-repo REPORT 3 Print the finished report and say the write was skipped because no wiki repo is configured for REPORT. The report itself is still the deliverable
gitea.sh hash-id 1 No SHA-1 helper on this machine. Stop and report that sha1sum or shasum has to be installed. Never hand-compute the hash
jsc-gitea:wiki write failure Retry once. Still failing, stop and report the page name that was not written, and print the report body so the work is not lost. Never report a page as written when it was not

Write the content page before its row in REPORT_CONTENTS, never the two at once: a directory row pointing at a page whose write failed is worse than a missing row.

Done when the page URL is reported, or the skipped write is reported with its reason, or the run stopped on a read that returned 7 or 8 and that status was reported.

4. Close

State the period label, entry count, repositories covered, template source, and the page URL. Name every unfinished work package that carried over — that list is what the next period starts from. State ELAPSED_MISSING and TOKEN_MISSING whenever either is above 0, so a small total is read as missing data rather than a light week.

Done when those five facts, the carry-over list and the two missing-data counts are stated.