devlog-tracker 0.27.0 → 0.30.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/README.md +109 -100
- package/README.zh-TW.md +235 -0
- package/claude/hooks.json +21 -0
- package/cli/agents-md.js +1 -0
- package/commands/keep.md +18 -2
- package/commands/lessons-drift.md +2 -2
- package/commands/search.md +22 -0
- package/commands/status.md +2 -1
- package/core/scripts/clean-devlog.sh +1 -0
- package/core/scripts/devlog-lock.sh +17 -1
- package/core/scripts/devlog-path.sh +15 -8
- package/core/scripts/enforce-devlog.sh +25 -0
- package/core/scripts/handoff-file.sh +106 -0
- package/core/scripts/lessons-advisory-state.sh +51 -0
- package/core/scripts/lessons-append.sh +16 -0
- package/core/scripts/lessons-drift-set.sh +14 -10
- package/core/scripts/lessons-on.sh +8 -3
- package/core/scripts/lessons-subagent-done.sh +36 -0
- package/core/scripts/lessons-subagent-start.sh +36 -0
- package/core/scripts/round-start.sh +65 -16
- package/core/scripts/search-devlog.sh +63 -0
- package/core/scripts/session-start-devlog.sh +7 -0
- package/core/scripts/status-devlog.sh +4 -4
- package/core/scripts/tests/test-clean-devlog.sh +12 -0
- package/core/scripts/tests/test-devlog-lock.sh +39 -0
- package/core/scripts/tests/test-devlog-path.sh +44 -0
- package/core/scripts/tests/test-enforce-devlog-files.sh +11 -0
- package/core/scripts/tests/test-enforce-devlog-session-handoff.sh +178 -0
- package/core/scripts/tests/test-enforce-devlog-workspace.sh +35 -0
- package/core/scripts/tests/test-enforce-devlog.sh +174 -0
- package/core/scripts/tests/test-handoff-file.sh +98 -0
- package/core/scripts/tests/test-lessons-advisory-state.sh +55 -0
- package/core/scripts/tests/test-lessons-append.sh +18 -0
- package/core/scripts/tests/test-lessons-drift-set.sh +14 -5
- package/core/scripts/tests/test-lessons-on-off.sh +16 -6
- package/core/scripts/tests/test-lessons-subagent-hooks.sh +95 -0
- package/core/scripts/tests/test-round-start.sh +296 -13
- package/core/scripts/tests/test-search-devlog.sh +126 -0
- package/core/scripts/tests/test-session-start-devlog.sh +59 -0
- package/core/scripts/tests/test-status-span.sh +3 -3
- package/package.json +2 -2
- package/skills/devlog-tracker/SKILL.md +83 -13
- package/skills/devlog-tracker/references/checkpoint-mode.md +21 -6
- package/skills/devlog-tracker/references/contract.md +83 -0
- package/skills/devlog-tracker/references/lessons-mode.md +38 -8
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Self-check for search-devlog.sh (/devlog-tracker:search), a pure-read
|
|
3
|
+
# lightweight grep across every devlog*.md file under .devlog/ -- devlog.md,
|
|
4
|
+
# devlog.archive.md, kept devlog.<name>.md, devlog.lessons.<topic>.md, and
|
|
5
|
+
# branch-scoped files all match the same glob, so there is no per-type logic
|
|
6
|
+
# to keep in sync.
|
|
7
|
+
set -uo pipefail
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
10
|
+
TMP_ROOT="$(mktemp -d)"
|
|
11
|
+
trap 'rm -rf "$TMP_ROOT"' EXIT
|
|
12
|
+
|
|
13
|
+
export CLAUDE_PROJECT_DIR="$TMP_ROOT"
|
|
14
|
+
DEVLOG_DIR="$TMP_ROOT/.devlog"
|
|
15
|
+
|
|
16
|
+
FAIL=0
|
|
17
|
+
assert_exit() {
|
|
18
|
+
local desc="$1" expected="$2" actual="$3"
|
|
19
|
+
if [ "$actual" -eq "$expected" ]; then
|
|
20
|
+
echo "PASS: $desc"
|
|
21
|
+
else
|
|
22
|
+
echo "FAIL: $desc (expected exit $expected, got $actual)"
|
|
23
|
+
FAIL=1
|
|
24
|
+
fi
|
|
25
|
+
}
|
|
26
|
+
assert_contains() {
|
|
27
|
+
local desc="$1" needle="$2" haystack="$3"
|
|
28
|
+
case "$haystack" in
|
|
29
|
+
*"$needle"*) echo "PASS: $desc" ;;
|
|
30
|
+
*) echo "FAIL: $desc (expected to contain '$needle', got: $haystack)"; FAIL=1 ;;
|
|
31
|
+
esac
|
|
32
|
+
}
|
|
33
|
+
assert_not_contains() {
|
|
34
|
+
local desc="$1" needle="$2" haystack="$3"
|
|
35
|
+
case "$haystack" in
|
|
36
|
+
*"$needle"*) echo "FAIL: $desc (expected NOT to contain '$needle')"; FAIL=1 ;;
|
|
37
|
+
*) echo "PASS: $desc" ;;
|
|
38
|
+
esac
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# --- No .devlog/ at all -> NO_INDEX ----------------------------------------
|
|
42
|
+
OUT="$(bash "$SCRIPT_DIR/search-devlog.sh" "foo" 2>&1)"
|
|
43
|
+
RC=$?
|
|
44
|
+
assert_exit "no .devlog/ -> exit 0" 0 "$RC"
|
|
45
|
+
[ "$OUT" = "NO_INDEX" ] && echo "PASS: no .devlog/ -> NO_INDEX" || { echo "FAIL: expected NO_INDEX, got: $OUT"; FAIL=1; }
|
|
46
|
+
|
|
47
|
+
mkdir -p "$DEVLOG_DIR"
|
|
48
|
+
|
|
49
|
+
# --- Missing keyword argument -> error, no files touched -------------------
|
|
50
|
+
bash "$SCRIPT_DIR/search-devlog.sh" >/dev/null 2>&1
|
|
51
|
+
assert_exit "missing keyword -> exit 1" 1 $?
|
|
52
|
+
|
|
53
|
+
# --- .devlog/ exists but has no devlog*.md files yet -> NO_INDEX -----------
|
|
54
|
+
OUT="$(bash "$SCRIPT_DIR/search-devlog.sh" "foo" 2>&1)"
|
|
55
|
+
[ "$OUT" = "NO_INDEX" ] && echo "PASS: empty .devlog/ -> NO_INDEX" || { echo "FAIL: expected NO_INDEX, got: $OUT"; FAIL=1; }
|
|
56
|
+
|
|
57
|
+
# --- Matches across main, archive, kept and lessons files -------------------
|
|
58
|
+
cat > "$DEVLOG_DIR/devlog.md" <<'EOF'
|
|
59
|
+
## Round 1 — 2026-09-08T00:00:00+08:00
|
|
60
|
+
|
|
61
|
+
### Summary
|
|
62
|
+
討論 span mode 的門檻設計。
|
|
63
|
+
|
|
64
|
+
### Status
|
|
65
|
+
DONE
|
|
66
|
+
EOF
|
|
67
|
+
|
|
68
|
+
cat > "$DEVLOG_DIR/devlog.archive.md" <<'EOF'
|
|
69
|
+
## Round 0 — 2026-09-01T00:00:00+08:00
|
|
70
|
+
|
|
71
|
+
### Summary
|
|
72
|
+
舊的 span mode 討論,已封存。
|
|
73
|
+
|
|
74
|
+
### Status
|
|
75
|
+
DONE
|
|
76
|
+
EOF
|
|
77
|
+
|
|
78
|
+
cat > "$DEVLOG_DIR/devlog.keep-plan.md" <<'EOF'
|
|
79
|
+
## Round 5 — 2026-09-05T00:00:00+08:00
|
|
80
|
+
|
|
81
|
+
### Summary
|
|
82
|
+
跟 keep 完全無關的一輪,內容是別的主題。
|
|
83
|
+
|
|
84
|
+
### Status
|
|
85
|
+
DONE
|
|
86
|
+
EOF
|
|
87
|
+
|
|
88
|
+
cat > "$DEVLOG_DIR/devlog.lessons.span-mode.md" <<'EOF'
|
|
89
|
+
## 2026-09-10T00:00:00+08:00
|
|
90
|
+
|
|
91
|
+
Span Mode 的門檻一開始設太低,導致誤判。
|
|
92
|
+
EOF
|
|
93
|
+
|
|
94
|
+
OUT="$(bash "$SCRIPT_DIR/search-devlog.sh" "span mode" 2>&1)"
|
|
95
|
+
RC=$?
|
|
96
|
+
assert_exit "search finds hits -> exit 0" 0 "$RC"
|
|
97
|
+
assert_contains "hit in devlog.md" "FILE=.devlog/devlog.md" "$OUT"
|
|
98
|
+
assert_contains "hit in devlog.archive.md" "FILE=.devlog/devlog.archive.md" "$OUT"
|
|
99
|
+
assert_contains "hit in devlog.lessons.span-mode.md" "FILE=.devlog/devlog.lessons.span-mode.md" "$OUT"
|
|
100
|
+
assert_not_contains "no hit in unrelated kept file" "FILE=.devlog/devlog.keep-plan.md" "$OUT"
|
|
101
|
+
assert_contains "match line reports nearest (###) heading" 'HEADING="### Summary"' "$OUT"
|
|
102
|
+
assert_contains "match line reports the matched text" "討論 span mode 的門檻設計" "$OUT"
|
|
103
|
+
|
|
104
|
+
# --- Heading context falls back to the nearest ## when no ### is closer ----
|
|
105
|
+
cat > "$DEVLOG_DIR/devlog.no-sub.md" <<'EOF'
|
|
106
|
+
## Round 9 — 2026-09-12T00:00:00+08:00
|
|
107
|
+
span mode 直接寫在 Round 標題底下,沒有任何 ### 子標題。
|
|
108
|
+
EOF
|
|
109
|
+
OUT_NOSUB="$(bash "$SCRIPT_DIR/search-devlog.sh" "span mode" 2>&1)"
|
|
110
|
+
assert_contains "falls back to nearest ## heading" 'HEADING="## Round 9' "$OUT_NOSUB"
|
|
111
|
+
|
|
112
|
+
# --- Case-insensitive match --------------------------------------------------
|
|
113
|
+
OUT_UPPER="$(bash "$SCRIPT_DIR/search-devlog.sh" "SPAN MODE" 2>&1)"
|
|
114
|
+
assert_contains "case-insensitive match" "FILE=.devlog/devlog.md" "$OUT_UPPER"
|
|
115
|
+
|
|
116
|
+
# --- No hits anywhere -> NO_MATCH -------------------------------------------
|
|
117
|
+
OUT_NONE="$(bash "$SCRIPT_DIR/search-devlog.sh" "找不到的關鍵字xyz" 2>&1)"
|
|
118
|
+
[ "$OUT_NONE" = "NO_MATCH" ] && echo "PASS: no hits -> NO_MATCH" || { echo "FAIL: expected NO_MATCH, got: $OUT_NONE"; FAIL=1; }
|
|
119
|
+
|
|
120
|
+
if [ "$FAIL" -eq 0 ]; then
|
|
121
|
+
echo "All checks passed."
|
|
122
|
+
exit 0
|
|
123
|
+
else
|
|
124
|
+
echo "Some checks FAILED."
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
@@ -499,6 +499,65 @@ else
|
|
|
499
499
|
FAIL=1
|
|
500
500
|
fi
|
|
501
501
|
|
|
502
|
+
# --- handoff.md present: printed before excerpt header --------------------
|
|
503
|
+
rm -f "$DEVLOG_DIR/devlog.md" "$DEVLOG_DIR/handoff.md" "$DEVLOG_DIR/.span-open"
|
|
504
|
+
cat > "$DEVLOG_DIR/devlog.md" <<'EOF'
|
|
505
|
+
## Round 1 — 2026-09-22T00:00:00+08:00
|
|
506
|
+
|
|
507
|
+
### Summary
|
|
508
|
+
summary 1
|
|
509
|
+
|
|
510
|
+
### Handoff
|
|
511
|
+
#### 現況
|
|
512
|
+
handoff 1
|
|
513
|
+
|
|
514
|
+
### Status
|
|
515
|
+
DONE
|
|
516
|
+
EOF
|
|
517
|
+
cat > "$DEVLOG_DIR/handoff.md" <<'EOF'
|
|
518
|
+
## Session Handoff
|
|
519
|
+
|
|
520
|
+
### 決策
|
|
521
|
+
- keep route A
|
|
522
|
+
|
|
523
|
+
### 待解問題
|
|
524
|
+
- open Q
|
|
525
|
+
|
|
526
|
+
### 失敗嘗試
|
|
527
|
+
- (無)
|
|
528
|
+
EOF
|
|
529
|
+
OUTPUT="$(echo '{"source":"startup"}' | bash "$SCRIPT_DIR/session-start-devlog.sh" 2>&1)"
|
|
530
|
+
assert_contains "handoff header present" "Session Handoff" "$OUTPUT"
|
|
531
|
+
assert_contains "handoff body present" "open Q" "$OUTPUT"
|
|
532
|
+
assert_contains "excerpt still present" "接手摘要" "$OUTPUT"
|
|
533
|
+
HOFF_POS="$(printf '%s\n' "$OUTPUT" | grep -n 'open Q' | head -1 | cut -d: -f1)"
|
|
534
|
+
EX_POS="$(printf '%s\n' "$OUTPUT" | grep -n '接手摘要' | head -1 | cut -d: -f1)"
|
|
535
|
+
if [ -n "$HOFF_POS" ] && [ -n "$EX_POS" ] && [ "$HOFF_POS" -lt "$EX_POS" ]; then
|
|
536
|
+
echo "PASS: handoff prints before devlog excerpt"
|
|
537
|
+
else
|
|
538
|
+
echo "FAIL: handoff should precede excerpt (hoff=$HOFF_POS ex=$EX_POS)"
|
|
539
|
+
FAIL=1
|
|
540
|
+
fi
|
|
541
|
+
|
|
542
|
+
# --- no handoff.md: excerpt only -----------------------------------------
|
|
543
|
+
rm -f "$DEVLOG_DIR/handoff.md"
|
|
544
|
+
OUTPUT="$(echo '{"source":"startup"}' | bash "$SCRIPT_DIR/session-start-devlog.sh" 2>&1)"
|
|
545
|
+
assert_not_contains "no handoff file -> no open Q" "open Q" "$OUTPUT"
|
|
546
|
+
assert_contains "excerpt still works" "接手摘要" "$OUTPUT"
|
|
547
|
+
|
|
548
|
+
# --- clear: still silent even with handoff.md ----------------------------
|
|
549
|
+
cat > "$DEVLOG_DIR/handoff.md" <<'EOF'
|
|
550
|
+
## Session Handoff
|
|
551
|
+
### 決策
|
|
552
|
+
- should not inject
|
|
553
|
+
EOF
|
|
554
|
+
OUTPUT="$(echo '{"source":"clear"}' | bash "$SCRIPT_DIR/session-start-devlog.sh" 2>&1)"
|
|
555
|
+
if [ -z "$OUTPUT" ]; then
|
|
556
|
+
echo "PASS: clear stays silent with handoff.md present"
|
|
557
|
+
else
|
|
558
|
+
echo "FAIL: clear should be silent, got: $OUTPUT"; FAIL=1
|
|
559
|
+
fi
|
|
560
|
+
|
|
502
561
|
if [ "$FAIL" -eq 0 ]; then
|
|
503
562
|
echo "All checks passed."
|
|
504
563
|
exit 0
|
|
@@ -30,10 +30,10 @@ OUT="$(bash "$SCRIPT_DIR/status-devlog.sh")"
|
|
|
30
30
|
case "$OUT" in *"LESSONS=yes"*) pass "lessons on when flag present" ;; *) fail "lessons on when flag present [$OUT]" ;; esac
|
|
31
31
|
rm -f "$TMP/.devlog/.lessons-enabled"
|
|
32
32
|
|
|
33
|
-
printf '%s\n' '{"
|
|
33
|
+
printf '%s\n' '{"count": 1, "threshold": 3}' > "$TMP/.devlog/.lessons-advisory-state"
|
|
34
34
|
OUT="$(bash "$SCRIPT_DIR/status-devlog.sh")"
|
|
35
|
-
case "$OUT" in *"
|
|
36
|
-
rm -f "$TMP/.devlog/.lessons-
|
|
35
|
+
case "$OUT" in *"LESSONS_ADVISORY=1/3"*) pass "lessons advisory status line" ;; *) fail "lessons advisory status line [$OUT]" ;; esac
|
|
36
|
+
rm -f "$TMP/.devlog/.lessons-advisory-state"
|
|
37
37
|
|
|
38
38
|
OUT="$(bash "$SCRIPT_DIR/span-open.sh")"
|
|
39
39
|
[ "$OUT" = "OPENED=1" ] && pass "span opened" || fail "span open [$OUT]"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devlog-tracker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "npx installer for devlog-tracker's Claude Code, Cursor and Codex adapters.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"devlog-tracker": "bin/devlog-tracker.js"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"test": "node --test cli/*.test.js scripts/*.test.js",
|
|
25
|
-
"version": "node scripts/sync-version.js && git add .claude-plugin/plugin.json .claude-plugin/marketplace.json README.md"
|
|
25
|
+
"version": "node scripts/sync-version.js && git add .claude-plugin/plugin.json .claude-plugin/marketplace.json README.md README.zh-TW.md"
|
|
26
26
|
},
|
|
27
27
|
"license": "Apache-2.0",
|
|
28
28
|
"author": {
|
|
@@ -8,6 +8,21 @@ description: 在專案的 .devlog/devlog.md 維護逐輪對話紀錄。使用者
|
|
|
8
8
|
參考 agfnow/agentflow 的 devlog 基礎協定做的簡化版,只保留「逐輪對話紀錄」這一層,
|
|
9
9
|
不含原版的 10 步驟 SDD pipeline、多模型對抗審查、external worker 外包等進階機制。
|
|
10
10
|
|
|
11
|
+
## Contract
|
|
12
|
+
|
|
13
|
+
每輪收尾/接手前先對齊這七項;細節與例外見下方章節與
|
|
14
|
+
`references/contract.md`(審核用展開,不取代本節)。
|
|
15
|
+
|
|
16
|
+
| 維度 | 契約(短) |
|
|
17
|
+
|---|---|
|
|
18
|
+
| **Requirements** | 強制記錄需 `.devlog/.enabled`(`/devlog-tracker:start`)。`/clear` 後不自動接續;要開工用 `/devlog-tracker:continue`(或明確說接續)。Cursor/Codex 對照 `.devlog-tracker/commands/*.md`。 |
|
|
19
|
+
| **Output** | 編輯開著的 Round(`.round-current.md`):必有 `### Summary`/`### Reply`/`### Handoff`/`### Status`;Handoff 小節順序固定。格式見「每一輪的紀錄格式」。 |
|
|
20
|
+
| **Invariants** | L1 寫回義務;聊天不旁白記錄動作;不改 User Input(除非 hook `(無 prompt)`);不為同一則訊息再 append `## Round`;設計真相在 `docs/design/*.md`,不是 lessons。 |
|
|
21
|
+
| **Validation** | Soft:收尾前自檢欄位與工作區。Hard:Stop/PreToolUse/workspace/files snapshot(見「每一輪的紀錄格式」末段與 hook 腳本)。fail-open/loop guard 見下方開關一節。 |
|
|
22
|
+
| **Transformation** | 單次動作走對應 `commands/*.md`(start/continue/compact/keep/…);本檔管協定與跨指令不變式,不重抄步驟。 |
|
|
23
|
+
| **Knowledge** | 檔案位置、分支主檔、mode 邊界見下方與 `references/*`;更深設計見 `docs/design/*`。 |
|
|
24
|
+
| **Observation** | 收尾/接手前看:開著的 Round、live git(`workspace-snapshot.sh`)、Handoff「完成條件」/「下一步」、是否該寫 `### 段落`(瑣碎度表、Segment Watch)。 |
|
|
25
|
+
|
|
11
26
|
## 核心原則
|
|
12
27
|
|
|
13
28
|
devlog.md 是**跨 session 交接連續性**(決策軌跡、目前卡點、下一步、完成條件)的 single source of truth,
|
|
@@ -60,6 +75,9 @@ Summary/Handoff」——後面這句要整句刪掉,不是縮短。
|
|
|
60
75
|
- 具名保存:`.devlog/devlog.<name>.md`(`/devlog-tracker:keep` 搬走的主題檔;SessionStart 不讀這些檔)
|
|
61
76
|
- 當輪暫存:`.devlog/.round-current.md`(目前開著的那一輪,Claude 該讀寫的是這個檔,不是 `devlog.md`;
|
|
62
77
|
收尾或中斷時由 hook 自動合併回 `devlog.md` 並清空,設計見 `docs/design/round-current-split.md`)
|
|
78
|
+
- Session Handoff 快照:`.devlog/handoff.md`(`main`/`master`);其他分支 `.devlog/handoff.<branch>.md`。
|
|
79
|
+
由 Stop 在 `IN_PROGRESS`/`BLOCKED` 收尾時覆寫、`DONE` 時刪除;Claude 只寫 Round 內的
|
|
80
|
+
`### Session Handoff`,不要直接編這個檔。設計見 `docs/design/session-handoff-file.md`。
|
|
63
81
|
- 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
82
|
|
|
65
83
|
第一次使用時,若 `.devlog/` 不存在就建立它。
|
|
@@ -136,9 +154,10 @@ matcher 設為 `startup|resume|clear|compact|fork`。**開新 session、resume
|
|
|
136
154
|
|
|
137
155
|
自動注入時:
|
|
138
156
|
|
|
139
|
-
1.
|
|
140
|
-
2.
|
|
141
|
-
3. Claude
|
|
157
|
+
1. 若目前分支的 `.devlog/handoff.md`(或 `handoff.<branch>.md`)非空,先注入這份 Session Handoff 快照
|
|
158
|
+
2. 再讀取 `.devlog/devlog.md`,注入最後一個 `## Checkpoint`(若有)、最後一個 `## Kept 索引`(若有;不是具名檔內容)、最後一個 `## Lessons 索引`(若有),加上最近 2 輪的 Summary / Handoff / Status(沒有 Summary 的 skeleton 才帶 User Input)
|
|
159
|
+
3. 印到 stdout,Claude Code 會把這段文字當成這次 session 的 additionalContext 自動注入
|
|
160
|
+
4. Claude 收到這段 context 後,開場就已經知道目前進度
|
|
142
161
|
|
|
143
162
|
`/clear` 時 hook 仍可能把殘留的開著 Round 標成 `INTERRUPTED`,但 stdout 什麼都不印。
|
|
144
163
|
之後只有使用者下 `/devlog-tracker:continue`,或明確說「continue」「接續」「繼續上一題」時,
|
|
@@ -210,6 +229,16 @@ BLOCKED 時寫清楚缺什麼、出現長怎樣(可觀察條件)>
|
|
|
210
229
|
<下一輪第一件具體要做的事(路徑、指令、要載入的 skill)。
|
|
211
230
|
IN_PROGRESS/BLOCKED 必寫;DONE 且沒有後續就整節省略>
|
|
212
231
|
|
|
232
|
+
### Session Handoff
|
|
233
|
+
#### 決策
|
|
234
|
+
- <仍影響後續方向的選擇;沒有就 `- (無)`>
|
|
235
|
+
|
|
236
|
+
#### 待解問題
|
|
237
|
+
- <下一 session 最該先看的卡點;沒有就 `- (無)`>
|
|
238
|
+
|
|
239
|
+
#### 失敗嘗試
|
|
240
|
+
- <試過但放棄/不可行的做法;沒有就 `- (無)`>
|
|
241
|
+
|
|
213
242
|
### Status
|
|
214
243
|
DONE | IN_PROGRESS | BLOCKED | INTERRUPTED
|
|
215
244
|
```
|
|
@@ -223,6 +252,10 @@ Round 編號:讀取檔案中最後一個 `## Round <N>`,本輪用 N+1;檔
|
|
|
223
252
|
(用詞、並列條件、例外)必須留在檔裡。超長內容由 hook 截斷並標明;不要在收尾時再手動縮成更短的改寫版。
|
|
224
253
|
- **三個讀者拆開:** `Summary` 只給人掃;`Reply` 只記對使用者說過/答應過的話;`Handoff` 只給下一輪
|
|
225
254
|
Claude 接手。同一件事不要三邊複述。
|
|
255
|
+
- **`### Session Handoff`(跨 session 精簡快照):** 與 Checkpoint 同款三欄(決策/待解問題/失敗嘗試),
|
|
256
|
+
不是 `### Handoff` 六小節的複本。`IN_PROGRESS`/`BLOCKED` 必寫(可 `- (無)`);`DONE` 不要求;
|
|
257
|
+
`INTERRUPTED` stub 不寫。Stop 通過後會把內容覆寫到 `.devlog/handoff.md`(分支檔同規則);
|
|
258
|
+
`DONE` 會刪掉該檔——不要把長期軌跡只寫在 handoff 檔裡。細節見 `docs/design/session-handoff-file.md`。
|
|
226
259
|
- Handoff 小節順序固定(決策 → 檔案 → 工作區 → 現況 → 完成條件 → 下一步),Stop hook 會檢查已出現的小節
|
|
227
260
|
順序有沒有錯、有沒有重複(不檢查內容對不對)。沒發生的整節省略,不要寫「無」。
|
|
228
261
|
`現況` 幾乎每輪都該有。`工作區`、`完成條件` 與 `下一步` 在 `IN_PROGRESS`/`BLOCKED` 必寫;`DONE` 且沒有後續就整節省略——
|
|
@@ -261,6 +294,10 @@ Round 編號:讀取檔案中最後一個 `## Round <N>`,本輪用 N+1;檔
|
|
|
261
294
|
會在下面多印一行 `[reason: ...]`(例如 `[reason: dangling:next_prompt]`),這是 hook 自己的
|
|
262
295
|
除錯代號、用方括號標記成內部 metadata,特意不用 HTML 註解(會被 Markdown 渲染器整段隱藏,
|
|
263
296
|
之後要 debug 反而看不到),不算違反「只寫一個值」——看到這行不用當成錯誤,Claude 也不用去動它。
|
|
297
|
+
- 若 Lessons Mode 開著(`.lessons-enabled` 存在):寫這個 Status 前,想一下這輪算不算「從
|
|
298
|
+
`BLOCKED` 解開」或「明顯繞了一圈才找到對的做法」——符合任一種就考慮用 `lessons-append.sh`
|
|
299
|
+
記一筆,非強制。前者下一輪開始時 hook 也會機械印一句提示(見下面「Lessons Mode」一節),
|
|
300
|
+
後者完全仰賴這裡的自我檢查,hook 判斷不到。
|
|
264
301
|
- `INTERRUPTED` 只由 hook 在意外中斷時寫上(非 usage 的 API 錯誤、SessionEnd、
|
|
265
302
|
下次 SessionStart(startup / resume / clear / fork)或下一則訊息發現 `.round-open` 還在)。
|
|
266
303
|
mid-turn 取消(例如 Esc)通常也是走這條延後路徑;`PostToolUseFailure` 的 `is_interrupt`
|
|
@@ -271,9 +308,21 @@ Round 編號:讀取檔案中最後一個 `## Round <N>`,本輪用 N+1;檔
|
|
|
271
308
|
當接續動作**必須**重新載入某個特定 skill 才能正確接手時,才把 skill 名稱寫進 Handoff
|
|
272
309
|
「下一步」裡。
|
|
273
310
|
|
|
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
|
|
311
|
+
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」);`IN_PROGRESS`/`BLOCKED` 還必須有完整的 `### Session Handoff`(決策/待解問題/失敗嘗試),通過後覆寫分支對應的 `handoff.md`,`DONE` 則刪除該檔。
|
|
275
312
|
新開的 Round 三個標題(Summary/Reply/Handoff)都要有,瑣碎輪也不例外。
|
|
276
313
|
|
|
314
|
+
### devlog-tracker 自己的管理指令不記錄
|
|
315
|
+
|
|
316
|
+
這一輪如果是使用者直接呼叫 devlog-tracker 自己的純管理指令——`/devlog-tracker:checkpoint`、
|
|
317
|
+
`clean`、`compact`、`keep`、`lessons`、`lessons-drift`、`lessons-off`、`lessons-on`、
|
|
318
|
+
`overview`、`pause`、`search`、`segment-watch`、`span`、`start`、`status`——`round-start.sh`
|
|
319
|
+
會整輪直接放行,不開 Round、不動任何計數器,等於這個 tick 沒發生過;不用、也不會被
|
|
320
|
+
Stop hook 要求補寫 Summary/Reply/Handoff。這些指令本身就是在操作 devlog 系統,不是開發
|
|
321
|
+
工作,記錄下來對接續開發沒有幫助。
|
|
322
|
+
|
|
323
|
+
`/devlog-tracker:continue` 與 `/devlog-tracker:resume` **不在此列**:這兩個指令執行完會接著
|
|
324
|
+
做實際開發工作(可能在同一輪裡做很多事),仍照正常規則強制記錄。
|
|
325
|
+
|
|
277
326
|
### 怎麼判斷這輪該寫多細(瑣碎程度)
|
|
278
327
|
|
|
279
328
|
「每輪都要記錄」管的是**要不要留下這一輪的痕跡**,瑣碎程度管的是**該寫多細**,這是兩件
|
|
@@ -351,9 +400,10 @@ JSON 格式、開關步驟、已知限制(分辨不出自動續接 vs 真人
|
|
|
351
400
|
(可用 `/devlog-tracker:checkpoint <輪數>` 調整)沒寫 `## Checkpoint`,Stop
|
|
352
401
|
hook 會要求補一段。
|
|
353
402
|
|
|
354
|
-
|
|
403
|
+
運作機制、`/devlog-tracker:pause` 之後的行為,見
|
|
355
404
|
`${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/checkpoint-mode.md`
|
|
356
|
-
(設計動機見 `docs/design/checkpoint-mode.md
|
|
405
|
+
(設計動機見 `docs/design/checkpoint-mode.md`)。補寫時用固定三段:
|
|
406
|
+
`### 決策`/`### 待解問題`/`### 失敗嘗試`(格式與填寫規則見該 reference)。
|
|
357
407
|
|
|
358
408
|
## 壓縮歸檔:`/devlog-tracker:compact`
|
|
359
409
|
|
|
@@ -392,17 +442,37 @@ Handoff。核對用 `commands/continue.md` 步驟 5.1–5.2(不要跟著做 5.
|
|
|
392
442
|
格式貼近 `CLAUDE.md` 條列寫法方便複製)。不寫入任何檔案,包含 `CLAUDE.md` 本身。步驟見
|
|
393
443
|
`commands/overview.md`。
|
|
394
444
|
|
|
445
|
+
## 跨檔搜尋:`/devlog-tracker:search <關鍵字>`
|
|
446
|
+
|
|
447
|
+
純讀取,不核對工作區、不等確認(跟 overview/lessons 一樣的唯讀風格)。用
|
|
448
|
+
`core/scripts/search-devlog.sh` 掃過 `.devlog/devlog*.md`(主檔、archive、keep、lessons、
|
|
449
|
+
分支檔一個 glob 涵蓋),做不分大小寫的固定字串比對,回報命中檔、最近 `##`/`###` 標題與
|
|
450
|
+
行內容。自然語言查詢由 Claude 先抽出關鍵片語再丟給腳本;不另建 index、不做 embedding。
|
|
451
|
+
讀完命中後**用自己的話**回答使用者在問什麼,必要時附檔名/標題/行號當出處——不要把腳本
|
|
452
|
+
原始輸出整段貼當主回答。不寫入任何檔案。步驟見 `commands/search.md`。
|
|
453
|
+
|
|
395
454
|
## Lessons Mode:開發歷程教訓(預設關閉,非架構知識庫)
|
|
396
455
|
|
|
397
456
|
跟 Checkpoint/Span 不同,管的是「開發**過程**踩過的坑」,不是進度或架構——架構
|
|
398
457
|
決策的 SSOT 永遠是 `docs/design/*.md`。預設關閉,隸屬主開關(沒下過
|
|
399
|
-
`/devlog-tracker:start`
|
|
400
|
-
從 `BLOCKED`
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
458
|
+
`/devlog-tracker:start` 會被拒絕)。開著時有兩種自我判斷訊號考慮記一筆:這輪
|
|
459
|
+
`Status` 從 `BLOCKED` 解開、你自行判斷這輪明顯繞了一圈——這兩種完全仰賴你自己
|
|
460
|
+
想起來,hook 不強制、不追蹤。另外有兩種機制性訊號,由 hook 累積計數、達門檻只印
|
|
461
|
+
一句顧問式建議(預設 3 次,`/devlog-tracker:lessons-drift <次數>` 可調,兩種共用
|
|
462
|
+
同一個門檻):工作區漂移(宣稱跟實際不符)累積達門檻、或 Status 是 `BLOCKED` 的
|
|
463
|
+
輪次累積達門檻;另外「上一輪從 `BLOCKED` 解開」這個轉變,下一輪開始時 hook 也會
|
|
464
|
+
機械印一句提示(不經過門檻計數,偵測到就印)。以上全部都完全不 hook 強制寫入
|
|
465
|
+
本身——寫不寫都不影響這一輪能不能收尾。
|
|
466
|
+
|
|
467
|
+
若這輪任務是透過 Agent 工具派 sub agent,或用 Workflow 工具跑多階段 pipeline,一樣可能
|
|
468
|
+
踩到值得記的坑,只是沒有 Round/Status 可比對訊號;讀完 sub agent/workflow 的最終回報後
|
|
469
|
+
自我判斷(例如 verify 推翻了它先前的 fix、它自陳繞了一圈、多個 agent 重複卡在同一種問題、
|
|
470
|
+
或成果被打回票要求重做),值得的話一樣呼叫 `lessons-append.sh`。Claude Code 上 hook 會自動
|
|
471
|
+
觸發:sub agent/Workflow agent 開始時被注入 `lessons-append.sh` 的絕對路徑用法、可以自己記;
|
|
472
|
+
它回來或背景任務通知到達時,你會看到一句 `[Lessons Mode 提示]`(`failed`/`killed` 另算進
|
|
473
|
+
共用計數器)。sub agent 已記過的不用重複記。
|
|
474
|
+
|
|
475
|
+
寫法、per-topic 存檔規則、索引重建、機制性訊號細節,見
|
|
406
476
|
`${CLAUDE_PLUGIN_ROOT}/skills/devlog-tracker/references/lessons-mode.md`(完整
|
|
407
477
|
設計見 `docs/design/lessons-mode.md`)。
|
|
408
478
|
|
|
@@ -19,16 +19,31 @@
|
|
|
19
19
|
|
|
20
20
|
## 被要求補寫的時候該怎麼寫
|
|
21
21
|
|
|
22
|
-
在 `devlog.md`
|
|
22
|
+
在 `devlog.md` 尾端追加(固定標題與三段結構,不要改成自由段落):
|
|
23
23
|
|
|
24
24
|
```markdown
|
|
25
|
-
## Checkpoint(Round <X>-<Y
|
|
26
|
-
|
|
25
|
+
## Checkpoint(Round <X>-<Y>)
|
|
26
|
+
|
|
27
|
+
### 決策
|
|
28
|
+
- <這段期間定案、會影響後續方向的選擇;沒有就寫 `- (無)`>
|
|
29
|
+
|
|
30
|
+
### 待解問題
|
|
31
|
+
- <仍懸而未決、下一 session 最該先看的卡點;沒有就寫 `- (無)`>
|
|
32
|
+
|
|
33
|
+
### 失敗嘗試
|
|
34
|
+
- <試過但放棄或證明不可行的做法,避免下一任重踩;沒有就寫 `- (無)`>
|
|
27
35
|
```
|
|
28
36
|
|
|
29
|
-
`X`-`Y` 是這段還沒被摘要過的 Round
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
`X`-`Y` 是這段還沒被摘要過的 Round 範圍。各段用條列、一句一點,從各輪 Summary/Handoff
|
|
38
|
+
抽重點即可,不用逐輪複述,也不要把每輪 Handoff 整段貼上——細節仍留在 Round 區塊裡。
|
|
39
|
+
**「待解問題」是給 SessionStart 注入與接手的首要線索**,寧可少寫決策、也不要漏掉仍卡住的問題。
|
|
40
|
+
寫完之後這一輪就會正常結束,不用再做任何事。
|
|
41
|
+
|
|
42
|
+
這三欄與 `.devlog/handoff.md` 的 Session Handoff 快照相同(見
|
|
43
|
+
`docs/design/session-handoff-file.md`):Checkpoint 是寫進 `devlog.md` 的
|
|
44
|
+
耐久路標;Session Handoff 是 Stop 覆寫、`DONE` 就刪的揮發快照。
|
|
45
|
+
|
|
46
|
+
主動寫 checkpoint(還沒被 Stop 擋、但覺得該補路標)時用同一套格式。
|
|
32
47
|
|
|
33
48
|
## 調整門檻
|
|
34
49
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Contract checklist(審核/改版用)
|
|
2
|
+
|
|
3
|
+
本檔展開 `SKILL.md` 頂部的 **Contract** 七維。runtime 以 `SKILL.md` 為準;
|
|
4
|
+
這裡只做「條目 ↔ 權威段落/腳本」對照,方便審核與改版,避免在多處重抄規則。
|
|
5
|
+
|
|
6
|
+
改行為時:先改權威段落或腳本,再確認本表 pointer 仍對;不要只改本檔。
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
| 條件 | 權威位置 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| 強制記錄開關 `.enabled`;未 start 不動作 | `SKILL.md`「用 `/devlog-tracker:start`…」;`commands/start.md`/`pause.md` |
|
|
13
|
+
| `/clear` 不注入、不自動接續 | `SKILL.md`「自動接續與 `/clear`」;`commands/continue.md` |
|
|
14
|
+
| continue/明確接續才開工;start 只對進度 | `commands/continue.md`;`SKILL.md`「接續:…」 |
|
|
15
|
+
| Cursor/Codex 無 slash → `commands/*.md` | `SKILL.md`「檔案位置」 |
|
|
16
|
+
|
|
17
|
+
## Output contracts
|
|
18
|
+
|
|
19
|
+
| 產出 | 權威位置 |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Round 骨架:User Input + Summary + Reply + Handoff + Status | `SKILL.md`「每一輪的紀錄格式」 |
|
|
22
|
+
| Handoff 小節順序與可省略規則 | 同上(寫入原則) |
|
|
23
|
+
| `#### 工作區` 七種格式 | 同上;生產者 `core/scripts/workspace-snapshot.sh` |
|
|
24
|
+
| `#### 檔案` machine-verify 區塊 | 同上;`docs/design/files-verify.md`;`core/scripts/files-snapshot.sh` |
|
|
25
|
+
| Checkpoint 三段 | `references/checkpoint-mode.md` |
|
|
26
|
+
| Session Handoff 三段(揮發快照) | `docs/design/session-handoff-file.md`;`SKILL.md` 格式節 |
|
|
27
|
+
| `### 段落` 格式 | `references/round-segments.md`;Reply Fold 見 `references/reply-fold.md` |
|
|
28
|
+
|
|
29
|
+
## Invariants
|
|
30
|
+
|
|
31
|
+
| 不變式 | 權威位置 |
|
|
32
|
+
|---|---|
|
|
33
|
+
| L1:接手必須同輪寫回 | `SKILL.md`「L1 寫回義務」;`commands/continue.md` 步驟 6 |
|
|
34
|
+
| 聊天不旁白記錄動作/不提 Round 欄位名 | `SKILL.md`「寫進 devlog 不等於講給使用者聽」 |
|
|
35
|
+
| 不改 User Input(除 hook 占位) | `SKILL.md` 寫入原則 |
|
|
36
|
+
| 同一則使用者訊息不另開 `## Round` | `SKILL.md` 強制流程步驟 2 |
|
|
37
|
+
| 編輯對象是 `.round-current.md`(開著時) | `SKILL.md`「檔案位置」;`docs/design/round-current-split.md` |
|
|
38
|
+
| Lessons ≠ 架構知識庫;設計在 `docs/design/` | `SKILL.md`「Lessons Mode」;`references/lessons-mode.md` |
|
|
39
|
+
| `INTERRUPTED` 只由 hook 寫 | `SKILL.md` Status 規則 |
|
|
40
|
+
|
|
41
|
+
## Validation
|
|
42
|
+
|
|
43
|
+
| 層級 | 誰執行 | 權威位置 |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Soft(agent 自檢) | 收尾前對照格式/完成條件/下一步 | `SKILL.md` 寫入原則與瑣碎度表 |
|
|
46
|
+
| Hard:缺 Summary/Reply/Handoff/非法 Status | Stop `enforce-devlog.sh` | `SKILL.md` 格式節末段 |
|
|
47
|
+
| Hard:工作區快照不符 | Stop + `workspace-snapshot.sh` | 同上;ssot Phase 1 |
|
|
48
|
+
| Hard:檔案區塊不符 | Stop + `files-snapshot.sh` | `docs/design/files-verify.md` |
|
|
49
|
+
| Hard:Session Handoff(IN_PROGRESS/BLOCKED) | Stop + `handoff-file.sh` | `docs/design/session-handoff-file.md`;`SKILL.md` 格式節 |
|
|
50
|
+
| Hard:上一輪工作區漂移擋工具 | PreToolUse(continue 同 session) | `SKILL.md`「接續」;`commands/continue.md` |
|
|
51
|
+
| Hard:Segment Watch 逾時先補段落 | PreToolUse | `references/round-segments.md` |
|
|
52
|
+
| Soft:Checkpoint/Lessons 建議 | hook 提示,不強制寫入本身 | `references/checkpoint-mode.md`/`lessons-mode.md` |
|
|
53
|
+
| fail-open/loop guard | hook 穩健性 | `SKILL.md`「兩個穩健性設計」 |
|
|
54
|
+
|
|
55
|
+
## Transformation
|
|
56
|
+
|
|
57
|
+
| 意圖 | 步驟檔 |
|
|
58
|
+
|---|---|
|
|
59
|
+
| 開強制記錄 | `commands/start.md` |
|
|
60
|
+
| 接續上一題 | `commands/continue.md` |
|
|
61
|
+
| 暫停/狀態/壓縮/清空 | `commands/pause.md`/`status.md`/`compact.md`/`clean.md` |
|
|
62
|
+
| 具名保存/接續/總覽 | `commands/keep.md`/`resume.md`/`overview.md` |
|
|
63
|
+
| Span/Checkpoint/Segment/Lessons | `commands/span.md`/`checkpoint.md`/`segment-watch.md`/`lessons*.md` |
|
|
64
|
+
| 協定與跨指令行為 | `SKILL.md`(本層不重抄步驟) |
|
|
65
|
+
|
|
66
|
+
## Knowledge
|
|
67
|
+
|
|
68
|
+
| 主題 | 權威位置 |
|
|
69
|
+
|---|---|
|
|
70
|
+
| 主檔/分支檔/歸檔/keep/round-current/handoff | `SKILL.md`「檔案位置」;`docs/design/branch-scoped-devlog.md`;`docs/design/session-handoff-file.md` |
|
|
71
|
+
| 錄製時機與截斷 | `docs/design/recording-moments.md` |
|
|
72
|
+
| Span/Checkpoint/Lessons/Reply Fold/Segments | 各 `references/*.md` + 對應 `docs/design/*` |
|
|
73
|
+
| 下一步黑名單 | `docs/design/next-step-blacklist.md` |
|
|
74
|
+
|
|
75
|
+
## Observation
|
|
76
|
+
|
|
77
|
+
| 時機 | 該看什麼 | 權威位置 |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| 收尾前 | live git → 寫/核對「工作區」;完成條件能否 DONE | `SKILL.md` 工作區/完成條件;`workspace-snapshot.sh` |
|
|
80
|
+
| 接手(continue/resume/注入後開工) | 歷史 Round Status、「工作區」vs 實際樹、「下一步」 | `commands/continue.md` 步驟 5;`resume.md` |
|
|
81
|
+
| 長輪中途 | 是否有意義階段結果 → `### 段落` | `references/round-segments.md`;瑣碎度表 |
|
|
82
|
+
| BLOCKED | 缺件是否已出現(可觀察條件,不是 git 相符) | `SKILL.md`/`commands/continue.md` |
|
|
83
|
+
| 使用者只問進度 | 讀檔回答;仍可寫回但不旁白 | `SKILL.md` 旁白例外 |
|
|
@@ -8,14 +8,18 @@
|
|
|
8
8
|
因為沒有 Round/Status 歷史可判斷「BLOCKED→解開」這個訊號。`/devlog-tracker:lessons-off` 只刪
|
|
9
9
|
`.lessons-enabled`,不動任何已寫的 `devlog.lessons.*.md` 或索引。
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
**兩種自我判斷訊號**(hook 判斷不到,完全仰賴你自己在 Round 收尾前想起來):這一輪的
|
|
12
|
+
`### Status` 從 `BLOCKED` 變成別的值,或你自行判斷這輪明顯繞了一圈才找到對的做法。
|
|
13
|
+
|
|
14
|
+
**兩種機制性訊號**(`round-start.sh` 在下一輪開始時累積計數,`.devlog/.lessons-advisory-state`
|
|
15
|
+
的 `count`/`threshold`,預設門檻 3、`/devlog-tracker:lessons-drift <次數>` 可調,兩種共用同一個
|
|
16
|
+
計數器/門檻,達門檻印一句 `[Lessons Mode 提示]` 後歸零):工作區漂移(宣稱跟實際不符)累積
|
|
17
|
+
出現,或上一輪 `### Status` 是 `BLOCKED` 累積出現。另外「上一輪從 `BLOCKED` 解開」這個轉變,
|
|
18
|
+
下一輪開始時 hook 會**額外**機械印一句提示——這個不經過門檻計數,偵測到就印一次(因為它本身
|
|
19
|
+
就是一次性事件,不是可以累積的次數)。
|
|
20
|
+
|
|
21
|
+
以上四種**完全不 hook 強制寫入本身**——寫不寫都不影響這一輪能不能收尾,跟「`#### 決策`
|
|
22
|
+
沒有就整節省略」同一種精神,不要自己加壓力覺得每輪都要交一份。
|
|
19
23
|
|
|
20
24
|
**寫法**:跑(`PLUGIN_ROOT` 同其他指令):
|
|
21
25
|
|
|
@@ -30,3 +34,29 @@ DEVLOG_PROJECT_DIR="$(pwd)" bash "${PLUGIN_ROOT}/core/scripts/lessons-append.sh"
|
|
|
30
34
|
`## Lessons 索引`(每個主題檔一行:則數、最新一則的標題、更新時間),SessionStart 只注入這個
|
|
31
35
|
索引,不會注入任何 `devlog.lessons.*.md` 的全文。要看全文用 `/devlog-tracker:lessons [<topic>]`
|
|
32
36
|
(沒給 topic 就只印索引)——這是純讀取,不像 `resume` 會核對工作區或等使用者確認才動手。
|
|
37
|
+
|
|
38
|
+
腳本輸出除了 `PATH=...` 之外,可能多印兩種提示,都是純資訊性、不阻擋:
|
|
39
|
+
- 同一主題累積滿 3 則的倍數時,印一句建議升級成 `docs/design/*.md` 正式決策;
|
|
40
|
+
- 建立**全新**主題檔時(這個 topic 之前不存在),若已有其他主題檔,印一行既有主題清單
|
|
41
|
+
(`NEW_TOPIC。既有主題:...`)——如果內容其實屬於某個既有主題,改用該名稱重跑,避免
|
|
42
|
+
同一件事分裂成兩個檔案。
|
|
43
|
+
|
|
44
|
+
## sub agent/workflow 情境
|
|
45
|
+
|
|
46
|
+
上面兩種自我判斷訊號預設你在跑 Round。改由 Agent 工具的 sub agent 或 Workflow 工具執行時,
|
|
47
|
+
沒有 Round/Status 可比,但一樣可能踩坑,判斷方式類比如下(一樣完全自我判斷,非強制):
|
|
48
|
+
verify 階段推翻了 sub agent 先前的 fix/claim、sub agent 自陳繞了一圈、同一個 workflow
|
|
49
|
+
裡多個 agent 各自卡在類似問題(彙整成一筆更有代表性的)、sub agent 的成果被使用者或
|
|
50
|
+
reviewer 打回票要求重做。
|
|
51
|
+
|
|
52
|
+
Claude Code 上 hook 會自動觸發(只在 Lessons Mode 開著時):
|
|
53
|
+
- sub agent/Workflow agent 開始時(`SubagentStart`),hook 會把 `lessons-append.sh` 的用法
|
|
54
|
+
連同**主專案絕對路徑**注入它的 context,它覺得值得就自己記一筆,並在最終回報裡說一聲。
|
|
55
|
+
worktree isolation 下也照那條絕對路徑指令跑,不會寫錯地方。
|
|
56
|
+
- 前景 sub agent 回來時(`PostToolUse`),或背景 sub agent/Workflow 的 task-notification
|
|
57
|
+
到達時(`round-start.sh`),你會看到一句 `[Lessons Mode 提示]`,提醒你檢查上面四種訊號;
|
|
58
|
+
背景任務 `status` 是 `failed`/`killed` 時還會算進共用計數器。
|
|
59
|
+
|
|
60
|
+
看到提示後:sub agent 已說明記過的主題不要重複記;多個 agent 卡在同一種問題時,由你彙整成
|
|
61
|
+
一筆更有代表性的。一樣全部非強制。Codex/Cursor 沒有對應 hook,仍是你自己判斷。詳見
|
|
62
|
+
`docs/design/lessons-mode.md`「sub agent/workflow 情境的自我判斷訊號」。
|