leerness 1.9.257 → 1.9.259

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,55 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.259 — 2026-05-30 — MCP leerness_selftest (71 도구) + npm test 무결성 게이트
4
+
5
+ **🔌 1.9.258 selftest 를 워크플로에 통합: 외부 AI(MCP) + 배포 파이프라인(npm test) 양쪽에서 무결성 검증.**
6
+
7
+ ### 구현
8
+ 1. **MCP 71번째 도구 `leerness_selftest`** (70 → 71):
9
+ - 외부 AI(Claude Code 등)가 `tools/call` 로 leerness 무결성 확인 → `{ version, total, pass, fail, ok, results[] }`
10
+ - tools/list 71 도구 노출 + 핸들러 → `selftest --json`
11
+ - 실제 stdio JSON-RPC 라운드트립 검증: tools/list 71 + tools/call ok=true 13/13
12
+ 2. **npm test 무결성 게이트**:
13
+ - `test`: `--version && selftest && e2e` — selftest 가 e2e 보다 먼저 (fast-fail)
14
+ - 배포/CI 시 코어 함수 손상을 e2e 전에 즉시 감지 (release sync-main 자동 publish 안전망)
15
+
16
+ ### stress-v204 — **18/18 PASS · 100%**
17
+ - 1.9.259 (7): VERSION + MCP 71 정의/핸들러 + 실 서버 list/call + npm test 게이트 순서
18
+ - 성능 (1): cold start avg 371ms
19
+ - 누적 회귀 (10): 1.9.207~258 + MCP initialize 프로토콜 회귀
20
+
21
+ ### 자동 release (121 main-push streak · 82 npm publish streak · R215)
22
+
23
+ 🔌 **selftest 3중 노출 완성** — CLI(1.9.258) + MCP 도구 + npm test 게이트. 외부 AI·CI·배포 모두 무결성 자동 검증.
24
+
25
+ ---
26
+
27
+ ## 1.9.258 — 2026-05-30 — leerness selftest 명령 (코어 함수 무결성 자가 검증)
28
+
29
+ **🩺 사용자/CI 가 설치된 leerness 바이너리의 건강 상태를 1초 내 검증하는 신규 명령.**
30
+
31
+ ### 배경
32
+ `npx` 캐시 손상, 부분 설치, 버전 충돌 등으로 leerness 가 비정상 동작할 수 있음. 1.9.255~257에서 export 한 보안/정확성/인코딩-핵심 순수 함수를 실제 호출해 무결성을 자가 검증.
33
+
34
+ ### 구현 (`leerness selftest [--json]`)
35
+ 1. **`_selfTestCases()`** — 13개 코어 함수 무결성 케이스 (순수 함수만, 파일/네트워크 부작용 0):
36
+ - `_isSecretKey` (시크릿 차단 3종) · `compareVer` (대소/null 2종) · `parseHarnessVersion`
37
+ - `_classifyCJK` (한/중/일) · `_riskLabel` (CP949/CP936) · `_dirInPath` · `_winPathPsScript` · `_unixPathBlock` · VERSION 형식
38
+ 2. **`selfTestCmd`** — 사람용 ✓/✗ 리스트 + `--json` (기계 판독)
39
+ - 전체 통과 → exit 0 / 1건이라도 실패 → **exit 1** (CI 친화) + 재설치 안내
40
+ 3. **`self-test` 별칭** + help 노출 + `selfTestCmd`/`_selfTestCases` export
41
+
42
+ ### stress-v203 — **21/21 PASS · 100%**
43
+ - 1.9.258 (10): export + 13 케이스 무결성 + CLI exit 0/json/별칭 + 실패시 감지 + help + 성능(<1.5s)
44
+ - 성능 (1): cold start avg 400ms
45
+ - 누적 회귀 (10): 1.9.207~257
46
+
47
+ ### 자동 release (120 main-push streak · 81 npm publish streak · R214)
48
+
49
+ 🩺 **설치 건강 진단** — `leerness selftest` 로 사용자/CI 가 바이너리 무결성을 즉시 확인 (손상 시 exit 1 + 재설치 안내).
50
+
51
+ ---
52
+
3
53
  ## 1.9.257 — 2026-05-30 — CJK 분류 함수 추출+단위테스트 + release 브랜치 정리 (🎉 80 npm streak)
4
54
 
