leerness 1.9.248 → 1.9.250
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 +77 -0
- package/README.md +3 -3
- package/bin/harness.js +128 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,82 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.250 — 2026-05-28 — UR-0018 2단계 POSIX 인코딩 자동 회복 (Linux/macOS/WSL)
|
|
4
|
+
|
|
5
|
+
**🌐 UR-0018 후속: Windows + POSIX 양방향 인코딩 보호 완성.**
|
|
6
|
+
|
|
7
|
+
### 배경
|
|
8
|
+
1.9.249는 Windows (CP949 → 65001) 에 집중. POSIX (Linux/macOS) 한국어 환경 + WSL 사용자도 LANG/LC_ALL 미설정 시 동일한 한글 깨짐 발생.
|
|
9
|
+
|
|
10
|
+
### 구현
|
|
11
|
+
1. **`_collectRuntimeEnv` 확장** (locale 필드):
|
|
12
|
+
- `posixEncodingOk: boolean | null` — LANG/LC_ALL/LC_CTYPE 에 UTF-8 포함 여부
|
|
13
|
+
- `isWSL: boolean` — `/proc/version` "microsoft" 매칭 또는 `WSL_DISTRO_NAME` env
|
|
14
|
+
2. **env summary**:
|
|
15
|
+
- `✓ POSIX locale UTF-8 — Linux/macOS (WSL) 한국어 출력 안전`
|
|
16
|
+
- `⚠ POSIX locale에 UTF-8 없음 (LANG=…) — 한국어 출력 깨질 위험`
|
|
17
|
+
- `→ 권장: export LANG=ko_KR.UTF-8 (또는 export LC_ALL=C.UTF-8)`
|
|
18
|
+
3. **handoff body**:
|
|
19
|
+
- `## ⚠ 터미널 인코딩 — POSIX(WSL) locale에 UTF-8 없음 (1.9.250, UR-0018 2단계)`
|
|
20
|
+
- `~/.bashrc 또는 ~/.zshrc 에 추가` 영구 적용 안내
|
|
21
|
+
4. **JSON envInfo 4필드 propagate** (handoff/session close/health 3 명령 일관성):
|
|
22
|
+
- `terminalEncodingOk` (1.9.249) — 이전 라운드에서 handoff 만 적용 → session close/health 추가
|
|
23
|
+
- `autoChcpApplied` (1.9.249) — 동일 propagate
|
|
24
|
+
- `posixEncodingOk` (1.9.250 신규)
|
|
25
|
+
- `isWSL` (1.9.250 신규)
|
|
26
|
+
|
|
27
|
+
### 영향 받지 않은 영역
|
|
28
|
+
- Windows chcp 65001 자동 회복 (1.9.249) 유지
|
|
29
|
+
- 1.9.248 agy / 1.9.247 fallback / 1.9.246 status bar / 1.9.245 api-skill 모두 유지
|
|
30
|
+
- handoff JSON 11 필드 매트릭스 유지
|
|
31
|
+
|
|
32
|
+
### stress-v195 — **26/26 PASS · 100%**
|
|
33
|
+
- 1.9.250 (12): VERSION + IIFE + POSIX UTF-8 검사 + WSL 감지 + env summary + handoff body + JSON 3 명령 propagate (4 필드)
|
|
34
|
+
- 성능 (2): cold start avg 368ms · env summary --json avg 1120ms
|
|
35
|
+
- 누적 회귀 (12): 1.9.207~249
|
|
36
|
+
|
|
37
|
+
### 자동 release (112 main-push streak · 73 npm publish streak · R206)
|
|
38
|
+
|
|
39
|
+
🌐 **양방향 인코딩 보호 완성** — Windows + POSIX 모두 leerness 자체 출력 한글 깨짐 사전 차단.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 1.9.249 — 2026-05-28 — UR-0018 터미널 인코딩 자동 회복 (한국어 Windows)
|
|
44
|
+
|
|
45
|
+
**🌐 사용자 명시 (UR-0018): "leerness가 적용된 프로젝트에서 터미널 출력이 깨지지 않게, 하드웨어의 언어 등을 사전에 참고하여 진행".**
|
|
46
|
+
|
|
47
|
+
### 배경
|
|
48
|
+
사용자 보고: `.harness/protected-files.md` 출력에서 "?뚯씪 ??젣/?뺣━" 패턴 (UTF-8 → CP949 오해석) 발생. 한국어 Windows 기본 코드페이지(CP949, 949)에서 leerness가 UTF-8로 출력한 한글이 깨져 보이는 문제.
|
|
49
|
+
|
|
50
|
+
### 구현 (bootstrap 자동 회복 + 가시화)
|
|
51
|
+
1. **`_ensureStdoutEncoding()` IIFE** (harness.js bootstrap, DEP0190 다음):
|
|
52
|
+
- `process.stdout/stderr.setEncoding('utf8')` 즉시 강제
|
|
53
|
+
- Windows + 비-65001 코드페이지 감지 시 → `chcp.com 65001` 자동 호출 (best-effort)
|
|
54
|
+
- 결과를 `process.env._LEERNESS_AUTOCHCP_APPLIED` 에 기록
|
|
55
|
+
- 무한 재호출 방지: `_LEERNESS_CHCP_DONE='1'` 자식 process 가드
|
|
56
|
+
- opt-out: `LEERNESS_NO_AUTOCHCP=1`
|
|
57
|
+
2. **env summary** 강화:
|
|
58
|
+
- "터미널 인코딩 UTF-8 (65001) — 안전" / "터미널 코드페이지 CP949 — 한국어 출력 깨짐 위험" 명시
|
|
59
|
+
3. **handoff body** 한국어 Windows + 비-65001 시 경고 섹션 추가
|
|
60
|
+
4. **JSON envInfo** 신규 2필드:
|
|
61
|
+
- `terminalEncodingOk: codepage === 65001`
|
|
62
|
+
- `autoChcpApplied: process.env._LEERNESS_AUTOCHCP_APPLIED` (적용된 이전 코드페이지)
|
|
63
|
+
5. **BUG fix** (`_collectRuntimeEnv`): chcp 출력 파싱 regex `\d{3,4}` → `\d{3,5}` (65001 5자리 캡처)
|
|
64
|
+
|
|
65
|
+
### 영향 받지 않은 영역
|
|
66
|
+
- 1.9.248 agy / 1.9.247 fallback / 1.9.246 status bar / 1.9.245 api-skill / 1.9.244 HOTFIX 모두 유지
|
|
67
|
+
- handoff JSON 11 필드 매트릭스 유지 (envInfo 확장)
|
|
68
|
+
|
|
69
|
+
### stress-v194 — **23/23 PASS · 100%**
|
|
70
|
+
- 1.9.249 (10): VERSION + IIFE bootstrap + chcp 자동/opt-out/재호출 가드 + env summary + handoff body + JSON envInfo 2필드 + 실제 응답 (terminalEncodingOk=true) + env summary 실제 출력
|
|
71
|
+
- 성능 (2): cold start avg 385ms (autochcp 포함) · 357ms (opt-out)
|
|
72
|
+
- 누적 회귀 (11): 1.9.207~248 + 보안
|
|
73
|
+
|
|
74
|
+
### 자동 release (111 main-push streak · 72 npm publish streak · R205)
|
|
75
|
+
|
|
76
|
+
🌐 **사용자 환경 자동 회복** — Windows 한국어 사용자의 한글 깨짐을 코드페이지 차원에서 사전 차단.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
3
80
|
## 1.9.248 — 2026-05-26 — UR-0017 Gemini CLI 제거 + Antigravity CLI (agy) 도입
|
|
4
81
|
|
|
5
82
|
**🔄 사용자 명시 (UR-0017): Gemini CLI 제거 + Antigravity (agy) 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.250 AI Agent Reliability Harness + Sandbox ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · sandbox · drift ║
|
|
17
|
-
║
|
|
17
|
+
║ 🌐 인코딩 자동 회복 (Windows + POSIX/WSL · UR-0018 2단계) ║
|
|
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.250';
|
|
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 처리).
|
|
@@ -24,6 +24,36 @@ if (!/--no-deprecation/.test(process.env.NODE_OPTIONS || '')) {
|
|
|
24
24
|
process.env.NODE_OPTIONS = ((process.env.NODE_OPTIONS || '') + ' --no-deprecation').trim();
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// 1.9.249 (사용자 명시 UR-0018): 터미널 출력 한국어 깨짐 사전 방지
|
|
28
|
+
// 사용자 보고: protected-files.md 같은 한국어 텍스트가 ? / 한자 조각으로 깨짐 (UTF-8 → CP949 오인식)
|
|
29
|
+
// 조치: (1) stdout/stderr UTF-8 명시 (2) Windows + 한국어 OS + 비-65001 코드페이지 시 chcp 65001 자동 시도
|
|
30
|
+
// 안전: 1회만 시도 (LEERNESS_NO_AUTOCHCP=1 로 opt-out), 실패 시 무시
|
|
31
|
+
(function _ensureStdoutEncoding() {
|
|
32
|
+
try {
|
|
33
|
+
if (process.stdout && process.stdout.setEncoding) process.stdout.setEncoding('utf8');
|
|
34
|
+
if (process.stderr && process.stderr.setEncoding) process.stderr.setEncoding('utf8');
|
|
35
|
+
} catch {}
|
|
36
|
+
// Windows + 한국어 사용자 환경 (chcp 949 = CP949) → 한국어 콘솔 자동 65001 (UTF-8)
|
|
37
|
+
if (process.platform !== 'win32') return;
|
|
38
|
+
if (process.env.LEERNESS_NO_AUTOCHCP === '1') return;
|
|
39
|
+
if (process.env._LEERNESS_CHCP_DONE === '1') return; // 자식 spawn 무한 재호출 방지
|
|
40
|
+
try {
|
|
41
|
+
const r = cp.spawnSync('chcp.com', [], { encoding: 'utf8', timeout: 2000, shell: true });
|
|
42
|
+
const out = (r.stdout || '') + (r.stderr || '');
|
|
43
|
+
const m = out.match(/(\d+)\s*$/m);
|
|
44
|
+
const code = m ? parseInt(m[1], 10) : null;
|
|
45
|
+
// 65001 = UTF-8, 949 = CP949 (한국), 932 = CP932 (일본), 936 = CP936 (중국)
|
|
46
|
+
if (code && code !== 65001) {
|
|
47
|
+
// 자동 chcp 65001 시도 (실패해도 무시 — 출력 방향 X 인 비-TTY 등)
|
|
48
|
+
try {
|
|
49
|
+
cp.spawnSync('chcp.com', ['65001'], { encoding: 'utf8', timeout: 2000, shell: true, stdio: 'ignore' });
|
|
50
|
+
process.env._LEERNESS_AUTOCHCP_APPLIED = String(code); // 진단용 — handoff body 에서 노출
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
53
|
+
process.env._LEERNESS_CHCP_DONE = '1';
|
|
54
|
+
} catch {}
|
|
55
|
+
})();
|
|
56
|
+
|
|
27
57
|
const MARK = '<!-- leerness:managed -->';
|
|
28
58
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
29
59
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -2390,7 +2420,10 @@ function _collectRuntimeEnv() {
|
|
|
2390
2420
|
LC_CTYPE: process.env.LC_CTYPE || null,
|
|
2391
2421
|
// Windows 한국어 환경 detect
|
|
2392
2422
|
OEMCP: process.env.OEMCP || null, // CP949 = 949
|
|
2393
|
-
isKoreanWindows: false
|
|
2423
|
+
isKoreanWindows: false,
|
|
2424
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS/WSL) terminal encoding 점검
|
|
2425
|
+
isWSL: false,
|
|
2426
|
+
posixEncodingOk: null // POSIX 전용: LANG/LC_ALL 에 UTF-8 포함 시 true
|
|
2394
2427
|
},
|
|
2395
2428
|
hardware: {
|
|
2396
2429
|
cpus: os.cpus().length,
|
|
@@ -2408,9 +2441,9 @@ function _collectRuntimeEnv() {
|
|
|
2408
2441
|
// 한국어 Windows 감지
|
|
2409
2442
|
try {
|
|
2410
2443
|
if (env.os.platform === 'win32') {
|
|
2411
|
-
// chcp 출력으로 코드페이지 확인
|
|
2444
|
+
// chcp 출력으로 코드페이지 확인 (1.9.249 fix: 65001 (5자리) 까지 매칭 — 이전 \d{3,4} 는 "6500" 만 캡처 BUG)
|
|
2412
2445
|
const r = cp.spawnSync('chcp', [], { encoding: 'utf8', shell: true, timeout: 3000 });
|
|
2413
|
-
const m = (r.stdout || '').match(/(\d{3,
|
|
2446
|
+
const m = (r.stdout || '').match(/(\d{3,5})/);
|
|
2414
2447
|
if (m) {
|
|
2415
2448
|
const cp_num = parseInt(m[1], 10);
|
|
2416
2449
|
env.locale.codepage = cp_num;
|
|
@@ -2418,6 +2451,22 @@ function _collectRuntimeEnv() {
|
|
|
2418
2451
|
}
|
|
2419
2452
|
}
|
|
2420
2453
|
} catch {}
|
|
2454
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS) + WSL terminal encoding 점검
|
|
2455
|
+
// LANG/LC_ALL 에 UTF-8 포함 시 안전, 그렇지 않으면 macOS/Linux 한국어 터미널 깨질 위험
|
|
2456
|
+
try {
|
|
2457
|
+
if (env.os.platform === 'linux' || env.os.platform === 'darwin') {
|
|
2458
|
+
const langStr = (env.locale.LANG || '') + ' ' + (env.locale.LC_ALL || '') + ' ' + (env.locale.LC_CTYPE || '');
|
|
2459
|
+
env.locale.posixEncodingOk = /UTF-?8/i.test(langStr);
|
|
2460
|
+
// WSL 감지 (Linux 환경에서 /proc/version 에 microsoft 포함 시)
|
|
2461
|
+
if (env.os.platform === 'linux') {
|
|
2462
|
+
try {
|
|
2463
|
+
const procVer = fs.readFileSync('/proc/version', 'utf8');
|
|
2464
|
+
if (/microsoft|wsl/i.test(procVer)) env.locale.isWSL = true;
|
|
2465
|
+
} catch {}
|
|
2466
|
+
if (process.env.WSL_DISTRO_NAME) env.locale.isWSL = true;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
} catch {}
|
|
2421
2470
|
// PowerShell 감지
|
|
2422
2471
|
try {
|
|
2423
2472
|
if (env.os.platform === 'win32') {
|
|
@@ -2577,6 +2626,27 @@ function envCmd(root, sub) {
|
|
|
2577
2626
|
log(` 💻 OS: ${gr(env.os.platform)} ${env.os.release} (${env.os.arch})`);
|
|
2578
2627
|
log(` 📦 Node: ${gr(env.node.version)}`);
|
|
2579
2628
|
log(` 🌐 Locale: LANG=${env.locale.LANG || 'unset'} · CP=${env.locale.codepage || 'unknown'}${env.locale.isKoreanWindows ? yl(' (한국어 Windows)') : ''}`);
|
|
2629
|
+
// 1.9.249 (UR-0018): 터미널 출력 인코딩 자동 점검 — 한국어 Windows + 비-65001 → 경고 + 자동 회복 결과
|
|
2630
|
+
if (env.locale.isKoreanWindows && env.locale.codepage !== 65001) {
|
|
2631
|
+
log(yl(` ⚠ 터미널 코드페이지 ${env.locale.codepage} (CP949) — 한국어 출력 깨짐 위험`));
|
|
2632
|
+
if (process.env._LEERNESS_AUTOCHCP_APPLIED) {
|
|
2633
|
+
log(gr(` ✓ chcp 65001 자동 적용됨 (이전: ${process.env._LEERNESS_AUTOCHCP_APPLIED}, 1.9.249)`));
|
|
2634
|
+
} else {
|
|
2635
|
+
log(dm(` → 수동: chcp 65001 (또는 LEERNESS_NO_AUTOCHCP=0)`));
|
|
2636
|
+
}
|
|
2637
|
+
} else if (env.locale.codepage === 65001) {
|
|
2638
|
+
log(gr(` ✓ 터미널 인코딩 UTF-8 (65001) — 한국어 출력 안전`));
|
|
2639
|
+
}
|
|
2640
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS/WSL) terminal encoding 점검
|
|
2641
|
+
if (env.os.platform === 'linux' || env.os.platform === 'darwin') {
|
|
2642
|
+
const wslTag = env.locale.isWSL ? yl(' (WSL)') : '';
|
|
2643
|
+
if (env.locale.posixEncodingOk === true) {
|
|
2644
|
+
log(gr(` ✓ POSIX locale UTF-8 — ${env.os.platform === 'darwin' ? 'macOS' : 'Linux'}${wslTag} 한국어 출력 안전`));
|
|
2645
|
+
} else if (env.locale.posixEncodingOk === false) {
|
|
2646
|
+
log(yl(` ⚠ POSIX locale에 UTF-8 없음 (LANG=${env.locale.LANG || 'unset'}) — 한국어 출력 깨질 위험`));
|
|
2647
|
+
log(dm(` → 권장: export LANG=ko_KR.UTF-8 (또는 export LC_ALL=C.UTF-8)`));
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2580
2650
|
log(` 🖥 Hardware: ${env.hardware.cpus} CPUs · ${env.hardware.memGB} GB RAM`);
|
|
2581
2651
|
log(` 🖱 Terminal: TTY=${env.terminal.isTTY}${env.terminal.powershell ? ` · PowerShell v${env.terminal.powershell}` : ''}`);
|
|
2582
2652
|
log(` 🔧 Tools:`);
|
|
@@ -6977,6 +7047,7 @@ function handoff(root) {
|
|
|
6977
7047
|
};
|
|
6978
7048
|
} catch {}
|
|
6979
7049
|
// 1.9.242: envInfo 통합 (handoff JSON 10번째 통합 필드) — 환경 + 인코딩 위험 (UR-0014 2단계)
|
|
7050
|
+
// 1.9.249: terminalEncodingOk + autoChcpApplied 필드 추가 (UR-0018)
|
|
6980
7051
|
try {
|
|
6981
7052
|
const runtimeEnv = _collectRuntimeEnv();
|
|
6982
7053
|
const encScan = _scanShellScriptsEncoding(root);
|
|
@@ -6987,7 +7058,13 @@ function handoff(root) {
|
|
|
6987
7058
|
nodeVersion: runtimeEnv.node.version,
|
|
6988
7059
|
shellScriptsScanned: encScan.scanned,
|
|
6989
7060
|
encodingRiskCount: encScan.atRisk.length,
|
|
6990
|
-
encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file)
|
|
7061
|
+
encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file),
|
|
7062
|
+
// 1.9.249 (UR-0018): 터미널 출력 인코딩 안전 여부 + 자동 회복 결과
|
|
7063
|
+
terminalEncodingOk: runtimeEnv.locale.codepage === 65001 || !runtimeEnv.locale.isKoreanWindows,
|
|
7064
|
+
autoChcpApplied: process.env._LEERNESS_AUTOCHCP_APPLIED || null,
|
|
7065
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS/WSL) terminal encoding 점검
|
|
7066
|
+
posixEncodingOk: runtimeEnv.locale.posixEncodingOk,
|
|
7067
|
+
isWSL: runtimeEnv.locale.isWSL || false
|
|
6991
7068
|
};
|
|
6992
7069
|
} catch {}
|
|
6993
7070
|
// 1.9.245: apiSkills 통합 (handoff JSON 11번째 통합 필드) — UR-0015 API 문서 캐시
|
|
@@ -7375,6 +7452,38 @@ function handoff(root) {
|
|
|
7375
7452
|
}
|
|
7376
7453
|
} catch {}
|
|
7377
7454
|
|
|
7455
|
+
// 1.9.249 (UR-0018): 터미널 코드페이지 자동 점검 + 자동 회복 노출
|
|
7456
|
+
// 한국어 Windows + 비-65001 → leerness 출력 깨짐 위험 → 자동 chcp 65001 (bootstrap), 결과 본문 노출
|
|
7457
|
+
try {
|
|
7458
|
+
const runtimeEnv = _collectRuntimeEnv();
|
|
7459
|
+
if (runtimeEnv.locale.isKoreanWindows && runtimeEnv.locale.codepage !== 65001) {
|
|
7460
|
+
const isTty5 = process.stdout && process.stdout.isTTY;
|
|
7461
|
+
const yl6 = s => isTty5 ? `\x1b[33m${s}\x1b[0m` : s;
|
|
7462
|
+
const gr6 = s => isTty5 ? `\x1b[32m${s}\x1b[0m` : s;
|
|
7463
|
+
const dm6 = s => isTty5 ? `\x1b[2m${s}\x1b[0m` : s;
|
|
7464
|
+
log('');
|
|
7465
|
+
log(yl6(`## ⚠ 터미널 인코딩 — 한국어 Windows + CP${runtimeEnv.locale.codepage} (1.9.249, UR-0018)`));
|
|
7466
|
+
log(dm6(` leerness 출력의 한국어가 ?/한자 조각으로 깨질 수 있음 (UTF-8 → CP949 오인식)`));
|
|
7467
|
+
if (process.env._LEERNESS_AUTOCHCP_APPLIED) {
|
|
7468
|
+
log(gr6(` ✓ 자동 회복: chcp 65001 적용됨 (이전: ${process.env._LEERNESS_AUTOCHCP_APPLIED})`));
|
|
7469
|
+
} else {
|
|
7470
|
+
log(dm6(` → 수동: chcp 65001 + 새 터미널 또는 LEERNESS_NO_AUTOCHCP 미설정 시 다음 호출 자동 회복`));
|
|
7471
|
+
}
|
|
7472
|
+
}
|
|
7473
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS/WSL) terminal encoding 경고
|
|
7474
|
+
if (runtimeEnv.locale.posixEncodingOk === false) {
|
|
7475
|
+
const isTty6 = process.stdout && process.stdout.isTTY;
|
|
7476
|
+
const yl7 = s => isTty6 ? `\x1b[33m${s}\x1b[0m` : s;
|
|
7477
|
+
const dm7 = s => isTty6 ? `\x1b[2m${s}\x1b[0m` : s;
|
|
7478
|
+
const wslTag = runtimeEnv.locale.isWSL ? ' (WSL)' : '';
|
|
7479
|
+
log('');
|
|
7480
|
+
log(yl7(`## ⚠ 터미널 인코딩 — POSIX${wslTag} locale에 UTF-8 없음 (1.9.250, UR-0018 2단계)`));
|
|
7481
|
+
log(dm7(` LANG=${runtimeEnv.locale.LANG || 'unset'} · LC_ALL=${runtimeEnv.locale.LC_ALL || 'unset'}`));
|
|
7482
|
+
log(dm7(` → 권장: export LANG=ko_KR.UTF-8 (또는 export LC_ALL=C.UTF-8)`));
|
|
7483
|
+
log(dm7(` → 영구 적용: ~/.bashrc 또는 ~/.zshrc 에 추가`));
|
|
7484
|
+
}
|
|
7485
|
+
} catch {}
|
|
7486
|
+
|
|
7378
7487
|
// 1.9.245: API skill cache 자동 참조 (사용자 명시 UR-0015)
|
|
7379
7488
|
// 현재 task 키워드 기반으로 .harness/api-skills/ 매칭 → 사용자가 정리해둔 API 문서 자동 노출
|
|
7380
7489
|
try {
|
|
@@ -11285,7 +11394,13 @@ function sessionClose(root, opts = {}) {
|
|
|
11285
11394
|
nodeVersion: runtimeEnv.node.version,
|
|
11286
11395
|
shellScriptsScanned: encScan.scanned,
|
|
11287
11396
|
encodingRiskCount: encScan.atRisk.length,
|
|
11288
|
-
encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file)
|
|
11397
|
+
encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file),
|
|
11398
|
+
// 1.9.249 (UR-0018): 터미널 출력 인코딩 안전 여부 + 자동 회복 결과
|
|
11399
|
+
terminalEncodingOk: runtimeEnv.locale.codepage === 65001 || !runtimeEnv.locale.isKoreanWindows,
|
|
11400
|
+
autoChcpApplied: process.env._LEERNESS_AUTOCHCP_APPLIED || null,
|
|
11401
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS/WSL) terminal encoding 점검
|
|
11402
|
+
posixEncodingOk: runtimeEnv.locale.posixEncodingOk,
|
|
11403
|
+
isWSL: runtimeEnv.locale.isWSL || false
|
|
11289
11404
|
};
|
|
11290
11405
|
} catch {}
|
|
11291
11406
|
// 1.9.245: apiSkills 통합 (session close JSON 11번째 통합 필드) — UR-0015
|
|
@@ -18079,7 +18194,13 @@ function healthCmd(root) {
|
|
|
18079
18194
|
nodeVersion: runtimeEnv.node.version,
|
|
18080
18195
|
shellScriptsScanned: encScan.scanned,
|
|
18081
18196
|
encodingRiskCount: encScan.atRisk.length,
|
|
18082
|
-
encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file)
|
|
18197
|
+
encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file),
|
|
18198
|
+
// 1.9.249 (UR-0018): 터미널 출력 인코딩 안전 여부 + 자동 회복 결과
|
|
18199
|
+
terminalEncodingOk: runtimeEnv.locale.codepage === 65001 || !runtimeEnv.locale.isKoreanWindows,
|
|
18200
|
+
autoChcpApplied: process.env._LEERNESS_AUTOCHCP_APPLIED || null,
|
|
18201
|
+
// 1.9.250 (UR-0018 2단계): POSIX (Linux/macOS/WSL) terminal encoding 점검
|
|
18202
|
+
posixEncodingOk: runtimeEnv.locale.posixEncodingOk,
|
|
18203
|
+
isWSL: runtimeEnv.locale.isWSL || false
|
|
18083
18204
|
};
|
|
18084
18205
|
} catch { out.envInfo = { error: 'envInfo 점검 실패' }; }
|
|
18085
18206
|
// 1.9.245: health --json apiSkills 통합 (3 명령 11 필드 — UR-0015)
|