leerness 1.9.192 โ†’ 1.9.194

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,113 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.194 โ€” 2026-05-21
4
+
5
+ **๐ŸŽฏ E์ถ• (๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€) ๋ณด๊ฐ• โ€” handoff ๋‹ค์Œ ๋‹จ๊ณ„ ์ž๋™ ์ œ์•ˆ + 24h+ ๋ฌด์ง„์ฒ™ lazy ๊ฐ์ง€.**
6
+
7
+ ์ž์œจ ๋ชจ๋“œ 124 ๋ผ์šด๋“œ. 1.9.192 C์ถ• / 1.9.193 B์ถ• ๋ณด๊ฐ•์— ์ด์–ด **E์ถ• (9/10 โ†’ ๋ชฉํ‘œ 9.5/10)** ๋ณด๊ฐ•.
8
+
9
+ ### ์‚ฌ์šฉ์ž ์˜๋„ ์ •๋ ฌ (1.9.191 verbatim)
10
+ > *"๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€๋“ฑ๋“ฑ ์ตœ๊ณ ์˜ ๋„๊ตฌ"*
11
+
12
+ ### 1. handoff ๋‹ค์Œ ๋‹จ๊ณ„ ์ž๋™ ์ œ์•ˆ (E์ถ• ํ•ต์‹ฌ)
13
+ - ํ˜„์žฌ in-progress task description + Memory Surface (decisions/lessons/plan) ์กฐํ•ฉ โ†’ ๋‹ค์Œ ๋‹จ๊ณ„ 1-3๊ฐœ ์ œ์•ˆ
14
+ - ์‚ฌ์šฉ์ž/AI ๊ฐ€ "Next Exact Step" ์„ ์ง์ ‘ ์ฑ„์šฐ์ง€ ์•Š์•„๋„ ์ฆ‰์‹œ ๋…ธ์ถœ
15
+ - **7๊ฐœ ํœด๋ฆฌ์Šคํ‹ฑ**:
16
+ 1. lessons.md ์‹คํŒจ ๋งค์นญ โ†’ ํšŒํ”ผ ์ „๋žต ์ ์šฉ (`leerness lessons --auto`)
17
+ 2. plan.md milestone ๋งค์นญ โ†’ milestone ๊ฒ€์ฆ (`leerness plan list`)
18
+ 3. decisions.md ๊ฒฐ์ • ๋งค์นญ โ†’ ์˜ํ–ฅ ํ™•์ธ (`leerness decision list`)
19
+ 4. review-evidence.md ๋ถ€์žฌ โ†’ e2e ์‹คํ–‰ (`node ./scripts/e2e.js`)
20
+ 5. 24h+ ์ •์ฒด โ†’ task status ๊ฐฑ์‹  (`leerness task update`)
21
+ 6. ๋ฒ„์ „ ๋ณ€๋™ task โ†’ CHANGELOG/README ๊ฐฑ์‹  ํ™•์ธ (`leerness whats-new`)
22
+ 7. stress test ๋ˆ„๋ฝ โ†’ ์ƒˆ stress ์ž‘์„ฑ ๊ถŒ์žฅ
23
+ - ๋„๊ธฐ: `--no-next-actions` ๋˜๋Š” `LEERNESS_NO_NEXT_ACTIONS=1`
24
+
25
+ ### 2. 24h+ ๋ฌด ์ง„์ฒ™ lazy ๊ฐ์ง€
26
+ - progress-tracker.md mtime โ‰ฅ 24h โ†’ `## โš  ์ง„์ฒ™ ์ •์ฒด ๊ฐ์ง€` ์ž๋™ ์ถœ๋ ฅ
27
+ - ํ˜„์žฌ in-progress task ID + request ์š”์•ฝ ํ‘œ์‹œ
28
+ - ๊ถŒ์žฅ ๋ช…๋ น: `leerness task update <id> --status` / `leerness lazy detect --json`
29
+ - ๋„๊ธฐ: `--no-lazy-warn` ๋˜๋Š” `LEERNESS_NO_LAZY_WARN=1`
30
+
31
+ ### 3. ๋ˆ„์  ํšŒ๊ท€ (1.9.188~193) โ€” ๋ชจ๋‘ ์œ ์ง€
32
+ - [1.9.193] agents multi consensus โ†’ lessons.md ์ž๋™
33
+ - [1.9.192] _loadOfficialSkillCache + 24h ์บ์‹œ
34
+ - [1.9.191] ๊ตฌ์กฐ ์ตœ์ ํ™” ๋ณด๊ณ ์„œ 88/100
35
+ - [1.9.190] _selectOne/_selectMany Ctrl+C ์ฆ‰์‹œ ์ข…๋ฃŒ
36
+ - [1.9.189] _showSlashCommandList + Tab cycle ํ•œ ์ค„ ๊ฐฑ์‹ 
37
+ - [1.9.188] stdin prompt ์ „๋‹ฌ
38
+
39
+ ### 4. stress-v139 โ€” 15/15 PASS
40
+ - E์ถ• ๋ณด๊ฐ• (6: ํ•จ์ˆ˜ + ์„น์…˜ + ์ž„์‹œ ์›Œํฌ์ŠคํŽ˜์ด์Šค ํ†ตํ•ฉ) + ์„ฑ๋Šฅ (2) + ๋ˆ„์  ํšŒ๊ท€ (7)
41
+ - ์ž„์‹œ ์›Œํฌ์ŠคํŽ˜์ด์Šค mtime 25h ๊ฐ•์ œ โ†’ โš  ์ง„์ฒ™ ์ •์ฒด ๊ฐ์ง€ โœ“
42
+ - ์„ฑ๋Šฅ: --version cold start avg **479 ms** ยท MCP 54 ๋„๊ตฌ **416 ms**
43
+
44
+ ### 5. 5์ถ• ๋งคํŠธ๋ฆญ์Šค ๋ณ€๋™
45
+ | ์ถ• | 1.9.193 | 1.9.194 | ฮ” |
46
+ |---|---|---|---|
47
+ | E. ๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€ | 9/10 | **9.5/10** | +0.5 (๋‹ค์Œ ๋‹จ๊ณ„ ์ž๋™ ์ œ์•ˆ + lazy ๊ฐ์ง€) |
48
+ | ์ข…ํ•ฉ | 45.5/50 (91%) | **46/50 (92%)** | +1% |
49
+
50
+ ### 6. ์ž๋™ release ํ๋ฆ„
51
+ - main ์ž๋™ push **56 ๋ผ์šด๋“œ ์—ฐ์†** (1.9.140~194)
52
+ - npm publish ์ž๋™ (1.9.178~)
53
+
54
+ ---
55
+
56
+ ## 1.9.193 โ€” 2026-05-21
57
+
58
+ **๐Ÿค– B์ถ• (๋ฉ€ํ‹ฐ Sub-Agent ์˜ค์ผ€์ŠคํŠธ๋ผ) ๋ณด๊ฐ• โ€” agents multi consensus ๊ฒฐ๊ณผ ์ž๋™ lessons.md ์ €์žฅ + ์บ์‹œ 7์ผ stale hint.**
59
+
60
+ ์ž์œจ ๋ชจ๋“œ 123 ๋ผ์šด๋“œ. 1.9.192 C์ถ• ๋ณด๊ฐ•์— ์ด์–ด, 5์ถ• ๋งคํŠธ๋ฆญ์Šค์—์„œ ๋‘ ๋ฒˆ์งธ๋กœ ์ ์ˆ˜๊ฐ€ ๋‚ฎ์•˜๋˜ **B์ถ• (8.5/10 โ†’ ๋ชฉํ‘œ 9/10)** ๋ณด๊ฐ•.
61
+
62
+ ### ์‚ฌ์šฉ์ž ์˜๋„ ์ •๋ ฌ (1.9.191 verbatim)
63
+ > *"๋ฉ€ํ‹ฐ ์„œ๋ธŒ ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ผ ... ์ตœ๊ณ ์˜ ๋„๊ตฌ"*
64
+
65
+ ### 1. agents multi --execute โ†’ lessons.md ์ž๋™ ์ €์žฅ (B์ถ• ํ•ต์‹ฌ)
66
+ - ๋งค `agents multi --execute` ํ˜ธ์ถœ ์‹œ consensus best agent + score ๊ฐ€ `.harness/lessons.md`์— ๊ธฐ๋ก
67
+ - ๊ฐ™์€ keyword ์žฌ๋ฐœ ์‹œ handoff lessons auto-recall (1.9.56)๊ฐ€ ์ž๋™ ๋งค์นญ โ†’ ๊ณผ๊ฑฐ best agent ์šฐ์„  ์‹œ๋„
68
+ - ๋„๊ธฐ: `LEERNESS_NO_MULTIAGENT_LESSON=1`
69
+
70
+ **lesson ๋ธ”๋ก ํฌ๋งท:**
71
+ ```markdown
72
+ ### 2026-05-21 multi-agent consensus โ€” best=claude (1.9.193)
73
+ - task: ...
74
+ - agents: claude, codex, gemini (3/3 success)
75
+ - best agent: claude, score=0.873
76
+ - others: codex=0.71, gemini=0.65
77
+ - lesson: ๊ฐ™์€ keyword ์žฌ๋ฐœ ์‹œ claude ์šฐ์„  ์‹œ๋„ (multi-signal consensus ์ž…์ฆ)
78
+ ```
79
+
80
+ ### 2. skill auto-cache age 7์ผ stale ๊ฐ•์กฐ (1.9.192 ํ›„์†)
81
+ - handoff body์—์„œ ์บ์‹œ age โ‰ฅ 7์ผ (veryStale) ์‹œ `โš  7์ผ+` ํ‘œ์‹œ
82
+ - ๊ฐฑ์‹  ๊ถŒ์žฅ hint: `1.9.193 7์ผ+ stale` ๋˜๋Š” `24h+ expired` ๋ช…์‹œ
83
+ - ์‚ฌ์šฉ์ž๊ฐ€ "์˜ค๋ž˜๋œ catalog ์ž„์„ ์ธ์ง€" โ†’ ์ž๋™ ๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€
84
+
85
+ ### 3. ๋ˆ„์  ํšŒ๊ท€ (1.9.187~192) โ€” ๋ชจ๋‘ ์œ ์ง€
86
+ - [1.9.192] _loadOfficialSkillCache + 24h ์บ์‹œ
87
+ - [1.9.191] ๊ตฌ์กฐ ์ตœ์ ํ™” ๋ณด๊ณ ์„œ 88/100
88
+ - [1.9.190] _selectOne/_selectMany Ctrl+C ์ฆ‰์‹œ ์ข…๋ฃŒ
89
+ - [1.9.189] _showSlashCommandList + Tab cycle ํ•œ ์ค„ ๊ฐฑ์‹ 
90
+ - [1.9.188] stdin prompt ์ „๋‹ฌ (useStdinForPrompt)
91
+ - [1.9.187] _loadLeernessConfig (.harness/leerness-config.json)
92
+
93
+ ### 4. stress-v138 โ€” 16/16 PASS
94
+ - consensus auto-lessons (3) + cache age hint (2) + 1.9.192 ์ž”์กด (2)
95
+ - ์„ฑ๋Šฅ: --version cold start avg **396 ms** (376/382/430) ยท MCP 54 ๋„๊ตฌ **369 ms**
96
+ - ๋ˆ„์  ํšŒ๊ท€ 1.9.187~192 (7)
97
+
98
+ ### 5. 5์ถ• ๋งคํŠธ๋ฆญ์Šค ๋ณ€๋™
99
+ | ์ถ• | 1.9.192 | 1.9.193 | ฮ” |
100
+ |---|---|---|---|
101
+ | B. ๋ฉ€ํ‹ฐ Sub-Agent ์˜ค์ผ€์ŠคํŠธ๋ผ | 8.5/10 | **9/10** | +0.5 (consensus ์ž๋™ lessons โ†’ ํ•™์Šต ์‚ฌ์ดํด ์™„์„ฑ) |
102
+ | C. ๊ณต์‹ ํ‘œ์ค€ ์Šคํ‚ฌ ์ž๋™ ํ™œ์šฉ | 9/10 | 9/10 | (์œ ์ง€) |
103
+ | ์ข…ํ•ฉ | 45/50 (90%) | **45.5/50 (91%)** | +1% |
104
+
105
+ ### 6. ์ž๋™ release ํ๋ฆ„
106
+ - main ์ž๋™ push **55 ๋ผ์šด๋“œ ์—ฐ์†** (1.9.140~193)
107
+ - npm publish ์ž๋™ (1.9.178~)
108
+
109
+ ---
110
+
3
111
  ## 1.9.192 โ€” 2026-05-21
