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.
Files changed (120) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +234 -0
  3. package/bin/devlog-tracker.js +51 -0
  4. package/cli/init.js +55 -0
  5. package/cli/init.test.js +37 -0
  6. package/cli/merge-hooks.js +60 -0
  7. package/cli/merge-hooks.test.js +187 -0
  8. package/cli/platforms/codex.js +13 -0
  9. package/cli/platforms/cursor.js +13 -0
  10. package/cli/status.js +14 -0
  11. package/cli/status.test.js +33 -0
  12. package/cli/vendor.js +37 -0
  13. package/cli/vendor.test.js +84 -0
  14. package/codex/hooks/on-pre-tool.sh +19 -0
  15. package/codex/hooks/on-session-end.sh +31 -0
  16. package/codex/hooks/on-session-start.sh +37 -0
  17. package/codex/hooks/on-stop.sh +18 -0
  18. package/codex/hooks/on-user-prompt-submit.sh +15 -0
  19. package/codex/hooks/project-dir.sh +13 -0
  20. package/codex/hooks/test-adapters.sh +98 -0
  21. package/codex/hooks.json +54 -0
  22. package/commands/checkpoint.md +17 -0
  23. package/commands/clean.md +50 -0
  24. package/commands/compact.md +24 -0
  25. package/commands/continue.md +30 -0
  26. package/commands/keep.md +100 -0
  27. package/commands/lessons-drift.md +19 -0
  28. package/commands/lessons-off.md +16 -0
  29. package/commands/lessons-on.md +20 -0
  30. package/commands/lessons.md +20 -0
  31. package/commands/overview.md +32 -0
  32. package/commands/pause.md +20 -0
  33. package/commands/resume.md +18 -0
  34. package/commands/segment-watch.md +21 -0
  35. package/commands/span.md +13 -0
  36. package/commands/start.md +19 -0
  37. package/commands/status.md +14 -0
  38. package/cursor/hooks/on-pre-tool.sh +24 -0
  39. package/cursor/hooks/on-session-end.sh +11 -0
  40. package/cursor/hooks/on-session-start.sh +15 -0
  41. package/cursor/hooks/on-stop.sh +44 -0
  42. package/cursor/hooks/on-submit-prompt.sh +28 -0
  43. package/cursor/hooks/on-tool-failure.sh +16 -0
  44. package/cursor/hooks/project-dir.sh +10 -0
  45. package/cursor/hooks/test-adapters.sh +201 -0
  46. package/cursor/hooks.json +26 -0
  47. package/hooks/scripts/await-open.sh +23 -0
  48. package/hooks/scripts/checkpoint-set.sh +44 -0
  49. package/hooks/scripts/clean-devlog.sh +69 -0
  50. package/hooks/scripts/close-open-round.sh +186 -0
  51. package/hooks/scripts/compact-devlog.sh +72 -0
  52. package/hooks/scripts/detect-pending-question.sh +31 -0
  53. package/hooks/scripts/devlog-lock.sh +38 -0
  54. package/hooks/scripts/devlog-md.sh +222 -0
  55. package/hooks/scripts/devlog-path.sh +70 -0
  56. package/hooks/scripts/enforce-devlog.sh +629 -0
  57. package/hooks/scripts/files-snapshot.sh +70 -0
  58. package/hooks/scripts/json-field.sh +76 -0
  59. package/hooks/scripts/keep-move.sh +155 -0
  60. package/hooks/scripts/kept-list.sh +40 -0
  61. package/hooks/scripts/lessons-append.sh +93 -0
  62. package/hooks/scripts/lessons-drift-set.sh +42 -0
  63. package/hooks/scripts/lessons-off.sh +15 -0
  64. package/hooks/scripts/lessons-on.sh +21 -0
  65. package/hooks/scripts/lessons-read.sh +60 -0
  66. package/hooks/scripts/on-session-end.sh +14 -0
  67. package/hooks/scripts/on-stop-failure.sh +18 -0
  68. package/hooks/scripts/on-tool-failure.sh +25 -0
  69. package/hooks/scripts/pause-devlog.sh +13 -0
  70. package/hooks/scripts/redact-prompt.sh +19 -0
  71. package/hooks/scripts/resume-devlog.sh +41 -0
  72. package/hooks/scripts/round-start.sh +333 -0
  73. package/hooks/scripts/run-tests.sh +26 -0
  74. package/hooks/scripts/segment-watch-set.sh +47 -0
  75. package/hooks/scripts/segment-watch.sh +197 -0
  76. package/hooks/scripts/session-start-devlog.sh +157 -0
  77. package/hooks/scripts/span-close.sh +9 -0
  78. package/hooks/scripts/span-open.sh +21 -0
  79. package/hooks/scripts/start-devlog.sh +24 -0
  80. package/hooks/scripts/status-devlog.sh +43 -0
  81. package/hooks/scripts/tests/test-await-open.sh +112 -0
  82. package/hooks/scripts/tests/test-branch-scoped-integration.sh +108 -0
  83. package/hooks/scripts/tests/test-checkpoint-set.sh +36 -0
  84. package/hooks/scripts/tests/test-clean-devlog.sh +160 -0
  85. package/hooks/scripts/tests/test-cli-init-e2e.sh +37 -0
  86. package/hooks/scripts/tests/test-close-open-round.sh +325 -0
  87. package/hooks/scripts/tests/test-compact-devlog.sh +62 -0
  88. package/hooks/scripts/tests/test-devlog-lock.sh +37 -0
  89. package/hooks/scripts/tests/test-devlog-md.sh +530 -0
  90. package/hooks/scripts/tests/test-devlog-path.sh +118 -0
  91. package/hooks/scripts/tests/test-enforce-devlog-files.sh +233 -0
  92. package/hooks/scripts/tests/test-enforce-devlog-handoff-order.sh +223 -0
  93. package/hooks/scripts/tests/test-enforce-devlog-workspace.sh +333 -0
  94. package/hooks/scripts/tests/test-enforce-devlog.sh +1290 -0
  95. package/hooks/scripts/tests/test-files-snapshot.sh +142 -0
  96. package/hooks/scripts/tests/test-json-field.sh +57 -0
  97. package/hooks/scripts/tests/test-keep-move.sh +127 -0
  98. package/hooks/scripts/tests/test-kept-list.sh +80 -0
  99. package/hooks/scripts/tests/test-lessons-append.sh +138 -0
  100. package/hooks/scripts/tests/test-lessons-drift-set.sh +36 -0
  101. package/hooks/scripts/tests/test-lessons-on-off.sh +75 -0
  102. package/hooks/scripts/tests/test-lessons-read.sh +97 -0
  103. package/hooks/scripts/tests/test-on-interrupt.sh +186 -0
  104. package/hooks/scripts/tests/test-redact-prompt.sh +27 -0
  105. package/hooks/scripts/tests/test-resume-devlog.sh +35 -0
  106. package/hooks/scripts/tests/test-round-start.sh +825 -0
  107. package/hooks/scripts/tests/test-segment-watch-set.sh +75 -0
  108. package/hooks/scripts/tests/test-segment-watch.sh +468 -0
  109. package/hooks/scripts/tests/test-session-start-devlog.sh +508 -0
  110. package/hooks/scripts/tests/test-start-pause-devlog.sh +84 -0
  111. package/hooks/scripts/tests/test-status-span.sh +50 -0
  112. package/hooks/scripts/tests/test-workspace-snapshot.sh +130 -0
  113. package/hooks/scripts/workspace-snapshot.sh +69 -0
  114. package/package.json +37 -0
  115. package/skills/devlog-tracker/SKILL.md +411 -0
  116. package/skills/devlog-tracker/references/checkpoint-mode.md +42 -0
  117. package/skills/devlog-tracker/references/lessons-mode.md +32 -0
  118. package/skills/devlog-tracker/references/reply-fold.md +129 -0
  119. package/skills/devlog-tracker/references/round-segments.md +55 -0
  120. package/skills/devlog-tracker/references/span-mode.md +65 -0
