leerness 1.9.89 → 1.9.91

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,49 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.91 — 2026-05-20
4
+
5
+ **MCP server 19번째 도구 `leerness_skill_search`** (1.9.90 외부 AI 노출).
6
+
7
+ ### Added — MCP 19번째 도구
8
+ - `leerness_skill_search` — 1.9.90 skill search 명령을 외부 AI에 노출.
9
+ - inputSchema: `{ capability: string (required), path: string }`
10
+ - 응답: `skill search --json` 결과
11
+ - 외부 AI가 capability 키워드로 사용 가능한 skill 직접 검색.
12
+ - MCP server 도구 카운트: **18 → 19**.
13
+
14
+ ### Verified
15
+ - stress-v37 — MCP 19 도구 + skill_search 호출 + 누적 회귀.
16
+ - e2e 219/219 PASS 유지.
17
+
18
+ ---
19
+
20
+ ## 1.9.90 — 2026-05-20
21
+
22
+ **`leerness skill search <capability>` 새 명령** — capability 배열 부분 일치 검색.
23
+
24
+ ### Added — `leerness skill search`
25
+ - `leerness skill search "<capability>"` — capability 키워드로 skill 검색.
26
+ - substring + case-insensitive 매칭.
27
+ - `--json`: 구조화 출력 (`{ query, total, matches[] }`).
28
+ - skill match (jaccard 점수 매칭)과 다름:
29
+ - `skill match`: 자연어 task → 점수 기반 추천
30
+ - `skill search`: capability 필드에 정확히 키워드 포함된 skill만
31
+ - 예:
32
+ ```
33
+ leerness skill search "API" → commerce-api
34
+ leerness skill search "검증" → firebase, ai-verified-skill-publisher
35
+ ```
36
+
37
+ ### Use Case
38
+ - "내가 이 능력을 가진 skill을 찾고 싶다" 명확한 의도에 사용.
39
+ - skill match가 너무 광범위할 때 capability로 좁히기.
40
+
41
+ ### Verified
42
+ - stress-v36 — search 명령 + 부분 일치 + --json + 누적 회귀.
43
+ - e2e 219/219 PASS 유지.
44
+
45
+ ---
46
+
3
47
  ## 1.9.89 — 2026-05-20
4
48
 
