leerness 1.9.224 β†’ 1.9.226

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,79 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.226 β€” 2026-05-23
4
+
5
+ **πŸ”„ round-history CLI + handoff ν—€λ“œλΌμΈ λΌμš΄λ“œ μΉ΄μš΄ν„° + MCP 62번째 도ꡬ.**
6
+
7
+ ### 1. `leerness round-history` μƒˆ λͺ…λ Ή β€” 자율 λΌμš΄λ“œ 톡계
8
+ - git tag `v1.9.X` 기반 λˆ„μ  λΌμš΄λ“œ 카운트 (graceful fallback: git μ—†μœΌλ©΄ 0)
9
+ - 응닡: `{ currentVersion, roundCount, baselineVersion, latestTags[], nextMilestone, roundsToNextMilestone, firstTagAt, latestTagAt, daysActive, avgRoundsPerDay }`
10
+ - λ§ˆμΌμŠ€ν†€ μžλ™ 감지: 50/75/100/125/150/175/200/250/300/400/500
11
+ - `--json` μ˜΅μ…˜ (μ™ΈλΆ€ μžλ™ν™”)
12
+
13
+ ### 2. handoff ν—€λ“œλΌμΈ 17번째 μš”μ†Œ
14
+ - 5 λΌμš΄λ“œ 이상 λˆ„μ  μ‹œ `πŸ”„ R<N>` μžλ™ λ…ΈμΆœ
15
+ - λ‹€μŒ λ§ˆμΌμŠ€ν†€μ΄ 20 λΌμš΄λ“œ 이내일 λ•Œ: `πŸ”„ R182 β†’ R200 (18R λ‚¨μŒ)` κ°•μ‘°
16
+ - 자율 λͺ¨λ“œ 진행도 ν•œλˆˆμ—
17
+
18
+ ### 3. MCP 62번째 도ꡬ β€” `leerness_round_history`
19
+ - μ™ΈλΆ€ AIκ°€ "이 ν”„λ‘œμ νŠΈλŠ” μ–Όλ§ˆλ‚˜ 진행됐고 λ‹€μŒ λ§ˆμΌμŠ€ν†€κΉŒμ§€ λͺ‡ λΌμš΄λ“œ λ‚¨μ•˜λ‚˜?"λ₯Ό 회수
20
+ - MCP 61 β†’ 62 (+1)
21
+
22
+ ### 4. μ‹€ μΈ‘μ • (leerness 자체 ν”„λ‘œμ νŠΈ)
23
+ - λˆ„μ  λΌμš΄λ“œ: **182R** (baseline v1.9.6 β†’ v1.9.225)
24
+ - ν™œλ™ κΈ°κ°„: 14일 / 평균 **13 rounds/day**
25
+ - λ‹€μŒ λ§ˆμΌμŠ€ν†€: **R200 (18 λΌμš΄λ“œ λ‚¨μŒ)**
26
+
27
+ ### 5. λˆ„μ  νšŒκ·€ (1.9.207~225) β€” λͺ¨λ‘ μœ μ§€
28
+
29
+ ### 6. stress-v171 β€” 16/16 PASS
30
+ - 1.9.226 (7): VERSION + round-history CLI + --json + git μ—†λŠ” fallback + handoff ν—€λ“œλΌμΈ + MCP 62 등둝 + MCP μ‹€ 호좜
31
+ - μ„±λŠ₯ (2): cold_start avg 336ms / round-history 535ms
32
+ - λˆ„μ  νšŒκ·€ (7): 1.9.207~225
33
+
34
+ ### 7. μžλ™ release (88 λΌμš΄λ“œ main-push streak Β· 49 λΌμš΄λ“œ npm publish streak)
35
+
36
+ πŸ”„ **자율 λΌμš΄λ“œ 진행도 κ°€μ‹œν™”** β€” handoff ν•œ μ€„μ—μ„œ λ§ˆμΌμŠ€ν†€ 예츑 κ°€λŠ₯
37
+
38
+ ---
39
+
40
+ ## 1.9.225 β€” 2026-05-22
41
+
42
+ **πŸ”§ drift check --auto-fix delivered 톡합 + LEERNESS_AUTO_APPLY_DELIVERED env opt-in.**
43
+
44
+ ### 1. `drift check --auto-fix` delivered νŒ¨ν„΄ μžλ™ 적용 (1.9.82 νŒ¨ν„΄ ν™•μž₯)
45
+ - 1.9.82 λ³΄μ•ˆ μ‹ ν˜Έ β†’ audit --fix μžλ™ 호좜 νŒ¨ν„΄μ„ delivered μ‹œμŠ€ν…œμ—λ„ 적용
46
+ - `--auto-fix` ν”Œλž˜κ·Έ μ‚¬μš© μ‹œ `_detectDeliveredRequests` β†’ 후보 μžλ™ μ™„λ£Œ
47
+ - `autoCompleteReason: 'drift-auto-fix-1.9.225'` 좔적
48
+ - drift score κ°€μ€‘μΉ˜ κ°€μ§œ λ―Έλ‹΅ μ‹ ν˜Έ 제거 β†’ drift 회볡 완성도 ν–₯상
49
+
50
+ ### 2. `LEERNESS_AUTO_APPLY_DELIVERED=1` env opt-in (자율 λͺ¨λ“œμš©)
51
+ - handoff 첫 호좜 μ‹œ μžλ™ 적용 (`autoCompleteReason: 'env-auto-apply-1.9.225'`)
52
+ - 자율 λͺ¨λ“œμ—μ„œ λ§€ λΌμš΄λ“œλ§ˆλ‹€ μžλ™ 정리 β†’ AIκ°€ μ‹ κ²½ μ“Έ ν•„μš” X
53
+ - env λ―Έμ„€μ • μ‹œ κΈ°μ‘΄ λ™μž‘ (μ•ˆλ‚΄λ§Œ)
54
+
55
+ ### 3. handoff λ³Έλ¬Έ κ°€μ΄λ“œ μΆ”κ°€
56
+ - 1.9.224 λ³Έλ¬Έ μ„Ήμ…˜μ— `β†’ 자율 λͺ¨λ“œ μžλ™ 적용: export LEERNESS_AUTO_APPLY_DELIVERED=1` μ•ˆλ‚΄
57
+ - μ‚¬μš©μžκ°€ 자율 λͺ¨λ“œ opt-in λ°œκ²¬ν•˜κΈ° μ‰½κ²Œ
58
+
59
+ ### 4. μ‚¬μš©μž μš”μ²­ μžλ™ μ™„λ£Œ μ‹œμŠ€ν…œ β€” 4 λΌμš΄λ“œ λˆ„μ  μ™„μ„±
60
+ - 1.9.223 CLI auto-complete (μˆ˜λ™ 호좜)
61
+ - 1.9.224 MCP 61 + handoff λ³Έλ¬Έ + session close μžλ™ 적용
62
+ - 1.9.225 drift --auto-fix 톡합 + env opt-in μžλ™ν™”
63
+
64
+ ### 5. λˆ„μ  νšŒκ·€ (1.9.207~224) β€” λͺ¨λ‘ μœ μ§€
65
+
66
+ ### 6. stress-v170 β€” 14/14 PASS
67
+ - 1.9.225 (5): VERSION + drift auto-fix 톡합 + drift κΈ°λ³Έ 보쑴 + env auto-apply + env μ—†μœΌλ©΄ 미적용
68
+ - μ„±λŠ₯ (2): cold_start avg 367ms / drift auto-fix 383ms
69
+ - λˆ„μ  νšŒκ·€ (7): 1.9.207~224
70
+
71
+ ### 7. μžλ™ release (87 λΌμš΄λ“œ main-push streak Β· 48 λΌμš΄λ“œ npm publish streak)
72
+
73
+ πŸ”§ **drift 회볡 μ‹œμŠ€ν…œ λˆ„μ  κ°•ν™”** (1.9.39/82/225 β€” 3 λΌμš΄λ“œ)
74
+
75
+ ---
76
+
3
77
  ## 1.9.224 β€” 2026-05-22
