leerness 1.9.194 β†’ 1.9.196

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,134 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.196 β€” 2026-05-21
4
+
5
+ **πŸ—„ DμΆ• (μž₯κΈ° λ§₯락 μœ μ§€) 보강 β€” 7일+ μž₯κΈ° 정체 + 30일+ lessons 회고 + ScheduleWakeup miss detector.**
6
+
7
+ 자율 λͺ¨λ“œ 126 λΌμš΄λ“œ. μ‚¬μš©μž λͺ…μ‹œ:
8
+ > *"λ‹€μŒ λΌμš΄λ“œ μ§„ν–‰ν•˜κ³ , ScheduleWakeup κ°€ μ •μƒμ μœΌλ‘œ μž‘λ™ν•˜λ„λ‘ μ‘°μ·¨λ₯Ό μ·¨ν•΄μ€˜"*
9
+
10
+ 5μΆ• 맀트릭슀 λ§ˆμ§€λ§‰ 미보강 좕인 **DμΆ• (9.5/10 β†’ λͺ©ν‘œ 10/10)** + μ‚¬μš©μž λͺ…μ‹œ ScheduleWakeup μ•ˆμ •ν™”.
11
+
12
+ ### 1. DμΆ• 핡심 β€” μž₯κΈ° 정체 + 30일+ 회고 (handoff μžλ™)
13
+ **7일+ critical 단계** (24h+ lazy λ‹€μŒ 단계):
14
+ ```
15
+ ## ⚠ μ§„μ²™ 정체 감지 (1.9.194 EμΆ•) β€” progress-tracker λ§ˆμ§€λ§‰ 변동 8d μ „
16
+ ...
17
+ πŸ”΄ 7일+ μž₯κΈ° 정체 (8d) β€” μž₯κΈ° λ§₯락 손싀 μœ„ν—˜ (1.9.196 DμΆ•)
18
+ β†’ μ¦‰μ‹œ 회고: leerness retro . --since 8d
19
+ β†’ λ˜λŠ” archive: leerness task drop T-XXXX
20
+ ```
21
+
22
+ **30일+ μž₯κΈ° lessons 회고** (long-term memory recall):
23
+ - handoff keyword λ§€μΉ­ + lessons.md 30일+ μ „ 블둝
24
+ - μƒˆ μ„Ήμ…˜: `## πŸ—„ μž₯κΈ° lessons 회고 (1.9.196 DμΆ•) β€” ν‚€μ›Œλ“œ "X" κ΄€λ ¨ 30일+ N건`
25
+ - μžŠν˜€μ§„ κ³Όκ±° κ΅ν›ˆ μžλ™ μž¬μƒκΈ° β†’ 같은 μ‹€μˆ˜ 반볡 λ°©μ§€
26
+ - 끄기: `--no-longterm-recall` / `LEERNESS_NO_LONGTERM_RECALL=1`
27
+
28
+ ### 2. ScheduleWakeup μ•ˆμ •ν™” (μ‚¬μš©μž λͺ…μ‹œ) β€” λ‹€μΈ΅ redundancy
29
+ **Layer 1**: 더 짧은 ScheduleWakeup (1.9.193λΆ€ν„° 900s β†’ **270s** β€” 5λΆ„ cache μ•ˆμ— μœ μ§€)
30
+ **Layer 2**: CronCreate every 13min (durable: false) β€” primary λˆ„λ½ μ‹œ backup
31
+ **Layer 3**: handoff에 wakeup miss detector β€” 60λΆ„+ 무 ν™œλ™ μ‹œ μ•Œλ¦Ό
32
+ ```
33
+ ## ⏰ ScheduleWakeup miss μ˜μ‹¬ (1.9.196) β€” λ§ˆμ§€λ§‰ ν™œλ™ 90λΆ„ μ „
34
+ 자율 λͺ¨λ“œ 정상 cycle: ~15λΆ„. 60λΆ„ 이상 무 ν™œλ™ β†’ μ‹œμŠ€ν…œ sleep λ˜λŠ” wakeup λˆ„λ½
35
+ β†’ 재개: μ‚¬μš©μžκ°€ "λ‹€μŒ λΌμš΄λ“œ" λ˜λŠ” "/loop" μž…λ ₯
36
+ ```
37
+ 끄기: `LEERNESS_NO_WAKEUP_MISS=1`
38
+
39
+ ### 3. λˆ„μ  νšŒκ·€ (1.9.190~195) β€” λͺ¨λ‘ μœ μ§€
40
+ - [1.9.195] _probeProviderEndpoints (provider universal probe)
41
+ - [1.9.194] _suggestNextActions (handoff next-actions)
42
+ - [1.9.193] agents multi consensus β†’ lessons.md
43
+ - [1.9.192] _loadOfficialSkillCache + 24h μΊμ‹œ
44
+ - [1.9.191] ꡬ쑰 μ΅œμ ν™” λ³΄κ³ μ„œ 88/100
45
+ - [1.9.190] _selectOne/_selectMany Ctrl+C μ¦‰μ‹œ μ’…λ£Œ
46
+
47
+ ### 4. stress-v141 β€” 15/15 PASS
48
+ - DμΆ• 보강 (6: ν•¨μˆ˜ + 7일+ + 30일+ + miss detector + μž„μ‹œ μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 톡합) + μ„±λŠ₯ (2) + λˆ„μ  νšŒκ·€ (7)
49
+ - μ„±λŠ₯: --version cold start avg **709 ms** Β· MCP 54 도ꡬ **534 ms**
50
+
51
+ ### 5. 5μΆ• 맀트릭슀 변동
52
+ | μΆ• | 1.9.195 | 1.9.196 | Ξ” |
53
+ |---|---|---|---|
54
+ | D. μž₯κΈ° λ§₯락 μœ μ§€ | 9.5/10 | **10/10** | +0.5 (7일+ critical + 30일+ recall + miss detector) |
55
+ | μ’…ν•© | 46.5/50 (93%) | **47/50 (94%)** | +1% |
56
+
57
+ ### 6. 5μΆ• λͺ¨λ“  보강 μ™„λ£Œ
58
+ | μΆ• | μ‹œμž‘ | ν˜„μž¬ | Ξ” |
59
+ |---|---|---|---|
60
+ | A. λ²”μš© AI ν•˜λ„€μŠ€ | 9 | **9.5** | +0.5 (1.9.195 probe) |
61
+ | B. λ©€ν‹° Sub-Agent | 8.5 | **9** | +0.5 (1.9.193 consensus lessons) |
62
+ | C. 곡식 μŠ€ν‚¬ μžλ™ | 8 | **9** | +1 (1.9.192 official catalog) |
63
+ | D. μž₯κΈ° λ§₯락 μœ μ§€ | 9.5 | **10** | +0.5 (1.9.196 7일+/30일+ recall) |
64
+ | E. κ²ŒμœΌλ¦„ λ°©μ§€ | 9 | **9.5** | +0.5 (1.9.194 next-actions) |
65
+ | **μ’…ν•©** | 44/50 (88%) | **47/50 (94%)** | **+6%** |
66
+
67
+ ### 7. μžλ™ release 흐름
68
+ - main μžλ™ push **58 λΌμš΄λ“œ 연속** (1.9.140~196)
69
+ - npm publish μžλ™ (1.9.178~)
70
+
71
+ ---
72
+
73
+ ## 1.9.195 β€” 2026-05-21
74
+
75
+ **🌐 AμΆ• (λ²”μš© AI ν•˜λ„€μŠ€) 보강 β€” `leerness provider probe` μ‹ κ·œ λͺ…λ Ή (CLI/endpoint/API ν‚€ 3μ’… μžλ™ 감지).**
76
+
77
+ 자율 λͺ¨λ“œ 125 λΌμš΄λ“œ. 1.9.192 C / 193 B / 194 E 보강에 이어 **AμΆ• (9/10 β†’ λͺ©ν‘œ 9.5/10)** 보강.
78
+
79
+ ### μ‚¬μš©μž μ˜λ„ μ •λ ¬ (1.9.191 verbatim)
80
+ > *"λ²”μš© AI ν•˜λ„€μŠ€ ... 졜고의 도ꡬ"*
81
+
82
+ ### 1. `leerness provider probe` μ‹ κ·œ λͺ…λ Ή (AμΆ• 핡심)
83
+ - **3μ’… μžλ™ 감지** (μ˜μ‘΄μ„± 0 β€” Node built-in cp + http):
84
+ 1. **CLI binaries**: claude / codex / gemini / copilot / ollama (PATH + `--version`)
85
+ 2. **Local endpoint**: Ollama (11434) / LM Studio (1234) / llama.cpp (8080)
86
+ 3. **Cloud API key**: OPENROUTER / GROQ / TOGETHER / ANTHROPIC / OPENAI
87
+
88
+ - **좜λ ₯ μ˜΅μ…˜**: `--json` (μžλ™ν™”/CI) Β· ν…μŠ€νŠΈ λ§ˆν¬λ‹€μš΄ (μ‚¬λžŒ 읽기)
89
+ - **νƒ€μž„μ•„μ›ƒ**: `--timeout 1500` (κΈ°λ³Έ, ms)
90
+ - **ν™˜κ²½λ³€μˆ˜ override**: `OLLAMA_HOST` / `LMSTUDIO_HOST` / `LLAMACPP_HOST`
91
+
92
+ ### 2. μ‹€ μΈ‘μ • (개발 PC)
93
+ ```
94
+ | id | bin | found | version |
95
+ | claude | claude | βœ“ | 2.1.146 (Claude Code) |
96
+ | codex | codex | βœ“ | codex-cli 0.132.0 |
97
+ | gemini | gemini | βœ— | - |
98
+ | copilot | copilot | βœ— | - |
99
+ | ollama | ollama | βœ“ | (installed) |
100
+
101
+ βœ“ μ‚¬μš© κ°€λŠ₯ 후보 3건
102
+ ```
103
+
104
+ ### 3. μ‹ κ·œ ν•¨μˆ˜
105
+ - `_probeProviderEndpoints(root, timeoutMs)` β€” 3μ’… 톡합 감지
106
+ - `_probeHttpEndpoint(url, timeoutMs)` β€” Promise 기반 HTTP reachability check
107
+
108
+ ### 4. λˆ„μ  νšŒκ·€ (1.9.189~194) β€” λͺ¨λ‘ μœ μ§€
109
+ - [1.9.194] _suggestNextActions + lazy 감지
110
+ - [1.9.193] agents multi consensus β†’ lessons.md
111
+ - [1.9.192] _loadOfficialSkillCache + 24h μΊμ‹œ
112
+ - [1.9.191] ꡬ쑰 μ΅œμ ν™” λ³΄κ³ μ„œ 88/100
113
+ - [1.9.190] _selectOne/_selectMany Ctrl+C μ¦‰μ‹œ μ’…λ£Œ
114
+ - [1.9.189] _showSlashCommandList + Tab cycle ν•œ 쀄 κ°±μ‹ 
115
+
116
+ ### 5. stress-v140 β€” 15/15 PASS
117
+ - provider probe (6: ν•¨μˆ˜ + 3μ’… λŒ€μƒ + --json + ν…μŠ€νŠΈ) + μ„±λŠ₯ (2) + λˆ„μ  νšŒκ·€ (7)
118
+ - μ„±λŠ₯: --version cold start avg **442 ms** Β· MCP 54 도ꡬ **514 ms**
119
+
120
+ ### 6. 5μΆ• 맀트릭슀 변동
121
+ | μΆ• | 1.9.194 | 1.9.195 | Ξ” |
122
+ |---|---|---|---|
123
+ | A. λ²”μš© AI ν•˜λ„€μŠ€ | 9/10 | **9.5/10** | +0.5 (universal probe β€” 11 backend 후보 μžλ™ 감지) |
124
+ | μ’…ν•© | 46/50 (92%) | **46.5/50 (93%)** | +1% |
125
+
126
+ ### 7. μžλ™ release 흐름
127
+ - main μžλ™ push **57 λΌμš΄λ“œ 연속** (1.9.140~195)
128
+ - npm publish μžλ™ (1.9.178~)
129
+
130
+ ---
131
+
3
132
  ## 1.9.194 β€” 2026-05-21
