leerness 1.9.77 → 1.9.78
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 +30 -0
- package/README.md +3 -2
- package/bin/harness.js +35 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.78 — 2026-05-20
|
|
4
|
+
|
|
5
|
+
**`drift check`에 5번째 신호 추가 — 보안 누락이 drift score 가중** (1.9.75/76 보안 검사 통합).
|
|
6
|
+
|
|
7
|
+
### Added — drift check 보안 신호
|
|
8
|
+
- 기존 4 신호: session-handoff / current-state / progress-tracker / task-log.
|
|
9
|
+
- **5번째 신호**: `.env` + `.gitignore` 보안 점검.
|
|
10
|
+
- `.env→.env.example` 누락 → +15 score.
|
|
11
|
+
- `.gitignore`에 `.env` 누락 → **+30 score** (최우선 위험).
|
|
12
|
+
- 기타 시크릿 패턴 (`.env.local`, `*.pem`, `credentials.json` 등) 누락 → max +20 (개당 +5).
|
|
13
|
+
- `drift check --json` 의 `fired` 배열에 새 항목 추가:
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"file": ".env / .gitignore",
|
|
17
|
+
"weight": 45,
|
|
18
|
+
"label": "보안 위험 (1.9.78): .env→.env.example 누락 N건 · .gitignore 시크릿 누락 M건"
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
- 보안 누락이 drift level을 critical로 승격시킬 수 있음 (CI 친화).
|
|
22
|
+
|
|
23
|
+
### Use Case
|
|
24
|
+
- 매 \`leerness handoff\` 시 drift 신호로 보안 위험 즉시 인지 (1.9.76 보안 요약과 동시).
|
|
25
|
+
- AI 에이전트가 drift critical 시 \`drift check --auto-fix\` → `audit --fix` 호출 → 자동 회복.
|
|
26
|
+
|
|
27
|
+
### Verified
|
|
28
|
+
- stress-v24 — drift 보안 신호 + level 승격 + 1.9.43~77 누적 회귀 + 성능.
|
|
29
|
+
- e2e 219/219 PASS 유지.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
3
33
|
## 1.9.77 — 2026-05-20
|
|
4
34
|
|
|
5
35
|
**MCP server 15번째 도구 `leerness_brainstorm` 추가** (1.9.72 brainstorm 외부 노출).
|
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.78 AI Agent Reliability Harness ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · prevent drift ║
|
|
17
17
|
╚══════════════════════════════════════════════════════════════╝
|
|
18
18
|
```
|
|
@@ -433,6 +433,7 @@ npm test # = node ./scripts/e2e.js
|
|
|
433
433
|
|
|
434
434
|
## 변경 이력 (최근)
|
|
435
435
|
|
|
436
|
+
- **1.9.78** — **`drift check` 5번째 신호** — `.env` + `.gitignore` 보안 누락을 drift score에 가중 (`.env` 자체 누락 시 +30, 동기화 누락 +15). 보안 위험이 drift critical 승격 가능.
|
|
436
437
|
- **1.9.77** — **MCP server 15번째 도구 `leerness_brainstorm`** — 1.9.72 brainstorm (decisions + skills + tasks + rules + evidence + lessons + skillHistory + taskLogFails)을 외부 AI에 노출. AI가 새 작업 시작 전 누적 컨텍스트 자동 회수.
|
|
437
438
|
- **1.9.76** — **`leerness handoff`에 보안 상태 요약 자동 표시** — `.env→.env.example` 누락 + `.gitignore` 시크릿 패턴 누락을 매 handoff에 1-2 line 자동 노출. AI가 세션 시작 즉시 보안 위험 인지.
|
|
438
439
|
- **1.9.75** — **`leerness audit` 보안 강화** — `.env` 존재 시 `.gitignore`에 시크릿 패턴 (`.env`/`.env.local`/`.env.production`/`*.pem`/`credentials.json`) 자동 검증, `--fix`로 자동 추가.
|
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.78';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -3309,7 +3309,7 @@ function _banner(opts = {}) {
|
|
|
3309
3309
|
lines.push('');
|
|
3310
3310
|
for (const ln of lines) log(ln);
|
|
3311
3311
|
if (opts.quickStart) {
|
|
3312
|
-
log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.
|
|
3312
|
+
log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.78+ 워크플로)')));
|
|
3313
3313
|
log(' ' + C.green('npx leerness@latest init .') + C.dim(' # 신규 프로젝트 + 외부 AI CLI 설정'));
|
|
3314
3314
|
log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨텍스트 + lessons + 매칭 skill + 이전 history hit (1.9.69)'));
|
|
3315
3315
|
log(' ' + C.green('npx leerness skill match "<query>"') + C.dim(' # 매칭 skill + rolling history 자동 누적 (1.9.68)'));
|
|
@@ -6310,6 +6310,39 @@ function driftCheckCmd(root, opts = {}) {
|
|
|
6310
6310
|
fired.push(s);
|
|
6311
6311
|
}
|
|
6312
6312
|
}
|
|
6313
|
+
// 1.9.78: 보안 신호 (env / .gitignore 누락) — 5번째 신호
|
|
6314
|
+
try {
|
|
6315
|
+
const envPath = path.join(root, '.env');
|
|
6316
|
+
if (exists(envPath)) {
|
|
6317
|
+
let secScore = 0;
|
|
6318
|
+
const secIssues = [];
|
|
6319
|
+
// (a) .env vs .env.example 동기화
|
|
6320
|
+
try {
|
|
6321
|
+
const d = envDiff(root);
|
|
6322
|
+
if (d.inEnvOnly.length) {
|
|
6323
|
+
secIssues.push(`.env→.env.example 누락 ${d.inEnvOnly.length}건`);
|
|
6324
|
+
secScore += 15;
|
|
6325
|
+
}
|
|
6326
|
+
} catch {}
|
|
6327
|
+
// (b) .gitignore 시크릿 패턴
|
|
6328
|
+
try {
|
|
6329
|
+
const giText = exists(path.join(root, '.gitignore')) ? read(path.join(root, '.gitignore')) : '';
|
|
6330
|
+
const giLines = giText.split('\n').map(l => l.trim());
|
|
6331
|
+
const SECRET_PATTERNS = ['.env', '.env.local', '.env.production', '.env.*.local', '*.pem', 'credentials.json'];
|
|
6332
|
+
const missing = SECRET_PATTERNS.filter(p => !giLines.some(l => l === p || l === '/' + p));
|
|
6333
|
+
if (missing.length) {
|
|
6334
|
+
secIssues.push(`.gitignore 시크릿 누락 ${missing.length}건`);
|
|
6335
|
+
// 누락이 .env 자체면 최우선 위험 — 15점 가중
|
|
6336
|
+
if (missing.includes('.env')) secScore += 30;
|
|
6337
|
+
else secScore += Math.min(20, missing.length * 5);
|
|
6338
|
+
}
|
|
6339
|
+
} catch {}
|
|
6340
|
+
if (secScore > 0) {
|
|
6341
|
+
totalScore += secScore;
|
|
6342
|
+
fired.push({ file: '.env / .gitignore', ageDays: null, threshold: 0, weight: secScore, label: `보안 위험 (1.9.78): ${secIssues.join(' · ')}` });
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
} catch {}
|
|
6313
6346
|
// 신규 _apps/* 에서 task 0건도 신호로
|
|
6314
6347
|
const appsDir = path.join(root, '_apps');
|
|
6315
6348
|
let appsZeroTask = [];
|