5
55
  **🧪 1.9.255/256 테스트 인프라 연장 + 🧹 누적 release 브랜치 정리 (handoff 장기 경고 해소).**
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.257-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v202-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-213-blueviolet)]() [![main-push](https://img.shields.io/badge/🎉_main--push_streak-119_rounds-success)]() [![npm-streak](https://img.shields.io/badge/🎉_npm--publish-80_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.259-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v204-18%2F18-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-71-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-215-blueviolet)]() [![main-push](https://img.shields.io/badge/🎉_main--push_streak-121_rounds-success)]() [![npm-streak](https://img.shields.io/badge/🎉_npm--publish-82_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.257 AI Agent Reliability Harness + Sandbox ║
15
+ ║ v1.9.259 AI Agent Reliability Harness + Sandbox ║
16
16
  ║ verify · remember · orchestrate · audit · sandbox · drift ║
17
- 🎉 80 npm streak · CJK 분류 단위테스트 + 브랜치 정리 (R213) ║
17
+ 🔌 MCP 71 도구 + selftest 게이트 (CLI+MCP+npm test · R215) ║
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.257';
10
+ const VERSION = '1.9.259';
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 처리).
@@ -2884,6 +2884,63 @@ function pathSetupCmd(root, opts = {}) {
2884
2884
  }
2885
2885
  }
2886
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
+
2887
2944
  // 1.9.245: API skill cache — 공식 문서 + 관련 링크 자동 정리 (사용자 명시 UR-0015)
2888
2945
  // .harness/api-skills/<id>.md 에 frontmatter + 본문 저장. handoff 자동 매칭.
2889
2946
  // Node built-in https (의존성 0), depth=1 same-domain crawl, max 10 links.
