leerness 1.9.196 β†’ 1.9.198

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,109 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.198 β€” 2026-05-21
4
+
5
+ **πŸ€– BμΆ• 9/10 β†’ 9.5/10 β€” handoff multi-agent consensus 이λ ₯ 기반 best agent μžλ™ μΆ”μ²œ.**
6
+
7
+ 자율 λͺ¨λ“œ 128 λΌμš΄λ“œ. 1.9.193 consensus μžλ™ lessons.md μ €μž₯ (BμΆ•) 후속 β€” μ €μž₯ν•œ 데이터λ₯Ό **handoff μ—μ„œ μ¦‰μ‹œ μž¬ν™œμš©**.
8
+
9
+ ### μ‚¬μš©μž μ˜λ„ μ •λ ¬ (1.9.191 verbatim)
10
+ > *"λ©€ν‹° μ„œλΈŒ μ—μ΄μ „νŠΈ μ˜€μΌ€μŠ€νŠΈλΌ ... 졜고의 도ꡬ"*
11
+
12
+ ### 1. handoff μ‹ κ·œ μ„Ήμ…˜ (BμΆ• 핡심)
13
+ ```
14
+ ## πŸ€– task λ§€μΉ­ best agent (1.9.198 BμΆ•) β€” ν‚€μ›Œλ“œ "authentication"
15
+ κ³Όκ±° multi-agent consensus 2건 β€” μΆ”μ²œ agent: claude (1회 best)
16
+ 졜근 hit: 2026-05-20 agent=claude score=0.873
17
+ β†’ μž¬μ‹€ν–‰: leerness agents multi "<task>" --execute
18
+ ```
19
+ - lessons.md 의 1.9.193 `multi-agent consensus β€” best=X (1.9.193)` νŒ¨ν„΄ μžλ™ μΆ”μΆœ
20
+ - keyword fuzzy 맀칭으둜 κ΄€λ ¨ hits 선별
21
+ - agent 별 λΉˆλ„ 카운트 β†’ μ΅œλ‹€ best agent μžλ™ λ…ΈμΆœ
22
+ - 끄기: `--no-multiagent-hint` λ˜λŠ” `LEERNESS_NO_MULTIAGENT_HINT=1`
23
+
24
+ ### 2. μ‹ κ·œ ν•¨μˆ˜
25
+ - `_loadMultiAgentConsensusHistory(root, keyword)` β€” lessons.md 1.9.193 νŒ¨ν„΄ μΆ”μΆœ + fuzzy λ§€μΉ­
26
+
27
+ ### 3. λˆ„μ  νšŒκ·€ (1.9.192~197) β€” λͺ¨λ‘ μœ μ§€
28
+ - [1.9.197] _readyBackendCountFromCache (60λΆ„ μΊμ‹œ + ν—€λ“œλΌμΈ)
29
+ - [1.9.196] DμΆ• 7일+/30일+ recall + ScheduleWakeup miss detector
30
+ - [1.9.195] _probeProviderEndpoints (provider universal probe)
31
+ - [1.9.194] _suggestNextActions (handoff next-actions)
32
+ - [1.9.193] agents multi consensus β†’ lessons.md
33
+ - [1.9.192] _loadOfficialSkillCache + 24h μΊμ‹œ
34
+
35
+ ### 4. stress-v143 β€” 14/14 PASS
36
+ - BμΆ• 보강 (5: ν•¨μˆ˜ + μ„Ήμ…˜ + μž„μ‹œ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 톡합 검증 + λΉˆλ„ 카운트)
37
+ - μ„±λŠ₯: --version cold start avg **500 ms** Β· MCP 54 도ꡬ **494 ms**
38
+
39
+ ### 5. 5μΆ• 맀트릭슀 변동
40
+ | μΆ• | 1.9.197 | 1.9.198 | Ξ” |
41
+ |---|---|---|---|
42
+ | B. λ©€ν‹° Sub-Agent μ˜€μΌ€μŠ€νŠΈλΌ | 9/10 | **9.5/10** | +0.5 (consensus 이λ ₯ μžλ™ 회수) |
43
+ | μ’…ν•© | 47.5/50 (95%) | **48/50 (96%)** | +1% |
44
+
45
+ ### 6. μ‚¬μš©μž λͺ…μ‹œ 쑰치
46
+ - Cron `10dcaa07` (hourly :17 backup) μ‚¬μš©μž μš”μ²­μœΌλ‘œ μ‚­μ œ
47
+ - μžλ™ λ£¨ν”„λŠ” **ScheduleWakeup 1500s (25λΆ„, R-0001 영ꡬ λ£°)** 단독 운영
48
+
49
+ ### 7. μžλ™ release 흐름
50
+ - main μžλ™ push **60 λΌμš΄λ“œ 연속** (1.9.140~198)
51
+ - npm publish μžλ™ (1.9.178~)
52
+
53
+ ---
54
+
55
+ ## 1.9.197 β€” 2026-05-21
56
+
57
+ **πŸ”Œ AμΆ• 9.5/10 β†’ 10/10 β€” provider probe handoff μžλ™ 톡합 + 60λΆ„ μΊμ‹œ. 5μΆ• 맀트릭슀 47.5/50 (95%).**
58
+
59
+ 자율 λͺ¨λ“œ 127 λΌμš΄λ“œ. 1.9.196 DμΆ• 완성에 이어 **AμΆ• 9.5 β†’ 10/10** λ§ˆμ§€λ§‰ 보강.
60
+
61
+ ### μ‚¬μš©μž μ˜λ„ μ •λ ¬ (1.9.191 verbatim)
62
+ > *"λ²”μš© AI ν•˜λ„€μŠ€ ... 졜고의 도ꡬ"*
63
+
64
+ ### 1. handoff ν—€λ“œλΌμΈ 11번째 μš”μ†Œ (1.9.197 μ‹ κ·œ)
65
+ ```
66
+ πŸ“Š ν—€λ“œλΌμΈ (1.9.81/93/113/152/162/192/197): ... Β· πŸ”Œ backend 3/13 (0hβœ“)
67
+ ```
68
+ - `πŸ”Œ backend {ready}/{total} ({age}{status})`
69
+ - 13 후보 = CLI 5 + Local endpoint 3 + Cloud API key 5
70
+ - 60λΆ„ μΊμ‹œ hit μ‹œ μ¦‰μ‹œ ν‘œμ‹œ (network λΆ€ν•˜ X)
71
+ - μΊμ‹œ 만료 μ‹œ `⚠` ν‘œμ‹œ β†’ μ‚¬μš©μž/AI κ°€ `provider probe` μž¬μ‹€ν–‰ 인지
72
+
73
+ ### 2. 60λΆ„ TTL μΊμ‹œ (1.9.197 μ‹ κ·œ)
74
+ - 파일: `.harness/provider-probe-cache.json` (λΉ„μ‹œν¬λ¦Ώ, 체크인 κ°€λŠ₯)
75
+ - `_PROVIDER_PROBE_CACHE_TTL_MS = 60 * 60 * 1000`
76
+ - `provider probe` μ‹€ν–‰ μ‹œ μžλ™ μ €μž₯ (`--no-cache` 둜 끄기)
77
+ - ν•¨μˆ˜: `_loadProviderProbeCache` / `_writeProviderProbeCache` / `_readyBackendCountFromCache`
78
+
79
+ ### 3. λˆ„μ  νšŒκ·€ (1.9.191~196) β€” λͺ¨λ‘ μœ μ§€
80
+ - [1.9.196] DμΆ• 7일+/30일+ recall + ScheduleWakeup miss detector
81
+ - [1.9.195] _probeProviderEndpoints (provider universal probe)
82
+ - [1.9.194] _suggestNextActions (handoff next-actions)
83
+ - [1.9.193] agents multi consensus β†’ lessons.md
84
+ - [1.9.192] _loadOfficialSkillCache + 24h μΊμ‹œ
85
+ - [1.9.191] ꡬ쑰 μ΅œμ ν™” λ³΄κ³ μ„œ 88/100
86
+
87
+ ### 4. stress-v142 β€” 15/15 PASS
88
+ - AμΆ• 9.5β†’10 보강 (6: ν•¨μˆ˜ + μΊμ‹œ μžλ™ μ €μž₯ + ν—€λ“œλΌμΈ 11번째 + handoff 톡합 검증)
89
+ - μ„±λŠ₯: --version cold start avg **506 ms** Β· MCP 54 도ꡬ **591 ms**
90
+
91
+ ### 5. 5μΆ• 맀트릭슀 (λͺ¨λ“  μΆ• 보강 μ™„λ£Œ)
92
+ | μΆ• | 1.9.191 | 1.9.197 | Ξ” |
93
+ |---|---|---|---|
94
+ | A. λ²”μš© AI ν•˜λ„€μŠ€ | 9 | **10** | +1 (probe + handoff μžλ™) |
95
+ | B. λ©€ν‹° Sub-Agent | 8.5 | **9** | +0.5 (consensus lessons) |
96
+ | C. 곡식 μŠ€ν‚¬ μžλ™ | 8 | **9** | +1 (official catalog handoff) |
97
+ | D. μž₯κΈ° λ§₯락 μœ μ§€ | 9.5 | **10** | +0.5 (7일+/30일+ recall) |
98
+ | E. κ²ŒμœΌλ¦„ λ°©μ§€ | 9 | **9.5** | +0.5 (next-actions) |
99
+ | **μ’…ν•©** | **44/50 (88%)** | **47.5/50 (95%)** | **+7%** 🎯 |
100
+
101
+ ### 6. μžλ™ release 흐름
102
+ - main μžλ™ push **59 λΌμš΄λ“œ 연속** (1.9.140~197)
103
+ - npm publish μžλ™ (1.9.178~)
104
+
105
+ ---
106
+
3
107
  ## 1.9.196 β€” 2026-05-21
