leerness 1.9.80 → 1.9.82

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,52 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.82 — 2026-05-20
4
+
5
+ **`drift check --auto-fix` 에 보안 회복 통합** (1.9.78 + 1.9.75 audit --fix 결합).
6
+
7
+ ### Added — drift --auto-fix 보안 자동 회복
8
+ - 1.9.39 `drift check --auto-fix` 확장:
9
+ - 기존: critical level 시 `session close` 자동 실행.
10
+ - **신규 (1.9.82)**: 보안 신호 (1.9.78) 발견 시 **우선 `audit --fix` 자동 실행** → `.gitignore` + `.env.example` 동기화 → 재검사.
11
+ - 호출 순서:
12
+ 1. drift 신호 평가 (5개)
13
+ 2. 보안 신호 fired → `audit --fix` 자동 실행 + 재귀 재검사
14
+ 3. (보안 없는 critical) → `session close` 자동 실행 + 재귀 재검사
15
+ - AI 에이전트가 `drift check --auto-fix` 한 번으로 보안 + 세션 마감 둘 다 자동 회복.
16
+
17
+ ### Verified
18
+ - stress-v28 — drift --auto-fix 보안 회복 / 재검사 후 안정화 / 누적 회귀.
19
+ - e2e 219/219 PASS 유지.
20
+
21
+ ---
22
+
23
+ ## 1.9.81 — 2026-05-20
24
+
25
+ **`handoff` "통합 헤드라인" 한 줄 요약** (drift + 보안 + skill + MCP).
26
+
27
+ ### Added — handoff 헤드라인
28
+ - Date / Project 라인 직후에 한 줄 요약 자동 노출:
29
+ ```
30
+ 📊 헤드라인 (1.9.81): drift healthy (0) · 🔒 보안 OK · 🔌 MCP 8회 · 📒 skill query 4회 · 📚 12 skills
31
+ ```
32
+ - 표시 요소:
33
+ - `drift <level> (<score>)` — 1.9.78 5신호 결과
34
+ - `🔒 보안 OK` 또는 `🚨 보안 위험` — 1.9.76 보안 요약 압축
35
+ - `🔌 MCP N회` — 1.9.70 MCP 누적 카운트
36
+ - `📒 skill query N회` — 1.9.68 rolling history 누적
37
+ - `📚 N skills` — 설치된 skill 총 수
38
+ - 데이터 없는 항목은 자동 생략 (잡음 방지).
39
+ - 끄기: `--no-headline` 또는 `--compact`.
40
+
41
+ ### Use Case
42
+ - AI 에이전트가 한 줄로 워크스페이스 상태 즉시 인지 → "drift attention인데 MCP 0회면 도구 안 쓰고 있다" 같은 빠른 판단.
43
+
44
+ ### Verified
45
+ - stress-v27 — 헤드라인 노출 / --no-headline / 누적 회귀.
46
+ - e2e 219/219 PASS 유지.
47
+
48
+ ---
49
+
3
50
  ## 1.9.80 — 2026-05-20
4
51
 
5
52
  **handoff에서 `.env` 보안 critical 시 자동 회복 옵션** (1.9.76 보안 요약 + 1.9.75 audit --fix 결합).
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.80-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.82-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.80 AI Agent Reliability Harness ║
15
+ ║ v1.9.82 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.82** — **`drift check --auto-fix` 보안 회복 통합** — 1.9.78 보안 신호 발견 시 `audit --fix` 자동 실행 → `.gitignore` + `.env.example` 동기화 후 재검사. 보안 + 세션 마감 한 번에 자동 회복.
437
+ - **1.9.81** — **`handoff` 통합 헤드라인** — drift level + 보안 상태 + MCP 활동 + skill query + 설치 skill 수를 한 줄로 압축. AI가 세션 시작 즉시 워크스페이스 상태 인지.
436
438
  - **1.9.80** — **handoff 보안 critical 자동 회복** — `.env` 가 `.gitignore` 에 없으면 🚨 CRITICAL 경고 + `LEERNESS_AUTO_SECURITY_FIX=1` 시 `audit --fix` 자동 실행.
437
439
  - **1.9.79** — **`leerness skill suggest` 알고리즘 강화** — 1.9.68 rolling history 빈도 (×2 가중) 추가. 반복 검색된 키워드를 신규 skill 후보로 자동 식별 (Hermes-style 학습).
438
440
  - **1.9.78** — **`drift check` 5번째 신호** — `.env` + `.gitignore` 보안 누락을 drift score에 가중 (`.env` 자체 누락 시 +30, 동기화 누락 +15). 보안 위험이 drift critical 승격 가능.
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.80';
9
+ const VERSION = '1.9.82';
10
10
  const MARK = '<!-- leerness:managed -->';
11
11
  const README_START = '<!-- leerness:project-readme:start -->';
12
12
  const README_END = '<!-- leerness:project-readme:end -->';
