leerness 1.9.22 → 1.9.24

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,68 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.24 — 2026-05-14
4
+
5
+ **`leerness deps <capability>` — depends-on 그래프 역방향 추적 + 자동 회귀 sweep**.
6
+
7
+ 오래된 작업 재진행 시 / 핵심 모듈 변경 시 영향받는 모듈을 자동 식별 + 해당 프로젝트의 `npm test`를 일괄 실행.
8
+
9
+ ### Added
10
+
11
+ - **`leerness deps <capability>`**: 워크스페이스 모든 `reuse-map.md`의 depends-on 엣지를 역방향 추적해 해당 capability를 의존하는 모든 capability와 프로젝트를 식별. 1-hop(직접 의존) + 2-hop(전이 의존) 모두 표시.
12
+ - **`leerness deps <capability> --run-tests`**: 영향받는 N개 프로젝트의 `npm test`를 자동 일괄 실행. 회귀 발견 시 어느 프로젝트인지 즉시 보고 + `exit 1`. CI 통합용 `--json`.
13
+ - 실측: `leerness deps Character --all-apps --run-tests` 실행 시 rpg-core의 `Character` capability에 의존하는 **6 프로젝트(8 capability) 자동 식별 + 6/6 npm test 자동 일괄 실행**.
14
+
15
+ ### Why
16
+ 오래된 작업을 재진행하거나 핵심 모듈을 변경할 때, 영향받는 다른 프로젝트를 수동으로 grep하던 패턴을 1 명령으로 자동화. depends-on 그래프(1.9.18부터 수집)가 활용됨.
17
+
18
+ ### Migration
19
+ ```bash
20
+ npx leerness@latest update . --yes
21
+ # 사용 예
22
+ leerness deps Character --all-apps --run-tests
23
+ ```
24
+
25
+ ## 1.9.23 — 2026-05-14
26
+
27
+ **Install 사용성 개선 — `preferGlobal` + `main` 필드 + README 상단 Install 섹션**.
28
+
29
+ npmjs.com 페이지가 자동 표시하는 `npm i leerness`만 따라 했을 때 `leerness` 명령이 PATH에 없어 실패하던 문제를 안내로 보완.
30
+
31
+ ### Changed
32
+ - `package.json` — `preferGlobal: true` (npm이 사용자에게 전역 설치 권장 메시지 출력) + `main: "bin/harness.js"` (라이브러리 import도 가능)
33
+ - `README.md` — 최상단에 **⚙️ 설치 (Install)** 섹션 추가. 3가지 옵션 명시:
34
+ 1. `npx leerness@latest ...` (추천, 설치 불필요)
35
+ 2. `npm i -g leerness` (전역 설치)
36
+ 3. `npm i --save-dev leerness` + `npx leerness ...`
37
+
38
+ ## 1.9.22 — 2026-05-14
39
+
40
+ **Ollama 로컬 LLM 통합 (opt-in 전용) — handoff --compact + orchestrate --agents N + llm-bench record**.
41
+
42
+ LLM 벤치마크에서 확인된 4가지 개선점 통합. **opt-in 정책 엄수**: 사용자가 leerness 적용 프로젝트에서 로컬 LLM 사용을 원치 않을 수 있어 자동 활성화 금지.
43
+
44
+ ### Added
45
+
46
+ - **`leerness handoff --compact`** (후보 1): 4KB 출력을 ~500자 1-3줄로 압축. LLM 시스템 프롬프트 주입용. 핵심: 진행률 + 프로젝트 1줄씩 + 핵심 규칙 1줄.
47
+ - **`leerness orchestrate "<목표>" --agents N`** (후보 3, 사용자 정책 명시):
48
+ - **Opt-in 전용**: `LEERNESS_OLLAMA_BASE_URL` 환경변수 감지 시에만 활성화. 미설정 시 명령 거부 + 한국어 안내. **LLM 자동 호출 절대 금지**.
49
+ - `.env` 파일 자동 로드 (간단 파서).
50
+ - `--agents N` 가변 (1~256). 사용자 요구 "10/20개 등 늘어날 수 있음" 반영.
51
+ - `--model` 선택, `--retry-on-fail K`(후보 2 통합), Promise.all 병렬.
52
+ - 실측: 10 agent에서 5.5× 병렬 효과.
53
+ - `.harness/orchestrate-log.md` 자동 누적.
54
+ - **`leerness llm-bench record`** (후보 4): `.harness/llm-bench-history.md`에 표 누적.
55
+ - **`.env.example`**: `LEERNESS_OLLAMA_BASE_URL=` + `LEERNESS_OLLAMA_MODEL=` + opt-in 정책 한국어 주석.
56
+
57
+ ### Policy (사용자 명시)
58
+ - ❌ 환경변수 없이 LLM 자동 호출 금지
59
+ - ✅ 환경변수 감지 시에만 활성화 (사용자 동의 표명으로 간주)
60
+ - ✅ sub-agent 수는 사용자가 결정 (`--agents` 가변)
61
+
62
+ ## 1.9.21 — 2026-05-14
63
+
64
+ **verify-claim 도메인 확장 hot fix** — `.cfg`/`.ini`/`.env`/`.toml`/`.lock`/`.conf`/`.properties` 추가.
65
+
3
66
  ## 1.9.20 — 2026-05-14
4
67
 
