leerness 1.9.175 β 1.9.177
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 +106 -0
- package/README.md +3 -3
- package/bin/harness.js +343 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,111 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.177 β 2026-05-21
|
|
4
|
+
|
|
5
|
+
**π `task add` μλ review-request trigger β μ¬μ©μ λͺ
μ 1.9.176 μλν.**
|
|
6
|
+
|
|
7
|
+
μμ¨ λͺ¨λ 107 λΌμ΄λ. 1.9.176 (μ¬μ©μ λͺ
μ: 무쑰건 ꡬν μ μ¬μ κ²ν ) μ μλν β μ¬μ©μ/AIκ° `task add` νΈμΆ μ reviewλ₯Ό μ§μ μ€ννμ§ μμλ μλ trigger.
|
|
8
|
+
|
|
9
|
+
### ν΅ν© νλ¦
|
|
10
|
+
```bash
|
|
11
|
+
$ leerness task add "OAuth λ‘κ·ΈμΈ κ΅¬νν΄μ€"
|
|
12
|
+
β task added: T-0001
|
|
13
|
+
|
|
14
|
+
π review-request (1.9.177 μλ): type=feature Β· β μ§ν μμ (705ms)
|
|
15
|
+
κΆμ₯ λ¨κ³:
|
|
16
|
+
1) leerness reuse find "<ν΅μ¬ capability>" β μ€λ³΅ ꡬν μ¬μ μ°¨λ¨
|
|
17
|
+
2) leerness plan add "<milestone>" β μ§ν μΆμ
|
|
18
|
+
... +2건 (leerness review-request "OAuth λ‘κ·ΈμΈ κ΅¬νν΄μ€" μΌλ‘ μ 체 보기)
|
|
19
|
+
π‘ π₯ leerness agents recommend feature β μμ
μ νλ³ sub-agent λ§€ν νμ© κ°λ₯
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
β μ¬μ©μ/AIκ° λͺ
μμ μΌλ‘ `:review` νΈμΆ μ ν΄λ, `task add` λ§μΌλ‘ μλ μ¬μ κ²ν μλ£. **1.9.176 μ¬μ©μ λͺ
μ μλκ° default λμμ ν΅ν©**.
|
|
23
|
+
|
|
24
|
+
### Opt-out (3 κ°μ§)
|
|
25
|
+
1. CLI νλκ·Έ: `leerness task add "..." --no-review`
|
|
26
|
+
2. νκ²½λ³μ: `LEERNESS_NO_AUTO_REVIEW=1`
|
|
27
|
+
3. μ΄μ λ©ν: `--status done|dropped|blocked` (μ΄λ―Έ μ’
λ£λ μμ
μ review λΆνμ)
|
|
28
|
+
|
|
29
|
+
### νμ μ μ±
(κ°κ²°)
|
|
30
|
+
- ν€λ 1μ€: `type=X Β· β N μΆ©λ Β· π N μ¬μ¬μ© ν보 Β· β μ§ν μμ / β νμΈ νμ (ms)`
|
|
31
|
+
- κΆμ₯ λ¨κ³ 첫 2건 (λλ¨Έμ§λ `leerness review-request` μ§μ νΈμΆ μλ΄)
|
|
32
|
+
- ν¨μ¨ μ μ 1건 (κ°μ₯ μ€μν hint)
|
|
33
|
+
- `proceed=false` μ β μ¬μ λ
ΈμΆ
|
|
34
|
+
|
|
35
|
+
### MCP νΈνμ±
|
|
36
|
+
`leerness_task_add` (MCP) νΈμΆ μμλ μλ review λμ β μΈλΆ AI (Claude/Codex/Gemini)κ° task λ±λ‘ μ μλμΌλ‘ μ¬μ κ²ν κ²°κ³Ό λ°μ.
|
|
37
|
+
|
|
38
|
+
### μ±λ₯
|
|
39
|
+
μ€μΈ‘: ~1.1μ΄ task add (μ΄μ ~30ms + review 1μ΄ μΆκ°). brainstorm/reuse-map νμ λΉμ© β opt-out κ°λ₯.
|
|
40
|
+
|
|
41
|
+
### Verified
|
|
42
|
+
- e2e 217/217 baseline μ μ§
|
|
43
|
+
- stress-v122: **18/18** (taskAdd ν΅ν© 4 + μ€ λμ 7 + MCP νΈν 1 + λμ νκ· 6)
|
|
44
|
+
- VERSION = 1.9.177 / autonomous-rounds = 107 / main μλ push 38 λΌμ΄λ μ°μ
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 1.9.176 β 2026-05-21
|
|
49
|
+
|
|
50
|
+
**β μ¬μ©μ λͺ
μ: `leerness review-request` β μ¬μ©μ μꡬλ₯Ό 무쑰건 ꡬν μ μ¬μ κ²ν .**
|
|
51
|
+
|
|
52
|
+
μ¬μ©μ λͺ
μ: *"leernessκ° μ μ©λ νλ‘μ νΈλ μ¬μ©μμ μꡬλ₯Ό 무쑰건μ μΌλ‘ ꡬννκΈ° μ μ, μΆ©λμ΄ λ°μν μ μλ λΆλΆμ΄λ μ μνκ³ μ νλ κΈ°λ₯ λ±μ ꡬννκ±°λ μ€κ³ν λ λ ν¨μ¨μ μΈ λ¨κ³κ° μλμ§ κ²ν ν΄λ³΄κ³ μ μν μλ μλλ‘ μ€κ³"*.
|
|
53
|
+
|
|
54
|
+
### `leerness review-request "<request>"` β 9κ° μ νΈ λΆμ
|
|
55
|
+
| μ νΈ | λ°μ΄ν° μμ€ |
|
|
56
|
+
|---|---|
|
|
57
|
+
| **estimatedType** | route ν€μλ λ§€ν (feature/bugfix/refactor/research/planning/release/consistency) |
|
|
58
|
+
| **conflicts** | lessons μ€ν¨ ν¨ν΄ + μ§ν μ€ task + taskLogFails |
|
|
59
|
+
| **reuseCandidates** | skills λ§€μΉ + reuse-map ν€μλ κ²μ |
|
|
60
|
+
| **lessonsRecall** | κ³Όκ±° decisions + κ΄λ ¨ lessons |
|
|
61
|
+
| **planConflicts** | μ§ν μ€ milestone (plan.md) |
|
|
62
|
+
| **featureConflicts** | feature_graph.md μμ κ²ΉμΉ¨ |
|
|
63
|
+
| **recommendedSteps** | μμ
μ νλ³ 3-4λ¨κ³ κΆμ₯ νλ¦ |
|
|
64
|
+
| **efficiencyHints** | μ¬μ¬μ©/sub-agent/skill νμ© μ μ |
|
|
65
|
+
| **proceed** | true (μμ ) / false (μ¬μ©μ νμΈ νμ) |
|
|
66
|
+
|
|
67
|
+
### μ¬μ© μ
|
|
68
|
+
```bash
|
|
69
|
+
$ leerness review-request "OAuth λ‘κ·ΈμΈ κ΅¬νν΄μ€"
|
|
70
|
+
# leerness review-request (1.9.176 μ¬μ κ²ν )
|
|
71
|
+
μμ²: "OAuth λ‘κ·ΈμΈ κ΅¬νν΄μ€"
|
|
72
|
+
μΆμ μμ
μ ν: feature
|
|
73
|
+
|
|
74
|
+
## π‘ ν¨μ¨ μ μ
|
|
75
|
+
π₯ leerness agents recommend feature β μμ
μ νλ³ sub-agent λ§€ν νμ© κ°λ₯
|
|
76
|
+
|
|
77
|
+
## π κΆμ₯ λ¨κ³ (feature)
|
|
78
|
+
1) leerness reuse find "<ν΅μ¬ capability>" β μ€λ³΅ ꡬν μ¬μ μ°¨λ¨
|
|
79
|
+
2) leerness plan add "<milestone>" β μ§ν μΆμ
|
|
80
|
+
3) leerness contract verify SPEC.md src/<mod>.js β μ¬μ β ꡬν μΌμΉ κ²μ¦
|
|
81
|
+
4) verify-claim --run-tests λ‘ evidence μ무ν
|
|
82
|
+
|
|
83
|
+
## βΆ μ§ν κΆμ₯: β μ§ν μμ
|
|
84
|
+
μ¬μ : μμ β μΆ©λ μ νΈ < 3 + plan μΆ©λ 0
|
|
85
|
+
λΆμ μμ: 938ms
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### ν΅ν© β 3 μ§μ
μ
|
|
89
|
+
- **CLI**: `leerness review-request "<request>"` (λλ λ¨μΆ `review-req`)
|
|
90
|
+
- **REPL**: `:review "<request>"` slash (1.9.175 νλ¦ μ°μ₯)
|
|
91
|
+
- **MCP**: `leerness_review_request` (μΈλΆ AI μ§μ νΈμΆ β **54λ²μ§Έ λꡬ**)
|
|
92
|
+
|
|
93
|
+
### AGENTS.md / CLAUDE.md κ°μ μλ΄
|
|
94
|
+
```markdown
|
|
95
|
+
## β μ¬μ©μ μμ² μ¬μ κ²ν μ무 (1.9.176 β μ¬μ©μ λͺ
μ)
|
|
96
|
+
**μ¬μ©μκ° "X ꡬνν΄μ€ / X λ§λ€μ΄μ€ / X μΆκ°ν΄μ€" κ°μ μμ²μ 쀬μ λ 무쑰건 μ¦μ ꡬννμ§ λ§ κ².**
|
|
97
|
+
λ¨Όμ `leerness review-request "<μμ²>"` νΈμΆ β λΆμ κ²°κ³Ό νμ β μ¬μ©μ νμΈ ν ꡬν.
|
|
98
|
+
"κ·Έλ₯ λ°λ‘ ν΄μ€ / review 건λλ°μ΄μ€" λͺ
μ μ΅νΈμμ μμλ§ review μλ΅.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Verified
|
|
102
|
+
- e2e 217/217 baseline μ μ§
|
|
103
|
+
- stress-v121: **23/23** (ν¨μ μ μ 4 + router/help 2 + μ€ λμ 6 + REPL/MCP 3 + metadata 2 + λμ νκ· 6)
|
|
104
|
+
- μμ
μ ν μΆμ μ νλ: feature/bugfix/refactor/research 4μ’
100% λ§€μΉ
|
|
105
|
+
- VERSION = 1.9.176 Β· MCP **54 λꡬ** Β· autonomous-rounds = 106 Β· main μλ push 37 λΌμ΄λ μ°μ
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
3
109
|
## 1.9.175 β 2026-05-21
|
|
4
110
|
|
|
5
111
|
**π REPL Bridge Slash 3μ’
β `:web` / `:pc` / `:lsp` μ¦μ νΈμΆ.**
|
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.177 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
17
|
+
β π task add μλ review trigger β default μ¬μ κ²ν β
|
|
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.177';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -1600,6 +1600,42 @@ function taskAdd(root, text) {
|
|
|
1600
1600
|
upsertProgress(root, { id, status: arg('--status','requested'), request: text, evidence: arg('--evidence','user-request'), nextAction: arg('--next','λ€μ μ‘μ
μμ±') });
|
|
1601
1601
|
ok(`task added: ${id}`);
|
|
1602
1602
|
_autoRoadmap(absRoot(root), 'data-change');
|
|
1603
|
+
// 1.9.177: task add μλ review-request trigger (μ¬μ©μ λͺ
μ 1.9.176 μλν).
|
|
1604
|
+
// μ¬μ©μκ° task μΆκ° μ μλμΌλ‘ μ¬μ κ²ν β μΆ©λ/μ¬μ¬μ©/ν¨μ¨/κΆμ₯ λ¨κ³ κ²°κ³Όλ₯Ό λ±λ‘ μ§ν νμ.
|
|
1605
|
+
// opt-out: --no-review λλ env LEERNESS_NO_AUTO_REVIEW=1, λλ status=in-progress/done κ°μ μ΄μ λ©ν.
|
|
1606
|
+
if (!has('--no-review')
|
|
1607
|
+
&& process.env.LEERNESS_NO_AUTO_REVIEW !== '1'
|
|
1608
|
+
&& !/^(done|dropped|blocked)$/i.test(arg('--status', 'requested'))
|
|
1609
|
+
&& text && text.trim()) {
|
|
1610
|
+
try {
|
|
1611
|
+
const t0 = Date.now();
|
|
1612
|
+
const r = cp.spawnSync(process.execPath, [__filename, 'review-request', text, '--path', absRoot(root), '--json'], {
|
|
1613
|
+
encoding: 'utf8', timeout: 15000,
|
|
1614
|
+
env: { ...process.env, LEERNESS_NO_BANNER: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' }
|
|
1615
|
+
});
|
|
1616
|
+
if (r.status === 0 && r.stdout) {
|
|
1617
|
+
const j = JSON.parse(r.stdout);
|
|
1618
|
+
log('');
|
|
1619
|
+
log(`π review-request (1.9.177 μλ): type=${j.estimatedType}` +
|
|
1620
|
+
(j.conflicts.length ? ` Β· β ${j.conflicts.length} μΆ©λ` : '') +
|
|
1621
|
+
(j.reuseCandidates.length ? ` Β· π ${j.reuseCandidates.length} μ¬μ¬μ© ν보` : '') +
|
|
1622
|
+
` Β· ${j.proceed ? 'β μ§ν μμ ' : 'β νμΈ νμ'} (${Date.now() - t0}ms)`);
|
|
1623
|
+
// κΆμ₯ λ¨κ³ 첫 2건 λ
ΈμΆ
|
|
1624
|
+
if (j.recommendedSteps && j.recommendedSteps.length) {
|
|
1625
|
+
log(' κΆμ₯ λ¨κ³:');
|
|
1626
|
+
j.recommendedSteps.slice(0, 2).forEach(s => log(' ' + s));
|
|
1627
|
+
if (j.recommendedSteps.length > 2) log(` ... +${j.recommendedSteps.length - 2}건 (leerness review-request "${text.slice(0, 30)}" μΌλ‘ μ 체 보기)`);
|
|
1628
|
+
}
|
|
1629
|
+
// ν¨μ¨ μ μ 1건λ§
|
|
1630
|
+
if (j.efficiencyHints && j.efficiencyHints.length) {
|
|
1631
|
+
log(` π‘ ${j.efficiencyHints[0]}`);
|
|
1632
|
+
}
|
|
1633
|
+
if (!j.proceed) {
|
|
1634
|
+
log(` β ${j.proceedReason}`);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
} catch {} // review μ€ν¨λ task add μ체μ μν₯ X
|
|
1638
|
+
}
|
|
1603
1639
|
}
|
|
1604
1640
|
function taskUpdate(root, id) {
|
|
1605
1641
|
if (!id) return fail('id required (e.g., task update T-0001 --status in-progress)');
|
|
@@ -9845,7 +9881,8 @@ function mcpServeCmd(root) {
|
|
|
9845
9881
|
{ 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
9882
|
{ 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
9883
|
{ 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'] } }
|
|
9884
|
+
{ 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'] } },
|
|
9885
|
+
{ 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
9886
|
];
|
|
9850
9887
|
|
|
9851
9888
|
function send(obj) {
|
|
@@ -9973,6 +10010,10 @@ function mcpServeCmd(root) {
|
|
|
9973
10010
|
if (args.name) cliArgs.splice(2, 0, String(args.name));
|
|
9974
10011
|
if (args.in) cliArgs.push('--in', String(args.in));
|
|
9975
10012
|
break;
|
|
10013
|
+
case 'leerness_review_request':
|
|
10014
|
+
// 1.9.176: μ¬μ©μ μμ² μ¬μ κ²ν (μ¬μ©μ λͺ
μ μμ²)
|
|
10015
|
+
cliArgs = ['review-request', String(args.request || ''), '--path', targetPath, '--json'];
|
|
10016
|
+
break;
|
|
9976
10017
|
default:
|
|
9977
10018
|
return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
|
|
9978
10019
|
}
|
|
@@ -11007,6 +11048,7 @@ async function _agentRepl(root, opts) {
|
|
|
11007
11048
|
log(C.dim(' π 1.9.170 β Tab=provider cycle, Shift+Tab=model cycle, :stream on|off (μ€μκ° μΆλ ₯)'));
|
|
11008
11049
|
log(C.dim(' π 1.9.174 β :permissions [basic|extended|full] λ‘ μ¦μ κΆν λ³κ²½ (default: basic μμ )'));
|
|
11009
11050
|
log(C.dim(' π 1.9.175 β :web / :pc / :lsp μΌλ‘ Bridge 3μ’
REPL μμμ μ¦μ νΈμΆ (μ½λ λΆμ/μΉ/PC)'));
|
|
11051
|
+
log(C.dim(' π 1.9.176 β :review "<μμ²>" μΌλ‘ μ¬μ©μ μμ² μ¬μ κ²ν (μΆ©λ/μ¬μ¬μ©/ν¨μ¨/κΆμ₯ λ¨κ³)'));
|
|
11010
11052
|
log(C.dim(` νμ¬ β provider=${state.provider} model=${state.model || '(κΈ°λ³Έ)'} role=${state.role} permissions=${_readPermissions(root).mode}`));
|
|
11011
11053
|
// 1.9.155: REPL μ§μ
μ handoff 컨ν
μ€νΈ μλ λ
ΈμΆ (UX κ°μ β μ¬μ©μκ° λ§€λ² :handoff μ ν΄λ 컨ν
μ€νΈ μΈμ§)
|
|
11012
11054
|
try {
|
|
@@ -11127,6 +11169,8 @@ async function _agentRepl(root, opts) {
|
|
|
11127
11169
|
log(' :brainstorm <topic> β leerness brainstorm "topic" (κ΄λ ¨ 컨ν
μ€νΈ νμ)');
|
|
11128
11170
|
log(' :tasks β leerness task list (νμ¬ task μν)');
|
|
11129
11171
|
log(' :plan β leerness plan show (νμ¬ milestone)');
|
|
11172
|
+
log(C.bold('\n π Review Slash (1.9.176) β μ¬μ©μ μμ² μ¬μ κ²ν :'));
|
|
11173
|
+
log(' :review "<request>" β μΆ©λ/μ¬μ¬μ©/ν¨μ¨/κΆμ₯ λ¨κ³ λΆμ ν ꡬν κΆμ₯');
|
|
11130
11174
|
log(C.bold('\n π Bridge Slash (1.9.175) β REPL μμμ μ¦μ Bridge νΈμΆ:'));
|
|
11131
11175
|
log(' :web check β playwright μ€μΉ νμΈ (opt-in)');
|
|
11132
11176
|
log(' :web screenshot <url> [--out f.png] β URL β PNG');
|
|
@@ -11317,6 +11361,27 @@ async function _agentRepl(root, opts) {
|
|
|
11317
11361
|
return false;
|
|
11318
11362
|
}
|
|
11319
11363
|
|
|
11364
|
+
// 1.9.176: :review <request> β μ¬μ©μ μμ² μ¬μ κ²ν slash (μ¬μ©μ λͺ
μ)
|
|
11365
|
+
// "μ΄κ±° ꡬνν΄μ€" κ°μ μμ²μ λ°μΌλ©΄ AI κ° λ¨Όμ :review νΈμΆ β μΆ©λ/μ¬μ¬μ©/ν¨μ¨ λΆμ.
|
|
11366
|
+
if (op === 'review') {
|
|
11367
|
+
const reqText = rest.join(' ').trim();
|
|
11368
|
+
if (!reqText) {
|
|
11369
|
+
log(C.yel(` β :review λ μμ² ν
μ€νΈ νμ β μ: :review "OAuth λ‘κ·ΈμΈ μΆκ°"`));
|
|
11370
|
+
return false;
|
|
11371
|
+
}
|
|
11372
|
+
log(C.dim(` β leerness review-request "${reqText.slice(0, 60)}${reqText.length > 60 ? 'β¦' : ''}"`));
|
|
11373
|
+
const t0 = Date.now();
|
|
11374
|
+
const r = runCommandSafe(process.execPath, [__filename, 'review-request', reqText, '--path', root], {
|
|
11375
|
+
cwd: root, root, timeout: 30000, kind: 'agent_repl_slash', label: 'repl-review',
|
|
11376
|
+
env: { LEERNESS_NO_BANNER: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' }
|
|
11377
|
+
});
|
|
11378
|
+
const dt = Date.now() - t0;
|
|
11379
|
+
if (r.stdout) log(r.stdout.trim().split('\n').slice(0, 60).join('\n'));
|
|
11380
|
+
if (r.status === 0) log(C.green(` β :review μλ£ (${dt}ms)`));
|
|
11381
|
+
else log(C.yel(` β :review μ€ν¨ (exit ${r.status}, ${dt}ms)`));
|
|
11382
|
+
return false;
|
|
11383
|
+
}
|
|
11384
|
+
|
|
11320
11385
|
// 1.9.150: leerness λ΄λΆ λͺ
λ Ή slash-commands β :verify / :audit / :handoff / :health
|
|
11321
11386
|
// 1.9.161: Memory Surface μ‘°ν slash μΆκ° β :lessons / :brainstorm / :tasks / :plan
|
|
11322
11387
|
if (op === 'verify' || op === 'audit' || op === 'handoff' || op === 'health'
|
|
@@ -12825,6 +12890,274 @@ function lspCmd(root, sub, ...args) {
|
|
|
12825
12890
|
fail(`μ μ μλ sub: ${sub} (check / symbols / references)`);
|
|
12826
12891
|
}
|
|
12827
12892
|
|
|
12893
|
+
// 1.9.176: μ¬μ©μ μμ² μ¬μ κ²ν (μ¬μ©μ λͺ
μ μμ²)
|
|
12894
|
+
// AI μμ΄μ νΈκ° μ¬μ©μ μꡬλ₯Ό **무쑰건 ꡬννκΈ° μ **μ λ¨Όμ :
|
|
12895
|
+
// 1) μΆ©λ μν (κ°μ ν€μλμ κ³Όκ±° μ€ν¨/lessons)
|
|
12896
|
+
// 2) κΈ°μ‘΄ μμ μ¬μ¬μ© ν보 (reuse-map / skills)
|
|
12897
|
+
// 3) λ ν¨μ¨μ μΈ λ¨κ³ μ μ (route + plan)
|
|
12898
|
+
// 4) κΆμ₯ λ¨κ³ 리μ€νΈ (μμ
μ νλ³)
|
|
12899
|
+
// λ₯Ό λΆμνμ¬ μ¬μ©μμκ² μ μ. μ¬μ©μ κ²°μ ν ꡬν μ§ν.
|
|
12900
|
+
//
|
|
12901
|
+
// μ¬μ© μ:
|
|
12902
|
+
// leerness review-request "OAuth λ‘κ·ΈμΈ κ΅¬νν΄μ€"
|
|
12903
|
+
// leerness review-request "..." --json # MCP/μΈλΆ AI ν΅ν©
|
|
12904
|
+
//
|
|
12905
|
+
// REPL: :review <request> (1.9.175 slash ν¨ν΄)
|
|
12906
|
+
// MCP : leerness_review_request (μΈλΆ AI μ§μ νΈμΆ)
|
|
12907
|
+
function reviewRequestCmd(root, request) {
|
|
12908
|
+
root = absRoot(root || process.cwd());
|
|
12909
|
+
if (!request || !String(request).trim()) {
|
|
12910
|
+
return fail('leerness review-request "<request>" β μ¬μ©μ μμ² ν
μ€νΈ νμ');
|
|
12911
|
+
}
|
|
12912
|
+
const t0 = Date.now();
|
|
12913
|
+
const text = String(request).trim();
|
|
12914
|
+
|
|
12915
|
+
// 1) μμ
μ ν μΆμ (route κΈ°λ° ν€μλ λ§€ν)
|
|
12916
|
+
const lower = text.toLowerCase();
|
|
12917
|
+
const routeKw = {
|
|
12918
|
+
bugfix: ['λ²κ·Έ', 'μ€λ₯', 'μλ¬', 'μμ ', 'κ³ μ³', 'μ€ν¨', 'fix', 'bug', 'error'],
|
|
12919
|
+
refactor: ['리ν©ν ', 'μ¬κ΅¬μ±', 'μ 리', 'κ°μ ', 'refactor', 'cleanup'],
|
|
12920
|
+
feature: ['μΆκ°', 'ꡬν', 'λ§λ€', 'μ', 'κΈ°λ₯', 'add', 'implement', 'feature', 'create', 'new'],
|
|
12921
|
+
research: ['μ‘°μ¬', 'λΆμ', 'λΉκ΅', 'κ²ν ', 'μ°κ΅¬', 'research', 'analyze', 'compare', 'investigate'],
|
|
12922
|
+
planning: ['κ³ν', 'μ€κ³', 'λ‘λλ§΅', 'plan', 'design', 'architecture', 'roadmap'],
|
|
12923
|
+
release: ['λ°°ν¬', '릴리μ¦', 'λ²μ ', 'release', 'deploy', 'publish'],
|
|
12924
|
+
consistency: ['μΌκ΄μ±', 'ν΅ν©', 'λκΈ°ν', 'λ§μΆ°', 'consistency', 'sync', 'align']
|
|
12925
|
+
};
|
|
12926
|
+
let estimatedType = 'feature'; // default
|
|
12927
|
+
let maxScore = 0;
|
|
12928
|
+
for (const [type, kws] of Object.entries(routeKw)) {
|
|
12929
|
+
const score = kws.filter(k => lower.includes(k)).length;
|
|
12930
|
+
if (score > maxScore) { maxScore = score; estimatedType = type; }
|
|
12931
|
+
}
|
|
12932
|
+
|
|
12933
|
+
// 2) κΈ°μ‘΄ μμ νμ β brainstorm spawn (λͺ¨λ surface ν΅ν© νμ)
|
|
12934
|
+
const conflictHints = []; // β κ°μ ν€μλ + μ€ν¨/μ€λ₯ ν¨ν΄
|
|
12935
|
+
const reuseCandidates = []; // π κΈ°μ‘΄ skill / reuse-map / decision ν보
|
|
12936
|
+
const lessonsRecall = []; // π§ κ³Όκ±° lesson
|
|
12937
|
+
const planConflicts = []; // π μ§ν μ€ milestoneκ³Ό μΆ©λ κ°λ₯
|
|
12938
|
+
|
|
12939
|
+
// brainstorm νΈμΆ (1.9.13~) β JSON κ²°κ³Ό νμ
|
|
12940
|
+
try {
|
|
12941
|
+
const r = cp.spawnSync(process.execPath, [__filename, 'brainstorm', text, '--path', root, '--json'], {
|
|
12942
|
+
encoding: 'utf8', timeout: 12000,
|
|
12943
|
+
env: { ...process.env, LEERNESS_NO_BANNER: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' }
|
|
12944
|
+
});
|
|
12945
|
+
if (r.stdout) {
|
|
12946
|
+
const j = JSON.parse(r.stdout);
|
|
12947
|
+
const hits = j.hits || {};
|
|
12948
|
+
// decisions β κ³Όκ±° κ²°μ ν보
|
|
12949
|
+
(hits.decisions || []).slice(0, 5).forEach(d => {
|
|
12950
|
+
lessonsRecall.push({ kind: 'decision', title: d.title, line: d.line, preview: (d.preview || '').slice(0, 100) });
|
|
12951
|
+
});
|
|
12952
|
+
// lessons β κ³Όκ±° κ΅ν (νΉν μ€ν¨ ν€μλ)
|
|
12953
|
+
(hits.lessons || []).slice(0, 5).forEach(l => {
|
|
12954
|
+
const preview = (l.text || l.preview || '').slice(0, 100);
|
|
12955
|
+
const isFailure = /μ€ν¨|μ€λ₯|μλ¬|fail|error|bug|λ¬Έμ |warning/i.test(preview);
|
|
12956
|
+
if (isFailure) {
|
|
12957
|
+
conflictHints.push({ kind: 'lesson-failure', preview, tags: l.tags });
|
|
12958
|
+
} else {
|
|
12959
|
+
lessonsRecall.push({ kind: 'lesson', preview, tags: l.tags });
|
|
12960
|
+
}
|
|
12961
|
+
});
|
|
12962
|
+
// skills β κΈ°μ‘΄ skill ν보
|
|
12963
|
+
(hits.skills || []).slice(0, 3).forEach(s => {
|
|
12964
|
+
reuseCandidates.push({ kind: 'skill', id: s.id, displayNameKo: s.displayNameKo, capabilities: s.capabilities });
|
|
12965
|
+
});
|
|
12966
|
+
// tasks β μ§ν μ€ task μΆ©λ
|
|
12967
|
+
(hits.tasks || []).slice(0, 3).forEach(tsk => {
|
|
12968
|
+
if (tsk.status && /in-progress|μ§ν/.test(String(tsk.status))) {
|
|
12969
|
+
conflictHints.push({ kind: 'task-in-progress', id: tsk.id, title: tsk.title });
|
|
12970
|
+
}
|
|
12971
|
+
});
|
|
12972
|
+
// plan milestones β μ§ν μ€ milestone
|
|
12973
|
+
(hits.planMilestones || []).slice(0, 3).forEach(m => {
|
|
12974
|
+
if (m.status && /in-progress|μ§ν/.test(String(m.status))) {
|
|
12975
|
+
planConflicts.push({ kind: 'milestone-in-progress', id: m.id, title: m.title });
|
|
12976
|
+
}
|
|
12977
|
+
});
|
|
12978
|
+
// taskLogFails β κ³Όκ±° κ°μ ν€μλ μ€ν¨ νμ
|
|
12979
|
+
(hits.taskLogFails || []).slice(0, 3).forEach(f => {
|
|
12980
|
+
conflictHints.push({ kind: 'task-log-failure', preview: (f.preview || f.text || '').slice(0, 100) });
|
|
12981
|
+
});
|
|
12982
|
+
}
|
|
12983
|
+
} catch {}
|
|
12984
|
+
|
|
12985
|
+
// 3) reuse-map λ§€μΉ β κΈ°μ‘΄ capability λ±λ‘ ν보
|
|
12986
|
+
try {
|
|
12987
|
+
const reusePath = path.join(root, '.harness/reuse-map.md');
|
|
12988
|
+
if (exists(reusePath)) {
|
|
12989
|
+
const reuseLines = read(reusePath).split('\n');
|
|
12990
|
+
const tokens = lower.split(/\s+/).filter(t => t.length >= 3);
|
|
12991
|
+
for (const line of reuseLines) {
|
|
12992
|
+
if (!/^\| /.test(line)) continue; // ν
μ΄λΈ rowλ§
|
|
12993
|
+
const ll = line.toLowerCase();
|
|
12994
|
+
const matched = tokens.filter(t => ll.includes(t)).length;
|
|
12995
|
+
if (matched > 0) {
|
|
12996
|
+
const cols = line.split('|').map(s => s.trim());
|
|
12997
|
+
if (cols[1]) {
|
|
12998
|
+
reuseCandidates.push({ kind: 'reuse-map', capability: cols[1], where: cols[2] || '', note: cols[3] || '' });
|
|
12999
|
+
}
|
|
13000
|
+
}
|
|
13001
|
+
}
|
|
13002
|
+
}
|
|
13003
|
+
} catch {}
|
|
13004
|
+
|
|
13005
|
+
// 4) feature_graph β κ°μ μμ λ³κ²½ κ°λ₯μ±
|
|
13006
|
+
const featureConflicts = [];
|
|
13007
|
+
try {
|
|
13008
|
+
const fgPath = path.join(root, '.harness/feature_graph.md');
|
|
13009
|
+
if (exists(fgPath)) {
|
|
13010
|
+
const fg = read(fgPath);
|
|
13011
|
+
const tokens = lower.split(/\s+/).filter(t => t.length >= 4);
|
|
13012
|
+
// F-XXXX λ
Έλ λΌμΈ μΆμΆ
|
|
13013
|
+
const nodeBlocks = fg.split(/\n### /);
|
|
13014
|
+
for (const blk of nodeBlocks.slice(1)) {
|
|
13015
|
+
const bl = blk.toLowerCase();
|
|
13016
|
+
const matched = tokens.filter(t => bl.includes(t)).length;
|
|
13017
|
+
if (matched > 0) {
|
|
13018
|
+
const titleMatch = blk.match(/^([^\n]+)/);
|
|
13019
|
+
const idMatch = blk.match(/F-\d+/);
|
|
13020
|
+
if (titleMatch && idMatch) {
|
|
13021
|
+
featureConflicts.push({ kind: 'feature', id: idMatch[0], title: titleMatch[1].trim() });
|
|
13022
|
+
}
|
|
13023
|
+
}
|
|
13024
|
+
}
|
|
13025
|
+
}
|
|
13026
|
+
} catch {}
|
|
13027
|
+
|
|
13028
|
+
// 5) κΆμ₯ λ¨κ³ (μμ
μ νλ³)
|
|
13029
|
+
const recommendedSteps = {
|
|
13030
|
+
feature: [
|
|
13031
|
+
'1) leerness reuse find "<ν΅μ¬ capability>" β μ€λ³΅ ꡬν μ¬μ μ°¨λ¨',
|
|
13032
|
+
'2) leerness plan add "<milestone>" β μ§ν μΆμ ',
|
|
13033
|
+
'3) leerness contract verify SPEC.md src/<mod>.js β μ¬μ β ꡬν μΌμΉ κ²μ¦',
|
|
13034
|
+
'4) verify-claim --run-tests λ‘ evidence μ무ν'
|
|
13035
|
+
],
|
|
13036
|
+
bugfix: [
|
|
13037
|
+
'1) leerness brainstorm "<λ²κ·Έ ν€μλ>" β κ³Όκ±° κ°μ μμ lesson νμ',
|
|
13038
|
+
'2) leerness verify-claim T-XXX --strict-claims β λκ΄μ νμ μ¬μ κ°μ§',
|
|
13039
|
+
'3) verify-code --run-tests β μ¬ν + fix κ²μ¦',
|
|
13040
|
+
'4) leerness lesson save "<root cause>" β κ°μ μ€μ μ¬λ° μ°¨λ¨'
|
|
13041
|
+
],
|
|
13042
|
+
refactor: [
|
|
13043
|
+
'1) leerness reuse-map β μν₯ λ²μ νμ
',
|
|
13044
|
+
'2) leerness impact <file> β κ°ν/μ½ν μ°Έμ‘° λΆλ¦¬',
|
|
13045
|
+
'3) leerness contract verify β μΈλΆ μΈν°νμ΄μ€ 보쑴 νμΈ',
|
|
13046
|
+
'4) verify-code --run-tests + νκ· ν
μ€νΈ'
|
|
13047
|
+
],
|
|
13048
|
+
research: [
|
|
13049
|
+
'1) leerness brainstorm "<μ£Όμ >" β λμ 컨ν
μ€νΈ νμ',
|
|
13050
|
+
'2) leerness lessons --query "<μ£Όμ >" β κ³Όκ±° κ°μ μμ κ²°μ ',
|
|
13051
|
+
'3) leerness review <file> --persona research β κΉμ΄ κ²ν ',
|
|
13052
|
+
'4) leerness decision add "<κ²°λ‘ >" β νμ κ°λ₯νκ² μꡬν'
|
|
13053
|
+
],
|
|
13054
|
+
planning: [
|
|
13055
|
+
'1) leerness plan add "<milestone>" β λΆν΄ μμ',
|
|
13056
|
+
'2) leerness reuse-map β κΈ°μ‘΄ μμ μΈλ²€ν 리',
|
|
13057
|
+
'3) leerness agents recommend planning β sub-agent λΆλ°°',
|
|
13058
|
+
'4) leerness session close β κ²°μ μꡬν'
|
|
13059
|
+
],
|
|
13060
|
+
release: [
|
|
13061
|
+
'1) leerness health β production-ready νμΈ',
|
|
13062
|
+
'2) leerness audit + verify-code β 보μ + κ²μ',
|
|
13063
|
+
'3) leerness release bump + note + publish'
|
|
13064
|
+
],
|
|
13065
|
+
consistency: [
|
|
13066
|
+
'1) leerness audit β design/reuse/handoff μΌκ΄μ± κ²μ¬',
|
|
13067
|
+
'2) leerness consistency check β μ μ¬ μΌκ΄μ± μλ°',
|
|
13068
|
+
'3) leerness drift check --auto-fix β μλ ν볡'
|
|
13069
|
+
]
|
|
13070
|
+
}[estimatedType] || [];
|
|
13071
|
+
|
|
13072
|
+
// 6) ν¨μ¨ μ μ (μ μ© κ°λ₯ν sub-agent + skill)
|
|
13073
|
+
const efficiencyHints = [];
|
|
13074
|
+
if (reuseCandidates.length > 0) {
|
|
13075
|
+
efficiencyHints.push(`π κΈ°μ‘΄ μμ ${reuseCandidates.length}건 λ°κ²¬ β μ κ· κ΅¬ν μ μ¬μ¬μ© κ²ν κΆμ₯`);
|
|
13076
|
+
}
|
|
13077
|
+
if (conflictHints.length > 0) {
|
|
13078
|
+
efficiencyHints.push(`β μΆ©λ μ νΈ ${conflictHints.length}건 β κ³Όκ±° μ€ν¨ lesson / μ§ν μ€ task νμΈ νμ`);
|
|
13079
|
+
}
|
|
13080
|
+
if (planConflicts.length > 0) {
|
|
13081
|
+
efficiencyHints.push(`π μ§ν μ€ milestone ${planConflicts.length}건과 μμ κ²ΉμΉ¨ κ°λ₯ β plan μ λ ¬ κΆμ₯`);
|
|
13082
|
+
}
|
|
13083
|
+
if (featureConflicts.length > 0) {
|
|
13084
|
+
efficiencyHints.push(`πΈ Feature Graph ${featureConflicts.length}건 μμ κ²ΉμΉ¨ β μμ‘΄μ± μ¬μ νμΈ`);
|
|
13085
|
+
}
|
|
13086
|
+
// λ€μ€ μμ΄μ νΈ λΆλ°° μΆμ²
|
|
13087
|
+
if (estimatedType === 'feature' || estimatedType === 'planning') {
|
|
13088
|
+
efficiencyHints.push(`π₯ leerness agents recommend ${estimatedType} β μμ
μ νλ³ sub-agent λ§€ν νμ© κ°λ₯`);
|
|
13089
|
+
}
|
|
13090
|
+
if (efficiencyHints.length === 0) {
|
|
13091
|
+
efficiencyHints.push('β¨ μΆ©λ μ νΈ μμ β μ¦μ μ§ν μμ ');
|
|
13092
|
+
}
|
|
13093
|
+
|
|
13094
|
+
// 7) proceed κΆμ₯ (μΆ©λ critical μ false)
|
|
13095
|
+
const proceed = conflictHints.length < 3 && planConflicts.length === 0;
|
|
13096
|
+
|
|
13097
|
+
const dt = Date.now() - t0;
|
|
13098
|
+
const out = {
|
|
13099
|
+
request: text,
|
|
13100
|
+
estimatedType,
|
|
13101
|
+
conflicts: conflictHints,
|
|
13102
|
+
reuseCandidates,
|
|
13103
|
+
lessonsRecall,
|
|
13104
|
+
planConflicts,
|
|
13105
|
+
featureConflicts,
|
|
13106
|
+
recommendedSteps,
|
|
13107
|
+
efficiencyHints,
|
|
13108
|
+
proceed,
|
|
13109
|
+
proceedReason: proceed ? 'μμ β μΆ©λ μ νΈ < 3 + plan μΆ©λ 0' : 'β μΆ©λ critical β μ¬μ©μ νμΈ ν μ§ν',
|
|
13110
|
+
durationMs: dt
|
|
13111
|
+
};
|
|
13112
|
+
|
|
13113
|
+
try { _recordRun(root, { kind: 'review_request', estimatedType, conflicts: conflictHints.length, reuse: reuseCandidates.length, durationMs: dt, ok: true }); } catch {}
|
|
13114
|
+
|
|
13115
|
+
if (has('--json')) {
|
|
13116
|
+
log(JSON.stringify(out, null, 2));
|
|
13117
|
+
return;
|
|
13118
|
+
}
|
|
13119
|
+
|
|
13120
|
+
log(`# leerness review-request (1.9.176 μ¬μ κ²ν )`);
|
|
13121
|
+
log(`μμ²: "${text.slice(0, 200)}${text.length > 200 ? 'β¦' : ''}"`);
|
|
13122
|
+
log(`μΆμ μμ
μ ν: ${estimatedType}`);
|
|
13123
|
+
log('');
|
|
13124
|
+
if (conflictHints.length) {
|
|
13125
|
+
log(`## β μΆ©λ μ νΈ (${conflictHints.length})`);
|
|
13126
|
+
conflictHints.slice(0, 5).forEach(c => log(` - [${c.kind}] ${c.title || c.id || ''} ${c.preview || ''}`.trim()));
|
|
13127
|
+
log('');
|
|
13128
|
+
}
|
|
13129
|
+
if (reuseCandidates.length) {
|
|
13130
|
+
log(`## π μ¬μ¬μ© ν보 (${reuseCandidates.length}) β μ κ· κ΅¬ν μ κ²ν `);
|
|
13131
|
+
reuseCandidates.slice(0, 5).forEach(r => {
|
|
13132
|
+
if (r.kind === 'skill') log(` - [skill] ${r.id}${r.displayNameKo ? ' Β· ' + r.displayNameKo : ''}`);
|
|
13133
|
+
else if (r.kind === 'reuse-map') log(` - [reuse] ${r.capability} @ ${r.where}`);
|
|
13134
|
+
});
|
|
13135
|
+
log('');
|
|
13136
|
+
}
|
|
13137
|
+
if (lessonsRecall.length) {
|
|
13138
|
+
log(`## π§ κ³Όκ±° 컨ν
μ€νΈ (${lessonsRecall.length}) β κ΄λ ¨ κ²°μ /κ΅ν`);
|
|
13139
|
+
lessonsRecall.slice(0, 3).forEach(l => log(` - [${l.kind}] ${l.title || l.preview}`));
|
|
13140
|
+
log('');
|
|
13141
|
+
}
|
|
13142
|
+
if (planConflicts.length || featureConflicts.length) {
|
|
13143
|
+
log(`## π μ§ν μ€ μμ (${planConflicts.length + featureConflicts.length})`);
|
|
13144
|
+
planConflicts.forEach(m => log(` - [milestone] ${m.id}: ${m.title}`));
|
|
13145
|
+
featureConflicts.slice(0, 5).forEach(f => log(` - [feature] ${f.id}: ${f.title}`));
|
|
13146
|
+
log('');
|
|
13147
|
+
}
|
|
13148
|
+
log(`## π‘ ν¨μ¨ μ μ`);
|
|
13149
|
+
efficiencyHints.forEach(h => log(` ${h}`));
|
|
13150
|
+
log('');
|
|
13151
|
+
if (recommendedSteps.length) {
|
|
13152
|
+
log(`## π κΆμ₯ λ¨κ³ (${estimatedType})`);
|
|
13153
|
+
recommendedSteps.forEach(s => log(` ${s}`));
|
|
13154
|
+
log('');
|
|
13155
|
+
}
|
|
13156
|
+
log(`## βΆ μ§ν κΆμ₯: ${proceed ? 'β μ§ν μμ ' : 'β μ¬μ©μ νμΈ νμ'}`);
|
|
13157
|
+
log(` μ¬μ : ${out.proceedReason}`);
|
|
13158
|
+
log(` λΆμ μμ: ${dt}ms`);
|
|
13159
|
+
}
|
|
13160
|
+
|
|
12828
13161
|
// 1.9.164: leerness which β μ§λ¨ λꡬ (ꡬλ²μ μΆ©λ / npx μΊμ / PATH μΆ©λ ν΄κ²°)
|
|
12829
13162
|
// μ¬μ©μκ° "μ΅μ λ²μ μλ μ ν¨" μμ¬ μ: μ€μ μ€ν μ€μΈ leerness μ κ²½λ‘ / λ²μ / npm μΊμ / PATH ν보 νμ.
|
|
12830
13163
|
function whichCmd() {
|
|
@@ -12906,7 +13239,7 @@ function whichCmd() {
|
|
|
12906
13239
|
}
|
|
12907
13240
|
|
|
12908
13241
|
function help() {
|
|
12909
|
-
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
|
|
13242
|
+
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
|
|
12910
13243
|
leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # νκ³ (1.9.13~1.9.16)
|
|
12911
13244
|
leerness insights [path] [--all-apps] [--include p1,p2] [--json] # λμ ν΅κ³ (1.9.13~1.9.16)
|
|
12912
13245
|
leerness brainstorm "<μ£Όμ >" [--all-apps] [--include p1,p2] [--json] # λΈλ μΈμ€ν λ° (1.9.13~1.9.16)
|
|
@@ -12988,6 +13321,13 @@ async function main() {
|
|
|
12988
13321
|
if (cmd === 'pc') return pcCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
12989
13322
|
|
|
12990
13323
|
if (cmd === 'lsp') return lspCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
13324
|
+
|
|
13325
|
+
// 1.9.176: leerness review-request "<request>" β μ¬μ©μ μμ² μ¬μ κ²ν (μ¬μ©μ λͺ
μ)
|
|
13326
|
+
// AI μμ΄μ νΈκ° 무쑰건 ꡬν μ μ μΆ©λ/μ¬μ¬μ©/ν¨μ¨/κΆμ₯ λ¨κ³ λΆμ.
|
|
13327
|
+
if (cmd === 'review-request' || cmd === 'review-req') {
|
|
13328
|
+
const reqText = args.slice(1).filter(x => !x.startsWith('-')).join(' ');
|
|
13329
|
+
return reviewRequestCmd(arg('--path', process.cwd()), reqText);
|
|
13330
|
+
}
|
|
12991
13331
|
if (cmd === 'contract' && args[1] === 'verify') return contractVerifyCmd(args[2], args[3]);
|
|
12992
13332
|
if (cmd === 'drift' && (args[1] === 'check' || !args[1])) return driftCheckCmd(args[2] || arg('--path', process.cwd()));
|
|
12993
13333
|
if (cmd === 'usage' && (args[1] === 'stats' || !args[1])) return usageStatsCmd(args[2] || arg('--path', process.cwd()));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.177",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|