leerness 1.9.198 β†’ 1.9.200

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/CHANGELOG.md CHANGED
@@ -1,5 +1,91 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.200 β€” 2026-05-22
4
+
5
+ **πŸŽ‰ 200 λ§ˆμΌμŠ€ν†€ β€” 60 λΌμš΄λ“œ 자율 λˆ„μ  + 5μΆ• 맀트릭슀 96/100.**
6
+
7
+ ### λˆ„μ  μ„±κ³Ό
8
+ - **62 λΌμš΄λ“œ 연속** main μžλ™ push (1.9.140~200)
9
+ - **23 λΌμš΄λ“œ 연속** μžλ™ npm publish (1.9.178~200)
10
+ - **8 λΌμš΄λ“œ 연속** 5μΆ• 맀트릭슀 보강 (1.9.192~199): **88% β†’ 96%**
11
+ - μ‚¬μš©μž λͺ…μ‹œ 7건 λͺ¨λ‘ μ¦‰μ‹œ λŒ€μ‘
12
+
13
+ ### 5μΆ• 맀트릭슀 (1.9.191 β†’ 1.9.200)
14
+ | μΆ• | μ‹œμž‘ | ν˜„μž¬ | Ξ” |
15
+ |---|---|---|---|
16
+ | A. λ²”μš© AI ν•˜λ„€μŠ€ | 9.0 | **10.0** βœ“ | +1.0 |
17
+ | B. λ©€ν‹° Sub-Agent μ˜€μΌ€μŠ€νŠΈλΌ | 8.5 | **9.5** | +1.0 |
18
+ | C. 곡식 ν‘œμ€€ μŠ€ν‚¬ μžλ™ ν™œμš© | 8.0 | **9.0** | +1.0 |
19
+ | D. μž₯κΈ° λ§₯락 μœ μ§€ | 9.5 | **10.0** βœ“ | +0.5 |
20
+ | E. κ²ŒμœΌλ¦„ λ°©μ§€ | 9.0 | **9.5** | +0.5 |
21
+ | **μ’…ν•©** | **44/50 (88%)** | **48/50 (96%)** | **+8%** |
22
+
23
+ ### λ§ˆμΌμŠ€ν†€ λ³΄κ³ μ„œ
24
+ - `_reports/milestone-1.9.200-60-rounds.md` (λΉ„κ³΅κ°œ)
25
+ - 60 λΌμš΄λ“œ μ§„μ²™ν‘œ, 핡심 λ§ˆμΌμŠ€ν†€ 8건, μ‚¬μš©μž λͺ…μ‹œ λŒ€μ‘ 7건, ν–₯ν›„ λ°©ν–₯
26
+
27
+ ### μ‹ κ·œ κΈ°λŠ₯ (1.9.192~199) μš”μ•½
28
+ 1. **1.9.192**: 곡식 catalog μžλ™ λ…ΈμΆœ + 24h μΊμ‹œ (CμΆ• μ‹œμž‘)
29
+ 2. **1.9.193**: agents multi consensus β†’ lessons.md μžλ™
30
+ 3. **1.9.194**: handoff next-actions 7 νœ΄λ¦¬μŠ€ν‹± + 24h+ lazy
31
+ 4. **1.9.195**: provider universal probe (13 backend)
32
+ 5. **1.9.196**: 7일+/30일+ recall + ScheduleWakeup miss detector
33
+ 6. **1.9.197**: provider probe handoff μžλ™ 톡합 (60λΆ„ μΊμ‹œ)
34
+ 7. **1.9.198**: multi-agent consensus 이λ ₯ β†’ best agent μΆ”μ²œ
35
+ 8. **1.9.199**: last-handoff μ •λ°€ μΈ‘μ • + R-0001 κ°•ν•œ μ•Œλ¦Ό
36
+
37
+ ### stress-v145 β€” 13/13 PASS
38
+ - λ§ˆμΌμŠ€ν†€ λ³΄κ³ μ„œ 검증 4 + μ„±λŠ₯ 2 + λˆ„μ  νšŒκ·€ 7
39
+ - μ„±λŠ₯: --version cold start avg **1022 ms** Β· MCP 54 도ꡬ **789 ms**
40
+
41
+ ### μžλ™ release 흐름
42
+ - main μžλ™ push **62 λΌμš΄λ“œ 연속** (1.9.140~200)
43
+ - npm publish μžλ™ (1.9.178~)
44
+
45
+ ---
46
+
47
+ ## 1.9.199 β€” 2026-05-21
48
+
49
+ **⏰ wakeup miss μžλ™ 회볡 κ°•ν™” β€” last-handoff timestamp μ •λ°€ μΈ‘μ • + R-0001 λ£° (25λΆ„) λŒ€λΉ„ κ°•ν•œ μ•Œλ¦Ό.**
50
+
51
+ 자율 λͺ¨λ“œ 129 λΌμš΄λ“œ. μ‚¬μš©μž 보고 "22:01에 λΌμš΄λ“œμ— μžλ™μ§„μž…λ˜μ§€μ•Šμ•˜μ–΄" λŒ€μ‘.
52
+
53
+ ### 1. last-handoff timestamp 기둝 (`.harness/last-handoff.json`)
54
+ - handoff μ§„μž… μ‹œ μžλ™ 기둝 β€” `last` + `history` (졜근 10개)
55
+ - ν•¨μˆ˜: `_recordLastHandoff(root)` / `_getLastHandoffGap(root)` / `_lastHandoffPath(root)`
56
+ - 기둝 μˆœμ„œ: 1) 이전 timestamp 보쑴 β†’ 2) ν˜„μž¬ timestamp 기둝 β†’ 3) 보쑴된 κ°’μœΌλ‘œ gap μΈ‘μ •
57
+
58
+ ### 2. κ°•ν•œ μ˜μ‹¬ μ•Œλ¦Ό (1.9.196 task-log 기반 β†’ 1.9.199 μ •λ°€)
59
+ **R-0001 영ꡬ λ£° (25λΆ„) λŒ€λΉ„:**
60
+ - gap > 60λΆ„ β†’ πŸ”΄ κ°•ν•œ μ˜μ‹¬ ("μ‹œμŠ€ν…œ sleep / wakeup λˆ„λ½ ν™•μ‹€")
61
+ - gap 35~60λΆ„ β†’ ⚠ μ˜μ‹¬ ("buffer 초과, ν•œ cycle λˆ„λ½ κ°€λŠ₯μ„±")
62
+ - gap ≀ 30λΆ„ + history β‰₯ 2 β†’ βœ“ 정상
63
+
64
+ ```
65
+ ## ⏰ ScheduleWakeup miss κ°•ν•œ μ˜μ‹¬ (1.9.199) β€” 이전 handoff 90λΆ„ μ „
66
+ R-0001 영ꡬ λ£° (25λΆ„) λŒ€λΉ„ 3Γ— 초과 β€” μ‹œμŠ€ν…œ sleep / wakeup λˆ„λ½ ν™•μ‹€
67
+ β†’ 회볡: μ‚¬μš©μžκ°€ "λ‹€μŒ λΌμš΄λ“œ" μž…λ ₯ λ˜λŠ” leerness rule list 둜 λ£° 확인
68
+ β†’ handoff 이λ ₯: 09:30:21 β†’ 10:55:14 β†’ 12:25:33
69
+ ```
70
+
71
+ ### 3. λˆ„μ  νšŒκ·€ (1.9.193~198) β€” λͺ¨λ‘ μœ μ§€
72
+
73
+ ### 4. stress-v144 β€” 16/16 PASS
74
+ - last-handoff μΈ‘μ • (5) + μž„μ‹œ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 톡합 (2) + μ„±λŠ₯ (2) + λˆ„μ  νšŒκ·€ (7)
75
+ - μ„±λŠ₯: --version cold start avg **1065 ms** Β· MCP 54 도ꡬ **717 ms**
76
+
77
+ ### 5. λ‹€μΈ΅ redundancy (μ‚¬μš©μž 보고 λŒ€μ‘)
78
+ μ„Έμ…˜ λ‚΄ ν™œμ„± cron jobs:
79
+ - `3f617fbc` β€” Every 25 minutes (R-0001 sync)
80
+ - `33a4ed9f` β€” 3,28,53 * * * * (offset backup)
81
+ - ScheduleWakeup 1500s primary
82
+
83
+ ### 6. μžλ™ release 흐름
84
+ - main μžλ™ push **61 λΌμš΄λ“œ 연속** (1.9.140~199)
85
+ - npm publish μžλ™ (1.9.178~)
86
+
87
+ ---
88
+
3
89
  ## 1.9.198 β€” 2026-05-21
