leerness 1.9.183 β†’ 1.9.185

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,166 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.185 β€” 2026-05-21
4
+
5
+ **πŸ”§ DEP0190 μžμ‹ process μ „νŒŒ fix + REPL stream 친절 진단 + Hermes UX 뢄석 보고 (μ‚¬μš©μž λͺ…μ‹œ).**
6
+
7
+ 자율 λͺ¨λ“œ 115 λΌμš΄λ“œ. μ‚¬μš©μž λͺ…μ‹œ 3μ’…:
8
+ 1. *"REPL μ—μ΄μ „νŠΈ λͺ¨λ“œ ꡬ동 μ‹€νŒ¨ + μΆ”λ‘ λ‚΄μš©/diff λ―Έν‘œμ‹œ"* β†’ μΉœμ ˆν•œ 진단 λ©”μ‹œμ§€
9
+ 2. *"agent[claude/actor/β–Ά]> (node:54076) [DEP0190] ..."* β†’ μžμ‹ process μ „νŒŒ fix
10
+ 3. *"SSH duffy@192.168.68.89 의 hermes REPL UX 확인 β†’ μœ μ‚¬ κ΅¬ν˜„"* β†’ λ³΄κ³ μ„œ μž‘μ„±
11
+
12
+ ### Fix #1 β€” DEP0190 μžμ‹ process μ „νŒŒ
13
+ 1.9.184 의 `process.on('warning')` ν•Έλ“€λŸ¬λŠ” λΆ€λͺ¨λ§Œ. claude/codex/gemini CLI κ°€ λ‚΄λΆ€ Node child λ₯Ό spawnν•  λ•Œ μžμ‹μ— 상속 X β†’ μ‚¬μš©μž REPL μž…λ ₯ 후에도 DEP0190 좜λ ₯.
14
+
15
+ ```js
16
+ // 1.9.185 (μ‚¬μš©μž λͺ…μ‹œ): NODE_OPTIONS=--no-deprecation μžλ™ μ„€μ • β†’ λͺ¨λ“  Node child κΉŒμ§€ μ „νŒŒ.
17
+ if (!/--no-deprecation/.test(process.env.NODE_OPTIONS || '')) {
18
+ process.env.NODE_OPTIONS = ((process.env.NODE_OPTIONS || '') + ' --no-deprecation').trim();
19
+ }
20
+ ```
21
+
22
+ `process.env` 변경은 μžμ‹ spawn μ‹œ 상속. λΆ€λͺ¨λŠ” 1.9.184 의 `process.on('warning')` 으둜 처리.
23
+
24
+ ### Fix #2 β€” REPL stream μ‹€νŒ¨ 친절 진단
25
+ **Before**:
26
+ ```
27
+ agent[claude/actor/β–Ά]> μ›Ήκ°œλ°œμ„ μ§„ν–‰ν•΄μ€˜
28
+ ── /stream (120053ms) ──
29
+ ⚠ μ‹€νŒ¨: exit=null
30
+ πŸ’‘ μ „ν™˜ κ°€λŠ₯: :provider codex / :provider gemini / :provider copilot
31
+ ```
32
+
33
+ **After**:
34
+ ```
35
+ agent[claude/actor/β–Ά]> μ›Ήκ°œλ°œμ„ μ§„ν–‰ν•΄μ€˜
36
+ ── /stream (120053ms) ──
37
+ ⚠ claude CLI 응닡 μ‹€νŒ¨: exit=null
38
+ ↳ κ°€λŠ₯ 원인: (1) claude CLI 응닡 μ‹œκ°„ 초과 (λͺ¨λΈ λ‘œλ”©/큰 응닡 λŒ€κΈ° 쀑)
39
+ (2) network/auth 문제 (특히 codex/gemini λŠ” 인터넷 + 토큰 ν•„μš”)
40
+ ↳ 직접 검증: claude --print "ping"
41
+ πŸ’‘ μ¦‰μ‹œ μ „ν™˜: :provider codex Β· :provider gemini Β· :provider copilot λ˜λŠ” Tab ν‚€
42
+ ```
43
+
44
+ μ‹€νŒ¨ μΌ€μ΄μŠ€ λΆ„κΈ°:
45
+ - `exit=null` / `timeout` β†’ 응닡 μ‹œκ°„ 초과 + 직접 검증 λͺ…λ Ή
46
+ - `exit=1` / `unauth` / `login` β†’ 인증 λˆ„λ½ + login λͺ…λ Ή (claude/codex/gemini login, copilot=gh auth login)
47
+
48
+ ### #3 β€” Hermes UX 뢄석 (μ‚¬μš©μž SSH 접속 μš”μ²­)
49
+
50
+ **SSH λ³΄μ•ˆ μ •μ±…**: νŒ¨μŠ€μ›Œλ“œλŠ” `LEERNESS_SSH_PASS` env λ³€μˆ˜λ‘œλ§Œ 전달. paramiko μž„μ‹œ μŠ€ν¬λ¦½νŠΈλŠ” 뢄석 μ™„λ£Œ ν›„ μ¦‰μ‹œ μ‚­μ œ. μ½”λ“œ/λ‘œκ·Έμ— μ ˆλŒ€ μ €μž₯ X.
51
+
52
+ **Hermes 사양 확인** (v0.14.0, Python 3.11, 89 commands Β· 29 tools Β· 85 skills):
53
+ - μœ„μΉ˜: `~/.local/bin/hermes` (Ollama hermes-gemma:latest)
54
+ - 2-column Welcome λ°•μŠ€ (logo + toolsets/skills catalog)
55
+ - μ‹€μ‹œκ°„ μƒνƒœλ°”: `βš• model β”‚ ctx % β”‚ [progress bar] β”‚ elapsed β”‚ ⏲ timer`
56
+ - minimal prompt: `❯ `
57
+ - slash commands: `/help`, `/compress`, `/quit`
58
+ - `-z/--oneshot` 슀크립트 λͺ¨λ“œ (λ°°λ„ˆ/μŠ€ν”Όλ„ˆ/μ„Έμ…˜ID λͺ¨λ‘ 제거)
59
+
60
+ **leerness 차용 후보** (1.9.186+):
61
+ 1. μƒνƒœλ°” μ‹€μ‹œκ°„ κ°±μ‹  (`⚑ provider β”‚ ctx N% β”‚ [bar] β”‚ elapsed β”‚ ⏲ timer`)
62
+ 2. `:compress` slash command β€” context μ••μΆ•
63
+ 3. 2-column Welcome λ°•μŠ€ μž¬λ””μžμΈ
64
+ 4. `--oneshot/-z` λͺ…ν™•ν™” (λ°°λ„ˆ/μŠ€ν”Όλ„ˆ 제거)
65
+ 5. Tip 라인 (`✦ Tip: ...`)
66
+
67
+ 상세 λ³΄κ³ μ„œ: `_reports/hermes-ux-analysis-1.9.185.md` (λΉ„κ³΅κ°œ)
68
+
69
+ ### Verified
70
+ - stress-v130: **15/15 PASS** (μ‚¬μš©μž λͺ…μ‹œ 4 + live 3 + λˆ„μ  8)
71
+ - e2e 217/217 baseline μœ μ§€
72
+ - `agents list` 호좜: DEP0190 좜λ ₯ μ—†μŒ βœ“
73
+ - VERSION = 1.9.185 Β· autonomous-rounds = 115 Β· main μžλ™ push 46 λΌμš΄λ“œ 연속
74
+
75
+ ---
76
+
77
+ ## 1.9.184 β€” 2026-05-21
78
+
79
+ **🎨 μ„€μΉ˜ UX 4μ’… β€” Ctrl+C 확인 prompt + λ‘œλ”©λ°” + skillpack μ œμ™Έ + DEP0190 μ–΅μ œ (μ‚¬μš©μž λͺ…μ‹œ).**
80
+
81
+ 자율 λͺ¨λ“œ 114 λΌμš΄λ“œ. μ‚¬μš©μž λͺ…μ‹œ 4μ’…:
82
+ 1. *"μ„€μΉ˜ κ°€μ΄λ“œμ—μ„œ Ctrl+C μž…λ ₯ μ‹œ μ„€μΉ˜ μ’…λ£Œ μ—¬λΆ€ 확인 둜직 μΆ”κ°€"* β†’ SIGINT handler (2단계 confirm)
83
+ 2. *"leerness 파일 μ„€μΉ˜ μ‹œμž‘ μ‹œ λ‘œλ”©λ°”λ‘œ κ΅¬ν˜„ + 생성 λͺ©λ‘ λ‚˜μ—΄ X"* β†’ progress bar (TTY)
84
+ 3. *"leerness-skillpack λ―Έμ‚¬μš© μ˜ˆμ • β†’ μ œμ™Έ"* β†’ μ•ˆλ‚΄ λ©”μ‹œμ§€ 제거
85
+ 4. *"REPL agent λͺ¨λ“œ μ§„μž… μ‹œ DEP0190 deprecation warning 제거"* β†’ process warning handler
86
+
87
+ ### Fix #1 β€” Ctrl+C μ’…λ£Œ 확인 prompt
88
+ ```js
89
+ // 1.9.184 (μ‚¬μš©μž λͺ…μ‹œ): μ„€μΉ˜ 도쀑 Ctrl+C μ‹œ μ’…λ£Œ 확인 prompt.
90
+ // 첫 Ctrl+C β†’ μ•ˆλ‚΄ (2초 이내 ν•œ 번 더 β†’ μ’…λ£Œ, κ·Έ μ™Έ β†’ 계속).
91
+ let _sigintCount = 0; let _sigintTimer = null;
92
+ const _sigintHandler = () => {
93
+ _sigintCount++;
94
+ if (_sigintCount === 1) {
95
+ process.stdout.write('\n\n ⚠ μ„€μΉ˜ μ€‘λ‹¨ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? Ctrl+C λ₯Ό 2초 이내에 ν•œ 번 더 λˆ„λ₯΄λ©΄ μ’…λ£Œλ©λ‹ˆλ‹€. (κ·Έ μ™Έ β†’ 계속 μ§„ν–‰)\n');
96
+ _sigintTimer = setTimeout(() => { _sigintCount = 0; }, 2000);
97
+ return;
98
+ }
99
+ process.exit(130);
100
+ };
101
+ ```
102
+ install μ‹œμž‘μ— 등둝, μ’…λ£Œ/REPL μ§„μž… μ‹œ cleanup.
103
+
104
+ ### Fix #2 β€” 파일 μ„€μΉ˜ progress bar (생성 λͺ©λ‘ λ―Έν‘œμ‹œ)
105
+ **Before** (line by line):
106
+ ```
107
+ βœ“ create: AGENTS.md
108
+ βœ“ create: CLAUDE.md
109
+ βœ“ create: .harness/HARNESS_VERSION
110
+ βœ“ create: .harness/manifest.json
111
+ ... (μˆ˜μ‹­ 쀄)
112
+ ```
113
+
114
+ **After** (single progress bar):
115
+ ```
116
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘ 24/30 (80%) .harness/skills/office/SKILL.md
117
+ ```
118
+ μ™„λ£Œ μ‹œ:
119
+ ```
120
+ βœ“ leerness 파일 μ„€μΉ˜ μ™„λ£Œ (30개)
121
+ ```
122
+
123
+ ### Fix #3 β€” leerness-skillpack μ•ˆλ‚΄ 제거
124
+ ```diff
125
+ - if (SKILLPACK_SOURCE === 'builtin') log(`Skill catalog source: builtin (leerness-skillpack λ―Έμ„€μΉ˜ β€” npm i leerness-skillpack 둜 ν™•μž₯ κ°€λŠ₯)`);
126
+ - else log(`Skill catalog source: ${SKILLPACK_SOURCE} (leerness-skillpack${SKILLPACK_META ? ` v${SKILLPACK_META.version}` : ''})`);
127
+ + // 1.9.184 (μ‚¬μš©μž λͺ…μ‹œ): leerness-skillpack λ―Έμ‚¬μš© μ •μ±… β€” μ•ˆλ‚΄ λ©”μ‹œμ§€ 제거. builtin catalog 만 μ‚¬μš©.
128
+ ```
129
+
130
+ ### Fix #4 β€” DEP0190 DeprecationWarning μ–΅μ œ
131
+ 파일 μ΅œμƒλ‹¨μ—μ„œ process warning handler 등둝:
132
+ ```js
133
+ // 1.9.184: DEP0190 (child_process shell: true) deprecation warning μ–΅μ œ (μ‚¬μš©μž λͺ…μ‹œ).
134
+ // leerness λŠ” cross-platform PATH resolution 을 μœ„ν•΄ shell: true λ₯Ό μ˜λ„μ μœΌλ‘œ μ‚¬μš©.
135
+ process.removeAllListeners('warning');
136
+ process.on('warning', (w) => {
137
+ if (w && (w.code === 'DEP0190' || /DEP0190/.test(String(w.message || '')))) return;
138
+ process.stderr.write(`(node:${process.pid}) ${w.name || 'Warning'}: ${w.message || w}\n`);
139
+ });
140
+ ```
141
+
142
+ **Before** (REPL μ§„μž… μ‹œ):
143
+ ```
144
+ agent[claude/actor/β–Ά]> (node:54076) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true...
145
+ ```
146
+
147
+ **After** (REPL μ§„μž… μ‹œ):
148
+ ```
149
+ agent[claude/actor/β–Ά]> _
150
+ ```
151
+ 깔끔.
152
+
153
+ ### Verified
154
+ - stress-v129: **14/14 PASS** (μ‚¬μš©μž λͺ…μ‹œ 4 + live install 3 + λˆ„μ  7)
155
+ - e2e 217/217 baseline μœ μ§€
156
+ - live install 검증:
157
+ - DEP0190 좜λ ₯ μ•ˆ 됨 βœ“
158
+ - "Skill catalog source: builtin" μ•ˆλ‚΄ μ—†μŒ βœ“
159
+ - 파일 생성 λͺ©λ‘ 0건 (non-TTY) βœ“
160
+ - VERSION = 1.9.184 Β· autonomous-rounds = 114 Β· main μžλ™ push 45 λΌμš΄λ“œ 연속
161
+
162
+ ---
163
+
3
164
  ## 1.9.183 β€” 2026-05-21