4
133
 
5
134
  **🎯 EμΆ• (κ²ŒμœΌλ¦„ λ°©μ§€) 보강 β€” handoff λ‹€μŒ 단계 μžλ™ μ œμ•ˆ + 24h+ 무진척 lazy 감지.**
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.194-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v139-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-124-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-56_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-92%2F100_(5μΆ•)-brightgreen)]() [![next-actions](https://img.shields.io/badge/handoff-next_actions_μžλ™-success)]() [![perf](https://img.shields.io/badge/cold_start-479ms-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.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)]()
6
6
 
7
7
  ```
8
8
  ╔══════════════════════════════════════════════════════════════╗
@@ -12,9 +12,9 @@
12
12
  β•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β•‘
13
13
  β•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β•‘
14
14
  β•‘ β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β• β•‘
15
- β•‘ v1.9.194 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.196 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ 🎯 handoff next-actions μžλ™ μ œμ•ˆ Β· 92/100 Β· 124 λΌμš΄λ“œ β•‘
17
+ β•‘ πŸ—„ 5μΆ• 보강 μ™„λ£Œ (94/100) Β· 30일+ recall Β· 126 λΌμš΄λ“œ β•‘
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.194';
10
+ const VERSION = '1.9.196';
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 처리).
@@ -3704,6 +3704,51 @@ function handoff(root) {
3704
3704
  log(dim(` β†’ λ³€κ²½: leerness task update ${latestRow.id} --status in-progress λ˜λŠ” --status completed`));
3705
3705
  log(dim(` β†’ 회고: leerness lazy detect --json`));
3706
3706
  log('');
3707
+ // 1.9.196: DμΆ• (μž₯κΈ° λ§₯락) 보강 β€” 7일+ critical 단계 μ•Œλ¦Ό + μžλ™ 회고 ꢌμž₯
3708
+ if (ageHours >= 24 * 7) {
3709
+ const days = Math.floor(ageHours / 24);
3710
+ log(yel(` πŸ”΄ 7일+ μž₯κΈ° 정체 (${days}d) β€” μž₯κΈ° λ§₯락 손싀 μœ„ν—˜ (1.9.196 DμΆ•)`));
3711
+ log(dim(` β†’ μ¦‰μ‹œ 회고: leerness retro . --since ${days}d`));
3712
+ log(dim(` β†’ λ˜λŠ” archive: leerness task drop ${latestRow.id}`));
3713
+ log('');
3714
+ }
3715
+ }
3716
+ }
3717
+ } catch {}
3718
+ }
3719
+ // 1.9.196: DμΆ• (μž₯κΈ° λ§₯락 μœ μ§€) 보강 β€” 30일+ μ „ lessons μžλ™ 회고 (long-term memory recall)
3720
+ // keyword 와 λ§€μΉ­λ˜λŠ” 30일+ 였래된 lessons 1건 λ…ΈμΆœ β†’ μžŠν˜€μ§„ κ³Όκ±° κ΅ν›ˆ μž¬μƒκΈ°
3721
+ // 끄기: --no-longterm-recall λ˜λŠ” LEERNESS_NO_LONGTERM_RECALL=1
3722
+ if (!has('--no-longterm-recall') && !has('--quiet') && process.env.LEERNESS_NO_LONGTERM_RECALL !== '1') {
3723
+ try {
3724
+ const lp = lessonsPath(root);
3725
+ if (exists(lp)) {
3726
+ const lt = read(lp);
3727
+ const cutoff = Date.now() - 30 * 24 * 3600 * 1000;
3728
+ const fuzzyRe = new RegExp(escapeRegex(keyword.slice(0, Math.max(4, Math.floor(keyword.length * 0.7)))), 'i');
3729
+ // ### YYYY-MM-DD 블둝 뢄리 β†’ 30일+ 이전 + keyword λ§€μΉ­
3730
+ const blocks = lt.split(/\n### /).slice(1).map(b => '### ' + b);
3731
+ const matches = [];
3732
+ for (const b of blocks) {
3733
+ const m = b.match(/^### (\d{4}-\d{2}-\d{2})/);
3734
+ if (!m) continue;
3735
+ const blockDate = new Date(m[1]).getTime();
3736
+ if (isNaN(blockDate) || blockDate > cutoff) continue;
3737
+ if (fuzzyRe.test(b)) matches.push({ date: m[1], title: (b.split('\n')[0] || '').slice(0, 80) });
3738
+ }
3739
+ if (matches.length > 0) {
3740
+ const isTty = process.stdout && process.stdout.isTTY;
3741
+ const blu = s => isTty ? `\x1b[34m${s}\x1b[0m` : s;
3742
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3743
+ const oldest = matches[matches.length - 1];
3744
+ const ageDays = Math.floor((Date.now() - new Date(oldest.date).getTime()) / (24 * 3600 * 1000));
3745
+ log(blu(`## πŸ—„ μž₯κΈ° lessons 회고 (1.9.196 DμΆ•) β€” ν‚€μ›Œλ“œ "${keyword}" κ΄€λ ¨ 30일+ ${matches.length}건`));
3746
+ log(dim(` 졜였래된: ${oldest.date} (${ageDays}일 μ „) β€” ${oldest.title}`));
3747
+ if (matches.length > 1) {
3748
+ log(dim(` 졜근30일+: ${matches[0].date} β€” ${matches[0].title}`));
3749
+ }
3750
+ log(dim(` β†’ 전체 회고: cat .harness/lessons.md`));
3751
+ log('');
3707
3752
  }
3708
3753
  }
3709
3754
  } catch {}
@@ -3712,6 +3757,29 @@ function handoff(root) {
3712
3757
  }
3713
3758
  } catch {}