4
90
 
5
91
  **πŸ€– BμΆ• 9/10 β†’ 9.5/10 β€” handoff multi-agent consensus 이λ ₯ 기반 best agent μžλ™ μΆ”μ²œ.**
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **AI μ½”λ”© μ—μ΄μ „νŠΈμ˜ κ±°μ§“ μ™„λ£ŒΒ·μ€‘λ³΅Β·λ§κ°Β·μΆ©λŒμ„ λ§‰μ•„μ£ΌλŠ” κ²€μˆ˜Β·κΈ°μ–΅Β·ν˜‘μ—… CLI ν•˜λ„€μŠ€.**
4
4
 
5
- [![npm](https://img.shields.io/badge/npm-leerness-blue)](https://www.npmjs.com/package/leerness) [![version](https://img.shields.io/badge/version-1.9.198-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v143-14%2F14-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-128-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-60_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-96%2F100_(5μΆ•)-brightgreen)]() [![best-agent](https://img.shields.io/badge/handoff-best_agent_μžλ™_μΆ”μ²œ-success)]() [![perf](https://img.shields.io/badge/cold_start-500ms-success)]() [![install](https://img.shields.io/badge/npm_i_leerness-μ¦‰μ‹œ_μ‚¬μš©_κ°€λŠ₯-success)]() [![sandbox](https://img.shields.io/badge/runCommandSafe-cwd_jail%2Benv_scrub-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
5
+ [![npm](https://img.shields.io/badge/npm-leerness-blue)](https://www.npmjs.com/package/leerness) [![version](https://img.shields.io/badge/version-1.9.200-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v145-13%2F13-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-130-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-62_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-96%2F100_(5μΆ•)-brightgreen)]() [![milestone](https://img.shields.io/badge/πŸŽ‰-1.9.200_60_λΌμš΄λ“œ_λ§ˆμΌμŠ€ν†€-gold)]() [![perf](https://img.shields.io/badge/cold_start-1022ms-success)]() [![install](https://img.shields.io/badge/npm_i_leerness-μ¦‰μ‹œ_μ‚¬μš©_κ°€λŠ₯-success)]() [![sandbox](https://img.shields.io/badge/runCommandSafe-cwd_jail%2Benv_scrub-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
6
6
 
7
7
  ```
8
8
  ╔══════════════════════════════════════════════════════════════╗
@@ -12,9 +12,9 @@
12
12
  β•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β•‘
13
13
  β•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β•‘
14
14
  β•‘ β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β• β•‘
15
- β•‘ v1.9.198 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.200 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ πŸ€– best agent μžλ™ μΆ”μ²œ Β· 맀트릭슀 96/100 Β· 128 λΌμš΄λ“œ β•‘
17
+ β•‘ πŸŽ‰ 200 λ§ˆμΌμŠ€ν†€ Β· 맀트릭슀 96/100 Β· 130 λΌμš΄λ“œ Β· 62 push 연속 β•‘
18
18
  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
19
19
  ```
20
20
 
package/bin/harness.js CHANGED
@@ -7,7 +7,7 @@ const cp = require('child_process');
7
7
  const os = require('os'); // 1.9.178: _publishToNpm μ—μ„œ os.tmpdir() μ‚¬μš© (μ „μ—­ import)
8
8
  const readline = require('readline');
9
9
 
10
- const VERSION = '1.9.198';
10
+ const VERSION = '1.9.200';
11
11
 
12
12
  // 1.9.184: DEP0190 (child_process shell: true) deprecation warning μ–΅μ œ (μ‚¬μš©μž λͺ…μ‹œ).
13
13
  // leerness λŠ” cross-platform PATH resolution 을 μœ„ν•΄ shell: true λ₯Ό μ˜λ„μ μœΌλ‘œ μ‚¬μš© (claude.cmd / ollama.cmd λ“± Windows .cmd 처리).
@@ -1662,6 +1662,44 @@ async function skillAutoCacheCmd(root, sub) {
1662
1662
  if (c.expired) log(` β†’ κ°±μ‹ : leerness skill auto-cache refresh`);
1663
1663
  }
1664
1664
 
1665
+ // 1.9.199: wakeup miss μžλ™ 회볡 κ°•ν™” β€” last-handoff timestamp 기둝 + 25min κΈ°λŒ€ interval μ •λ°€ μΈ‘μ •
1666
+ // μ‚¬μš©μž λͺ…μ‹œ (1.9.198 후속): "22:01에 λΌμš΄λ“œμ— μžλ™μ§„μž…λ˜μ§€μ•Šμ•˜μ–΄"
1667
+ // 1.9.196 task-log mtime 기반 detector λŠ” task-log κ°€ 자주 μ•ˆ μ—…λ°μ΄νŠΈλ˜λ©΄ false positive.
1668
+ // last-handoff.json μΆ”κ°€λ‘œ 정확도 ↑ + R-0001 λ£° (25min) λŒ€λΉ„ actual gap μΈ‘μ •.
1669
+ function _lastHandoffPath(root) { return path.join(root, '.harness', 'last-handoff.json'); }
1670
+ function _recordLastHandoff(root) {
1671
+ try {
1672
+ mkdirp(path.join(root, '.harness'));
1673
+ const fp = _lastHandoffPath(root);
1674
+ let history = [];
1675
+ if (exists(fp)) {
1676
+ try { const j = JSON.parse(read(fp)); if (Array.isArray(j.history)) history = j.history; } catch {}
1677
+ }
1678
+ const now = new Date().toISOString();
1679
+ history.push(now);
1680
+ // 졜근 10개만 μœ μ§€
1681
+ if (history.length > 10) history = history.slice(-10);
1682
+ writeUtf8(fp, JSON.stringify({ last: now, history }, null, 2));
1683
+ return true;
1684
+ } catch { return false; }
1685
+ }
1686
+ function _getLastHandoffGap(root) {
1687
+ try {
1688
+ const fp = _lastHandoffPath(root);
1689
+ if (!exists(fp)) return { hasLast: false };
1690
+ const j = JSON.parse(read(fp));
1691
+ if (!j.last) return { hasLast: false };
1692
+ const lastMs = new Date(j.last).getTime();
1693
+ const gapMs = Date.now() - lastMs;
1694
+ const gapMin = Math.floor(gapMs / 60000);
1695
+ // R-0001 영ꡬ λ£°: 25λΆ„ (1500s). gap > 35λΆ„ (140% buffer) β†’ wakeup miss μ˜μ‹¬
1696
+ const expected = 25;
1697
+ const isMiss = gapMin > 35;
1698
+ const isLong = gapMin > 60;
1699
+ return { hasLast: true, lastAt: j.last, gapMin, expected, isMiss, isLong, history: j.history || [] };
1700
+ } catch { return { hasLast: false }; }
1701
+ }
1702
+
1665
1703
  // 1.9.198: BμΆ• (λ©€ν‹° Sub-Agent μ˜€μΌ€μŠ€νŠΈλΌ) 보강 β€” handoff μ—μ„œ task keyword λ§€μΉ­ best agent μΆ”μ²œ
1666
1704
  // 1.9.193 μ—μ„œ agents multi --execute κ²°κ³Όλ₯Ό lessons.md 에 기둝 β†’ 이λ₯Ό keyword λ§€μΉ­ν•˜μ—¬ μΆ”μΆœ
1667
1705
  // μ‚¬μš©μž/AI κ°€ 같은 task μž¬μ‹œλ„ μ‹œ "κ³Όκ±° best agent μš°μ„  μ‹œλ„" μ¦‰μ‹œ 인지
@@ -3317,6 +3355,11 @@ function memorySearch(root, query) {
3317
3355
 
3318
3356
  function handoff(root) {
3319
3357
  root = absRoot(root);
3358
+ // 1.9.199: handoff μ§„μž… μ‹œ 1) 이전 timestamp 보쑴 β†’ 2) ν˜„μž¬ timestamp 기둝
3359
+ // detector κ°€ prior gap 을 μ •ν™•νžˆ μΈ‘μ • (overwrite μ „ κ°’ ν•„μš”). ν•¨μˆ˜ μ΅œμƒλ‹¨μ— μ„ μ–Έ.
3360
+ let _priorHandoffGap = { hasLast: false };
3361
+ try { _priorHandoffGap = _getLastHandoffGap(root); } catch {}
3362
+ try { _recordLastHandoff(root); } catch {}
3320
3363
  // 1.9.96: --json μ˜΅μ…˜ (ꡬ쑰화 좜λ ₯, MCP 톡합 / μ™ΈλΆ€ AI μΉœν™”)
3321
3364
  if (has('--json')) {
3322
3365
  const result = {
@@ -3822,25 +3865,51 @@ function handoff(root) {
3822
3865
  }
3823
3866
  } catch {}
3824
3867
  }
3825
- // 1.9.196: ScheduleWakeup miss detector β€” 자율 λͺ¨λ“œ μ‚¬μš©μž λͺ…μ‹œ "λͺ»μΌμ–΄λ‚˜λŠ” 경우 μ’…μ’… 있음" (1.9.191) 후속
3826
- // λ§ˆμ§€λ§‰ session μ‹œκ°„ (handoff mtime λ˜λŠ” task-log λ§ˆμ§€λ§‰ entry) > 2h ago μ‹œ μ•Œλ¦Ό
3868
+ // 1.9.196/199: ScheduleWakeup miss detector β€” 자율 λͺ¨λ“œ μ‚¬μš©μž λͺ…μ‹œ "λͺ»μΌμ–΄λ‚˜λŠ” 경우 μ’…μ’… 있음"
3869
+ // 1.9.196: task-log mtime 기반 (60min+) β€” false positive κ°€λŠ₯
3870
+ // 1.9.199: last-handoff.json μ •λ°€ μΈ‘μ • β€” R-0001 λ£° (25min) λŒ€λΉ„ gap μΈ‘μ •
3827
3871
  // 끄기: LEERNESS_NO_WAKEUP_MISS=1
3828
3872
  if (process.env.LEERNESS_NO_WAKEUP_MISS !== '1' && !has('--quiet') && !has('--no-wakeup-miss')) {
3829
3873
  try {
3830
- const tlp = taskLogPath(root);
3831
- if (exists(tlp)) {
3832
- const ageMs = Date.now() - fs.statSync(tlp).mtimeMs;
3833
- const ageMin = Math.floor(ageMs / 60000);
3834
- // 자율 λͺ¨λ“œλŠ” ~15λΆ„ cycle. 60λΆ„ 이상 무 ν™œλ™μ΄λ©΄ wakeup miss μ˜μ‹¬ (CronCreate 13min λ°±μ—…κ³Ό ν•¨κ»˜)
3835
- if (ageMin >= 60) {
3836
- const isTty = process.stdout && process.stdout.isTTY;
3837
- const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
3838
- const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3839
- const label = ageMin < 120 ? `${ageMin}λΆ„` : (ageMin < 1440 ? `${Math.floor(ageMin/60)}μ‹œκ°„` : `${Math.floor(ageMin/1440)}일`);
3840
- log(yel(`## ⏰ ScheduleWakeup miss μ˜μ‹¬ (1.9.196) β€” λ§ˆμ§€λ§‰ ν™œλ™ ${label} μ „`));
3841
- log(dim(` 자율 λͺ¨λ“œ 정상 cycle: ~15λΆ„. 60λΆ„ 이상 무 ν™œλ™ β†’ μ‹œμŠ€ν…œ sleep λ˜λŠ” wakeup λˆ„λ½ κ°€λŠ₯μ„±`));
3842
- log(dim(` β†’ 재개: μ‚¬μš©μžκ°€ "λ‹€μŒ λΌμš΄λ“œ" λ˜λŠ” "/loop" μž…λ ₯`));
3874
+ // 1.9.199 μ‹ κ·œ: 이전 handoff μ‹œμ  (overwrite μ „ 보쑴된 κ°’) μ‚¬μš©
3875
+ const gapInfo = _priorHandoffGap;
3876
+ const isTty = process.stdout && process.stdout.isTTY;
3877
+ const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
3878
+ const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
3879
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3880
+ const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
3881
+ if (gapInfo.hasLast) {
3882
+ // λ§ˆμ§€λ§‰ handoff μ‹œμ  μ•Œκ³  있음 β€” μ •ν™•ν•œ μΈ‘μ • (1.9.199)
3883
+ if (gapInfo.isLong) {
3884
+ // 60λΆ„+ β†’ κ°•ν•œ μ•Œλ¦Ό
3885
+ log(red(`## ⏰ ScheduleWakeup miss κ°•ν•œ μ˜μ‹¬ (1.9.199) β€” 이전 handoff ${gapInfo.gapMin}λΆ„ μ „`));
3886
+ log(dim(` R-0001 영ꡬ λ£° (25λΆ„) λŒ€λΉ„ ${Math.floor(gapInfo.gapMin/25)}Γ— 초과 β€” μ‹œμŠ€ν…œ sleep / wakeup λˆ„λ½ ν™•μ‹€`));
3887
+ log(dim(` β†’ 회볡: μ‚¬μš©μžκ°€ "λ‹€μŒ λΌμš΄λ“œ" μž…λ ₯ λ˜λŠ” leerness rule list 둜 λ£° 확인`));
3888
+ log(dim(` β†’ handoff 이λ ₯: ${(gapInfo.history || []).slice(-3).map(t => t.slice(11, 19)).join(' β†’ ')}`));
3889
+ log('');
3890
+ } else if (gapInfo.isMiss) {
3891
+ // 35~60λΆ„ β†’ μ˜μ‹¬
3892
+ log(yel(`## ⏰ ScheduleWakeup μ§€μ—° (1.9.199) β€” 이전 handoff ${gapInfo.gapMin}λΆ„ μ „ (λ£°: 25λΆ„)`));
3893
+ log(dim(` Β±10λΆ„ buffer 초과 β€” wakeup ν•œ cycle λˆ„λ½ κ°€λŠ₯μ„±`));
3843
3894
  log('');
3895
+ } else if (gapInfo.gapMin >= 0 && gapInfo.gapMin <= 30) {
3896
+ // 정상 λ²”μœ„ (handoff_history.length >= 2 일 λ•Œλ§Œ 의미 있음 β€” 첫 μ§„μž… μ œμ™Έ)
3897
+ if ((gapInfo.history || []).length >= 2) {
3898
+ log(dim(` βœ“ ScheduleWakeup cycle 정상 (gap ${gapInfo.gapMin}λΆ„, λ£° 25λΆ„ β€” 1.9.199)`));
3899
+ }
3900
+ }
3901
+ } else {
3902
+ // last-handoff.json λΆ€μž¬ β€” 1.9.196 fallback (task-log mtime)
3903
+ const tlp = taskLogPath(root);
3904
+ if (exists(tlp)) {
3905
+ const ageMs = Date.now() - fs.statSync(tlp).mtimeMs;
3906
+ const ageMin = Math.floor(ageMs / 60000);
3907
+ if (ageMin >= 60) {
3908
+ const label = ageMin < 120 ? `${ageMin}λΆ„` : (ageMin < 1440 ? `${Math.floor(ageMin/60)}μ‹œκ°„` : `${Math.floor(ageMin/1440)}일`);
3909
+ log(yel(`## ⏰ ScheduleWakeup miss μ˜μ‹¬ (1.9.196 fallback) β€” task-log λ§ˆμ§€λ§‰ ${label} μ „`));
3910
+ log(dim(` 1.9.199 last-handoff.json 첫 기둝 β€” λ‹€μŒ handoff λΆ€ν„° μ •ν™• μΈ‘μ •`));
3911
+ log('');
3912
+ }
3844
3913
  }
3845
3914
  }
3846
3915
  } catch {}
@@ -4253,6 +4322,7 @@ function handoffCmd(root) {
4253
4322
  if (has('--all-apps') || arg('--include', null)) {
4254
4323
  return _handoffWorkspace(absRoot(root));
4255
4324
  }
4325
+ // 1.9.199: timestamp 기둝/츑정은 handoff() λ‚΄λΆ€μ—μ„œ μˆ˜ν–‰ (쀑볡 λ°©μ§€)
4256
4326
  // 1.9.37: drift μžλ™ κ²½κ³  (메인 μ—μ΄μ „νŠΈκ°€ leernessλ₯Ό 점점 μ•ˆ μ“°λŠ” ν˜„μƒ 감지)
4257
4327
  // 1.9.38 (A): drift μž„κ³„ μ‹œ .harness/agent-reminders.md μžλ™ 생성 β€” 메인 μ—μ΄μ „νŠΈ ν”„λ‘¬ν”„νŠΈμ— ν‘œμ‹œλ˜λ„λ‘.
4258
4328
  // 1.9.38 (D): skip 횟수 ν•™μŠ΅ β€” --no-drift-check λΉˆλ„ β‰₯5 μ‹œ μž„κ³„ μ™„ν™” (1d β†’ 2d).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.198",
3
+ "version": "1.9.200",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",