新增 scripts/worklog/worklog.mjs,逐段對應改寫 worklog.sh:log/nowStr 改 import 自 wiki_api.mjs,extractTurn/turnDuration/turnTokens/redact 改 import 自 transcript.mjs,appendEntry/resolveToken/weekPageName/ weekPageHeader 改 import 自 wiki_api.mjs,取代原本各自開子行程呼叫; stdin JSON 解析、遞迴防護、啟用檢查、Codex transcript fallback、 WORKLOG_SCOPE 過濾、專案判定、模型決定與快取過期、濃縮 prompt 九條規則 逐字保留,退出碼一律 0。hooks/hooks.json 的 Stop hook 改用 node 執行; README/worklog SKILL.md/wiki_api.mjs 檔頭註解同步更新指向 worklog.mjs。 舊 worklog.sh 暫未刪除:依規劃需先在 WORKLOG_ENABLED=1 的環境實測 hook 真的會觸發並成功寫入週頁,這個環境目前未設定,留待後續驗證後再處理。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
172 lines
14 KiB
Markdown
172 lines
14 KiB
Markdown
---
|
||
name: worklog
|
||
description: 工作證明自動記錄(worklog)的操作與維護 skill。搭配相容的 Stop hook,把每輪工作內容透過 README 定義的 headless CLI(claude/codex/agy/opencode/copilot)濃縮成精簡條目並追加到 Gitea wiki 的當週工作紀錄頁(Worklog-yyyy-MM-W<週>),工作內容全程不落地。提供 --init(初始化週頁與環境變數指引)、--tune(判定並快取最適合的 Claude 摘要模型)、--diagnose(診斷 hook 為何沒動作)、--append(手動補寫一筆)、--show(讀當週頁回顧)五個模式。當使用者說工作證明、工作紀錄、worklog、週報自動化、把工作內容寫到 wiki、記錄到 Gitea wiki、hook 沒有寫入 wiki、補寫工作紀錄、看本週做了什麼、重新判定摘要模型,或提到 WORKLOG_ENABLED/WORKLOG_HOST/WORKLOG_REPO/WORKLOG_MODEL/WORKLOG_CLI/WORKLOG_SCOPE 時觸發。不適用於:Gitea 議題操作(用 issues-sync/issues)、專案文件化(用 funcs)。
|
||
---
|
||
|
||
# worklog — 工作證明自動記錄
|
||
|
||
把「每輪做了什麼」濃縮成一則條目,追加到 Gitea wiki 的當週工作紀錄頁。**自動記錄由相容的 `Stop` hook 完成,不需使用者同意、不需人工觸發**;本 skill 負責自動路徑之外的人工操作:初始化、模型判定、診斷、補寫、回顧。
|
||
|
||
| 元件 | 觸發者 | 職責 |
|
||
| --- | --- | --- |
|
||
| `hooks/hooks.json` 的 `Stop` hook | harness 自動 | 每輪結束抽本輪內容 → 濃縮 → 遮蔽 → 追加到當週頁 |
|
||
| 本 skill `/jsc-doc:worklog` | 使用者/助理手動 | `--init`/`--tune`/`--diagnose`/`--append`/`--show` |
|
||
| `scripts/worklog/worklog.mjs` | 上述兩者共用 | 主流程(單一實作,避免漂移):依 `WORKLOG_CLI` 呼叫 headless CLI,每筆整理成七個固定欄位(含 token 用量) |
|
||
| `scripts/worklog/wiki_api.mjs` | 上述兩者共用 | token 解析、wiki 讀寫、append 重試、週頁命名 |
|
||
| `scripts/worklog/transcript.mjs` | 上述兩者共用 | 抽本輪片段、估算花費時間、統計 token 用量、機密遮蔽 |
|
||
|
||
### 各助理支援範圍
|
||
|
||
| 功能 | Claude Code | Codex | Antigravity | OpenCode | GitHub Copilot |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| `Stop` hook 自動記錄 | ✅ | ✅ 需可讀 Codex session JSONL | ❌ 無 hook 機制 | ❌ 無 hook 機制 | ✅(2026/08/11 實測確認,見下方說明) |
|
||
| `--init`/`--diagnose`/`--append`/`--show` | ✅ | ⚠️ 需 plugin 目錄保留 `scripts/`(安裝後請實測一次) | ⚠️ 同左 | ⚠️ 需完整 plugin 目錄 | ⚠️ 需 plugin 目錄保留 `scripts/` |
|
||
| 摘要 CLI | `claude -p` | `codex exec` | `agy -p` | `opencode run` | `copilot -p` |
|
||
| `--tune` | ✅ | ❌ 無 `claude-api` skill 可載入 | ❌ 同左 | ❌ | ❌ |
|
||
| token 用量統計 | ✅ 輸入/輸出皆可得 | ✅ 輸入/輸出皆可得 | ❌ 無 transcript 解析器 | ❌ 無 transcript 解析器 | ⚠️ 只有輸出,輸入固定「未判定」(見下方說明) |
|
||
|
||
限制與實測結果的來源:
|
||
|
||
- **`Stop` hook 只有相容 hook 環境實際執行**;Claude Code 先用 `CLAUDE_PLUGIN_ROOT` 定位腳本,找不到時依序掃 `~/.claude/plugins/cache`、`~/.codex/plugins/cache`、`~/.copilot/installed-plugins`,最後命中 `*/jsc-doc/*/scripts/worklog/worklog.mjs`。`transcript.mjs` 支援 Claude Code transcript JSONL(`type` / `message.content` blocks)、Codex session JSONL(`payload` events / response items)與 Copilot events.jsonl(`type` 為 `user.message`/`assistant.message`/`tool.execution_complete` 的 `data.*` 欄位),其他助理若提供等效 hook,必須先補對應 transcript 解析器。
|
||
- **Copilot 支援細節(2026/08/11 實測)**:Copilot CLI 內部事件名稱是 `agentStop`(不是 `Stop`),欄位為 camelCase(`sessionId`/`transcriptPath`,只有 `stop_hook_active` 例外仍是 snake_case);但實測確認 **Copilot 的 plugin 載入器會把 `hooks/hooks.json` 裡的 `Stop` key 自動對應到它自己的 `agentStop` 事件**,本檔不需要另外宣告 `agentStop` key。transcript 路徑固定為 `~/.copilot/session-state/<sessionId>/events.jsonl`,且 hook payload 直接帶 `transcriptPath`,不需要像 Codex 分支那樣自己用 session id 反查檔案。**Copilot 逐輪只記錄 `assistant.message.data.outputTokens`,沒有對應的輸入 token 欄位**;`session.shutdown.modelMetrics` 雖然有完整輸入/輸出,但那是整個 session 結束才寫的累計值,語意不是「本輪」,故 Copilot 的輸入 token 一律固定輸出「未判定」,不得用該欄位冒充本輪數字。
|
||
- **Antigravity(`agy`)不支援自動記錄的兩個具體原因**:(1) `agy --help` 沒有任何 hook 相關子指令或設定項,CLI 本身不提供事件觸發點(觸發點缺);(2) 就算有觸發點,`agy` 的對話記錄存在 `~/.gemini/antigravity-cli/conversations/*.db` 內,內容是 `step_payload`/`gen_metadata` 等欄位的 protobuf 二進位 blob、`step_type` 是數字 enum,沒有公開 `.proto` schema 可解析(資料缺)。兩個條件都不成立,之後要支援得兩者都解決,不是單純補一支 transcript 解析器就好。
|
||
- **OpenCode 不支援自動記錄的原因**:目前的 skill 目錄安裝法本來就不含 `scripts/`,且其 CLI 同樣未見 hook 機制文件;若之後提供對應的 hook 機制與可讀的 transcript 格式,才有辦法補上,純粹「以完整 plugin 目錄執行」不足以讓自動記錄運作。
|
||
- **OpenCode 以「複製 `skills/` 目錄」安裝**時不會帶入 `scripts/`,本 skill 的所有模式都無法執行;若以完整 plugin 目錄執行並能解析 `scripts/worklog`,可用 `WORKLOG_CLI=opencode` 作為摘要 CLI。
|
||
- 其他助理若要用 `--append`/`--show` 等純 wiki 操作,只需 `node`;摘要路徑需要 README 定義的任一 headless CLI。`--tune` 仍是 Claude Code 專屬,其他 CLI 使用各自預設模型或手動設定其 CLI 行為。
|
||
|
||
### 腳本路徑解析(重要)
|
||
|
||
依 `/jsc-shared:spec-script-path`(寫法一:多行版)解析 plugin 根目錄,全文以 `${WORKLOG_DIR}` 表示該目錄:
|
||
|
||
```bash
|
||
# Claude Code
|
||
WORKLOG_DIR="${CLAUDE_PLUGIN_ROOT}/scripts/worklog"
|
||
|
||
# 其他助理:以 skill base directory 推導(<base>/../.. 即 plugin 根)
|
||
WORKLOG_DIR="<skill base directory>/../../scripts/worklog"
|
||
```
|
||
|
||
若解析不到或該目錄不存在,依 spec-script-path 的標準錯誤處理回報並停止,不要改用相對路徑重試。
|
||
|
||
---
|
||
|
||
## 共用規範(必要前置)
|
||
|
||
先載入 `/jsc-shared:spec-preflight` 並依其流程處理;載入不到即代表 shared plugin 未安裝,
|
||
依該 spec 詢問使用者是否安裝 `https://gitea.jsc.idv.tw/plugins/shared.git`,不安裝則中斷本 skill。
|
||
本 skill 需要的規範:`spec-version-guard`、`spec-output`、`spec-execution`、`spec-gitea`、`spec-time-log`、`spec-no-scratch-files`、`spec-script-path`、`spec-skill-invocation`、`spec-model`
|
||
|
||
本 skill 特有補充:
|
||
|
||
- **工作內容不落地**:依 `/jsc-shared:spec-no-scratch-files` 執行(transcript 片段只在程序記憶體與 stdin/stdout 間傳遞、wiki 走 API 不 clone,全程不產生暫存檔)。**本 skill 特有例外**:唯一允許落地的是**模型快取檔** `~/.claude/worklog/model`(僅含模型 id 與判定時間,不含任何工作內容)。
|
||
- **絕不阻斷**:hook 路徑任何失敗都以 exit 0 結束,只在 stderr 留訊息。
|
||
|
||
---
|
||
|
||
## 環境變數
|
||
|
||
| 變數 | 必要 | 說明 | 未設定 |
|
||
| --- | --- | --- | --- |
|
||
| `WORKLOG_ENABLED` | ✅ | 總開關,設為 `1` 才啟用 | hook 立即結束,完全不動作 |
|
||
| `WORKLOG_HOST` | ✅ | Gitea 主機,如 `gitea.housefun.com.tw` | 不啟用 |
|
||
| `WORKLOG_REPO` | ✅ | wiki 所在 repo,如 `H3285/WorkLog` | 不啟用 |
|
||
| `WORKLOG_MODEL` | | 強制指定摘要模型 | 讀快取檔 → 保底 `claude-haiku-4-5-20251001` |
|
||
| `WORKLOG_CLI` | | 摘要執行器:`auto`/`claude`/`codex`/`agy`/`opencode`/`copilot` | `auto`,先依目前 hook/session 環境判斷正在使用的 CLI,判斷不到或該 CLI 不可執行時才 fallback 到已安裝工具 |
|
||
| `WORKLOG_SCOPE` | | 冒號分隔的路徑前綴,僅這些路徑下的 session 才記 | 全部 session 都記 |
|
||
| `WORKLOG_ERRLOG` | | 錯誤訊息額外寫入的檔案路徑(只記錯誤、不含工作內容) | 只走 stderr |
|
||
|
||
**token 不需另設變數**,依 /jsc-shared:spec-gitea 的『token 解析優先序』自動解析並實際驗證(worklog 沒有專用變數,直接從 GITEA_TOKEN 開始)。
|
||
|
||
---
|
||
|
||
## 模式
|
||
|
||
### `--init`
|
||
|
||
1. 執行 `node "${WORKLOG_DIR}/wiki_api.mjs" probe`,回報 token 來源、Gitea 版本、當週頁狀態。
|
||
2. 當週頁不存在 → 執行 `node "${WORKLOG_DIR}/wiki_api.mjs" init` 建立(wiki 尚未初始化時一併初始化)。
|
||
3. 以表格印出應寫入 `~/.bashrc` 的 `WORKLOG_*` 變數清單;**不自動改使用者的 shell profile**(需人工確認的狀態變更)。
|
||
|
||
### `--tune`(Claude Code 專屬)
|
||
|
||
決定「目前最適合的摘要模型」並快取,`Stop` hook 只讀快取、**絕不自行呼叫 AI 判斷**(否則就變成雞生蛋,還會拖慢使用者的等待路徑)。
|
||
|
||
本模式需要 Claude Code 內建的 `claude-api` skill 與 `claude` CLI,**其他助理無法執行**:請改為手動設定 `WORKLOG_MODEL` 環境變數指定模型,或沿用保底模型。
|
||
|
||
| 步驟 | 動作 |
|
||
| --- | --- |
|
||
| 1 | 以 Skill 工具呼叫 `/jsc-shared:models --task summary` 取得推薦模型——探測、評分(延遲敏感、輕量摘要、低成本等 `spec-model` 對映表定義的必要標籤)、smoke test 全由該 skill 依 `/jsc-shared:spec-model` 完成,本模式不重寫這套邏輯、不自行載入 `claude-api` 或另跑 smoke test |
|
||
| 2 | 取推薦結果的模型 id 與一行理由,寫入 worklog 專屬快取檔 `~/.claude/worklog/model`(`model=<id>`、`tuned_at=<時間>`、`reason=<一行理由>`)——此檔與 `models` skill 自身的 `~/.claude/jsc/models.json` 快取用途不同(前者是 worklog hook 專讀的精簡快取,後者是全模型清單快取),兩者不合併、不互相讀取、不共用格式 |
|
||
| 3 | 回報選擇與理由 |
|
||
|
||
快取超過 **30 天** 視為過期:hook 改用保底模型 `claude-haiku-4-5-20251001`,並在條目標記 `(model: fallback)`,`--diagnose` 會提醒重跑 `--tune`。
|
||
|
||
### `--diagnose`
|
||
|
||
逐項檢查並以表格回報,用於「hook 沒有寫入 wiki」時定位:
|
||
|
||
| 檢查項 | 判準 |
|
||
| --- | --- |
|
||
| `node`/摘要 CLI | `node` 與 `WORKLOG_CLI` 指定或 auto 選到的 CLI 是否找得到 |
|
||
| `WORKLOG_*` 變數 | 必要三項是否齊全、`WORKLOG_SCOPE` 是否把當前路徑排除 |
|
||
| `scripts/worklog` 目錄 | `${WORKLOG_DIR}` 是否解析成功且三支腳本存在(不存在=此助理不支援) |
|
||
| token | `node "${WORKLOG_DIR}/wiki_api.mjs" probe` 的 token 來源與驗證結果 |
|
||
| wiki API | Gitea 版本、`repos/<repo>` 與當週頁狀態 |
|
||
| 摘要設定 | `WORKLOG_CLI`、選到的 CLI、Claude 模型快取是否存在與是否過期 |
|
||
| hook 註冊 | `hooks/hooks.json` 是否存在且 plugin 已啟用 |
|
||
|
||
### `--append "<內容>"`
|
||
|
||
手動補寫一筆(hook 漏記、離線工作、或事後補充)。條目格式與自動路徑一致:
|
||
|
||
```
|
||
## <時間> — <專案> <!-- worklog:<時間戳>-manual -->
|
||
- 專案/任務名稱:<專案或任務>
|
||
- 執行細節與產出:<做了什麼、動到什麼、產出為何>
|
||
- 花費時間:<實際耗時或未判定>
|
||
- 任務狀態:<完成/進行中/待確認/受阻>
|
||
- 遇到的困難:<困難或未遇到明確困難>
|
||
- 解決方式:<處理方式或不需額外處理>
|
||
- token 用量:<輸入/輸出或未判定>
|
||
```
|
||
|
||
專案取當前工作目錄的 `<owner>/<repo>`;內容仍會過 `node "${WORKLOG_DIR}/transcript.mjs" redact` 遮蔽後才寫入。手動補寫沒有 transcript 可解析,`token 用量` 固定寫「未判定」。
|
||
|
||
### `--show`
|
||
|
||
讀當週頁(`node "${WORKLOG_DIR}/wiki_api.mjs" show`)並以表格摘要本週工作,用於回顧與週報。
|
||
|
||
---
|
||
|
||
## 條目與頁面格式
|
||
|
||
- **週以星期六起算(六~五)**,因此換頁一律發生在星期六,與星期對齊。
|
||
- 週頁名稱:`Worklog-<yyyy>-<MM>-W<n>`,`n` =該週起始的星期六是當月第幾個星期六(例:`2026/07/29 三` 屬於 `07/25 六` 那一週 → `Worklog-2026-07-W4`)。
|
||
- 跨月的一週歸屬**起始星期六**所在的月份,確保同一週只有一頁(例:`2026/08/29 六 ~ 09/04 五` 全部寫入 `Worklog-2026-08-W5`)。
|
||
- 頁首標題:`# <yyyy> 年 <MM> 月 第 <n> 週工作紀錄(<起始日> 六 ~ <結束日> 五)`,日期範圍讓人一眼看出這頁涵蓋哪幾天。
|
||
- 每筆條目:`## <時間> — <專案>` +七個固定 bullet(專案/任務名稱、執行細節與產出、花費時間、任務狀態、遇到的困難、解決方式、token 用量);標題行尾帶 HTML 註解 marker(`<!-- worklog:… -->`)供寫後驗證與去重,wiki 渲染時不顯示。
|
||
- 多 session 同時寫入:`append_entry` 採「讀取 → 合併 → 寫回 → 寫後讀取驗證 marker」,未落地則重讀最新內容重試,最多 3 次。
|
||
|
||
---
|
||
|
||
## 機密與 PII(兩道防線)
|
||
|
||
| 防線 | 位置 | 內容 |
|
||
| --- | --- | --- |
|
||
| 1 | 濃縮提示詞 | 明令不得輸出 token/密碼/API key/連線字串/Email/電話/姓名/身分證號 |
|
||
| 2 | `transcript.mjs` 的 `redact` | 正則遮蔽:URL 內嵌憑證、40 字元 hex token、`gh?_`/`sk-` token、`token=`/`password=`、`Authorization:`、Email、台灣手機、身分證號 |
|
||
|
||
第二道防線不可移除 —— 模型有可能沒遵守指令,而 wiki 一旦寫入就留在 git 歷史裡。
|
||
|
||
---
|
||
|
||
## 呼叫方式
|
||
|
||
依 `/jsc-shared:spec-skill-invocation` 的統一呼叫方式,本 skill 的實際參數格式與範例:
|
||
|
||
| 助理 | 呼叫 |
|
||
| --- | --- |
|
||
| Claude Code / Antigravity | `/jsc-doc:worklog --init`、`/jsc-doc:worklog --tune`、`/jsc-doc:worklog --diagnose`、`/jsc-doc:worklog --append "修正 X 的 Y 問題"`、`/jsc-doc:worklog --show` |
|
||
| Codex | `$worklog --diagnose`,或用 `/skills` 選單;可設 `WORKLOG_CLI=codex` |
|
||
| OpenCode / GitHub Copilot | 需完整 plugin 目錄保留 `scripts/`;可設 `WORKLOG_CLI=opencode` 或 `WORKLOG_CLI=copilot` |
|