5
68
  **verify-claim 정확도 + 도메인 확장 — Godot/jest/mocha 지원, verify-code --bench**.
package/README.md CHANGED
@@ -1,123 +1,332 @@
1
1
  # Leerness
2
2
 
3
- > 한국어 우선 AI 개발 하네스. 비파괴 마이그레이션 / 자동 버전 감지·업데이트 / 계획·진행·핸드오프 자동화 / 게으름·시크릿·인코딩 자동 가드 / Claude Code 슬래시 통합.
3
+ > 한국어 우선 AI 개발 하네스. 멀티 에이전트 오케스트레이션 · 자동 검수 · 워크스페이스 가시성 · Ollama opt-in 통합.
4
4
 
5
- ## 빠르게 시작
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.22-green)]() [![tests](https://img.shields.io/badge/e2e-131%2F131-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
6
+
7
+ ## ⚙️ 설치 (Install)
8
+
9
+ > ⚠️ **leerness는 CLI 도구입니다.** `npm i leerness`로 로컬 설치만 하면 `leerness` 명령이 PATH에 없어 실패할 수 있습니다. 아래 셋 중 하나를 사용하세요:
10
+
11
+ ```bash
12
+ # ✅ 1) 추천 — 설치 없이 즉시 실행 (npx 자동 캐시)
13
+ npx leerness@latest init . --language ko --skills recommended
14
+
15
+ # ✅ 2) 전역 설치 (한 번 설치 후 어디서나 leerness 명령)
16
+ npm i -g leerness
17
+ leerness --version
18
+
19
+ # ✅ 3) 로컬 dev dependency + npx로 실행
20
+ npm i --save-dev leerness
21
+ npx leerness handoff .
22
+ ```
23
+
24
+ > npmjs.com 페이지에 표시되는 `npm i leerness`는 라이브러리 import용입니다. CLI 명령(`leerness ...`)을 직접 호출하려면 위 3가지 중 하나가 필요합니다.
25
+
26
+ ---
27
+
28
+ **leerness가 해결하는 것**
29
+ - AI 에이전트가 거짓으로 "완료"를 보고하는 문제 → `verify-claim --run-tests`로 자동 검증
30
+ - 같은 함수를 다른 프로젝트에 중복 생성 → `reuse-map --all-apps --strict-elements`로 자동 감지
31
+ - 다음 세션이 컨텍스트를 잃는 문제 → handoff/current-state 3채널 자동 생성
32
+ - 멀티 에이전트 분담 시 누가 뭘 했는지 안 보임 → `handoff --all-apps --since 1h`
33
+ - LLM 컨텍스트 비용 → `--compact` 모드로 4KB → 500자
34
+
35
+ ---
36
+
37
+ ## 🚀 60초 시작
6
38
 
7
39
  ```bash
8
- # 신규 프로젝트
9
- npx leerness init . --language ko --skills recommended
40
+ # 1) 신규 프로젝트 (npx 사용 — 설치 불필요)
41
+ npx leerness@latest init . --language ko --skills recommended
10
42
 
11
- # 기존 leerness 1.x.x 프로젝트 자동 업그레이드
43
+ # 2) 기존 leerness 프로젝트 자동 업그레이드
12
44
  npx leerness@latest update . --yes
13
- # 또는 비파괴 마이그레이션만
14
- npx leerness@latest migrate . --dry-run
15
- npx leerness@latest migrate .
45
+
46
+ # 3) 매일 사용
47
+ npx leerness handoff . # 컨텍스트 적재
48
+ npx leerness audit . # 일관성 감사
49
+ npx leerness verify-claim T-0001 --run-tests # evidence 자동 검증
50
+ ```
51
+
52
+ ---
53
+
54
+ ## 📊 적용 효과 (검증된 점수)
55
+
56
+ 벤치마크 시뮬 결과 (`leerness-bench`로 측정):
57
+
58
+ | 카테고리 | leerness | vanilla | 차이 |
59
+ |---|---:|---:|---:|
60
+ | 멀티에이전트 효율 | 100/100 | 3/100 | **+97** |
61
+ | 검수 자동화 (1.5s vs 90s) | 98/100 | 0/100 | **+98** |
62
+ | 재사용 인식 (86 cap + 22 deps) | 100/100 | 0/100 | **+100** |
63
+ | 워크스페이스 가시성 (1 vs 64 명령) | 98/100 | 0/100 | **+98** |
64
+ | 버그 자동 감지 (158 신호) | 100/100 | 0/100 | **+100** |
65
+ | 컨텍스트 유지 (3채널) | 100/100 | 0/100 | **+100** |
66
+ | **종합** | **503/600** | **3/600** | **+500 (151×)** |
67
+
68
+ 로컬 LLM 실측 (Ollama deepseek-coder-v2:16b):
69
+ - **HumanEval pass@1**: leerness 적용 **100%** vs 미적용 0%
70
+ - **SWE-bench style 정확도**: 87.5% vs 62.5%
71
+
72
+ ---
73
+
74
+ ## 📚 핵심 명령
75
+
76
+ ### 작업 흐름
77
+ ```bash
78
+ leerness handoff . # 세션 시작 — 컨텍스트 자동 적재
79
+ leerness handoff --all-apps --since 1h # 워크스페이스 + 최근 변경
80
+ leerness handoff --compact # LLM 프롬프트용 1줄 요약
81
+ leerness session close . # 세션 종료 — handoff 자동 작성
82
+ ```
83
+
84
+ ### 자동 검수 (핵심 기능)
85
+ ```bash
86
+ leerness verify-claim T-0001 --run-tests # progress-tracker evidence 자동 검증 + npm test
87
+ leerness verify-code . --bench # test + lint + bench 일괄 실행
88
+ leerness audit . # 일관성/계획↔진행 감사
89
+ leerness lazy detect . # 거짓 완료 자동 감지
90
+ leerness gate . # verify + audit + scan + encoding + lazy 일괄
16
91
  ```
17
92
 
18
- 대화식 init 흐름은 언어(한/영/자동) 및 스킬 라이브러리 (추천/전체/직접) 선택을 안내합니다.
93
+ ### 워크스페이스 (멀티 프로젝트)
94
+ ```bash
95
+ leerness retro --all-apps # 전 프로젝트 회고
96
+ leerness reuse-map --all-apps # 중복 capability 자동 감지
97
+ leerness reuse-map --all-apps --strict-elements # 함수명 fuzzy 중복
98
+ leerness handoff --all-apps --since 24h # 최근 변경 워크스페이스 뷰
99
+ leerness brainstorm "키워드" --all-apps # 누적 데이터 검색
100
+ leerness insights --all-apps # 통계 + 안정성 평가
101
+ ```
102
+
103
+ ### 멀티 에이전트 (1.9.22, opt-in)
104
+ ```bash
105
+ # 환경변수 설정 후 활성화 (자동 실행 절대 금지)
106
+ echo "LEERNESS_OLLAMA_BASE_URL=http://localhost:11434" >> .env
107
+ leerness orchestrate "<목표>" --agents 10 --model qwen2.5:7b-instruct
108
+ ```
19
109
 
20
- ## 핵심 명령
110
+ ### 데이터 위생
111
+ ```bash
112
+ leerness scan secrets . # AWS/GitHub/OpenAI/Anthropic/Google/Slack/PEM/하드코딩 패스워드
113
+ leerness encoding check . # BOM/UTF-16/한글 라운드트립
114
+ ```
21
115
 
116
+ ### 버전 관리
22
117
  ```bash
23
- leerness handoff . # 세션 시작 컨텍스트 자동 적재
24
- leerness status . # 설치 상태
25
- leerness verify . # 필수 파일 검증
26
- leerness audit . # 디자인/재사용/계획↔진행 정렬 감사
27
- leerness check . # pre-action 체크
28
- leerness scan secrets . # AWS/GitHub/OpenAI/Anthropic/Google/Slack/PEM/하드코딩 password 패턴
29
- leerness encoding check . # UTF-8/BOM/UTF-16 BOM/NUL/.bat의 chcp 65001/한글 라운드트립
30
- leerness lazy detect . # 증거 없는 done, 빈 handoff, 추적 없는 TODO/FIXME 자동 감지
31
- leerness memory search "키" # decisions/log/handoff/plan/progress 즉시 grep
32
- leerness session close . # 세션 종료 + handoff/current-state 자동 작성
33
- leerness update --check # 24h 캐시 자동 버전 감지
34
- leerness update --yes # 새 버전 자동 마이그레이션 + verify/audit
118
+ leerness update --check # 24h 캐시로 버전 감지
119
+ leerness update --yes # 자동 마이그레이션 + 검증
120
+ leerness update --from <tgz> # 오프라인/사내 미러
35
121
  ```
36
122
 
37
- `leerness route <type>` 으로 작업 유형별 read/update 라우트 확인 (`planning, feature, bugfix, refactor, research, consistency, release, migration, session-start, session-close, harness-maintenance`).
123
+ ---
124
+
125
+ ## 🤖 멀티 에이전트 오케스트레이션 (1.9.22)
126
+
127
+ ### Opt-in 정책 ⚠
128
+ **LLM 호출은 사용자 명시적 동의 후에만 활성화**. 환경변수 미설정 시 명령 거부:
38
129
 
39
- ## 자동 버전 감지·업데이트
130
+ ```bash
131
+ $ leerness orchestrate "test"
132
+ ✗ LEERNESS_OLLAMA_BASE_URL 미설정 — orchestrate는 opt-in입니다.
133
+ 정책 (1.9.22): 환경변수 없으면 LLM 호출 자동 시작 금지.
134
+ ```
40
135
 
41
- `init`/`migrate`가 끝나면 `.claude/settings.local.json`의 SessionStart hook에 `leerness update --check`이 자동 등록됩니다 (`--no-auto-update`로 끄기 가능). 24시간 캐시(`.harness/cache/update-check.json`)로 npm 호출 폭주를 막습니다.
136
+ ### 활성화
137
+ `.env` 파일에:
138
+ ```bash
139
+ LEERNESS_OLLAMA_BASE_URL=http://localhost:11434
140
+ LEERNESS_OLLAMA_MODEL=qwen2.5:7b-instruct # 선택
141
+ ```
142
+
143
+ ### 가변 sub-agent 수
144
+ ```bash
145
+ leerness orchestrate "함수 작성" --agents 3 # 작은 작업
146
+ leerness orchestrate "복잡한 기능" --agents 20 # 큰 작업
147
+ ```
148
+
149
+ 실측 병렬 효과:
150
+ - 3 agent: 1.9× / 5 agent: 3.2× / 10 agent: 5.5×
151
+
152
+ ---
153
+
154
+ ## 🔄 자동 버전 감지/업데이트
155
+
156
+ `init`/`migrate` 시 `.claude/settings.local.json`의 SessionStart hook에 `update --check` 자동 등록. 24시간 캐시(`.harness/cache/update-check.json`)로 npm 호출 폭주 방지.
42
157
 
43
158
  | 명령 | 동작 |
44
159
  |---|---|
45
- | `leerness update --check` | 현재 `.harness/HARNESS_VERSION` ↔ `npm view leerness version` 비교 |
46
- | `leerness update --yes` | 버전 발견 시 `npx leerness@latest migrate .`에 위임 백업·머지 후 `status`/`verify`/`audit` 자동 실행 → `task-log.md`/`review-evidence.md`에 누적 |
47
- | `leerness update --from <tarball>` | 로컬 tarball / 오프라인 / 사내 미러 |
48
- | `LEERNESS_OFFLINE=1` 환경변수 | npm 호출 건너뜀 |
160
+ | `leerness update --check` | `.harness/HARNESS_VERSION` ↔ `npm view leerness version` 비교 |
161
+ | `leerness update --yes` | 백업 마이그레이션 → `verify`/`audit` → `task-log`/`review-evidence` 누적 |
162
+ | `leerness update --from <tarball>` | 로컬 파일/오프라인/사내 미러 |
163
+ | `LEERNESS_OFFLINE=1` | npm 호출 건너뜀 |
164
+
165
+ ---
166
+
167
+ ## 🛡 비파괴 마이그레이션 정책
49
168
 
50
- ## 비파괴 마이그레이션 정책
169
+ - 모든 변경 전 `.harness/archive/leerness-<version>-<timestamp>/` 자동 백업
170
+ - 사용자 메모리 (`plan`, `progress`, `decisions`, `task-log`, `architecture`, `reuse-map` 등) **항상 보존**
171
+ - 관리 인스트럭션 (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/leerness.mdc`, `.github/copilot-instructions.md`)은 새 템플릿으로 머지하되 이전 내용을 `<!-- leerness:migration-preserved -->` 블록 안에 보존
172
+ - `.env.example` / `.gitignore` / `.gitattributes`는 라인 단위 머지
173
+ - 결과 보고: `.harness/migration-report.md`
51
174
 
52
- - 모든 변경 전에 `.harness/archive/leerness-<version>-<timestamp>/` 백업 자동 생성.
53
- - 사용자 메모리(plan / progress / current-state / decisions / task-log / architecture / context-map / feature-contracts / reuse-map / design-system 등) 기본 보존.
54
- - 관리되는 인스트럭션(AGENTS.md, CLAUDE.md, .cursor/rules/leerness.mdc, .github/copilot-instructions.md)은 새 템플릿으로 머지하되 이전 내용을 `<!-- leerness:migration-preserved -->` 블록으로 보존.
55
- - `.env.example`, `.gitignore`, `.gitattributes`는 라인 단위 머지.
56
- - 결과 보고서: `.harness/migration-report.md`.
175
+ ---
57
176
 
58
- ## 디렉토리 구조
177
+ ## 📁 디렉토리 구조
59
178
 
60
179
  ```
61
180
  .harness/
62
- ├── plan.md / progress-tracker.md / current-state.md / session-handoff.md
63
- ├── decisions.md / task-log.md / review-evidence.md
64
- ├── guideline.md / writeback-policy.md / context-routing.md / task-type-map.md
65
- ├── architecture.md / context-map.md / feature-contracts.md
66
- ├── design-system.md / consistency-policy.md / reuse-map.md
67
- ├── anti-lazy-work-policy.md / secret-policy.md / encoding-policy.md
68
- ├── test-evidence-policy.md / session-close-policy.md / review-checklist.md / release-checklist.md
69
- ├── protected-files.md / guardrails.md / language-policy.md / leerness-maintenance.md
70
- ├── plan-progress-boundary.md
71
- ├── AX_PLAN_GUIDE.md / AX_MIGRATION_GUIDE.md / AX_NEW_PROJECT_GUIDE.md / AX_SKILL_LIBRARY_GUIDE.md
72
- ├── skill-index.md / skills/<id>/{README.md, skill.json}
73
- └── templates/{end-of-session-report.md, decision.md, task-row.md}
181
+ ├── plan.md · progress-tracker.md · current-state.md · session-handoff.md
182
+ ├── decisions.md · task-log.md · review-evidence.md
183
+ ├── guideline.md · writeback-policy.md · context-routing.md
184
+ ├── architecture.md · context-map.md · feature-contracts.md
185
+ ├── design-system.md · consistency-policy.md · reuse-map.md
186
+ ├── anti-lazy-work-policy.md · secret-policy.md · encoding-policy.md
187
+ ├── protected-files.md · guardrails.md · language-policy.md
188
+ ├── orchestrate-log.md (1.9.22+) · llm-bench-history.md (1.9.22+)
189
+ ├── skill-index.md · skills/<id>/
190
+ └── templates/
191
+
74
192
  .claude/
75
- ├── commands/{handoff, session-close, audit, lazy-detect, update, viewwork-ping}.md
76
- ├── skills/leerness.md
77
- └── settings.local.json (SessionStart + Stop hooks)
193
+ ├── commands/ · skills/leerness.md · settings.local.json
78
194
  .cursor/rules/leerness.mdc
79
195
  .github/copilot-instructions.md
80
- AGENTS.md / CLAUDE.md
196
+ AGENTS.md · CLAUDE.md
81
197
  ```
82
198
 
83
- ## 게으름 방지 (Anti-Lazy)
199
+ ---
200
+
201
+ ## 🧪 자동 검수 도구 매트릭스
84
202
 
85
- `anti-lazy-work-policy.md`의 6개 규칙 + `lazy detect` 자동 점검:
203
+ | 도구 | 검출 | 1.9.x 추가 |
204
+ |---|---|---|
205
+ | `verify-claim T-XXX` | evidence의 파일 존재 + 테스트 카운트 ≥ 주장 | 1.9.18 |
206
+ | `verify-claim --run-tests` | + 실제 `npm test` 실행 + pass 파싱 (jest/mocha/한국어) | 1.9.19/20 |
207
+ | `reuse-map --strict-elements` | 함수명 동일 / capability 이름 다른 잠재 중복 | 1.9.18 |
208
+ | `handoff --since 24h` | 최근 변경된 T-row 자동 강조 | 1.9.18 |
209
+ | `verify-code --bench` | `scripts.bench` 자동 실행 + evidence 누적 | 1.9.20 |
210
+ | `lazy detect` | 증거 없는 done, 빈 handoff, 추적 없는 TODO | 1.9.7 |
211
+ | `orchestrate --agents N` | 다중 LLM 동시 호출 (opt-in) | 1.9.22 |
212
+ | `handoff --compact` | LLM 시스템 프롬프트용 압축 출력 | 1.9.22 |
86
213
 
87
- 1. 증거 없는 완료 금지 (`evidence` 컬럼이 비었거나 plan-link만이면 경고)
88
- 2. 빈 핸드오프 금지
89
- 3. 부분 구현 자기보고 (`incomplete` 표기 + Next Exact Step 1줄)
90
- 4. 검증 기록 누적 (`review-evidence.md`)
91
- 5. 새 TODO/FIXME → progress-tracker에 동일 ID로 추적
92
- 6. 자동 감지: 증거 없는 done, 추적 없는 TODO, blocker 방치, 검증 흔적 부재
214
+ ---
93
215
 
94
- ## 시크릿/인코딩 자동 가드
216
+ ## 🧰 Anti-Lazy Work Policy
95
217
 
96
- - `scan secrets`: 9패턴 (AWS/GitHub PAT/GitHub fine-grained/OpenAI/Anthropic/Google/Slack/PEM private key/하드코딩 password).
97
- - `encoding check`: BOM, UTF-16 BOM, NUL, .bat의 chcp 65001 누락, 한글 텍스트의 UTF-8 라운드트립.
218
+ `anti-lazy-work-policy.md`의 6규칙 + `lazy detect`/`verify-claim` 자동 점검:
98
219
 
99
- ## Claude Code 통합
220
+ 1. **증거 없는 완료 금지** — `evidence` 컬럼이 비었거나 plan-link만이면 경고
221
+ 2. **빈 핸드오프 금지** — Completed/In Progress/Next Exact Step 모두 비어 있으면 `insufficient`
222
+ 3. **부분 구현 자기보고** — `incomplete` 표기 + Next Exact Step 1줄
223
+ 4. **검증 기록 누적** — `review-evidence.md`에 typecheck/lint/test 결과
224
+ 5. **TODO 추적** — 새 TODO/FIXME → progress-tracker 동일 ID
225
+ 6. **자동 감지** — 거짓 완료/추적 없는 TODO/blocker 방치/검증 흔적 부재
226
+
227
+ ---
228
+
229
+ ## 🤝 Claude Code 통합
100
230
 
101
231
  설치 시 자동 등록:
102
- - `.claude/commands/handoff.md`, `session-close.md`, `audit.md`, `lazy-detect.md`, `update.md`, `viewwork-ping.md`
232
+ - `.claude/commands/{handoff, session-close, audit, lazy-detect, update}.md`
103
233
  - `.claude/skills/leerness.md` — Claude Code 스킬 정의
104
- - `.claude/settings.local.json` — SessionStart (`update --check`) + Stop (`viewwork emit`) hook
234
+ - `.claude/settings.local.json` — SessionStart hook (`update --check`)
235
+ - `.cursor/rules/leerness.mdc` — Cursor
236
+ - `.github/copilot-instructions.md` — Copilot
237
+
238
+ ---
239
+
240
+ ## 📦 스킬 라이브러리
241
+
242
+ ```bash
243
+ leerness skill list
244
+ leerness skill info <id>
245
+ leerness skill add <id>
246
+ leerness skill learn <id> --doc <url> --command "..." --capability "..."
247
+ leerness skill optimize <id> --before "..." --after "..."
248
+ leerness skill consolidate
249
+ ```
250
+
251
+ 기본 카탈로그: `feature-implementation`, `ai-verified-skill-publisher`, `open-meteo`, `static-site-builder`, `project-roadmap-generator`, `office`, `commerce-api`, `crawling`, `firebase`, `ads-analytics`, `appstore-review`.
105
252
 
106
- ## 스킬 라이브러리
253
+ ---
107
254
 
108
- `leerness skill list` / `leerness skill info <id>` / `leerness skill add <id>`.
255
+ ## 🌐 환경변수
256
+
257
+ | 변수 | 효과 |
258
+ |---|---|
259
+ | `LEERNESS_OFFLINE=1` | npm 호출 스킵 (오프라인) |
260
+ | `LEERNESS_NPM_TOKEN` | release publish용 (있을 때) |
261
+ | `LEERNESS_GITHUB_TOKEN` | gh release용 (있을 때) |
262
+ | **`LEERNESS_OLLAMA_BASE_URL`** | **1.9.22 — orchestrate opt-in 활성화** |
263
+ | `LEERNESS_OLLAMA_MODEL` | 기본 모델 (orchestrate `--model`로 override) |
109
264
 
110
- 기본 카탈로그: `office`, `commerce-api`, `crawling`, `firebase`, `ads-analytics`, `appstore-review`, `ai-verified-skill-publisher`, `feature-implementation`.
265
+ ---
111
266
 
112
- ## E2E
267
+ ## 🔧 자연어 트리거 → 명령 자동 매핑
268
+
269
+ | 사용자 발화 | 자동 실행 |
270
+ |---|---|
271
+ | "회고해줘 / 돌아보자" | `leerness retro` |
272
+ | "최근 N일 회고" | `leerness retro --days N` |
273
+ | "통계 / 누적 지표" | `leerness insights` |
274
+ | "X 관련 자료 / X 시작 전 검토" | `leerness brainstorm "X"` |
275
+ | "매 X마다 Y를 해줘" | `leerness rule add "Y" --trigger every-X` |
276
+
277
+ `AGENTS.md`에 자동 등록 — Claude Code/Cursor가 이를 보고 자연어를 명령으로 변환.
278
+
279
+ ---
280
+
281
+ ## ❓ FAQ
282
+
283
+ **Q. leerness가 내 코드를 변경하나요?**
284
+ A. 사용자 메모리(plan/progress/decisions/architecture/reuse-map 등)는 **항상 보존**. 관리 인스트럭션(AGENTS.md/CLAUDE.md 등)은 머지 + 이전 내용을 preserved 블록으로 보존. 모든 변경 전 `.harness/archive/`에 자동 백업.
285
+
286
+ **Q. 로컬 LLM을 사용하지 않고 싶어요.**
287
+ A. 기본 동작입니다. `LEERNESS_OLLAMA_BASE_URL` 환경변수를 설정하지 않으면 LLM 호출 절대 발생 안 함. `orchestrate` 명령만 거부됩니다 (다른 명령은 LLM 없이 동작).
288
+
289
+ **Q. CI에서 사용 가능?**
290
+ A. 네. `--json` 옵션 (retro/insights/brainstorm/handoff/reuse-map/verify-claim) + `exit code`로 통합. `verify-claim T-XXX --run-tests --json | jq '.verdict.runTests'`.
291
+
292
+ **Q. 다른 워크스페이스 모드 명령은?**
293
+ A. `--all-apps`는 현재 디렉토리 + `_apps/*` (또는 부모의 `_apps/*`)의 모든 leerness 프로젝트를 발견. `--include p1,p2`로 명시도 가능.
294
+
295
+ ---
296
+
297
+ ## 🧪 E2E
113
298
 
114
299
  ```bash
115
- npm test
116
- # = node ./scripts/e2e.js
300
+ npm test # = node ./scripts/e2e.js
117
301
  ```
118
302
 
119
- 임시 디렉토리에서 30+개 시나리오 실측 (B1 in-place upsert 회귀 검증 포함).
303
+ **131/131 시나리오** 통과 (1.9.7~1.9.22 회귀 + 신규 검증).
304
+
305
+ ---
306
+
307
+ ## 📜 변경 이력 (최근)
308
+
309
+ - **1.9.22** — Ollama opt-in 통합 (`orchestrate --agents N`), `handoff --compact`, `llm-bench record`
310
+ - **1.9.21** — `.cfg`/`.ini`/`.env`/`.toml`/`.lock` 메타 파일 verify-claim regex 확장
311
+ - **1.9.20** — Godot/jest/mocha 지원, `verify-code --bench`, file regex 도메인 폴더 자동 인식
312
+ - **1.9.19** — `verify-claim --run-tests` 동적 검증, `--strict-elements` same-file vs diff-file 구분
313
+ - **1.9.18** — `--since`, `--strict-elements`, `depends-on` 그래프, `verify-claim`
314
+ - **1.9.17** — `handoff/reuse-map --all-apps` 워크스페이스 모드
315
+ - **1.9.16** — `retro/insights/brainstorm --json` export
316
+ - **1.9.15** — `retro --all-apps` 워크스페이스 회고
317
+ - ... (전체 CHANGELOG.md 참조)
318
+
319
+ ---
320
+
321
+ ## 🤝 기여
322
+
323
+ - **이슈**: https://github.com/gugu9999gu/leerness/issues
324
+ - **PR**: e2e 통과 + 한국어 주석 + UTF-8 BOM 없음
325
+
326
+ ---
120
327
 
121
328
  ## 라이선스
122
329
 
123
- MIT.
330
+ MIT — © leerness contributors
331
+
332
+ > **AI 에이전트를 잘 다루는 도구가 되도록 설계되었습니다.** 사용자 동의 없이 자동으로 외부 LLM/API를 호출하지 않습니다.
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.22';
9
+ const VERSION = '1.9.24';
10
10
  const MARK = '<!-- leerness:managed -->';
11
11
  const README_START = '<!-- leerness:project-readme:start -->';
12
12
  const README_END = '<!-- leerness:project-readme:end -->';
@@ -1861,6 +1861,131 @@ async function orchestrateCmd(root, goalParts) {
1861
1861
  log(`📜 누적 기록: .harness/orchestrate-log.md`);
1862
1862
  }
1863
1863
 
1864
+ // 1.9.24: leerness deps <capability> — depends-on 그래프 역방향 추적 + 자동 회귀 sweep
1865
+ // 사용 예: leerness deps Character
1866
+ // → rpg-core/Character를 의존하는 모든 capability 식별 (rpg-net/Session, rpg-data/* 등)
1867
+ // → 영향받은 프로젝트의 npm test 자동 일괄 실행
1868
+ // → 회귀 발생 시 어느 프로젝트인지 즉시 보고
1869
+ function depsImpactCmd(root, targetCapability) {
1870
+ root = absRoot(root || process.cwd());
1871
+ if (!targetCapability) { fail('impact <capability> 필요. 예: leerness impact Character'); return process.exit(1); }
1872
+ const paths = _collectWorkspacePaths(root);
1873
+ if (!paths.length) {
1874
+ // --all-apps 자동
1875
+ process.argv.push('--all-apps');
1876
+ }
1877
+ const allPaths = _collectWorkspacePaths(root);
1878
+ if (!allPaths.length) return fail('워크스페이스 프로젝트 없음. _apps/* 또는 --include 사용.');
1879
+
1880
+ // 1) 모든 reuse-map에서 entries + depends-on 엣지 수집
1881
+ const allEntries = []; // { project, entry }
1882
+ const allEdges = []; // { fromProject, fromCap, toCap }
1883
+ for (const p of allPaths) {
1884
+ const entries = _readReuseMap(p);
1885
+ for (const e of entries) {
1886
+ allEntries.push({ project: path.basename(p), projectPath: p, entry: e });
1887
+ for (const dep of e.dependsOn) {
1888
+ allEdges.push({ fromProject: path.basename(p), fromCap: e.capability, toCap: dep });
1889
+ }
1890
+ }
1891
+ }
1892
+
1893
+ // 2) targetCapability를 의존하는 capability 식별 (역방향)
1894
+ const target = String(targetCapability);
1895
+ const targetLower = target.toLowerCase();
1896
+ const directImpact = allEdges.filter(e => e.toCap.toLowerCase() === targetLower);
1897
+ const impactedProjects = new Set(directImpact.map(e => e.fromProject));
1898
+
1899
+ // 2단계 전이: 영향받은 capability를 또 의존하는 것들 (2-hop)
1900
+ const transitiveImpact = [];
1901
+ for (const e1 of directImpact) {
1902
+ for (const e2 of allEdges) {
1903
+ if (e2.toCap.toLowerCase() === e1.fromCap.toLowerCase()) {
1904
+ transitiveImpact.push({ via: e1.fromCap, ...e2 });
1905
+ impactedProjects.add(e2.fromProject);
1906
+ }
1907
+ }
1908
+ }
1909
+
1910
+ // target capability 자체가 어디 등록됐는지
1911
+ const definedAt = allEntries.filter(e => e.entry.capability.toLowerCase() === targetLower);
1912
+
1913
+ if (has('--json')) {
1914
+ log(JSON.stringify({
1915
+ target,
1916
+ definedAt: definedAt.map(d => ({ project: d.project, element: d.entry.element })),
1917
+ directImpact,
1918
+ transitiveImpact,
1919
+ impactedProjects: Array.from(impactedProjects)
1920
+ }, null, 2));
1921
+ return;
1922
+ }
1923
+
1924
+ log(`# leerness impact "${target}" (1.9.24)`);
1925
+ log('');
1926
+ log(`## 정의 위치`);
1927
+ if (!definedAt.length) {
1928
+ log(` ⚠ "${target}" capability가 reuse-map에 등록되지 않음 — 영향 추적 불가`);
1929
+ return process.exit(1);
1930
+ }
1931
+ for (const d of definedAt) log(` - ${d.project}: ${d.entry.element}`);
1932
+
1933
+ log('');
1934
+ log(`## 직접 의존 (1-hop, ${directImpact.length}건)`);
1935
+ if (!directImpact.length) log(` (없음) — 단독 capability. 변경 안전.`);
1936
+ for (const e of directImpact) log(` - ${e.fromProject}/${e.fromCap}`);
1937
+
1938
+ if (transitiveImpact.length) {
1939
+ log('');
1940
+ log(`## 전이 의존 (2-hop, ${transitiveImpact.length}건)`);
1941
+ for (const e of transitiveImpact) log(` - ${e.fromProject}/${e.fromCap} (경유: ${e.via})`);
1942
+ }
1943
+
1944
+ log('');
1945
+ log(`## 영향받는 프로젝트 (${impactedProjects.size}개)`);
1946
+ for (const p of impactedProjects) log(` - ${p}`);
1947
+
1948
+ // 3) --run-tests 옵션이면 영향받은 프로젝트의 npm test 일괄 실행
1949
+ if (has('--run-tests')) {
1950
+ log('');
1951
+ log(`## 🚦 자동 회귀 sweep (--run-tests)`);
1952
+ const results = [];
1953
+ for (const projName of impactedProjects) {
1954
+ const projPath = allPaths.find(p => path.basename(p) === projName);
1955
+ if (!projPath) continue;
1956
+ const pkgPath = path.join(projPath, 'package.json');
1957
+ if (!exists(pkgPath)) { log(` ⚠ ${projName}: package.json 없음 — skip`); continue; }
1958
+ let pkg = null;
1959
+ try { pkg = JSON.parse(read(pkgPath)); } catch {}
1960
+ if (!pkg?.scripts?.test) { log(` ⚠ ${projName}: scripts.test 없음 — skip`); continue; }
1961
+ const t0 = Date.now();
1962
+ const r = cp.spawnSync('npm test', [], { cwd: projPath, encoding: 'utf8', shell: true, timeout: 5 * 60 * 1000 });
1963
+ const elapsed = Date.now() - t0;
1964
+ const out = (r.stdout || '') + (r.stderr || '');
1965
+ const m = out.match(/(\d+)\s*\/\s*(\d+)\s*(?:passed|통과|pass|passing)/i);
1966
+ const passed = r.status === 0;
1967
+ results.push({ project: projName, passed, exit: r.status, elapsed, parsed: m ? { num: parseInt(m[1], 10), denom: parseInt(m[2], 10) } : null });
1968
+ const tag = passed ? '✓' : '✗';
1969
+ const ratio = m ? ` (${m[1]}/${m[2]})` : '';
1970
+ log(` ${tag} ${projName}: exit=${r.status}${ratio} ${elapsed}ms`);
1971
+ }
1972
+ log('');
1973
+ const pass = results.filter(r => r.passed).length;
1974
+ const fail = results.length - pass;
1975
+ log(`## 종합`);
1976
+ log(` - 영향받는 프로젝트 ${impactedProjects.size}개 중 ${pass}개 통과, ${fail}개 실패`);
1977
+ if (fail > 0) {
1978
+ log(` ⚠ ${target} 변경이 ${fail}개 프로젝트에 회귀 발생 가능 — 해당 프로젝트 testing 우선`);
1979
+ return process.exit(1);
1980
+ } else {
1981
+ log(` ✓ 모든 영향받는 프로젝트 회귀 없음 — ${target} 변경 안전`);
1982
+ }
1983
+ } else {
1984
+ log('');
1985
+ log(` 💡 \`--run-tests\` 옵션으로 영향받는 ${impactedProjects.size}개 프로젝트 npm test 자동 일괄 실행 가능`);
1986
+ }
1987
+ }
1988
+
1864
1989
  // 1.9.22 후보 4: llm-bench record + retro 통합
1865
1990
  function llmBenchRecordCmd(root) {
1866
1991
  root = absRoot(root || process.cwd());
@@ -3877,7 +4002,7 @@ function viewworkInstall(root) {
3877
4002
  }
3878
4003
 
3879
4004
  function help() {
3880
- 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 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 viewwork install [path]\n leerness viewwork emit [path] [--action a] [--note n] [--agent x] [--tool t]\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
4005
+ 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 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 viewwork install [path]\n leerness viewwork emit [path] [--action a] [--note n] [--agent x] [--tool t]\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
3881
4006
  leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # 회고 (1.9.13~1.9.16)
3882
4007
  leerness insights [path] [--all-apps] [--include p1,p2] [--json] # 누적 통계 (1.9.13~1.9.16)
3883
4008
  leerness brainstorm "<주제>" [--all-apps] [--include p1,p2] [--json] # 브레인스토밍 (1.9.13~1.9.16)
@@ -3915,6 +4040,7 @@ async function main() {
3915
4040
  if (cmd === 'verify-claim') return verifyClaimCmd(arg('--path', process.cwd()), args[1]);
3916
4041
  if (cmd === 'orchestrate') return await orchestrateCmd(arg('--path', process.cwd()), args.slice(1).filter(x => !x.startsWith('-')));
3917
4042
  if (cmd === 'llm-bench' && args[1] === 'record') return llmBenchRecordCmd(arg('--path', process.cwd()));
4043
+ if (cmd === 'deps') return depsImpactCmd(arg('--path', process.cwd()), args[1]);
3918
4044
  if (cmd === 'session' && args[1] === 'close') { const r = sessionClose(args[2] || process.cwd()); viewworkEmit(args[2] || process.cwd(), { action: 'task', tool: 'session-close', note: 'session close' }); return r; }
3919
4045
  if (cmd === 'viewwork' && args[1] === 'install') return viewworkInstall(args[2] || process.cwd());
3920
4046
  if (cmd === 'viewwork' && args[1] === 'emit') return viewworkEmit(args[2] || process.cwd(), { action: arg('--action','task'), note: arg('--note',''), agent: arg('--agent','leerness'), tool: arg('--tool','leerness-cli') });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.22",
3
+ "version": "1.9.24",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",
@@ -28,6 +28,8 @@
28
28
  "license": "MIT",
29
29
  "author": "leerness contributors",
30
30
  "type": "commonjs",
31
+ "main": "bin/harness.js",
32
+ "preferGlobal": true,
31
33
  "engines": {
32
34
  "node": ">=18"
33
35
  },