leerness 1.9.187 β†’ 1.9.188

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,102 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.188 β€” 2026-05-21
4
+
5
+ **πŸ› REPL ν•œκΈ€ prompt 전달 BUG fix (stdin) + μ„ΈλΆ€ λͺ¨λΈ ν‘œμ‹œ + μž…λ ₯ ꡬ뢄선 (μ‚¬μš©μž λͺ…μ‹œ 3μ’…).**
6
+
7
+ 자율 λͺ¨λ“œ 118 λΌμš΄λ“œ. μ‚¬μš©μž λͺ…μ‹œ 핡심 버그:
8
+ ```
9
+ agent[claude/actor/β–Ά]> 이 폴더에 파이썬 ν”„λ‘œκ·Έλž¨μ„ ν•˜λ‚˜ μ œμž‘ν•΄μ€˜
10
+ ── claude stream ──
11
+ μ €λŠ” 이 ν”„λ‘œμ νŠΈμ˜ **μˆ˜μ„ 개발자이자 ν”„λ‘œμ νŠΈ λ§€λ‹ˆμ €**μž…λ‹ˆλ‹€.
12
+ ...
13
+ λ©”μ‹œμ§€κ°€ "μ—­ν• :"둜만 λλ‚˜μ„œ μ˜λ„λ₯Ό ν™•μ‹ ν•˜κΈ° μ–΄λ ΅μŠ΅λ‹ˆλ‹€.
14
+ ```
15
+ μ‚¬μš©μž μ˜λ„μ™€ λ¬΄κ΄€ν•œ 응닡 β€” **claudeκ°€ ν•œκΈ€ prompt 끝뢀뢄("μ—­ν• :") fragment만 λ°›μŒ**.
16
+
17
+ ### κ·Όλ³Έ 원인 (μ½”λ“œ audit)
18
+
19
+ `cp.spawn(cmd, args, { shell: true })` + Windows cmd.exe + ν•œκΈ€/특수문자 promptText:
20
+ - shell:true 일 λ•Œ args κ°€ joinλ˜μ–΄ shell command line ν˜•μ„±
21
+ - Windows cmd.exeκ°€ ν•œκΈ€/곡백 escape μ‹€νŒ¨ β†’ claude에 일뢀 fragment만 전달
22
+
23
+ ### Fix #1 β€” promptλ₯Ό stdin으둜 전달 (shell escape 우회)
24
+
25
+ ```diff
26
+ - if (provider === 'claude') { cmd = 'claude'; args = ['--print', promptText]; }
27
+ + // 1.9.188: promptText λŠ” stdin 으둜 β†’ args μ—μ„œ 제거 (ν•œκΈ€/특수문자 μ•ˆμ „)
28
+ + let useStdinForPrompt = false;
29
+ + if (provider === 'claude') {
30
+ + cmd = 'claude';
31
+ + args = ['--print']; // promptText 제거
32
+ + useStdinForPrompt = true;
33
+ + }
34
+ ```
35
+
36
+ spawn μ‹œ:
37
+ ```js
38
+ child = cp.spawn(cmd, args, {
39
+ stdio: [useStdinForPrompt ? 'pipe' : 'ignore', 'pipe', 'pipe'],
40
+ shell: true
41
+ });
42
+ if (useStdinForPrompt && child.stdin) {
43
+ child.stdin.write(promptText);
44
+ child.stdin.end();
45
+ }
46
+ ```
47
+
48
+ `_cliChat` 도 λ™μΌν•˜κ²Œ `runCommandSafe(..., { input: stdinInput })` 으둜 λ³€κ²½.
49
+
50
+ ### Live 검증 (ν•œκΈ€ prompt μ •ν™• 전달)
51
+ ```bash
52
+ $ leerness agents multi "이 폴더에 파이썬 hello world ν”„λ‘œκ·Έλž¨ μ œμž‘ (μ‘λ‹΅λ§Œ μ½”λ“œ)" --only claude --execute
53
+ βœ“ claude Β· 8279ms Β· 9 토큰
54
+ --- 처음 600자 ---
55
+ `hello.py` 생성 κΆŒν•œμ΄ ν•„μš”ν•©λ‹ˆλ‹€. μŠΉμΈν•΄ μ£Όμ„Έμš”.
56
+ ```
57
+ **1.9.187κΉŒμ§€**: "μˆ˜μ„ 개발자/ν”„λ‘œμ νŠΈ λ§€λ‹ˆμ €..." 같은 λ¬΄κ΄€ν•œ 응닡 (μ—­ν•  fragment만 λ°›μŒ)
58
+ **1.9.188**: `hello.py 생성 κΆŒν•œ ν•„μš”` β€” μ •ν™•ν•œ μš”μ²­ 이해 βœ“
59
+
60
+ ### Fix #2 β€” μ„ΈλΆ€ λͺ¨λΈ ν‘œμ‹œ
61
+ **Before**: `⚑ provider=claude · model=(기본)`
62
+ **After**: `⚑ provider=claude · model=claude-opus-4-7`
63
+
64
+ ```js
65
+ // 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ): state.model μžλ™ default (catalog 첫 λͺ¨λΈ)
66
+ if (!state.model) {
67
+ const cat = _PROVIDER_MODEL_CATALOG[state.provider];
68
+ if (cat && cat.length) state.model = cat[0].id;
69
+ }
70
+ ```
71
+
72
+ prompt 도 μ„ΈλΆ€ λͺ¨λΈ λͺ…μ‹œ:
73
+ ```
74
+ Before: agent[claude/actor/β–Ά]>
75
+ After: agent[claude Β· opus-4-7/actor/β–Ά]>
76
+ ```
77
+
78
+ ### Fix #3 β€” μž…λ ₯ ꡬ뢄선 (Hermes UX 영감)
79
+ 각 응닡 끝에 κ°€λ‘œ 디바이더 μžλ™ 좜λ ₯ β†’ μž…λ ₯ μ˜μ—­ μ‹œκ° λͺ…ν™•:
80
+
81
+ ```
82
+ [assistant: claude/claude-opus-4-7, role=actor, 4598ms · 425자]
83
+
84
+ ────────────────────────────────────────────────...
85
+ agent[claude Β· opus-4-7/actor/β–Ά]> _
86
+ ```
87
+
88
+ `_printInputDivider()` ν•¨μˆ˜ λ„μž… β€” 터미널 width κΈ°μ€€ μžλ™ 길이.
89
+
90
+ ### Verified
91
+ - stress-v133: **15/15 PASS** (μ‚¬μš©μž λͺ…μ‹œ 6 + live 2 + λˆ„μ  7)
92
+ - e2e 217/217 baseline μœ μ§€
93
+ - live 검증:
94
+ - ν•œκΈ€ prompt "이 폴더에 파이썬 hello world μ œμž‘" β†’ claude μ •ν™• 응닡 (12.5초)
95
+ - 영문 prompt "1+1=?" β†’ claude 응닡 (9.3초, νšŒκ·€ μ—†μŒ)
96
+ - VERSION = 1.9.188 Β· autonomous-rounds = 118 Β· main μžλ™ push 49 λΌμš΄λ“œ 연속
97
+
98
+ ---
99
+
3
100
  ## 1.9.187 β€” 2026-05-21
