leerness 1.9.193 β 1.9.195
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 +112 -0
- package/README.md +3 -3
- package/bin/harness.js +259 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.195 β 2026-05-21
|
|
4
|
+
|
|
5
|
+
**π AμΆ (λ²μ© AI νλ€μ€) λ³΄κ° β `leerness provider probe` μ κ· λͺ
λ Ή (CLI/endpoint/API ν€ 3μ’
μλ κ°μ§).**
|
|
6
|
+
|
|
7
|
+
μμ¨ λͺ¨λ 125 λΌμ΄λ. 1.9.192 C / 193 B / 194 E 보κ°μ μ΄μ΄ **AμΆ (9/10 β λͺ©ν 9.5/10)** 보κ°.
|
|
8
|
+
|
|
9
|
+
### μ¬μ©μ μλ μ λ ¬ (1.9.191 verbatim)
|
|
10
|
+
> *"λ²μ© AI νλ€μ€ ... μ΅κ³ μ λꡬ"*
|
|
11
|
+
|
|
12
|
+
### 1. `leerness provider probe` μ κ· λͺ
λ Ή (AμΆ ν΅μ¬)
|
|
13
|
+
- **3μ’
μλ κ°μ§** (μμ‘΄μ± 0 β Node built-in cp + http):
|
|
14
|
+
1. **CLI binaries**: claude / codex / gemini / copilot / ollama (PATH + `--version`)
|
|
15
|
+
2. **Local endpoint**: Ollama (11434) / LM Studio (1234) / llama.cpp (8080)
|
|
16
|
+
3. **Cloud API key**: OPENROUTER / GROQ / TOGETHER / ANTHROPIC / OPENAI
|
|
17
|
+
|
|
18
|
+
- **μΆλ ₯ μ΅μ
**: `--json` (μλν/CI) Β· ν
μ€νΈ λ§ν¬λ€μ΄ (μ¬λ μ½κΈ°)
|
|
19
|
+
- **νμμμ**: `--timeout 1500` (κΈ°λ³Έ, ms)
|
|
20
|
+
- **νκ²½λ³μ override**: `OLLAMA_HOST` / `LMSTUDIO_HOST` / `LLAMACPP_HOST`
|
|
21
|
+
|
|
22
|
+
### 2. μ€ μΈ‘μ (κ°λ° PC)
|
|
23
|
+
```
|
|
24
|
+
| id | bin | found | version |
|
|
25
|
+
| claude | claude | β | 2.1.146 (Claude Code) |
|
|
26
|
+
| codex | codex | β | codex-cli 0.132.0 |
|
|
27
|
+
| gemini | gemini | β | - |
|
|
28
|
+
| copilot | copilot | β | - |
|
|
29
|
+
| ollama | ollama | β | (installed) |
|
|
30
|
+
|
|
31
|
+
β μ¬μ© κ°λ₯ ν보 3건
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. μ κ· ν¨μ
|
|
35
|
+
- `_probeProviderEndpoints(root, timeoutMs)` β 3μ’
ν΅ν© κ°μ§
|
|
36
|
+
- `_probeHttpEndpoint(url, timeoutMs)` β Promise κΈ°λ° HTTP reachability check
|
|
37
|
+
|
|
38
|
+
### 4. λμ νκ· (1.9.189~194) β λͺ¨λ μ μ§
|
|
39
|
+
- [1.9.194] _suggestNextActions + lazy κ°μ§
|
|
40
|
+
- [1.9.193] agents multi consensus β lessons.md
|
|
41
|
+
- [1.9.192] _loadOfficialSkillCache + 24h μΊμ
|
|
42
|
+
- [1.9.191] ꡬ쑰 μ΅μ ν λ³΄κ³ μ 88/100
|
|
43
|
+
- [1.9.190] _selectOne/_selectMany Ctrl+C μ¦μ μ’
λ£
|
|
44
|
+
- [1.9.189] _showSlashCommandList + Tab cycle ν μ€ κ°±μ
|
|
45
|
+
|
|
46
|
+
### 5. stress-v140 β 15/15 PASS
|
|
47
|
+
- provider probe (6: ν¨μ + 3μ’
λμ + --json + ν
μ€νΈ) + μ±λ₯ (2) + λμ νκ· (7)
|
|
48
|
+
- μ±λ₯: --version cold start avg **442 ms** Β· MCP 54 λꡬ **514 ms**
|
|
49
|
+
|
|
50
|
+
### 6. 5μΆ λ§€νΈλ¦μ€ λ³λ
|
|
51
|
+
| μΆ | 1.9.194 | 1.9.195 | Ξ |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| A. λ²μ© AI νλ€μ€ | 9/10 | **9.5/10** | +0.5 (universal probe β 11 backend ν보 μλ κ°μ§) |
|
|
54
|
+
| μ’
ν© | 46/50 (92%) | **46.5/50 (93%)** | +1% |
|
|
55
|
+
|
|
56
|
+
### 7. μλ release νλ¦
|
|
57
|
+
- main μλ push **57 λΌμ΄λ μ°μ** (1.9.140~195)
|
|
58
|
+
- npm publish μλ (1.9.178~)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 1.9.194 β 2026-05-21
|
|
63
|
+
|
|
64
|
+
**π― EμΆ (κ²μΌλ¦ λ°©μ§) λ³΄κ° β handoff λ€μ λ¨κ³ μλ μ μ + 24h+ 무μ§μ² lazy κ°μ§.**
|
|
65
|
+
|
|
66
|
+
μμ¨ λͺ¨λ 124 λΌμ΄λ. 1.9.192 CμΆ / 1.9.193 BμΆ λ³΄κ°μ μ΄μ΄ **EμΆ (9/10 β λͺ©ν 9.5/10)** 보κ°.
|
|
67
|
+
|
|
68
|
+
### μ¬μ©μ μλ μ λ ¬ (1.9.191 verbatim)
|
|
69
|
+
> *"κ²μΌλ¦ λ°©μ§λ±λ± μ΅κ³ μ λꡬ"*
|
|
70
|
+
|
|
71
|
+
### 1. handoff λ€μ λ¨κ³ μλ μ μ (EμΆ ν΅μ¬)
|
|
72
|
+
- νμ¬ in-progress task description + Memory Surface (decisions/lessons/plan) μ‘°ν© β λ€μ λ¨κ³ 1-3κ° μ μ
|
|
73
|
+
- μ¬μ©μ/AI κ° "Next Exact Step" μ μ§μ μ±μ°μ§ μμλ μ¦μ λ
ΈμΆ
|
|
74
|
+
- **7κ° ν΄λ¦¬μ€ν±**:
|
|
75
|
+
1. lessons.md μ€ν¨ λ§€μΉ β ννΌ μ λ΅ μ μ© (`leerness lessons --auto`)
|
|
76
|
+
2. plan.md milestone λ§€μΉ β milestone κ²μ¦ (`leerness plan list`)
|
|
77
|
+
3. decisions.md κ²°μ λ§€μΉ β μν₯ νμΈ (`leerness decision list`)
|
|
78
|
+
4. review-evidence.md λΆμ¬ β e2e μ€ν (`node ./scripts/e2e.js`)
|
|
79
|
+
5. 24h+ μ 체 β task status κ°±μ (`leerness task update`)
|
|
80
|
+
6. λ²μ λ³λ task β CHANGELOG/README κ°±μ νμΈ (`leerness whats-new`)
|
|
81
|
+
7. stress test λλ½ β μ stress μμ± κΆμ₯
|
|
82
|
+
- λκΈ°: `--no-next-actions` λλ `LEERNESS_NO_NEXT_ACTIONS=1`
|
|
83
|
+
|
|
84
|
+
### 2. 24h+ 무 μ§μ² lazy κ°μ§
|
|
85
|
+
- progress-tracker.md mtime β₯ 24h β `## β μ§μ² μ 체 κ°μ§` μλ μΆλ ₯
|
|
86
|
+
- νμ¬ in-progress task ID + request μμ½ νμ
|
|
87
|
+
- κΆμ₯ λͺ
λ Ή: `leerness task update <id> --status` / `leerness lazy detect --json`
|
|
88
|
+
- λκΈ°: `--no-lazy-warn` λλ `LEERNESS_NO_LAZY_WARN=1`
|
|
89
|
+
|
|
90
|
+
### 3. λμ νκ· (1.9.188~193) β λͺ¨λ μ μ§
|
|
91
|
+
- [1.9.193] agents multi consensus β lessons.md μλ
|
|
92
|
+
- [1.9.192] _loadOfficialSkillCache + 24h μΊμ
|
|
93
|
+
- [1.9.191] ꡬ쑰 μ΅μ ν λ³΄κ³ μ 88/100
|
|
94
|
+
- [1.9.190] _selectOne/_selectMany Ctrl+C μ¦μ μ’
λ£
|
|
95
|
+
- [1.9.189] _showSlashCommandList + Tab cycle ν μ€ κ°±μ
|
|
96
|
+
- [1.9.188] stdin prompt μ λ¬
|
|
97
|
+
|
|
98
|
+
### 4. stress-v139 β 15/15 PASS
|
|
99
|
+
- EμΆ λ³΄κ° (6: ν¨μ + μΉμ
+ μμ μν¬μ€νμ΄μ€ ν΅ν©) + μ±λ₯ (2) + λμ νκ· (7)
|
|
100
|
+
- μμ μν¬μ€νμ΄μ€ mtime 25h κ°μ β β μ§μ² μ 체 κ°μ§ β
|
|
101
|
+
- μ±λ₯: --version cold start avg **479 ms** Β· MCP 54 λꡬ **416 ms**
|
|
102
|
+
|
|
103
|
+
### 5. 5μΆ λ§€νΈλ¦μ€ λ³λ
|
|
104
|
+
| μΆ | 1.9.193 | 1.9.194 | Ξ |
|
|
105
|
+
|---|---|---|---|
|
|
106
|
+
| E. κ²μΌλ¦ λ°©μ§ | 9/10 | **9.5/10** | +0.5 (λ€μ λ¨κ³ μλ μ μ + lazy κ°μ§) |
|
|
107
|
+
| μ’
ν© | 45.5/50 (91%) | **46/50 (92%)** | +1% |
|
|
108
|
+
|
|
109
|
+
### 6. μλ release νλ¦
|
|
110
|
+
- main μλ push **56 λΌμ΄λ μ°μ** (1.9.140~194)
|
|
111
|
+
- npm publish μλ (1.9.178~)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
3
115
|
## 1.9.193 β 2026-05-21
|
|
4
116
|
|
|
5
117
|
**π€ BμΆ (λ©ν° Sub-Agent μ€μΌμ€νΈλΌ) λ³΄κ° β agents multi consensus κ²°κ³Ό μλ lessons.md μ μ₯ + μΊμ 7μΌ stale hint.**
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **AI μ½λ© μμ΄μ νΈμ κ±°μ§ μλ£Β·μ€λ³΅Β·λ§κ°Β·μΆ©λμ λ§μμ£Όλ κ²μΒ·κΈ°μ΅Β·νμ
CLI νλ€μ€.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []() [-brightgreen)]() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
β βββ ββββββ ββββββ ββββββββββββββββββββββββ ββββββββ β
|
|
13
13
|
β βββββββββββββββββββββββββββ ββββββ ββββββββββββββββββββββ β
|
|
14
14
|
β βββββββββββββββββββββββββββ ββββββ βββββββββββββββββββββ β
|
|
15
|
-
β v1.9.
|
|
15
|
+
β v1.9.195 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
17
|
+
β π provider probe 11 backend μλ Β· 93/100 Β· 125 λΌμ΄λ β
|
|
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.
|
|
10
|
+
const VERSION = '1.9.195';
|
|
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,112 @@ async function skillAutoCacheCmd(root, sub) {
|
|
|
1662
1662
|
if (c.expired) log(` β κ°±μ : leerness skill auto-cache refresh`);
|
|
1663
1663
|
}
|
|
1664
1664
|
|
|
1665
|
+
// 1.9.194: EμΆ (κ²μΌλ¦ λ°©μ§) β handoff μμ λ€μ λ¨κ³ 1-3κ° μλ μ μ
|
|
1666
|
+
// νμ¬ in-progress task description + Memory Surface (decisions/lessons/plan) μ‘°ν© β
|
|
1667
|
+
// "λ€μ λ¨κ³λ‘ 무μμ ν μ§" μΆλ‘ (μ¬μ©μ/AI μ§μ μ
λ ₯ μμ΄ μ¦μ λ
ΈμΆ)
|
|
1668
|
+
// μκ³ λ¦¬μ¦:
|
|
1669
|
+
// 1) lessons.md μ keyword λ§€μΉ + μ€ν¨/λ‘€λ°± ν€μλ β "ννΌ μ λ΅ μ μ©"
|
|
1670
|
+
// 2) plan.md μ keyword λ§€μΉ + M-XXXX β "κ³ν milestone κ²μ¦"
|
|
1671
|
+
// 3) decisions.md μ keyword λ§€μΉ β "κ²°μ N μν₯ νμΈ"
|
|
1672
|
+
// 4) review-evidence.md λΆμ¬ β "verify-code λλ e2e μ€ν"
|
|
1673
|
+
// 5) progress-tracker.md 24h+ μ 체 β "task status κ°±μ "
|
|
1674
|
+
// 6) CHANGELOG λ³΄κ° λΆμ¬ β "λ²μ λ³κ²½ μ CHANGELOG κ°±μ "
|
|
1675
|
+
// 7) stress-vXXX λλ½ β "stress test μμ±"
|
|
1676
|
+
// 1.9.116 brainstorm νμμ λ€λ₯Έ μ : brainstorm μ "κ΄λ ¨ hits νμ" / next-actions λ "λ€μ μ€ν λͺ
λ Ή μ μ"
|
|
1677
|
+
function _suggestNextActions(root, latestRow, keyword) {
|
|
1678
|
+
const actions = [];
|
|
1679
|
+
const taskText = String(latestRow.request || '').toLowerCase();
|
|
1680
|
+
const fuzzyRe = keyword ? new RegExp(escapeRegex(keyword.slice(0, Math.max(4, Math.floor(keyword.length * 0.7)))), 'i') : null;
|
|
1681
|
+
|
|
1682
|
+
// 1) lessons.md μ€ν¨ λ§€μΉ β ννΌ μ λ΅
|
|
1683
|
+
try {
|
|
1684
|
+
if (fuzzyRe && exists(lessonsPath(root))) {
|
|
1685
|
+
const lt = read(lessonsPath(root));
|
|
1686
|
+
const blocks = lt.split(/\n### /);
|
|
1687
|
+
const hits = blocks.filter(b => fuzzyRe.test(b) && /(μ€ν¨|fail|λ‘€λ°±|λ²κ·Έ|incomplete)/i.test(b));
|
|
1688
|
+
if (hits.length > 0) {
|
|
1689
|
+
actions.push({ icon: 'π‘', title: `κ³Όκ±° μ€ν¨ ννΌ β lessons.md μ "${keyword}" κ΄λ ¨ ${hits.length}건`, command: `leerness lessons --auto --path .` });
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
} catch {}
|
|
1693
|
+
|
|
1694
|
+
// 2) plan.md milestone λ§€μΉ β milestone κ²μ¦
|
|
1695
|
+
try {
|
|
1696
|
+
if (fuzzyRe && exists(planPath(root))) {
|
|
1697
|
+
const pt = read(planPath(root));
|
|
1698
|
+
const milestones = (pt.match(/^### (M-\d{4})\..*$/gm) || []).filter(l => fuzzyRe.test(l));
|
|
1699
|
+
if (milestones.length > 0) {
|
|
1700
|
+
const m = milestones[0].match(/M-\d{4}/);
|
|
1701
|
+
if (m) actions.push({ icon: 'π―', title: `plan.md milestone ${m[0]} κ²μ¦ β "${keyword}" κ΄λ ¨`, command: `leerness plan list --filter "${keyword}"` });
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
} catch {}
|
|
1705
|
+
|
|
1706
|
+
// 3) decisions.md κ²°μ λ§€μΉ
|
|
1707
|
+
try {
|
|
1708
|
+
if (fuzzyRe && exists(decisionsPath(root))) {
|
|
1709
|
+
const dt = read(decisionsPath(root));
|
|
1710
|
+
const blocks = _extractDecisionBlocks(dt);
|
|
1711
|
+
const hits = blocks.filter(b => fuzzyRe.test(b));
|
|
1712
|
+
if (hits.length > 0) {
|
|
1713
|
+
actions.push({ icon: 'π', title: `decisions.md "${keyword}" κ΄λ ¨ κ²°μ ${hits.length}건 μν₯ νμΈ`, command: `leerness decision list --filter "${keyword}"` });
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
} catch {}
|
|
1717
|
+
|
|
1718
|
+
// 4) review-evidence.md λΆμ¬ β e2e
|
|
1719
|
+
try {
|
|
1720
|
+
if (!exists(evidencePath(root)) || fs.statSync(evidencePath(root)).size < 100) {
|
|
1721
|
+
actions.push({ icon: 'π§ͺ', title: `review-evidence.md λΉμ΄μμ β e2e λλ verify-code μ€ν`, command: `node ./scripts/e2e.js` });
|
|
1722
|
+
}
|
|
1723
|
+
} catch {}
|
|
1724
|
+
|
|
1725
|
+
// 5) 24h+ μ 체 β task status κ°±μ (handoff lazy-warn κ³Ό λ³κ° β λ€μ λ¨κ³ λͺ
λ Ή)
|
|
1726
|
+
try {
|
|
1727
|
+
const pp = progressPath(root);
|
|
1728
|
+
if (exists(pp)) {
|
|
1729
|
+
const ageHours = Math.floor((Date.now() - fs.statSync(pp).mtimeMs) / 3600000);
|
|
1730
|
+
if (ageHours >= 24 && latestRow.id) {
|
|
1731
|
+
actions.push({ icon: 'π', title: `progress-tracker ${ageHours}h μ 체 β task ${latestRow.id} status κ°±μ `, command: `leerness task update ${latestRow.id} --status completed` });
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
} catch {}
|
|
1735
|
+
|
|
1736
|
+
// 6) CHANGELOG / README λ²μ μΌμΉ νμΈ (1.9.X bump ν μμ£Ό λλ½λλ λ¨κ³)
|
|
1737
|
+
try {
|
|
1738
|
+
if (/(\d\.\d\.\d+)/.test(taskText) || /(bump|version|release)/i.test(taskText)) {
|
|
1739
|
+
actions.push({ icon: 'π', title: `λ²μ λ³λ task β CHANGELOG.md / README.md κ°±μ νμΈ`, command: `node ./bin/harness.js whats-new .` });
|
|
1740
|
+
}
|
|
1741
|
+
} catch {}
|
|
1742
|
+
|
|
1743
|
+
// 7) stress test λλ½ (μμ¨ λΌμ΄λ μμ£Ό λλ½)
|
|
1744
|
+
try {
|
|
1745
|
+
const stressDir = path.resolve(root, '..', '_apps', 'leerness-stress', 'bin');
|
|
1746
|
+
if (exists(stressDir)) {
|
|
1747
|
+
const files = fs.readdirSync(stressDir).filter(f => /^stress-v\d+\.js$/.test(f));
|
|
1748
|
+
if (files.length > 0) {
|
|
1749
|
+
const versions = files.map(f => Number(f.match(/v(\d+)/)[1])).sort((a, b) => b - a);
|
|
1750
|
+
const latest = versions[0];
|
|
1751
|
+
// νμ¬ λΌμ΄λ = 1.9.X μμ stress-v(X-55) μ λ? λ¨μν μ΅μ stress κ° 7μΌ+ μ€λλλ©΄ κΆμ₯
|
|
1752
|
+
const latestFile = path.join(stressDir, `stress-v${latest}.js`);
|
|
1753
|
+
const ageHours = Math.floor((Date.now() - fs.statSync(latestFile).mtimeMs) / 3600000);
|
|
1754
|
+
if (ageHours >= 24 && /(bump|version|보κ°|μΆκ°|κΈ°λ₯)/.test(taskText)) {
|
|
1755
|
+
actions.push({ icon: 'π§¬', title: `stress-v${latest} λ§μ§λ§ κ°±μ ${ageHours}h μ β μ stress test μμ± κΆμ₯`, command: `node _apps/leerness-stress/bin/stress-v${latest+1}.js` });
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
} catch {}
|
|
1760
|
+
|
|
1761
|
+
// μ€λ³΅ μ κ±° (icon+title κΈ°μ€) + top 3
|
|
1762
|
+
const seen = new Set();
|
|
1763
|
+
return actions.filter(a => {
|
|
1764
|
+
const key = a.icon + a.title.slice(0, 30);
|
|
1765
|
+
if (seen.has(key)) return false;
|
|
1766
|
+
seen.add(key);
|
|
1767
|
+
return true;
|
|
1768
|
+
}).slice(0, 3);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1665
1771
|
// 1.9.182: handoff 컨ν
μ€νΈ (νμ¬ in-progress task) μμ μλ query μΆμΆ
|
|
1666
1772
|
function _autoInstallQueryFromHandoff(root) {
|
|
1667
1773
|
try {
|
|
@@ -3557,6 +3663,51 @@ function handoff(root) {
|
|
|
3557
3663
|
}
|
|
3558
3664
|
} catch {}
|
|
3559
3665
|
}
|
|
3666
|
+
// 1.9.194: EμΆ (κ²μΌλ¦ λ°©μ§) λ³΄κ° β handoff λ€μ λ¨κ³ 1-3κ° μλ μ μ
|
|
3667
|
+
// νμ¬ in-progress task description + Memory Surface (decisions/lessons/plan) μ‘°ν© β
|
|
3668
|
+
// "λ€μ λ¨κ³λ‘ 무μμ ν μ§" 3κ°λ₯Ό μ¦μ μ μ (μ¬μ©μκ° μ§μ μ±μ°μ§ μμλ AIμκ² λ
ΈμΆλ¨)
|
|
3669
|
+
// skill installed μ¬λΆμ λ¬΄κ΄ β keyword λ§ μμΌλ©΄ λμ (κ²μΌλ¦ λ°©μ§λ λͺ¨λ μν¬μ€νμ΄μ€ νμ)
|
|
3670
|
+
// λκΈ°: --no-next-actions λλ LEERNESS_NO_NEXT_ACTIONS=1
|
|
3671
|
+
if (!has('--no-next-actions') && !has('--quiet') && process.env.LEERNESS_NO_NEXT_ACTIONS !== '1') {
|
|
3672
|
+
try {
|
|
3673
|
+
const actions = _suggestNextActions(root, latestRow, keyword);
|
|
3674
|
+
if (actions.length > 0) {
|
|
3675
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
3676
|
+
const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
3677
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
3678
|
+
log(grn(`## π― λ€μ λ¨κ³ μλ μ μ (1.9.194 EμΆ β κ²μΌλ¦ λ°©μ§) β ν€μλ "${keyword}"`));
|
|
3679
|
+
for (const a of actions) {
|
|
3680
|
+
log(dim(` ${a.icon} ${a.title}`));
|
|
3681
|
+
if (a.command) log(dim(` \`${a.command}\``));
|
|
3682
|
+
}
|
|
3683
|
+
log(dim(` β μ§μ μ
λ ₯: leerness next-action add "<text>"`));
|
|
3684
|
+
log('');
|
|
3685
|
+
}
|
|
3686
|
+
} catch {}
|
|
3687
|
+
}
|
|
3688
|
+
// 1.9.194: 24h+ 무 μ§μ² lazy κ°μ§ β progress-tracker mtime κΈ°λ°
|
|
3689
|
+
// νμ¬ in-progress task κ° 24h μ΄μ λ³λ μμΌλ©΄ "lazy μμ¬" hint
|
|
3690
|
+
// λκΈ°: --no-lazy-warn λλ LEERNESS_NO_LAZY_WARN=1
|
|
3691
|
+
if (!has('--no-lazy-warn') && !has('--quiet') && process.env.LEERNESS_NO_LAZY_WARN !== '1') {
|
|
3692
|
+
try {
|
|
3693
|
+
const pp = progressPath(root);
|
|
3694
|
+
if (exists(pp)) {
|
|
3695
|
+
const ageMs = Date.now() - fs.statSync(pp).mtimeMs;
|
|
3696
|
+
const ageHours = Math.floor(ageMs / 3600000);
|
|
3697
|
+
if (ageHours >= 24) {
|
|
3698
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
3699
|
+
const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
3700
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
3701
|
+
const ageLabel = ageHours < 48 ? `${ageHours}h` : `${Math.floor(ageHours/24)}d`;
|
|
3702
|
+
log(yel(`## β μ§μ² μ 체 κ°μ§ (1.9.194 EμΆ) β progress-tracker λ§μ§λ§ λ³λ ${ageLabel} μ `));
|
|
3703
|
+
log(dim(` νμ¬ in-progress task: ${latestRow.id} ${(latestRow.request || '').slice(0, 60)}`));
|
|
3704
|
+
log(dim(` β λ³κ²½: leerness task update ${latestRow.id} --status in-progress λλ --status completed`));
|
|
3705
|
+
log(dim(` β νκ³ : leerness lazy detect --json`));
|
|
3706
|
+
log('');
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
} catch {}
|
|
3710
|
+
}
|
|
3560
3711
|
}
|
|
3561
3712
|
}
|
|
3562
3713
|
} catch {}
|
|
@@ -5355,7 +5506,113 @@ function providerCmd(root, sub, ...args) {
|
|
|
5355
5506
|
if (!dryRun) log(` .env μ LEERNESS_ENABLE_<X>=1 μ€μ ν \`leerness agents list\` λ‘ νμΈ`);
|
|
5356
5507
|
})();
|
|
5357
5508
|
}
|
|
5358
|
-
|
|
5509
|
+
// 1.9.195: provider probe β AμΆ (λ²μ© AI νλ€μ€) 보κ°. μ¬μ©μ μλ: "λ²μ© AI νλ€μ€ ... μ΅κ³ μ λꡬ"
|
|
5510
|
+
// μμ€ν
μ μ¬μ© κ°λ₯ν provider μλ κ°μ§ (PATH λͺ
λ Ή + λ‘컬 endpoint + API ν€ νκ²½λ³μ)
|
|
5511
|
+
// κ°μ§ λμ:
|
|
5512
|
+
// - CLI: claude / codex / gemini / copilot / ollama (PATH check)
|
|
5513
|
+
// - Local endpoint: Ollama (11434) / LM Studio (1234) / llama.cpp server (8080)
|
|
5514
|
+
// - Cloud API key: OPENROUTER_API_KEY / GROQ_API_KEY / TOGETHER_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY
|
|
5515
|
+
// κ²°κ³Ό β table + LEERNESS_ENABLE_* μ€μ κΆμ₯
|
|
5516
|
+
if (sub === 'probe') {
|
|
5517
|
+
return (async () => {
|
|
5518
|
+
const json = has('--json');
|
|
5519
|
+
const timeoutMs = Number(arg('--timeout', '1500'));
|
|
5520
|
+
const results = await _probeProviderEndpoints(root, timeoutMs);
|
|
5521
|
+
if (json) { log(JSON.stringify(results, null, 2)); return; }
|
|
5522
|
+
log(`# leerness provider probe (1.9.195 β AμΆ λ²μ© AI νλ€μ€ 보κ°)`);
|
|
5523
|
+
log(`νμμμ: ${timeoutMs}ms`);
|
|
5524
|
+
log('');
|
|
5525
|
+
log('## CLI binaries (PATH)');
|
|
5526
|
+
log('| id | bin | found | version |');
|
|
5527
|
+
log('|---|---|---|---|');
|
|
5528
|
+
for (const r of results.cli) {
|
|
5529
|
+
log(`| ${r.id} | ${r.bin} | ${r.found ? 'β' : 'β'} | ${r.version || '-'} |`);
|
|
5530
|
+
}
|
|
5531
|
+
log('');
|
|
5532
|
+
log('## Local endpoint (HTTP)');
|
|
5533
|
+
log('| name | url | reachable | latency |');
|
|
5534
|
+
log('|---|---|---|---|');
|
|
5535
|
+
for (const r of results.endpoints) {
|
|
5536
|
+
log(`| ${r.name} | ${r.url} | ${r.reachable ? 'β' : 'β'} | ${r.latencyMs != null ? r.latencyMs + 'ms' : '-'} |`);
|
|
5537
|
+
}
|
|
5538
|
+
log('');
|
|
5539
|
+
log('## Cloud API keys (.env)');
|
|
5540
|
+
log('| key | present | mask |');
|
|
5541
|
+
log('|---|---|---|');
|
|
5542
|
+
for (const r of results.cloudKeys) {
|
|
5543
|
+
log(`| ${r.key} | ${r.present ? 'β' : 'β'} | ${r.mask || '-'} |`);
|
|
5544
|
+
}
|
|
5545
|
+
log('');
|
|
5546
|
+
const total = results.cli.filter(x => x.found).length + results.endpoints.filter(x => x.reachable).length + results.cloudKeys.filter(x => x.present).length;
|
|
5547
|
+
log(`β μ¬μ© κ°λ₯ ν보 ${total}건`);
|
|
5548
|
+
log(' β νμ±ν: .env μ LEERNESS_ENABLE_<ID>=1 + ENDPOINT/API ν€ μ€μ ');
|
|
5549
|
+
log(' β νμΈ: leerness agents list');
|
|
5550
|
+
})();
|
|
5551
|
+
}
|
|
5552
|
+
fail(`μ μ μλ sub: ${sub} (list / add / remove / sync / probe)`);
|
|
5553
|
+
}
|
|
5554
|
+
|
|
5555
|
+
// 1.9.195: provider probe ν΅μ¬ β CLI/endpoint/API ν€ 3μ’
κ°μ§
|
|
5556
|
+
// μμ‘΄μ± 0 β Node built-in cp.spawnSync (CLI version) + http.get (endpoint) + process.env (API key)
|
|
5557
|
+
async function _probeProviderEndpoints(root, timeoutMs) {
|
|
5558
|
+
const result = { cli: [], endpoints: [], cloudKeys: [], at: new Date().toISOString() };
|
|
5559
|
+
// 1) CLI binaries β PATH + --version
|
|
5560
|
+
const cliTargets = [
|
|
5561
|
+
{ id: 'claude', bin: 'claude' },
|
|
5562
|
+
{ id: 'codex', bin: 'codex' },
|
|
5563
|
+
{ id: 'gemini', bin: 'gemini' },
|
|
5564
|
+
{ id: 'copilot', bin: 'copilot' },
|
|
5565
|
+
{ id: 'ollama', bin: 'ollama' }
|
|
5566
|
+
];
|
|
5567
|
+
for (const t of cliTargets) {
|
|
5568
|
+
try {
|
|
5569
|
+
const r = cp.spawnSync(t.bin, ['--version'], { encoding: 'utf8', timeout: timeoutMs, shell: true });
|
|
5570
|
+
// exit 0 λλ stdout μ "vX.Y.Z" λΉμ·ν ννκ° μμΌλ©΄ found μ²λ¦¬
|
|
5571
|
+
const out = (r.stdout || '').trim();
|
|
5572
|
+
const errOut = (r.stderr || '').trim();
|
|
5573
|
+
const looksLikeVersion = /\d+\.\d+\.\d+|\bversion\b/i.test(out);
|
|
5574
|
+
const found = r.status === 0 || looksLikeVersion;
|
|
5575
|
+
result.cli.push({ id: t.id, bin: t.bin, found, version: found ? (out.split('\n')[0].slice(0, 40) || null) : null });
|
|
5576
|
+
} catch (e) {
|
|
5577
|
+
result.cli.push({ id: t.id, bin: t.bin, found: false, version: null });
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5580
|
+
// 2) Local endpoints β http GET (μμ‘΄μ± 0)
|
|
5581
|
+
const endpointTargets = [
|
|
5582
|
+
{ name: 'ollama', url: process.env.OLLAMA_HOST || 'http://localhost:11434', path: '/api/tags' },
|
|
5583
|
+
{ name: 'lmstudio', url: process.env.LMSTUDIO_HOST || 'http://localhost:1234', path: '/v1/models' },
|
|
5584
|
+
{ name: 'llama.cpp', url: process.env.LLAMACPP_HOST || 'http://localhost:8080', path: '/health' }
|
|
5585
|
+
];
|
|
5586
|
+
for (const t of endpointTargets) {
|
|
5587
|
+
const reach = await _probeHttpEndpoint(t.url + t.path, timeoutMs);
|
|
5588
|
+
result.endpoints.push({ name: t.name, url: t.url + t.path, reachable: reach.ok, latencyMs: reach.latencyMs, status: reach.status });
|
|
5589
|
+
}
|
|
5590
|
+
// 3) Cloud API keys β .env
|
|
5591
|
+
const cloudKeys = ['OPENROUTER_API_KEY', 'GROQ_API_KEY', 'TOGETHER_API_KEY', 'ANTHROPIC_API_KEY', 'OPENAI_API_KEY'];
|
|
5592
|
+
for (const k of cloudKeys) {
|
|
5593
|
+
const val = process.env[k] || '';
|
|
5594
|
+
const present = val.length >= 10;
|
|
5595
|
+
result.cloudKeys.push({ key: k, present, mask: present ? `${val.slice(0, 4)}...${val.slice(-2)}` : null });
|
|
5596
|
+
}
|
|
5597
|
+
return result;
|
|
5598
|
+
}
|
|
5599
|
+
|
|
5600
|
+
// 1.9.195: HTTP endpoint reachability check (μμ‘΄μ± 0)
|
|
5601
|
+
function _probeHttpEndpoint(url, timeoutMs) {
|
|
5602
|
+
return new Promise((resolve) => {
|
|
5603
|
+
try {
|
|
5604
|
+
const lib = url.startsWith('https:') ? require('https') : require('http');
|
|
5605
|
+
const t0 = Date.now();
|
|
5606
|
+
const req = lib.get(url, { timeout: timeoutMs }, (res) => {
|
|
5607
|
+
res.on('data', () => {});
|
|
5608
|
+
res.on('end', () => resolve({ ok: res.statusCode < 500, status: res.statusCode, latencyMs: Date.now() - t0 }));
|
|
5609
|
+
});
|
|
5610
|
+
req.on('timeout', () => { req.destroy(); resolve({ ok: false, latencyMs: null, status: null }); });
|
|
5611
|
+
req.on('error', () => resolve({ ok: false, latencyMs: null, status: null }));
|
|
5612
|
+
} catch {
|
|
5613
|
+
resolve({ ok: false, latencyMs: null, status: null });
|
|
5614
|
+
}
|
|
5615
|
+
});
|
|
5359
5616
|
}
|
|
5360
5617
|
|
|
5361
5618
|
// 1.9.36: μμ
ν€μλ λΆμμΌλ‘ μ΅μ CLI μΆμ²
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.195",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|