@@ -1815,6 +1815,56 @@ function handoff(root) {
1815
1815
  log('# Session Start Context');
1816
1816
  log(`Date: ${today()}`);
1817
1817
  log(`Project: ${detectProjectName(root)}`);
1818
+ // 1.9.81: 통합 헤드라인 — drift level + 보안 상태 + skill 추천 + MCP 활동을 한 줄로 압축
1819
+ // AI 에이전트가 매 세션 시작 즉시 컨텍스트 인지. --no-headline 또는 --compact로 끄기.
1820
+ if (!has('--no-headline') && !has('--compact')) {
1821
+ try {
1822
+ const parts = [];
1823
+ // 1) drift level (가벼운 check)
1824
+ try {
1825
+ const r = cp.spawnSync(process.execPath, [__filename, 'drift', 'check', root, '--json'],
1826
+ { encoding: 'utf8', timeout: 8000, env: { ...process.env, LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '0' } });
1827
+ const j = JSON.parse(r.stdout.trim());
1828
+ if (j.level) parts.push(`drift ${j.level.replace(/^[^\w]+/, '')} (${j.score})`);
1829
+ } catch {}
1830
+ // 2) 보안 상태
1831
+ try {
1832
+ const envPath = path.join(root, '.env');
1833
+ if (exists(envPath)) {
1834
+ const giText = exists(path.join(root, '.gitignore')) ? read(path.join(root, '.gitignore')) : '';
1835
+ const giLines = giText.split('\n').map(l => l.trim());
1836
+ if (giLines.includes('.env') || giLines.includes('/.env')) parts.push('🔒 보안 OK');
1837
+ else parts.push('🚨 보안 위험');
1838
+ }
1839
+ } catch {}
1840
+ // 3) MCP 활동 누적
1841
+ try {
1842
+ const stats = _readUsageStats(root);
1843
+ const mcpTotal = stats.mcp?.tools ? Object.values(stats.mcp.tools).reduce((s, n) => s + n, 0) : 0;
1844
+ if (mcpTotal > 0) parts.push(`🔌 MCP ${mcpTotal}회`);
1845
+ } catch {}
1846
+ // 4) skill match history 누적
1847
+ try {
1848
+ const histPath = path.join(root, '.harness', 'skill-suggestions.md');
1849
+ if (exists(histPath)) {
1850
+ const txt = read(histPath);
1851
+ const cnt = (txt.match(/^## [\d-]+ [\d:]+ — query/gm) || []).length;
1852
+ if (cnt > 0) parts.push(`📒 skill query ${cnt}회`);
1853
+ }
1854
+ } catch {}
1855
+ // 5) 설치된 skill 수
1856
+ try {
1857
+ const all = listAllSkills(root);
1858
+ const skillCnt = Object.keys(all).length;
1859
+ if (skillCnt > 0) parts.push(`📚 ${skillCnt} skills`);
1860
+ } catch {}
1861
+ if (parts.length) {
1862
+ const isTty = process.stdout && process.stdout.isTTY;
1863
+ const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
1864
+ log(cy(`📊 헤드라인 (1.9.81): ${parts.join(' · ')}`));
1865
+ }
1866
+ } catch {}
1867
+ }
1818
1868
  // 1.9.8: active rules 자동 노출 (매 세션 시작 시 AI에게 보임)
1819
1869
  const activeRules = readRules(root).filter(r => r.status === 'active');
1820
1870
  if (activeRules.length) {
@@ -3334,7 +3384,7 @@ function _banner(opts = {}) {
3334
3384
  lines.push('');
3335
3385
  for (const ln of lines) log(ln);
3336
3386
  if (opts.quickStart) {
3337
- log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.80+ 워크플로)')));
3387
+ log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.82+ 워크플로)')));
3338
3388
  log(' ' + C.green('npx leerness@latest init .') + C.dim(' # 신규 프로젝트 + 외부 AI CLI 설정'));
3339
3389
  log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨텍스트 + lessons + 매칭 skill + 이전 history hit (1.9.69)'));
3340
3390
  log(' ' + C.green('npx leerness skill match "<query>"') + C.dim(' # 매칭 skill + rolling history 자동 누적 (1.9.68)'));
@@ -6402,8 +6452,30 @@ function driftCheckCmd(root, opts = {}) {
6402
6452
  }
6403
6453
  } catch {}
6404
6454
  // 1.9.39: --auto-fix — critical 시 session close 자동 실행
6455
+ // 1.9.82: --auto-fix가 보안 신호도 자동 회복 (audit --fix 호출)
6405
6456
  const autoFix = has('--auto-fix');
6406
- if (autoFix && level === '🔴 critical') {
6457
+ // 1.9.82: 보안 신호가 fired에 있으면 우선 audit --fix 호출
6458
+ const hasSecurityFired = fired.some(f => /보안 위험 \(1\.9\.78\)/.test(f.label));
6459
+ if (autoFix && hasSecurityFired) {
6460
+ log('');
6461
+ log(`🔒 --auto-fix 활성 (1.9.82) — 보안 신호 회복: audit --fix 자동 실행 중...`);
6462
+ try {
6463
+ const r = cp.spawnSync(process.execPath, [__filename, 'audit', root, '--fix'],
6464
+ { encoding: 'utf8', timeout: 30000, env: { ...process.env, LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' } });
6465
+ if (r.status === 0) {
6466
+ log(`✓ audit --fix 완료 — .gitignore + .env.example 동기화`);
6467
+ // 재검사 (보안 신호 회복 확인)
6468
+ log('');
6469
+ log(`재검사 중...`);
6470
+ return driftCheckCmd(root); // 재귀 1회 (auto-fix 없이)
6471
+ } else {
6472
+ log(`⚠ audit --fix 실패 (exit ${r.status}) — 수동 \`leerness audit --fix\` 권장`);
6473
+ }
6474
+ } catch (e) {
6475
+ log(`⚠ auto-fix 보안 회복 오류: ${e.message}`);
6476
+ }
6477
+ }
6478
+ if (autoFix && level === '🔴 critical' && !hasSecurityFired) {
6407
6479
  log('');
6408
6480
  log(`🔧 --auto-fix 활성 — session close 자동 실행 중...`);
6409
6481
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.80",
3
+ "version": "1.9.82",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",