devlog-tracker 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +234 -0
- package/bin/devlog-tracker.js +51 -0
- package/cli/init.js +55 -0
- package/cli/init.test.js +37 -0
- package/cli/merge-hooks.js +60 -0
- package/cli/merge-hooks.test.js +187 -0
- package/cli/platforms/codex.js +13 -0
- package/cli/platforms/cursor.js +13 -0
- package/cli/status.js +14 -0
- package/cli/status.test.js +33 -0
- package/cli/vendor.js +37 -0
- package/cli/vendor.test.js +84 -0
- package/codex/hooks/on-pre-tool.sh +19 -0
- package/codex/hooks/on-session-end.sh +31 -0
- package/codex/hooks/on-session-start.sh +37 -0
- package/codex/hooks/on-stop.sh +18 -0
- package/codex/hooks/on-user-prompt-submit.sh +15 -0
- package/codex/hooks/project-dir.sh +13 -0
- package/codex/hooks/test-adapters.sh +98 -0
- package/codex/hooks.json +54 -0
- package/commands/checkpoint.md +17 -0
- package/commands/clean.md +50 -0
- package/commands/compact.md +24 -0
- package/commands/continue.md +30 -0
- package/commands/keep.md +100 -0
- package/commands/lessons-drift.md +19 -0
- package/commands/lessons-off.md +16 -0
- package/commands/lessons-on.md +20 -0
- package/commands/lessons.md +20 -0
- package/commands/overview.md +32 -0
- package/commands/pause.md +20 -0
- package/commands/resume.md +18 -0
- package/commands/segment-watch.md +21 -0
- package/commands/span.md +13 -0
- package/commands/start.md +19 -0
- package/commands/status.md +14 -0
- package/cursor/hooks/on-pre-tool.sh +24 -0
- package/cursor/hooks/on-session-end.sh +11 -0
- package/cursor/hooks/on-session-start.sh +15 -0
- package/cursor/hooks/on-stop.sh +44 -0
- package/cursor/hooks/on-submit-prompt.sh +28 -0
- package/cursor/hooks/on-tool-failure.sh +16 -0
- package/cursor/hooks/project-dir.sh +10 -0
- package/cursor/hooks/test-adapters.sh +201 -0
- package/cursor/hooks.json +26 -0
- package/hooks/scripts/await-open.sh +23 -0
- package/hooks/scripts/checkpoint-set.sh +44 -0
- package/hooks/scripts/clean-devlog.sh +69 -0
- package/hooks/scripts/close-open-round.sh +186 -0
- package/hooks/scripts/compact-devlog.sh +72 -0
- package/hooks/scripts/detect-pending-question.sh +31 -0
- package/hooks/scripts/devlog-lock.sh +38 -0
- package/hooks/scripts/devlog-md.sh +222 -0
- package/hooks/scripts/devlog-path.sh +70 -0
- package/hooks/scripts/enforce-devlog.sh +629 -0
- package/hooks/scripts/files-snapshot.sh +70 -0
- package/hooks/scripts/json-field.sh +76 -0
- package/hooks/scripts/keep-move.sh +155 -0
- package/hooks/scripts/kept-list.sh +40 -0
- package/hooks/scripts/lessons-append.sh +93 -0
- package/hooks/scripts/lessons-drift-set.sh +42 -0
- package/hooks/scripts/lessons-off.sh +15 -0
- package/hooks/scripts/lessons-on.sh +21 -0
- package/hooks/scripts/lessons-read.sh +60 -0
- package/hooks/scripts/on-session-end.sh +14 -0
- package/hooks/scripts/on-stop-failure.sh +18 -0
- package/hooks/scripts/on-tool-failure.sh +25 -0
- package/hooks/scripts/pause-devlog.sh +13 -0
- package/hooks/scripts/redact-prompt.sh +19 -0
- package/hooks/scripts/resume-devlog.sh +41 -0
- package/hooks/scripts/round-start.sh +333 -0
- package/hooks/scripts/run-tests.sh +26 -0
- package/hooks/scripts/segment-watch-set.sh +47 -0
- package/hooks/scripts/segment-watch.sh +197 -0
- package/hooks/scripts/session-start-devlog.sh +157 -0
- package/hooks/scripts/span-close.sh +9 -0
- package/hooks/scripts/span-open.sh +21 -0
- package/hooks/scripts/start-devlog.sh +24 -0
- package/hooks/scripts/status-devlog.sh +43 -0
- package/hooks/scripts/tests/test-await-open.sh +112 -0
- package/hooks/scripts/tests/test-branch-scoped-integration.sh +108 -0
- package/hooks/scripts/tests/test-checkpoint-set.sh +36 -0
- package/hooks/scripts/tests/test-clean-devlog.sh +160 -0
- package/hooks/scripts/tests/test-cli-init-e2e.sh +37 -0
- package/hooks/scripts/tests/test-close-open-round.sh +325 -0
- package/hooks/scripts/tests/test-compact-devlog.sh +62 -0
- package/hooks/scripts/tests/test-devlog-lock.sh +37 -0
- package/hooks/scripts/tests/test-devlog-md.sh +530 -0
- package/hooks/scripts/tests/test-devlog-path.sh +118 -0
- package/hooks/scripts/tests/test-enforce-devlog-files.sh +233 -0
- package/hooks/scripts/tests/test-enforce-devlog-handoff-order.sh +223 -0
- package/hooks/scripts/tests/test-enforce-devlog-workspace.sh +333 -0
- package/hooks/scripts/tests/test-enforce-devlog.sh +1290 -0
- package/hooks/scripts/tests/test-files-snapshot.sh +142 -0
- package/hooks/scripts/tests/test-json-field.sh +57 -0
- package/hooks/scripts/tests/test-keep-move.sh +127 -0
- package/hooks/scripts/tests/test-kept-list.sh +80 -0
- package/hooks/scripts/tests/test-lessons-append.sh +138 -0
- package/hooks/scripts/tests/test-lessons-drift-set.sh +36 -0
- package/hooks/scripts/tests/test-lessons-on-off.sh +75 -0
- package/hooks/scripts/tests/test-lessons-read.sh +97 -0
- package/hooks/scripts/tests/test-on-interrupt.sh +186 -0
- package/hooks/scripts/tests/test-redact-prompt.sh +27 -0
- package/hooks/scripts/tests/test-resume-devlog.sh +35 -0
- package/hooks/scripts/tests/test-round-start.sh +825 -0
- package/hooks/scripts/tests/test-segment-watch-set.sh +75 -0
- package/hooks/scripts/tests/test-segment-watch.sh +468 -0
- package/hooks/scripts/tests/test-session-start-devlog.sh +508 -0
- package/hooks/scripts/tests/test-start-pause-devlog.sh +84 -0
- package/hooks/scripts/tests/test-status-span.sh +50 -0
- package/hooks/scripts/tests/test-workspace-snapshot.sh +130 -0
- package/hooks/scripts/workspace-snapshot.sh +69 -0
- package/package.json +37 -0
- package/skills/devlog-tracker/SKILL.md +411 -0
- package/skills/devlog-tracker/references/checkpoint-mode.md +42 -0
- package/skills/devlog-tracker/references/lessons-mode.md +32 -0
- package/skills/devlog-tracker/references/reply-fold.md +129 -0
- package/skills/devlog-tracker/references/round-segments.md +55 -0
- package/skills/devlog-tracker/references/span-mode.md +65 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devlog-tracker
|
|
3
|
+
description: 在專案的 .devlog/devlog.md 維護逐輪對話紀錄。使用者下 /devlog-tracker:start 後 Stop hook 強制每輪寫入;SessionStart 在 startup / resume / compact / fork 注入進度,/clear 不注入;要接續用 /devlog-tracker:continue。當使用者提到「devlog-tracker」「.devlog/devlog.md」「/devlog-tracker:continue」或明確要寫/接續這份紀錄時使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Devlog Tracker(簡化版)
|
|
7
|
+
|
|
8
|
+
參考 agfnow/agentflow 的 devlog 基礎協定做的簡化版,只保留「逐輪對話紀錄」這一層,
|
|
9
|
+
不含原版的 10 步驟 SDD pipeline、多模型對抗審查、external worker 外包等進階機制。
|
|
10
|
+
|
|
11
|
+
## 核心原則
|
|
12
|
+
|
|
13
|
+
devlog.md 是**跨 session 交接連續性**(決策軌跡、目前卡點、下一步、完成條件)的 single source of truth,
|
|
14
|
+
也是 L1「人觸發 continue/開 session 後 agent 可接手」的主入口;接手輪必須把狀態**寫回**本檔。
|
|
15
|
+
不是整個專案的單一真相來源:程式碼/檔案狀態的真相仍是 git(`#### 工作區` 是收尾當下的已核對快取:
|
|
16
|
+
`IN_PROGRESS`/`BLOCKED` 時 Stop hook 一律對過 live git,`DONE` 若「檔案」有內容也對過;接手時樹可能已變,`continue`/`resume`
|
|
17
|
+
仍以實際工作樹為準,見 `docs/design/continue.md`);完整逐字過程的真相是對話 transcript(`/clear` 後不存在);設計
|
|
18
|
+
決策的真相是 `docs/design/*.md`。使用者在裡面許願、Claude 也在裡面回報進度與結果——取代「終端機
|
|
19
|
+
一 clear 就沒了」的對話記錄,讓工作可以隨時中斷、隨時接續。L2(無人喚醒)與 L3(跨機共享 `.devlog/`)不在範圍。
|
|
20
|
+
|
|
21
|
+
## 寫進 devlog 不等於講給使用者聽
|
|
22
|
+
|
|
23
|
+
`### Summary`/`### Reply`/`### Handoff`/`### 段落`/`## Checkpoint` 這些內容是寫給「下一個
|
|
24
|
+
讀 devlog.md 的人」看的,不是講給正在對話的使用者聽的——這是兩件不同的事,收尾時
|
|
25
|
+
用 Edit/Write 工具**安靜地**寫進 `.devlog/.round-current.md`(這一輪還開著時的
|
|
26
|
+
實際編輯對象,收尾成功或被判定中斷後才會由 hook 自動併回 `.devlog/devlog.md`;
|
|
27
|
+
工具呼叫本身不會顯示給使用者),寫完之後**不要**在聊天回覆裡再提這件事。
|
|
28
|
+
|
|
29
|
+
具體來說,這輪收尾的聊天回覆裡:
|
|
30
|
+
|
|
31
|
+
- **不要**出現「devlog」「Round」「Summary」「Handoff」「Reply」「Status」「這一輪」這些字,
|
|
32
|
+
也不要說「已寫入」「已補上」「已記錄」「收尾完成」之類的動作旁白——使用者看不到
|
|
33
|
+
你剛剛用工具做了什麼,講這些等於自己報告一件使用者沒問過的事,是雜訊。
|
|
34
|
+
- **不要**把剛寫進 Handoff/Summary/Reply 的內容(決策、下一步、現況、對使用者說過的話)換句話再講一次。
|
|
35
|
+
如果使用者原本就在等這個結論,直接把結論講給他聽即可,不用先鋪一句「我把這輪記
|
|
36
|
+
錄下來了」再講結論。
|
|
37
|
+
- 唯一的例外是使用者自己開口問跟 devlog 有關的事(例如問「這輪有記錄嗎」「幫我看
|
|
38
|
+
一下 devlog」),這時才正常回答。
|
|
39
|
+
|
|
40
|
+
**反例**(不要這樣回):「devlog 已補上這輪的 Summary/Handoff/Status(標記
|
|
41
|
+
IN_PROGRESS,因為背景任務還在跑)。等它跑完我會回報結果並更新這一輪。」
|
|
42
|
+
|
|
43
|
+
**正例**(改成這樣):「background 任務還在跑(daily_tune.py 那段約 11.5
|
|
44
|
+
分鐘),跑完我會回報結果。」——結論相同,但完全不提 devlog/Round/Handoff 這些
|
|
45
|
+
內部記錄動作。
|
|
46
|
+
|
|
47
|
+
**最容易漏掉的一種情況:結尾的「這輪改了什麼」總結。** 這輪如果除了
|
|
48
|
+
`.devlog/.round-current.md`(收尾後才會併入 `devlog.md`)還真的改了別的檔案
|
|
49
|
+
(例如 README.md、程式碼),結尾照常給一兩句話總結改了什麼、下一步是什麼——
|
|
50
|
+
但這個異動本身**不算在「改了什麼」裡面,永遠不要提**,因為那是記錄動作本身、
|
|
51
|
+
不是產出。舉例:這輪同時修了 `README.md` 又寫了 `.devlog/.round-current.md`,
|
|
52
|
+
結尾只講「README.md 已更新成...」,不要接著再講「devlog 也已更新/已補上這輪的
|
|
53
|
+
Summary/Handoff」——後面這句要整句刪掉,不是縮短。
|
|
54
|
+
|
|
55
|
+
## 檔案位置
|
|
56
|
+
|
|
57
|
+
- 主檔:`.devlog/devlog.md`——在 `main`/`master` 分支上工作時使用
|
|
58
|
+
- 分支主檔:`.devlog/devlog.<branch>.md`——在同一個 worktree 裡切換到其他分支時,主檔會依目前 checkout 的分支自動分開(斜線轉成 `-`);detached HEAD 退回用 worktree 目錄名。另開一個 `git worktree`(不同目錄)本來就有自己獨立的 `.devlog/`,不受這個機制影響。第一次在某分支偵測到還沒有專屬檔案、且 `.devlog/devlog.md` 已有內容時,會把它改名(非複製)成該分支的檔案。細節見 `docs/design/branch-scoped-devlog.md`。
|
|
59
|
+
- 歸檔:`.devlog/devlog.archive.md`
|
|
60
|
+
- 具名保存:`.devlog/devlog.<name>.md`(`/devlog-tracker:keep` 搬走的主題檔;SessionStart 不讀這些檔)
|
|
61
|
+
- 當輪暫存:`.devlog/.round-current.md`(目前開著的那一輪,Claude 該讀寫的是這個檔,不是 `devlog.md`;
|
|
62
|
+
收尾或中斷時由 hook 自動合併回 `devlog.md` 並清空,設計見 `docs/design/round-current-split.md`)
|
|
63
|
+
- Cursor/Codex 上沒有 `/devlog-tracker:*` slash 選單。若專案是用 `npx devlog-tracker init` 裝的,指令對照就是 `.devlog-tracker/commands/*.md`:先 `source .devlog-tracker/env.sh`,再照使用者意圖對應的那份 `.md` 檔案的步驟做(例如「開始追蹤」對應 `commands/start.md`,「接續上一題」對應 `commands/continue.md`)。手動裝的專案見 README「Cursor(選用)」「Codex(選用)」章節。
|
|
64
|
+
|
|
65
|
+
第一次使用時,若 `.devlog/` 不存在就建立它。
|
|
66
|
+
|
|
67
|
+
本文件與各 `commands/*.md`、`references/*.md` 提到「devlog.md」或「主檔」時,
|
|
68
|
+
若專案目前不在 `main`/`master` 分支,指的實際上是該分支對應的
|
|
69
|
+
`devlog.<branch>.md`(規則見上)——這些文件不會逐一改寫成分支中立的說法,
|
|
70
|
+
以此為準即可。
|
|
71
|
+
|
|
72
|
+
## 用 `/devlog-tracker:start` 明確開啟強制記錄(不用猜這輪有沒有呼叫到 skill)
|
|
73
|
+
|
|
74
|
+
Claude Code 目前沒有正式、穩定的方式讓 hook 知道「這一輪有沒有呼叫到某個 skill」,
|
|
75
|
+
所以這裡不猜也不解析 transcript,改用一個明確的開關檔案 `.devlog/.enabled`:
|
|
76
|
+
|
|
77
|
+
- 使用者下 `/devlog-tracker:start`:建立這個開關檔(見 `commands/start.md`),代表「這個專案從現在起
|
|
78
|
+
要強制記錄」,同時讀一次現有 devlog 摘要目前進度(對進度,不自動開工)
|
|
79
|
+
- 使用者下 `/devlog-tracker:continue`:讀現有 devlog,核對最後一輪 Handoff「工作區」後再依下一步接著做(見
|
|
80
|
+
`commands/continue.md`)。`/clear` 之後要接續,用這個,不要用 start
|
|
81
|
+
- 使用者下 `/devlog-tracker:pause`:刪掉開關檔,暫停強制記錄,但完全不動歷史紀錄
|
|
82
|
+
- 沒下過 `/devlog-tracker:start` 的專案:這個 plugin 裝著也不會有任何動作,不會留下 `.devlog/` 檔案
|
|
83
|
+
|
|
84
|
+
開關啟動之後,才會進入下面這套強制流程:
|
|
85
|
+
|
|
86
|
+
1. 使用者送出新訊息時,`UserPromptSubmit` hook(`hooks/scripts/round-start.sh`)
|
|
87
|
+
若開關開著,就在 `.devlog/.round-current.md` 寫入這一輪的 skeleton(`### User Input`
|
|
88
|
+
+ `Status: IN_PROGRESS`),並寫 `.devlog/.round-open`。`.turn-start` 雜湊是
|
|
89
|
+
**寫完 skeleton 之後**才對 `.round-current.md` 拍的,所以 Stop 仍能判斷 Claude
|
|
90
|
+
有沒有再補收尾。
|
|
91
|
+
2. Claude 編輯**同一個** Round:不要再 append 一個新的 `## Round`。不要改 User Input
|
|
92
|
+
(除非裡面是 hook 的 `(無 prompt)` 占位)。補上 `### Summary` / `### Reply` / `### Handoff`,
|
|
93
|
+
把 Status 改成 `DONE` / `IN_PROGRESS` / `BLOCKED`。這一輪還開著的時候,編輯的對象
|
|
94
|
+
是 `.devlog/.round-current.md`,不是 `devlog.md`——這一輪還沒併回去之前,
|
|
95
|
+
`devlog.md` 完全看不到它。
|
|
96
|
+
3. `Stop` hook(`hooks/scripts/enforce-devlog.sh`)若雜湊沒變、或最後一個 Round
|
|
97
|
+
缺少 `### Summary` / `### Reply` / `### Handoff`,就用 exit code 2 擋下來。通過則刪掉
|
|
98
|
+
`.round-open`,並把 `.round-current.md` 的內容併回 `devlog.md` 尾端、清空
|
|
99
|
+
`.round-current.md`(設計見 `docs/design/round-current-split.md`)。
|
|
100
|
+
|
|
101
|
+
好處:就算工作做到一半被中斷(下一輪還沒開始就被使用者關掉、或換 session),
|
|
102
|
+
只要**上一輪有正常結束過**,devlog.md 就一定留有當時的 Status(多半是 `IN_PROGRESS`
|
|
103
|
+
或 `BLOCKED`)可以接續——這跟「plan 是否完成」完全無關,純粹綁在「這一輪有沒有結束」
|
|
104
|
+
這個事件上。
|
|
105
|
+
|
|
106
|
+
需要誠實說明的邊界:User Input 在送出當下就已經在 `.devlog/.round-current.md`
|
|
107
|
+
(收尾成功或被判定中斷後才會併回 `devlog.md`)。正常結束時 Stop 仍保證有 Summary / Handoff。
|
|
108
|
+
意外中斷會把同一塊標成 `INTERRUPTED`(process 被殺、或 mid-turn 取消時,Status 通常要等
|
|
109
|
+
**下一則訊息**或**下次 SessionStart(startup / resume / clear / fork)**才補上)。
|
|
110
|
+
`PostToolUseFailure` 的 `is_interrupt` 若有觸發,只是 best-effort 的額外路徑,不能當成 Esc
|
|
111
|
+
會立刻蓋章。中間沒寫成 `### 段落` 的過程仍會丟——Segment Watch 只在還有下一個工具呼叫時催促。
|
|
112
|
+
|
|
113
|
+
### 兩個穩健性設計(參考 agfnow/agentflow 的 stop-hook.js)
|
|
114
|
+
|
|
115
|
+
- **loop guard**:`enforce-devlog.sh` 一開始會讀 stdin 的 `stop_hook_active` 欄位——這是
|
|
116
|
+
Claude Code 官方標準欄位,代表「這輪已經被本支 hook 擋下來一次、Claude 正在重跑」,
|
|
117
|
+
此時直接放行,不會一直卡住同一輪。Claude Code 本身也有連續擋 8 次的上限保護,這是多
|
|
118
|
+
一層保險。
|
|
119
|
+
- **fail-open**:三支 hook 腳本都不用 `set -e`,每一步可能失敗的地方(讀不到檔案、雜湊
|
|
120
|
+
算不出來)都明確接住、失敗就直接放行。這些腳本的職責是「檢查」,不該因為自己的臭蟲
|
|
121
|
+
就意外把使用者的 session 卡死。
|
|
122
|
+
|
|
123
|
+
更新(Span Mode 之後):agentflow 的 Stop hook 會依「這一輪是不是還在進行中」
|
|
124
|
+
放寬檢查強度,這裡原本認為 Claude Code 原生的「一個使用者訊息 = 一輪」架構沒有
|
|
125
|
+
對應的地方可以搬這個設計過來。後來為了支援 `/loop`/`Workflow` 這類會被自動
|
|
126
|
+
排程反覆喚醒的長任務,加了上面的 Span Mode,算是這個設計的一個窄化版本——只在
|
|
127
|
+
Claude 主動宣告「接下來會有一串自動續接」時才放寬,且用 tick 計數做安全閥,
|
|
128
|
+
不是像 agentflow 那樣泛用地判斷「這輪是否還在進行中」。一般互動式對話仍然是
|
|
129
|
+
完整的「一個訊息 = 一輪」強制模式,沒有變。
|
|
130
|
+
|
|
131
|
+
## 自動接續與 `/clear`
|
|
132
|
+
|
|
133
|
+
這個 plugin 內建一個 SessionStart hook(`hooks/hooks.json` + `hooks/scripts/session-start-devlog.sh`),
|
|
134
|
+
matcher 設為 `startup|resume|clear|compact|fork`。**開新 session、resume、`/compact`、`/fork`**
|
|
135
|
+
時會自動讀檔注入;**`/clear` 不會注入**——對話清空就是空的。
|
|
136
|
+
|
|
137
|
+
自動注入時:
|
|
138
|
+
|
|
139
|
+
1. 腳本讀取 `.devlog/devlog.md`,注入最後一個 `## Checkpoint`(若有)、最後一個 `## Kept 索引`(若有;不是具名檔內容),加上最近 2 輪的 Summary / Handoff / Status(沒有 Summary 的 skeleton 才帶 User Input)
|
|
140
|
+
2. 印到 stdout,Claude Code 會把這段文字當成這次 session 的 additionalContext 自動注入
|
|
141
|
+
3. Claude 收到這段 context 後,開場就已經知道目前進度
|
|
142
|
+
|
|
143
|
+
`/clear` 時 hook 仍可能把殘留的開著 Round 標成 `INTERRUPTED`,但 stdout 什麼都不印。
|
|
144
|
+
之後只有使用者下 `/devlog-tracker:continue`,或明確說「continue」「接續」「繼續上一題」時,
|
|
145
|
+
才讀 `.devlog/devlog.md`,核對 Handoff「工作區」後再依下一步接著做(見 `commands/continue.md`)。
|
|
146
|
+
一般新請求當成空白對話,不要先讀檔接舊工作。`/devlog-tracker:start` 只對進度,不開工。
|
|
147
|
+
|
|
148
|
+
找不到 `.devlog/devlog.md` 時 hook 直接 exit 0,不輸出任何東西,不會干擾沒有用 devlog 的專案。
|
|
149
|
+
|
|
150
|
+
如果 hook 在 startup / resume / fork 沒有生效(例如使用者不是用 Claude Code、或 hook 因為某些
|
|
151
|
+
環境問題沒跑),Claude 仍應主動:使用者在已有 devlog.md 的專案裡提出一般開發需求時,先讀一次
|
|
152
|
+
`.devlog/devlog.md` 最後幾輪。最後一輪 `DONE`:只對進度,不核對、不開工。否則依
|
|
153
|
+
`commands/continue.md` 步驟 5 核對後再接手。
|
|
154
|
+
這個 fallback **不適用於 `/clear` 之後**——clear 之後沒有說 continue,就不要讀檔。
|
|
155
|
+
|
|
156
|
+
## 接續:`/devlog-tracker:continue`
|
|
157
|
+
|
|
158
|
+
`/clear` 之後要接著做上一題,下 `/devlog-tracker:continue`(或明確說「continue」
|
|
159
|
+
「接續」「繼續上一題」)。讀 `devlog.md`,**先核對**最後一輪 Handoff 的 `#### 工作區`
|
|
160
|
+
(跑步驟 5.1,編成同一格式再對),再依「下一步」開工,並對照「完成條件」。有快照但不符才先寫 `### 段落`;
|
|
161
|
+
沒有快照(舊 Round、`INTERRUPTED` stub)直接以實際狀態為準,不用寫。步驟見 `commands/continue.md`。
|
|
162
|
+
`DONE` 就說明上一題已結束、等新需求,不核對。`BLOCKED`:缺的外部輸入仍缺就停,已經出現就做;
|
|
163
|
+
不要用 git 相不相符當作缺件已到。SessionStart 注入的摘錄若讓你要動手做「下一步」,同樣先核對。
|
|
164
|
+
同一條對話的下一則訊息也一樣:UserPromptSubmit 若發現上一輪 `#### 工作區` 跟 live git 不符,會注入說明並在 PreToolUse 擋住其他工具,直到這一輪寫了含實際快照的 `### 段落`。Span 安靜 tick 與 task-notification 不擋。`DONE` 一律不擋(跟 Stop hook 不同:Stop 在 `DONE` 有「檔案」時會機器核對,但這裡管的是「上一輪的宣稱還能不能拿來接續下一步」——`DONE` 沒有下一步可接,即使當初有檔案也不用重查)。沒呼叫任何工具的純文字回覆不會碰到 PreToolUse,仍應先核對再依實際工作樹行動。擋著的時候,唯讀的 `git status`/`diff`/`log`/`show`/`rev-parse`(不含任何 shell 串接符號)仍可執行,方便自行核對「宣稱 vs 實際」再動手寫段落。
|
|
165
|
+
不要自動觸發。`/devlog-tracker:start` 只對進度,不開工、不核對。
|
|
166
|
+
|
|
167
|
+
### L1 寫回義務
|
|
168
|
+
|
|
169
|
+
接手(continue、SessionStart 注入後依下一步行動、或同 session 接著做)不是「讀檔 → 改程式 → 結束」。
|
|
170
|
+
**同一輪必須把狀態寫回** `.devlog/devlog.md`(本輪 Round 的 Summary/Reply/Handoff/Status),讓下一任只靠檔案就能再接。讀而不寫 = 交接斷鏈 = L1 失敗。有 `.enabled` 時 Stop 會擋;沒有 Stop/未 start/Cursor 未裝 hook 時仍要自行寫回。子 agent 若只改 code,主對話負責收尾寫回(或 brief 要求子任務寫回)。聊天不要旁白「已寫入 devlog」。
|
|
171
|
+
|
|
172
|
+
## 每一輪的紀錄格式
|
|
173
|
+
|
|
174
|
+
hook 已在送出時寫好 User Input;Claude **編輯最後一個 Round**,不要為同一則使用者訊息再新增一個 `## Round`:
|
|
175
|
+
|
|
176
|
+
```markdown
|
|
177
|
+
## Round <N> — <ISO 8601 時間戳,含時區>
|
|
178
|
+
|
|
179
|
+
### User Input
|
|
180
|
+
<使用者這輪的輸入:預設保留送出原文;見下方 User Input 原則>
|
|
181
|
+
|
|
182
|
+
### Summary
|
|
183
|
+
<2–4 句,給人掃:這輪結論、有沒有卡住。不要寫檔案路徑、commit hash、skill 名稱、逐步指令>
|
|
184
|
+
|
|
185
|
+
### Reply
|
|
186
|
+
<這輪實際對使用者說的話/答應的邊界/未決提問,短述即可。給下一輪知道承諾,不是 Handoff>
|
|
187
|
+
|
|
188
|
+
### Handoff
|
|
189
|
+
#### 決策
|
|
190
|
+
<影響後續方向的選擇與理由;若依賴設計文件,寫上 `docs/design/...` 路徑。沒做選擇就整節省略>
|
|
191
|
+
|
|
192
|
+
#### 檔案
|
|
193
|
+
<機器可核對格式,見下方「檔案 machine-verify」:零個以上 `commit <hash>:` 區塊(依時間序),
|
|
194
|
+
加上最多一個 `尚未 commit:` 區塊,各自帶 `新增:`/`修改:`/`刪除:` 分類行(無則省略該行)。
|
|
195
|
+
沒動檔就整節省略>
|
|
196
|
+
|
|
197
|
+
#### 工作區
|
|
198
|
+
<IN_PROGRESS/BLOCKED 必寫;DONE 若上面「檔案」有內容(宣稱動過/commit 過檔案)也必寫,
|
|
199
|
+
Stop hook 會機器核對;DONE 且「檔案」整節省略時,工作區才能跟著省略。收尾前跑 git 再寫,見下方格式>
|
|
200
|
+
|
|
201
|
+
#### 現況
|
|
202
|
+
<任務做到哪、卡在哪。git 快照寫在「工作區」,不要寫這裡。幾乎每輪都該有。
|
|
203
|
+
BLOCKED 時寫清楚缺什麼、出現長怎樣(可觀察條件)>
|
|
204
|
+
|
|
205
|
+
#### 完成條件
|
|
206
|
+
<IN_PROGRESS/BLOCKED 必寫:可觀察的做完判準(測試指令、檔案行為、使用者已確認的範圍)。
|
|
207
|
+
下一輪對照此節決定能否 DONE。DONE 且沒有後續就整節省略>
|
|
208
|
+
|
|
209
|
+
#### 下一步
|
|
210
|
+
<下一輪第一件具體要做的事(路徑、指令、要載入的 skill)。
|
|
211
|
+
IN_PROGRESS/BLOCKED 必寫;DONE 且沒有後續就整節省略>
|
|
212
|
+
|
|
213
|
+
### Status
|
|
214
|
+
DONE | IN_PROGRESS | BLOCKED | INTERRUPTED
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Round 編號:讀取檔案中最後一個 `## Round <N>`,本輪用 N+1;檔案不存在就從 Round 1 開始。
|
|
218
|
+
|
|
219
|
+
寫入原則:
|
|
220
|
+
- **User Input:送出原文優先。** hook 在 `UserPromptSubmit` 已寫入送出當下的 prompt(截斷/遮罩規則見
|
|
221
|
+
`docs/design/recording-moments.md`)。Claude **不要改寫、不要潤飾、不要事後摘要取代原文**,除非
|
|
222
|
+
裡面是 hook 的 `(無 prompt)` 占位。目標是讓人「只讀這份檔案、不用翻對話紀錄」就能接續;關鍵措辭
|
|
223
|
+
(用詞、並列條件、例外)必須留在檔裡。超長內容由 hook 截斷並標明;不要在收尾時再手動縮成更短的改寫版。
|
|
224
|
+
- **三個讀者拆開:** `Summary` 只給人掃;`Reply` 只記對使用者說過/答應過的話;`Handoff` 只給下一輪
|
|
225
|
+
Claude 接手。同一件事不要三邊複述。
|
|
226
|
+
- Handoff 小節順序固定(決策 → 檔案 → 工作區 → 現況 → 完成條件 → 下一步),Stop hook 會檢查已出現的小節
|
|
227
|
+
順序有沒有錯、有沒有重複(不檢查內容對不對)。沒發生的整節省略,不要寫「無」。
|
|
228
|
+
`現況` 幾乎每輪都該有。`工作區`、`完成條件` 與 `下一步` 在 `IN_PROGRESS`/`BLOCKED` 必寫;`DONE` 且沒有後續就整節省略——
|
|
229
|
+
但 `DONE` 若 `檔案` 有內容(宣稱動過/commit 過檔案),`工作區` 一樣必寫且會被 Stop hook 機器核對,
|
|
230
|
+
避免「已 commit 完成」卻其實沒 commit 這種宣稱跟實際不符沒人發現。
|
|
231
|
+
`完成條件` 要寫到下一輪能對照判斷「可否 DONE」(例如「`bash hooks/scripts/tests/test-foo.sh` 全過」),
|
|
232
|
+
不要只寫「功能完成」。`下一步` 要具體到下一輪打開就能做(路徑/反引號指令/skill 名),寫「繼續完成」不算完成;
|
|
233
|
+
`IN_PROGRESS` 時 Stop 會做輕量可執行檢查(見下)。`BLOCKED` 的 `現況` 或 `下一步` 必須寫「缺什麼、出現長怎樣」。
|
|
234
|
+
- **`工作區` 是收尾當下的 git 快照,給下一輪核對用。** 寫之前跑 `git status --short`、`git rev-parse --abbrev-ref HEAD`、`git rev-parse --short HEAD`,照輸出寫。`abbrev-ref` 為 `HEAD` 時用 detached 格式;`rev-parse --short HEAD` 失敗但 `git symbolic-ref --short HEAD` 抓得到分支名(尚無 commit,例如剛 `git init`)用 unborn 格式;兩者都失敗才是非 git。髒檔是整棵樹的未提交,不必跟「檔案」那輪 delta 相同。格式:
|
|
235
|
+
- 乾淨:`main @ a1b2c3d,工作樹乾淨`(一行)
|
|
236
|
+
- 有未提交:第一行 `feat/foo @ a1b2c3d`,第二行 `未提交:src/a.ts, hooks/foo.sh`
|
|
237
|
+
- 非 git:一行 `非 git 工作區`
|
|
238
|
+
- detached 乾淨:`HEAD detached @ a1b2c3d`(一行)
|
|
239
|
+
- detached 有未提交:第一行 `HEAD detached @ a1b2c3d`,第二行 `未提交:src/a.ts, hooks/foo.sh`
|
|
240
|
+
- unborn(尚無 commit)乾淨:`main @ (尚無 commit),工作樹乾淨`(一行)
|
|
241
|
+
- unborn(尚無 commit)有未提交:第一行 `main @ (尚無 commit)`,第二行 `未提交:src/a.ts, hooks/foo.sh`
|
|
242
|
+
(七種格式的機器生產者只有 `hooks/scripts/workspace-snapshot.sh`。寫入照上面手寫;Stop 用同一 function 核對。改格式時改 SKILL 與該腳本,不要在 continue.md 再抄一份。)
|
|
243
|
+
`INTERRUPTED` stub 不寫這一節。`IN_PROGRESS`/`BLOCKED` 收尾時,Stop hook 會自己算一次
|
|
244
|
+
即時 git 快照,跟這一節逐字比對,不符就擋下來並印出正確內容(`hooks/scripts/workspace-snapshot.sh`,
|
|
245
|
+
docs/design/devlog-as-ssot-assessment.md Phase 1);`DONE` 若「檔案」有內容一樣核對——只有
|
|
246
|
+
沒動檔的 `DONE` 與 `INTERRUPTED` 不受影響。
|
|
247
|
+
接手跑 `workspace-snapshot.sh`(`PLUGIN_ROOT` 同其他指令),stdout 就是要對的快照,不要手編(continue/fallback 見 `commands/continue.md` 步驟 5;resume 只做 5.1–5.2,等確認才做下一步)。腳本找不到才退回上面七種格式手編。
|
|
248
|
+
- **`檔案` 是機器可核對的區塊格式(devlog ssot Phase 4)。** 零個以上 `commit <hash>:` 區塊
|
|
249
|
+
(commit 短 hash,依時間序),每個後面接最多三行分類(`新增:`/`修改:`/`刪除:`,逗號分隔路徑,
|
|
250
|
+
沒有就省略那行);最多一個 `尚未 commit:` 區塊,格式相同。一輪可以先 commit 一部分、後面
|
|
251
|
+
繼續改,兩種區塊可以並存。Stop hook 對 `commit` 區塊做逐字精確核對(含分類),對
|
|
252
|
+
`尚未 commit` 區塊只核對「宣稱的路徑是否真的在目前髒檔清單裡」(不核對分類,也不要求
|
|
253
|
+
涵蓋所有髒檔——跨輪殘留、還沒 commit 的舊檔案不算這輪漏列)。Rename 一律回報成
|
|
254
|
+
刪除+新增,不是第四類。`.devlog/` 路徑不算進比對。看不懂的行(沒有照這個格式寫)會被擋下來,
|
|
255
|
+
不是 fail-open——這是 Claude 該產生的格式,不是可有可無的宣告。細節見
|
|
256
|
+
`docs/design/files-verify.md`(`hooks/scripts/files-snapshot.sh`)。
|
|
257
|
+
- Handoff 只寫已發生的事;未來式只允許出現在「下一步」與「完成條件」。
|
|
258
|
+
- `Status` 只寫 `DONE`、`IN_PROGRESS`、`BLOCKED`、`INTERRUPTED` 其中一個,不要在下面再附「接下來要做什麼」
|
|
259
|
+
(那句搬進 Handoff 的「下一步」)。`IN_PROGRESS` = 還能做;`BLOCKED` = 缺外部輸入;
|
|
260
|
+
`DONE` = 這輪請求已結束(應已滿足「完成條件」或本輪請求本身已結束)。**例外只有 hook 自動蓋 `INTERRUPTED` 時**:`close-open-round.sh`
|
|
261
|
+
會在下面多印一行 `[reason: ...]`(例如 `[reason: dangling:next_prompt]`),這是 hook 自己的
|
|
262
|
+
除錯代號、用方括號標記成內部 metadata,特意不用 HTML 註解(會被 Markdown 渲染器整段隱藏,
|
|
263
|
+
之後要 debug 反而看不到),不算違反「只寫一個值」——看到這行不用當成錯誤,Claude 也不用去動它。
|
|
264
|
+
- `INTERRUPTED` 只由 hook 在意外中斷時寫上(非 usage 的 API 錯誤、SessionEnd、
|
|
265
|
+
下次 SessionStart(startup / resume / clear / fork)或下一則訊息發現 `.round-open` 還在)。
|
|
266
|
+
mid-turn 取消(例如 Esc)通常也是走這條延後路徑;`PostToolUseFailure` 的 `is_interrupt`
|
|
267
|
+
若有觸發只是 best-effort,不能當成一定會立刻蓋章。Claude 正常收尾時不要自己選這個值。
|
|
268
|
+
usage 用光(`rate_limit` / `billing_error` / `account_on_hold`)不標中斷。
|
|
269
|
+
- 每輪一個區塊,不要把多輪內容合併寫成一個 Round。
|
|
270
|
+
- 不要另外開欄位列「這輪用了哪些 skill」——那是稽核用途,跟接續開發沒有直接關係。只有
|
|
271
|
+
當接續動作**必須**重新載入某個特定 skill 才能正確接手時,才把 skill 名稱寫進 Handoff
|
|
272
|
+
「下一步」裡。
|
|
273
|
+
|
|
274
|
+
Stop hook 會檢查最後一個 Round 是否同時有 `### Summary`、`### Reply` 與 `### Handoff`、三者底下有內容、`### Status` 是四個合法值之一,已出現的 Handoff 小節順序與不重複(決策 → 檔案 → 工作區 → 現況 → 完成條件 → 下一步),以及 `IN_PROGRESS`/`BLOCKED` 時 Handoff 有「完成條件」與「下一步」且「下一步」不是純黑名單空話(例如整節只寫「繼續完成」,見 `docs/design/next-step-blacklist.md`;這是字串比對,不是語意評分);`IN_PROGRESS` 的「下一步」另做輕量可執行檢查(須含路徑、反引號指令、或檔名/skill 跡象);`BLOCKED` 時「現況」或「下一步」須含缺件句式(缺/等待/等使用者等);`#### 工作區` 跟 hook 算出的 git 快照相符——`IN_PROGRESS`/`BLOCKED` 一律核對,`DONE` 則只在「檔案」有內容時才核對(瑣碎、沒動檔的 DONE 輪不受影響);`#### 檔案` 非空時,hook 也會核對它是否符合實際 git 變更(commit 區塊精確核對,未 commit 區塊單向核對,見上方「檔案 machine-verify」)。
|
|
275
|
+
新開的 Round 三個標題(Summary/Reply/Handoff)都要有,瑣碎輪也不例外。
|
|
276
|
+
|
|
277
|
+
### 怎麼判斷這輪該寫多細(瑣碎程度)
|
|
278
|
+
|
|
279
|
+
「每輪都要記錄」管的是**要不要留下這一輪的痕跡**,瑣碎程度管的是**該寫多細**,這是兩件
|
|
280
|
+
不同的事——瑣碎不代表可以跳過不記,只代表這輪該寫得短。
|
|
281
|
+
|
|
282
|
+
判斷測試:**如果把這一輪從 devlog 刪掉,之後光讀檔案接續工作,會不會漏掉重要資訊?**
|
|
283
|
+
會漏掉就不瑣碎,要完整寫;不會漏掉(純確認、閒聊、使用者只回「好」「謝謝」、沒有產生任何
|
|
284
|
+
實質變化或懸而未決的事)就是瑣碎,但**還是要有這個 Round 區塊**,只是 Summary 一句話、
|
|
285
|
+
Reply 一句(對使用者說過的話)、Handoff 只留「現況」一句(沒有「工作區」),Status 多半 `DONE`。三個標題仍然都要有。
|
|
286
|
+
|
|
287
|
+
具體訊號:
|
|
288
|
+
|
|
289
|
+
| 訊號 | 不瑣碎(寫詳細) | 瑣碎(一句話帶過) |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| 檔案異動 | 有改到/新增/刪除檔案 | 完全沒動任何檔案 |
|
|
292
|
+
| 決策 | 做了會影響後續方向的選擇 | 沒有做任何選擇,純粹回應 |
|
|
293
|
+
| Status | `IN_PROGRESS` / `BLOCKED`(還有事沒完) | `DONE` 且沒有任何懸而未決 |
|
|
294
|
+
| 內容重複性 | 帶來新資訊 | 只是重複或確認前一輪已經記過的事 |
|
|
295
|
+
|
|
296
|
+
## Round Segments:單輪內的階段性記錄
|
|
297
|
+
|
|
298
|
+
一輪如果有好幾個明顯階段(先探索、再決策、再實作、再驗證),不要憋到最後才寫
|
|
299
|
+
一次 Summary/Handoff——中途 crash 會整個過程全部遺失。邊做邊在 User Input 和
|
|
300
|
+
收尾的 Summary/Handoff 之間追加 `### 段落 N - HH:MM` 子區塊,跟判斷
|
|
301
|
+
`Status: IN_PROGRESS` 同一套標準:「有意義的階段性結果」才寫,不是照時間或工具
|
|
302
|
+
呼叫次數機械觸發。不要把段落內容再抄進 Summary 或 Handoff。
|
|
303
|
+
|
|
304
|
+
另有一道保底:同一輪連續約 10 分鐘(可用 `/devlog-tracker:segment-watch <時間長度>`
|
|
305
|
+
調整)沒改 `.devlog/.round-current.md`,下一個工具會被 PreToolUse hook 擋住,先
|
|
306
|
+
Read `.devlog/.round-current.md` 再用 Edit/StrReplace 追加一段(**禁止**用 Write
|
|
307
|
+
覆寫整份檔)。
|
|
308
|
+
|
|
309
|
+
完整格式範例、寫入細則、跟 dynamic workflow/subagent 的例外情況,見
|
|
310
|
+
`${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/round-segments.md`。
|
|
311
|
+
|
|
312
|
+
## Reply Fold:把「Claude 提問、user 回答」記成同一個 Round
|
|
313
|
+
|
|
314
|
+
一輪如果是 Claude 用純文字結尾提出一個具體問題(不是用 `AskUserQuestion`
|
|
315
|
+
工具),下一則使用者訊息通常是答案、不是新話題——預設行為(每個
|
|
316
|
+
`UserPromptSubmit` 開新 `## Round`)會把這組問答硬拆成兩個不相關的 Round。
|
|
317
|
+
Reply Fold 讓它折進同一個 Round。
|
|
318
|
+
|
|
319
|
+
`AskUserQuestion` 在同一 turn 內問答,不用 fold、不要跑 `await-open.sh`;
|
|
320
|
+
但仍要用 `### 段落(AskUserQuestion)` 把問題與答案寫進本 Round,方便 L1
|
|
321
|
+
接手。細節見 `references/reply-fold.md`。
|
|
322
|
+
|
|
323
|
+
**提問前**(純文字跨 turn;結束 turn 之前):先用 Edit 在 `### Summary` 之前插入一段
|
|
324
|
+
`### 段落(Claude 提問)` 記下問題原文,再跑
|
|
325
|
+
`${CLAUDE_PLUGIN_ROOT}/hooks/scripts/await-open.sh` 標記「下一則訊息大概是在
|
|
326
|
+
回答這個 Round」。使用者回答時 `round-start.sh` 會自動折成對應段落,不用手動
|
|
327
|
+
處理。連續多輪一問一答(例如 grilling)時不必每題重寫 Summary/Reply/Handoff/
|
|
328
|
+
Status,只有整場問答真正結束才收尾一次。
|
|
329
|
+
|
|
330
|
+
完整步驟、折疊格式、猜錯的處理、跟 task-notification/Span Mode/checkpoint
|
|
331
|
+
計數的關係,見 `${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/reply-fold.md`。
|
|
332
|
+
|
|
333
|
+
## Span Mode:橫跨多次自動續接的長任務
|
|
334
|
+
|
|
335
|
+
`/loop` 動態模式、`Workflow`、或任何被自己排程(`ScheduleWakeup`、背景 agent
|
|
336
|
+
完成通知)反覆喚醒、不是使用者手動打字觸發的長任務,如果每個自動 tick 都當一
|
|
337
|
+
輪強制寫,會逼出大量沒意義的紀錄或卡住整條自動化流程。只有**確定接下來會進入
|
|
338
|
+
一連串自動續接**時才開(一般互動式對話不需要,也不應該開),用
|
|
339
|
+
`/devlog-tracker:span` 建立 `.devlog/.span-open`,累積到門檻
|
|
340
|
+
(`max_silent_ticks`)才強制寫一次;崩潰最多漏記固定數量的 tick,不是整段 span。
|
|
341
|
+
|
|
342
|
+
JSON 格式、開關步驟、已知限制(分辨不出自動續接 vs 真人插話),見
|
|
343
|
+
`${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/span-mode.md`(設計動機
|
|
344
|
+
見 `docs/design/span-mode.md`)。
|
|
345
|
+
|
|
346
|
+
## Checkpoint Mode:定期摘要
|
|
347
|
+
|
|
348
|
+
跟 Span Mode 不同:Span 管「一輪內部/自動續接期間要不要強制寫」,Checkpoint
|
|
349
|
+
管「累積夠多輪之後,要不要插入一段橫跨多輪的摘要」,讓翻閱 devlog.md 的人不用
|
|
350
|
+
逐輪爬完才知道整體進度。`/devlog-tracker:start` 後全自動運作,累積約 20 輪
|
|
351
|
+
(可用 `/devlog-tracker:checkpoint <輪數>` 調整)沒寫 `## Checkpoint`,Stop
|
|
352
|
+
hook 會要求補一段。
|
|
353
|
+
|
|
354
|
+
運作機制、補寫格式、`/devlog-tracker:pause` 之後的行為,見
|
|
355
|
+
`${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/checkpoint-mode.md`
|
|
356
|
+
(設計動機見 `docs/design/checkpoint-mode.md`)。
|
|
357
|
+
|
|
358
|
+
## 壓縮歸檔:`/devlog-tracker:compact`
|
|
359
|
+
|
|
360
|
+
歸檔不再是自動觸發,而是使用者主動下 `/devlog-tracker:compact` 指令時才做(見 `commands/compact.md`)。
|
|
361
|
+
規則:
|
|
362
|
+
|
|
363
|
+
- 保留:專案摘要(如果有)、最近 5 輪、所有還沒 `DONE`(`IN_PROGRESS`/`BLOCKED`/`INTERRUPTED`)的輪次
|
|
364
|
+
- 其餘 `DONE` 的舊輪次:完整搬到 `.devlog/devlog.archive.md`(append,不覆寫既有歸檔)
|
|
365
|
+
- 只搬移,不刪除、不改寫內容
|
|
366
|
+
|
|
367
|
+
## 具名保存:`/devlog-tracker:keep`
|
|
368
|
+
|
|
369
|
+
掃描整份 `devlog.md`,把值得留名的主題段落一次分別**搬走**成 `.devlog/devlog.<name>.md`(也可只抽出一段,或合併成全部歷史一個檔)。這不是 compact:compact 把舊的 `DONE` 輪次 append 進 `devlog.archive.md`;keep 寫的是一個主題一個檔,且從不寫 archive。步驟見 `commands/keep.md`。不要自動觸發。
|
|
370
|
+
|
|
371
|
+
每次搬走都會在 `devlog.md` 尾端留一個 `## Kept 索引` 區塊(自動重建,永遠只有一份),
|
|
372
|
+
每個具名檔一行:`devlog.<name>.md`、搬走的 Round 範圍、`kept_at` 時間戳、一句主題描述
|
|
373
|
+
(`keep-move.sh --desc`,`commands/keep.md` 批次確認時生成的那句;沒帶 `--desc` 或既存
|
|
374
|
+
的舊索引行就沒有這一段)。SessionStart 注入的接手摘要會帶上這個索引(不是具名檔的內容),
|
|
375
|
+
讓「哪個主題被搬去哪個檔」不用翻完整份 `devlog.md` 或憑印象猜檔名
|
|
376
|
+
(`docs/design/devlog-as-ssot-assessment.md` Phase 3)。
|
|
377
|
+
|
|
378
|
+
## 接續具名保存:`/devlog-tracker:resume <name>`
|
|
379
|
+
|
|
380
|
+
需要重啟具名主題時,用 resume 讀取 `.devlog/devlog.<name>.md` 的最後一輪與
|
|
381
|
+
Handoff。核對用 `commands/continue.md` 步驟 5.1–5.2(不要跟著做 5.3 立刻開工);
|
|
382
|
+
`IN_PROGRESS`/`INTERRUPTED`/`BLOCKED` 都要核對,提出接續後等使用者確認才做下一步。
|
|
383
|
+
`DONE` 不核對、不開工。新工作仍記錄到 `devlog.md`,不要改寫 keep 檔。SessionStart 不會自動注入具名檔。
|
|
384
|
+
步驟見 `commands/resume.md`。
|
|
385
|
+
|
|
386
|
+
## 跨檔總覽:`/devlog-tracker:overview`
|
|
387
|
+
|
|
388
|
+
純讀取,不核對工作區、不等確認(跟 `/devlog-tracker:lessons` 一樣的唯讀風格)。用
|
|
389
|
+
`hooks/scripts/kept-list.sh` 解析 `## Kept 索引` 取出所有 `devlog.<name>.md` 檔名(含存在性
|
|
390
|
+
檢查,磁碟上被手動刪掉的 ghost row 只提一句,不嘗試修復),讀完所有存在的檔案後在對話裡
|
|
391
|
+
產出兩塊:跨主題敘事總覽,以及一節「可能該進 `CLAUDE.md` 的規範候選」(挑得出來才輸出,
|
|
392
|
+
格式貼近 `CLAUDE.md` 條列寫法方便複製)。不寫入任何檔案,包含 `CLAUDE.md` 本身。步驟見
|
|
393
|
+
`commands/overview.md`。
|
|
394
|
+
|
|
395
|
+
## Lessons Mode:開發歷程教訓(預設關閉,非架構知識庫)
|
|
396
|
+
|
|
397
|
+
跟 Checkpoint/Span 不同,管的是「開發**過程**踩過的坑」,不是進度或架構——架構
|
|
398
|
+
決策的 SSOT 永遠是 `docs/design/*.md`。預設關閉,隸屬主開關(沒下過
|
|
399
|
+
`/devlog-tracker:start` 會被拒絕)。開著時有三種訊號考慮記一筆:這輪 `Status`
|
|
400
|
+
從 `BLOCKED` 解開、你自行判斷這輪明顯繞了一圈,或工作區漂移(宣稱跟實際不符)
|
|
401
|
+
累積達門檻(預設 3 次,`/devlog-tracker:lessons-drift <次數>` 可調)時 hook 印
|
|
402
|
+
的一句顧問式建議。三種都完全不 hook 強制寫入本身——寫不寫都不影響這一輪能不能
|
|
403
|
+
收尾。
|
|
404
|
+
|
|
405
|
+
寫法、per-topic 存檔規則、索引重建、漂移計數細節,見
|
|
406
|
+
`${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/lessons-mode.md`(完整
|
|
407
|
+
設計見 `docs/design/lessons-mode.md`)。
|
|
408
|
+
|
|
409
|
+
## 無條件清空:`/devlog-tracker:clean`
|
|
410
|
+
|
|
411
|
+
把 `devlog.md` 整份清空(含專案摘要與所有 Round 歷史),不搬移、不備份,不可復原。跟 compact/keep 不一樣:那兩個都是「搬去別的檔案保留」,clean 是真的丟棄。執行前一定要先問使用者、拿到明確的「清空」才動手;只有目前開著的那一輪會留下(若有開著,內容讀自 `.devlog/.round-current.md`,不是已經清空的 `devlog.md`),重編成 `## Round 1`。步驟見 `commands/clean.md`。不要自動觸發。
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Checkpoint Mode:定期摘要
|
|
2
|
+
|
|
3
|
+
跟 Span Mode 處理的是不同問題:Span Mode 管的是「一輪內部/自動續接期間要不要
|
|
4
|
+
強制寫」,Checkpoint Mode 管的是「累積夠多輪之後,要不要在 devlog.md 裡插入一段
|
|
5
|
+
橫跨多輪的摘要」,讓翻閱 devlog.md 的人不用逐輪爬完才知道整體進度。
|
|
6
|
+
|
|
7
|
+
設計動機見 `docs/design/checkpoint-mode.md`;這裡只講操作規則。
|
|
8
|
+
|
|
9
|
+
## 怎麼運作(不用手動開關)
|
|
10
|
+
|
|
11
|
+
`/devlog-tracker:start` 會自動建立 `.devlog/.checkpoint-state`,之後全程自動:
|
|
12
|
+
|
|
13
|
+
- 每個互動輪次,`round-start.sh` 把裡面的 `rounds_since_checkpoint` +1
|
|
14
|
+
(Span Mode 的 span 開著、這個 tick 會被安靜放行時不算)
|
|
15
|
+
- `enforce-devlog.sh` 每輪檢查一次:如果 `devlog.md` 裡 `## Checkpoint` 開頭的
|
|
16
|
+
標題數量比上次看到的多,代表這輪寫了新的 checkpoint,自動把計數器歸零;
|
|
17
|
+
否則如果 `rounds_since_checkpoint` 已經到 `max_silent_rounds`(預設 20),
|
|
18
|
+
就擋下這一輪,要求補寫一段摘要
|
|
19
|
+
|
|
20
|
+
## 被要求補寫的時候該怎麼寫
|
|
21
|
+
|
|
22
|
+
在 `devlog.md` 尾端追加:
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
## Checkpoint(Round <X>-<Y> 摘要)
|
|
26
|
+
這段期間完成了...、修了...、決定採用...
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`X`-`Y` 是這段還沒被摘要過的 Round 範圍,內容對齊各輪 Summary 抓重點就好,不用逐輪複述、
|
|
30
|
+
也不要變成各輪 Handoff 的合集——細節本來就還留在 Round 區塊裡,checkpoint 只是給翻閱時的路標,
|
|
31
|
+
不替代每輪 Summary。寫完之後這一輪就會正常結束,不用再做任何事。
|
|
32
|
+
|
|
33
|
+
## 調整門檻
|
|
34
|
+
|
|
35
|
+
`max_silent_rounds` 預設 20,覺得這個專案的節奏不合適,用
|
|
36
|
+
`/devlog-tracker:checkpoint <正整數輪數>` 調整(不要手改
|
|
37
|
+
`.devlog/.checkpoint-state`,除非指令不可用)。
|
|
38
|
+
|
|
39
|
+
## `/devlog-tracker:pause` 之後
|
|
40
|
+
|
|
41
|
+
暫停強制記錄時 `.checkpoint-state` 不會被刪除,計數保留;之後重新
|
|
42
|
+
`/devlog-tracker:start` 會接著原本的計數繼續,不會歸零重算。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Lessons Mode:開發歷程教訓(預設關閉,非架構知識庫)
|
|
2
|
+
|
|
3
|
+
`docs/design/lessons-mode.md` 的完整設計。這裡只講操作規則。
|
|
4
|
+
|
|
5
|
+
跟 Checkpoint/Span 不同,Lessons Mode 管的是「開發**過程**踩過的坑」,不是進度或架構——
|
|
6
|
+
架構/設計決策的 SSOT 永遠是 `docs/design/*.md`,這個模式不取代它。**預設關閉**,隸屬主開關:
|
|
7
|
+
`/devlog-tracker:lessons-on` 若沒下過 `/devlog-tracker:start`(`.enabled` 不存在)會直接拒絕,
|
|
8
|
+
因為沒有 Round/Status 歷史可判斷「BLOCKED→解開」這個訊號。`/devlog-tracker:lessons-off` 只刪
|
|
9
|
+
`.lessons-enabled`,不動任何已寫的 `devlog.lessons.*.md` 或索引。
|
|
10
|
+
|
|
11
|
+
**開著的時候,有三種訊號會讓你考慮記一筆**:這一輪的 `### Status` 從 `BLOCKED` 變成別的值
|
|
12
|
+
(機器可判斷,但不因此強制),你自行判斷這輪明顯繞了一圈才找到對的做法,或是
|
|
13
|
+
`round-start.sh` 既有的工作區漂移偵測累積達門檻(`.devlog/.lessons-drift-state`,預設
|
|
14
|
+
3 次,`/devlog-tracker:lessons-drift <次數>` 可調)時印出的一句
|
|
15
|
+
`[Lessons Mode 提示]`。三種都**完全不 hook 強制寫入本身**——寫不寫都不影響這一輪能不能
|
|
16
|
+
收尾,跟「`#### 決策` 沒有就整節省略」同一種精神,不要自己加壓力覺得每輪都要交一份。
|
|
17
|
+
第三種訊號本身(累積計數、達門檻才印、印完歸零)才是機制性的,跟 Checkpoint Mode 一樣
|
|
18
|
+
只在 `.lessons-enabled` 存在時才計數。
|
|
19
|
+
|
|
20
|
+
**寫法**:跑(`PLUGIN_ROOT` 同其他指令):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/lessons-append.sh" \
|
|
24
|
+
--topic "<主題 kebab-case slug,跟 keep 的 <name> 同一套正規化規則>" \
|
|
25
|
+
--text "<自由散文,一段就好:卡在哪、怎麼解開、下次怎麼避免>"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
同一個主題重複呼叫會累加進同一個 `devlog.lessons.<topic>.md`;不同主題各自成檔。內容不用固定
|
|
29
|
+
子欄位,跟 `#### 決策` 一樣是敘事性的,不要硬套模板。腳本會自動重建 `devlog.md` 尾端的
|
|
30
|
+
`## Lessons 索引`(每個主題檔一行:則數、最新一則的標題、更新時間),SessionStart 只注入這個
|
|
31
|
+
索引,不會注入任何 `devlog.lessons.*.md` 的全文。要看全文用 `/devlog-tracker:lessons [<topic>]`
|
|
32
|
+
(沒給 topic 就只印索引)——這是純讀取,不像 `resume` 會核對工作區或等使用者確認才動手。
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Reply Fold:把「Claude 提問、user 回答」記成同一個 Round
|
|
2
|
+
|
|
3
|
+
一輪如果是 Claude 用純文字結尾提出一個具體問題(不是用 `AskUserQuestion`
|
|
4
|
+
工具、而是整個 turn 就在這句問題上結束),下一則使用者訊息通常就是答案,
|
|
5
|
+
不是新話題。預設行為(每個 `UserPromptSubmit` 開一個新 `## Round`)會把這
|
|
6
|
+
組問答拆成兩個不相關的 Round。Reply Fold 讓這種情況折進同一個 Round,記
|
|
7
|
+
成一個 `### 段落`。
|
|
8
|
+
|
|
9
|
+
## AskUserQuestion(同輪內紀錄,不用 fold)
|
|
10
|
+
|
|
11
|
+
用 `AskUserQuestion` 問問題時,問題跟答案都在**同一個 turn**裡(呼叫工具、
|
|
12
|
+
拿到結果,沒有中間的 Stop),不會產生第二個 Round,**不要**開
|
|
13
|
+
`.awaiting-reply`/`await-open.sh`。
|
|
14
|
+
|
|
15
|
+
但 L1 接手仍要能在檔裡看到「問了什麼、答了什麼」:
|
|
16
|
+
|
|
17
|
+
1. 呼叫 `AskUserQuestion` **之前或同時**,用 Edit 在 `### Summary` 之前追加:
|
|
18
|
+
|
|
19
|
+
`````markdown
|
|
20
|
+
### 段落 N - HH:MM(AskUserQuestion)
|
|
21
|
+
```text
|
|
22
|
+
<問題原文/選項摘要>
|
|
23
|
+
```
|
|
24
|
+
`````
|
|
25
|
+
|
|
26
|
+
2. 工具回傳答案後,在同一 Round 再追加一段(或併進同一段落)寫清楚使用者選了/回了什麼。
|
|
27
|
+
3. 若整輪因此變成在等外部輸入才繼續,收尾 `Status: BLOCKED`,並在 `現況`/`下一步`
|
|
28
|
+
寫缺件句式(缺什麼、出現長怎樣)。
|
|
29
|
+
|
|
30
|
+
這樣不靠 transcript,下一任只讀 `devlog.md` 就知道澄清題問到哪。
|
|
31
|
+
|
|
32
|
+
**什麼時候該開 Reply Fold(純文字提問跨 turn):** 確定要用文字問題結束這個 turn 時,在結束 turn 之前:
|
|
33
|
+
|
|
34
|
+
1. 先用 Edit 在這個 Round 的 `### Summary` 之前插入一個小段落,記下**這次
|
|
35
|
+
問的問題原文**(跟自動折入答案用同一種格式,方便前後對照)。這一步的
|
|
36
|
+
編輯對象是 `.devlog/.round-current.md`——提問當下這一輪還沒收尾,本來就
|
|
37
|
+
還沒併回 `.devlog/devlog.md`(見 `docs/design/round-current-split.md`):
|
|
38
|
+
|
|
39
|
+
`````markdown
|
|
40
|
+
### 段落 N - HH:MM(Claude 提問)
|
|
41
|
+
```text
|
|
42
|
+
<問題原文;hook 已寫的 User Input 規則:送出原文優先,截斷/遮罩見 recording-moments>
|
|
43
|
+
```
|
|
44
|
+
`````
|
|
45
|
+
|
|
46
|
+
這一步不能省——沒有它,devlog 裡只留得下使用者的回答(下一則訊息自動
|
|
47
|
+
折入的段落),問的是什麼反而不見了,事後只看檔案會看不懂答案在答什麼。
|
|
48
|
+
2. 確保這一輪的 Summary/Reply/Handoff/Status 存在且有效(`Status` 常見是
|
|
49
|
+
`BLOCKED`,但 `IN_PROGRESS` 也可能)——**第一次**提問要完整寫;如果這已
|
|
50
|
+
經是同一個 Round 內連續第二題以後的提問,且工作區、決策都還沒變,不用
|
|
51
|
+
整段重寫,見下面「連續多輪一問一答」。
|
|
52
|
+
3. 用 Bash 執行:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
CLAUDE_PROJECT_DIR="$(pwd)" bash "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/await-open.sh"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
這會寫入 `.devlog/.awaiting-reply`,記住「下一則訊息大概是在回答這個
|
|
59
|
+
Round」。不需要使用者下任何指令,也不用手寫這個 JSON。
|
|
60
|
+
|
|
61
|
+
上面第 2 步已經讓這一輪正常收尾(Summary/Handoff/Status 都有效),所以
|
|
62
|
+
這個 turn 結束時它會照一般流程併回 `.devlog/devlog.md`。也就是說,**提問
|
|
63
|
+
出去、答案還沒進來的這段期間**(使用者可能過很久才回覆),這一輪確實已經
|
|
64
|
+
完整躺在 `devlog.md` 的歷史裡,不是懸在 `.devlog/.round-current.md` 裡假裝
|
|
65
|
+
還開著——只有在下一則訊息真的進來、被判定是在回答時,才會被下面的機制短
|
|
66
|
+
暫重新打開,回覆折進去、這個 turn 收尾後又立刻併回去。
|
|
67
|
+
|
|
68
|
+
**下一則訊息進來之後會自動發生什麼事:** `round-start.sh` 看到
|
|
69
|
+
`.awaiting-reply`、且輪次跟 `devlog.md` 目前最後一個 `## Round` 吻合(提問
|
|
70
|
+
時那一輪已經正常收尾過,這時只會存在於 `devlog.md`,不在
|
|
71
|
+
`.devlog/.round-current.md` 裡),就不開新 Round,而是先把 `devlog.md` 裡
|
|
72
|
+
那個 Round 整段搬回 `.devlog/.round-current.md`(`devlog_reopen_last_round`,
|
|
73
|
+
`devlog.md` 那邊同步移除),再改成在那個 Round 的 `### Summary` 之前插入一個
|
|
74
|
+
新段落:
|
|
75
|
+
|
|
76
|
+
`````markdown
|
|
77
|
+
### 段落 2 - 14:32(回覆上一輪的問題)
|
|
78
|
+
```text
|
|
79
|
+
<使用者這則訊息的原話;hook 截斷/遮罩規則同 User Input>
|
|
80
|
+
```
|
|
81
|
+
`````
|
|
82
|
+
|
|
83
|
+
`.devlog/.round-open` 會重新指向這個 Round,讓這輪如果又意外中斷,
|
|
84
|
+
`INTERRUPTED` 一樣能正確蓋在同一個 Round 上。折入之後,如果問答到此結束、
|
|
85
|
+
要往下做別的事了,Claude 照常編輯這個 Round 的 Summary/Reply/Handoff/Status,
|
|
86
|
+
反映答案後的結果;如果答案帶出**下一個**問題(連續問答),見下面這段。
|
|
87
|
+
|
|
88
|
+
**連續多輪一問一答(例如 grilling):只在真正結束時完整收尾。** 一個 Round
|
|
89
|
+
裡如果連續好幾輪都是「Claude 問一題、使用者答一題」,不要每題都重寫一次
|
|
90
|
+
完整的 Summary/Reply/Handoff/Status——那樣每題都要跑一次大改動,會把使用者剛
|
|
91
|
+
答完的內容跟 Claude 剛問的下一題擠開,變得很難照順序讀。改成:
|
|
92
|
+
|
|
93
|
+
- 答案:下一則訊息進來時,Reply Fold 自動折入,不用手動處理。
|
|
94
|
+
- 下一題:只做上面「什麼時候該開」的步驟 1(插入一個 `### 段落
|
|
95
|
+
(Claude 提問)` 記下問題原文)+ 步驟 3(`await-open.sh`),**不必**重寫
|
|
96
|
+
Summary/Reply/Handoff/Status——只要工作區、決策這些沒變,原本那份還有效。
|
|
97
|
+
- 真正收尾(結束這整場問答、要換話題或往下做別的事)時,才完整改寫一次
|
|
98
|
+
Summary(總結整場問答得出的結論)、Reply(對使用者說過的結論/未決提問)與
|
|
99
|
+
Handoff(決策/現況/完成條件/下一步,反映最終結果),Status 改成當下該有的值。
|
|
100
|
+
|
|
101
|
+
這樣一整場問答結束後,devlog 裡會依序留下每一題的原文段落與對應的回答
|
|
102
|
+
段落,跟一份收尾時寫的總結——問題和答案都保留了,但中途不會被大段落
|
|
103
|
+
的收尾內容打斷。
|
|
104
|
+
|
|
105
|
+
**猜錯的處理:** hook 沒辦法驗證「下一則訊息真的是在回答」,只看
|
|
106
|
+
`.awaiting-reply` 有沒有開著。如果開了之後使用者其實問了不相干的新問題,
|
|
107
|
+
還是會被自動折進舊 Round 當一個段落。發現猜錯時,在那個段落裡說明「其實
|
|
108
|
+
是新話題」,然後自己手動開一個新的 `## Round` 接手新請求——不用回頭改寫
|
|
109
|
+
被誤折的段落。
|
|
110
|
+
|
|
111
|
+
**背景 task-notification 也走同一套折疊,但完全自動:** 如果送進來的
|
|
112
|
+
`prompt` 本身是一段 `<task-notification>…</task-notification>`(子 agent
|
|
113
|
+
在背景完成的通知,不是使用者真的打字),`round-start.sh` 會自己偵測、不
|
|
114
|
+
需要 Claude 先跑 `await-open.sh`。原始 XML 不會被記下來,只留一行精簡摘要
|
|
115
|
+
(例如 `Agent "Fix wave" finished(status=completed, task-id=t1)`),折成
|
|
116
|
+
`### 段落 N - HH:MM(背景任務通知)` 插進最後一個 Round;若當時 `devlog.md`
|
|
117
|
+
還沒有任何 Round,才會退回開一個新 Round,但內容一樣是精簡摘要。
|
|
118
|
+
|
|
119
|
+
這個標記檔也會跨 `/clear` 存活:如果開了之後中間發生過一次 `/clear`,
|
|
120
|
+
下一則訊息進來時 Claude 早就不記得當初問的是什麼,卻還是會被折進那個
|
|
121
|
+
已經沒有上下文的舊 Round。發現時的處理跟上面猜錯的情況一樣——在那個段落
|
|
122
|
+
裡說清楚,再手動開一個新的 `## Round` 接手。
|
|
123
|
+
|
|
124
|
+
**跟 Span Mode 的關係:** 兩者同時存在時(不常見),Span Mode 優先——這個
|
|
125
|
+
tick 會被 Span Mode 安靜跳過,`.awaiting-reply` 照樣被消耗掉但不產生任何
|
|
126
|
+
折入。
|
|
127
|
+
|
|
128
|
+
**跟 checkpoint 計數的關係:** 折入的這個 tick 不算開新 Round,
|
|
129
|
+
`rounds_since_checkpoint` 不會遞增,跟 Span Mode 跳過的 tick 待遇一致。
|