3714
3759
  }
3760
+ // 1.9.196: ScheduleWakeup miss detector β€” 자율 λͺ¨λ“œ μ‚¬μš©μž λͺ…μ‹œ "λͺ»μΌμ–΄λ‚˜λŠ” 경우 μ’…μ’… 있음" (1.9.191) 후속
3761
+ // λ§ˆμ§€λ§‰ session μ‹œκ°„ (handoff mtime λ˜λŠ” task-log λ§ˆμ§€λ§‰ entry) > 2h ago μ‹œ μ•Œλ¦Ό
3762
+ // 끄기: LEERNESS_NO_WAKEUP_MISS=1
3763
+ if (process.env.LEERNESS_NO_WAKEUP_MISS !== '1' && !has('--quiet') && !has('--no-wakeup-miss')) {
3764
+ try {
3765
+ const tlp = taskLogPath(root);
3766
+ if (exists(tlp)) {
3767
+ const ageMs = Date.now() - fs.statSync(tlp).mtimeMs;
3768
+ const ageMin = Math.floor(ageMs / 60000);
3769
+ // 자율 λͺ¨λ“œλŠ” ~15λΆ„ cycle. 60λΆ„ 이상 무 ν™œλ™μ΄λ©΄ wakeup miss μ˜μ‹¬ (CronCreate 13min λ°±μ—…κ³Ό ν•¨κ»˜)
3770
+ if (ageMin >= 60) {
3771
+ const isTty = process.stdout && process.stdout.isTTY;
3772
+ const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
3773
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3774
+ const label = ageMin < 120 ? `${ageMin}λΆ„` : (ageMin < 1440 ? `${Math.floor(ageMin/60)}μ‹œκ°„` : `${Math.floor(ageMin/1440)}일`);
3775
+ log(yel(`## ⏰ ScheduleWakeup miss μ˜μ‹¬ (1.9.196) β€” λ§ˆμ§€λ§‰ ν™œλ™ ${label} μ „`));
3776
+ log(dim(` 자율 λͺ¨λ“œ 정상 cycle: ~15λΆ„. 60λΆ„ 이상 무 ν™œλ™ β†’ μ‹œμŠ€ν…œ sleep λ˜λŠ” wakeup λˆ„λ½ κ°€λŠ₯μ„±`));
3777
+ log(dim(` β†’ 재개: μ‚¬μš©μžκ°€ "λ‹€μŒ λΌμš΄λ“œ" λ˜λŠ” "/loop" μž…λ ₯`));
3778
+ log('');
3779
+ }
3780
+ }
3781
+ } catch {}
3782
+ }
3715
3783
  // 1.9.121: 졜근 λ©”λͺ¨λ¦¬ 변동 μ•Œλ¦Ό β€” 24h λ‚΄ μΆ”κ°€λœ 5μ’… surface ν•­λͺ© 카운트