4
78
 
5
79
  **πŸ”Œ MCP 61 도ꡬ (leerness_requests_auto_complete) + handoff λ³Έλ¬Έ + session close --auto-apply-delivered.**
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.224-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v169-16%2F16-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-61-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-154-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-86_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-100%2F100_(5μΆ•)-brightgreen)]() [![auto-complete](https://img.shields.io/badge/πŸ“₯_requests-auto--complete-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-556ms-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.226-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v171-16%2F16-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-62-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-182-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-88_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-100%2F100_(5μΆ•)-brightgreen)]() [![round-history](https://img.shields.io/badge/πŸ”„_round--history-R182_β†’_R200-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-336ms-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.224 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.226 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ πŸ”Œ MCP 61 Β· handoff λ³Έλ¬Έ + session close --auto-apply β•‘
17
+ β•‘ πŸ”„ round-history CLI + handoff R182 β†’ R200 λ§ˆμΌμŠ€ν†€ β•‘
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.224';
10
+ const VERSION = '1.9.226';
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 처리).
@@ -2054,6 +2054,84 @@ function _compareSemver(a, b) {
2054
2054
  return 0;
2055
2055
  }
2056
2056
 
2057
+ // 1.9.226: round-history β€” git tag v1.9.X 기반 자율 λΌμš΄λ“œ 톡계 + λ‹€μŒ λ§ˆμΌμŠ€ν†€
2058
+ // git이 μ—†κ±°λ‚˜ tagκ°€ μ—†μœΌλ©΄ graceful fallback (current version + 0 history)
2059
+ // 응닡: { currentVersion, roundCount, baselineVersion, latestTags[], nextMilestone, roundsToNextMilestone, firstTagAt, latestTagAt, daysActive, avgRoundsPerDay }
2060
+ function _computeRoundHistory(root) {
2061
+ const result = {
2062
+ currentVersion: VERSION,
2063
+ roundCount: 0,
2064
+ baselineVersion: null,
2065
+ latestTags: [],
2066
+ nextMilestone: null,
2067
+ roundsToNextMilestone: null,
2068
+ firstTagAt: null,
2069
+ latestTagAt: null,
2070
+ daysActive: 0,
2071
+ avgRoundsPerDay: 0
2072
+ };
2073
+ try {
2074
+ // git tag --list 'v1.9.*' --sort=creatordate (μ‹œκ°„μˆœ)
2075
+ const r = cp.spawnSync('git', ['tag', '--list', 'v1.9.*', '--sort=creatordate', '--format=%(refname:short)|%(creatordate:iso8601)'], {
2076
+ cwd: root, encoding: 'utf8', timeout: 5000
2077
+ });
2078
+ if (r.status !== 0 || !r.stdout) return result;
2079
+ const lines = r.stdout.split('\n').filter(l => l.trim() && /^v\d+\.\d+\.\d+\|/.test(l));
2080
+ if (lines.length === 0) return result;
2081
+ const tags = lines.map(l => {
2082
+ const [name, date] = l.split('|');
2083
+ return { name: name.trim(), version: name.replace(/^v/, '').trim(), date: date.trim() };
2084
+ });
2085
+ result.roundCount = tags.length;
2086
+ result.baselineVersion = tags[0].version;
2087
+ result.firstTagAt = tags[0].date;
2088
+ result.latestTagAt = tags[tags.length - 1].date;
2089
+ // 졜근 10개
2090
+ result.latestTags = tags.slice(-10).reverse().map(t => ({ version: t.version, date: t.date.split('T')[0] }));
2091
+ // λ‹€μŒ λ§ˆμΌμŠ€ν†€ (50/100/150/200/300/...)
2092
+ const milestones = [50, 75, 100, 125, 150, 175, 200, 250, 300, 400, 500];
2093
+ const next = milestones.find(m => m > result.roundCount);
2094
+ if (next != null) {
2095
+ result.nextMilestone = next;
2096
+ result.roundsToNextMilestone = next - result.roundCount;
2097
+ }
2098
+ // 일일 평균
2099
+ const first = new Date(result.firstTagAt).getTime();
2100
+ const last = new Date(result.latestTagAt).getTime();
2101
+ const days = Math.max(1, Math.floor((last - first) / 86400000));
2102
+ result.daysActive = days;
2103
+ result.avgRoundsPerDay = Math.round((result.roundCount / days) * 100) / 100;
2104
+ } catch {}
2105
+ return result;
2106
+ }
2107
+
2108
+ function roundHistoryCmd(root) {
2109
+ root = absRoot(root);
2110
+ const isTty = process.stdout && process.stdout.isTTY;
2111
+ const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
2112
+ const gr = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
2113
+ const yl = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
2114
+ const dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
2115
+ const data = _computeRoundHistory(root);
2116
+ if (has('--json')) { log(JSON.stringify(data, null, 2)); return; }
2117
+ log(cy(`# leerness round-history (1.9.226) β€” 자율 λΌμš΄λ“œ 톡계`));
2118
+ log('');
2119
+ log(` πŸ“¦ ν˜„μž¬ 버전: ${gr(data.currentVersion)}`);
2120
+ log(` πŸ”„ λˆ„μ  λΌμš΄λ“œ: ${gr(String(data.roundCount))}`);
2121
+ if (data.baselineVersion) log(` πŸ“ baseline: v${data.baselineVersion} (${(data.firstTagAt || '').split('T')[0]})`);
2122
+ if (data.latestTagAt) log(` ⏰ 졜근 tag: ${(data.latestTagAt || '').split('T')[0]}`);
2123
+ if (data.daysActive > 0) log(` πŸ“Š ν™œλ™: ${data.daysActive}일 / 평균 ${gr(data.avgRoundsPerDay + ' rounds/day')}`);
2124
+ log('');
2125
+ if (data.nextMilestone != null) {
2126
+ log(yl(` 🎯 λ‹€μŒ λ§ˆμΌμŠ€ν†€: R${data.nextMilestone} (${data.roundsToNextMilestone} λΌμš΄λ“œ λ‚¨μŒ)`));
2127
+ } else {
2128
+ log(gr(` πŸŽ‰ λͺ¨λ“  λ§ˆμΌμŠ€ν†€ 달성 (500+)`));
2129
+ }
2130
+ log('');
2131
+ log(` 졜근 10 tags:`);
2132
+ data.latestTags.forEach(t => log(` β€’ v${t.version} (${t.date})`));
2133
+ }
2134
+
2057
2135
  // 1.9.208: ν”Œλž«νΌ/API μ œμ•½ 사전 체크 (μ‚¬μš©μž λͺ…μ‹œ)
2058
2136
  // "μ‚¬μš©μžμ˜ λͺ…령을 λ°›μœΌλ©΄, κ³ λ €ν•΄μ•Όν•˜λŠ” 뢀뢄을 λ¨Όμ € ν™•μΈν•˜κ³  μ§„ν–‰ν•˜κ²Œ ν•˜λ©΄ μ–΄λ–¨μ§€"
2059
2137
  // "νŠΉμ • ν”Œλž«νΌμ˜ API ... ν˜ΈμΆœμ†λ„κ°€ μ΄ˆλ‹Ή 5회 μ΄ν•˜λ‘œλ§Œ ν•΄μ•Όν•œλ‹€λŠ” κ·œμ •μ„ λ¨Όμ € 확인"
@@ -5987,6 +6065,17 @@ function handoff(root) {
5987
6065
  parts.push(`🌐 official ${m.total}/${m.cacheTotal} (${ageStr}${status})`);
5988
6066
  }
5989
6067
  } catch {}