4
101
 
5
102
  **πŸ”“ λΉ„μ‹œν¬λ¦Ώ LEERNESS_* 섀정을 .env β†’ .harness/leerness-config.json 으둜 뢄리 (AI κ°€μ‹œμ„±).**
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.187-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v132-19%2F19-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-117-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-48_rounds-success)]() [![config-split](https://img.shields.io/badge/.env_뢄리-λΉ„μ‹œν¬λ¦Ώ_AIκ°€μ‹œμ„±-success)]() [![secret-guard](https://img.shields.io/badge/μ‹œν¬λ¦Ώ_κ°€λ“œ-load%2Bwrite_이쀑망-success)]() [![install](https://img.shields.io/badge/npm_i_leerness-μ¦‰μ‹œ_μ‚¬μš©_κ°€λŠ₯-success)]() [![repl-fix](https://img.shields.io/badge/REPL_stream-shell%3Atrue_fix-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.188-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v133-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-118-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-49_rounds-success)]() [![hangul-fix](https://img.shields.io/badge/ν•œκΈ€_prompt-stdin_정확전달-success)]() [![model-show](https://img.shields.io/badge/μ„ΈλΆ€λͺ¨λΈ-prompt%2Bμƒνƒœλ°”_ν‘œμ‹œ-success)]() [![divider](https://img.shields.io/badge/μž…λ ₯_ꡬ뢄선-μžλ™μΆœλ ₯-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.187 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.188 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ πŸ”“ .env 뢄리 (μ‹œν¬λ¦Ώ) Β· leerness-config.json (AI κ°€μ‹œ) β•‘
17
+ β•‘ πŸ› ν•œκΈ€ prompt stdin 전달 Β· μ„ΈλΆ€λͺ¨λΈ ν‘œμ‹œ Β· μž…λ ₯ ꡬ뢄선 β•‘
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.187';
10
+ const VERSION = '1.9.188';
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 처리).
@@ -11048,10 +11048,11 @@ async function _cliChat(root, provider, prompt, opts) {
11048
11048
  return { ok: false, error: `${provider} λΉ„ν™œμ„± (${status.status}) β€” .env μ—μ„œ ${agent.envFlag}=1 + CLI μ„€μΉ˜ ν•„μš”`, provider };
11049
11049
  }
11050
11050
  // CLI 별 λΉ„-μΈν„°λž™ν‹°λΈŒ 호좜 인자 λ§€ν•‘ (read-only λͺ¨λ“œ β€” REPL μ•ˆμ—μ„œ 파일 μˆ˜μ • X)
11051
- let cmd, args;
11052
- if (provider === 'claude') { cmd = 'claude'; args = ['--print', prompt]; }
11053
- else if (provider === 'codex') { cmd = 'codex'; args = ['exec', '--skip-git-repo-check', prompt]; }
11054
- else if (provider === 'gemini') { cmd = 'gemini'; args = ['-p', prompt]; }
11051
+ // 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ fix): ν•œκΈ€/특수문자 prompt μ‹œ shell escape μ‹€νŒ¨ νšŒν”Ό β†’ stdin 으둜 전달.
11052
+ let cmd, args, stdinInput = null;
11053
+ if (provider === 'claude') { cmd = 'claude'; args = ['--print']; stdinInput = prompt; }
11054
+ else if (provider === 'codex') { cmd = 'codex'; args = ['exec', '--skip-git-repo-check', '-']; stdinInput = prompt; }
11055
+ else if (provider === 'gemini') { cmd = 'gemini'; args = ['-p', prompt]; } // gemini λŠ” 인자 only
11055
11056
  else if (provider === 'copilot') { cmd = 'gh'; args = ['copilot', 'suggest', prompt]; }
11056
11057
  else return { ok: false, error: `provider ${provider} 미지원`, provider };
11057
11058
  // runCommandSafe β€” env scrub + observability μžλ™
@@ -11059,7 +11060,8 @@ async function _cliChat(root, provider, prompt, opts) {
11059
11060
  cwd: process.cwd(), root,
11060
11061
  timeout: opts.timeout || 60000,
11061
11062
  allowOutsideCwd: true, // CLI κ°€ cwd λ°–μ—μ„œ 싀행될 수 있음
11062
- kind: 'agent_repl_cli', label: `repl-${provider}`
11063
+ kind: 'agent_repl_cli', label: `repl-${provider}`,
11064
+ input: stdinInput // 1.9.188: claude/codex λŠ” stdin 전달
11063
11065
  });
