leerness 1.9.249 → 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 CHANGED
@@ -1,5 +1,45 @@
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
+
3
43
  ## 1.9.249 — 2026-05-28 — UR-0018 터미널 인코딩 자동 회복 (한국어 Windows)
4
44
 
5
45
  **🌐 사용자 명시 (UR-0018): "leerness가 적용된 프로젝트에서 터미널 출력이 깨지지 않게, 하드웨어의 언어 등을 사전에 참고하여 진행".**
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.249-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v194-23%2F23-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-70-brightgreen)]() [![cli](https://img.shields.io/badge/CLI_commands-57-brightgreen)]() [![json-fields](https://img.shields.io/badge/JSON_통합-11_필드-blueviolet)]() [![rounds](https://img.shields.io/badge/autonomous_R-205-blueviolet)]() [![main-push](https://img.shields.io/badge/🎉_main--push_streak-111_rounds-success)]() [![npm-streak](https://img.shields.io/badge/🎉_npm--publish-72_streak-success)]() [![encoding](https://img.shields.io/badge/🌐_터미널인코딩-자동회복-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-385ms-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.250-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v195-26%2F26-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-70-brightgreen)]() [![cli](https://img.shields.io/badge/CLI_commands-57-brightgreen)]() [![json-fields](https://img.shields.io/badge/JSON_통합-11_필드-blueviolet)]() [![rounds](https://img.shields.io/badge/autonomous_R-206-blueviolet)]() [![main-push](https://img.shields.io/badge/🎉_main--push_streak-112_rounds-success)]() [![npm-streak](https://img.shields.io/badge/🎉_npm--publish-73_streak-success)]() [![encoding](https://img.shields.io/badge/🌐_인코딩보호-Windows%2BPOSIX-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-368ms-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.249 AI Agent Reliability Harness + Sandbox ║
15
+ ║ v1.9.250 AI Agent Reliability Harness + Sandbox ║
16
16
  ║ verify · remember · orchestrate · audit · sandbox · drift ║
17
- ║ 🌐 터미널 인코딩 자동 회복 (한국어 Windows · UR-0018)
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.249';
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 처리).
@@ -2420,7 +2420,10 @@ function _collectRuntimeEnv() {
2420
2420
  LC_CTYPE: process.env.LC_CTYPE || null,
2421
2421
  // Windows 한국어 환경 detect
2422
2422
  OEMCP: process.env.OEMCP || null, // CP949 = 949
2423
- 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
2424
2427
  },
2425
2428
  hardware: {
2426
2429
  cpus: os.cpus().length,
@@ -2448,6 +2451,22 @@ function _collectRuntimeEnv() {
2448
2451
  }
2449
2452
  }
2450
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 {}
2451
2470
  // PowerShell 감지
2452
2471
  try {
2453
2472
  if (env.os.platform === 'win32') {
@@ -2618,6 +2637,16 @@ function envCmd(root, sub) {
2618
2637
  } else if (env.locale.codepage === 65001) {
2619
2638
  log(gr(` ✓ 터미널 인코딩 UTF-8 (65001) — 한국어 출력 안전`));
2620
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
+ }
2621
2650
  log(` 🖥 Hardware: ${env.hardware.cpus} CPUs · ${env.hardware.memGB} GB RAM`);
2622
2651
  log(` 🖱 Terminal: TTY=${env.terminal.isTTY}${env.terminal.powershell ? ` · PowerShell v${env.terminal.powershell}` : ''}`);
2623
2652
  log(` 🔧 Tools:`);
@@ -7032,7 +7061,10 @@ function handoff(root) {
7032
7061
  encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file),
7033
7062
  // 1.9.249 (UR-0018): 터미널 출력 인코딩 안전 여부 + 자동 회복 결과
7034
7063
  terminalEncodingOk: runtimeEnv.locale.codepage === 65001 || !runtimeEnv.locale.isKoreanWindows,
7035
- autoChcpApplied: process.env._LEERNESS_AUTOCHCP_APPLIED || null
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
7036
7068
  };
7037
7069
  } catch {}
7038
7070
  // 1.9.245: apiSkills 통합 (handoff JSON 11번째 통합 필드) — UR-0015 API 문서 캐시
@@ -7438,6 +7470,18 @@ function handoff(root) {
7438
7470
  log(dm6(` → 수동: chcp 65001 + 새 터미널 또는 LEERNESS_NO_AUTOCHCP 미설정 시 다음 호출 자동 회복`));
7439
7471
  }
7440
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
+ }
7441
7485
  } catch {}
7442
7486
 
7443
7487
  // 1.9.245: API skill cache 자동 참조 (사용자 명시 UR-0015)
@@ -11350,7 +11394,13 @@ function sessionClose(root, opts = {}) {
11350
11394
  nodeVersion: runtimeEnv.node.version,
11351
11395
  shellScriptsScanned: encScan.scanned,
11352
11396
  encodingRiskCount: encScan.atRisk.length,
11353
- 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
11354
11404
  };
11355
11405
  } catch {}
11356
11406
  // 1.9.245: apiSkills 통합 (session close JSON 11번째 통합 필드) — UR-0015
@@ -18144,7 +18194,13 @@ function healthCmd(root) {
18144
18194
  nodeVersion: runtimeEnv.node.version,
18145
18195
  shellScriptsScanned: encScan.scanned,
18146
18196
  encodingRiskCount: encScan.atRisk.length,
18147
- 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
18148
18204
  };
18149
18205
  } catch { out.envInfo = { error: 'envInfo 점검 실패' }; }
18150
18206
  // 1.9.245: health --json apiSkills 통합 (3 명령 11 필드 — UR-0015)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.249",
3
+ "version": "1.9.250",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",