leerness 1.9.179 β 1.9.181
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 +139 -0
- package/README.md +3 -3
- package/bin/harness.js +80 -61
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,144 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.181 β 2026-05-21
|
|
4
|
+
|
|
5
|
+
**πͺ REPL μ§μ
νλ¦ μ 리 β μ¬μ©μ λͺ
μ 4μ’
+ μ§μ ꡬλ μ€ νΈμΆ κ²μ¦.**
|
|
6
|
+
|
|
7
|
+
μμ¨ λͺ¨λ 111 λΌμ΄λ. μ¬μ©μ μ§μ ꡬλ ν
μ€νΈ κ²°κ³Ό λ³΄κ³ (μ€ν¬λ¦°μ· 첨λΆ):
|
|
8
|
+
1. *"1.9.149 Hermes/OpenClaw μ€νμΌ λ±μ 문ꡬλ μ κ±°"* β μ€μΉ μλ£ λ©μμ§ λ¨μν
|
|
9
|
+
2. *"μ΄ λ¨κ³μμ Ollama μ μΈν λͺ¨λΈμ μ ννλλ° REPL μ§μ
μ Ollama μ°μ νΈμΆ"* β installβREPL provider μλ μ ν
|
|
10
|
+
3. *"νλ‘λ°μ΄λ μ ν μ ν λ¨κ³ μμ΄ λ°λ‘ μ±ν
λͺ¨λλ‘ μ§μ
"* β μ§μ
prompt μ κ±°
|
|
11
|
+
4. *"REPLμ μ§μ ꡬλν΄μ λͺ
λ Ή μ
λ ₯ν΄λ³΄κ³ κ°λ°/μΉ/PC/μΆλ‘ /μ§λ¬Έ-λ΅λ³ λμ ν
μ€νΈ"* β agents multi --execute μ€ νΈμΆ κ²μ¦
|
|
12
|
+
|
|
13
|
+
### Fix #1 β 문ꡬ λ¨μν
|
|
14
|
+
```diff
|
|
15
|
+
- log('π μ€μΉ μλ£ β REPL agent λͺ¨λλ₯Ό μμν©λλ€ (1.9.149 Hermes/OpenClaw μ€νμΌ)...');
|
|
16
|
+
+ log('π μ€μΉ μλ£ β REPL agent λͺ¨λλ₯Ό μμν©λλ€...');
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Fix #2 β installβREPL provider νλμ½λ© μ κ±°
|
|
20
|
+
```diff
|
|
21
|
+
- await _agentRepl(root, { provider: 'ollama', role: 'actor' }); // 1.9.151 β 무쑰건 ollama
|
|
22
|
+
+ await _agentRepl(root, { role: 'actor' }); // provider λ―Έμ§μ β auto-select λμ (1.9.181 fix)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Fix #3 β λΉ-Ollama μ°μ μλ μ ν (Ollama μ°μ νΈμΆ X)
|
|
26
|
+
```js
|
|
27
|
+
const ready = EXTERNAL_AGENTS.map(a => ({ def: a, status: _checkAgent(a) }))
|
|
28
|
+
.filter(x => x.status.status === 'ready');
|
|
29
|
+
const nonOllama = ready.filter(x => x.def.id !== 'ollama');
|
|
30
|
+
if (nonOllama.length >= 1) {
|
|
31
|
+
// λΉ-Ollama νμ± β 첫 λ²μ§Έ μλ (μ¬μ©μ λͺ
μ: Ollama μ°μ νΈμΆ X)
|
|
32
|
+
initialProvider = nonOllama[0].def.id;
|
|
33
|
+
_autoPickNote = nonOllama.length === 1
|
|
34
|
+
? `${initialProvider} μλ μ ν (νμ± CLI 1κ°)`
|
|
35
|
+
: `${initialProvider} μλ μ ν (νμ± CLI ${nonOllama.length}κ° Β· TabμΌλ‘ μ ν)`;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Fix #4 β provider μ ν prompt λ¨κ³ μ κ±° (μλ μ ν)
|
|
40
|
+
μ΄μ :
|
|
41
|
+
```
|
|
42
|
+
β Ollama λ―Έκ°λ λλ λͺ¨λΈ μμ
|
|
43
|
+
π‘ νμ± μΈλΆ CLI 4κ° λ°κ²¬ β provider μ ν κ°λ₯:
|
|
44
|
+
1) claude (v2.1.145)
|
|
45
|
+
2) codex (vcodex-cli 0.132.0)
|
|
46
|
+
...
|
|
47
|
+
provider μ ν (λ²νΈ / Enter=ollama κ³μ): _
|
|
48
|
+
```
|
|
49
|
+
μ§κΈ:
|
|
50
|
+
```
|
|
51
|
+
βΈ Provider: claude μλ μ ν (νμ± CLI 4κ° Β· TabμΌλ‘ μ ν)
|
|
52
|
+
[μ±ν
λͺ¨λ μ¦μ μ§μ
]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### μ§μ ꡬλ μ€ νΈμΆ κ²μ¦ (μ¬μ©μ λͺ
μ 4λ²μ§Έ μμ²)
|
|
56
|
+
```bash
|
|
57
|
+
$ leerness agents multi "1+1=? μ«μλ§ λ΅ν΄μ£ΌμΈμ." --only claude,gemini --execute --timeout 30
|
|
58
|
+
β claude Β· 4810ms Β· 1 ν ν°
|
|
59
|
+
β gemini Β· 1266ms Β· exit=null
|
|
60
|
+
best: claude Β· score=0.600
|
|
61
|
+
--- μ²μ 600μ ---
|
|
62
|
+
2
|
|
63
|
+
```
|
|
64
|
+
**claude μΆλ‘ μλ΅ μ μ**. geminiλ λ³λ νκ²½ μ΄μ (--yolo κΆν λλ quota β 1.9.182μμ μΆκ° λλ²κ·Έ ν보).
|
|
65
|
+
|
|
66
|
+
### Verified
|
|
67
|
+
- stress-v126: **18/18** (μ¬μ©μ λͺ
μ 4 + μλ μ ν λμ 4 + μ§μ ꡬλ 2 + VERSION+λμ νκ· 8)
|
|
68
|
+
- e2e 217/217 baseline μ μ§
|
|
69
|
+
- claude μ€ νΈμΆ 4810ms Β· μλ΅ "2" β REPL agentμ ν΅μ¬ λ₯λ ₯ (μ€ λͺ¨λΈ νΈμΆ + μΆλ‘ + μλ΅ μμ ) λμ νμΈ
|
|
70
|
+
- VERSION = 1.9.181 Β· autonomous-rounds = 111 Β· main μλ push 42 λΌμ΄λ μ°μ
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 1.9.180 β 2026-05-21
|
|
75
|
+
|
|
76
|
+
**π§ REPL Tab cycle ν΅μ¬ fix + μ±ν
μμ separator β μ¬μ©μ λͺ
μ (μ§μ ꡬλ ν
μ€νΈ κ²°κ³Ό).**
|
|
77
|
+
|
|
78
|
+
μμ¨ λͺ¨λ 110 λΌμ΄λ. μ¬μ©μ λͺ
μ: *"REPL agent λͺ¨λλ₯Ό λ€κ° μ§μ ꡬλν΄μ ν
μ€νΈν΄μ€ / REPL agent λͺ¨λλ κ³ μ λ ν€λμ μ±ν
νμμ΄μ΄μΌν΄ / κ·Έλ¦¬κ³ λͺ¨λΈμ΄λ νλ‘λ°μ΄λ μ νμ΄ μννμ§μμκ±°κ°μ"*.
|
|
79
|
+
|
|
80
|
+
### ν΅μ¬ fix β Tab cycle μ€ λμ 보μ₯
|
|
81
|
+
|
|
82
|
+
#### 1. readline `completer` no-op
|
|
83
|
+
```js
|
|
84
|
+
// 1.9.180: completer no-op β readlineμ μ체 Tab completionμ΄ keypress 리μ€λλ₯Ό κ°λ‘μ±λ λ¬Έμ μ°¨λ¨
|
|
85
|
+
const rl = readline.createInterface({
|
|
86
|
+
input: process.stdin,
|
|
87
|
+
output: process.stdout,
|
|
88
|
+
completer: (line) => [[], line]
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
μ΄μ : μ¬μ©μκ° Tabμ λλ₯΄λ©΄ readline κΈ°λ³Έ completerκ° λΉ κ²°κ³Όλ₯Ό νμνλ©° promptλ₯Ό μ¬μΆλ ₯ν΄ keypress 리μ€λκ° λμνμ§ μμ λκ° μμμ.
|
|
92
|
+
μ§κΈ: `completer: () => [[], line]` λͺ
μλ‘ readlineμ Tab κ°λ‘μ±κΈ° μ°¨λ¨ β keypress 리μ€λκ° νμ λ°λ.
|
|
93
|
+
|
|
94
|
+
#### 2. Shift+Tab β `cycleModel(false)` λ§€ν μμ (CRITICAL)
|
|
95
|
+
```js
|
|
96
|
+
process.stdin.on('keypress', (str, key) => {
|
|
97
|
+
if (!key) return;
|
|
98
|
+
if (key.name === 'tab') {
|
|
99
|
+
// 1.9.180 fix: Shift+Tab β cycleModel (μ΄μ cycleProvider μλͺ»)
|
|
100
|
+
if (key.shift === true) {
|
|
101
|
+
cycleModel(false); // Shift+Tab β νμ¬ providerμ λͺ¨λΈ cycle
|
|
102
|
+
} else {
|
|
103
|
+
cycleProvider(false); // Tab β λ€μ provider
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
μ΄μ (1.9.170): `cycleProvider(key.shift)` β Shift+Tabμ provider reverse μκ³ model cycle ν€κ° μμμ.
|
|
109
|
+
μ§κΈ: μ¬μ©μ μλλλ‘ `Tab=provider`, `Shift+Tab=model`.
|
|
110
|
+
|
|
111
|
+
### μκ° νΌλλ°± κ°ν (μ¬μ©μ λͺ
μ: "μννμ§ μμ")
|
|
112
|
+
```
|
|
113
|
+
β provider [3/5]: claude β ready
|
|
114
|
+
β 7κ° λͺ¨λΈ catalog Β· Shift+TabμΌλ‘ model cycle
|
|
115
|
+
|
|
116
|
+
β model [2/7]: claude-opus-4
|
|
117
|
+
β μ΅μ thinking λͺ¨λΈ
|
|
118
|
+
```
|
|
119
|
+
- bold green provider Β· bold magenta model
|
|
120
|
+
- `[idx/total]` μμΉ/μ΄μ νμ
|
|
121
|
+
- ready/β status νμ± μ¬λΆ νμ
|
|
122
|
+
- catalog λͺ¨λΈ μ λ
ΈμΆ
|
|
123
|
+
|
|
124
|
+
### μ±ν
μμ separator (μ¬μ©μ λͺ
μ: "κ³ μ λ ν€λμ μ±ν
νμ")
|
|
125
|
+
```
|
|
126
|
+
[... νμ νλ©΄ (ν€λ + Tips + What's new + Slash + ν€λ³΄λ + μνλ°) ...]
|
|
127
|
+
|
|
128
|
+
βββββββββββββββββββββββββββββ μ±ν
μμ βββββββββββββββββββββββββββββ
|
|
129
|
+
λ©μμ§ μ
λ ₯ ν Enter Β· :help μΌλ‘ λͺ
λ Ή λͺ©λ‘ Β· Ctrl+C λ‘ μ’
λ£
|
|
130
|
+
|
|
131
|
+
agent[ollama/actor/βΆ]> _
|
|
132
|
+
```
|
|
133
|
+
νμ νλ©΄ (κ³ μ ν€λ) κ³Ό μ
λ ₯ μμ (μ±ν
) μ μκ°μ ꡬλΆμ λͺ
ννκ².
|
|
134
|
+
|
|
135
|
+
### Verified
|
|
136
|
+
- e2e 217/217 baseline μ μ§
|
|
137
|
+
- stress-v125: **17/17** (Tab cycle fix 3 + μκ° νΌλλ°± 4 + μ±ν
μμ 3 + λμ νκ· 7)
|
|
138
|
+
- VERSION = 1.9.180 Β· autonomous-rounds = 110 Β· main μλ push 41 λΌμ΄λ μ°μ
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
3
142
|
## 1.9.179 β 2026-05-21
|
|
4
143
|
|
|
5
144
|
**π¨ REPL νμ νλ©΄ μ¬λμμΈ β Hermes/Claude/Codex/Gemini CLI μ€νμΌ (μ¬μ©μ λͺ
μ).**
|
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) []() []() []() []() []() []() []() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
β βββ ββββββ ββββββ ββββββββββββββββββββββββ ββββββββ β
|
|
13
13
|
β βββββββββββββββββββββββββββ ββββββ ββββββββββββββββββββββ β
|
|
14
14
|
β βββββββββββββββββββββββββββ ββββββ βββββββββββββββββββββ β
|
|
15
|
-
β v1.9.
|
|
15
|
+
β v1.9.181 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
17
|
+
β πͺ REPL μ§μ
νλ¦ μ 리 (provider μλ μ ν Β· μ€νΈμΆ κ²μ¦) β
|
|
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.181';
|
|
11
11
|
const MARK = '<!-- leerness:managed -->';
|
|
12
12
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
13
13
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -934,12 +934,13 @@ async function install(root, opts = {}) {
|
|
|
934
934
|
// resolveInstallOptions (1.9.146) κ° μ΄λ―Έ λͺ¨λ prompt λͺ¨μ μμΉμ ν΅ν©λ 4μ§μ λ€ prompt μμ.
|
|
935
935
|
// λ³λ setupAgents λͺ
λ Ήμ μ¬μ©μκ° λͺ
μμ μΌλ‘ `leerness setup-agents` νΈμΆ μμλ§.
|
|
936
936
|
// 1.9.151: μ€μΉ μλ£ μ§ν β startRepl μ ν μ REPL agent λͺ¨λ μ¦μ μ§μ
(μ¬μ©μ λͺ
μ μμ²)
|
|
937
|
+
// 1.9.181: 문ꡬ λ¨μν + provider νλμ½λ© μ κ±° (μ¬μ©μ λͺ
μ β install μ νν CLIλ₯Ό REPLμ΄ μλ μ ν)
|
|
937
938
|
if (resolved.startRepl && !opts.migration && process.stdin.isTTY && process.env.LEERNESS_NO_PROMPT !== '1') {
|
|
938
939
|
log('');
|
|
939
|
-
log('π μ€μΉ μλ£ β REPL agent λͺ¨λλ₯Ό
|
|
940
|
+
log('π μ€μΉ μλ£ β REPL agent λͺ¨λλ₯Ό μμν©λλ€...');
|
|
940
941
|
log('');
|
|
941
942
|
try {
|
|
942
|
-
await _agentRepl(root, {
|
|
943
|
+
await _agentRepl(root, { role: 'actor' }); // provider λ―Έμ§μ β _agentRepl μ auto-select λμ (1.9.181 fix)
|
|
943
944
|
} catch (e) { warn('REPL μ§μ
μ€ν¨: ' + e.message); }
|
|
944
945
|
}
|
|
945
946
|
}
|
|
@@ -11053,30 +11054,41 @@ async function _agentRepl(root, opts) {
|
|
|
11053
11054
|
// 1.9.153: .env μλ λ‘λ (REPL μ§μ
μ§μ ) β install μ§ν LEERNESS_ENABLE_* μ¦μ λ°μ
|
|
11054
11055
|
try { _loadEnvFile(root); } catch {}
|
|
11055
11056
|
const readline = require('readline');
|
|
11056
|
-
|
|
11057
|
+
// 1.9.180: completer no-op β readline μ Tab completion κ°λ‘μ±κΈ°λ₯Ό μ°¨λ¨ν΄ keypress 리μ€λκ° Tab cycleμ μ²λ¦¬.
|
|
11058
|
+
// (μ¬μ©μ λͺ
μ: "λͺ¨λΈ/νλ‘λ°μ΄λ μ νμ΄ μννμ§ μλ€" β readline Tab completionμ΄ cycle ν€λ₯Ό κ°λ‘μ±λ κ²½μ° fix)
|
|
11059
|
+
const rl = readline.createInterface({
|
|
11060
|
+
input: process.stdin,
|
|
11061
|
+
output: process.stdout,
|
|
11062
|
+
completer: (line) => [[], line] // λΉ completion + μλ³Έ line λ°ν β Tabμ keypress 리μ€λλ‘λ§ μ²λ¦¬
|
|
11063
|
+
});
|
|
11057
11064
|
const isTty = process.stdout.isTTY;
|
|
11058
11065
|
const C = isTty ? {
|
|
11059
11066
|
cy: s => `\x1b[36m${s}\x1b[0m`, dim: s => `\x1b[2m${s}\x1b[0m`,
|
|
11060
11067
|
bold: s => `\x1b[1m${s}\x1b[0m`, green: s => `\x1b[32m${s}\x1b[0m`,
|
|
11061
11068
|
yel: s => `\x1b[33m${s}\x1b[0m`, mag: s => `\x1b[35m${s}\x1b[0m`
|
|
11062
11069
|
} : { cy:s=>s, dim:s=>s, bold:s=>s, green:s=>s, yel:s=>s, mag:s=>s };
|
|
11063
|
-
// 1.9.
|
|
11070
|
+
// 1.9.181 fix: provider μλ μ ν β prompt λ¨κ³ μ κ±°νκ³ μ¦μ μ±ν
λͺ¨λ μ§μ
(μ¬μ©μ λͺ
μ).
|
|
11071
|
+
// μ μ±
: λΉ-Ollama νμ± CLI μ°μ β Ollama β fallback. 볡μ νμ± μ prompt μμ΄ μ²« λΉ-Ollama μλ μ ν.
|
|
11072
|
+
// μ¬μ©μ μλ: "νλ‘λ°μ΄λ μ ν μ ν λ¨κ³μμ΄ λ°λ‘ μ±ν
λͺ¨λλ‘ μ§μ
ν΄λ λ κ±°κ°μ" + "Ollamaλ₯Ό μ°μ νΈμΆ X".
|
|
11073
|
+
// Tab μΌλ‘ μΈμ λ cycle κ°λ₯νλ―λ‘ μλ μ νν΄λ μ¬μ©μκ° μ¦μ μ ν κ°λ₯.
|
|
11064
11074
|
let initialProvider = opts.provider;
|
|
11075
|
+
let _autoPickNote = '';
|
|
11065
11076
|
if (!initialProvider) {
|
|
11066
11077
|
const ready = EXTERNAL_AGENTS.map(a => ({ def: a, status: _checkAgent(a) }))
|
|
11067
11078
|
.filter(x => x.status.status === 'ready');
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11079
|
+
const nonOllama = ready.filter(x => x.def.id !== 'ollama');
|
|
11080
|
+
if (nonOllama.length >= 1) {
|
|
11081
|
+
// λΉ-Ollama νμ± β 첫 λ²μ§Έ μλ (μ¬μ©μ λͺ
μ: Ollama μ°μ νΈμΆ X)
|
|
11082
|
+
initialProvider = nonOllama[0].def.id;
|
|
11083
|
+
_autoPickNote = nonOllama.length === 1
|
|
11084
|
+
? `${initialProvider} μλ μ ν (νμ± CLI 1κ°)`
|
|
11085
|
+
: `${initialProvider} μλ μ ν (νμ± CLI ${nonOllama.length}κ° Β· TabμΌλ‘ μ ν)`;
|
|
11086
|
+
} else if (ready.length === 1) {
|
|
11087
|
+
initialProvider = ready[0].def.id; // ollama λ¨λ
|
|
11088
|
+
_autoPickNote = `${initialProvider} μλ μ ν`;
|
|
11078
11089
|
} else {
|
|
11079
|
-
initialProvider = 'ollama'; // νμ± 0κ° β fallback
|
|
11090
|
+
initialProvider = 'ollama'; // νμ± 0κ° β fallback
|
|
11091
|
+
_autoPickNote = 'fallback ollama (νμ± CLI μμ β .env μμ LEERNESS_ENABLE_* νμ±ν κΆμ₯)';
|
|
11080
11092
|
}
|
|
11081
11093
|
}
|
|
11082
11094
|
// μΈμ
state
|
|
@@ -11110,47 +11122,27 @@ async function _agentRepl(root, opts) {
|
|
|
11110
11122
|
log('');
|
|
11111
11123
|
log(C.dim(` βΈ Welcome back Β· ${wsName} (${rel(process.cwd(), absRoot(root))})`));
|
|
11112
11124
|
log(C.dim(` βΈ Session: ${state.sessionId}`));
|
|
11125
|
+
if (_autoPickNote) log(C.dim(` βΈ Provider: ${_autoPickNote}`));
|
|
11113
11126
|
log('');
|
|
11114
|
-
//
|
|
11127
|
+
// 1.9.181 fix: provider μ§μ
μμ prompt λ¨κ³ μ κ±° β μλ μ νλ§ μν (μ¬μ©μ λͺ
μ β λ°λ‘ μ±ν
λͺ¨λ μ§μ
).
|
|
11115
11128
|
if (state.provider === 'ollama' && !state.model) {
|
|
11116
|
-
|
|
11129
|
+
// Ollama μ¬μ© κ°λ₯ β 첫 λͺ¨λΈ μλ μ ν (μ¬μ©μ prompt μμ)
|
|
11117
11130
|
const r = await _ollamaListModels();
|
|
11118
11131
|
if (r.ok && r.models.length) {
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
const choice = await new Promise(res => rl.question(C.cy('\n λͺ¨λΈ λ²νΈ μ ν (Enter=1): '), res));
|
|
11122
|
-
const idx = parseInt(choice, 10) - 1;
|
|
11123
|
-
state.model = (idx >= 0 && idx < r.models.length) ? r.models[idx] : r.models[0];
|
|
11124
|
-
log(C.green(` β λͺ¨λΈ μ ν: ${state.model}`));
|
|
11132
|
+
state.model = process.env.LEERNESS_OLLAMA_MODEL || r.models[0];
|
|
11133
|
+
log(C.dim(` βΈ Model: ${state.model} (Ollama ${r.models.length}κ° catalog Β· Shift+TabμΌλ‘ λ³κ²½)`));
|
|
11125
11134
|
} else {
|
|
11126
|
-
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11135
|
-
readyCli.forEach((x, i) => log(` ${i + 1}) ${x.def.id} (v${x.status.version || '?'})`));
|
|
11136
|
-
const choice = await new Promise(res => rl.question(C.cy('\n provider μ ν (λ²νΈ / Enter=ollama κ³μ): '), res));
|
|
11137
|
-
const idx = parseInt(choice, 10) - 1;
|
|
11138
|
-
if (idx >= 0 && idx < readyCli.length) {
|
|
11139
|
-
state.provider = readyCli[idx].def.id;
|
|
11140
|
-
state.model = null; // μ provider κΈ°λ³Έ λͺ¨λΈ μ¬μ©
|
|
11141
|
-
log(C.green(` β provider μ ν: ${state.provider} (λ©μμ§ μ
λ ₯ μ¦μ μ¬μ©)`));
|
|
11142
|
-
} else {
|
|
11143
|
-
state.model = process.env.LEERNESS_OLLAMA_MODEL || 'llama3';
|
|
11144
|
-
log(C.dim(` ollama fallback: ${state.model} β μΆν :provider <μ΄λ¦> μΌλ‘ μ ν κ°λ₯`));
|
|
11145
|
-
}
|
|
11146
|
-
} else {
|
|
11147
|
-
log(C.dim(` ollama serve + ollama pull <model> / λλ .env μμ LEERNESS_ENABLE_CLAUDE=1 λ± νμ±ν`));
|
|
11148
|
-
state.model = process.env.LEERNESS_OLLAMA_MODEL || 'llama3';
|
|
11149
|
-
log(C.dim(` fallback: ${state.model} (μ€ νΈμΆ μ€ν¨ μ :provider λ©λ΄ λλ :quit)`));
|
|
11150
|
-
}
|
|
11151
|
-
} catch {
|
|
11135
|
+
// Ollama λ―Έκ°λ β λΉ-Ollama νμ± CLI κ° μμΌλ©΄ μλ μ ν, μμΌλ©΄ fallback ollama (warn)
|
|
11136
|
+
const readyCli = EXTERNAL_AGENTS.filter(a => a.id !== 'ollama')
|
|
11137
|
+
.map(a => ({ def: a, status: _checkAgent(a) }))
|
|
11138
|
+
.filter(x => x.status.status === 'ready');
|
|
11139
|
+
if (readyCli.length) {
|
|
11140
|
+
state.provider = readyCli[0].def.id;
|
|
11141
|
+
state.model = null;
|
|
11142
|
+
log(C.green(` βΈ Ollama λ―Έκ°λ β ${state.provider} μλ μ ν (TabμΌλ‘ λ€λ₯Έ provider μ ν κ°λ₯)`));
|
|
11143
|
+
} else {
|
|
11152
11144
|
state.model = process.env.LEERNESS_OLLAMA_MODEL || 'llama3';
|
|
11153
|
-
log(C.
|
|
11145
|
+
log(C.yel(` β Ollama λ―Έκ°λ + νμ± CLI μμ β fallback ${state.model} (μ€ νΈμΆ μ€ν¨ μ :quit λλ :provider)`));
|
|
11154
11146
|
}
|
|
11155
11147
|
}
|
|
11156
11148
|
}
|
|
@@ -11187,6 +11179,11 @@ async function _agentRepl(root, opts) {
|
|
|
11187
11179
|
+ C.green(`role=${state.role}`) + ' Β· '
|
|
11188
11180
|
+ C.yel(`perms=${permMode}`) + ' Β· '
|
|
11189
11181
|
+ (state.streamMode ? C.green('βΆ stream=on') : C.dim('β‘ stream=off')));
|
|
11182
|
+
// 1.9.180: μ±ν
μμ μ§μ
separator (μ¬μ©μ λͺ
μ β "κ³ μ ν€λ + μ±ν
νμ")
|
|
11183
|
+
// νμ νλ©΄ λμ λͺ
νν ꡬλΆμ + μλ΄ β μ±ν
μμ λͺ
ν.
|
|
11184
|
+
log('');
|
|
11185
|
+
log(C.dim(' βββββββββββββββββββββββββββββ μ±ν
μμ βββββββββββββββββββββββββββββ'));
|
|
11186
|
+
log(C.dim(' λ©μμ§ μ
λ ₯ ν Enter Β· :help μΌλ‘ λͺ
λ Ή λͺ©λ‘ Β· Ctrl+C λ‘ μ’
λ£'));
|
|
11190
11187
|
// 1.9.155: REPL μ§μ
μ handoff 컨ν
μ€νΈ μλ λ
ΈμΆ (UX κ°μ β μ¬μ©μκ° λ§€λ² :handoff μ ν΄λ 컨ν
μ€νΈ μΈμ§)
|
|
11191
11188
|
try {
|
|
11192
11189
|
const hf = cp.spawnSync(process.execPath, [__filename, 'handoff', root, '--compact', '--no-drift-check', '--no-headline'], {
|
|
@@ -11224,20 +11221,34 @@ async function _agentRepl(root, opts) {
|
|
|
11224
11221
|
} catch {}
|
|
11225
11222
|
return _PROVIDER_CYCLE_ORDER.slice();
|
|
11226
11223
|
};
|
|
11224
|
+
// 1.9.180: cycleProvider/cycleModel β μκ° νΌλλ°± κ°ν (μ¬μ©μ λͺ
μ "μννμ§ μλ€").
|
|
11225
|
+
// μ΄μ : ν μ€ β λ©μμ§λ§. 1.9.180: provider μμΉ νμ [1/5] + bold highlight + νμ± μ¬λΆ νμ.
|
|
11227
11226
|
const cycleProvider = (reverse) => {
|
|
11228
11227
|
const list = getProviders();
|
|
11229
11228
|
let idx = list.indexOf(state.provider);
|
|
11230
11229
|
if (idx < 0) idx = 0;
|
|
11231
11230
|
idx = reverse ? (idx - 1 + list.length) % list.length : (idx + 1) % list.length;
|
|
11232
11231
|
state.provider = list[idx];
|
|
11233
|
-
state.model = null;
|
|
11232
|
+
state.model = null;
|
|
11234
11233
|
const cat = _PROVIDER_MODEL_CATALOG[state.provider];
|
|
11235
|
-
|
|
11236
|
-
|
|
11234
|
+
// νμ± μ¬λΆ μ¬μ νμΈ (1.9.180 UX β μ¬μ©μκ° μ¦μ μΈμ§)
|
|
11235
|
+
let activeMark = '';
|
|
11236
|
+
try {
|
|
11237
|
+
if (state.provider !== 'ollama') {
|
|
11238
|
+
const agent = EXTERNAL_AGENTS.find(a => a.id === state.provider);
|
|
11239
|
+
if (agent) {
|
|
11240
|
+
const st = _checkAgent(agent);
|
|
11241
|
+
activeMark = st.status === 'ready' ? C.green(' β ready') : C.yel(` β ${st.status}`);
|
|
11242
|
+
}
|
|
11243
|
+
}
|
|
11244
|
+
} catch {}
|
|
11237
11245
|
process.stdout.write('\r\x1b[K');
|
|
11238
|
-
process.stdout.write(C.green(` β provider: ${state.provider}
|
|
11246
|
+
process.stdout.write(C.bold(C.green(` β provider [${idx + 1}/${list.length}]: ${state.provider}`)) + activeMark + '\n');
|
|
11247
|
+
if (cat?.length) {
|
|
11248
|
+
process.stdout.write(C.dim(` β ${cat.length}κ° λͺ¨λΈ catalog Β· Shift+TabμΌλ‘ model cycle\n`));
|
|
11249
|
+
}
|
|
11239
11250
|
rl.setPrompt(prompt());
|
|
11240
|
-
rl.prompt(true);
|
|
11251
|
+
rl.prompt(true);
|
|
11241
11252
|
};
|
|
11242
11253
|
const cycleModel = (reverse) => {
|
|
11243
11254
|
const cat = _PROVIDER_MODEL_CATALOG[state.provider] || [];
|
|
@@ -11252,17 +11263,25 @@ async function _agentRepl(root, opts) {
|
|
|
11252
11263
|
idx = reverse ? (idx - 1 + cat.length) % cat.length : (idx + 1) % cat.length;
|
|
11253
11264
|
state.model = cat[idx].id;
|
|
11254
11265
|
process.stdout.write('\r\x1b[K');
|
|
11255
|
-
process.stdout.write(C.
|
|
11266
|
+
process.stdout.write(C.bold(C.mag(` β model [${idx + 1}/${cat.length}]: ${state.model}`)) + '\n');
|
|
11267
|
+
if (cat[idx].note) {
|
|
11268
|
+
process.stdout.write(C.dim(` β ${cat[idx].note}\n`));
|
|
11269
|
+
}
|
|
11256
11270
|
rl.setPrompt(prompt());
|
|
11257
11271
|
rl.prompt(true);
|
|
11258
11272
|
};
|
|
11259
11273
|
process.stdin.on('keypress', (str, key) => {
|
|
11260
11274
|
if (!key) return;
|
|
11261
11275
|
if (key.name === 'tab') {
|
|
11262
|
-
|
|
11276
|
+
// 1.9.180 fix: Shift+Tab β cycleModel (μ¬μ©μ λͺ
μ μλ).
|
|
11277
|
+
// μ΄μ (1.9.170): cycleProvider(key.shift) β Shift+Tab μ provider reverse cycleλ§ λμ΄ model μ νμ΄ λΆκ°λ₯νμ.
|
|
11278
|
+
// μ¬μ©μ λͺ
μ: "Tab=provider, Shift+Tab=model μ νκ³Ό μ νμ΄ κ°νΈνκ²".
|
|
11279
|
+
if (key.shift === true) {
|
|
11280
|
+
cycleModel(false); // Shift+Tab β νμ¬ providerμ λ€μ model
|
|
11281
|
+
} else {
|
|
11282
|
+
cycleProvider(false); // Tab β λ€μ provider
|
|
11283
|
+
}
|
|
11263
11284
|
}
|
|
11264
|
-
// Shift+\ λλ λ€λ₯Έ λͺ¨λΈ cycle alias β μΌλΆ ν°λ―Έλμμ Shift+Tab μ²λ¦¬ μ΄λ €μ λλΉ
|
|
11265
|
-
// (Shift+Tabμ key.name='tab' + key.shift=true λ‘ μμμ μ²λ¦¬λ¨)
|
|
11266
11285
|
});
|
|
11267
11286
|
} catch (e) {
|
|
11268
11287
|
log(C.dim(` (Tab cycle λΉνμ±: ${e.message})`));
|
|
@@ -11625,7 +11644,7 @@ async function _agentRepl(root, opts) {
|
|
|
11625
11644
|
async function agentCmd(root, taskArg) {
|
|
11626
11645
|
root = absRoot(root || process.cwd());
|
|
11627
11646
|
const task = (taskArg || arg('--task', '') || '').trim();
|
|
11628
|
-
// 1.9.149: REPL μ§μ
β μΈμ μκ±°λ --interactive λͺ
μ (
|
|
11647
|
+
// 1.9.149+1.9.181: REPL μ§μ
β μΈμ μκ±°λ --interactive λͺ
μ (provider μλ μ ν)
|
|
11629
11648
|
if (!task || has('--interactive') || has('--repl')) {
|
|
11630
11649
|
if (process.stdin.isTTY && !has('--no-repl') && process.env.LEERNESS_NO_PROMPT !== '1') {
|
|
11631
11650
|
const t0 = Date.now();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.181",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|