6068
+ // 17) 1.9.226: round-history ν—€λ“œλΌμΈ β€” 자율 λΌμš΄λ“œ μΉ΄μš΄ν„° + λ‹€μŒ λ§ˆμΌμŠ€ν†€ (5 λΌμš΄λ“œ 이상 μ‹œλ§Œ ν‘œμ‹œ)
6069
+ try {
6070
+ const rh = _computeRoundHistory(root);
6071
+ if (rh.roundCount >= 5) {
6072
+ let label = `πŸ”„ R${rh.roundCount}`;
6073
+ if (rh.nextMilestone != null && rh.roundsToNextMilestone <= 20) {
6074
+ label += ` β†’ R${rh.nextMilestone} (${rh.roundsToNextMilestone}R λ‚¨μŒ)`;
6075
+ }
6076
+ parts.push(label);
6077
+ }
6078
+ } catch {}
5990
6079
  // 12) 1.9.204: μžλ™ λͺ¨λ“œ ν™œμ„± ν‘œμ‹œ (μ‚¬μš©μž λͺ…μ‹œ) β€” R-0001 every-round λ£° ν™œμ„± μ‹œ ν—€λ“œλΌμΈ λ…ΈμΆœ
5991
6080
  try {
5992
6081
  const autoRule = _getAutoLoopRule(root);
@@ -6141,8 +6230,25 @@ function handoff(root) {
6141
6230
 
6142
6231
  // 1.9.224: handoff λ³Έλ¬Έ μžλ™ λ…ΈμΆœ β€” delivered νŒ¨ν„΄ 후보 β‰₯ 1건 μ‹œ (1.9.223 ν™•μž₯)
6143
6232
  // "Round X.Y.Z β€” κ΅¬ν˜„ μ™„λ£Œ" νŒ¨ν„΄μ΄ λˆ„μ λ˜λ©΄ λ³Έλ¬Έ μ„Ήμ…˜μœΌλ‘œ μžλ™ μ•ˆλ‚΄ (ν—€λ“œλΌμΈλ§ŒμœΌλ‘œλŠ” λ†“μΉ˜κΈ° 쉬움)
6233
+ // 1.9.225: LEERNESS_AUTO_APPLY_DELIVERED=1 env ν™œμ„± μ‹œ handoff 첫 ν˜ΈμΆœμ—μ„œ μžλ™ 적용 (자율 λͺ¨λ“œμš© opt-in)
6144
6234
  try {
6145
- const delivered = _detectDeliveredRequests(root);
6235
+ let delivered = _detectDeliveredRequests(root);
6236
+ const envAutoApply = process.env.LEERNESS_AUTO_APPLY_DELIVERED === '1';
6237
+ if (envAutoApply && delivered.candidates && delivered.candidates.length > 0) {
6238
+ let appliedCnt = 0;
6239
+ for (const c of delivered.candidates) {
6240
+ const u = _updateUserRequest(root, c.id, { status: 'completed', autoCompletedAt: new Date().toISOString(), autoCompleteReason: 'env-auto-apply-1.9.225' });
6241
+ if (u) appliedCnt++;
6242
+ }
6243
+ if (appliedCnt > 0) {
6244
+ const isTty = process.stdout && process.stdout.isTTY;
6245
+ const gr5 = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
6246
+ log('');
6247
+ log(gr5(`## πŸ“₯ μ‚¬μš©μž μš”μ²­ μžλ™ μ™„λ£Œ (1.9.225, env LEERNESS_AUTO_APPLY_DELIVERED=1, ${appliedCnt}건)`));
6248
+ // 적용 ν›„ 재쑰회
6249
+ delivered = _detectDeliveredRequests(root);
6250
+ }
6251
+ }
6146
6252
  if (delivered.candidates && delivered.candidates.length > 0) {
6147
6253
  const isTty = process.stdout && process.stdout.isTTY;
6148
6254
  const cy4 = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
@@ -6158,6 +6264,7 @@ function handoff(root) {
6158
6264
  }
6159
6265
  log(dm4(` β†’ κ²€ν† : leerness requests auto-complete`));
6160
6266
  log(dm4(` β†’ 적용: leerness requests auto-complete --apply (μ•ˆμ „ 정리)`));
6267
+ log(dm4(` β†’ 자율 λͺ¨λ“œ μžλ™ 적용: export LEERNESS_AUTO_APPLY_DELIVERED=1 (1.9.225)`));
6161
6268
  }
6162
6269
  } catch {}
6163
6270
 
@@ -12867,6 +12974,26 @@ function driftCheckCmd(root, opts = {}) {
12867
12974
  log(`⚠ auto-fix λ³΄μ•ˆ 회볡 였λ₯˜: ${e.message}`);
12868
12975
  }
12869
12976
  }
12977
+ // 1.9.225: drift check --auto-fix 에 delivered νŒ¨ν„΄ μžλ™ 적용 톡합 (1.9.223/224 μ‹œμŠ€ν…œ 회수)
12978
+ // μ‚¬μš©μž μš”μ²­μ— "κ΅¬ν˜„ μ™„λ£Œ" νŒ¨ν„΄μ΄ λˆ„μ λ˜λ©΄ κ°€μ§œ λ―Έλ‹΅ μ‹ ν˜Έκ°€ drift score λ₯Ό κ°€μ€‘μ‹œν‚¬ 수 있음 β†’ μžλ™ 정리.
12979
+ // 1.9.82 audit --fix νŒ¨ν„΄κ³Ό 동일: --auto-fix μ‹œ μ¦‰μ‹œ 적용, 적용 ν›„ μž¬κ²€μ‚¬.
12980
+ if (autoFix) {
12981
+ try {
12982
+ const delivered = _detectDeliveredRequests(root);
12983
+ if (delivered.candidates && delivered.candidates.length > 0) {
12984
+ log('');
12985
+ log(`πŸ“₯ --auto-fix ν™œμ„± (1.9.225) β€” delivered νŒ¨ν„΄ ${delivered.candidates.length}건 μžλ™ μ™„λ£Œ 쀑...`);
12986
+ let ok = 0;
12987
+ for (const c of delivered.candidates) {
12988
+ const u = _updateUserRequest(root, c.id, { status: 'completed', autoCompletedAt: new Date().toISOString(), autoCompleteReason: 'drift-auto-fix-1.9.225' });
12989
+ if (u) ok++;
12990
+ }
12991
+ log(`βœ“ delivered μžλ™ μ™„λ£Œ ${ok}/${delivered.candidates.length}건`);
12992
+ }
12993
+ } catch (e) {
12994
+ log(`⚠ delivered auto-apply 였λ₯˜ (1.9.225): ${e.message}`);
12995
+ }
12996
+ }
12870
12997
  if (autoFix && level === 'πŸ”΄ critical' && !hasSecurityFired) {
12871
12998
  log('');
12872
12999
  log(`πŸ”§ --auto-fix ν™œμ„± β€” session close μžλ™ μ‹€ν–‰ 쀑...`);
@@ -13851,7 +13978,8 @@ function mcpServeCmd(root) {
13851
13978
  { name: 'leerness_intent_classify', description: '1.9.216 (1.9.213 μ‚¬μš©μž λͺ…μ‹œ) β€” μ‚¬μš©μž μ˜λ„ νŒŒμ•… + scope expansion 게이트. 응닡: { intent: precise|broad|default, signals, domain, explicitMentions, expansionCandidates, mode: dry-run }. 3원칙 μ•ˆμ „: (1) Always-Off Opt-In, (2) Dry-run κΈ°λ³Έ (μ‹€ν–‰ X), (3) λͺ…μ‹œ vs μΆ”λ‘  뢄리 라벨링. 5 도메인 (game/web/api/cli/data). μ™ΈλΆ€ AIκ°€ "이 μš”μ²­μ€ μ •ν™•νžˆ κ·Έκ²ƒλ§Œ / 포괄적 / 기본인가?"λ₯Ό 회수. 인자: { request (required), path? }', inputSchema: { type: 'object', properties: { request: { type: 'string' }, path: { type: 'string' } }, required: ['request'] } },
13852
13979
  { name: 'leerness_idempotency_audit', description: '1.9.216 (1.9.212 μ‚¬μš©μž λͺ…μ‹œ) β€” λ©±λ“±μ„± μœ„λ°˜ 탐지. 4μ˜μ—­ 점검: rule-duplicate (medium) / task-duplicate-request (medium) / user-request-duplicate (low) / wakeup-duplicate (high). 응닡: { violations[], verified[], summary: {totalViolations, high/medium/low, overall} }. μ™ΈλΆ€ AIκ°€ "μ›Œν¬μŠ€νŽ˜μ΄μŠ€μ— 쀑볡/좩돌이 μžˆλ‚˜?"λ₯Ό 회수. πŸŽ‰ MCP 58 도ꡬ λ§ˆμΌμŠ€ν†€ (50β†’58). 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
13853
13980
  { name: 'leerness_session_resume', description: '1.9.221 (1.9.220 μ‚¬μš©μž λͺ…μ‹œ) β€” 비정상 μ’…λ£Œ 감지 + 자율 재개. 5μ‹ ν˜Έ 뢄석: last-handoff-stale / wakeup-missed / in-progress-stale / auto-resume-plan-unused / release-branch-pending. 응닡: { abnormalShutdown, severity (none/low/medium/high), signals[], resumeGuide[] }. μ™ΈλΆ€ AIκ°€ "μ ˆμ „/μ‹œμŠ€ν…œμ’…λ£Œ/μ„Έμ…˜μ’…λ£Œ ν›„ leerness μƒνƒœκ°€ 정상인가? μ–΄λ–»κ²Œ 재개?"λ₯Ό 회수. πŸŽ‰ MCP 60 도ꡬ λ§ˆμΌμŠ€ν†€ (53β†’60, +7 in 1.9.168/216/221). 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
13854
- { name: 'leerness_requests_auto_complete', description: '1.9.224 (1.9.223 μžλ™ 회수) β€” delivered νŒ¨ν„΄ μžλ™ 감지 + μžλ™ μ™„λ£Œ. "Round X.Y.Z β€” κ΅¬ν˜„ μ™„λ£Œ" / "implemented" / "delivered" νŒ¨ν„΄μ΄ μžˆλŠ” open μš”μ²­ 쀑 ν˜„μž¬ 버전 μ΄ν•˜μΈ 것을 ν›„λ³΄λ‘œ λΆ„λ₯˜. 응닡: { total, candidates: [{id, text, claimedVersion, currentVersion, deliveredKeyword, recordedAt}], currentVersion, applied (apply=true μ‹œ), completedIds[] }. μ™ΈλΆ€ AIκ°€ "운영 λˆ„μ λœ κ°€μ§œ λ―Έλ‹΅ μ‹ ν˜Έ 정리 κ°€λŠ₯ν•œκ°€?"λ₯Ό 회수. κΈ°λ³Έ dry-run, apply: true λͺ…μ‹œ μ‹œμ—λ§Œ μ‹€ 적용. 인자: { path?, apply? (default false) }', inputSchema: { type: 'object', properties: { path: { type: 'string' }, apply: { type: 'boolean' } } } }
13981
+ { name: 'leerness_requests_auto_complete', description: '1.9.224 (1.9.223 μžλ™ 회수) β€” delivered νŒ¨ν„΄ μžλ™ 감지 + μžλ™ μ™„λ£Œ. "Round X.Y.Z β€” κ΅¬ν˜„ μ™„λ£Œ" / "implemented" / "delivered" νŒ¨ν„΄μ΄ μžˆλŠ” open μš”μ²­ 쀑 ν˜„μž¬ 버전 μ΄ν•˜μΈ 것을 ν›„λ³΄λ‘œ λΆ„λ₯˜. 응닡: { total, candidates: [{id, text, claimedVersion, currentVersion, deliveredKeyword, recordedAt}], currentVersion, applied (apply=true μ‹œ), completedIds[] }. μ™ΈλΆ€ AIκ°€ "운영 λˆ„μ λœ κ°€μ§œ λ―Έλ‹΅ μ‹ ν˜Έ 정리 κ°€λŠ₯ν•œκ°€?"λ₯Ό 회수. κΈ°λ³Έ dry-run, apply: true λͺ…μ‹œ μ‹œμ—λ§Œ μ‹€ 적용. 인자: { path?, apply? (default false) }', inputSchema: { type: 'object', properties: { path: { type: 'string' }, apply: { type: 'boolean' } } } },
13982
+ { name: 'leerness_round_history', description: '1.9.226 β€” 자율 λΌμš΄λ“œ 톡계. git tag v1.9.X 기반 λˆ„μ  λΌμš΄λ“œ 카운트 + λ‹€μŒ λ§ˆμΌμŠ€ν†€ (50/75/100/125/150/175/200/250/300/400/500) + 평균 rounds/day. 응닡: { currentVersion, roundCount, baselineVersion, latestTags[], nextMilestone, roundsToNextMilestone, firstTagAt, latestTagAt, daysActive, avgRoundsPerDay }. μ™ΈλΆ€ AIκ°€ "이 ν”„λ‘œμ νŠΈλŠ” μ–Όλ§ˆλ‚˜ 진행됐고 λ‹€μŒ λ§ˆμΌμŠ€ν†€κΉŒμ§€ λͺ‡ λΌμš΄λ“œ λ‚¨μ•˜λ‚˜?"λ₯Ό 회수. 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } }
13855
13983
  ];
13856
13984
 
13857
13985
  function send(obj) {
@@ -14012,6 +14140,10 @@ function mcpServeCmd(root) {
14012
14140
  cliArgs = ['requests', 'auto-complete', '--path', targetPath, '--json'];
14013
14141
  if (args.apply === true) cliArgs.push('--apply');
14014
14142
  break;
14143
+ case 'leerness_round_history':
14144
+ // 1.9.226: 자율 λΌμš΄λ“œ 톡계 + λ‹€μŒ λ§ˆμΌμŠ€ν†€
14145
+ cliArgs = ['round-history', '--path', targetPath, '--json'];
14146
+ break;
14015
14147
  default:
14016
14148
  return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
14017
14149
  }
@@ -17643,6 +17775,8 @@ async function main() {
17643
17775
  if (cmd === 'requests') return requestsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
17644
17776
  // 1.9.220: leerness session-resume β€” 비정상 μ’…λ£Œ 감지 + 자율 재개 κ°€μ΄λ“œ (μ‚¬μš©μž λͺ…μ‹œ)
17645
17777
  if (cmd === 'session-resume') return sessionResumeCmd(arg('--path', process.cwd()));
17778
+ // 1.9.226: leerness round-history β€” 자율 λΌμš΄λ“œ 톡계 + λ‹€μŒ λ§ˆμΌμŠ€ν†€
17779
+ if (cmd === 'round-history') return roundHistoryCmd(arg('--path', process.cwd()));
17646
17780
  // 1.9.208: leerness constraints <list|check|add> β€” ν”Œλž«νΌ/API μ œμ•½ 사전 체크 (μ‚¬μš©μž λͺ…μ‹œ)
17647
17781
  if (cmd === 'constraints') return constraintsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
17648
17782
  // 1.9.209: leerness pre-wake-audit β€” sleep μ „ sub-agent audit (μ‚¬μš©μž λͺ…μ‹œ)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.224",
3
+ "version": "1.9.226",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",