4
112
 
5
113
  **๐ŸŒ C์ถ• (๊ณต์‹ ํ‘œ์ค€ ์Šคํ‚ฌ ์ž๋™ ํ™œ์šฉ) ๋ณด๊ฐ• โ€” handoff์— ๊ณต์‹ organization catalog ์ž๋™ ๋…ธ์ถœ + 24h ์บ์‹œ.**
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ์˜ ๊ฑฐ์ง“ ์™„๋ฃŒยท์ค‘๋ณตยท๋ง๊ฐยท์ถฉ๋Œ์„ ๋ง‰์•„์ฃผ๋Š” ๊ฒ€์ˆ˜ยท๊ธฐ์–ตยทํ˜‘์—… CLI ํ•˜๋„ค์Šค.**
4
4
 
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.192-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v137-17%2F17-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-122-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-54_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/๋ชฉ์ _๋งคํŠธ๋ฆญ์Šค-90%2F100_(5์ถ•)-brightgreen)]() [![official-skills](https://img.shields.io/badge/official_skills-handoff_์ž๋™_๋…ธ์ถœ-success)]() [![perf](https://img.shields.io/badge/cold_start-398ms-success)]() [![install](https://img.shields.io/badge/npm_i_leerness-์ฆ‰์‹œ_์‚ฌ์šฉ_๊ฐ€๋Šฅ-success)]() [![sandbox](https://img.shields.io/badge/runCommandSafe-cwd_jail%2Benv_scrub-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
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.194-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v139-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-54-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-124-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-56_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/๋ชฉ์ _๋งคํŠธ๋ฆญ์Šค-92%2F100_(5์ถ•)-brightgreen)]() [![next-actions](https://img.shields.io/badge/handoff-next_actions_์ž๋™-success)]() [![perf](https://img.shields.io/badge/cold_start-479ms-success)]() [![install](https://img.shields.io/badge/npm_i_leerness-์ฆ‰์‹œ_์‚ฌ์šฉ_๊ฐ€๋Šฅ-success)]() [![sandbox](https://img.shields.io/badge/runCommandSafe-cwd_jail%2Benv_scrub-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
6
6
 
7
7
  ```
8
8
  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
@@ -12,9 +12,9 @@
12
12
  โ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ• โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ• โ•šโ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ•‘
13
13
  โ•‘ โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•‘ โ•‘
14
14
  โ•‘ โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ• โ•šโ•โ•โ•šโ•โ• โ•šโ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ• โ•‘
15
- โ•‘ v1.9.192 AI Agent Reliability Harness + Sandbox โ•‘
15
+ โ•‘ v1.9.194 AI Agent Reliability Harness + Sandbox โ•‘
16
16
  โ•‘ verify ยท remember ยท orchestrate ยท audit ยท sandbox ยท drift โ•‘
17
- โ•‘ ๐ŸŒ official skills handoff ์ž๋™ ยท ๋งคํŠธ๋ฆญ์Šค 90/100 ยท 122 ๋ผ์šด๋“œ โ•‘
17
+ โ•‘ ๐ŸŽฏ handoff next-actions ์ž๋™ ์ œ์•ˆ ยท 92/100 ยท 124 ๋ผ์šด๋“œ โ•‘
18
18
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
19
19
  ```
20
20
 
package/bin/harness.js CHANGED
@@ -7,7 +7,7 @@ const cp = require('child_process');
7
7
  const os = require('os'); // 1.9.178: _publishToNpm ์—์„œ os.tmpdir() ์‚ฌ์šฉ (์ „์—ญ import)
8
8
  const readline = require('readline');
9
9
 
10
- const VERSION = '1.9.192';
10
+ const VERSION = '1.9.194';
11
11
 
12
12
  // 1.9.184: DEP0190 (child_process shell: true) deprecation warning ์–ต์ œ (์‚ฌ์šฉ์ž ๋ช…์‹œ).
13
13
  // leerness ๋Š” cross-platform PATH resolution ์„ ์œ„ํ•ด shell: true ๋ฅผ ์˜๋„์ ์œผ๋กœ ์‚ฌ์šฉ (claude.cmd / ollama.cmd ๋“ฑ Windows .cmd ์ฒ˜๋ฆฌ).
@@ -1662,6 +1662,112 @@ async function skillAutoCacheCmd(root, sub) {
1662
1662
  if (c.expired) log(` โ†’ ๊ฐฑ์‹ : leerness skill auto-cache refresh`);
1663
1663
  }
1664
1664
 
1665
+ // 1.9.194: E์ถ• (๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€) โ€” handoff ์—์„œ ๋‹ค์Œ ๋‹จ๊ณ„ 1-3๊ฐœ ์ž๋™ ์ œ์•ˆ
1666
+ // ํ˜„์žฌ in-progress task description + Memory Surface (decisions/lessons/plan) ์กฐํ•ฉ โ†’
1667
+ // "๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋ฌด์—‡์„ ํ• ์ง€" ์ถ”๋ก  (์‚ฌ์šฉ์ž/AI ์ง์ ‘ ์ž…๋ ฅ ์—†์ด ์ฆ‰์‹œ ๋…ธ์ถœ)
1668
+ // ์•Œ๊ณ ๋ฆฌ์ฆ˜:
1669
+ // 1) lessons.md ์— keyword ๋งค์นญ + ์‹คํŒจ/๋กค๋ฐฑ ํ‚ค์›Œ๋“œ โ†’ "ํšŒํ”ผ ์ „๋žต ์ ์šฉ"
1670
+ // 2) plan.md ์— keyword ๋งค์นญ + M-XXXX โ†’ "๊ณ„ํš milestone ๊ฒ€์ฆ"
1671
+ // 3) decisions.md ์— keyword ๋งค์นญ โ†’ "๊ฒฐ์ • N ์˜ํ–ฅ ํ™•์ธ"
1672
+ // 4) review-evidence.md ๋ถ€์žฌ โ†’ "verify-code ๋˜๋Š” e2e ์‹คํ–‰"
1673
+ // 5) progress-tracker.md 24h+ ์ •์ฒด โ†’ "task status ๊ฐฑ์‹ "
1674
+ // 6) CHANGELOG ๋ณด๊ฐ• ๋ถ€์žฌ โ†’ "๋ฒ„์ „ ๋ณ€๊ฒฝ ์‹œ CHANGELOG ๊ฐฑ์‹ "
1675
+ // 7) stress-vXXX ๋ˆ„๋ฝ โ†’ "stress test ์ž‘์„ฑ"
1676
+ // 1.9.116 brainstorm ํšŒ์ˆ˜์™€ ๋‹ค๋ฅธ ์ : brainstorm ์€ "๊ด€๋ จ hits ํšŒ์ˆ˜" / next-actions ๋Š” "๋‹ค์Œ ์‹คํ–‰ ๋ช…๋ น ์ œ์•ˆ"
1677
+ function _suggestNextActions(root, latestRow, keyword) {
1678
+ const actions = [];
1679
+ const taskText = String(latestRow.request || '').toLowerCase();
1680
+ const fuzzyRe = keyword ? new RegExp(escapeRegex(keyword.slice(0, Math.max(4, Math.floor(keyword.length * 0.7)))), 'i') : null;
1681
+
1682
+ // 1) lessons.md ์‹คํŒจ ๋งค์นญ โ†’ ํšŒํ”ผ ์ „๋žต
1683
+ try {
1684
+ if (fuzzyRe && exists(lessonsPath(root))) {
1685
+ const lt = read(lessonsPath(root));
1686
+ const blocks = lt.split(/\n### /);
1687
+ const hits = blocks.filter(b => fuzzyRe.test(b) && /(์‹คํŒจ|fail|๋กค๋ฐฑ|๋ฒ„๊ทธ|incomplete)/i.test(b));
1688
+ if (hits.length > 0) {
1689
+ actions.push({ icon: '๐Ÿ›ก', title: `๊ณผ๊ฑฐ ์‹คํŒจ ํšŒํ”ผ โ€” lessons.md ์— "${keyword}" ๊ด€๋ จ ${hits.length}๊ฑด`, command: `leerness lessons --auto --path .` });
1690
+ }
1691
+ }
1692
+ } catch {}
1693
+
1694
+ // 2) plan.md milestone ๋งค์นญ โ†’ milestone ๊ฒ€์ฆ
1695
+ try {
1696
+ if (fuzzyRe && exists(planPath(root))) {
1697
+ const pt = read(planPath(root));
1698
+ const milestones = (pt.match(/^### (M-\d{4})\..*$/gm) || []).filter(l => fuzzyRe.test(l));
1699
+ if (milestones.length > 0) {
1700
+ const m = milestones[0].match(/M-\d{4}/);
1701
+ if (m) actions.push({ icon: '๐ŸŽฏ', title: `plan.md milestone ${m[0]} ๊ฒ€์ฆ โ€” "${keyword}" ๊ด€๋ จ`, command: `leerness plan list --filter "${keyword}"` });
1702
+ }
1703
+ }
1704
+ } catch {}
1705
+
1706
+ // 3) decisions.md ๊ฒฐ์ • ๋งค์นญ
1707
+ try {
1708
+ if (fuzzyRe && exists(decisionsPath(root))) {
1709
+ const dt = read(decisionsPath(root));
1710
+ const blocks = _extractDecisionBlocks(dt);
1711
+ const hits = blocks.filter(b => fuzzyRe.test(b));
1712
+ if (hits.length > 0) {
1713
+ actions.push({ icon: '๐Ÿ’ญ', title: `decisions.md "${keyword}" ๊ด€๋ จ ๊ฒฐ์ • ${hits.length}๊ฑด ์˜ํ–ฅ ํ™•์ธ`, command: `leerness decision list --filter "${keyword}"` });
1714
+ }
1715
+ }
1716
+ } catch {}
1717
+
1718
+ // 4) review-evidence.md ๋ถ€์žฌ โ†’ e2e
1719
+ try {
1720
+ if (!exists(evidencePath(root)) || fs.statSync(evidencePath(root)).size < 100) {
1721
+ actions.push({ icon: '๐Ÿงช', title: `review-evidence.md ๋น„์–ด์žˆ์Œ โ€” e2e ๋˜๋Š” verify-code ์‹คํ–‰`, command: `node ./scripts/e2e.js` });
1722
+ }
1723
+ } catch {}
1724
+
1725
+ // 5) 24h+ ์ •์ฒด โ†’ task status ๊ฐฑ์‹  (handoff lazy-warn ๊ณผ ๋ณ„๊ฐœ โ€” ๋‹ค์Œ ๋‹จ๊ณ„ ๋ช…๋ น)
1726
+ try {
1727
+ const pp = progressPath(root);
1728
+ if (exists(pp)) {
1729
+ const ageHours = Math.floor((Date.now() - fs.statSync(pp).mtimeMs) / 3600000);
1730
+ if (ageHours >= 24 && latestRow.id) {
1731
+ actions.push({ icon: '๐Ÿ”„', title: `progress-tracker ${ageHours}h ์ •์ฒด โ€” task ${latestRow.id} status ๊ฐฑ์‹ `, command: `leerness task update ${latestRow.id} --status completed` });
1732
+ }
1733
+ }
1734
+ } catch {}
1735
+
1736
+ // 6) CHANGELOG / README ๋ฒ„์ „ ์ผ์น˜ ํ™•์ธ (1.9.X bump ํ›„ ์ž์ฃผ ๋ˆ„๋ฝ๋˜๋Š” ๋‹จ๊ณ„)
1737
+ try {
1738
+ if (/(\d\.\d\.\d+)/.test(taskText) || /(bump|version|release)/i.test(taskText)) {
1739
+ actions.push({ icon: '๐Ÿ“', title: `๋ฒ„์ „ ๋ณ€๋™ task โ€” CHANGELOG.md / README.md ๊ฐฑ์‹  ํ™•์ธ`, command: `node ./bin/harness.js whats-new .` });
1740
+ }
1741
+ } catch {}
1742
+
1743
+ // 7) stress test ๋ˆ„๋ฝ (์ž์œจ ๋ผ์šด๋“œ ์ž์ฃผ ๋ˆ„๋ฝ)
1744
+ try {
1745
+ const stressDir = path.resolve(root, '..', '_apps', 'leerness-stress', 'bin');
1746
+ if (exists(stressDir)) {
1747
+ const files = fs.readdirSync(stressDir).filter(f => /^stress-v\d+\.js$/.test(f));
1748
+ if (files.length > 0) {
1749
+ const versions = files.map(f => Number(f.match(/v(\d+)/)[1])).sort((a, b) => b - a);
1750
+ const latest = versions[0];
1751
+ // ํ˜„์žฌ ๋ผ์šด๋“œ = 1.9.X ์—์„œ stress-v(X-55) ์ •๋„? ๋‹จ์ˆœํžˆ ์ตœ์‹  stress ๊ฐ€ 7์ผ+ ์˜ค๋ž˜๋˜๋ฉด ๊ถŒ์žฅ
1752
+ const latestFile = path.join(stressDir, `stress-v${latest}.js`);
1753
+ const ageHours = Math.floor((Date.now() - fs.statSync(latestFile).mtimeMs) / 3600000);
1754
+ if (ageHours >= 24 && /(bump|version|๋ณด๊ฐ•|์ถ”๊ฐ€|๊ธฐ๋Šฅ)/.test(taskText)) {
1755
+ actions.push({ icon: '๐Ÿงฌ', title: `stress-v${latest} ๋งˆ์ง€๋ง‰ ๊ฐฑ์‹  ${ageHours}h ์ „ โ€” ์ƒˆ stress test ์ž‘์„ฑ ๊ถŒ์žฅ`, command: `node _apps/leerness-stress/bin/stress-v${latest+1}.js` });
1756
+ }
1757
+ }
1758
+ }
1759
+ } catch {}
1760
+
1761
+ // ์ค‘๋ณต ์ œ๊ฑฐ (icon+title ๊ธฐ์ค€) + top 3
1762
+ const seen = new Set();
1763
+ return actions.filter(a => {
1764
+ const key = a.icon + a.title.slice(0, 30);
1765
+ if (seen.has(key)) return false;
1766
+ seen.add(key);
1767
+ return true;
1768
+ }).slice(0, 3);
1769
+ }
1770
+
1665
1771
  // 1.9.182: handoff ์ปจํ…์ŠคํŠธ (ํ˜„์žฌ in-progress task) ์—์„œ ์ž๋™ query ์ถ”์ถœ
1666
1772
  function _autoInstallQueryFromHandoff(root) {
1667
1773
  try {
@@ -3524,6 +3630,7 @@ function handoff(root) {
3524
3630
  // 1.9.192: ๊ณต์‹ organization skill catalog ์ž๋™ ๋งค์นญ (C์ถ• ๋ณด๊ฐ• โ€” ์‚ฌ์šฉ์ž ์˜๋„)
3525
3631
  // "๊ณต์‹ ํ‘œ์ค€ํ™”๋œ ์Šคํ‚ฌ์„ ์ ์žฌ์ ์†Œ๋กœ ์ž๋™ ํ™œ์šฉ ... ์ตœ๊ณ ์˜ ๋„๊ตฌ" โ€” handoff ์‹œ keyword ๊ธฐ๋ฐ˜ ์ž๋™ ์ถ”์ฒœ
3526
3632
  // ์บ์‹œ (.harness/skill-auto-cache.json, 24h TTL) ์‚ฌ์šฉ โ†’ GitHub API ๋ถ€๋‹ด X
3633
+ // 1.9.193: cache age > 7์ผ โ†’ ์ž๋™ refresh ๊ถŒ์žฅ hint ๊ฐ•ํ™”
3527
3634
  // ๋„๊ธฐ: --no-official-skills ๋˜๋Š” LEERNESS_NO_OFFICIAL_SKILLS=1
3528
3635
  if (!has('--no-official-skills') && !has('--quiet') && process.env.LEERNESS_NO_OFFICIAL_SKILLS !== '1') {
3529
3636
  try {
@@ -3532,14 +3639,18 @@ function handoff(root) {
3532
3639
  const isTty = process.stdout && process.stdout.isTTY;
3533
3640
  const cyan = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
3534
3641
  const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3642
+ const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
3535
3643
  const cacheAge = ofm.ageHours != null ? (ofm.ageHours < 24 ? `${ofm.ageHours}h` : `${Math.floor(ofm.ageHours/24)}d`) : '?';
3536
- log(cyan(`## ๐ŸŒ ๊ณต์‹ organization ์Šคํ‚ฌ ์ž๋™ ๋งค์นญ (1.9.192) โ€” ํ‚ค์›Œ๋“œ "${keyword}"`));
3537
- log(dim(` vercel-labs/anthropics ๋“ฑ catalog ์บ์‹œ ${cacheAge}${ofm.expired ? ' โš  ๋งŒ๋ฃŒ' : ''} ยท ${ofm.total}/${ofm.cacheTotal}๊ฑด ๋งค์นญ`));
3644
+ // 1.9.193: cache age 7์ผ ์ด์ƒ์ด๋ฉด ๊ฐ•์กฐ ํ‘œ์‹œ (week stale)
3645
+ const veryStale = ofm.ageHours != null && ofm.ageHours >= 24 * 7;
3646
+ log(cyan(`## ๐ŸŒ ๊ณต์‹ organization ์Šคํ‚ฌ ์ž๋™ ๋งค์นญ (1.9.192/193) โ€” ํ‚ค์›Œ๋“œ "${keyword}"`));
3647
+ const ageLabel = veryStale ? yel(`${cacheAge} โš  7์ผ+`) : (ofm.expired ? yel(`${cacheAge} โš  ๋งŒ๋ฃŒ`) : `${cacheAge} โœ“`);
3648
+ log(dim(` vercel-labs/anthropics ๋“ฑ catalog ์บ์‹œ ${ageLabel} ยท ${ofm.total}/${ofm.cacheTotal}๊ฑด ๋งค์นญ`));
3538
3649
  for (const e of ofm.entries) {
3539
3650
  log(dim(` โ€ข [${e.preset || e.source || '?'}] ${e.name} โ€” ${(e.description || '').slice(0, 70)}`));
3540
3651
  }
3541
3652
  log(dim(` โ†’ ์„ค์น˜: leerness skill auto-install --yes`));
3542
- if (ofm.expired) log(dim(` โ†’ ๊ฐฑ์‹ : leerness skill auto-cache refresh`));
3653
+ if (ofm.expired || veryStale) log(yel(` โ†’ ๊ฐฑ์‹  ๊ถŒ์žฅ: leerness skill auto-cache refresh (1.9.193 ${veryStale ? '7์ผ+ stale' : '24h+ expired'})`));
3543
3654
  log('');
3544
3655
  } else if (ofm.cacheTotal === 0) {
3545
3656
  // ์บ์‹œ ์—†์Œ โ€” ์ฒซ ์‚ฌ์šฉ ์•ˆ๋‚ด
@@ -3552,6 +3663,51 @@ function handoff(root) {
3552
3663
  }
3553
3664
  } catch {}
3554
3665
  }
3666
+ // 1.9.194: E์ถ• (๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€) ๋ณด๊ฐ• โ€” handoff ๋‹ค์Œ ๋‹จ๊ณ„ 1-3๊ฐœ ์ž๋™ ์ œ์•ˆ
3667
+ // ํ˜„์žฌ in-progress task description + Memory Surface (decisions/lessons/plan) ์กฐํ•ฉ โ†’
3668
+ // "๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋ฌด์—‡์„ ํ• ์ง€" 3๊ฐœ๋ฅผ ์ฆ‰์‹œ ์ œ์•ˆ (์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ฑ„์šฐ์ง€ ์•Š์•„๋„ AI์—๊ฒŒ ๋…ธ์ถœ๋จ)
3669
+ // skill installed ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ โ€” keyword ๋งŒ ์žˆ์œผ๋ฉด ๋™์ž‘ (๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€๋Š” ๋ชจ๋“  ์›Œํฌ์ŠคํŽ˜์ด์Šค ํ•„์ˆ˜)
3670
+ // ๋„๊ธฐ: --no-next-actions ๋˜๋Š” LEERNESS_NO_NEXT_ACTIONS=1
3671
+ if (!has('--no-next-actions') && !has('--quiet') && process.env.LEERNESS_NO_NEXT_ACTIONS !== '1') {
3672
+ try {
3673
+ const actions = _suggestNextActions(root, latestRow, keyword);
3674
+ if (actions.length > 0) {
3675
+ const isTty = process.stdout && process.stdout.isTTY;
3676
+ const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
3677
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3678
+ log(grn(`## ๐ŸŽฏ ๋‹ค์Œ ๋‹จ๊ณ„ ์ž๋™ ์ œ์•ˆ (1.9.194 E์ถ• โ€” ๊ฒŒ์œผ๋ฆ„ ๋ฐฉ์ง€) โ€” ํ‚ค์›Œ๋“œ "${keyword}"`));
3679
+ for (const a of actions) {
3680
+ log(dim(` ${a.icon} ${a.title}`));
3681
+ if (a.command) log(dim(` \`${a.command}\``));
3682
+ }
3683
+ log(dim(` โ†’ ์ง์ ‘ ์ž…๋ ฅ: leerness next-action add "<text>"`));
3684
+ log('');
3685
+ }
3686
+ } catch {}
3687
+ }
3688
+ // 1.9.194: 24h+ ๋ฌด ์ง„์ฒ™ lazy ๊ฐ์ง€ โ€” progress-tracker mtime ๊ธฐ๋ฐ˜
3689
+ // ํ˜„์žฌ in-progress task ๊ฐ€ 24h ์ด์ƒ ๋ณ€๋™ ์—†์œผ๋ฉด "lazy ์˜์‹ฌ" hint
3690
+ // ๋„๊ธฐ: --no-lazy-warn ๋˜๋Š” LEERNESS_NO_LAZY_WARN=1
3691
+ if (!has('--no-lazy-warn') && !has('--quiet') && process.env.LEERNESS_NO_LAZY_WARN !== '1') {
3692
+ try {
3693
+ const pp = progressPath(root);
3694
+ if (exists(pp)) {
3695
+ const ageMs = Date.now() - fs.statSync(pp).mtimeMs;
3696
+ const ageHours = Math.floor(ageMs / 3600000);
3697
+ if (ageHours >= 24) {
3698
+ const isTty = process.stdout && process.stdout.isTTY;
3699
+ const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
3700
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3701
+ const ageLabel = ageHours < 48 ? `${ageHours}h` : `${Math.floor(ageHours/24)}d`;
3702
+ log(yel(`## โš  ์ง„์ฒ™ ์ •์ฒด ๊ฐ์ง€ (1.9.194 E์ถ•) โ€” progress-tracker ๋งˆ์ง€๋ง‰ ๋ณ€๋™ ${ageLabel} ์ „`));
3703
+ log(dim(` ํ˜„์žฌ in-progress task: ${latestRow.id} ${(latestRow.request || '').slice(0, 60)}`));
3704
+ log(dim(` โ†’ ๋ณ€๊ฒฝ: leerness task update ${latestRow.id} --status in-progress ๋˜๋Š” --status completed`));
3705
+ log(dim(` โ†’ ํšŒ๊ณ : leerness lazy detect --json`));
3706
+ log('');
3707
+ }
3708
+ }
3709
+ } catch {}
3710
+ }
3555
3711
  }
3556
3712
  }
3557
3713
  } catch {}
@@ -6047,6 +6203,21 @@ function agentsCmd(root, sub, ...args) {
6047
6203
  const block = `\n## ${today()} agents multi --execute (1.9.156)\n- task: ${task.slice(0, 200)}\n- agents: ${ready.map(x => x.def.id).join(', ')}\n- success: ${ok.length}/${ready.length}\n- best: ${best.agent} (score=${best.score.toFixed(3)})\n`;
6048
6204
  append(tlp, block);
6049
6205
  } catch {}
6206
+ // 1.9.193: B์ถ• (๋ฉ€ํ‹ฐ Sub-Agent ์˜ค์ผ€์ŠคํŠธ๋ผ) ๋ณด๊ฐ• โ€” consensus ๊ฒฐ๊ณผ๋ฅผ lessons.md ์— ์ž๋™ ๊ธฐ๋ก
6207
+ // ๊ฐ™์€ task ์žฌ์‹œ๋„ ์‹œ ๊ณผ๊ฑฐ best agent + score ๊ฐ€ handoff lessons auto-recall ์—์„œ ๋งค์นญ
6208
+ // ๋„๊ธฐ: LEERNESS_NO_MULTIAGENT_LESSON=1
6209
+ if (process.env.LEERNESS_NO_MULTIAGENT_LESSON !== '1') {
6210
+ try {
6211
+ const lp = lessonsPath(root);
6212
+ const lessonBlock = `\n### ${today()} multi-agent consensus โ€” best=${best.agent} (1.9.193)\n`
6213
+ + `- task: ${task.slice(0, 200)}\n`
6214
+ + `- agents: ${ready.map(x => x.def.id).join(', ')} (${ok.length}/${ready.length} success)\n`
6215
+ + `- best agent: ${best.agent}, score=${best.score.toFixed(3)}\n`
6216
+ + (scored.length > 1 ? `- others: ${scored.slice(1, 4).map(s => `${s.agent}=${s.score.toFixed(2)}`).join(', ')}\n` : '')
6217
+ + `- lesson: ๊ฐ™์€ keyword ์žฌ๋ฐœ ์‹œ ${best.agent} ์šฐ์„  ์‹œ๋„ (multi-signal consensus ์ž…์ฆ)\n`;
6218
+ append(lp, lessonBlock);
6219
+ } catch {}
6220
+ }
6050
6221
  }
6051
6222
  if (failures.length && !best) {
6052
6223
  process.exitCode = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.192",
3
+ "version": "1.9.194",
4
4
  "description": "Leerness: ๋น„ํŒŒ๊ดด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ์ž๋™ ๋ฒ„์ „ ๊ฐ์ง€ยท์—…๋ฐ์ดํŠธ, ๊ณ„ํš/์ง„ํ–‰/ํ•ธ๋“œ์˜คํ”„ ์ž๋™ํ™”, ๊ฒŒ์œผ๋ฆ„ยท์‹œํฌ๋ฆฟยท์ธ์ฝ”๋”ฉ ์ž๋™ ๊ฐ€๋“œ, Claude Code ์Šฌ๋ž˜์‹œ ํ†ตํ•ฉ์„ ๊ฐ–์ถ˜ ํ•œ๊ตญ์–ด ์šฐ์„  AI ๊ฐœ๋ฐœ ํ•˜๋„ค์Šค.",
5
5
  "keywords": [
6
6
  "leerness",