From 975ac7886e3d6149df69a72bcb1a4f92be3ca5f2 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Wed, 29 Jul 2026 19:09:18 +0800 Subject: [PATCH] =?UTF-8?q?fix(worklog):=20=E9=80=B1=E9=A0=81=E6=94=B9?= =?UTF-8?q?=E7=82=BA=E6=98=9F=E6=9C=9F=E5=85=AD=E8=B5=B7=E7=AE=97=EF=BC=8C?= =?UTF-8?q?=E6=8F=9B=E9=A0=81=E8=88=87=E6=98=9F=E6=9C=9F=E5=B0=8D=E9=BD=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 舊規則以 ceil(日/7) 分週,換頁點固定落在每月 8/15/22/29 號,會把同一個 工作週切成兩頁(例:2026/07/28 二 在 W4、07/29 三 卻跳到 W5)。使用者開著 舊頁時看不到新條目,會誤判成 worklog 停止記錄。 - 週以星期六起算(六~五),週頁以該週起始的星期六為錨點命名 - W 的 n =該星期六是當月第幾個星期六,頁名格式不變,舊頁照樣可讀 - 跨月的一週歸屬起始星期六所在月份,確保同一週只有一頁 (2026/08/29 六 ~ 09/04 五 全部寫入 Worklog-2026-08-W5) - 頁首標題補上日期範圍,開頁即可看出涵蓋哪幾天,避免再次誤判 - week_page_header 原本收了 page 卻不使用,一律以當下時間算標題,手動補寫 舊頁時會寫錯週;改為從頁名反推所屬週 - 同步 SKILL.md 與 README.md 的分週說明 驗證:2026/01/01 ~ 2027/12/31 每日「頁名 → 反推週起始日」全部一致(0 筆不符), 月初、月末與跨月邊界皆正確。 Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 2 +- scripts/worklog/wiki_api.py | 67 ++++++++++++++++++++++++++++++++----- skills/worklog/SKILL.md | 6 ++-- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a76aead..4a1d8de 100644 --- a/README.md +++ b/README.md @@ -257,7 +257,7 @@ copilot plugin marketplace remove doc ### `worklog` -工作證明自動記錄與手動維護流程。相容的 `Stop` hook 會把每輪工作透過 `WORKLOG_CLI` 指定的 headless CLI 整理成六個固定欄位:專案/任務名稱、執行細節與產出、花費時間、任務狀態、遇到的困難、解決方式,並追加到 Gitea wiki 當週頁(`Worklog-yyyy-MM-W<週>`)。手動模式提供 `--init`、`--tune`(Claude Code 專屬)、`--diagnose`、`--append`、`--show`。 +工作證明自動記錄與手動維護流程。相容的 `Stop` hook 會把每輪工作透過 `WORKLOG_CLI` 指定的 headless CLI 整理成六個固定欄位:專案/任務名稱、執行細節與產出、花費時間、任務狀態、遇到的困難、解決方式,並追加到 Gitea wiki 當週頁(`Worklog-yyyy-MM-W<週>`,**週以星期六起算**,換頁固定發生在星期六)。手動模式提供 `--init`、`--tune`(Claude Code 專屬)、`--diagnose`、`--append`、`--show`。 - **Claude Code / Antigravity**:`/jsc-doc:worklog --diagnose` - **Codex**:`$worklog --diagnose`,或用 `/skills` 選單 diff --git a/scripts/worklog/wiki_api.py b/scripts/worklog/wiki_api.py index 61df289..98a020b 100755 --- a/scripts/worklog/wiki_api.py +++ b/scripts/worklog/wiki_api.py @@ -3,7 +3,7 @@ # 用途:Gitea Wiki 讀寫工具(worklog 專用)。提供 token 解析、頁面讀取、 # 建立、append 追加(read-modify-write + 寫後驗證重試),供 worklog.sh # 與 /jsc-doc:worklog skill 共用,避免兩份實作漂移。 -# 更新時間:2026/07/27 11:14:16 +# 更新時間:2026/07/29 19:03:29 # 相依:Python 3 標準庫(urllib、base64、json、re)。不需 requests、不需 jq。 # 機密:token 一律從環境變數或本機憑證檔讀取,絕不輸出、絕不寫入任何檔案。 # ============================================================================== @@ -307,18 +307,67 @@ def append_entry(host, repo, token, page, header, entry, marker, retries=3): # 週頁命名 # ------------------------------------------------------------------------------ -def week_page_name(when=None): - """依台灣時區產生週頁名稱 Worklog-yyyy-MM-W<該月第幾週>(第幾週=ceil(日/7))。""" +# 週的定義:星期六起算(六~五),週頁以該週起始的星期六為錨點命名。 +# 舊規則以 ceil(日/7) 分週,換頁點固定落在每月 8/15/22/29 號,會把同一個工作週 +# 切成兩頁(例:2026/07/28 二 在 W4、07/29 三 卻跳到 W5),使用者開著舊頁會誤判成 +# 「worklog 停止記錄」。改以星期六為界後,換頁一律發生在週六,與星期對齊。 +WEEK_START_WEEKDAY = 5 # Python weekday():週一 0、週二 1 …… 週六 5、週日 6 + + +def week_start(when=None): + """取得指定時間所屬工作週的起始日(該週的星期六;當天就是星期六時回傳當天)。""" when = when or datetime.now(TAIPEI) - week = (when.day + 6) // 7 - return f"Worklog-{when.year:04d}-{when.month:02d}-W{week}" + return when - timedelta(days=(when.weekday() - WEEK_START_WEEKDAY) % 7) + + +def week_start_from_page(page): + """ + 從週頁名稱反推該週起始的星期六。 + + 供手動指定頁面時產生正確標題;格式不符或該月不存在第 n 個星期六時回傳 None。 + """ + if not page: + return None + matched = re.match(r"^Worklog-(\d{4})-(\d{2})-W(\d)$", page.strip()) + if not matched: + return None + year, month, week = (int(matched.group(i)) for i in (1, 2, 3)) + try: + first_day = datetime(year, month, 1, tzinfo=TAIPEI) + except ValueError: + return None + first_saturday = first_day + timedelta(days=(WEEK_START_WEEKDAY - first_day.weekday()) % 7) + start = first_saturday + timedelta(days=7 * (week - 1)) + return start if start.month == month else None + + +def week_page_name(when=None): + """ + 依台灣時區產生週頁名稱 Worklog-yyyy-MM-W。 + + 週以星期六起算(六~五),n =該週起始的星期六是當月第幾個星期六。 + 跨月的一週歸屬起始星期六所在的月份,確保同一週只會有一頁 + (例:2026/08/29 六 ~ 09/04 五 都寫入 Worklog-2026-08-W5)。 + """ + start = week_start(when) + week = (start.day - 1) // 7 + 1 + return f"Worklog-{start.year:04d}-{start.month:02d}-W{week}" def week_page_header(page=None, when=None): - """產生週頁首行標題(例:# 2026 年 07 月 第 4 週工作紀錄)。""" - when = when or datetime.now(TAIPEI) - week = (when.day + 6) // 7 - return f"# {when.year} 年 {when.month:02d} 月 第 {week} 週工作紀錄" + """ + 產生週頁首行標題(例:# 2026 年 07 月 第 4 週工作紀錄(07/25 六 ~ 07/31 五))。 + + 標題含日期範圍,讓開頁的人一眼看出這頁涵蓋哪幾天,不必回頭推算週次。 + 傳入 page 時以頁名反推所屬週,避免手動補寫舊頁時寫入當下這週的標題。 + """ + start = week_start_from_page(page) or week_start(when) + end = start + timedelta(days=6) + week = (start.day - 1) // 7 + 1 + return ( + f"# {start.year} 年 {start.month:02d} 月 第 {week} 週工作紀錄" + f"({start.month:02d}/{start.day:02d} 六 ~ {end.month:02d}/{end.day:02d} 五)" + ) # ------------------------------------------------------------------------------ diff --git a/skills/worklog/SKILL.md b/skills/worklog/SKILL.md index a7bc13d..ff379f8 100644 --- a/skills/worklog/SKILL.md +++ b/skills/worklog/SKILL.md @@ -148,8 +148,10 @@ GITEA_TOKEN →(對目標 host 驗證失敗時)→ tea 設定檔中該 host ## 條目與頁面格式 -- 週頁名稱:`Worklog---W<該月第幾週>`,第幾週 = `ceil(日/7)`(例:`2026/07/27` → `Worklog-2026-07-W4`)。 -- 頁首標題:`# 月 第 <週> 週工作紀錄`。 +- **週以星期六起算(六~五)**,因此換頁一律發生在星期六,與星期對齊。 +- 週頁名稱:`Worklog---W`,`n` =該週起始的星期六是當月第幾個星期六(例:`2026/07/29 三` 屬於 `07/25 六` 那一週 → `Worklog-2026-07-W4`)。 +- 跨月的一週歸屬**起始星期六**所在的月份,確保同一週只有一頁(例:`2026/08/29 六 ~ 09/04 五` 全部寫入 `Worklog-2026-08-W5`)。 +- 頁首標題:`# 月 第 週工作紀錄(<起始日> 六 ~ <結束日> 五)`,日期範圍讓人一眼看出這頁涵蓋哪幾天。 - 每筆條目:`## <時間> — <專案>` +六個固定 bullet(專案/任務名稱、執行細節與產出、花費時間、任務狀態、遇到的困難、解決方式);標題行尾帶 HTML 註解 marker(``)供寫後驗證與去重,wiki 渲染時不顯示。 - 多 session 同時寫入:`append_entry` 採「讀取 → 合併 → 寫回 → 寫後讀取驗證 marker」,未落地則重讀最新內容重試,最多 3 次。