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 +47 -0
- package/README.md +4 -2
- package/bin/harness.js +75 -3
- package/package.json +1 -1
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
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
╔══════════════════════════════════════════════════════════════╗
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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 {
|