leerness 1.9.174 → 1.9.176
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 +122 -0
- package/README.md +3 -3
- package/bin/harness.js +352 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,127 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.176 — 2026-05-21
|
|
4
|
+
|
|
5
|
+
**⚠ 사용자 명시: `leerness review-request` — 사용자 요구를 무조건 구현 전 사전 검토.**
|
|
6
|
+
|
|
7
|
+
사용자 명시: *"leerness가 적용된 프로젝트는 사용자의 요구를 무조건적으로 구현하기 전에, 충돌이 발생할 수 있는 부분이나 제작하고자 하는 기능 등을 구현하거나 설계할 때 더 효율적인 단계가 있는지 검토해보고 제시할 수도 있도록 설계"*.
|
|
8
|
+
|
|
9
|
+
### `leerness review-request "<request>"` — 9개 신호 분석
|
|
10
|
+
| 신호 | 데이터 소스 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| **estimatedType** | route 키워드 매핑 (feature/bugfix/refactor/research/planning/release/consistency) |
|
|
13
|
+
| **conflicts** | lessons 실패 패턴 + 진행 중 task + taskLogFails |
|
|
14
|
+
| **reuseCandidates** | skills 매칭 + reuse-map 키워드 검색 |
|
|
15
|
+
| **lessonsRecall** | 과거 decisions + 관련 lessons |
|
|
16
|
+
| **planConflicts** | 진행 중 milestone (plan.md) |
|
|
17
|
+
| **featureConflicts** | feature_graph.md 영역 겹침 |
|
|
18
|
+
| **recommendedSteps** | 작업 유형별 3-4단계 권장 흐름 |
|
|
19
|
+
| **efficiencyHints** | 재사용/sub-agent/skill 활용 제안 |
|
|
20
|
+
| **proceed** | true (안전) / false (사용자 확인 필요) |
|
|
21
|
+
|
|
22
|
+
### 사용 예
|
|
23
|
+
```bash
|
|
24
|
+
$ leerness review-request "OAuth 로그인 구현해줘"
|
|
25
|
+
# leerness review-request (1.9.176 사전 검토)
|
|
26
|
+
요청: "OAuth 로그인 구현해줘"
|
|
27
|
+
추정 작업 유형: feature
|
|
28
|
+
|
|
29
|
+
## 💡 효율 제안
|
|
30
|
+
👥 leerness agents recommend feature — 작업 유형별 sub-agent 매핑 활용 가능
|
|
31
|
+
|
|
32
|
+
## 📍 권장 단계 (feature)
|
|
33
|
+
1) leerness reuse find "<핵심 capability>" — 중복 구현 사전 차단
|
|
34
|
+
2) leerness plan add "<milestone>" — 진행 추적
|
|
35
|
+
3) leerness contract verify SPEC.md src/<mod>.js — 사양 ↔ 구현 일치 검증
|
|
36
|
+
4) verify-claim --run-tests 로 evidence 의무화
|
|
37
|
+
|
|
38
|
+
## ▶ 진행 권장: ✓ 진행 안전
|
|
39
|
+
사유: 안전 — 충돌 신호 < 3 + plan 충돌 0
|
|
40
|
+
분석 소요: 938ms
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 통합 — 3 진입점
|
|
44
|
+
- **CLI**: `leerness review-request "<request>"` (또는 단축 `review-req`)
|
|
45
|
+
- **REPL**: `:review "<request>"` slash (1.9.175 흐름 연장)
|
|
46
|
+
- **MCP**: `leerness_review_request` (외부 AI 직접 호출 — **54번째 도구**)
|
|
47
|
+
|
|
48
|
+
### AGENTS.md / CLAUDE.md 강제 안내
|
|
49
|
+
```markdown
|
|
50
|
+
## ⚠ 사용자 요청 사전 검토 의무 (1.9.176 — 사용자 명시)
|
|
51
|
+
**사용자가 "X 구현해줘 / X 만들어줘 / X 추가해줘" 같은 요청을 줬을 때 무조건 즉시 구현하지 말 것.**
|
|
52
|
+
먼저 `leerness review-request "<요청>"` 호출 → 분석 결과 표시 → 사용자 확인 후 구현.
|
|
53
|
+
"그냥 바로 해줘 / review 건너뛰어줘" 명시 옵트아웃 시에만 review 생략.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Verified
|
|
57
|
+
- e2e 217/217 baseline 유지
|
|
58
|
+
- stress-v121: **23/23** (함수 정의 4 + router/help 2 + 실 동작 6 + REPL/MCP 3 + metadata 2 + 누적 회귀 6)
|
|
59
|
+
- 작업 유형 추정 정확도: feature/bugfix/refactor/research 4종 100% 매칭
|
|
60
|
+
- VERSION = 1.9.176 · MCP **54 도구** · autonomous-rounds = 106 · main 자동 push 37 라운드 연속
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 1.9.175 — 2026-05-21
|
|
65
|
+
|
|
66
|
+
**🌉 REPL Bridge Slash 3종 — `:web` / `:pc` / `:lsp` 즉시 호출.**
|
|
67
|
+
|
|
68
|
+
자율 모드 105 라운드. 1.9.165~167 Bridge 3종이 1.9.168 MCP로 외부 AI 직접 호출 가능. **1.9.175: REPL 안에서도 직접 호출 가능** — 사용자 + AI 가 같은 REPL 세션에서 코드 분석/웹/PC 자동화 즉시 사용.
|
|
69
|
+
|
|
70
|
+
### 사용 예시
|
|
71
|
+
```
|
|
72
|
+
agent[claude/actor/▶]> :lsp symbols src/api.ts
|
|
73
|
+
→ leerness lsp symbols src/api.ts
|
|
74
|
+
# leerness lsp symbols (1.9.173 다국어)
|
|
75
|
+
file: src/api.ts · lang: javascript
|
|
76
|
+
mode: typescript-compiler · 24 symbols · 12ms
|
|
77
|
+
3:function parseRequest
|
|
78
|
+
8:class User
|
|
79
|
+
...
|
|
80
|
+
✓ :lsp symbols 완료 (132ms)
|
|
81
|
+
|
|
82
|
+
agent[claude/actor/▶]> :web screenshot https://example.com --out shot.png
|
|
83
|
+
→ leerness web screenshot https://example.com --out shot.png
|
|
84
|
+
✓ screenshot saved: shot.png · 1842ms
|
|
85
|
+
✓ :web screenshot 완료 (2014ms)
|
|
86
|
+
|
|
87
|
+
agent[claude/actor/▶]> :pc click 800 400
|
|
88
|
+
⚠ :pc click 은 permissions=full 필요 (현재: basic)
|
|
89
|
+
:permissions full 로 즉시 변경 가능 (1.9.174)
|
|
90
|
+
|
|
91
|
+
agent[claude/actor/▶]> :permissions full
|
|
92
|
+
✓ 권한 모드 변경: full
|
|
93
|
+
agent[claude/actor/▶]> :pc click 800 400
|
|
94
|
+
✓ click (800, 400) — 23ms
|
|
95
|
+
✓ :pc click 완료 (35ms)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 통합 흐름 — 사용자 명시 4 라운드 누적
|
|
99
|
+
| 라운드 | 강화 |
|
|
100
|
+
|---|---|
|
|
101
|
+
| 1.9.170 | Tab/Shift+Tab cycle + 실시간 스트리밍 |
|
|
102
|
+
| 1.9.172 | 스트리밍 spinner + tool_use + diff 색깔 |
|
|
103
|
+
| 1.9.174 | install 권한 prompt 제거 + REPL `:permissions` 변경 |
|
|
104
|
+
| **1.9.175** | **REPL `:web` / `:pc` / `:lsp` slash 3종 즉시 호출** |
|
|
105
|
+
|
|
106
|
+
→ **REPL 안에서 leerness 의 모든 capability 사용 가능** (AI 대화 + 코드 분석 + 웹 + PC + 권한 변경, 한 세션).
|
|
107
|
+
|
|
108
|
+
### 위험 sub 사전 권한 검사
|
|
109
|
+
`:pc click/type/screenshot` 시 `permissions !== 'full'` 이면 즉시 경고 + 변경 안내 (1.9.174 `:permissions full` 연동).
|
|
110
|
+
|
|
111
|
+
### 구현
|
|
112
|
+
- `op === 'web' || op === 'pc' || op === 'lsp'` 핸들러 추가 (Memory slash 분기 직전)
|
|
113
|
+
- `subParts = rest.length ? rest : ['check']` (인자 없으면 check 기본)
|
|
114
|
+
- `runCommandSafe(process.execPath, [__filename, ...cliArgs, '--path', root], ...)` 통합 호출
|
|
115
|
+
- observability: `kind: 'agent_repl_slash'`, `label: 'repl-<op>'`
|
|
116
|
+
- stdout 50줄 까지 표시 (Memory slash 30줄보다 확장 — symbol/diff 출력 용도)
|
|
117
|
+
|
|
118
|
+
### Verified
|
|
119
|
+
- e2e 217/217 baseline 유지
|
|
120
|
+
- stress-v120: **17/17** (slash 핸들러 4 + :pc 권한 사전 검사 2 + :help/환영 5 + 누적 회귀 6)
|
|
121
|
+
- VERSION = 1.9.175 / autonomous-rounds = 105 / main 자동 push 36 라운드 연속
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
3
125
|
## 1.9.174 — 2026-05-21
|
|
4
126
|
|
|
5
127
|
**🔐 사용자 명시 — install 권한 prompt 제거 + REPL `:permissions` 즉시 변경.**
|
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,9 +12,9 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
15
|
+
║ v1.9.176 AI Agent Reliability Harness + Sandbox ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · sandbox · drift ║
|
|
17
|
-
║
|
|
17
|
+
║ ⚠ review-request — 무조건 구현 전 충돌/효율 사전 검토 ║
|
|
18
18
|
╚══════════════════════════════════════════════════════════════╝
|
|
19
19
|
```
|
|
20
20
|
|
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.176';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -9845,7 +9845,8 @@ function mcpServeCmd(root) {
|
|
|
9845
9845
|
{ name: 'leerness_provider_remove', description: '1.9.159 — Provider Registry 에서 사용자 정의 provider 제거. 인자: { id (required), path? }. 빌트인 5종 id 는 제거 불가 (override 만 제거 가능). 🎉 MCP 50 도구 마일스톤 — Provider Registry CRUD MCP 완성 (list/add/remove)', inputSchema: { type: 'object', properties: { id: { type: 'string' }, path: { type: 'string' } }, required: ['id'] } },
|
|
9846
9846
|
{ name: 'leerness_web', description: '1.9.168 — Web Bridge (1.9.165 playwright opt-in). sub: check (설치 + permissions.browser 확인) | screenshot (URL → PNG) | extract (URL + CSS selector → DOM 텍스트). 외부 AI가 leerness 의 웹 자동화 능력을 직접 호출. playwright 미설치 시 친절 안내 (graceful). 인자: { sub (required), url?, out?, selector?, path? }', inputSchema: { type: 'object', properties: { sub: { type: 'string', enum: ['check', 'screenshot', 'extract'] }, url: { type: 'string' }, out: { type: 'string' }, selector: { type: 'string' }, path: { type: 'string' } }, required: ['sub'] } },
|
|
9847
9847
|
{ name: 'leerness_pc', description: '1.9.168 — PC Bridge (1.9.166 robotjs/nut-tree opt-in). sub: check (설치 + permissions.mouse/keyboard) | click (x,y) | type (text) | screenshot (out). ⚠ full permissions 권장 (mouse/keyboard 접근). 외부 AI가 데스크탑 자동화 능력을 직접 호출. 인자: { sub (required), x?, y?, text?, out?, path? }', inputSchema: { type: 'object', properties: { sub: { type: 'string', enum: ['check', 'click', 'type', 'screenshot'] }, x: { type: 'number' }, y: { type: 'number' }, text: { type: 'string' }, out: { type: 'string' }, path: { type: 'string' } }, required: ['sub'] } },
|
|
9848
|
-
{ name: 'leerness_lsp', description: '1.9.168 — LSP Bridge (1.9.167 typescript opt-in + regex fallback). sub: check (설치 여부) | symbols (file → function/class/interface/type/enum 목록) | references (name + in 디렉토리 → 호출 위치). 외부 AI가 코드 인텔리전스를 직접 호출 (의존성 0 fallback 동작). 🎉 MCP 53 도구 마일스톤. 인자: { sub (required), file?, name?, in?, path? }', inputSchema: { type: 'object', properties: { sub: { type: 'string', enum: ['check', 'symbols', 'references'] }, file: { type: 'string' }, name: { type: 'string' }, in: { type: 'string' }, path: { type: 'string' } }, required: ['sub'] } }
|
|
9848
|
+
{ name: 'leerness_lsp', description: '1.9.168 — LSP Bridge (1.9.167 typescript opt-in + regex fallback). sub: check (설치 여부) | symbols (file → function/class/interface/type/enum 목록) | references (name + in 디렉토리 → 호출 위치). 외부 AI가 코드 인텔리전스를 직접 호출 (의존성 0 fallback 동작). 🎉 MCP 53 도구 마일스톤. 인자: { sub (required), file?, name?, in?, path? }', inputSchema: { type: 'object', properties: { sub: { type: 'string', enum: ['check', 'symbols', 'references'] }, file: { type: 'string' }, name: { type: 'string' }, in: { type: 'string' }, path: { type: 'string' } }, required: ['sub'] } },
|
|
9849
|
+
{ name: 'leerness_review_request', description: '1.9.176 — 사용자 요청 사전 검토 (사용자 명시 요청). AI 에이전트가 사용자 요구를 **무조건 구현 전**에 호출. 분석: 1) estimatedType (route 추정), 2) conflicts (lesson 실패/진행중 task), 3) reuseCandidates (skill/reuse-map 매칭), 4) lessonsRecall (과거 결정), 5) planConflicts (진행중 milestone), 6) featureConflicts (feature graph 영역 겹침), 7) recommendedSteps (작업 유형별 3-5 단계), 8) efficiencyHints, 9) proceed (true/false). 사용자 결정 도움. 인자: { request (required), path? }', inputSchema: { type: 'object', properties: { request: { type: 'string' }, path: { type: 'string' } }, required: ['request'] } }
|
|
9849
9850
|
];
|
|
9850
9851
|
|
|
9851
9852
|
function send(obj) {
|
|
@@ -9973,6 +9974,10 @@ function mcpServeCmd(root) {
|
|
|
9973
9974
|
if (args.name) cliArgs.splice(2, 0, String(args.name));
|
|
9974
9975
|
if (args.in) cliArgs.push('--in', String(args.in));
|
|
9975
9976
|
break;
|
|
9977
|
+
case 'leerness_review_request':
|
|
9978
|
+
// 1.9.176: 사용자 요청 사전 검토 (사용자 명시 요청)
|
|
9979
|
+
cliArgs = ['review-request', String(args.request || ''), '--path', targetPath, '--json'];
|
|
9980
|
+
break;
|
|
9976
9981
|
default:
|
|
9977
9982
|
return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
|
|
9978
9983
|
}
|
|
@@ -11006,6 +11011,8 @@ async function _agentRepl(root, opts) {
|
|
|
11006
11011
|
log(C.dim(' Memory Slash (1.9.161): :lessons | :brainstorm <topic> | :tasks | :plan'));
|
|
11007
11012
|
log(C.dim(' 🆕 1.9.170 — Tab=provider cycle, Shift+Tab=model cycle, :stream on|off (실시간 출력)'));
|
|
11008
11013
|
log(C.dim(' 🆕 1.9.174 — :permissions [basic|extended|full] 로 즉시 권한 변경 (default: basic 안전)'));
|
|
11014
|
+
log(C.dim(' 🆕 1.9.175 — :web / :pc / :lsp 으로 Bridge 3종 REPL 안에서 즉시 호출 (코드 분석/웹/PC)'));
|
|
11015
|
+
log(C.dim(' 🆕 1.9.176 — :review "<요청>" 으로 사용자 요청 사전 검토 (충돌/재사용/효율/권장 단계)'));
|
|
11009
11016
|
log(C.dim(` 현재 — provider=${state.provider} model=${state.model || '(기본)'} role=${state.role} permissions=${_readPermissions(root).mode}`));
|
|
11010
11017
|
// 1.9.155: REPL 진입 시 handoff 컨텍스트 자동 노출 (UX 개선 — 사용자가 매번 :handoff 안 해도 컨텍스트 인지)
|
|
11011
11018
|
try {
|
|
@@ -11126,6 +11133,19 @@ async function _agentRepl(root, opts) {
|
|
|
11126
11133
|
log(' :brainstorm <topic> — leerness brainstorm "topic" (관련 컨텍스트 회수)');
|
|
11127
11134
|
log(' :tasks — leerness task list (현재 task 상태)');
|
|
11128
11135
|
log(' :plan — leerness plan show (현재 milestone)');
|
|
11136
|
+
log(C.bold('\n 🆕 Review Slash (1.9.176) — 사용자 요청 사전 검토:'));
|
|
11137
|
+
log(' :review "<request>" — 충돌/재사용/효율/권장 단계 분석 후 구현 권장');
|
|
11138
|
+
log(C.bold('\n 🆕 Bridge Slash (1.9.175) — REPL 안에서 즉시 Bridge 호출:'));
|
|
11139
|
+
log(' :web check — playwright 설치 확인 (opt-in)');
|
|
11140
|
+
log(' :web screenshot <url> [--out f.png] — URL → PNG');
|
|
11141
|
+
log(' :web extract <url> --selector "css" — DOM 텍스트 추출');
|
|
11142
|
+
log(' :pc check — robotjs/nut-tree 설치 확인 (⚠ full 권한)');
|
|
11143
|
+
log(' :pc click <x> <y> — 좌표 클릭');
|
|
11144
|
+
log(' :pc type "<text>" — 키보드 입력');
|
|
11145
|
+
log(' :pc screenshot --out shot.png — PC 화면 캡처');
|
|
11146
|
+
log(' :lsp check — typescript 설치 + 다국어 fallback');
|
|
11147
|
+
log(' :lsp symbols <file> — 심볼 추출 (JS/TS/Py/Go/Rust/Java)');
|
|
11148
|
+
log(' :lsp references <name> [--in <dir>] — 심볼 참조 검색');
|
|
11129
11149
|
return false;
|
|
11130
11150
|
}
|
|
11131
11151
|
if (op === 'model') {
|
|
@@ -11272,6 +11292,60 @@ async function _agentRepl(root, opts) {
|
|
|
11272
11292
|
log('');
|
|
11273
11293
|
return false;
|
|
11274
11294
|
}
|
|
11295
|
+
// 1.9.175: Bridge 3종 slash — :web / :pc / :lsp (REPL 안에서 즉시 Bridge 호출)
|
|
11296
|
+
// 사용 예:
|
|
11297
|
+
// :web check — playwright 설치 확인
|
|
11298
|
+
// :web screenshot https://example.com — URL → PNG
|
|
11299
|
+
// :pc check — robotjs 설치 확인
|
|
11300
|
+
// :pc click 800 400 — 좌표 클릭 (full 권한 필요)
|
|
11301
|
+
// :lsp symbols src/api.ts — 파일 심볼 추출
|
|
11302
|
+
// :lsp references myFunc --in src — 심볼 참조 검색
|
|
11303
|
+
if (op === 'web' || op === 'pc' || op === 'lsp') {
|
|
11304
|
+
const subParts = rest.length ? rest : ['check']; // 인자 없으면 check 기본
|
|
11305
|
+
const cliArgs = [op, ...subParts];
|
|
11306
|
+
// permissions 사전 안내 (full 모드 필요한 sub 만)
|
|
11307
|
+
if (op === 'pc' && ['click', 'type', 'screenshot'].includes(subParts[0])) {
|
|
11308
|
+
const p = _readPermissions(root);
|
|
11309
|
+
if (p.mode !== 'full') {
|
|
11310
|
+
log(C.yel(` ⚠ :pc ${subParts[0]} 은 permissions=full 필요 (현재: ${p.mode})`));
|
|
11311
|
+
log(C.dim(` :permissions full 로 즉시 변경 가능 (1.9.174)`));
|
|
11312
|
+
return false;
|
|
11313
|
+
}
|
|
11314
|
+
}
|
|
11315
|
+
log(C.dim(` → leerness ${cliArgs.join(' ')}`));
|
|
11316
|
+
const t0 = Date.now();
|
|
11317
|
+
const r = runCommandSafe(process.execPath, [__filename, ...cliArgs, '--path', root], {
|
|
11318
|
+
cwd: root, root, timeout: 60000, kind: 'agent_repl_slash', label: `repl-${op}`,
|
|
11319
|
+
env: { LEERNESS_NO_BANNER: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' }
|
|
11320
|
+
});
|
|
11321
|
+
const dt = Date.now() - t0;
|
|
11322
|
+
if (r.stdout) log(r.stdout.trim().split('\n').slice(0, 50).join('\n'));
|
|
11323
|
+
if (r.status === 0) log(C.green(` ✓ :${op} ${subParts[0] || ''} 완료 (${dt}ms)`));
|
|
11324
|
+
else log(C.yel(` ⚠ :${op} 실패 (exit ${r.status}, ${dt}ms)`));
|
|
11325
|
+
return false;
|
|
11326
|
+
}
|
|
11327
|
+
|
|
11328
|
+
// 1.9.176: :review <request> — 사용자 요청 사전 검토 slash (사용자 명시)
|
|
11329
|
+
// "이거 구현해줘" 같은 요청을 받으면 AI 가 먼저 :review 호출 → 충돌/재사용/효율 분석.
|
|
11330
|
+
if (op === 'review') {
|
|
11331
|
+
const reqText = rest.join(' ').trim();
|
|
11332
|
+
if (!reqText) {
|
|
11333
|
+
log(C.yel(` ⚠ :review 는 요청 텍스트 필요 — 예: :review "OAuth 로그인 추가"`));
|
|
11334
|
+
return false;
|
|
11335
|
+
}
|
|
11336
|
+
log(C.dim(` → leerness review-request "${reqText.slice(0, 60)}${reqText.length > 60 ? '…' : ''}"`));
|
|
11337
|
+
const t0 = Date.now();
|
|
11338
|
+
const r = runCommandSafe(process.execPath, [__filename, 'review-request', reqText, '--path', root], {
|
|
11339
|
+
cwd: root, root, timeout: 30000, kind: 'agent_repl_slash', label: 'repl-review',
|
|
11340
|
+
env: { LEERNESS_NO_BANNER: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' }
|
|
11341
|
+
});
|
|
11342
|
+
const dt = Date.now() - t0;
|
|
11343
|
+
if (r.stdout) log(r.stdout.trim().split('\n').slice(0, 60).join('\n'));
|
|
11344
|
+
if (r.status === 0) log(C.green(` ✓ :review 완료 (${dt}ms)`));
|
|
11345
|
+
else log(C.yel(` ⚠ :review 실패 (exit ${r.status}, ${dt}ms)`));
|
|
11346
|
+
return false;
|
|
11347
|
+
}
|
|
11348
|
+
|
|
11275
11349
|
// 1.9.150: leerness 내부 명령 slash-commands — :verify / :audit / :handoff / :health
|
|
11276
11350
|
// 1.9.161: Memory Surface 조회 slash 추가 — :lessons / :brainstorm / :tasks / :plan
|
|
11277
11351
|
if (op === 'verify' || op === 'audit' || op === 'handoff' || op === 'health'
|
|
@@ -12780,6 +12854,274 @@ function lspCmd(root, sub, ...args) {
|
|
|
12780
12854
|
fail(`알 수 없는 sub: ${sub} (check / symbols / references)`);
|
|
12781
12855
|
}
|
|
12782
12856
|
|
|
12857
|
+
// 1.9.176: 사용자 요청 사전 검토 (사용자 명시 요청)
|
|
12858
|
+
// AI 에이전트가 사용자 요구를 **무조건 구현하기 전**에 먼저:
|
|
12859
|
+
// 1) 충돌 위험 (같은 키워드의 과거 실패/lessons)
|
|
12860
|
+
// 2) 기존 자원 재사용 후보 (reuse-map / skills)
|
|
12861
|
+
// 3) 더 효율적인 단계 제안 (route + plan)
|
|
12862
|
+
// 4) 권장 단계 리스트 (작업 유형별)
|
|
12863
|
+
// 를 분석하여 사용자에게 제시. 사용자 결정 후 구현 진행.
|
|
12864
|
+
//
|
|
12865
|
+
// 사용 예:
|
|
12866
|
+
// leerness review-request "OAuth 로그인 구현해줘"
|
|
12867
|
+
// leerness review-request "..." --json # MCP/외부 AI 통합
|
|
12868
|
+
//
|
|
12869
|
+
// REPL: :review <request> (1.9.175 slash 패턴)
|
|
12870
|
+
// MCP : leerness_review_request (외부 AI 직접 호출)
|
|
12871
|
+
function reviewRequestCmd(root, request) {
|
|
12872
|
+
root = absRoot(root || process.cwd());
|
|
12873
|
+
if (!request || !String(request).trim()) {
|
|
12874
|
+
return fail('leerness review-request "<request>" — 사용자 요청 텍스트 필요');
|
|
12875
|
+
}
|
|
12876
|
+
const t0 = Date.now();
|
|
12877
|
+
const text = String(request).trim();
|
|
12878
|
+
|
|
12879
|
+
// 1) 작업 유형 추정 (route 기반 키워드 매핑)
|
|
12880
|
+
const lower = text.toLowerCase();
|
|
12881
|
+
const routeKw = {
|
|
12882
|
+
bugfix: ['버그', '오류', '에러', '수정', '고쳐', '실패', 'fix', 'bug', 'error'],
|
|
12883
|
+
refactor: ['리팩토', '재구성', '정리', '개선', 'refactor', 'cleanup'],
|
|
12884
|
+
feature: ['추가', '구현', '만들', '새', '기능', 'add', 'implement', 'feature', 'create', 'new'],
|
|
12885
|
+
research: ['조사', '분석', '비교', '검토', '연구', 'research', 'analyze', 'compare', 'investigate'],
|
|
12886
|
+
planning: ['계획', '설계', '로드맵', 'plan', 'design', 'architecture', 'roadmap'],
|
|
12887
|
+
release: ['배포', '릴리즈', '버전', 'release', 'deploy', 'publish'],
|
|
12888
|
+
consistency: ['일관성', '통합', '동기화', '맞춰', 'consistency', 'sync', 'align']
|
|
12889
|
+
};
|
|
12890
|
+
let estimatedType = 'feature'; // default
|
|
12891
|
+
let maxScore = 0;
|
|
12892
|
+
for (const [type, kws] of Object.entries(routeKw)) {
|
|
12893
|
+
const score = kws.filter(k => lower.includes(k)).length;
|
|
12894
|
+
if (score > maxScore) { maxScore = score; estimatedType = type; }
|
|
12895
|
+
}
|
|
12896
|
+
|
|
12897
|
+
// 2) 기존 자원 회수 — brainstorm spawn (모든 surface 통합 회수)
|
|
12898
|
+
const conflictHints = []; // ⚠ 같은 키워드 + 실패/오류 패턴
|
|
12899
|
+
const reuseCandidates = []; // 🔁 기존 skill / reuse-map / decision 후보
|
|
12900
|
+
const lessonsRecall = []; // 🧠 과거 lesson
|
|
12901
|
+
const planConflicts = []; // 📋 진행 중 milestone과 충돌 가능
|
|
12902
|
+
|
|
12903
|
+
// brainstorm 호출 (1.9.13~) — JSON 결과 회수
|
|
12904
|
+
try {
|
|
12905
|
+
const r = cp.spawnSync(process.execPath, [__filename, 'brainstorm', text, '--path', root, '--json'], {
|
|
12906
|
+
encoding: 'utf8', timeout: 12000,
|
|
12907
|
+
env: { ...process.env, LEERNESS_NO_BANNER: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' }
|
|
12908
|
+
});
|
|
12909
|
+
if (r.stdout) {
|
|
12910
|
+
const j = JSON.parse(r.stdout);
|
|
12911
|
+
const hits = j.hits || {};
|
|
12912
|
+
// decisions — 과거 결정 후보
|
|
12913
|
+
(hits.decisions || []).slice(0, 5).forEach(d => {
|
|
12914
|
+
lessonsRecall.push({ kind: 'decision', title: d.title, line: d.line, preview: (d.preview || '').slice(0, 100) });
|
|
12915
|
+
});
|
|
12916
|
+
// lessons — 과거 교훈 (특히 실패 키워드)
|
|
12917
|
+
(hits.lessons || []).slice(0, 5).forEach(l => {
|
|
12918
|
+
const preview = (l.text || l.preview || '').slice(0, 100);
|
|
12919
|
+
const isFailure = /실패|오류|에러|fail|error|bug|문제|warning/i.test(preview);
|
|
12920
|
+
if (isFailure) {
|
|
12921
|
+
conflictHints.push({ kind: 'lesson-failure', preview, tags: l.tags });
|
|
12922
|
+
} else {
|
|
12923
|
+
lessonsRecall.push({ kind: 'lesson', preview, tags: l.tags });
|
|
12924
|
+
}
|
|
12925
|
+
});
|
|
12926
|
+
// skills — 기존 skill 후보
|
|
12927
|
+
(hits.skills || []).slice(0, 3).forEach(s => {
|
|
12928
|
+
reuseCandidates.push({ kind: 'skill', id: s.id, displayNameKo: s.displayNameKo, capabilities: s.capabilities });
|
|
12929
|
+
});
|
|
12930
|
+
// tasks — 진행 중 task 충돌
|
|
12931
|
+
(hits.tasks || []).slice(0, 3).forEach(tsk => {
|
|
12932
|
+
if (tsk.status && /in-progress|진행/.test(String(tsk.status))) {
|
|
12933
|
+
conflictHints.push({ kind: 'task-in-progress', id: tsk.id, title: tsk.title });
|
|
12934
|
+
}
|
|
12935
|
+
});
|
|
12936
|
+
// plan milestones — 진행 중 milestone
|
|
12937
|
+
(hits.planMilestones || []).slice(0, 3).forEach(m => {
|
|
12938
|
+
if (m.status && /in-progress|진행/.test(String(m.status))) {
|
|
12939
|
+
planConflicts.push({ kind: 'milestone-in-progress', id: m.id, title: m.title });
|
|
12940
|
+
}
|
|
12941
|
+
});
|
|
12942
|
+
// taskLogFails — 과거 같은 키워드 실패 흔적
|
|
12943
|
+
(hits.taskLogFails || []).slice(0, 3).forEach(f => {
|
|
12944
|
+
conflictHints.push({ kind: 'task-log-failure', preview: (f.preview || f.text || '').slice(0, 100) });
|
|
12945
|
+
});
|
|
12946
|
+
}
|
|
12947
|
+
} catch {}
|
|
12948
|
+
|
|
12949
|
+
// 3) reuse-map 매칭 — 기존 capability 등록 후보
|
|
12950
|
+
try {
|
|
12951
|
+
const reusePath = path.join(root, '.harness/reuse-map.md');
|
|
12952
|
+
if (exists(reusePath)) {
|
|
12953
|
+
const reuseLines = read(reusePath).split('\n');
|
|
12954
|
+
const tokens = lower.split(/\s+/).filter(t => t.length >= 3);
|
|
12955
|
+
for (const line of reuseLines) {
|
|
12956
|
+
if (!/^\| /.test(line)) continue; // 테이블 row만
|
|
12957
|
+
const ll = line.toLowerCase();
|
|
12958
|
+
const matched = tokens.filter(t => ll.includes(t)).length;
|
|
12959
|
+
if (matched > 0) {
|
|
12960
|
+
const cols = line.split('|').map(s => s.trim());
|
|
12961
|
+
if (cols[1]) {
|
|
12962
|
+
reuseCandidates.push({ kind: 'reuse-map', capability: cols[1], where: cols[2] || '', note: cols[3] || '' });
|
|
12963
|
+
}
|
|
12964
|
+
}
|
|
12965
|
+
}
|
|
12966
|
+
}
|
|
12967
|
+
} catch {}
|
|
12968
|
+
|
|
12969
|
+
// 4) feature_graph — 같은 영역 변경 가능성
|
|
12970
|
+
const featureConflicts = [];
|
|
12971
|
+
try {
|
|
12972
|
+
const fgPath = path.join(root, '.harness/feature_graph.md');
|
|
12973
|
+
if (exists(fgPath)) {
|
|
12974
|
+
const fg = read(fgPath);
|
|
12975
|
+
const tokens = lower.split(/\s+/).filter(t => t.length >= 4);
|
|
12976
|
+
// F-XXXX 노드 라인 추출
|
|
12977
|
+
const nodeBlocks = fg.split(/\n### /);
|
|
12978
|
+
for (const blk of nodeBlocks.slice(1)) {
|
|
12979
|
+
const bl = blk.toLowerCase();
|
|
12980
|
+
const matched = tokens.filter(t => bl.includes(t)).length;
|
|
12981
|
+
if (matched > 0) {
|
|
12982
|
+
const titleMatch = blk.match(/^([^\n]+)/);
|
|
12983
|
+
const idMatch = blk.match(/F-\d+/);
|
|
12984
|
+
if (titleMatch && idMatch) {
|
|
12985
|
+
featureConflicts.push({ kind: 'feature', id: idMatch[0], title: titleMatch[1].trim() });
|
|
12986
|
+
}
|
|
12987
|
+
}
|
|
12988
|
+
}
|
|
12989
|
+
}
|
|
12990
|
+
} catch {}
|
|
12991
|
+
|
|
12992
|
+
// 5) 권장 단계 (작업 유형별)
|
|
12993
|
+
const recommendedSteps = {
|
|
12994
|
+
feature: [
|
|
12995
|
+
'1) leerness reuse find "<핵심 capability>" — 중복 구현 사전 차단',
|
|
12996
|
+
'2) leerness plan add "<milestone>" — 진행 추적',
|
|
12997
|
+
'3) leerness contract verify SPEC.md src/<mod>.js — 사양 ↔ 구현 일치 검증',
|
|
12998
|
+
'4) verify-claim --run-tests 로 evidence 의무화'
|
|
12999
|
+
],
|
|
13000
|
+
bugfix: [
|
|
13001
|
+
'1) leerness brainstorm "<버그 키워드>" — 과거 같은 영역 lesson 회수',
|
|
13002
|
+
'2) leerness verify-claim T-XXX --strict-claims — 낙관적 표시 사전 감지',
|
|
13003
|
+
'3) verify-code --run-tests — 재현 + fix 검증',
|
|
13004
|
+
'4) leerness lesson save "<root cause>" — 같은 실수 재발 차단'
|
|
13005
|
+
],
|
|
13006
|
+
refactor: [
|
|
13007
|
+
'1) leerness reuse-map — 영향 범위 파악',
|
|
13008
|
+
'2) leerness impact <file> — 강한/약한 참조 분리',
|
|
13009
|
+
'3) leerness contract verify — 외부 인터페이스 보존 확인',
|
|
13010
|
+
'4) verify-code --run-tests + 회귀 테스트'
|
|
13011
|
+
],
|
|
13012
|
+
research: [
|
|
13013
|
+
'1) leerness brainstorm "<주제>" — 누적 컨텍스트 회수',
|
|
13014
|
+
'2) leerness lessons --query "<주제>" — 과거 같은 영역 결정',
|
|
13015
|
+
'3) leerness review <file> --persona research — 깊이 검토',
|
|
13016
|
+
'4) leerness decision add "<결론>" — 회수 가능하게 영구화'
|
|
13017
|
+
],
|
|
13018
|
+
planning: [
|
|
13019
|
+
'1) leerness plan add "<milestone>" — 분해 시작',
|
|
13020
|
+
'2) leerness reuse-map — 기존 자원 인벤토리',
|
|
13021
|
+
'3) leerness agents recommend planning — sub-agent 분배',
|
|
13022
|
+
'4) leerness session close — 결정 영구화'
|
|
13023
|
+
],
|
|
13024
|
+
release: [
|
|
13025
|
+
'1) leerness health — production-ready 확인',
|
|
13026
|
+
'2) leerness audit + verify-code — 보안 + 검수',
|
|
13027
|
+
'3) leerness release bump + note + publish'
|
|
13028
|
+
],
|
|
13029
|
+
consistency: [
|
|
13030
|
+
'1) leerness audit — design/reuse/handoff 일관성 검사',
|
|
13031
|
+
'2) leerness consistency check — 잠재 일관성 위반',
|
|
13032
|
+
'3) leerness drift check --auto-fix — 자동 회복'
|
|
13033
|
+
]
|
|
13034
|
+
}[estimatedType] || [];
|
|
13035
|
+
|
|
13036
|
+
// 6) 효율 제안 (적용 가능한 sub-agent + skill)
|
|
13037
|
+
const efficiencyHints = [];
|
|
13038
|
+
if (reuseCandidates.length > 0) {
|
|
13039
|
+
efficiencyHints.push(`🔁 기존 자원 ${reuseCandidates.length}건 발견 — 신규 구현 전 재사용 검토 권장`);
|
|
13040
|
+
}
|
|
13041
|
+
if (conflictHints.length > 0) {
|
|
13042
|
+
efficiencyHints.push(`⚠ 충돌 신호 ${conflictHints.length}건 — 과거 실패 lesson / 진행 중 task 확인 필요`);
|
|
13043
|
+
}
|
|
13044
|
+
if (planConflicts.length > 0) {
|
|
13045
|
+
efficiencyHints.push(`📋 진행 중 milestone ${planConflicts.length}건과 영역 겹침 가능 — plan 정렬 권장`);
|
|
13046
|
+
}
|
|
13047
|
+
if (featureConflicts.length > 0) {
|
|
13048
|
+
efficiencyHints.push(`🕸 Feature Graph ${featureConflicts.length}건 영역 겹침 — 의존성 사전 확인`);
|
|
13049
|
+
}
|
|
13050
|
+
// 다중 에이전트 분배 추천
|
|
13051
|
+
if (estimatedType === 'feature' || estimatedType === 'planning') {
|
|
13052
|
+
efficiencyHints.push(`👥 leerness agents recommend ${estimatedType} — 작업 유형별 sub-agent 매핑 활용 가능`);
|
|
13053
|
+
}
|
|
13054
|
+
if (efficiencyHints.length === 0) {
|
|
13055
|
+
efficiencyHints.push('✨ 충돌 신호 없음 — 즉시 진행 안전');
|
|
13056
|
+
}
|
|
13057
|
+
|
|
13058
|
+
// 7) proceed 권장 (충돌 critical 시 false)
|
|
13059
|
+
const proceed = conflictHints.length < 3 && planConflicts.length === 0;
|
|
13060
|
+
|
|
13061
|
+
const dt = Date.now() - t0;
|
|
13062
|
+
const out = {
|
|
13063
|
+
request: text,
|
|
13064
|
+
estimatedType,
|
|
13065
|
+
conflicts: conflictHints,
|
|
13066
|
+
reuseCandidates,
|
|
13067
|
+
lessonsRecall,
|
|
13068
|
+
planConflicts,
|
|
13069
|
+
featureConflicts,
|
|
13070
|
+
recommendedSteps,
|
|
13071
|
+
efficiencyHints,
|
|
13072
|
+
proceed,
|
|
13073
|
+
proceedReason: proceed ? '안전 — 충돌 신호 < 3 + plan 충돌 0' : '⚠ 충돌 critical — 사용자 확인 후 진행',
|
|
13074
|
+
durationMs: dt
|
|
13075
|
+
};
|
|
13076
|
+
|
|
13077
|
+
try { _recordRun(root, { kind: 'review_request', estimatedType, conflicts: conflictHints.length, reuse: reuseCandidates.length, durationMs: dt, ok: true }); } catch {}
|
|
13078
|
+
|
|
13079
|
+
if (has('--json')) {
|
|
13080
|
+
log(JSON.stringify(out, null, 2));
|
|
13081
|
+
return;
|
|
13082
|
+
}
|
|
13083
|
+
|
|
13084
|
+
log(`# leerness review-request (1.9.176 사전 검토)`);
|
|
13085
|
+
log(`요청: "${text.slice(0, 200)}${text.length > 200 ? '…' : ''}"`);
|
|
13086
|
+
log(`추정 작업 유형: ${estimatedType}`);
|
|
13087
|
+
log('');
|
|
13088
|
+
if (conflictHints.length) {
|
|
13089
|
+
log(`## ⚠ 충돌 신호 (${conflictHints.length})`);
|
|
13090
|
+
conflictHints.slice(0, 5).forEach(c => log(` - [${c.kind}] ${c.title || c.id || ''} ${c.preview || ''}`.trim()));
|
|
13091
|
+
log('');
|
|
13092
|
+
}
|
|
13093
|
+
if (reuseCandidates.length) {
|
|
13094
|
+
log(`## 🔁 재사용 후보 (${reuseCandidates.length}) — 신규 구현 전 검토`);
|
|
13095
|
+
reuseCandidates.slice(0, 5).forEach(r => {
|
|
13096
|
+
if (r.kind === 'skill') log(` - [skill] ${r.id}${r.displayNameKo ? ' · ' + r.displayNameKo : ''}`);
|
|
13097
|
+
else if (r.kind === 'reuse-map') log(` - [reuse] ${r.capability} @ ${r.where}`);
|
|
13098
|
+
});
|
|
13099
|
+
log('');
|
|
13100
|
+
}
|
|
13101
|
+
if (lessonsRecall.length) {
|
|
13102
|
+
log(`## 🧠 과거 컨텍스트 (${lessonsRecall.length}) — 관련 결정/교훈`);
|
|
13103
|
+
lessonsRecall.slice(0, 3).forEach(l => log(` - [${l.kind}] ${l.title || l.preview}`));
|
|
13104
|
+
log('');
|
|
13105
|
+
}
|
|
13106
|
+
if (planConflicts.length || featureConflicts.length) {
|
|
13107
|
+
log(`## 📋 진행 중 영역 (${planConflicts.length + featureConflicts.length})`);
|
|
13108
|
+
planConflicts.forEach(m => log(` - [milestone] ${m.id}: ${m.title}`));
|
|
13109
|
+
featureConflicts.slice(0, 5).forEach(f => log(` - [feature] ${f.id}: ${f.title}`));
|
|
13110
|
+
log('');
|
|
13111
|
+
}
|
|
13112
|
+
log(`## 💡 효율 제안`);
|
|
13113
|
+
efficiencyHints.forEach(h => log(` ${h}`));
|
|
13114
|
+
log('');
|
|
13115
|
+
if (recommendedSteps.length) {
|
|
13116
|
+
log(`## 📍 권장 단계 (${estimatedType})`);
|
|
13117
|
+
recommendedSteps.forEach(s => log(` ${s}`));
|
|
13118
|
+
log('');
|
|
13119
|
+
}
|
|
13120
|
+
log(`## ▶ 진행 권장: ${proceed ? '✓ 진행 안전' : '⚠ 사용자 확인 필요'}`);
|
|
13121
|
+
log(` 사유: ${out.proceedReason}`);
|
|
13122
|
+
log(` 분석 소요: ${dt}ms`);
|
|
13123
|
+
}
|
|
13124
|
+
|
|
12783
13125
|
// 1.9.164: leerness which — 진단 도구 (구버전 충돌 / npx 캐시 / PATH 충돌 해결)
|
|
12784
13126
|
// 사용자가 "최신 버전 작동 안 함" 의심 시: 실제 실행 중인 leerness 의 경로 / 버전 / npm 캐시 / PATH 후보 표시.
|
|
12785
13127
|
function whichCmd() {
|
|
@@ -12861,7 +13203,7 @@ function whichCmd() {
|
|
|
12861
13203
|
}
|
|
12862
13204
|
|
|
12863
13205
|
function help() {
|
|
12864
|
-
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 memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26/27 낙관적 표시 감지 (1.9.27: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수)\n leerness persona list|show <id>|add <id> # 1.9.29 페르소나 카탈로그 (보안/성능/UX/testing/docs 5종 내장)\n leerness review <file> --persona <id1,id2,...> # 1.9.29 도메인 페르소나 리뷰 프롬프트 자동 생성\n leerness agents list|check|quota # 1.9.30/31 외부 AI CLI 가용성 + quota 추정 (claude/codex/gemini/copilot)\n leerness agents dispatch "<task>" --to <id> # 1.9.30 활성 CLI 대상 실행 명령 생성 (실 호출 X, 사용자 실행)\n leerness agents multi "<task>" [--only c1,c2] [--write] [--execute] [--timeout 60] # 1.9.152/156 활성 N개 일괄 dispatch (--execute: 실 spawn + consensus)\n leerness provider list|add|remove [args] # 1.9.157 Provider Registry — 사용자 정의 CLI provider 동적 추가 (OpenRouter/Bedrock 흡수)\n leerness agents dispatch "<task>" --multi # 1.9.152 multi 모드 alias (또는 --to all)\n leerness setup-agents [path] [--yes|--no-setup-agents] # 1.9.32 sub-agent CLI 인터랙티브 설정 (.env + 미설치 자동 설치)\n leerness init [path] [--no-stale-check] # 1.9.33 npx 캐시 함정 — 옛 버전 자동 경고 (끄려면 --no-stale-check)\n leerness which [--json] # 1.9.164 진단: 현재 실행 경로/버전 + npm 캐시 + PATH 후보 (구버전 충돌 해결)\n leerness web check|screenshot|extract <url> [--out file.png] [--selector "css"] # 1.9.165 playwright bridge (opt-in: npm i -g playwright + permissions.browser)\n leerness pc check|click|type|screenshot [--x N --y N] [--text "s"] [--out f.png] # 1.9.166 robotjs/nut-tree bridge (opt-in: npm i -g robotjs + permissions.mouse/keyboard, ⚠ full 모드 권장)\n leerness lsp check|symbols|references <file/name> [--in dir] [--json] # 1.9.167 LSP 어댑터 MVP (typescript opt-in + regex fallback, 코드 인텔리전스)\n leerness contract verify <spec.md> <impl.js> [--json] # 1.9.35 명세 ↔ 구현 일치 검사 (함수/필드)\n leerness reuse autodetect [path] [--apply] [--json] # 1.9.35 src/*.js의 module.exports → reuse-map 후보 등록\n leerness audit [path] [--fix] # 1.9.35 --fix: session-handoff/current-state 자동 갱신\n leerness verify-claim <T-ID> ... [--strict-claims] # 1.9.26 verify-claim에 낙관적 표시 자동 검사 통합\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 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
|
|
13206
|
+
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 memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26/27 낙관적 표시 감지 (1.9.27: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수)\n leerness persona list|show <id>|add <id> # 1.9.29 페르소나 카탈로그 (보안/성능/UX/testing/docs 5종 내장)\n leerness review <file> --persona <id1,id2,...> # 1.9.29 도메인 페르소나 리뷰 프롬프트 자동 생성\n leerness agents list|check|quota # 1.9.30/31 외부 AI CLI 가용성 + quota 추정 (claude/codex/gemini/copilot)\n leerness agents dispatch "<task>" --to <id> # 1.9.30 활성 CLI 대상 실행 명령 생성 (실 호출 X, 사용자 실행)\n leerness agents multi "<task>" [--only c1,c2] [--write] [--execute] [--timeout 60] # 1.9.152/156 활성 N개 일괄 dispatch (--execute: 실 spawn + consensus)\n leerness provider list|add|remove [args] # 1.9.157 Provider Registry — 사용자 정의 CLI provider 동적 추가 (OpenRouter/Bedrock 흡수)\n leerness agents dispatch "<task>" --multi # 1.9.152 multi 모드 alias (또는 --to all)\n leerness setup-agents [path] [--yes|--no-setup-agents] # 1.9.32 sub-agent CLI 인터랙티브 설정 (.env + 미설치 자동 설치)\n leerness init [path] [--no-stale-check] # 1.9.33 npx 캐시 함정 — 옛 버전 자동 경고 (끄려면 --no-stale-check)\n leerness which [--json] # 1.9.164 진단: 현재 실행 경로/버전 + npm 캐시 + PATH 후보 (구버전 충돌 해결)\n leerness web check|screenshot|extract <url> [--out file.png] [--selector "css"] # 1.9.165 playwright bridge (opt-in: npm i -g playwright + permissions.browser)\n leerness pc check|click|type|screenshot [--x N --y N] [--text "s"] [--out f.png] # 1.9.166 robotjs/nut-tree bridge (opt-in: npm i -g robotjs + permissions.mouse/keyboard, ⚠ full 모드 권장)\n leerness lsp check|symbols|references <file/name> [--in dir] [--json] # 1.9.167 LSP 어댑터 MVP (typescript opt-in + regex fallback, 코드 인텔리전스)\n leerness review-request "<request>" [--json] # 1.9.176 사용자 요청 사전 검토 (충돌/재사용/효율/권장 단계 — 사용자 명시)\n leerness contract verify <spec.md> <impl.js> [--json] # 1.9.35 명세 ↔ 구현 일치 검사 (함수/필드)\n leerness reuse autodetect [path] [--apply] [--json] # 1.9.35 src/*.js의 module.exports → reuse-map 후보 등록\n leerness audit [path] [--fix] # 1.9.35 --fix: session-handoff/current-state 자동 갱신\n leerness verify-claim <T-ID> ... [--strict-claims] # 1.9.26 verify-claim에 낙관적 표시 자동 검사 통합\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 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
|
|
12865
13207
|
leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # 회고 (1.9.13~1.9.16)
|
|
12866
13208
|
leerness insights [path] [--all-apps] [--include p1,p2] [--json] # 누적 통계 (1.9.13~1.9.16)
|
|
12867
13209
|
leerness brainstorm "<주제>" [--all-apps] [--include p1,p2] [--json] # 브레인스토밍 (1.9.13~1.9.16)
|
|
@@ -12943,6 +13285,13 @@ async function main() {
|
|
|
12943
13285
|
if (cmd === 'pc') return pcCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
12944
13286
|
|
|
12945
13287
|
if (cmd === 'lsp') return lspCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
13288
|
+
|
|
13289
|
+
// 1.9.176: leerness review-request "<request>" — 사용자 요청 사전 검토 (사용자 명시)
|
|
13290
|
+
// AI 에이전트가 무조건 구현 전에 충돌/재사용/효율/권장 단계 분석.
|
|
13291
|
+
if (cmd === 'review-request' || cmd === 'review-req') {
|
|
13292
|
+
const reqText = args.slice(1).filter(x => !x.startsWith('-')).join(' ');
|
|
13293
|
+
return reviewRequestCmd(arg('--path', process.cwd()), reqText);
|
|
13294
|
+
}
|
|
12946
13295
|
if (cmd === 'contract' && args[1] === 'verify') return contractVerifyCmd(args[2], args[3]);
|
|
12947
13296
|
if (cmd === 'drift' && (args[1] === 'check' || !args[1])) return driftCheckCmd(args[2] || arg('--path', process.cwd()));
|
|
12948
13297
|
if (cmd === 'usage' && (args[1] === 'stats' || !args[1])) return usageStatsCmd(args[2] || arg('--path', process.cwd()));
|