@@ -0,0 +1,54 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "bash \"${DEVLOG_TRACKER_ROOT}/codex/hooks/on-session-start.sh\""
9
+ }
10
+ ]
11
+ }
12
+ ],
13
+ "UserPromptSubmit": [
14
+ {
15
+ "hooks": [
16
+ {
17
+ "type": "command",
18
+ "command": "bash \"${DEVLOG_TRACKER_ROOT}/codex/hooks/on-user-prompt-submit.sh\""
19
+ }
20
+ ]
21
+ }
22
+ ],
23
+ "PreToolUse": [
24
+ {
25
+ "hooks": [
26
+ {
27
+ "type": "command",
28
+ "command": "bash \"${DEVLOG_TRACKER_ROOT}/codex/hooks/on-pre-tool.sh\""
29
+ }
30
+ ]
31
+ }
32
+ ],
33
+ "Stop": [
34
+ {
35
+ "hooks": [
36
+ {
37
+ "type": "command",
38
+ "command": "bash \"${DEVLOG_TRACKER_ROOT}/codex/hooks/on-stop.sh\""
39
+ }
40
+ ]
41
+ }
42
+ ],
43
+ "SessionEnd": [
44
+ {
45
+ "hooks": [
46
+ {
47
+ "type": "command",
48
+ "command": "bash \"${DEVLOG_TRACKER_ROOT}/codex/hooks/on-session-end.sh\""
49
+ }
50
+ ]
51
+ }
52
+ ]
53
+ }
54
+ }
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: 調整 Checkpoint Mode 的沉默門檻——累積多少輪沒寫 ## Checkpoint 就要求補跨輪摘要。
3
+ ---
4
+
5
+ 取得使用者要設定的輪數(正整數);沒帶就先問,不要用預設值硬猜。
6
+ 跑:
7
+
8
+ ```bash
9
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
10
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/checkpoint-set.sh" <rounds>
11
+ ```
12
+
13
+ 不要自己手改 `.devlog/.checkpoint-state`。
14
+
15
+ - stdout 是 `NOT_STARTED`:告知還沒 `/devlog-tracker:start`;問要不要現在 start,不要自己跑 start。
16
+ - stdout 有 `CHECKPOINT_MAX_SILENT_ROUNDS=<n>`:告知新門檻已生效。
17
+ - exit 1:原樣顯示 stderr,請使用者換正整數再試。
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: 無條件清空 .devlog/devlog.md(含專案摘要與所有 Round 歷史),只留這一輪重編成 Round 1;不可復原,執行前一定要先問使用者確認
3
+ ---
4
+
5
+ 請執行 devlog clean(無條件清空)。這是使用者主動執行 `/devlog-tracker:clean` 時才做的事,不要自動觸發。
6
+
7
+ 確認之前不要跑清空腳本、不要動 `devlog.md` 的既有歷史內容。這一輪本身仍照 devlog-tracker 的一般規則:結束前要補 `### Summary` / `### Handoff` / `### Status`(Status 通常是 `BLOCKED`,因為在等使用者回覆)——這跟「先問再等」不衝突,Stop hook 檢查的是這一輪有沒有收尾,不是有沒有清空。
8
+
9
+ ## 1. 讀檔
10
+
11
+ 讀取 `.devlog/devlog.md` 全文。若檔案不存在,告知「目前沒有東西可清空」,不要建立 `.devlog/` 或任何新檔,結束。
12
+
13
+ ## 2. 先問,然後停下來等
14
+
15
+ 數一下檔案裡有幾個 `## Round`(判斷標題時,略過圍欄程式碼區塊 ``` 內的行,與 hook 腳本解析方式一致)。用這一則訊息問:
16
+
17
+ ```
18
+ 這個動作會把 .devlog/devlog.md 整份清空(含專案摘要與全部 <N> 個 Round 歷史),
19
+ 不可復原、不會搬移或備份到別的檔案(devlog.archive.md、devlog.<name>.md 具名保存檔
20
+ 都不受影響,如果想先保留這份的內容,改用 /devlog-tracker:keep)。
21
+ 清空同時也會關閉 Span Mode(刪 .span-open)、把 checkpoint 計數歸零。
22
+ 確定要清空,請回覆「清空」;其他任何回覆都當作取消。
23
+ ```
24
+
25
+ 這一輪照上面的規則正常收尾(Summary 記下「詢問是否清空,等待回覆」,Status 用 `BLOCKED`),然後停止。
26
+
27
+ - 回覆不是「清空」(含沒回覆、模糊、其他任何字)→ 不跑腳本、不改 `devlog.md`,告知已取消,這一輪(或折入/新開的這一輪)收尾即可,結束。
28
+ - 回覆「清空」→ 進入步驟 3。
29
+
30
+ ## 3. 跑清空腳本
31
+
32
+ ```bash
33
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
34
+
35
+ ```bash
36
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
37
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/clean-devlog.sh" --confirmed
38
+ ```
39
+ ```
40
+
41
+ `--confirmed` 是必要參數,只有在使用者明確回覆「清空」之後才可以帶這個參數執行;不要在其他情況下跑這支腳本。腳本是唯一的實作來源:有沒有開著的 Round、要重編成 Round 1 還是整份刪除、重置 `.span-open` 與 checkpoint 狀態,都不要自己動手做。exit 1 時原樣顯示 stderr,不要自行重試、不要自己動手改檔案。
42
+
43
+ ## 4. 處理結果並收尾這一輪
44
+
45
+ 依 stdout 的 `KEPT_ROUND`:
46
+
47
+ - `KEPT_ROUND=1`:告知已清空,這一輪重編成 `## Round 1`。這一輪結束前補上(或改寫)`### Summary`(記下這次清空的結果)/ `### Handoff` / `### Status`(Stop hook 仍會檢查)。
48
+ - `KEPT_ROUND=0`:告知已整份清空。若 `.devlog/.enabled` 存在,說下一則訊息會重新從 Round 1 開始記錄;若不存在(強制記錄目前是暫停或從未啟動),說清楚要先 `/devlog-tracker:start` 才會開始新的 Round 1。沒有輪次可補收尾。
49
+
50
+ 不要讀寫 `devlog.archive.md` 或任何 `.devlog/devlog.<name>.md` 具名檔。
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: 把 .devlog/devlog.md 裡已完成且較舊的紀錄搬到 devlog.archive.md,避免主檔案無限膨脹
3
+ ---
4
+
5
+ 請執行 devlog 壓縮:
6
+
7
+ 1. 讀取 `.devlog/devlog.md` 全文。若檔案不存在,告知使用者目前沒有東西可壓縮,不要建立空檔案,結束。
8
+ 2. 找出所有 `## Round <N>` 區塊,判斷各自的 Status。
9
+ 3. 保留規則(以下皆保留在 devlog.md,不搬動):
10
+ - 檔案開頭的專案摘要(如果有)
11
+ - 最近 5 輪(不論 Status 是什麼)
12
+ - 所有 Status 為 `IN_PROGRESS`、`BLOCKED` 或 `INTERRUPTED` 的輪次,不論多舊
13
+ - 所有 `## Checkpoint` 區塊,永遠留在 devlog.md、不搬到 archive——它們是
14
+ checkpoint 機制存在的目的:翻閱時的摘要路標,搬走就失去了作用
15
+ 4. 跑(不要自己搬檔):
16
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
17
+ ```bash
18
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
19
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/compact-devlog.sh"
20
+ ```
21
+ 檔案不存在時腳本 exit 1:告知沒有東西可壓縮。
22
+ 5. 用 stdout 的 `MOVED` / `REMAINING` / `ARCHIVE` 回報一句話。
23
+
24
+ 不要在使用者沒有要求的情況下自動觸發這個流程;這是使用者主動執行 `/devlog-tracker:compact` 時才做的事。不要讀取或寫入 `.devlog/devlog.<name>.md` 具名檔(那是 `/devlog-tracker:keep` 的產物)。
@@ -0,0 +1,30 @@
1
+ ---
2
+ description: 讀取 .devlog/devlog.md,核對最後一輪 Handoff 的工作區後再依下一步接著做。/clear 之後不會自動接續,要下這個指令才會讀檔。
3
+ ---
4
+
5
+ 請執行 devlog continue(接續上一題)。這是使用者主動執行 `/devlog-tracker:continue`,或明確說「continue」「接續」「繼續上一題」時才做的事。`/clear` 之後的一般新請求不要先讀檔接舊工作。
6
+
7
+ 1. 讀取 `.devlog/devlog.md`。若檔案不存在,告知「目前沒有 devlog 可接續」,不要建立 `.devlog/` 或任何新檔,結束。記下 `.devlog/` 的上層目錄(也就是專案根目錄)的絕對路徑,作為本輪接下來都要用的專案根目錄——後面步驟(尤其是步驟 5.1)一律沿用這個值,不要再用 shell 的 `pwd` 重新推。Bash 工具的工作目錄會在同一段對話裡的呼叫之間持續累積,中途若因為別的原因 `cd` 過,`pwd` 就不再代表這個專案根目錄。
8
+ 2. 若 `.devlog/.span-open` 存在:先告訴使用者有一個還沒關的 span(Round 編號與 `opened_at`,若讀得到),問要繼續這個自動化任務還是先關掉它。沒有明確要關就當成要繼續,不要自己刪 `.span-open`。
9
+ 3. 讀最近的 Round(不夠再往前讀;有 `## Checkpoint` 就一併看最後一個)。不要讀 `devlog.archive.md` 或 `devlog.<name>.md`,除非 Handoff 下一步明確指向它們。
10
+ 4. 依**最後一個歷史 Round**(不是這一輪 continue 自己的 skeleton)的 Status 行動。`DONE`:告訴使用者上一題已經結束,等新需求。不要核對、不要自己找下一件工作。
11
+ 5. `IN_PROGRESS`、`INTERRUPTED`、`BLOCKED`:先核對,再行動。不要先問「上次做到哪」。不要改歷史 Round。
12
+ 1. 跑與寫「工作區」相同的生產者,不要自己跑 git、不要手編成 SKILL 的七種格式。先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
13
+ ```bash
14
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
15
+ CLAUDE_PROJECT_DIR="<步驟 1 記下的專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/hooks/scripts/workspace-snapshot.sh"
16
+ ```
17
+ 把 `CLAUDE_PROJECT_DIR` 換成實際的絕對路徑字串再執行,不要真的呼叫 `pwd`。stdout 就是實際快照(1 行或 2 行)。腳本檔找不到時才退回 `skills/devlog-tracker/SKILL.md` `#### 工作區` 的七種格式手編。不要重跑測試套件,除非「下一步」本身就是跑測試。
18
+ 2. 把編成的實際快照對照該歷史 Round 的 `#### 工作區` 正文。
19
+ - 沒有這一節(舊 Round、`INTERRUPTED` stub):沒有宣稱可對,不算「不符」——不用寫 `### 段落`,直接以剛才編成的實際快照為準。
20
+ - 有這一節但跟編成的實際快照不符:在**這一輪**先追加一段 `### 段落`,寫宣稱 vs 實際(用剛才腳本的 stdout 當實際快照)。
21
+ - 有這一節且相符:不用寫 `### 段落`。
22
+ 3. 然後依**實際工作樹**行動(不要照 Handoff「工作區」或「現況」的字面當事實):
23
+ - `IN_PROGRESS`/`INTERRUPTED`:做 Handoff「下一步」(沒有就依「現況」與實際工作樹推出並做)。對照「完成條件」判斷能否收成 `DONE`。
24
+ - `BLOCKED`:看缺的外部輸入本身在不在——已經出現就做下一步;仍缺就說明缺什麼並停。git 相不相符不能證明缺件已到,不要發明輸入。
25
+ 6. **寫回義務(L1 硬契約):** 接手=核對 → 行動 → **同一輪收尾寫回** `.devlog/devlog.md`。讀而不寫算失敗——下一任無法再接。編輯**這一個** Round(continue 的 skeleton/開著的 Round),不要再新增一個 `## Round`,也不要改歷史 Round。必寫 `### Summary`、`### Reply`、`### Handoff`、`### Status`(契約見 SKILL.md)。收尾時若 Status 是 `IN_PROGRESS`/`BLOCKED`,照契約寫本輪的 `#### 工作區`、`#### 完成條件`、`#### 下一步`。聊天不要旁白「已寫入 devlog」。
26
+ - **有** `/devlog-tracker:start`(`.enabled`)時:Stop hook 會擋沒寫完的收尾。
27
+ - **沒有** Stop/未 `start`/Cursor 未裝 hook:仍必須自行用 Edit/Write 寫回;沒有擋關不代表可以省略。
28
+ - **子 agent** 若只改程式不收尾:主對話負責寫回,或在派出 brief 裡要求子任務寫回同一 Round。
29
+
30
+ `/devlog-tracker:start` 不是 continue:start 只開強制記錄並對進度;要接著做才用本指令。
@@ -0,0 +1,100 @@
1
+ ---
2
+ description: 掃描整份 devlog.md,把值得留名的主題段落一次分別搬成 devlog.<name>.md;也可只抽出一段或合併成全部歷史一個檔
3
+ ---
4
+
5
+ 請執行 devlog keep(具名搬走)。這是使用者主動執行 `/devlog-tracker:keep` 時才做的事,不要自動觸發。
6
+
7
+ 確認之前不要寫任何檔。若這一輪本身是開著的 Round,永遠不要把它搬走,這一輪結束前仍要補 `### Summary` / `### Handoff` / `### Status`(若沒有開著的 Round,見步驟 1 第 2 點)。
8
+
9
+ ## 1. 讀檔、找出開著的 Round
10
+
11
+ 1. 讀取 `.devlog/devlog.md` 全文。若檔案不存在,告知「目前沒有東西可 keep」,不要建立 `.devlog/` 或任何新檔,結束。
12
+ 2. 開著的 Round:若 `.devlog/.round-open` 存在且有 `"round"` 數字,用那個編號。若 `.round-open` 不存在(從未 start 或已 pause),表示沒有開著的 Round,檔案裡所有 `## Round` 都是歷史,不要把最後一個 Round 當成開著的 Round 來排除。
13
+ 3. 歷史 Round = 檔案裡除了開著的 Round 以外的所有 `## Round`(判斷 `## ` 標題時,略過圍欄程式碼區塊 ``` 內的行,與 hook 腳本解析方式一致)。若沒有任何歷史 Round,告知「目前沒有東西可 keep」,不要建立新檔,結束。
14
+
15
+ ## 2. 切出主題段落,過濾瑣碎段落
16
+
17
+ 1. 依各輪 `### User Input` 與 `### Summary` 的主題變化,把**全部**歷史 Round(不含開著的 Round)切成連續、不重疊、涵蓋所有歷史 Round 的候選段落,由舊到新排列,不要留空隙。如果同一個主題橫跨了 Round 編號的缺口(例如先前 keep 或 compact 已經搬走中間的 Round,留下不連續的編號),在缺口處切成兩段:每一段的 `from`–`to` 之間必須都是實際存在的歷史 Round,不能有缺號(腳本會嚴格比對數量,缺號的段落會直接失敗)。
18
+ 2. 用 skills/devlog-tracker 判斷瑣碎程度的同一套訊號,評估每一個候選段落:有檔案異動、有影響後續的決策、有未完成工作、刪掉會接續不上 → 值得留名,列為候選;只有確認、閒聊、重複 → 偏低,直接丟掉,不列入建議清單,繼續留在 `devlog.md`,不用再嘗試併進相鄰段落。段落裡有未收尾的 `IN_PROGRESS` / `BLOCKED` / `INTERRUPTED` Round 可以正常納入候選段落,不要僅因為未收尾就拒絕或把它排除到段落外。
19
+ 3. 若一個候選段落都沒有,告知「目前沒有值得分主題留名的段落」,不要建立新檔,結束。
20
+ 4. 對每個候選段落,用**那一段的內容**(不是留下的 Round)產生建議 `<name>`:小寫 ASCII kebab-case,2–4 段,只反映主題。不要加日期、不要加 `round-12-18`。例如 `span-mode`、`keep-plan`。這一批裡若兩段的建議 `<name>` 相同,比照步驟 4 的撞名規則先加上 `-2`/`-3` 分開,再一起列出:Round 編號較小(較早)的段落保留原建議名稱,較晚的段落加 `-2`/`-3`。
21
+ 5. 同時為每個候選段落生成步驟 3 要顯示的「一句這段在做什麼」。這句話記下來留到步驟 5 用(會原樣寫進 `## Kept 索引` 那一行),不是只顯示過就丟掉;使用者在步驟 3 若修改了範圍或檔名,這句描述不用跟著重新生成,除非該段的主題內容本身也變了。
22
+
23
+ ## 3. 一次列出全部候選段落,然後停下來等
24
+
25
+ 用這一則訊息列出所有候選段落(不要分開一段一段問):
26
+
27
+ ```
28
+ 掃到 N 段值得留名:
29
+ 1. Round <from>–<to> <一句這段在做什麼> → devlog.<name>.md
30
+ 2. Round <from>–<to> <一句這段在做什麼> → devlog.<name>.md
31
+ ...
32
+ 其餘 Round(<留下的範圍,可能不只一段、逗號分隔,或「無」>)偏瑣碎,留在 devlog.md。
33
+
34
+ 回覆:
35
+ 採用 → 全部照上面寫入
36
+ 改第 N 段範圍 <from>-<to> / 改第 N 段檔名 <name> / 移除第 N 段
37
+ 全部歷史合併成一個檔 <name> → 放棄分段,整份歷史存成一檔
38
+ 取消
39
+ ```
40
+
41
+ 同一則回覆可以合併多條修改,例如「改第 2 段檔名 foo,移除第 3 段」。`N` 一律對應上面列出的原始編號,修改不會讓其他段落重新編號。
42
+
43
+ 然後停止。使用者還沒回覆前不要寫任何檔。
44
+
45
+ - 取消,或套用修改後一段都不剩 → 不改檔,結束。
46
+ - 「全部歷史合併成一個檔 `<name>`」→ 放棄前面列出的分段,改成單一段:`from` = 最早的歷史 Round、`to` = 最晚的歷史 Round(仍不含開著的 Round),`<name>` 用使用者這裡給的名稱。之後只處理這一段,跳過步驟 4 的「重疊」與「批次撞名」檢查(只有一段)。
47
+ - 其他回覆(採用 / 各種修改組合)→ 帶著套用修改後的段落清單,進入步驟 4。
48
+
49
+ ## 4. 驗證每一段的範圍與檔名(不通過就再問一次,仍不寫檔)
50
+
51
+ **範圍**
52
+
53
+ - 每一段的 `from`–`to` 必須連續、含端點、屬於歷史 Round,且不得包含開著的 Round。
54
+ - 這一批裡任兩段的範圍不可重疊。
55
+ - `from` > `to`、`from`–`to` 之間有任一整數不是實際存在的歷史 Round(例如中間被先前的 keep 或 compact 搬走過,留下缺號)、範圍含開著的 Round、或跟同批另一段重疊 → 說明原因,請使用者改,不要寫檔。範圍內有未收尾的 `IN_PROGRESS` / `BLOCKED` / `INTERRUPTED` Round 不算拒絕理由,可以正常納入。
56
+
57
+ **`<name>` 正規化**(逐段套用)
58
+
59
+ 使用者給的字串依序處理:若以 `devlog.` 開頭先剝掉;若以 `.md` 結尾再剝掉。因此 `foo`、`devlog.foo`、`devlog.foo.md` 都是 `foo`。空白改成 `-`;連續 `-` 收成一個;去掉頭尾的 `-`。
60
+
61
+ 拒絕(再問、不寫檔):
62
+
63
+ - 結果是空的,或路徑會變成 `.devlog/devlog.md`
64
+ - 結果是 `archive`(那是 compact 的 `devlog.archive.md`)
65
+ - 含 `/`、`\` 或 `..`
66
+ - 長度超過 64 個字元
67
+
68
+ 使用者自訂可以用非 ASCII,只要通過上面的檢查。Claude 的第一個建議仍必須是 ASCII kebab-case。
69
+
70
+ **撞名**
71
+
72
+ 目標 `.devlog/devlog.<name>.md` 已存在,或跟同一批裡另一段最終確認的檔名相同 → 不要覆寫,也不要讓兩段寫進同一個檔。改建議 `devlog.<name>-2.md`(已存在就 `-3`,依此加),等使用者確認或另取名。
73
+
74
+ ## 5. 依序跑搬移腳本(每段各跑一次,由舊到新)
75
+
76
+ 把步驟 4 驗證通過的段落,依 `from` 由小到大排序。對每一段依序跑(一段一次,不要自己搬檔,也不要一次塞多段給腳本):
77
+
78
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
79
+
80
+ ```bash
81
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
82
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/keep-move.sh" \
83
+ --from <from> --to <to> --name "<name>" --desc "<這段在做什麼的一句話>"
84
+ ```
85
+
86
+ `<from>`、`<to>`、`<name>` 必須使用該段步驟 4 確認後的值。`<這段在做什麼的一句話>` 用步驟 2.5 記下的那句描述(純文字,不要換行、不要含反引號);腳本會把它原樣接在 `## Kept 索引` 那一行的 `kept_at` 之後。腳本是搬移、Checkpoint 歸屬、full keep 重編與 checkpoint counter reset 的唯一實作來源;它一次只認一段範圍,完全不知道這是批次的一部分,`commands/keep.md` 自己負責依序呼叫。
87
+
88
+ 任一段的腳本 exit 1:立刻停止整批,原樣顯示那一段的 stderr,不要自行重試刪除,也不要手動補做搬移,也不要繼續跑後面還沒處理的段落。已經成功搬走的段落不要回滾。
89
+
90
+ 如果這批段落最終涵蓋了 `devlog.md` 目前剩下的所有歷史 Round(沒有瑣碎段落留下),跑到最後一段(Round 號碼最新的那一段)時,腳本會自動判定為 full keep:專案摘要併入那一檔、開著的 Round 重編號成 1、`.span-open` 刪除、checkpoint counter 歸零。這是預期行為,不用特別處理,也不用另外判斷「這是不是 full keep」。
91
+
92
+ ## 6. 處理腳本結果
93
+
94
+ 每段成功時記下 stdout 給的具名檔路徑、`ROUNDS=<from>-<to>` 與 `REMAINING=<int>`,等這批全部段落都跑完(或某段失敗中止)後,一次在步驟 7 回報。
95
+
96
+ ## 7. 回報並收尾這一輪
97
+
98
+ 依段落回報:每個具名檔路徑、搬走幾輪(哪些編號);再依最後一次成功執行的 `REMAINING` 回報 `devlog.md` 目前剩幾輪(這個數字含還開著的那一輪,不是只算歷史 Round)。若中途因某段腳本失敗而中止,清楚列出哪些段落已經搬走(連檔名)、哪些完全沒嘗試。不要讀寫 `devlog.archive.md`。
99
+
100
+ 若 `.round-open` 存在:在開著的那一輪補上 `### Summary` / `### Handoff` / `### Status` 再結束(Stop hook 仍會檢查)。若沒有開著的 Round:不要改寫歷史 Round 的收尾。
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: 調整 Lessons Mode「工作區漂移重複發生」機制性提醒的門檻——累積幾次工作區不符才印一次建議。
3
+ ---
4
+
5
+ 取得使用者要設定的次數(正整數);沒帶就先問,不要用預設值硬猜。跑:
6
+
7
+ ```bash
8
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
9
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/lessons-drift-set.sh" <次數>
10
+ ```
11
+
12
+ 不要自己手改 `.devlog/.lessons-drift-state`。
13
+
14
+ - stdout 是 `NOT_STARTED`:告知這個專案還沒 `/devlog-tracker:start`,問要不要現在
15
+ `/devlog-tracker:start`,不要自己跑 start。
16
+ - stdout 是 `LESSONS_NOT_ENABLED`:告知這個門檻隸屬 Lessons Mode,請先
17
+ `/devlog-tracker:lessons-on`,不要自己跑 lessons-on。
18
+ - stdout 有 `LESSONS_DRIFT_THRESHOLD=<n>`:告知新門檻已生效。
19
+ - exit 1:原樣顯示 stderr,請使用者換正整數再試,不要自己編數字硬跑。
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: 關閉 Lessons Mode。不會刪除任何已寫的 devlog.lessons.*.md 或索引,只是之後不再考慮記新的一筆。
3
+ ---
4
+
5
+ 請執行:
6
+
7
+ 1. 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
8
+ ```bash
9
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
10
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/lessons-off.sh"
11
+ ```
12
+ 不要自己刪 `.lessons-enabled`。
13
+ 2. stdout 是 `NOT_ENABLED`:告知 Lessons Mode 本來就沒開,結束。
14
+ 3. stdout 是 `LESSONS_DISABLED`:告知已關閉,歷史教訓都還在(`devlog.lessons.*.md` 與 `## Lessons 索引`),可用 `/devlog-tracker:lessons-on` 再開。
15
+
16
+ 不要動任何 `devlog.lessons.*.md`、`## Lessons 索引`,也不要動 `.devlog/.enabled`(那是主開關,不受這個指令影響)。
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: 開啟 Lessons Mode(開發歷程教訓,預設關閉)。隸屬主開關:沒下過 /devlog-tracker:start 就開不了。
3
+ ---
4
+
5
+ 請執行:
6
+
7
+ 1. 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
8
+ ```bash
9
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
10
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/lessons-on.sh"
11
+ ```
12
+ 不要自己用手建 `.lessons-enabled`。
13
+ 2. stdout 是 `NOT_ENABLED`:告知這個專案還沒下過 `/devlog-tracker:start`,Lessons Mode 隸屬主開關,沒有 Round/Status 紀錄可判斷「BLOCKED→解開」,請先 `/devlog-tracker:start` 再開這個。
14
+ 3. stdout 是 `LESSONS_ENABLED=...`:告知 Lessons Mode 已開啟。簡短說明:
15
+ - 這是給「開發歷程中的困難/決策」用的,不是架構知識庫(那個留在 `docs/design/*.md`)
16
+ - 只有兩種訊號會讓你考慮記一筆:這輪的 Status 從 `BLOCKED` 解開,或你自己判斷這輪明顯繞了一圈才對
17
+ - 完全不強制——寫不寫都不影響這一輪能不能收尾,跟 `#### 決策` 同一種「沒有就整節省略」的精神
18
+ - 用 `/devlog-tracker:lessons` 查現有教訓,或 `/devlog-tracker:lessons-off` 關掉
19
+
20
+ 不要因為 `.lessons-enabled` 已經存在就跳過步驟 3——重新確認一次現在的狀態即可。
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: 查看 Lessons 索引,或讀某個主題的完整教訓紀錄(純讀取,不核對工作區、不等確認)。
3
+ ---
4
+
5
+ 取得使用者是否有給 `<topic>`(可能沒有,代表只看索引)。記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1)。先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),再跑:
6
+
7
+ ```bash
8
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
9
+ CLAUDE_PROJECT_DIR="<剛才記下的專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/hooks/scripts/lessons-read.sh" "<topic,沒有就留空>"
10
+ ```
11
+
12
+ 沒有 `<topic>`:
13
+ - `NO_INDEX`:告知目前沒有任何 lessons 紀錄,結束。
14
+ - 其他輸出:就是目前的 `## Lessons 索引` 內容(每個主題檔一行:則數、最新一則標題、更新時間),原樣顯示給使用者,不用額外解讀或摘要。
15
+
16
+ 有 `<topic>`:
17
+ - 回傳 `MISSING`:列出 `CANDIDATES`(若有)讓使用者選別的主題名稱,不要自己猜一個相近的名字硬讀。
18
+ - 其他輸出:第一行 `PATH=...` 之後是該主題檔的完整內容(所有歷史條目,由舊到新),原樣顯示給使用者。
19
+
20
+ 這是純讀取,不做 `commands/continue.md`/`commands/resume.md` 那套「核對工作區、等確認才動手」流程——lessons 是參考資料,不是暫停中的工作主題。讀完之後不要自動據此修改任何檔案,除非使用者接著明確要求。
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: 把已 keep 的具名檔(devlog.<name>.md)整合成一份跨主題總覽,並列出看起來該進 CLAUDE.md 的規範候選。純讀取,不核對工作區、不等確認。
3
+ ---
4
+
5
+ 請執行 devlog overview(已 keep 舊檔總覽)。這是使用者主動執行 `/devlog-tracker:overview` 時才做的事。
6
+
7
+ 這是純讀取,不做 `commands/continue.md`/`commands/resume.md` 那套「核對工作區、等確認才動手」流程——已 keep 的檔案是參考資料,不是暫停中的工作主題。讀完之後不要自動據此修改任何檔案(包含 `CLAUDE.md`),除非使用者接著明確要求。
8
+
9
+ ## 1. 取得已 keep 的檔案清單
10
+
11
+ 記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1)。先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),再跑:
12
+
13
+ ```bash
14
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
15
+ CLAUDE_PROJECT_DIR="<剛才記下的專案根目錄絕對路徑>" bash "${PLUGIN_ROOT}/hooks/scripts/kept-list.sh"
16
+ ```
17
+
18
+ - `NO_INDEX`:告知「目前沒有已 keep 的舊檔」,結束。
19
+ - 其他輸出:每行一個 `FILE=<絕對路徑> EXISTS=1` 或 `EXISTS=0`。`EXISTS=0` 是索引裡還留著、但檔案已被手動刪掉的 ghost row,不要嘗試讀它,記下檔名等步驟 3 一併提一句;`EXISTS=1` 才要讀。
20
+
21
+ 若 `EXISTS=1` 的檔案一個都沒有(清單全是 ghost row),告知「已 keep 的舊檔都不存在了」,列出這些 ghost 檔名,結束。
22
+
23
+ ## 2. 讀取內容,整合總覽
24
+
25
+ 用 Read 讀取每個 `EXISTS=1` 的檔案全文。讀完後在對話裡輸出兩塊,不寫入任何檔案:
26
+
27
+ 1. **跨主題總覽**:依主題(不是依檔案機械條列)概述做了什麼、關鍵決定、還沒收尾或之後可能要接續的事。同一主題如果分散在多個檔案,合併描述,不用一檔一段硬切。
28
+ 2. **可能該進 CLAUDE.md 的規範**:從內容裡挑出讀起來像「規則、決定、之後應該一直遵守」的部分(不是單次任務細節、不是已經過時或被後續內容取代的決定)。格式盡量貼近 CLAUDE.md 條列寫法(一行一條規則,必要時附一句原因),方便使用者直接複製貼上。找不到夠格的候選就不要輸出這一節、也不要硬湊。
29
+
30
+ ## 3. 收尾
31
+
32
+ 若步驟 1 有 ghost row,在總覽最後補一句列出哪些 `devlog.<name>.md` 已經在索引裡但磁碟上找不到(不用建議刪索引行或做任何修復,這是已知限制,見 `docs/design/keep.md` Kept index)。
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: 暫停這個專案的 devlog 強制記錄機制。不會刪除任何歷史紀錄,只是之後 Stop 與 PreToolUse hook 都因 `.enabled` 移除而停止檢查。
3
+ ---
4
+
5
+ 請執行:
6
+
7
+ 1. 跑:
8
+ ```bash
9
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
10
+
11
+ ```bash
12
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
13
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/pause-devlog.sh"
14
+ ```
15
+ ```
16
+ 不要自己刪 `.enabled`。
17
+ 2. stdout 是 `NOT_ENABLED`:告知這個專案本來就沒有啟動強制記錄,結束。
18
+ 3. stdout 是 `PAUSED`:告知強制記錄已暫停,歷史都還在,可用 `/devlog-tracker:start` 再開。
19
+
20
+ 不要動 `.devlog/devlog.md`、`.checkpoint-state`、`.segment-state`。
@@ -0,0 +1,18 @@
1
+ ---
2
+ description: 讀取具名保存的 devlog,核對最後一輪 Handoff 工作區後再接續該段工作。
3
+ ---
4
+
5
+ 取得使用者提供的 `<name>`;沒有名稱時先詢問。記下你目前已經確認的專案根目錄絕對路徑(後面步驟都要用這個值,不要用 `$(pwd)` 重新推——理由同 `commands/continue.md` 步驟 1:Bash 工具的工作目錄會在對話裡持續累積前面呼叫的 `cd`,用當下的 `pwd` 可能已經不是這個專案根目錄)。先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),再跑:
6
+
7
+ ```bash
8
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
9
+ CLAUDE_PROJECT_DIR="<剛才記下的專案根目錄絕對路徑,不要用 $(pwd) 重新推>" bash "${PLUGIN_ROOT}/hooks/scripts/resume-devlog.sh" --name "<name>"
10
+ ```
11
+
12
+ 若回傳 `MISSING`,列出 `CANDIDATES` 讓使用者選,不要自動執行工作。
13
+ 找到檔案後,讀最後一個歷史 Round。`DONE`:告訴使用者該主題已結束,等新需求。不核對、不開工。
14
+ `IN_PROGRESS`、`INTERRUPTED`、`BLOCKED`:先做 `commands/continue.md` **步驟 5.1–5.2**(沿用上面同一個專案根目錄絕對路徑,不要重新推;不要跟著做 5.3)。步驟 5.2 的 `### 段落` 寫進 `devlog.md` 的 open Round,不要寫進 keep 檔。然後依核對後的**實際工作樹**提出接續方式,**等待使用者確認後才做下一步**:
15
+ - `IN_PROGRESS`/`INTERRUPTED`:提出 Handoff「下一步」(沒有就依「現況」與實際工作樹推)。
16
+ - `BLOCKED`:說明缺什麼;缺的外部輸入已經出現就提出下一步,仍缺就停。git 相不相符不能證明缺件已到,不要發明輸入。
17
+
18
+ 後續紀錄一律寫進 `.devlog/devlog.md`,不要改寫具名 keep 檔。使用者確認並開工後,**同一輪必須收尾寫回** Summary/Reply/Handoff/Status(L1 寫回義務同 `commands/continue.md` 步驟 6)。
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: 調整 Segment Watch 的沉默門檻——同一輪連續多久沒改 devlog.md 就要求先補一段 ### 段落。
3
+ ---
4
+
5
+ 取得使用者要設定的時間長度(例如「10 分鐘」「5min」「300 秒」);沒帶就先問,不要用預設值硬猜。
6
+ 換算成整數秒數 `<seconds>`,跑:
7
+
8
+ ```bash
9
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
10
+
11
+ ```bash
12
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
13
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/segment-watch-set.sh" <seconds>
14
+ ```
15
+ ```
16
+
17
+ 不要自己手改 `.devlog/.segment-state`。
18
+
19
+ - stdout 是 `NOT_STARTED`:告知這個專案還沒 `/devlog-tracker:start`,門檻設定只在啟動後才有意義;問要不要現在 `/devlog-tracker:start`,不要自己跑 start。
20
+ - stdout 有 `SEGMENT_MAX_SILENT_SECONDS=<n>`:告知使用者新門檻已生效(換算回分鐘講會更好懂)。
21
+ - exit 1(例如帶了非正整數):原樣顯示 stderr,請使用者換一個時間長度再試,不要自己編秒數硬跑。
@@ -0,0 +1,13 @@
1
+ ---
2
+ description: 開啟或關閉 Span Mode,讓自動續接的長任務定期記錄進度。
3
+ ---
4
+
5
+ 先判斷使用者要開啟或關閉:
6
+
7
+ - 使用者明確要求關閉,或 `.devlog/.span-open` 已存在且沒有明確要求重新開啟:
8
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄),設 `PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"`,再跑 `CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/span-close.sh"`,
9
+ 再依 SKILL 的 span 收尾規則寫一個**新的 Round**,總結整段 span。
10
+ - 使用者要求開啟:先把目前 Round 正常寫完,`Status` 設為 `IN_PROGRESS`,再跑
11
+ `CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/span-open.sh"`。
12
+
13
+ 不要手寫 `.span-open` JSON。腳本 exit 1 時顯示 stderr,停止操作。
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: 啟動這個專案的 devlog 強制記錄機制。之後每一輪結束前都會被 Stop hook 檢查,沒寫 devlog 就不能結束。
3
+ ---
4
+
5
+ 請執行以下步驟:
6
+
7
+ 1. 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
8
+ ```bash
9
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
10
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/start-devlog.sh"
11
+ ```
12
+ 不要自己用手建 `.enabled` / `.checkpoint-state` / `.segment-state`。
13
+ 2. 若 stdout 有 `GITIGNORE_DEVLOG=no`:鄭重提醒——`.devlog/` 會寫入使用者原文(遮罩只覆蓋常見 token 前綴,不是通用掃密)。**強烈建議**把 `.devlog/` 加進專案 `.gitignore`。問要不要現在加。只有使用者明確說要,才在 `.gitignore` 末尾追加一行 `.devlog/`(檔案不存在就建立)。不要改其他行。若使用者拒絕,再警告一次「之後若不小心 commit,prompt/殘留密鑰可能進版控」,然後繼續步驟 3。
14
+ 3. 讀取 `.devlog/devlog.md`(若存在):
15
+ - 有內容:摘要目前進度,跟使用者確認「上次做到哪、狀態是什麼」
16
+ - 不存在:告知使用者這是全新開始,準備寫下 Round 1
17
+ 4. 告訴使用者:從現在開始,每一則使用者訊息送出時就會先寫 User Input skeleton,結束前仍要補 Summary / Handoff;同一輪約 10 分鐘沒改這個檔,下一個工具會被要求先補 `### 段落`(門檻可用 `/devlog-tracker:segment-watch <時間長度>` 調整);可以用 `/devlog-tracker:pause` 關掉。
18
+
19
+ 不要因為 `.enabled` 已經存在就跳過步驟 3。`/clear` 之後若要接著做上一題,用 `/devlog-tracker:continue`,不要用 start 開工。
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: 查看這個專案 devlog 強制記錄是否開著、span / checkpoint / 最後一輪 Status。
3
+ ---
4
+
5
+ 跑:
6
+ ```bash
7
+ 先決定 plugin 根目錄(有 `CLAUDE_PLUGIN_ROOT` 用它;否則用 `DEVLOG_TRACKER_ROOT`;兩者都空就用含 `.claude-plugin/plugin.json` 的本 plugin 根目錄):
8
+
9
+ ```bash
10
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-${DEVLOG_TRACKER_ROOT:-}}"
11
+ CLAUDE_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/hooks/scripts/status-devlog.sh"
12
+ ```
13
+ ```
14
+ 把 stdout 翻譯成給人看的幾行(含 `LESSONS=yes/no`:Lessons Mode 開關狀態;`LESSONS_DRIFT=<count>/<threshold>`:Lessons Mode 開著時,工作區漂移不符的累積次數/門檻)。不要改任何檔。`NOT_STARTED` 就說還沒 `/devlog-tracker:start`。
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ _src="${BASH_SOURCE[0]}"
4
+ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
5
+ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../hooks/scripts" && pwd)"
6
+ INPUT="$(cat 2>/dev/null || true)"
7
+ ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
8
+ export CLAUDE_PROJECT_DIR="$ROOT"
9
+ ERR_FILE="$(mktemp "${TMPDIR:-/tmp}/cursor-pre-tool.XXXXXX")" || { echo '{}'; exit 0; }
10
+ printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/segment-watch.sh" >/dev/null 2>"$ERR_FILE"
11
+ RESULT=$?
12
+ MESSAGE="$(cat "$ERR_FILE" 2>/dev/null || true)"
13
+ rm -f "$ERR_FILE"
14
+ if [ "$RESULT" -eq 2 ]; then
15
+ if command -v jq >/dev/null 2>&1; then
16
+ jq -n --arg m "$MESSAGE" '{permission:"deny",user_message:$m}'
17
+ else
18
+ esc="$(printf '%s' "$MESSAGE" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ /\\t/g' | awk '{printf "%s\\n", $0}' | sed '$ s/\\n$//')"
19
+ printf '{"permission":"deny","user_message":"%s"}\n' "$esc"
20
+ fi
21
+ else
22
+ echo '{}'
23
+ fi
24
+ exit 0
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ _src="${BASH_SOURCE[0]}"
4
+ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
5
+ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../hooks/scripts" && pwd)"
6
+ INPUT="$(cat 2>/dev/null || true)"
7
+ ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
8
+ export CLAUDE_PROJECT_DIR="$ROOT"
9
+ printf '%s' "$INPUT" | bash "$PLUGIN_SCRIPTS/on-session-end.sh" >/dev/null 2>&1 || true
10
+ echo '{}'
11
+ exit 0
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ _src="${BASH_SOURCE[0]}"
4
+ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
5
+ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../hooks/scripts" && pwd)"
6
+ INPUT="$(cat 2>/dev/null || true)"
7
+ ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
8
+ export CLAUDE_PROJECT_DIR="$ROOT"
9
+ EXCERPT="$(printf '%s' '{"source":"startup"}' | bash "$PLUGIN_SCRIPTS/session-start-devlog.sh" 2>/dev/null || true)"
10
+ if command -v jq >/dev/null 2>&1; then
11
+ jq -n --arg c "$EXCERPT" '{additional_context:$c}'
12
+ else
13
+ esc="$(printf '%s' "$EXCERPT" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ /\\t/g' | awk '{printf "%s\\n", $0}' | sed '$ s/\\n$//')"
14
+ printf '{"additional_context":"%s"}\n' "$esc"
15
+ fi
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+ set -uo pipefail
3
+ _src="${BASH_SOURCE[0]}"
4
+ SCRIPT_DIR="$(cd "${_src%/*}" && pwd)"
5
+ PLUGIN_SCRIPTS="$(cd "$SCRIPT_DIR/../../hooks/scripts" && pwd)"
6
+ INPUT="$(cat 2>/dev/null || true)"
7
+ ROOT="$(printf '%s' "$INPUT" | bash "$SCRIPT_DIR/project-dir.sh")"
8
+ export CLAUDE_PROJECT_DIR="$ROOT"
9
+ STATUS=""
10
+ LOOP_COUNT=0
11
+ if command -v jq >/dev/null 2>&1; then
12
+ STATUS="$(printf '%s' "$INPUT" | jq -r '.status // empty' 2>/dev/null || true)"
13
+ LOOP_COUNT="$(printf '%s' "$INPUT" | jq -r '.loop_count // 0' 2>/dev/null || echo 0)"
14
+ else
15
+ STATUS="$(printf '%s' "$INPUT" | grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' 2>/dev/null | head -1 | sed 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' || true)"
16
+ LOOP_COUNT="$(printf '%s' "$INPUT" | grep -o '"loop_count"[[:space:]]*:[[:space:]]*[0-9]\+' 2>/dev/null | grep -o '[0-9]\+$' || echo 0)"
17
+ fi
18
+ case "$STATUS" in
19
+ aborted|error)
20
+ bash "$PLUGIN_SCRIPTS/close-open-round.sh" "$STATUS" >/dev/null 2>&1 || true
21
+ echo '{}'
22
+ exit 0
23
+ ;;
24
+ completed) ;;
25
+ *) echo '{}'; exit 0 ;;
26
+ esac
27
+ case "$LOOP_COUNT" in ''|*[!0-9]*) LOOP_COUNT=0 ;; esac
28
+ [ "$LOOP_COUNT" -ge 1 ] && ENFORCE_INPUT='{"stop_hook_active":true}' || ENFORCE_INPUT='{}'
29
+ ERR_FILE="$(mktemp "${TMPDIR:-/tmp}/cursor-stop.XXXXXX")" || { echo '{}'; exit 0; }
30
+ printf '%s' "$ENFORCE_INPUT" | bash "$PLUGIN_SCRIPTS/enforce-devlog.sh" >/dev/null 2>"$ERR_FILE"
31
+ RESULT=$?
32
+ MESSAGE="$(cat "$ERR_FILE" 2>/dev/null || true)"
33
+ rm -f "$ERR_FILE"
34
+ if [ "$RESULT" -eq 2 ]; then
35
+ if command -v jq >/dev/null 2>&1; then
36
+ jq -n --arg m "$MESSAGE" '{followup_message:$m}'
37
+ else
38
+ esc="$(printf '%s' "$MESSAGE" | sed 's/\\/\\\\/g; s/"/\\"/g')"
39
+ printf '{"followup_message":"%s"}\n' "$esc"
40
+ fi
41
+ else
42
+ echo '{}'
43
+ fi
44
+ exit 0