@@ -15836,7 +15893,8 @@ function mcpServeCmd(root) {
15836
15893
  { name: 'leerness_py_check', description: '1.9.239 (사용자 명시 UR-0013) — Python 파일 분석. 의존성 0 regex fallback. .md 외 .py 도 leerness 인지. 응답: { totalFiles, totalLOC, totalImports, totalFuncs, totalClasses, totalTodos, biggest: [{ file, loc, funcs, classes }] }. 외부 AI가 "이 프로젝트 Python 표면이 얼마나 되나"를 회수. 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
15837
15894
  { name: 'leerness_agent_mode', description: '1.9.239 (사용자 명시 UR-0013) — 자율 모드 전용 통합 명령. start: handoff + drift --auto-fix + session-resume --auto-fix (진입). tick: pulse 한 줄 (매 라운드). stop: session close --auto-apply-delivered --auto-cleanup-branches (마감). 외부 AI 가 자율 라운드 진입/매 라운드/마감을 단일 호출로 수행. 인자: { path?, sub (required: "start"|"tick"|"stop"|"help") }', inputSchema: { type: 'object', properties: { path: { type: 'string' }, sub: { type: 'string', enum: ['start', 'tick', 'stop', 'help'] } }, required: ['sub'] } },
15838
15895
  { name: 'leerness_env_info', description: '1.9.241 (사용자 명시 UR-0014) — 환경 종합 정보 회수. OS / 언어 (LANG, 코드페이지) / 한국어 Windows / 하드웨어 / 터미널 (TTY, PowerShell 버전) / 도구 버전 (git, npm, python). 외부 AI 가 환경 호환성을 미리 인지 → 인코딩 오류 예방. 응답: { os, node, locale, hardware, terminal, tools }. 인자: { path?, encodingCheck? }. encodingCheck: true 시 셸 스크립트 (.ps1/.bat/.cmd/.sh) BOM 없는 비-ASCII 위험 감지', inputSchema: { type: 'object', properties: { path: { type: 'string' }, encodingCheck: { type: 'boolean' } } } },
15839
- { name: 'leerness_api_skill', description: '1.9.245 (사용자 명시 UR-0015) — API 문서·관련링크 자동 캐시. 공식 API 문서 URL을 fetch 하고 1단계 same-domain 관련 링크까지 정리 → .harness/api-skills/<id>.md 저장. 후속 같은 API 관련 작업 시 자동 참조. 응답: list (skills 배열) / show (전체 본문) / match (task 매칭 결과). 인자: { path?, sub ("list"|"show"|"match"|"add"|"drop"), url? (add), id? (show/drop), query? (match), direction? (add: 구현 방향 텍스트) }. 외부 AI가 "이 프로젝트 어떤 API 문서가 정리되어 있나?" / "내 작업과 매칭되는 API skill 있나?" 회수.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, sub: { type: 'string', enum: ['list', 'show', 'match', 'add', 'drop'] }, url: { type: 'string' }, id: { type: 'string' }, query: { type: 'string' }, direction: { type: 'string' } }, required: ['sub'] } }
15896
+ { name: 'leerness_api_skill', description: '1.9.245 (사용자 명시 UR-0015) — API 문서·관련링크 자동 캐시. 공식 API 문서 URL을 fetch 하고 1단계 same-domain 관련 링크까지 정리 → .harness/api-skills/<id>.md 저장. 후속 같은 API 관련 작업 시 자동 참조. 응답: list (skills 배열) / show (전체 본문) / match (task 매칭 결과). 인자: { path?, sub ("list"|"show"|"match"|"add"|"drop"), url? (add), id? (show/drop), query? (match), direction? (add: 구현 방향 텍스트) }. 외부 AI가 "이 프로젝트 어떤 API 문서가 정리되어 있나?" / "내 작업과 매칭되는 API skill 있나?" 회수.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, sub: { type: 'string', enum: ['list', 'show', 'match', 'add', 'drop'] }, url: { type: 'string' }, id: { type: 'string' }, query: { type: 'string' }, direction: { type: 'string' } }, required: ['sub'] } },
15897
+ { name: 'leerness_selftest', description: '1.9.258/259 — 설치된 leerness 바이너리의 코어 함수(보안 _isSecretKey / 버전 compareVer / 인코딩 _classifyCJK 등) 무결성 자가 검증. 응답: { version, total, pass, fail, ok, results[] }. 외부 AI/CI 가 "이 leerness 설치가 정상인가?(npx 캐시 손상·부분 설치 감지)" 를 1초 내 확인. 인자: 없음.', inputSchema: { type: 'object', properties: {} } }
15840
15898
  ];
15841
15899
 
15842
15900
  function send(obj) {
@@ -16039,6 +16097,10 @@ function mcpServeCmd(root) {
16039
16097
  if (args.apply === true) cliArgs.push('--apply');
16040
16098
  if (typeof args.keep === 'number') cliArgs.push('--keep', String(args.keep));
16041
16099
  break;
16100
+ case 'leerness_selftest':
16101
+ // 1.9.259 (1.9.258): 코어 함수 무결성 자가 검증
16102
+ cliArgs = ['selftest', '--json'];
16103
+ break;
16042
16104
  default:
16043
16105
  return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
16044
16106
  }
@@ -19695,7 +19757,7 @@ function whichCmd() {
19695
19757
  }
19696
19758
 
19697
19759
  function help() {
19698
- 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
19760
+ 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
19699
19761
  leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # 회고 (1.9.13~1.9.16)
19700
19762
  leerness insights [path] [--all-apps] [--include p1,p2] [--json] # 누적 통계 (1.9.13~1.9.16)
19701
19763
  leerness brainstorm "<주제>" [--all-apps] [--include p1,p2] [--json] # 브레인스토밍 (1.9.13~1.9.16)
@@ -19898,6 +19960,8 @@ async function main() {
19898
19960
  // 1.9.254: leerness path-setup [--apply] — CLI PATH 자동 등록 (사용자 명시 UR-0019)
19899
19961
  // npm global bin 경로 감지 + leerness 가 PATH 에서 찾아지는지 확인 → 미등록 시 플랫폼별 등록
19900
19962
  if (cmd === 'path-setup' || cmd === 'path') return pathSetupCmd(arg('--path', process.cwd()), { apply: has('--apply'), json: has('--json') });
19963
+ // 1.9.258: leerness selftest — 설치된 바이너리 코어 함수 무결성 자가 검증 (CI/사용자 진단)
19964
+ if (cmd === 'selftest' || cmd === 'self-test') return selfTestCmd({ json: has('--json') });
19901
19965
  // 1.9.245: API skill cache — 공식 문서·관련링크 자동 정리 (사용자 명시 UR-0015)
19902
19966
  if (cmd === 'api-skill') return apiSkillCmd(arg('--path', process.cwd()), args[1] || 'help');
19903
19967
  // 1.9.208: leerness constraints <list|check|add> — 플랫폼/API 제약 사전 체크 (사용자 명시)
@@ -20057,5 +20121,7 @@ module.exports = {
20057
20121
  _winPathPsScript, _unixPathBlock, pathSetupCmd,
20058
20122
  _isSecretKey, compareVer, parseHarnessVersion,
20059
20123
  // 1.9.257: CJK 인코딩 분류 (UR-0014 계열) 순수 함수 — 단위 테스트
20060
- _classifyCJK, _riskLabel
20124
+ _classifyCJK, _riskLabel,
20125
+ // 1.9.258: selftest — 코어 함수 무결성 검증
20126
+ _selfTestCases, selfTestCmd
20061
20127
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.257",
3
+ "version": "1.9.259",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",
@@ -45,7 +45,7 @@
45
45
  "LICENSE"
46
46
  ],
47
47
  "scripts": {
48
- "test": "node ./bin/harness.js --version && node ./scripts/e2e.js",
48
+ "test": "node ./bin/harness.js --version && node ./bin/harness.js selftest && node ./scripts/e2e.js",
49
49
  "test:smoke": "node ./scripts/e2e.js",
50
50
  "prepack": "node ./bin/harness.js --version"
51
51
  },