leerness 1.9.256 → 1.9.258

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,56 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.258 — 2026-05-30 — leerness selftest 명령 (코어 함수 무결성 자가 검증)
4
+
5
+ **🩺 사용자/CI 가 설치된 leerness 바이너리의 건강 상태를 1초 내 검증하는 신규 명령.**
6
+
7
+ ### 배경
8
+ `npx` 캐시 손상, 부분 설치, 버전 충돌 등으로 leerness 가 비정상 동작할 수 있음. 1.9.255~257에서 export 한 보안/정확성/인코딩-핵심 순수 함수를 실제 호출해 무결성을 자가 검증.
9
+
10
+ ### 구현 (`leerness selftest [--json]`)
11
+ 1. **`_selfTestCases()`** — 13개 코어 함수 무결성 케이스 (순수 함수만, 파일/네트워크 부작용 0):
12
+ - `_isSecretKey` (시크릿 차단 3종) · `compareVer` (대소/null 2종) · `parseHarnessVersion`
13
+ - `_classifyCJK` (한/중/일) · `_riskLabel` (CP949/CP936) · `_dirInPath` · `_winPathPsScript` · `_unixPathBlock` · VERSION 형식
14
+ 2. **`selfTestCmd`** — 사람용 ✓/✗ 리스트 + `--json` (기계 판독)
15
+ - 전체 통과 → exit 0 / 1건이라도 실패 → **exit 1** (CI 친화) + 재설치 안내
16
+ 3. **`self-test` 별칭** + help 노출 + `selfTestCmd`/`_selfTestCases` export
17
+
18
+ ### stress-v203 — **21/21 PASS · 100%**
19
+ - 1.9.258 (10): export + 13 케이스 무결성 + CLI exit 0/json/별칭 + 실패시 감지 + help + 성능(<1.5s)
20
+ - 성능 (1): cold start avg 400ms
21
+ - 누적 회귀 (10): 1.9.207~257
22
+
23
+ ### 자동 release (120 main-push streak · 81 npm publish streak · R214)
24
+
25
+ 🩺 **설치 건강 진단** — `leerness selftest` 로 사용자/CI 가 바이너리 무결성을 즉시 확인 (손상 시 exit 1 + 재설치 안내).
26
+
27
+ ---
28
+
29
+ ## 1.9.257 — 2026-05-30 — CJK 분류 함수 추출+단위테스트 + release 브랜치 정리 (🎉 80 npm streak)
30
+
31
+ **🧪 1.9.255/256 테스트 인프라 연장 + 🧹 누적 release 브랜치 정리 (handoff 장기 경고 해소).**
32
+
33
+ ### 구현
34
+ 1. **CJK 분류 순수 함수 모듈 스코프 추출** (테스트 가능성):
35
+ - `_classifyCJK(buf, len)` / `_riskLabel(cjk)` — `_scanShellScriptsEncoding` 내부 중첩 → 모듈 스코프로 추출 + export
36
+ - UTF-8 lead byte 기반 Korean(EA-ED)/Japanese(E3)/Chinese(E4-E9) 분류 → CP949/CP932/CP936 위험 판정 (UR-0014 계열)
37
+ - 실 동작 단위 테스트: 한국어/일본어/중국어/ASCII 버퍼 분류 + 동률 시 korean 우선 + len 범위 제한 + risk label 4종
38
+ - env encoding 명령 동작 보존 (추출 부작용 0 — e2e + A3 검증)
39
+ 2. **release 브랜치 누적 정리** (🧹 maintenance):
40
+ - 로컬 release/* 브랜치 **213 → 20** (`release cleanup --apply --keep 12`)
41
+ - handoff 가 수십 라운드 경고하던 "50+ branches 누적" 해소. 태그 + 원격이 히스토리 보존 → 로컬 정리 안전.
42
+
43
+ ### stress-v202 — **24/24 PASS · 100%**
44
+ - 1.9.257 (13): export + _classifyCJK (5) + _riskLabel (5) + env encoding 보존
45
+ - 성능 (1): cold start avg 385ms
46
+ - 누적 회귀 (10): 1.9.207~256 — 실 함수 호출 검증 (_isSecretKey/PATH/posix 등)
47
+
48
+ ### 자동 release (119 main-push streak · 🎉 80 npm publish streak · R213)
49
+
50
+ 🎉 **80 npm publish streak** — 테스트 인프라 3 라운드 누적(1.9.255 require.main + 1.9.256 보안/버전 + 1.9.257 CJK) + 누적 브랜치 정리.
51
+
52
+ ---
53
+
3
54
  ## 1.9.256 — 2026-05-29 — 단위 테스트 인프라 확대 (보안/정확성-핵심 순수 함수)
4
55
 
5
56
  **🧪 1.9.255 require.main 가드 기반 확장: 소스 regex 가 아닌 실제 함수 동작을 검증하는 단위 테스트로 회귀 강화.**
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.256-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v201-24%2F24-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-212-blueviolet)]() [![main-push](https://img.shields.io/badge/🎉_main--push_streak-118_rounds-success)]() [![npm-streak](https://img.shields.io/badge/🎉_npm--publish-79_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)]()
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.258-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v203-21%2F21-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-70-brightgreen)]() [![cli](https://img.shields.io/badge/CLI_commands-58-brightgreen)]() [![json-fields](https://img.shields.io/badge/JSON_통합-11_필드-blueviolet)]() [![rounds](https://img.shields.io/badge/autonomous_R-214-blueviolet)]() [![main-push](https://img.shields.io/badge/🎉_main--push_streak-120_rounds-success)]() [![npm-streak](https://img.shields.io/badge/🎉_npm--publish-81_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.256 AI Agent Reliability Harness + Sandbox ║
15
+ ║ v1.9.258 AI Agent Reliability Harness + Sandbox ║
16
16
  ║ verify · remember · orchestrate · audit · sandbox · drift ║
17
- 🧪 단위 테스트 인프라 확대 (보안/버전 동작 · R212)
17
+ 🩺 leerness selftest 코어 함수 무결성 자가 검증 (R214)
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.256';
10
+ const VERSION = '1.9.258';
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 처리).
@@ -2559,39 +2559,41 @@ function _terminalEncodingNotice(opts = {}) {
2559
2559
  return { ok, lines };
2560
2560
  }
2561
2561
 
2562
+ // 1.9.243: CJK 분류 — Korean/Japanese/Chinese 비-ASCII 패턴 통계 (UR-0014 3단계)
2563
+ // 1.9.257: _scanShellScriptsEncoding 내부 중첩 → 모듈 스코프로 추출 (순수 함수 — 단위 테스트 가능).
2564
+ // UTF-8 3-byte 시퀀스 시작 바이트로 CJK 언어 분류 (인코딩 오인식 위험 판단용).
2565
+ function _classifyCJK(buf, len) {
2566
+ let korean = 0, japanese = 0, chinese = 0, other = 0;
2567
+ for (let i = 0; i < Math.min(buf.length, len); i++) {
2568
+ const b = buf[i];
2569
+ if (b < 0x80) continue;
2570
+ // Korean Hangul Syllables U+AC00-D7AF → 3-byte: EA B0 80 ~ ED 9F BF
2571
+ if (b >= 0xEA && b <= 0xED) korean++;
2572
+ // Japanese Hiragana/Katakana U+3040-30FF → 3-byte: E3 81 80 ~ E3 83 BF
2573
+ else if (b === 0xE3) japanese++;
2574
+ // CJK Unified Ideographs U+4E00-9FFF → 3-byte: E4 B8 80 ~ E9 BF BF
2575
+ else if (b >= 0xE4 && b <= 0xE9) chinese++;
2576
+ else other++;
2577
+ }
2578
+ return { korean, japanese, chinese, other };
2579
+ }
2580
+ function _riskLabel(cjk) {
2581
+ if (cjk.korean >= cjk.japanese && cjk.korean >= cjk.chinese && cjk.korean > 0) {
2582
+ return { type: 'korean', risk: 'Windows 한국어 PowerShell 에서 CP949 로 오인식 가능 (BOM 추가 권장)' };
2583
+ }
2584
+ if (cjk.japanese > cjk.korean && cjk.japanese >= cjk.chinese) {
2585
+ return { type: 'japanese', risk: 'Windows 일본어 PowerShell 에서 CP932 (Shift-JIS) 로 오인식 가능 (BOM 추가 권장)' };
2586
+ }
2587
+ if (cjk.chinese > 0) {
2588
+ return { type: 'chinese', risk: 'Windows 중국어 PowerShell 에서 CP936 (GBK) 로 오인식 가능 (BOM 추가 권장)' };
2589
+ }
2590
+ return { type: 'non-ascii', risk: 'Windows 비-ASCII 셸 스크립트 — BOM 없는 UTF-8 인코딩 오인식 가능 (BOM 추가 권장)' };
2591
+ }
2592
+
2562
2593
  // 셸 스크립트 (.ps1/.bat/.cmd/.sh) 인코딩 위험 감지
2563
2594
  // 위험 시그널: 한국어 (또는 비-ASCII) 문자 + BOM 없음 + Windows 환경
2564
2595
  function _scanShellScriptsEncoding(root) {
2565
2596
  const result = { scanned: 0, atRisk: [], notes: [] };
2566
- // 1.9.243: CJK 분류 — Korean/Japanese/Chinese 비-ASCII 패턴 통계 (UR-0014 3단계)
2567
- function _classifyCJK(buf, len) {
2568
- let korean = 0, japanese = 0, chinese = 0, other = 0;
2569
- for (let i = 0; i < Math.min(buf.length, len); i++) {
2570
- const b = buf[i];
2571
- if (b < 0x80) continue;
2572
- // UTF-8 3-byte 시퀀스 시작 바이트 분류
2573
- // Korean Hangul Syllables U+AC00-D7AF → 3-byte: EA B0 80 ~ ED 9F BF
2574
- if (b >= 0xEA && b <= 0xED) korean++;
2575
- // Japanese Hiragana/Katakana U+3040-30FF → 3-byte: E3 81 80 ~ E3 83 BF
2576
- else if (b === 0xE3) japanese++;
2577
- // CJK Unified Ideographs U+4E00-9FFF → 3-byte: E4 B8 80 ~ E9 BF BF
2578
- else if (b >= 0xE4 && b <= 0xE9) chinese++;
2579
- else other++;
2580
- }
2581
- return { korean, japanese, chinese, other };
2582
- }
2583
- function _riskLabel(cjk) {
2584
- if (cjk.korean >= cjk.japanese && cjk.korean >= cjk.chinese && cjk.korean > 0) {
2585
- return { type: 'korean', risk: 'Windows 한국어 PowerShell 에서 CP949 로 오인식 가능 (BOM 추가 권장)' };
2586
- }
2587
- if (cjk.japanese > cjk.korean && cjk.japanese >= cjk.chinese) {
2588
- return { type: 'japanese', risk: 'Windows 일본어 PowerShell 에서 CP932 (Shift-JIS) 로 오인식 가능 (BOM 추가 권장)' };
2589
- }
2590
- if (cjk.chinese > 0) {
2591
- return { type: 'chinese', risk: 'Windows 중국어 PowerShell 에서 CP936 (GBK) 로 오인식 가능 (BOM 추가 권장)' };
2592
- }
2593
- return { type: 'non-ascii', risk: 'Windows 비-ASCII 셸 스크립트 — BOM 없는 UTF-8 인코딩 오인식 가능 (BOM 추가 권장)' };
2594
- }
2595
2597
  function walk(dir, depth = 0) {
2596
2598
  if (depth > 3) return; // 너무 깊이 들어가지 않음
2597
2599
  let entries;
@@ -2882,6 +2884,63 @@ function pathSetupCmd(root, opts = {}) {
2882
2884
  }
2883
2885
  }
2884
2886
 
2887
+ // 1.9.258: leerness selftest — 설치된 leerness 바이너리의 코어 순수 함수 자가 검증.
2888
+ // 1.9.255~257 에서 export 한 보안/정확성/인코딩-핵심 함수를 실제 호출해 무결성 확인.
2889
+ // 사용자/CI 가 "내 leerness 가 정상인가?" 를 1초 내 검증 (npm 캐시 손상/부분 설치 감지).
2890
+ // --json: 기계 판독. 실패 시 exit 1 (CI 친화).
2891
+ function _selfTestCases() {
2892
+ // 각 케이스: { name, run: () => boolean } — 순수 함수만 (파일/네트워크 부작용 0)
2893
+ return [
2894
+ { name: '_isSecretKey: NPM_TOKEN 차단', run: () => _isSecretKey('NPM_TOKEN') === true },
2895
+ { name: '_isSecretKey: API_KEY/SECRET/PASSWORD 차단', run: () => _isSecretKey('OPENAI_API_KEY') && _isSecretKey('MY_SECRET') && _isSecretKey('db_PASSWORD') },
2896
+ { name: '_isSecretKey: 비시크릿 LEERNESS_* 통과', run: () => _isSecretKey('LEERNESS_ENABLE_AGY') === false && _isSecretKey('LANG') === false },
2897
+ { name: 'compareVer: 대소 비교', run: () => compareVer('1.9.258', '1.9.257') === 1 && compareVer('1.9.0', '1.10.0') === -1 && compareVer('2.0.0', '2.0.0') === 0 },
2898
+ { name: 'compareVer: 누락 파트/null 안전', run: () => compareVer('1.9', '1.9.0') === 0 && compareVer(null, '0.0.0') === 0 },
2899
+ { name: 'parseHarnessVersion: canonical + legacy plus', run: () => parseHarnessVersion('1.9.0').base === '1.9.0' && parseHarnessVersion('leerness@1.8.0+plus@1.0.1').plus === '1.0.1' },
2900
+ { name: '_classifyCJK: 한국어 감지', run: () => { const b = Buffer.from('안녕', 'utf8'); return _classifyCJK(b, b.length).korean > 0; } },
2901
+ { name: '_classifyCJK: 중국어/일본어 구분', run: () => { const z = Buffer.from('中', 'utf8'), j = Buffer.from('ひ', 'utf8'); return _classifyCJK(z, z.length).chinese > 0 && _classifyCJK(j, j.length).japanese > 0; } },
2902
+ { name: '_riskLabel: korean→CP949 / chinese→CP936', run: () => /CP949/.test(_riskLabel({ korean: 3, japanese: 0, chinese: 0, other: 0 }).risk) && /CP936/.test(_riskLabel({ korean: 0, japanese: 0, chinese: 3, other: 0 }).risk) },
2903
+ { name: '_dirInPath: 정규화 (trailing slash)', run: () => { const sep = process.platform === 'win32' ? ';' : ':'; const old = process.env.PATH; process.env.PATH = '/usr/bin' + sep + '/opt/x/bin'; const r = _dirInPath('/opt/x/bin/') === true && _dirInPath('/no/such') === false; process.env.PATH = old; return r; } },
2904
+ { name: '_winPathPsScript: User scope + setx 미사용', run: () => { const ps = _winPathPsScript('C:\\npm'); return /SetEnvironmentVariable\('PATH', \$nu, 'User'\)/.test(ps) && !/setx/i.test(ps); } },
2905
+ { name: '_unixPathBlock: 멱등 마커 + export', run: () => { const b = _unixPathBlock('/x/bin'); return b.includes('managed') && /export PATH="\$PATH:\/x\/bin"/.test(b); } },
2906
+ { name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
2907
+ ];
2908
+ }
2909
+ function selfTestCmd(opts = {}) {
2910
+ const isTty = process.stdout && process.stdout.isTTY;
2911
+ const gr = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
2912
+ const rd = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
2913
+ const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
2914
+ const dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
2915
+ const cases = _selfTestCases();
2916
+ const results = cases.map(c => {
2917
+ let ok = false, err = null;
2918
+ try { ok = c.run() === true; } catch (e) { ok = false; err = e.message; }
2919
+ return { name: c.name, ok, err };
2920
+ });
2921
+ const pass = results.filter(r => r.ok).length;
2922
+ const fail = results.length - pass;
2923
+ if (opts.json) {
2924
+ log(JSON.stringify({ version: VERSION, total: results.length, pass, fail, ok: fail === 0, results }, null, 2));
2925
+ if (fail > 0) process.exitCode = 1;
2926
+ return;
2927
+ }
2928
+ log(cy(`# leerness selftest (1.9.258) — 코어 함수 무결성 검증 (v${VERSION})`));
2929
+ log('');
2930
+ results.forEach(r => {
2931
+ if (r.ok) log(` ${gr('✓')} ${r.name}`);
2932
+ else log(` ${rd('✗')} ${r.name}${r.err ? dm(' — ' + r.err) : ''}`);
2933
+ });
2934
+ log('');
2935
+ if (fail === 0) {
2936
+ log(gr(` ✓ 전체 ${results.length}건 통과 — leerness 설치 정상`));
2937
+ } else {
2938
+ log(rd(` ✗ ${fail}/${results.length}건 실패 — 설치 손상 의심`));
2939
+ log(dm(` → 재설치: npm i -g leerness@latest · 진단: leerness which`));
2940
+ process.exitCode = 1;
2941
+ }
2942
+ }
2943
+
2885
2944
  // 1.9.245: API skill cache — 공식 문서 + 관련 링크 자동 정리 (사용자 명시 UR-0015)
2886
2945
  // .harness/api-skills/<id>.md 에 frontmatter + 본문 저장. handoff 자동 매칭.
2887
2946
  // Node built-in https (의존성 0), depth=1 same-domain crawl, max 10 links.
@@ -19693,7 +19752,7 @@ function whichCmd() {
19693
19752
  }
19694
19753
 
19695
19754
  function help() {
19696
- log(`Leerness v${VERSION}\n\nUsage:\n leerness init [path] [--language auto|ko|en] [--skills recommended|all|a,b]\n leerness migrate [path] [--dry-run] [--force]\n leerness update [path] [--check|--yes|--force|--from <tarball>]\n leerness auto-update install [path]\n leerness status [path]\n leerness verify [path]\n leerness debug [path]\n leerness audit [path]\n leerness check [path]\n leerness scan secrets [path]\n leerness encoding check [path]\n leerness lazy detect [path]\n leerness memory search "query" [--limit 5]\n leerness handoff [path] [--all-apps] [--include p1,p2] [--since 24h|3d] [--compact] [--json] # 1.9.17-22 워크스페이스 (--compact: LLM 시스템 프롬프트용 1줄 요약)\n leerness orchestrate "<목표>" [--agents N] [--model qwen2.5:7b-instruct] [--retry-on-fail K] # 1.9.22 Ollama opt-in (LEERNESS_OLLAMA_BASE_URL 필요)\n leerness llm-bench record --score N --model X [--label L] [--tokens T] # 1.9.22 LLM 벤치 히스토리 누적\n leerness deps <capability> [--run-tests] [--json] # 1.9.24 depends-on 역방향 추적 + 자동 회귀 sweep\n leerness memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26/27 낙관적 표시 감지 (1.9.27: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수)\n leerness persona list|show <id>|add <id> # 1.9.29 페르소나 카탈로그 (보안/성능/UX/testing/docs 5종 내장)\n leerness review <file> --persona <id1,id2,...> # 1.9.29 도메인 페르소나 리뷰 프롬프트 자동 생성\n leerness agents list|check|quota # 1.9.30/31 외부 AI CLI 가용성 + quota 추정 (claude/codex/agy/copilot)\n leerness agents dispatch "<task>" --to <id> # 1.9.30 활성 CLI 대상 실행 명령 생성 (실 호출 X, 사용자 실행)\n leerness agents multi "<task>" [--only c1,c2] [--write] [--execute] [--timeout 60] # 1.9.152/156 활성 N개 일괄 dispatch (--execute: 실 spawn + consensus)\n leerness provider list|add|remove [args] # 1.9.157 Provider Registry — 사용자 정의 CLI provider 동적 추가 (OpenRouter/Bedrock 흡수)\n leerness agents dispatch "<task>" --multi # 1.9.152 multi 모드 alias (또는 --to all)\n leerness setup-agents [path] [--yes|--no-setup-agents] # 1.9.32 sub-agent CLI 인터랙티브 설정 (.env + 미설치 자동 설치)\n leerness init [path] [--no-stale-check] # 1.9.33 npx 캐시 함정 — 옛 버전 자동 경고 (끄려면 --no-stale-check)\n leerness which [--json] # 1.9.164 진단: 현재 실행 경로/버전 + npm 캐시 + PATH 후보 (구버전 충돌 해결)\n leerness web check|screenshot|extract <url> [--out file.png] [--selector "css"] # 1.9.165 playwright bridge (opt-in: npm i -g playwright + permissions.browser)\n leerness pc check|click|type|screenshot [--x N --y N] [--text "s"] [--out f.png] # 1.9.166 robotjs/nut-tree bridge (opt-in: npm i -g robotjs + permissions.mouse/keyboard, ⚠ full 모드 권장)\n leerness lsp check|symbols|references <file/name> [--in dir] [--json] # 1.9.167 LSP 어댑터 MVP (typescript opt-in + regex fallback, 코드 인텔리전스)\n leerness review-request "<request>" [--json] # 1.9.176 사용자 요청 사전 검토 (충돌/재사용/효율/권장 단계 — 사용자 명시)\n leerness contract verify <spec.md> <impl.js> [--json] # 1.9.35 명세 ↔ 구현 일치 검사 (함수/필드)\n leerness reuse autodetect [path] [--apply] [--json] # 1.9.35 src/*.js의 module.exports → reuse-map 후보 등록\n leerness audit [path] [--fix] # 1.9.35 --fix: session-handoff/current-state 자동 갱신\n leerness verify-claim <T-ID> ... [--strict-claims] # 1.9.26 verify-claim에 낙관적 표시 자동 검사 통합\n leerness reuse-map [path] [--all-apps] [--include p1,p2] [--strict-elements] [--json] # 1.9.18 중복/잠재중복/depends-on\n leerness verify-claim <T-ID> [--path .] [--run-tests] [--json] # 1.9.18-20 evidence 자동 검증 (1.9.20: scenes/scripts 등 도메인 폴더 + jest/mocha 파싱)\n leerness verify-code [path] [--build] [--bench] # 1.9.20 --bench: scripts.bench 추가 실행 + evidence 누적\n leerness session close [path]\n leerness route <task-type>\n leerness self check [path]\n leerness readme sync [path]\n leerness consistency check [path]\n leerness consistency merge-design-guide [path]\n leerness plan show|init|add|drop|progress|sync [args]\n leerness task list|add|update|drop|fix-evidence|relink [args]\n leerness skill list|info <name>\n leerness skill learn <id> --doc <url> --command "..." --capability "..." [--note ...]\n leerness skill use <id> [--note ...]\n leerness skill optimize <id> --before "..." --after "..." [--note ...]\n leerness skill remove <id>\n leerness skill consolidate [--threshold 0.3]\n leerness gate [path] # verify+audit+scan+encoding+lazy
19755
+ log(`Leerness v${VERSION}\n\nUsage:\n leerness init [path] [--language auto|ko|en] [--skills recommended|all|a,b]\n leerness migrate [path] [--dry-run] [--force]\n leerness update [path] [--check|--yes|--force|--from <tarball>]\n leerness auto-update install [path]\n leerness status [path]\n leerness verify [path]\n leerness debug [path]\n leerness audit [path]\n leerness check [path]\n leerness scan secrets [path]\n leerness encoding check [path]\n leerness lazy detect [path]\n leerness memory search "query" [--limit 5]\n leerness handoff [path] [--all-apps] [--include p1,p2] [--since 24h|3d] [--compact] [--json] # 1.9.17-22 워크스페이스 (--compact: LLM 시스템 프롬프트용 1줄 요약)\n leerness orchestrate "<목표>" [--agents N] [--model qwen2.5:7b-instruct] [--retry-on-fail K] # 1.9.22 Ollama opt-in (LEERNESS_OLLAMA_BASE_URL 필요)\n leerness llm-bench record --score N --model X [--label L] [--tokens T] # 1.9.22 LLM 벤치 히스토리 누적\n leerness deps <capability> [--run-tests] [--json] # 1.9.24 depends-on 역방향 추적 + 자동 회귀 sweep\n leerness memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26/27 낙관적 표시 감지 (1.9.27: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수)\n leerness persona list|show <id>|add <id> # 1.9.29 페르소나 카탈로그 (보안/성능/UX/testing/docs 5종 내장)\n leerness review <file> --persona <id1,id2,...> # 1.9.29 도메인 페르소나 리뷰 프롬프트 자동 생성\n leerness agents list|check|quota # 1.9.30/31 외부 AI CLI 가용성 + quota 추정 (claude/codex/agy/copilot)\n leerness agents dispatch "<task>" --to <id> # 1.9.30 활성 CLI 대상 실행 명령 생성 (실 호출 X, 사용자 실행)\n leerness agents multi "<task>" [--only c1,c2] [--write] [--execute] [--timeout 60] # 1.9.152/156 활성 N개 일괄 dispatch (--execute: 실 spawn + consensus)\n leerness provider list|add|remove [args] # 1.9.157 Provider Registry — 사용자 정의 CLI provider 동적 추가 (OpenRouter/Bedrock 흡수)\n leerness agents dispatch "<task>" --multi # 1.9.152 multi 모드 alias (또는 --to all)\n leerness setup-agents [path] [--yes|--no-setup-agents] # 1.9.32 sub-agent CLI 인터랙티브 설정 (.env + 미설치 자동 설치)\n leerness init [path] [--no-stale-check] # 1.9.33 npx 캐시 함정 — 옛 버전 자동 경고 (끄려면 --no-stale-check)\n leerness which [--json] # 1.9.164 진단: 현재 실행 경로/버전 + npm 캐시 + PATH 후보 (구버전 충돌 해결)\n leerness selftest [--json] # 1.9.258 코어 함수 무결성 자가 검증 (설치 손상/부분설치 감지, CI 친화 exit 1)\n leerness path-setup [--apply] [--json] # 1.9.254 leerness CLI PATH 자동 등록 (npm global bin 미등록 시)\n leerness web check|screenshot|extract <url> [--out file.png] [--selector "css"] # 1.9.165 playwright bridge (opt-in: npm i -g playwright + permissions.browser)\n leerness pc check|click|type|screenshot [--x N --y N] [--text "s"] [--out f.png] # 1.9.166 robotjs/nut-tree bridge (opt-in: npm i -g robotjs + permissions.mouse/keyboard, ⚠ full 모드 권장)\n leerness lsp check|symbols|references <file/name> [--in dir] [--json] # 1.9.167 LSP 어댑터 MVP (typescript opt-in + regex fallback, 코드 인텔리전스)\n leerness review-request "<request>" [--json] # 1.9.176 사용자 요청 사전 검토 (충돌/재사용/효율/권장 단계 — 사용자 명시)\n leerness contract verify <spec.md> <impl.js> [--json] # 1.9.35 명세 ↔ 구현 일치 검사 (함수/필드)\n leerness reuse autodetect [path] [--apply] [--json] # 1.9.35 src/*.js의 module.exports → reuse-map 후보 등록\n leerness audit [path] [--fix] # 1.9.35 --fix: session-handoff/current-state 자동 갱신\n leerness verify-claim <T-ID> ... [--strict-claims] # 1.9.26 verify-claim에 낙관적 표시 자동 검사 통합\n leerness reuse-map [path] [--all-apps] [--include p1,p2] [--strict-elements] [--json] # 1.9.18 중복/잠재중복/depends-on\n leerness verify-claim <T-ID> [--path .] [--run-tests] [--json] # 1.9.18-20 evidence 자동 검증 (1.9.20: scenes/scripts 등 도메인 폴더 + jest/mocha 파싱)\n leerness verify-code [path] [--build] [--bench] # 1.9.20 --bench: scripts.bench 추가 실행 + evidence 누적\n leerness session close [path]\n leerness route <task-type>\n leerness self check [path]\n leerness readme sync [path]\n leerness consistency check [path]\n leerness consistency merge-design-guide [path]\n leerness plan show|init|add|drop|progress|sync [args]\n leerness task list|add|update|drop|fix-evidence|relink [args]\n leerness skill list|info <name>\n leerness skill learn <id> --doc <url> --command "..." --capability "..." [--note ...]\n leerness skill use <id> [--note ...]\n leerness skill optimize <id> --before "..." --after "..." [--note ...]\n leerness skill remove <id>\n leerness skill consolidate [--threshold 0.3]\n leerness gate [path] # verify+audit+scan+encoding+lazy
19697
19756
  leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # 회고 (1.9.13~1.9.16)
19698
19757
  leerness insights [path] [--all-apps] [--include p1,p2] [--json] # 누적 통계 (1.9.13~1.9.16)
19699
19758
  leerness brainstorm "<주제>" [--all-apps] [--include p1,p2] [--json] # 브레인스토밍 (1.9.13~1.9.16)
@@ -19896,6 +19955,8 @@ async function main() {
19896
19955
  // 1.9.254: leerness path-setup [--apply] — CLI PATH 자동 등록 (사용자 명시 UR-0019)
19897
19956
  // npm global bin 경로 감지 + leerness 가 PATH 에서 찾아지는지 확인 → 미등록 시 플랫폼별 등록
19898
19957
  if (cmd === 'path-setup' || cmd === 'path') return pathSetupCmd(arg('--path', process.cwd()), { apply: has('--apply'), json: has('--json') });
19958
+ // 1.9.258: leerness selftest — 설치된 바이너리 코어 함수 무결성 자가 검증 (CI/사용자 진단)
19959
+ if (cmd === 'selftest' || cmd === 'self-test') return selfTestCmd({ json: has('--json') });
19899
19960
  // 1.9.245: API skill cache — 공식 문서·관련링크 자동 정리 (사용자 명시 UR-0015)
19900
19961
  if (cmd === 'api-skill') return apiSkillCmd(arg('--path', process.cwd()), args[1] || 'help');
19901
19962
  // 1.9.208: leerness constraints <list|check|add> — 플랫폼/API 제약 사전 체크 (사용자 명시)
@@ -20053,5 +20114,9 @@ module.exports = {
20053
20114
  VERSION,
20054
20115
  _npmGlobalBin, _dirInPath, _leernessResolvable, _pathDiagnose, _registerPath,
20055
20116
  _winPathPsScript, _unixPathBlock, pathSetupCmd,
20056
- _isSecretKey, compareVer, parseHarnessVersion
20117
+ _isSecretKey, compareVer, parseHarnessVersion,
20118
+ // 1.9.257: CJK 인코딩 분류 (UR-0014 계열) 순수 함수 — 단위 테스트
20119
+ _classifyCJK, _riskLabel,
20120
+ // 1.9.258: selftest — 코어 함수 무결성 검증
20121
+ _selfTestCases, selfTestCmd
20057
20122
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.256",
3
+ "version": "1.9.258",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",