4
108
 
5
109
  **πŸ—„ DμΆ• (μž₯κΈ° λ§₯락 μœ μ§€) 보강 β€” 7일+ μž₯κΈ° 정체 + 30일+ lessons 회고 + ScheduleWakeup miss detector.**
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.196-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v141-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-126-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-58_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-94%2F100_(5μΆ•)-brightgreen)]() [![longterm-recall](https://img.shields.io/badge/handoff-30일%2B_lessons_recall-success)]() [![perf](https://img.shields.io/badge/cold_start-709ms-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.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)]()
6
6
 
7
7
  ```
8
8
  ╔══════════════════════════════════════════════════════════════╗
@@ -12,9 +12,9 @@
12
12
  β•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β•‘
13
13
  β•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β•‘
14
14
  β•‘ β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β• β•‘
15
- β•‘ v1.9.196 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.198 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ πŸ—„ 5μΆ• 보강 μ™„λ£Œ (94/100) Β· 30일+ recall Β· 126 λΌμš΄λ“œ β•‘
17
+ β•‘ πŸ€– best agent μžλ™ μΆ”μ²œ Β· 맀트릭슀 96/100 Β· 128 λΌμš΄λ“œ β•‘
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.196';
10
+ const VERSION = '1.9.198';
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,39 @@ async function skillAutoCacheCmd(root, sub) {
1662
1662
  if (c.expired) log(` β†’ κ°±μ‹ : leerness skill auto-cache refresh`);
1663
1663
  }
1664
1664
 
1665
+ // 1.9.198: BμΆ• (λ©€ν‹° Sub-Agent μ˜€μΌ€μŠ€νŠΈλΌ) 보강 β€” handoff μ—μ„œ task keyword λ§€μΉ­ best agent μΆ”μ²œ
1666
+ // 1.9.193 μ—μ„œ agents multi --execute κ²°κ³Όλ₯Ό lessons.md 에 기둝 β†’ 이λ₯Ό keyword λ§€μΉ­ν•˜μ—¬ μΆ”μΆœ
1667
+ // μ‚¬μš©μž/AI κ°€ 같은 task μž¬μ‹œλ„ μ‹œ "κ³Όκ±° best agent μš°μ„  μ‹œλ„" μ¦‰μ‹œ 인지
1668
+ function _loadMultiAgentConsensusHistory(root, keyword) {
1669
+ try {
1670
+ const lp = lessonsPath(root);
1671
+ if (!exists(lp)) return [];
1672
+ const lt = read(lp);
1673
+ // 1.9.193 νŒ¨ν„΄: ### YYYY-MM-DD multi-agent consensus β€” best=<agent> (1.9.193)
1674
+ // blocks 뢄리 ν›„ keyword λ§€μΉ­ + best agent μΆ”μΆœ
1675
+ const blocks = lt.split(/\n### /).slice(1).map(b => '### ' + b);
1676
+ const re193 = /multi-agent consensus β€” best=(\S+) \(1\.9\.193\)/;
1677
+ const fuzzyRe = keyword ? new RegExp(escapeRegex(keyword.slice(0, Math.max(4, Math.floor(keyword.length * 0.7)))), 'i') : null;
1678
+ const hits = [];
1679
+ for (const b of blocks) {
1680
+ const m = re193.exec(b);
1681
+ if (!m) continue;
1682
+ if (fuzzyRe && !fuzzyRe.test(b)) continue;
1683
+ // task / score μΆ”μΆœ
1684
+ const taskM = b.match(/- task: ([^\n]+)/);
1685
+ const scoreM = b.match(/- best agent: \S+, score=([\d.]+)/);
1686
+ const dateM = b.match(/^### (\d{4}-\d{2}-\d{2})/);
1687
+ hits.push({
1688
+ date: dateM ? dateM[1] : '?',
1689
+ agent: m[1],
1690
+ task: taskM ? taskM[1].slice(0, 80) : '',
1691
+ score: scoreM ? Number(scoreM[1]) : null
1692
+ });
1693
+ }
1694
+ return hits;
1695
+ } catch { return []; }
1696
+ }
1697
+
1665
1698
  // 1.9.194: EμΆ• (κ²ŒμœΌλ¦„ λ°©μ§€) β€” handoff μ—μ„œ λ‹€μŒ 단계 1-3개 μžλ™ μ œμ•ˆ
1666
1699
  // ν˜„μž¬ in-progress task description + Memory Surface (decisions/lessons/plan) μ‘°ν•© β†’
1667
1700
  // "λ‹€μŒ λ‹¨κ³„λ‘œ 무엇을 ν• μ§€" μΆ”λ‘  (μ‚¬μš©μž/AI 직접 μž…λ ₯ 없이 μ¦‰μ‹œ λ…ΈμΆœ)
@@ -3487,10 +3520,19 @@ function handoff(root) {
3487
3520
  parts.push(`🌐 official ${m.total}/${m.cacheTotal} (${ageStr}${status})`);
3488
3521
  }
3489
3522
  } catch {}
3523
+ // 11) 1.9.197: AμΆ• (λ²”μš© AI ν•˜λ„€μŠ€) 9.5β†’10 보강 β€” provider probe 60λΆ„ μΊμ‹œ μžλ™ λ…ΈμΆœ
3524
+ // μ‚¬μš©μž λͺ…μ‹œ: "λ²”μš© AI ν•˜λ„€μŠ€ ... 졜고의 도ꡬ" β€” λ§€ handoff μ‹œ 11 backend ready μƒνƒœ μ¦‰μ‹œ λ…ΈμΆœ
3525
+ try {
3526
+ const pb = _readyBackendCountFromCache(root);
3527
+ if (pb.hasCache) {
3528
+ const ageLabel = pb.ageHours != null ? (pb.ageHours < 24 ? `${pb.ageHours}h` : `${Math.floor(pb.ageHours/24)}d`) : '?';
3529
+ parts.push(`πŸ”Œ backend ${pb.ready}/${pb.total} (${ageLabel}${pb.expired ? '⚠' : 'βœ“'})`);
3530
+ }
3531
+ } catch {}
3490
3532
  if (parts.length) {
3491
3533
  const isTty = process.stdout && process.stdout.isTTY;
3492
3534
  const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
3493
- log(cy(`πŸ“Š ν—€λ“œλΌμΈ (1.9.81/93/113/152/162/192): ${parts.join(' Β· ')}`));
3535
+ log(cy(`πŸ“Š ν—€λ“œλΌμΈ (1.9.81/93/113/152/162/192/197): ${parts.join(' Β· ')}`));
3494
3536
  }
3495
3537
  } catch {}
3496
3538
  }
@@ -3716,6 +3758,29 @@ function handoff(root) {
3716
3758
  }
3717
3759
  } catch {}
3718
3760
  }
3761
+ // 1.9.198: BμΆ• (λ©€ν‹° Sub-Agent μ˜€μΌ€μŠ€νŠΈλΌ) 보강 β€” handoff μ—μ„œ keyword λ§€μΉ­ best agent μžλ™ μΆ”μ²œ
3762
+ // 1.9.193 lessons.md 기둝을 회수 β†’ "이 task ν‚€μ›Œλ“œλŠ” 이전에 agent X κ°€ best μ˜€λ‹€" ν‘œμ‹œ
3763
+ // 끄기: --no-multiagent-hint λ˜λŠ” LEERNESS_NO_MULTIAGENT_HINT=1
3764
+ if (!has('--no-multiagent-hint') && !has('--quiet') && process.env.LEERNESS_NO_MULTIAGENT_HINT !== '1') {
3765
+ try {
3766
+ const maHits = _loadMultiAgentConsensusHistory(root, keyword);
3767
+ if (maHits.length > 0) {
3768
+ // κ°€μž₯ 졜근 hit 1 + 동일 agent λΉˆλ„ 카운트
3769
+ const recent = maHits[maHits.length - 1];
3770
+ const agentCounts = {};
3771
+ for (const h of maHits) { agentCounts[h.agent] = (agentCounts[h.agent] || 0) + 1; }
3772
+ const topAgent = Object.entries(agentCounts).sort((a, b) => b[1] - a[1])[0];
3773
+ const isTty = process.stdout && process.stdout.isTTY;
3774
+ const blu = s => isTty ? `\x1b[34m${s}\x1b[0m` : s;
3775
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3776
+ log(blu(`## πŸ€– task λ§€μΉ­ best agent (1.9.198 BμΆ•) β€” ν‚€μ›Œλ“œ "${keyword}"`));
3777
+ log(dim(` κ³Όκ±° multi-agent consensus ${maHits.length}건 β€” μΆ”μ²œ agent: ${topAgent[0]} (${topAgent[1]}회 best)`));
3778
+ log(dim(` 졜근 hit: ${recent.date} agent=${recent.agent}${recent.score != null ? ` score=${recent.score.toFixed(3)}` : ''}`));
3779
+ log(dim(` β†’ μž¬μ‹€ν–‰: leerness agents multi "${(latestRow.request || '').slice(0, 60)}" --execute`));
3780
+ log('');
3781
+ }
3782
+ } catch {}
3783
+ }
3719
3784
  // 1.9.196: DμΆ• (μž₯κΈ° λ§₯락 μœ μ§€) 보강 β€” 30일+ μ „ lessons μžλ™ 회고 (long-term memory recall)
3720
3785
  // keyword 와 λ§€μΉ­λ˜λŠ” 30일+ 였래된 lessons 1건 λ…ΈμΆœ β†’ μžŠν˜€μ§„ κ³Όκ±° κ΅ν›ˆ μž¬μƒκΈ°
3721
3786
  // 끄기: --no-longterm-recall λ˜λŠ” LEERNESS_NO_LONGTERM_RECALL=1
@@ -5586,6 +5651,8 @@ function providerCmd(root, sub, ...args) {
5586
5651
  const json = has('--json');
5587
5652
  const timeoutMs = Number(arg('--timeout', '1500'));
5588
5653
  const results = await _probeProviderEndpoints(root, timeoutMs);
5654
+ // 1.9.197: μΊμ‹œ μžλ™ μ €μž₯ (handoff μžλ™ ν†΅ν•©μš©)
5655
+ if (!has('--no-cache')) _writeProviderProbeCache(root, results);
5589
5656
  if (json) { log(JSON.stringify(results, null, 2)); return; }
5590
5657
  log(`# leerness provider probe (1.9.195 β€” AμΆ• λ²”μš© AI ν•˜λ„€μŠ€ 보강)`);
5591
5658
  log(`νƒ€μž„μ•„μ›ƒ: ${timeoutMs}ms`);
@@ -5665,6 +5732,41 @@ async function _probeProviderEndpoints(root, timeoutMs) {
5665
5732
  return result;
5666
5733
  }
5667
5734
 
5735
+ // 1.9.197: AμΆ• 9.5β†’10 보강 β€” provider probe κ²°κ³Ό 60λΆ„ μΊμ‹œ (handoff μžλ™ 톡합)
5736
+ // μ‚¬μš©μž λͺ…μ‹œ (1.9.191): "λ²”μš© AI ν•˜λ„€μŠ€ ... 졜고의 도ꡬ"
5737
+ // λ§€ handoff λ§ˆλ‹€ 11 backend probe λΉ„μš© (~1.5초)을 μΊμ‹œλ‘œ 흑수 β†’ 1/60 λΌμš΄λ“œλ§Œ μ‹€μ œ probe
5738
+ // μΊμ‹œ μœ„μΉ˜: .harness/provider-probe-cache.json (λΉ„μ‹œν¬λ¦Ώ, 체크인 κ°€λŠ₯)
5739
+ const _PROVIDER_PROBE_CACHE_TTL_MS = 60 * 60 * 1000;
5740
+ function _providerProbeCachePath(root) { return path.join(root, '.harness', 'provider-probe-cache.json'); }
5741
+ function _loadProviderProbeCache(root) {
5742
+ try {
5743
+ const fp = _providerProbeCachePath(root);
5744
+ if (!exists(fp)) return null;
5745
+ const j = JSON.parse(read(fp));
5746
+ if (!j.at || !j.result) return null;
5747
+ const ageMs = Date.now() - new Date(j.at).getTime();
5748
+ return { ...j, ageMs, expired: ageMs > _PROVIDER_PROBE_CACHE_TTL_MS };
5749
+ } catch { return null; }
5750
+ }
5751
+ function _writeProviderProbeCache(root, result) {
5752
+ try {
5753
+ mkdirp(path.join(root, '.harness'));
5754
+ writeUtf8(_providerProbeCachePath(root), JSON.stringify({ at: new Date().toISOString(), result }, null, 2));
5755
+ return true;
5756
+ } catch { return false; }
5757
+ }
5758
+ // handoff ν—€λ“œλΌμΈμš© β€” μΊμ‹œ hit μ‹œ μ¦‰μ‹œ λ°˜ν™˜, miss μ‹œ null (async probe trigger λŠ” handoff κ°€ 직접)
5759
+ function _readyBackendCountFromCache(root) {
5760
+ const c = _loadProviderProbeCache(root);
5761
+ if (!c || !c.result) return { ready: 0, total: 11, ageHours: null, expired: false, hasCache: false };
5762
+ const r = c.result;
5763
+ const ready = (r.cli || []).filter(x => x.found).length
5764
+ + (r.endpoints || []).filter(x => x.reachable).length
5765
+ + (r.cloudKeys || []).filter(x => x.present).length;
5766
+ const total = (r.cli || []).length + (r.endpoints || []).length + (r.cloudKeys || []).length;
5767
+ return { ready, total, ageHours: Math.floor(c.ageMs / 3600000), expired: c.expired, hasCache: true };
5768
+ }
5769
+
5668
5770
  // 1.9.195: HTTP endpoint reachability check (μ˜μ‘΄μ„± 0)
5669
5771
  function _probeHttpEndpoint(url, timeoutMs) {
5670
5772
  return new Promise((resolve) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.196",
3
+ "version": "1.9.198",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",