5
49
  **자율 모드 19 라운드 종합 검증 + 마무리** (1.9.70 ~ 1.9.88).
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.89-green)]() [![tests](https://img.shields.io/badge/e2e-219%2F219-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.91-green)]() [![tests](https://img.shields.io/badge/e2e-219%2F219-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
6
6
 
7
7
  ```
8
8
  ╔══════════════════════════════════════════════════════════════╗
@@ -12,7 +12,7 @@
12
12
  ║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
13
13
  ║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
14
14
  ║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
15
- ║ v1.9.89 AI Agent Reliability Harness ║
15
+ ║ v1.9.91 AI Agent Reliability Harness ║
16
16
  ║ verify · remember · orchestrate · audit · prevent drift ║
17
17
  ╚══════════════════════════════════════════════════════════════╝
18
18
  ```
@@ -433,6 +433,8 @@ npm test # = node ./scripts/e2e.js
433
433
 
434
434
  ## 변경 이력 (최근)
435
435
 
436
+ - **1.9.91** — **MCP server 19번째 도구 `leerness_skill_search`** — 1.9.90 skill search를 외부 AI에 노출.
437
+ - **1.9.90** — **`leerness skill search <capability>` 새 명령** — capability 배열 부분 일치 검색 (skill match와 다른 정확 매칭). `--json` 옵션.
436
438
  - **1.9.89** — **자율 모드 19 라운드 종합 검증** — stress-v35 24/24 PASS + handoff 692ms / health 689ms (회귀 없음). 자율 모드 (1.9.70~88) 안정 완료.
437
439
  - **1.9.88** — **`handoff`에 brainstorm 자동 hits 노출** — 현재 task 키워드로 자동 호출 → decisions / lessons / task-log fail / skill 미리보기 1줄씩 (1.9.72 brainstorm 통합).
438
440
  - **1.9.87** — **`session-workflow.md` 템플릿 갱신** — 1.9.69~86 누적 신규 기능 안내 추가 (handoff history hit / 보안 요약 / CRITICAL / 헤드라인 / health / drift --auto-fix 보안 / MCP 18 도구). init 가이드 정확성 보장.
package/bin/harness.js CHANGED
@@ -6,7 +6,7 @@ const path = require('path');
6
6
  const cp = require('child_process');
7
7
  const readline = require('readline');
8
8
 
9
- const VERSION = '1.9.89';
9
+ const VERSION = '1.9.91';
10
10
  const MARK = '<!-- leerness:managed -->';
11
11
  const README_START = '<!-- leerness:project-readme:start -->';
12
12
  const README_END = '<!-- leerness:project-readme:end -->';
@@ -3433,7 +3433,7 @@ function _banner(opts = {}) {
3433
3433
  lines.push('');
3434
3434
  for (const ln of lines) log(ln);
3435
3435
  if (opts.quickStart) {
3436
- log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.89+ 워크플로)')));
3436
+ log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.91+ 워크플로)')));
3437
3437
  log(' ' + C.green('npx leerness@latest init .') + C.dim(' # 신규 프로젝트 + 외부 AI CLI 설정'));
3438
3438
  log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨텍스트 + lessons + 매칭 skill + 이전 history hit (1.9.69)'));
3439
3439
  log(' ' + C.green('npx leerness skill match "<query>"') + C.dim(' # 매칭 skill + rolling history 자동 누적 (1.9.68)'));
@@ -3443,7 +3443,7 @@ function _banner(opts = {}) {
3443
3443
  log(' ' + C.green('npx leerness session close .') + C.dim(' # 마감 + 다음 라운드 추천 (default)'));
3444
3444
  log('');
3445
3445
  log(C.bold(C.cyan(' 🤖 메인 에이전트 (Claude/Cursor/Copilot)용')));
3446
- log(' ' + C.green('npx leerness mcp serve') + C.dim(' # MCP 서버 — 18 도구 (health 포함, 1.9.86)'));
3446
+ log(' ' + C.green('npx leerness mcp serve') + C.dim(' # MCP 서버 — 19 도구 (skill_search 포함, 1.9.91)'));
3447
3447
  log(' ' + C.green('npx leerness agents bench "<task>"') + C.dim(' # 3 CLI 동시 비교'));
3448
3448
  log('');
3449
3449
  }
@@ -7245,6 +7245,49 @@ function _cosine(a, b) {
7245
7245
  return (na && nb) ? dot / (Math.sqrt(na) * Math.sqrt(nb)) : 0;
7246
7246
  }
7247
7247
 
7248
+ // 1.9.90: leerness skill search <capability> — capability 배열에서 부분 일치 검색
7249
+ // skill match (jaccard)와 다름: capability 필드 정확 매칭 (substring + case-insensitive)
7250
+ function skillSearchCmd(root, capabilityQuery) {
7251
+ root = absRoot(root || process.cwd());
7252
+ if (!capabilityQuery) { fail('사용법: leerness skill search "<capability keyword>" [--json]'); return process.exit(1); }
7253
+ const all = listAllSkills(root);
7254
+ const q = capabilityQuery.toLowerCase();
7255
+ const matches = [];
7256
+ for (const [id, v] of Object.entries(all)) {
7257
+ const caps = v.capabilities || [];
7258
+ const matched = caps.filter(c => String(c).toLowerCase().includes(q));
7259
+ if (matched.length) {
7260
+ matches.push({
7261
+ id,
7262
+ displayNameKo: v.displayNameKo || id,
7263
+ source: v._source,
7264
+ matchedCapabilities: matched,
7265
+ allCapabilities: caps.length,
7266
+ usageCount: v.usage?.count || 0
7267
+ });
7268
+ }
7269
+ }
7270
+ if (has('--json')) {
7271
+ log(JSON.stringify({ query: capabilityQuery, total: matches.length, matches }, null, 2));
7272
+ return;
7273
+ }
7274
+ log(`# leerness skill search (1.9.90)`);
7275
+ log(`query (capability): "${capabilityQuery}"`);
7276
+ log(`전체 ${Object.keys(all).length}개 skill 중 매칭 ${matches.length}건`);
7277
+ log('');
7278
+ if (!matches.length) {
7279
+ log(' (해당 능력 없음 — 다른 키워드 시도 또는 \`leerness skill discover\`로 확장)');
7280
+ return;
7281
+ }
7282
+ log(`| ID | 한글명 | 매칭 능력 | 사용 |`);
7283
+ log(`|---|---|---|---:|`);
7284
+ for (const m of matches) {
7285
+ log(`| ${m.id} | ${m.displayNameKo} | ${m.matchedCapabilities.slice(0, 2).join(' / ')}${m.matchedCapabilities.length > 2 ? ' …' : ''} | ${m.usageCount}회 |`);
7286
+ }
7287
+ log('');
7288
+ log(`💡 상세: \`leerness skill info <id>\` · 사용 시작: \`leerness skill use <id>\``);
7289
+ }
7290
+
7248
7291
  async function skillMatchCmd(root, query) {
7249
7292
  root = absRoot(root || process.cwd());
7250
7293
  if (!query) { fail('사용법: leerness skill match "<task or keywords>" [--embedding]'); return process.exit(1); }
@@ -7388,7 +7431,8 @@ function mcpServeCmd(root) {
7388
7431
  { name: 'leerness_brainstorm', description: '1.9.16/72/77 — 누적 컨텍스트(decisions+skills+tasks+rules+evidence+lessons+skillHistory+taskLogFails) 자원 회수. 외부 AI가 새 작업 시작 전 호출', inputSchema: { type: 'object', properties: { topic: { type: 'string' }, path: { type: 'string' }, allApps: { type: 'boolean' } }, required: ['topic'] } },
7389
7432
  { name: 'leerness_skill_match', description: '1.9.45/50/83 — 사용자 task 키워드에 매칭되는 설치된 skill 추천 (jaccard 또는 embedding). 1.9.68 rolling history 자동 누적', inputSchema: { type: 'object', properties: { query: { type: 'string' }, path: { type: 'string' }, useEmbedding: { type: 'boolean' } }, required: ['query'] } },
7390
7433
  { name: 'leerness_skill_list', description: '1.9.84 — 워크스페이스에 설치된 skill 목록 + 사용 횟수 + 출처 (catalog/user). 외부 AI가 사용 가능한 skill 조회', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
7391
- { name: 'leerness_health', description: '1.9.85/86 — 종합 헬스 체크 (drift + 보안 + skills + MCP + tasks + issues 배열). 외부 AI가 워크스페이스 상태 한 번에 확인', inputSchema: { type: 'object', properties: { path: { type: 'string' }, strict: { type: 'boolean' } } } }
7434
+ { name: 'leerness_health', description: '1.9.85/86 — 종합 헬스 체크 (drift + 보안 + skills + MCP + tasks + issues 배열). 외부 AI가 워크스페이스 상태 한 번에 확인', inputSchema: { type: 'object', properties: { path: { type: 'string' }, strict: { type: 'boolean' } } } },
7435
+ { name: 'leerness_skill_search', description: '1.9.90/91 — capability 배열에서 부분 일치하는 skill 검색 (substring + case-insensitive). skill match와 다른 정확 매칭', inputSchema: { type: 'object', properties: { capability: { type: 'string' }, path: { type: 'string' } }, required: ['capability'] } }
7392
7436
  ];
7393
7437
 
7394
7438
  function send(obj) {
@@ -7438,6 +7482,7 @@ function mcpServeCmd(root) {
7438
7482
  case 'leerness_skill_match': cliArgs = ['skill', 'match', args.query || '', '--path', targetPath, '--json', ...(args.useEmbedding ? ['--embedding'] : [])]; break;
7439
7483
  case 'leerness_skill_list': cliArgs = ['skill', 'list', targetPath, '--json']; break;
7440
7484
  case 'leerness_health': cliArgs = ['health', targetPath, '--json', ...(args.strict ? ['--strict'] : [])]; break;
7485
+ case 'leerness_skill_search': cliArgs = ['skill', 'search', args.capability || '', '--path', targetPath, '--json']; break;
7441
7486
  default:
7442
7487
  return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
7443
7488
  }
@@ -8089,6 +8134,8 @@ async function main() {
8089
8134
  if (cmd === 'skill' && args[1] === 'export') return skillExportCmd(absRoot(arg('--path', process.cwd())), args[2]);
8090
8135
  if (cmd === 'skill' && args[1] === 'export-all') return skillExportAllCmd(absRoot(arg('--path', process.cwd())));
8091
8136
  if (cmd === 'skill' && args[1] === 'match') return skillMatchCmd(absRoot(arg('--path', process.cwd())), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
8137
+ // 1.9.90: leerness skill search <capability> — capability 키워드로 검색 (substring 정확 일치)
8138
+ if (cmd === 'skill' && args[1] === 'search') return skillSearchCmd(absRoot(arg('--path', process.cwd())), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
8092
8139
  if (cmd === 'benchmark') return benchmarkCmd(absRoot(args[1] || arg('--path', process.cwd())));
8093
8140
  if (cmd === 'skill' && args[1] === 'publish') return skillPublishCmd(absRoot(arg('--path', process.cwd())));
8094
8141
  if (cmd === 'skill' && args[1] === 'suggest') return skillSuggestCmd(absRoot(arg('--path', process.cwd())));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.89",
3
+ "version": "1.9.91",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",