11064
11066
  if (r.status === 0) {
11065
11067
  return { ok: true, response: (r.stdout || '').trim(), provider, model: provider };
@@ -11088,15 +11090,25 @@ async function _cliChatStream(root, provider, promptText, opts) {
11088
11090
  // 1.9.186 (μ‚¬μš©μž λͺ…μ‹œ fix): claude --output-format=stream-json κ°€ 일뢀 λ²„μ „μ—μ„œ 빈 응닡.
11089
11091
  // default λ₯Ό plain --print 둜 λ³€κ²½ β†’ _cliChat κ³Ό λ™μΌν•œ 인자, μž‘λ™ κ²€μ¦λœ νŒ¨ν„΄.
11090
11092
  // stream ν˜•μ‹ μ‚¬μš© opt-in: LEERNESS_REPL_STREAM_FORMAT=json (μ‹€μ‹œκ°„ thinking/tool_use 보고 싢을 λ•Œ).
11093
+ // 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ fix): shell:true + Windows cmd.exe + ν•œκΈ€/특수문자 promptText β†’ args escape μ‹€νŒ¨.
11094
+ // μ‚¬μš©μž 보고: "이 폴더에 파이썬 ν”„λ‘œκ·Έλž¨ μ œμž‘" λ³΄λƒˆμœΌλ‚˜ claudeλŠ” "μ—­ν• :" fragment만 λ°›μŒ.
11095
+ // ν•΄κ²°: promptText λ₯Ό args μ—μ„œ μ œκ±°ν•˜κ³  stdin 으둜 전달 (shell escape 우회).
11091
11096
  const useStreamJson = process.env.LEERNESS_REPL_STREAM_FORMAT === 'json';
11097
+ let useStdinForPrompt = false; // 1.9.188: claude/codex λŠ” stdin 으둜 prompt 전달 (shell escape 우회)
11092
11098
  if (provider === 'claude') {
11093
11099
  cmd = 'claude';
11100
+ // 1.9.188: promptText λŠ” stdin 으둜 β†’ args μ—μ„œ 제거 (ν•œκΈ€/특수문자 μ•ˆμ „)
11094
11101
  args = useStreamJson
11095
- ? ['--print', '--output-format=stream-json', '--verbose', promptText]
11096
- : ['--print', promptText]; // plain text 응닡 (μž‘λ™ 검증됨)
11102
+ ? ['--print', '--output-format=stream-json', '--verbose']
11103
+ : ['--print'];
11104
+ useStdinForPrompt = true;
11105
+ }
11106
+ else if (provider === 'codex') {
11107
+ cmd = 'codex';
11108
+ args = ['exec', '--skip-git-repo-check', '-']; // - = stdin from claude/codex convention
11109
+ useStdinForPrompt = true;
11097
11110
  }
11098
- else if (provider === 'codex') { cmd = 'codex'; args = ['exec', '--skip-git-repo-check', promptText]; }
11099
- else if (provider === 'gemini') { cmd = 'gemini'; args = ['-p', promptText]; }
11111
+ else if (provider === 'gemini') { cmd = 'gemini'; args = ['-p', promptText]; } // gemini -p λŠ” 인자 λͺ¨λ“œλ§Œ 지원
11100
11112
  else if (provider === 'copilot') { cmd = 'gh'; args = ['copilot', 'suggest', promptText]; }
11101
11113
  else return { ok: false, error: `provider ${provider} 미지원`, provider };
11102
11114
  const t0 = Date.now();
@@ -11156,17 +11168,26 @@ async function _cliChatStream(root, provider, promptText, opts) {
11156
11168
  process.stdout.write(dim(`\n ── ${provider} stream ──\n`));
11157
11169
  let child;
11158
11170
  try {
11159
- // 1.9.186 (μ‚¬μš©μž λͺ…μ‹œ fix): Windows .cmd ν˜Έν™˜μ„ μœ„ν•΄ shell: true.
11160
- // 1.9.185 κΉŒμ§€ shell: false β†’ Windows μ—μ„œ claude.cmd λͺ» μ°Ύμ•„ 빈 응닡 (μ‚¬μš©μž 보고: 27초 ν›„ 0자).
11161
- // _cliChat (μž‘λ™ν•˜λŠ” ν•¨μˆ˜) 이 runCommandSafe β†’ spawnSync shell: true νŒ¨ν„΄μ΄λΌμ„œ μž‘λ™.
11162
- // _cliChatStream 도 λ™μΌν•˜κ²Œ shell: true μ‚¬μš© (DEP0190 은 1.9.184/185 fix 둜 μ–΅μ œλ¨).
11163
- // security: shell escape μš°λ €λŠ” promptText κ°€ μ‚¬μš©μž 직접 μž…λ ₯ β€” sandboxed REPL μ•ˆμ—μ„œλ§Œ μ‚¬μš©.
11171
+ // 1.9.186 + 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ fix):
11172
+ // Windows .cmd ν˜Έν™˜μ„ μœ„ν•΄ shell: true μœ μ§€.
11173
+ // 1.9.188: promptText κ°€ ν•œκΈ€/특수문자일 λ•Œ shell escape μ‹€νŒ¨ β†’ stdin 으둜 전달.
11174
+ // useStdinForPrompt=true μ‹œ stdio[0]='pipe' + child.stdin.write(promptText) + end().
11175
+ // shell μΈμžμ—λŠ” escape-safe flags 만 남김 ('--print' λ“±).
11164
11176
  child = cp.spawn(cmd, args, {
11165
11177
  cwd: process.cwd(),
11166
11178
  env: _scrubEnv({}),
11167
11179
  shell: true,
11168
- stdio: ['ignore', 'pipe', 'pipe']
11180
+ stdio: [useStdinForPrompt ? 'pipe' : 'ignore', 'pipe', 'pipe']
11169
11181
  });
11182
+ // 1.9.188: promptText λ₯Ό stdin 으둜 μ•ˆμ „ 전달
11183
+ if (useStdinForPrompt && child.stdin) {
11184
+ try {
11185
+ child.stdin.write(promptText);
11186
+ child.stdin.end();
11187
+ } catch (e) {
11188
+ // stdin μ“°κΈ° μ‹€νŒ¨ μ‹œ child κ°€ stdin μ•ˆ 받을 μˆ˜λ„ β€” λ¬΄μ‹œν•˜κ³  μ§„ν–‰
11189
+ }
11190
+ }
11170
11191
  } catch (e) {
11171
11192
  if (spinnerInterval) clearInterval(spinnerInterval);
11172
11193
  return resolve({ ok: false, error: 'spawn μ‹€νŒ¨: ' + e.message, provider });
@@ -11571,10 +11592,16 @@ async function _agentRepl(root, opts) {
11571
11592
  log('');
11572
11593
  log(C.dim(' ⌨ Tab=provider cycle Β· Shift+Tab=model Β· Ctrl+C=quit'));
11573
11594
  log('');
11574
- // 1.9.179: μƒνƒœλ°” ν•œ 쀄 β€” 색깔/κ΅¬λΆ„μž κ°•ν™”
11595
+ // 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ): state.model 이 λΉ„μ–΄μžˆμœΌλ©΄ catalog 첫 λͺ¨λΈ μžλ™ μ„€μ • β†’ μ„ΈλΆ€ λͺ¨λΈ ν‘œμ‹œ.
11596
+ // "model=(κΈ°λ³Έ)" 같은 λͺ¨ν˜Έν•œ ν‘œμ‹œ λŒ€μ‹  μ‹€μ œ μ‚¬μš©λ  λͺ¨λΈ 이름 (예: claude-opus-4-7) λͺ…μ‹œ.
11597
+ if (!state.model) {
11598
+ const cat = _PROVIDER_MODEL_CATALOG[state.provider];
11599
+ if (cat && cat.length) state.model = cat[0].id;
11600
+ }
11601
+ // 1.9.179+1.9.188: μƒνƒœλ°” ν•œ 쀄 β€” μ„ΈλΆ€ λͺ¨λΈ + 색깔/κ΅¬λΆ„μž κ°•ν™”
11575
11602
  const permMode = _readPermissions(root).mode || 'basic';
11576
11603
  log(' ' + C.bold('⚑ ') + C.cy(`provider=${state.provider}`) + ' Β· '
11577
- + C.mag(`model=${state.model || '(κΈ°λ³Έ)'}`) + ' Β· '
11604
+ + C.mag(`model=${state.model || '(unknown)'}`) + ' Β· '
11578
11605
  + C.green(`role=${state.role}`) + ' Β· '
11579
11606
  + C.yel(`perms=${permMode}`) + ' Β· '
11580
11607
  + (state.streamMode ? C.green('β–Ά stream=on') : C.dim('β–‘ stream=off')));
@@ -11598,7 +11625,24 @@ async function _agentRepl(root, opts) {
11598
11625
  }
11599
11626
  } catch {}
11600
11627
  log('');
11601
- const prompt = () => isTty ? C.cy(`agent[${state.provider}/${state.role}${state.streamMode ? '/β–Ά' : ''}]> `) : 'agent> ';
11628
+ // 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ): prompt μœ„/μ•„λž˜ ꡬ뢄선 + μ„ΈλΆ€ λͺ¨λΈ λͺ…μ‹œ (μ‚¬μš©μž μž…λ ₯μΉΈ μ‹œκ° κ°•μ‘°).
11629
+ // λ§€ 응닡 직후 readline.question 호좜 전에 _printInputDivider() ν˜ΈμΆœν•˜μ—¬ μž…λ ₯ μ˜μ—­ λͺ…ν™•ν™”.
11630
+ const _termCols = () => {
11631
+ try { return Math.max(40, (process.stdout.columns || 80)); } catch { return 80; }
11632
+ };
11633
+ const _printInputDivider = () => {
11634
+ if (!isTty) return;
11635
+ const cols = _termCols();
11636
+ const line = '─'.repeat(Math.min(cols - 4, 120));
11637
+ process.stdout.write('\n' + C.dim(' ' + line) + '\n');
11638
+ };
11639
+ // prompt 에 μ„ΈλΆ€ λͺ¨λΈ ν‘œμ‹œ (μ‚¬μš©μž λͺ…μ‹œ): agent[claude Β· claude-opus-4-7 / actor / β–Ά]>
11640
+ const prompt = () => {
11641
+ if (!isTty) return 'agent> ';
11642
+ const modelShort = (state.model || '').replace(/^(claude|gpt|gemini)-/, '').slice(0, 18);
11643
+ const modelTag = modelShort ? C.dim(' Β· ') + C.mag(modelShort) : '';
11644
+ return C.cy(`agent[${state.provider}${modelTag}${C.cy('/' + state.role)}${state.streamMode ? C.cy('/β–Ά') : ''}${C.cy(']>')} `);
11645
+ };
11602
11646
  rl.setPrompt(prompt());
11603
11647
 
11604
11648
  // 1.9.170: Tab cycle β€” provider (Tab) / model within provider (Shift+Tab)
@@ -12012,13 +12056,13 @@ async function _agentRepl(root, opts) {
12012
12056
  // 1.9.170: stream λͺ¨λ“œμ—μ„œλŠ” 이미 μ‹€μ‹œκ°„μœΌλ‘œ 좜λ ₯λμœΌλ―€λ‘œ ν—€λ”λ§Œ ν‘œμ‹œ (응닡 쀑볡 λ°©μ§€)
12013
12057
  if (state.streamMode && ['claude', 'codex', 'gemini', 'copilot'].includes(state.provider)) {
12014
12058
  log(C.dim(` [assistant: ${state.provider}/${state.model || 'default'}, role=${state.role}, ${dt}ms Β· ${result.response.length}자]`));
12015
- log('');
12016
12059
  } else {
12017
12060
  log('');
12018
12061
  log(C.bold(`assistant (${state.model || state.provider}, role=${state.role}, ${dt}ms)`));
12019
12062
  log(result.response);
12020
- log('');
12021
12063
  }
12064
+ // 1.9.188 (μ‚¬μš©μž λͺ…μ‹œ): 응닡 끝 + μž…λ ₯ ꡬ뢄선 (μž…λ ₯μΉΈ μ‹œκ° λͺ…ν™•)
12065
+ _printInputDivider();
12022
12066
  if (state.history.length % 6 === 0) saveSession(); // 6ν„΄λ§ˆλ‹€ μžλ™ μ €μž₯
12023
12067
  } else {
12024
12068
  // 1.9.185 (μ‚¬μš©μž λͺ…μ‹œ): REPL 호좜 μ‹€νŒ¨ μΉœμ ˆν•œ 진단 β€” μ–΄λŠ λ‹¨κ³„μ—μ„œ μ‹€νŒ¨ν–ˆλŠ”μ§€ + μ¦‰μ‹œ 검증 λͺ…λ Ή μ•ˆλ‚΄
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.187",
3
+ "version": "1.9.188",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",