4
165
 
5
166
  **πŸ“¦ npm i leerness + ꡬ버전 μžλ™ 감지/κ²½κ³ /μ—…λ°μ΄νŠΈ λͺ…λ Ήμ–΄ μ•ˆλ‚΄ (μ‚¬μš©μž λͺ…μ‹œ 3μ’…).**
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.183-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v128-16%2F16-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-113-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-44_rounds-success)]() [![install](https://img.shields.io/badge/npm_i_leerness-μ¦‰μ‹œ_μ‚¬μš©_κ°€λŠ₯-success)]() [![stale-check](https://img.shields.io/badge/ꡬ버전_감지-λͺ¨λ“ _λͺ…λ Ή_μ‹œμ -success)]() [![skill-presets](https://img.shields.io/badge/skill_catalog-곡식_2μ’…%2B--github_ν™•μž₯-success)]() [![direction](https://img.shields.io/badge/λ°©ν–₯μ„±_평가-86%2F100-brightgreen)]() [![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.185-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v130-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-115-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-46_rounds-success)]() [![dep-child](https://img.shields.io/badge/DEP0190-λΆ€λͺ¨%2Bμžμ‹_μ „νŒŒ-success)]() [![repl-diag](https://img.shields.io/badge/REPL_μ‹€νŒ¨-친절_진단_μ•ˆλ‚΄-success)]() [![hermes-ux](https://img.shields.io/badge/Hermes_UX-뢄석_μ™„λ£Œ-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.183 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.185 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ 🌐 곡식 catalog μžλ™ 탐색 Β· μžκ°€ μ„±μž₯ν˜• Β· ꡬ버전 감지/μ•ˆλ‚΄ β•‘
17
+ β•‘ πŸ”§ DEP0190 μžμ‹ μ „νŒŒΒ·REPL 친절 진단·Hermes UX 뢄석 β•‘
18
18
  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
19
19
  ```
20
20
 
package/bin/harness.js CHANGED
@@ -7,7 +7,23 @@ 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.183';
10
+ const VERSION = '1.9.185';
11
+
12
+ // 1.9.184: DEP0190 (child_process shell: true) deprecation warning μ–΅μ œ (μ‚¬μš©μž λͺ…μ‹œ).
13
+ // leerness λŠ” cross-platform PATH resolution 을 μœ„ν•΄ shell: true λ₯Ό μ˜λ„μ μœΌλ‘œ μ‚¬μš© (claude.cmd / ollama.cmd λ“± Windows .cmd 처리).
14
+ // 인자 escape κ°€ ν•„μš”ν•œ μœ„μΉ˜λŠ” κ²€μ¦λœ μž…λ ₯만 spawnSync 에 전달. REPL agent μ§„μž… μ‹œ _checkAgent κ°€ λ°œμ‚°ν•˜λŠ” λ…Έμ΄μ¦ˆ 제거.
15
+ process.removeAllListeners('warning');
16
+ process.on('warning', (w) => {
17
+ if (w && (w.code === 'DEP0190' || /DEP0190/.test(String(w.message || '')))) return;
18
+ process.stderr.write(`(node:${process.pid}) ${w.name || 'Warning'}: ${w.message || w}\n`);
19
+ });
20
+ // 1.9.185 (μ‚¬μš©μž λͺ…μ‹œ): REPL μ§„μž… ν›„ user input μ‹œμ μ—λ„ DEP0190 λ°œμƒ (claude/ollama CLI κ°€ Node μžμ‹ spawn μ‹œ μžμ‹μ˜ λ…Έμ΄μ¦ˆ).
21
+ // λΆ€λͺ¨ ν•Έλ“€λŸ¬λŠ” μžμ‹μ— 상속 X β†’ NODE_OPTIONS=--no-deprecation 으둜 λͺ¨λ“  Node child κΉŒμ§€ μ „νŒŒ.
22
+ // process.env 변경은 μžμ‹ spawn μ‹œ 상속 (이미 μ‹œμž‘λœ λΆ€λͺ¨μ—λŠ” 영ν–₯ X, λΆ€λͺ¨λŠ” μœ„μ˜ 'warning' ν•Έλ“€λŸ¬λ‘œ 처리).
23
+ if (!/--no-deprecation/.test(process.env.NODE_OPTIONS || '')) {
24
+ process.env.NODE_OPTIONS = ((process.env.NODE_OPTIONS || '') + ' --no-deprecation').trim();
25
+ }
26
+
11
27
  const MARK = '<!-- leerness:managed -->';
12
28
  const README_START = '<!-- leerness:project-readme:start -->';
13
29
  const README_END = '<!-- leerness:project-readme:end -->';
@@ -767,6 +783,26 @@ async function resolveInstallOptions(root, opts = {}) {
767
783
 
768
784
  async function install(root, opts = {}) {
769
785
  root = absRoot(root); mkdirp(root);
786
+ // 1.9.184 (μ‚¬μš©μž λͺ…μ‹œ): μ„€μΉ˜ 도쀑 Ctrl+C μ‹œ μ’…λ£Œ 확인 prompt.
787
+ // 첫 Ctrl+C β†’ μ•ˆλ‚΄ (2초 이내 ν•œ 번 더 β†’ μ’…λ£Œ, κ·Έ μ™Έ β†’ 계속).
788
+ // readline raw mode μ‹œ readline 이 'SIGINT' 이벀트둜 ν‘μˆ˜ν•  수 μžˆμ–΄ process-level + finally ν•΄μ œ.
789
+ let _sigintCount = 0; let _sigintTimer = null;
790
+ const _sigintHandler = () => {
791
+ _sigintCount++;
792
+ if (_sigintCount === 1) {
793
+ try { process.stdout.write('\n\n ⚠ μ„€μΉ˜ μ€‘λ‹¨ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ? Ctrl+C λ₯Ό 2초 이내에 ν•œ 번 더 λˆ„λ₯΄λ©΄ μ’…λ£Œλ©λ‹ˆλ‹€. (κ·Έ μ™Έ β†’ 계속 μ§„ν–‰)\n'); } catch {}
794
+ clearTimeout(_sigintTimer);
795
+ _sigintTimer = setTimeout(() => { _sigintCount = 0; }, 2000);
796
+ return;
797
+ }
798
+ clearTimeout(_sigintTimer);
799
+ try { process.stdout.write('\n βœ— μ„€μΉ˜ 쀑단됨 (μ‚¬μš©μž μš”μ²­)\n'); } catch {}
800
+ process.exit(130);
801
+ };
802
+ if (!opts.migration && !opts.nonInteractive && process.stdin.isTTY) {
803
+ process.on('SIGINT', _sigintHandler);
804
+ }
805
+ const _cleanupSigint = () => { try { process.removeListener('SIGINT', _sigintHandler); clearTimeout(_sigintTimer); } catch {} };
770
806
  // 1.9.41: migrate 직전 이전 버전 캑처 β€” μ°¨λΆ„ μ•ˆλ‚΄μ— μ‚¬μš©
771
807
  try {
772
808
  const hv = path.join(root, '.harness', 'HARNESS_VERSION');
@@ -796,8 +832,7 @@ async function install(root, opts = {}) {
796
832
  if (resolved.startRepl) log(`REPL μžλ™ μ‹œμž‘: 예 (μ„€μΉ˜ μ™„λ£Œ ν›„ \`leerness agent\` μ§„μž…)`);
797
833
  if (resolved.permissionMode) log(`Agent κΆŒν•œ λͺ¨λ“œ: ${resolved.permissionMode} (1.9.174 β€” REPLμ—μ„œ \`:permissions extended|full\` 둜 μ¦‰μ‹œ λ³€κ²½ κ°€λŠ₯)`);
798
834
  // 1.9.10: μŠ€ν‚¬ μΉ΄νƒˆλ‘œκ·Έ 좜처 μ•ˆλ‚΄
799
- if (SKILLPACK_SOURCE === 'builtin') log(`Skill catalog source: builtin (leerness-skillpack λ―Έμ„€μΉ˜ β€” \`npm i leerness-skillpack\`둜 ν™•μž₯ κ°€λŠ₯)`);
800
- else log(`Skill catalog source: ${SKILLPACK_SOURCE} (leerness-skillpack${SKILLPACK_META ? ` v${SKILLPACK_META.version}` : ''})`);
835
+ // 1.9.184 (μ‚¬μš©μž λͺ…μ‹œ): leerness-skillpack λ―Έμ‚¬μš© μ •μ±… β€” μ•ˆλ‚΄ λ©”μ‹œμ§€ 제거. builtin catalog 만 μ‚¬μš©.
801
836
  const files = coreFiles(root, lang, skills);
802
837
  const backup = createBackup(root, opts.force ? 'force' : (opts.migration ? 'migration' : 'init'), files, opts.dry);
803
838
  if (opts.dry) {
@@ -816,7 +851,20 @@ async function install(root, opts = {}) {
816
851
  '.claude/commands/handoff.md','.claude/commands/session-close.md','.claude/commands/audit.md','.claude/commands/lazy-detect.md','.claude/commands/update.md',
817
852
  '.claude/skills/leerness.md'
818
853
  ]);
854
+ // 1.9.184 (μ‚¬μš©μž λͺ…μ‹œ): 파일 μ„€μΉ˜ β€” 생성 λͺ©λ‘ λ‚˜μ—΄ X, λ‘œλ”©λ°” + 단일 μ™„λ£Œ λ©”μ‹œμ§€.
819
855
  const actions = [];
856
+ const totalFiles = Object.keys(files).length;
857
+ const isTty = process.stdout.isTTY && !opts.dry;
858
+ const drawProgress = (done, file) => {
859
+ if (!isTty) return;
860
+ const pct = Math.round(done * 100 / totalFiles);
861
+ const filled = Math.floor(pct / 5);
862
+ const bar = '\x1b[36m' + 'β–ˆ'.repeat(filled) + '\x1b[2m' + 'β–‘'.repeat(20 - filled) + '\x1b[0m';
863
+ const truncFile = (file || '').length > 32 ? '...' + file.slice(-29) : (file || '');
864
+ process.stdout.write(`\r ${bar} \x1b[1m${done}/${totalFiles}\x1b[0m (${pct}%) \x1b[2m${truncFile}\x1b[0m\x1b[K`);
865
+ };
866
+ drawProgress(0, '');
867
+ let _done = 0;
820
868
  for (const [f, c] of Object.entries(files)) {
821
869
  const existsNow = exists(path.join(root, f));
822
870
  const mergeManaged = managedOverwrite.has(f);
@@ -828,7 +876,12 @@ async function install(root, opts = {}) {
828
876
  }
829
877
  const r = writeIfSafe(root, f, c, { force: opts.force, mergeManaged, archiveDir: backup.archiveDir });
830
878
  actions.push(r);
831
- ok(`${r.action}: ${r.file}`);
879
+ _done++;
880
+ drawProgress(_done, f);
881
+ }
882
+ if (isTty) {
883
+ process.stdout.write('\r\x1b[K'); // clear progress line
884
+ log(` \x1b[32mβœ“\x1b[0m leerness 파일 μ„€μΉ˜ μ™„λ£Œ (${totalFiles}개)`);
832
885
  }
833
886
  if (!opts.dry) {
834
887
  mergeLinesFile(path.join(root, '.gitignore'), [
@@ -943,11 +996,13 @@ async function install(root, opts = {}) {
943
996
  log('');
944
997
  log('πŸš€ μ„€μΉ˜ μ™„λ£Œ β€” REPL agent λͺ¨λ“œλ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€...');
945
998
  log('');
999
+ _cleanupSigint(); // 1.9.184: REPL μ§„μž… μ „ SIGINT handler ν•΄μ œ (readline 이 자체 처리)
946
1000
  try {
947
1001
  await _agentRepl(root, { role: 'actor' }); // provider λ―Έμ§€μ • β†’ _agentRepl 의 auto-select λ™μž‘ (1.9.181 fix)
948
1002
  } catch (e) { warn('REPL μ§„μž… μ‹€νŒ¨: ' + e.message); }
949
1003
  }
950
1004
  }
1005
+ _cleanupSigint(); // 1.9.184: install ν•¨μˆ˜ μ’…λ£Œ μ‹œ SIGINT handler ν•΄μ œ (λͺ¨λ“  μ’…λ£Œ 경둜)
951
1006
  }
952
1007
 
953
1008
  function installSkills(root, skills) { for (const name of skills) addSkill(root, name, true); }
@@ -11819,14 +11874,25 @@ async function _agentRepl(root, opts) {
11819
11874
  }
11820
11875
  if (state.history.length % 6 === 0) saveSession(); // 6ν„΄λ§ˆλ‹€ μžλ™ μ €μž₯
11821
11876
  } else {
11822
- log(C.yel(` ⚠ μ‹€νŒ¨: ${result.error || 'unknown'}`));
11823
- // 1.9.164: μ‹€νŒ¨ μ‹œ μ¦‰μ‹œ μ „ν™˜ κ°€λŠ₯ provider μ•ˆλ‚΄ (UX κ°œμ„  β€” μ‚¬μš©μž λͺ…μ‹œ μš”μ²­)
11877
+ // 1.9.185 (μ‚¬μš©μž λͺ…μ‹œ): REPL 호좜 μ‹€νŒ¨ μΉœμ ˆν•œ 진단 β€” μ–΄λŠ λ‹¨κ³„μ—μ„œ μ‹€νŒ¨ν–ˆλŠ”μ§€ + μ¦‰μ‹œ 검증 λͺ…λ Ή μ•ˆλ‚΄
11878
+ const errMsg = result.error || 'unknown';
11879
+ log(C.yel(` ⚠ ${state.provider} CLI 응닡 μ‹€νŒ¨: ${errMsg}`));
11880
+ // μ‹€νŒ¨ 원인 λΆ„λ₯˜
11881
+ if (/exit=null/.test(errMsg) || /timeout/i.test(errMsg)) {
11882
+ log(C.dim(` ↳ κ°€λŠ₯ 원인: (1) ${state.provider} CLI 응닡 μ‹œκ°„ 초과 (λͺ¨λΈ λ‘œλ”©/큰 응닡 λŒ€κΈ° 쀑)`));
11883
+ log(C.dim(` (2) network/auth 문제 (특히 codex/gemini λŠ” 인터넷 + 토큰 ν•„μš”)`));
11884
+ log(C.dim(` ↳ 직접 검증: ${state.provider} --print "ping" ${state.provider === 'gemini' ? '--yolo' : ''}`));
11885
+ } else if (/exit=1/.test(errMsg) || /unauth/i.test(errMsg) || /login/i.test(errMsg)) {
11886
+ log(C.dim(` ↳ κ°€λŠ₯ 원인: 인증 λˆ„λ½ (login ν•„μš”)`));
11887
+ log(C.dim(` ↳ ν•΄κ²°: ${state.provider} login ${state.provider === 'copilot' ? '(gh auth login)' : ''}`));
11888
+ }
11889
+ // μ „ν™˜ κ°€λŠ₯ provider μ•ˆλ‚΄
11824
11890
  try {
11825
11891
  const others = EXTERNAL_AGENTS.filter(a => a.id !== state.provider)
11826
11892
  .map(a => ({ def: a, status: _checkAgent(a) }))
11827
11893
  .filter(x => x.status.status === 'ready');
11828
11894
  if (others.length) {
11829
- log(C.dim(` πŸ’‘ μ „ν™˜ κ°€λŠ₯: ${others.map(x => `:provider ${x.def.id}`).join(' / ')}`));
11895
+ log(C.dim(` πŸ’‘ μ¦‰μ‹œ μ „ν™˜: ${others.map(x => `:provider ${x.def.id}`).join(' Β· ')} λ˜λŠ” Tab ν‚€`));
11830
11896
  } else {
11831
11897
  log(C.dim(` πŸ’‘ λ‹€λ₯Έ provider ν™œμ„±ν™”: .env μ—μ„œ LEERNESS_ENABLE_<CLAUDE|CODEX|GEMINI|COPILOT>=1`));
11832
11898
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.183",
3
+ "version": "1.9.185",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",