3716
3784
  // AI μ—μ΄μ „νŠΈκ°€ 이전 μ„Έμ…˜ μ’…λ£Œ ν›„ μ–΄λ–€ λ©”λͺ¨λ¦¬κ°€ μΆ”κ°€λλŠ”μ§€ μ¦‰μ‹œ 인지.
3717
3785
  // 끄기: --no-mem-delta λ˜λŠ” LEERNESS_NO_MEM_DELTA=1
@@ -5506,7 +5574,113 @@ function providerCmd(root, sub, ...args) {
5506
5574
  if (!dryRun) log(` .env 에 LEERNESS_ENABLE_<X>=1 μ„€μ • ν›„ \`leerness agents list\` 둜 확인`);
5507
5575
  })();
5508
5576
  }
5509
- fail(`μ•Œ 수 μ—†λŠ” sub: ${sub} (list / add / remove / sync)`);
5577
+ // 1.9.195: provider probe β€” AμΆ• (λ²”μš© AI ν•˜λ„€μŠ€) 보강. μ‚¬μš©μž μ˜λ„: "λ²”μš© AI ν•˜λ„€μŠ€ ... 졜고의 도ꡬ"
5578
+ // μ‹œμŠ€ν…œμ— μ‚¬μš© κ°€λŠ₯ν•œ provider μžλ™ 감지 (PATH λͺ…λ Ή + 둜컬 endpoint + API ν‚€ ν™˜κ²½λ³€μˆ˜)
5579
+ // 감지 λŒ€μƒ:
5580
+ // - CLI: claude / codex / gemini / copilot / ollama (PATH check)
5581
+ // - Local endpoint: Ollama (11434) / LM Studio (1234) / llama.cpp server (8080)
5582
+ // - Cloud API key: OPENROUTER_API_KEY / GROQ_API_KEY / TOGETHER_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY
5583
+ // κ²°κ³Ό β†’ table + LEERNESS_ENABLE_* μ„€μ • ꢌμž₯
5584
+ if (sub === 'probe') {
5585
+ return (async () => {
5586
+ const json = has('--json');
5587
+ const timeoutMs = Number(arg('--timeout', '1500'));
5588
+ const results = await _probeProviderEndpoints(root, timeoutMs);
5589
+ if (json) { log(JSON.stringify(results, null, 2)); return; }
5590
+ log(`# leerness provider probe (1.9.195 β€” AμΆ• λ²”μš© AI ν•˜λ„€μŠ€ 보강)`);
5591
+ log(`νƒ€μž„μ•„μ›ƒ: ${timeoutMs}ms`);
5592
+ log('');
5593
+ log('## CLI binaries (PATH)');
5594
+ log('| id | bin | found | version |');
5595
+ log('|---|---|---|---|');
5596
+ for (const r of results.cli) {
5597
+ log(`| ${r.id} | ${r.bin} | ${r.found ? 'βœ“' : 'βœ—'} | ${r.version || '-'} |`);
5598
+ }
5599
+ log('');
5600
+ log('## Local endpoint (HTTP)');
5601
+ log('| name | url | reachable | latency |');
5602
+ log('|---|---|---|---|');
5603
+ for (const r of results.endpoints) {
5604
+ log(`| ${r.name} | ${r.url} | ${r.reachable ? 'βœ“' : 'βœ—'} | ${r.latencyMs != null ? r.latencyMs + 'ms' : '-'} |`);
5605
+ }
5606
+ log('');
5607
+ log('## Cloud API keys (.env)');
5608
+ log('| key | present | mask |');
5609
+ log('|---|---|---|');
5610
+ for (const r of results.cloudKeys) {
5611
+ log(`| ${r.key} | ${r.present ? 'βœ“' : 'βœ—'} | ${r.mask || '-'} |`);
5612
+ }
5613
+ log('');
5614
+ const total = results.cli.filter(x => x.found).length + results.endpoints.filter(x => x.reachable).length + results.cloudKeys.filter(x => x.present).length;
5615
+ log(`βœ“ μ‚¬μš© κ°€λŠ₯ 후보 ${total}건`);
5616
+ log(' β†’ ν™œμ„±ν™”: .env 에 LEERNESS_ENABLE_<ID>=1 + ENDPOINT/API ν‚€ μ„€μ •');
5617
+ log(' β†’ 확인: leerness agents list');
5618
+ })();
5619
+ }
5620
+ fail(`μ•Œ 수 μ—†λŠ” sub: ${sub} (list / add / remove / sync / probe)`);
5621
+ }
5622
+
5623
+ // 1.9.195: provider probe 핡심 β€” CLI/endpoint/API ν‚€ 3μ’… 감지
5624
+ // μ˜μ‘΄μ„± 0 β€” Node built-in cp.spawnSync (CLI version) + http.get (endpoint) + process.env (API key)
5625
+ async function _probeProviderEndpoints(root, timeoutMs) {
5626
+ const result = { cli: [], endpoints: [], cloudKeys: [], at: new Date().toISOString() };
5627
+ // 1) CLI binaries β€” PATH + --version
5628
+ const cliTargets = [
5629
+ { id: 'claude', bin: 'claude' },
5630
+ { id: 'codex', bin: 'codex' },
5631
+ { id: 'gemini', bin: 'gemini' },
5632
+ { id: 'copilot', bin: 'copilot' },
5633
+ { id: 'ollama', bin: 'ollama' }
5634
+ ];
5635
+ for (const t of cliTargets) {
5636
+ try {
5637
+ const r = cp.spawnSync(t.bin, ['--version'], { encoding: 'utf8', timeout: timeoutMs, shell: true });
5638
+ // exit 0 λ˜λŠ” stdout 에 "vX.Y.Z" λΉ„μŠ·ν•œ ν˜•νƒœκ°€ 있으면 found 처리
5639
+ const out = (r.stdout || '').trim();
5640
+ const errOut = (r.stderr || '').trim();
5641
+ const looksLikeVersion = /\d+\.\d+\.\d+|\bversion\b/i.test(out);
5642
+ const found = r.status === 0 || looksLikeVersion;
5643
+ result.cli.push({ id: t.id, bin: t.bin, found, version: found ? (out.split('\n')[0].slice(0, 40) || null) : null });
5644
+ } catch (e) {
5645
+ result.cli.push({ id: t.id, bin: t.bin, found: false, version: null });
5646
+ }
5647
+ }
5648
+ // 2) Local endpoints β€” http GET (μ˜μ‘΄μ„± 0)
5649
+ const endpointTargets = [
5650
+ { name: 'ollama', url: process.env.OLLAMA_HOST || 'http://localhost:11434', path: '/api/tags' },
5651
+ { name: 'lmstudio', url: process.env.LMSTUDIO_HOST || 'http://localhost:1234', path: '/v1/models' },
5652
+ { name: 'llama.cpp', url: process.env.LLAMACPP_HOST || 'http://localhost:8080', path: '/health' }
5653
+ ];
5654
+ for (const t of endpointTargets) {
5655
+ const reach = await _probeHttpEndpoint(t.url + t.path, timeoutMs);
5656
+ result.endpoints.push({ name: t.name, url: t.url + t.path, reachable: reach.ok, latencyMs: reach.latencyMs, status: reach.status });
5657
+ }
5658
+ // 3) Cloud API keys β€” .env
5659
+ const cloudKeys = ['OPENROUTER_API_KEY', 'GROQ_API_KEY', 'TOGETHER_API_KEY', 'ANTHROPIC_API_KEY', 'OPENAI_API_KEY'];
5660
+ for (const k of cloudKeys) {
5661
+ const val = process.env[k] || '';
5662
+ const present = val.length >= 10;
5663
+ result.cloudKeys.push({ key: k, present, mask: present ? `${val.slice(0, 4)}...${val.slice(-2)}` : null });
5664
+ }
5665
+ return result;
5666
+ }
5667
+
5668
+ // 1.9.195: HTTP endpoint reachability check (μ˜μ‘΄μ„± 0)
5669
+ function _probeHttpEndpoint(url, timeoutMs) {
5670
+ return new Promise((resolve) => {
5671
+ try {
5672
+ const lib = url.startsWith('https:') ? require('https') : require('http');
5673
+ const t0 = Date.now();
5674
+ const req = lib.get(url, { timeout: timeoutMs }, (res) => {
5675
+ res.on('data', () => {});
5676
+ res.on('end', () => resolve({ ok: res.statusCode < 500, status: res.statusCode, latencyMs: Date.now() - t0 }));
5677
+ });
5678
+ req.on('timeout', () => { req.destroy(); resolve({ ok: false, latencyMs: null, status: null }); });
5679
+ req.on('error', () => resolve({ ok: false, latencyMs: null, status: null }));
5680
+ } catch {
5681
+ resolve({ ok: false, latencyMs: null, status: null });
5682
+ }
5683
+ });
5510
5684
  }
5511
5685
 
5512
5686
  // 1.9.36: μž‘μ—… ν‚€μ›Œλ“œ λΆ„μ„μœΌλ‘œ 졜적 CLI μΆ”μ²œ
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.194",
3
+ "version": "1.9.196",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",