devlog-tracker 0.27.0 → 0.29.2
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/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/round-start.sh +51 -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-round-start.sh +247 -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 +81 -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 +32 -8
|
@@ -14,23 +14,32 @@ OUT="$(CLAUDE_PROJECT_DIR="$TMP" bash "$SCRIPT_DIR/lessons-drift-set.sh" 5)"
|
|
|
14
14
|
[ "$OUT" = "LESSONS_NOT_ENABLED" ] && echo "PASS: lessons not enabled" || { echo "FAIL: $OUT"; FAIL=1; }
|
|
15
15
|
|
|
16
16
|
touch "$TMP/.devlog/.lessons-enabled"
|
|
17
|
-
printf '%s\n' '{"
|
|
17
|
+
printf '%s\n' '{"count": 2, "threshold": 3}' > "$TMP/.devlog/.lessons-advisory-state"
|
|
18
18
|
|
|
19
19
|
OUT="$(CLAUDE_PROJECT_DIR="$TMP" bash "$SCRIPT_DIR/lessons-drift-set.sh" 5)"
|
|
20
20
|
case "$OUT" in *LESSONS_DRIFT_THRESHOLD=5*) echo "PASS: set 5" ;; *) echo "FAIL: $OUT"; FAIL=1 ;; esac
|
|
21
|
-
grep -q '"
|
|
21
|
+
grep -q '"count": 2' "$TMP/.devlog/.lessons-advisory-state" \
|
|
22
22
|
&& echo "PASS: count preserved" || { echo "FAIL: count reset"; FAIL=1; }
|
|
23
|
-
grep -q '"threshold": 5' "$TMP/.devlog/.lessons-
|
|
23
|
+
grep -q '"threshold": 5' "$TMP/.devlog/.lessons-advisory-state" \
|
|
24
24
|
&& echo "PASS: threshold written" || { echo "FAIL: threshold"; FAIL=1; }
|
|
25
25
|
|
|
26
26
|
CLAUDE_PROJECT_DIR="$TMP" bash "$SCRIPT_DIR/lessons-drift-set.sh" 0 >/dev/null 2>&1
|
|
27
27
|
[ $? -eq 1 ] && echo "PASS: reject 0" || { echo "FAIL: accepted 0"; FAIL=1; }
|
|
28
28
|
|
|
29
|
-
rm -f "$TMP/.devlog/.lessons-
|
|
29
|
+
rm -f "$TMP/.devlog/.lessons-advisory-state"
|
|
30
30
|
OUT="$(CLAUDE_PROJECT_DIR="$TMP" bash "$SCRIPT_DIR/lessons-drift-set.sh" 7)"
|
|
31
31
|
case "$OUT" in *LESSONS_DRIFT_THRESHOLD=7*) echo "PASS: create 7" ;; *) echo "FAIL: create $OUT"; FAIL=1 ;; esac
|
|
32
|
-
grep -q '"
|
|
32
|
+
grep -q '"count": 0' "$TMP/.devlog/.lessons-advisory-state" \
|
|
33
33
|
&& echo "PASS: create count 0" || { echo "FAIL: create count"; FAIL=1; }
|
|
34
34
|
|
|
35
|
+
# --- migrates an old .lessons-drift-state before applying the new threshold
|
|
36
|
+
rm -f "$TMP/.devlog/.lessons-advisory-state"
|
|
37
|
+
printf '%s\n' '{"mismatch_count": 4, "threshold": 3}' > "$TMP/.devlog/.lessons-drift-state"
|
|
38
|
+
OUT="$(CLAUDE_PROJECT_DIR="$TMP" bash "$SCRIPT_DIR/lessons-drift-set.sh" 9)"
|
|
39
|
+
case "$OUT" in *LESSONS_DRIFT_THRESHOLD=9*) echo "PASS: migrate then set 9" ;; *) echo "FAIL: $OUT"; FAIL=1 ;; esac
|
|
40
|
+
[ ! -f "$TMP/.devlog/.lessons-drift-state" ] && echo "PASS: old file removed after migrate+set" || { echo "FAIL: old file still present"; FAIL=1; }
|
|
41
|
+
grep -q '"count": 4' "$TMP/.devlog/.lessons-advisory-state" && echo "PASS: migrated count preserved through set" || { echo "FAIL: migrated count lost"; FAIL=1; }
|
|
42
|
+
grep -q '"threshold": 9' "$TMP/.devlog/.lessons-advisory-state" && echo "PASS: new threshold applied after migrate" || { echo "FAIL: threshold not applied"; FAIL=1; }
|
|
43
|
+
|
|
35
44
|
if [ "$FAIL" -eq 0 ]; then echo "All checks passed."; exit 0
|
|
36
45
|
else echo "Some checks FAILED."; exit 1; fi
|
|
@@ -44,11 +44,21 @@ case "$OUT" in
|
|
|
44
44
|
*"LESSONS_ENABLED="*) echo "PASS: reports LESSONS_ENABLED" ;;
|
|
45
45
|
*) echo "FAIL: expected LESSONS_ENABLED=..., got $OUT"; FAIL=1 ;;
|
|
46
46
|
esac
|
|
47
|
-
assert_file ".lessons-
|
|
48
|
-
grep -q '"
|
|
49
|
-
&& echo "PASS:
|
|
50
|
-
grep -q '"threshold": 3' "$TMP_ROOT/.devlog/.lessons-
|
|
51
|
-
&& echo "PASS:
|
|
47
|
+
assert_file ".lessons-advisory-state created alongside .lessons-enabled" "$TMP_ROOT/.devlog/.lessons-advisory-state"
|
|
48
|
+
grep -q '"count": 0' "$TMP_ROOT/.devlog/.lessons-advisory-state" \
|
|
49
|
+
&& echo "PASS: advisory count starts at 0" || { echo "FAIL: advisory count not 0"; FAIL=1; }
|
|
50
|
+
grep -q '"threshold": 3' "$TMP_ROOT/.devlog/.lessons-advisory-state" \
|
|
51
|
+
&& echo "PASS: advisory threshold defaults to 3" || { echo "FAIL: advisory threshold not 3"; FAIL=1; }
|
|
52
|
+
|
|
53
|
+
# --- lessons-on migrates an old .lessons-drift-state on re-run -------------
|
|
54
|
+
rm -f "$TMP_ROOT/.devlog/.lessons-advisory-state"
|
|
55
|
+
printf '%s\n' '{"mismatch_count": 2, "threshold": 7}' > "$TMP_ROOT/.devlog/.lessons-drift-state"
|
|
56
|
+
OUT="$(bash "$SCRIPT_DIR/lessons-on.sh")"
|
|
57
|
+
assert_exit "lessons-on migrates old state file -> 0" 0 $?
|
|
58
|
+
assert_file "migration produced .lessons-advisory-state" "$TMP_ROOT/.devlog/.lessons-advisory-state"
|
|
59
|
+
assert_not_file "migration removed .lessons-drift-state" "$TMP_ROOT/.devlog/.lessons-drift-state"
|
|
60
|
+
grep -q '"count": 2' "$TMP_ROOT/.devlog/.lessons-advisory-state" && echo "PASS: migrated count preserved" || { echo "FAIL: migrated count lost"; FAIL=1; }
|
|
61
|
+
grep -q '"threshold": 7' "$TMP_ROOT/.devlog/.lessons-advisory-state" && echo "PASS: migrated threshold preserved" || { echo "FAIL: migrated threshold lost"; FAIL=1; }
|
|
52
62
|
|
|
53
63
|
# --- lessons-off disables, leaves main switch and any lessons files alone --
|
|
54
64
|
echo 'keep me' > "$TMP_ROOT/.devlog/devlog.lessons.foo.md"
|
|
@@ -61,7 +71,7 @@ esac
|
|
|
61
71
|
assert_not_file ".lessons-enabled removed" "$TMP_ROOT/.devlog/.lessons-enabled"
|
|
62
72
|
assert_file "main .enabled untouched" "$TMP_ROOT/.devlog/.enabled"
|
|
63
73
|
assert_file "lessons file untouched" "$TMP_ROOT/.devlog/devlog.lessons.foo.md"
|
|
64
|
-
assert_file ".lessons-
|
|
74
|
+
assert_file ".lessons-advisory-state untouched by lessons-off" "$TMP_ROOT/.devlog/.lessons-advisory-state"
|
|
65
75
|
|
|
66
76
|
# --- lessons-off when already off -> reports NOT_ENABLED, no error --------
|
|
67
77
|
OUT="$(bash "$SCRIPT_DIR/lessons-off.sh")"
|
|
@@ -634,6 +634,49 @@ fi
|
|
|
634
634
|
assert_file_absent "task-notification during open span: no .round-open" "$DEVLOG_DIR/.round-open"
|
|
635
635
|
rm -f "$DEVLOG_DIR/.span-open"
|
|
636
636
|
|
|
637
|
+
# --- 19: devlog-tracker admin slash commands are exempt from Round logging -
|
|
638
|
+
rm -f "$DEVLOG_DIR/devlog.md" "$DEVLOG_DIR/.round-open" "$DEVLOG_DIR/.turn-start" "$DEVLOG_DIR/.round-current.md" "$DEVLOG_DIR/.checkpoint-state"
|
|
639
|
+
printf '%s\n' '{"rounds_since_checkpoint": 3, "max_silent_rounds": 20, "checkpoint_marker_count": 0}' > "$DEVLOG_DIR/.checkpoint-state"
|
|
640
|
+
ADMIN_PROMPT='<command-name>/devlog-tracker:status</command-name><command-message>status</command-message><command-args></command-args>'
|
|
641
|
+
printf '{"prompt":"%s"}' "$ADMIN_PROMPT" | bash "$SCRIPT_DIR/round-start.sh"
|
|
642
|
+
assert_file_absent "admin command: no .round-current.md" "$DEVLOG_DIR/.round-current.md"
|
|
643
|
+
assert_file_absent "admin command: no .round-open" "$DEVLOG_DIR/.round-open"
|
|
644
|
+
assert_file_absent "admin command: no .turn-start" "$DEVLOG_DIR/.turn-start"
|
|
645
|
+
assert_file_absent "admin command: no devlog.md created" "$DEVLOG_DIR/devlog.md"
|
|
646
|
+
CP="$(grep -o '"rounds_since_checkpoint"[[:space:]]*:[[:space:]]*[0-9]\+' "$DEVLOG_DIR/.checkpoint-state" | grep -o '[0-9]\+$')"
|
|
647
|
+
if [ "$CP" = "3" ]; then
|
|
648
|
+
echo "PASS: admin command does not increment rounds_since_checkpoint"
|
|
649
|
+
else
|
|
650
|
+
echo "FAIL: expected rounds_since_checkpoint to stay 3, got $CP"
|
|
651
|
+
FAIL=1
|
|
652
|
+
fi
|
|
653
|
+
rm -f "$DEVLOG_DIR/.checkpoint-state"
|
|
654
|
+
|
|
655
|
+
# --- 20: a namespaced-but-different command name is not falsely exempted ---
|
|
656
|
+
# "lessons-on" must not match the "lessons" case arm (prefix collision guard).
|
|
657
|
+
LESSONS_ON_PROMPT='<command-name>/devlog-tracker:lessons-on</command-name><command-message>lessons-on</command-message><command-args></command-args>'
|
|
658
|
+
printf '{"prompt":"%s"}' "$LESSONS_ON_PROMPT" | bash "$SCRIPT_DIR/round-start.sh"
|
|
659
|
+
if [ -f "$DEVLOG_DIR/.round-current.md" ]; then
|
|
660
|
+
echo "FAIL: lessons-on command should still be exempt (matched its own arm)"
|
|
661
|
+
FAIL=1
|
|
662
|
+
else
|
|
663
|
+
echo "PASS: lessons-on command exempt via its own case arm"
|
|
664
|
+
fi
|
|
665
|
+
|
|
666
|
+
# --- 21: /devlog-tracker:continue is NOT exempt -- real work may follow ----
|
|
667
|
+
rm -f "$DEVLOG_DIR/devlog.md" "$DEVLOG_DIR/.round-open" "$DEVLOG_DIR/.turn-start" "$DEVLOG_DIR/.round-current.md"
|
|
668
|
+
CONTINUE_PROMPT='<command-name>/devlog-tracker:continue</command-name><command-message>continue</command-message><command-args></command-args>'
|
|
669
|
+
printf '{"prompt":"%s"}' "$CONTINUE_PROMPT" | bash "$SCRIPT_DIR/round-start.sh"
|
|
670
|
+
CUR_BODY="$(cat "$DEVLOG_DIR/.round-current.md" 2>/dev/null || echo '')"
|
|
671
|
+
assert_contains "continue command still opens a Round" "## Round 1 —" "$CUR_BODY"
|
|
672
|
+
if [ -f "$DEVLOG_DIR/.round-open" ]; then
|
|
673
|
+
echo "PASS: continue command still sets .round-open"
|
|
674
|
+
else
|
|
675
|
+
echo "FAIL: continue command should still set .round-open"
|
|
676
|
+
FAIL=1
|
|
677
|
+
fi
|
|
678
|
+
rm -f "$DEVLOG_DIR/devlog.md" "$DEVLOG_DIR/.round-open" "$DEVLOG_DIR/.turn-start" "$DEVLOG_DIR/.round-current.md"
|
|
679
|
+
|
|
637
680
|
# --- workspace claim on next prompt ----------------------------------------
|
|
638
681
|
WS="$TMP_ROOT/ws"
|
|
639
682
|
mkdir -p "$WS/.devlog"
|
|
@@ -674,6 +717,10 @@ OUT="$(printf '%s' '{"prompt":"keep going"}' | bash "$SCRIPT_DIR/round-start.sh"
|
|
|
674
717
|
grep -q '^## Round 2' "$WS/.devlog/.round-current.md" && echo "PASS: still opened Round 2" || { echo "FAIL: no round 2"; FAIL=1; }
|
|
675
718
|
|
|
676
719
|
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md"
|
|
720
|
+
# This fixture is reused below by the drift-only counter assertions (1 -> 2 ->
|
|
721
|
+
# reset-at-3). Its ### Status must stay non-BLOCKED: if it were BLOCKED, the
|
|
722
|
+
# BLOCKED-round bump would also fire on the same invocation and double-count
|
|
723
|
+
# the shared counter, breaking those assertions with a confusing failure.
|
|
677
724
|
cat > "$WS/.devlog/devlog.md" <<EOF
|
|
678
725
|
## Round 1 — 2026-09-11T00:00:00+08:00
|
|
679
726
|
|
|
@@ -708,35 +755,35 @@ MARKER="$(cat "$WS/.devlog/.workspace-mismatch")"
|
|
|
708
755
|
# --- lessons drift counter: mechanical nudge on repeated mismatch --------
|
|
709
756
|
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md" "$WS/.devlog/.workspace-mismatch"
|
|
710
757
|
touch "$WS/.devlog/.lessons-enabled"
|
|
711
|
-
printf '%s\n' '{"
|
|
758
|
+
printf '%s\n' '{"count": 0, "threshold": 3}' > "$WS/.devlog/.lessons-advisory-state"
|
|
712
759
|
|
|
713
760
|
OUT="$(printf '%s' '{"prompt":"keep going"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
714
761
|
assert_not_contains "drift count 1/3: no nudge yet" "[Lessons Mode 提示]" "$OUT"
|
|
715
|
-
grep -q '"
|
|
762
|
+
grep -q '"count": 1' "$WS/.devlog/.lessons-advisory-state" && echo "PASS: drift count -> 1" || { echo "FAIL: drift count not 1"; FAIL=1; }
|
|
716
763
|
|
|
717
764
|
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md"
|
|
718
765
|
OUT="$(printf '%s' '{"prompt":"keep going"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
719
766
|
assert_not_contains "drift count 2/3: no nudge yet" "[Lessons Mode 提示]" "$OUT"
|
|
720
|
-
grep -q '"
|
|
767
|
+
grep -q '"count": 2' "$WS/.devlog/.lessons-advisory-state" && echo "PASS: drift count -> 2" || { echo "FAIL: drift count not 2"; FAIL=1; }
|
|
721
768
|
|
|
722
769
|
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md"
|
|
723
770
|
OUT="$(printf '%s' '{"prompt":"keep going"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
724
771
|
assert_contains "drift count hits threshold: prints nudge" "[Lessons Mode 提示]" "$OUT"
|
|
725
|
-
grep -q '"
|
|
772
|
+
grep -q '"count": 0' "$WS/.devlog/.lessons-advisory-state" && echo "PASS: drift count reset after nudge" || { echo "FAIL: drift count not reset"; FAIL=1; }
|
|
726
773
|
|
|
727
774
|
# without .lessons-enabled: no counting, no nudge, state file untouched
|
|
728
775
|
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md" "$WS/.devlog/.lessons-enabled"
|
|
729
|
-
printf '%s\n' '{"
|
|
776
|
+
printf '%s\n' '{"count": 2, "threshold": 3}' > "$WS/.devlog/.lessons-advisory-state"
|
|
730
777
|
OUT="$(printf '%s' '{"prompt":"keep going"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
731
778
|
assert_not_contains "lessons off: no nudge even near threshold" "[Lessons Mode 提示]" "$OUT"
|
|
732
|
-
grep -q '"
|
|
733
|
-
rm -f "$WS/.devlog/.lessons-
|
|
779
|
+
grep -q '"count": 2' "$WS/.devlog/.lessons-advisory-state" && echo "PASS: drift count untouched when lessons off" || { echo "FAIL: drift count changed when lessons off"; FAIL=1; }
|
|
780
|
+
rm -f "$WS/.devlog/.lessons-advisory-state" "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md"
|
|
734
781
|
|
|
735
782
|
# --- lessons drift counter: upgrade path — .lessons-enabled exists (from
|
|
736
|
-
# before this branch) but .lessons-
|
|
783
|
+
# before this branch) but .lessons-advisory-state was never created. round-start.sh
|
|
737
784
|
# must create it with defaults and still act on this same invocation's
|
|
738
785
|
# mismatch, not require a second message ------------------------------------
|
|
739
|
-
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md" "$WS/.devlog/.workspace-mismatch" "$WS/.devlog/.lessons-
|
|
786
|
+
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md" "$WS/.devlog/.workspace-mismatch" "$WS/.devlog/.lessons-advisory-state"
|
|
740
787
|
touch "$WS/.devlog/.lessons-enabled"
|
|
741
788
|
cat > "$WS/.devlog/devlog.md" <<EOF
|
|
742
789
|
## Round 1 — 2026-09-11T00:00:00+08:00
|
|
@@ -761,11 +808,11 @@ do x
|
|
|
761
808
|
IN_PROGRESS
|
|
762
809
|
EOF
|
|
763
810
|
OUT="$(printf '%s' '{"prompt":"keep going"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
764
|
-
[ -f "$WS/.devlog/.lessons-
|
|
765
|
-
grep -q '"
|
|
766
|
-
grep -q '"threshold": 3' "$WS/.devlog/.lessons-
|
|
811
|
+
[ -f "$WS/.devlog/.lessons-advisory-state" ] && echo "PASS: upgrade path creates .lessons-advisory-state on first drift" || { echo "FAIL: .lessons-advisory-state not created for pre-existing lessons-enabled"; FAIL=1; }
|
|
812
|
+
grep -q '"count": 1' "$WS/.devlog/.lessons-advisory-state" 2>/dev/null && echo "PASS: newly-created state already counted this invocation's mismatch (1)" || { echo "FAIL: count not 1 in newly-created state"; FAIL=1; }
|
|
813
|
+
grep -q '"threshold": 3' "$WS/.devlog/.lessons-advisory-state" 2>/dev/null && echo "PASS: newly-created state has default threshold 3" || { echo "FAIL: threshold not 3 in newly-created state"; FAIL=1; }
|
|
767
814
|
assert_not_contains "upgrade path: no nudge yet on first-ever drift (1 < 3)" "[Lessons Mode 提示]" "$OUT"
|
|
768
|
-
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md" "$WS/.devlog/.lessons-enabled" "$WS/.devlog/.lessons-
|
|
815
|
+
rm -f "$WS/.devlog/.round-open" "$WS/.devlog/.round-current.md" "$WS/.devlog/.lessons-enabled" "$WS/.devlog/.lessons-advisory-state"
|
|
769
816
|
|
|
770
817
|
cat > "$WS/.devlog/devlog.md" <<EOF
|
|
771
818
|
## Round 1 — 2026-09-11T00:00:00+08:00
|
|
@@ -816,6 +863,193 @@ printf '%s' '{"prompt":"tick"}' | bash "$SCRIPT_DIR/round-start.sh" >/dev/null
|
|
|
816
863
|
[ ! -f "$WS/.devlog/.workspace-mismatch" ] && echo "PASS: span skip writes no marker" || { echo "FAIL: span marker"; FAIL=1; }
|
|
817
864
|
rm -f "$WS/.devlog/.span-open"
|
|
818
865
|
|
|
866
|
+
# --- BLOCKED-round accumulation shares the advisory counter -----------------
|
|
867
|
+
BLK_DIR="$(mktemp -d)"
|
|
868
|
+
export CLAUDE_PROJECT_DIR="$BLK_DIR"
|
|
869
|
+
mkdir -p "$BLK_DIR/.devlog"
|
|
870
|
+
touch "$BLK_DIR/.devlog/.enabled" "$BLK_DIR/.devlog/.lessons-enabled"
|
|
871
|
+
printf '%s\n' '{"count": 0, "threshold": 3}' > "$BLK_DIR/.devlog/.lessons-advisory-state"
|
|
872
|
+
cat > "$BLK_DIR/.devlog/devlog.md" <<'EOF'
|
|
873
|
+
## Round 1 — 2026-09-20T00:00:00+08:00
|
|
874
|
+
|
|
875
|
+
### Summary
|
|
876
|
+
s
|
|
877
|
+
|
|
878
|
+
### Reply
|
|
879
|
+
fixture reply.
|
|
880
|
+
|
|
881
|
+
### Handoff
|
|
882
|
+
#### 現況
|
|
883
|
+
waiting
|
|
884
|
+
#### 完成條件
|
|
885
|
+
缺的外部輸入已出現,且可觀察條件達成。
|
|
886
|
+
#### 下一步
|
|
887
|
+
apply the answer
|
|
888
|
+
|
|
889
|
+
### Status
|
|
890
|
+
BLOCKED
|
|
891
|
+
EOF
|
|
892
|
+
OUT="$(printf '%s' '{"prompt":"next"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
893
|
+
assert_not_contains "BLOCKED round 1/3: no advisory yet" "[Lessons Mode 提示]" "$OUT"
|
|
894
|
+
grep -q '"count": 1' "$BLK_DIR/.devlog/.lessons-advisory-state" && echo "PASS: BLOCKED round bumped counter to 1" || { echo "FAIL: counter not bumped to 1"; FAIL=1; }
|
|
895
|
+
|
|
896
|
+
rm -f "$BLK_DIR/.devlog/.round-open" "$BLK_DIR/.devlog/.round-current.md"
|
|
897
|
+
cat >> "$BLK_DIR/.devlog/devlog.md" <<'EOF'
|
|
898
|
+
|
|
899
|
+
## Round 2 — 2026-09-20T00:05:00+08:00
|
|
900
|
+
|
|
901
|
+
### Summary
|
|
902
|
+
s
|
|
903
|
+
|
|
904
|
+
### Reply
|
|
905
|
+
fixture reply.
|
|
906
|
+
|
|
907
|
+
### Handoff
|
|
908
|
+
#### 現況
|
|
909
|
+
waiting
|
|
910
|
+
#### 完成條件
|
|
911
|
+
缺的外部輸入已出現,且可觀察條件達成。
|
|
912
|
+
#### 下一步
|
|
913
|
+
apply the answer
|
|
914
|
+
|
|
915
|
+
### Status
|
|
916
|
+
BLOCKED
|
|
917
|
+
EOF
|
|
918
|
+
OUT="$(printf '%s' '{"prompt":"next again"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
919
|
+
assert_not_contains "BLOCKED round 2/3: no advisory yet" "[Lessons Mode 提示]" "$OUT"
|
|
920
|
+
grep -q '"count": 2' "$BLK_DIR/.devlog/.lessons-advisory-state" && echo "PASS: BLOCKED round bumped counter to 2" || { echo "FAIL: counter not bumped to 2"; FAIL=1; }
|
|
921
|
+
|
|
922
|
+
rm -f "$BLK_DIR/.devlog/.round-open" "$BLK_DIR/.devlog/.round-current.md"
|
|
923
|
+
cat >> "$BLK_DIR/.devlog/devlog.md" <<'EOF'
|
|
924
|
+
|
|
925
|
+
## Round 3 — 2026-09-20T00:10:00+08:00
|
|
926
|
+
|
|
927
|
+
### Summary
|
|
928
|
+
s
|
|
929
|
+
|
|
930
|
+
### Reply
|
|
931
|
+
fixture reply.
|
|
932
|
+
|
|
933
|
+
### Handoff
|
|
934
|
+
#### 現況
|
|
935
|
+
waiting
|
|
936
|
+
#### 完成條件
|
|
937
|
+
缺的外部輸入已出現,且可觀察條件達成。
|
|
938
|
+
#### 下一步
|
|
939
|
+
apply the answer
|
|
940
|
+
|
|
941
|
+
### Status
|
|
942
|
+
BLOCKED
|
|
943
|
+
EOF
|
|
944
|
+
OUT="$(printf '%s' '{"prompt":"next once more"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
945
|
+
assert_contains "BLOCKED round 3/3: hits threshold" "[Lessons Mode 提示]" "$OUT"
|
|
946
|
+
grep -q '"count": 0' "$BLK_DIR/.devlog/.lessons-advisory-state" && echo "PASS: counter reset after threshold" || { echo "FAIL: counter not reset"; FAIL=1; }
|
|
947
|
+
rm -rf "$BLK_DIR"
|
|
948
|
+
|
|
949
|
+
# --- BLOCKED->resolved: mechanical, one-shot print, not counted -------------
|
|
950
|
+
RES_DIR="$(mktemp -d)"
|
|
951
|
+
export CLAUDE_PROJECT_DIR="$RES_DIR"
|
|
952
|
+
mkdir -p "$RES_DIR/.devlog"
|
|
953
|
+
touch "$RES_DIR/.devlog/.enabled" "$RES_DIR/.devlog/.lessons-enabled"
|
|
954
|
+
cat > "$RES_DIR/.devlog/devlog.md" <<'EOF'
|
|
955
|
+
## Round 1 — 2026-09-20T00:00:00+08:00
|
|
956
|
+
|
|
957
|
+
### Summary
|
|
958
|
+
s
|
|
959
|
+
|
|
960
|
+
### Reply
|
|
961
|
+
fixture reply.
|
|
962
|
+
|
|
963
|
+
### Handoff
|
|
964
|
+
#### 現況
|
|
965
|
+
waiting
|
|
966
|
+
#### 完成條件
|
|
967
|
+
缺的外部輸入已出現,且可觀察條件達成。
|
|
968
|
+
#### 下一步
|
|
969
|
+
apply the answer
|
|
970
|
+
|
|
971
|
+
### Status
|
|
972
|
+
BLOCKED
|
|
973
|
+
|
|
974
|
+
## Round 2 — 2026-09-20T00:05:00+08:00
|
|
975
|
+
|
|
976
|
+
### Summary
|
|
977
|
+
resolved it
|
|
978
|
+
|
|
979
|
+
### Reply
|
|
980
|
+
fixture reply.
|
|
981
|
+
|
|
982
|
+
### Handoff
|
|
983
|
+
#### 現況
|
|
984
|
+
done
|
|
985
|
+
|
|
986
|
+
### Status
|
|
987
|
+
DONE
|
|
988
|
+
EOF
|
|
989
|
+
OUT="$(printf '%s' '{"prompt":"whats next"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
990
|
+
assert_contains "BLOCKED->resolved prints a one-shot advisory" "上一輪從 BLOCKED 解開了" "$OUT"
|
|
991
|
+
[ ! -f "$RES_DIR/.devlog/.lessons-advisory-state" ] && echo "PASS: resolved-transition print does not touch the shared counter" || { echo "FAIL: resolved-transition print created/touched the counter file"; FAIL=1; }
|
|
992
|
+
|
|
993
|
+
# resolved print requires two rounds of history: with only one round of
|
|
994
|
+
# history (regardless of its own status) there's no "second-to-last" round
|
|
995
|
+
# to compare against.
|
|
996
|
+
rm -rf "$RES_DIR"
|
|
997
|
+
RES2_DIR="$(mktemp -d)"
|
|
998
|
+
export CLAUDE_PROJECT_DIR="$RES2_DIR"
|
|
999
|
+
mkdir -p "$RES2_DIR/.devlog"
|
|
1000
|
+
touch "$RES2_DIR/.devlog/.enabled" "$RES2_DIR/.devlog/.lessons-enabled"
|
|
1001
|
+
cat > "$RES2_DIR/.devlog/devlog.md" <<'EOF'
|
|
1002
|
+
## Round 1 — 2026-09-20T00:00:00+08:00
|
|
1003
|
+
|
|
1004
|
+
### Summary
|
|
1005
|
+
s
|
|
1006
|
+
|
|
1007
|
+
### Reply
|
|
1008
|
+
fixture reply.
|
|
1009
|
+
|
|
1010
|
+
### Handoff
|
|
1011
|
+
#### 現況
|
|
1012
|
+
done
|
|
1013
|
+
|
|
1014
|
+
### Status
|
|
1015
|
+
DONE
|
|
1016
|
+
EOF
|
|
1017
|
+
OUT="$(printf '%s' '{"prompt":"go"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
1018
|
+
assert_not_contains "cold start (one round of history): no resolved print" "上一輪從 BLOCKED 解開了" "$OUT"
|
|
1019
|
+
rm -rf "$RES2_DIR"
|
|
1020
|
+
export CLAUDE_PROJECT_DIR="$TMP_ROOT"
|
|
1021
|
+
|
|
1022
|
+
# --- without .lessons-enabled: BLOCKED accumulation does not run at all ----
|
|
1023
|
+
NOLES_DIR="$(mktemp -d)"
|
|
1024
|
+
export CLAUDE_PROJECT_DIR="$NOLES_DIR"
|
|
1025
|
+
mkdir -p "$NOLES_DIR/.devlog"
|
|
1026
|
+
touch "$NOLES_DIR/.devlog/.enabled"
|
|
1027
|
+
cat > "$NOLES_DIR/.devlog/devlog.md" <<'EOF'
|
|
1028
|
+
## Round 1 — 2026-09-20T00:00:00+08:00
|
|
1029
|
+
|
|
1030
|
+
### Summary
|
|
1031
|
+
s
|
|
1032
|
+
|
|
1033
|
+
### Reply
|
|
1034
|
+
fixture reply.
|
|
1035
|
+
|
|
1036
|
+
### Handoff
|
|
1037
|
+
#### 現況
|
|
1038
|
+
waiting
|
|
1039
|
+
#### 完成條件
|
|
1040
|
+
缺的外部輸入已出現,且可觀察條件達成。
|
|
1041
|
+
#### 下一步
|
|
1042
|
+
apply the answer
|
|
1043
|
+
|
|
1044
|
+
### Status
|
|
1045
|
+
BLOCKED
|
|
1046
|
+
EOF
|
|
1047
|
+
OUT="$(printf '%s' '{"prompt":"next"}' | bash "$SCRIPT_DIR/round-start.sh" 2>/dev/null)"
|
|
1048
|
+
assert_not_contains "lessons off: no BLOCKED-accumulation advisory" "[Lessons Mode 提示]" "$OUT"
|
|
1049
|
+
[ ! -f "$NOLES_DIR/.devlog/.lessons-advisory-state" ] && echo "PASS: lessons off leaves no advisory-state file" || { echo "FAIL: advisory-state file created while lessons off"; FAIL=1; }
|
|
1050
|
+
rm -rf "$NOLES_DIR"
|
|
1051
|
+
export CLAUDE_PROJECT_DIR="$TMP_ROOT"
|
|
1052
|
+
|
|
819
1053
|
if [ "$FAIL" -eq 0 ]; then
|
|
820
1054
|
echo "All checks passed."
|
|
821
1055
|
exit 0
|
|
@@ -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.29.2",
|
|
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": {
|