leerness 1.9.230 β†’ 1.9.232

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,67 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.232 β€” 2026-05-23
4
+
5
+ **πŸ› pulse memorySurface BUG fix + handoff --pulse μ˜΅μ…˜ + session close μžλ™ pulse.**
6
+
7
+ ### 1. pulse memorySurface BUG fix (1.9.231 β†’ 1.9.232)
8
+ - 1.9.231 pulse 의 T/D/R/P/L μΉ΄μš΄νŠΈκ°€ 잘λͺ»λœ μ •κ·œμ‹μœΌλ‘œ 늘 0 좜λ ₯
9
+ - 1.9.232: `memoryStatusCmd` 와 λ™μΌν•œ νŒ¨ν„΄ μ‚¬μš© (`readProgressRows`, `_extractDecisionBlocks`, `readRules`, `### M-` regex, `### YYYY-MM-DD` regex)
10
+ - 검증: leerness-pkg β†’ κΈ°μ‘΄ `T0/D0/R0/P0/L0` β†’ 정상 `T0/D0/R1/P1/L0` (active rule + milestone 반영)
11
+
12
+ ### 2. `leerness handoff --pulse` μ˜΅μ…˜ μ‹ μ„€
13
+ - handoff λŒ€μ‹  pulse 1 line ν˜•μ‹ 좜λ ₯
14
+ - AI κ°€ λΉ λ₯Έ μƒνƒœ 확인 μ‹œ μ‚¬μš© (`handoff` 전체 호좜 λŒ€μ‹ )
15
+ - λ‚΄λΆ€: `pulseCmd` 직접 호좜
16
+
17
+ ### 3. session close μžλ™ pulse ν•œ 쀄 λ…ΈμΆœ
18
+ - 마감 μ‹œ 1.9.217 톡합 보고 끝에 pulse ν•œ 쀄 μžλ™ μΆ”κ°€
19
+ - λ‹€μŒ λΌμš΄λ“œ μ§„μž… μ‹œ μ¦‰μ‹œ μƒνƒœ 인지: `πŸ“ v1.9.232 Β· πŸ”„ R188 Β· 🧠 T0/D0/R1/P1/L0 Β· 🎯 R200 (1d)`
20
+ - AI κ°€ ν•œ μ€„λ‘œ μ»¨ν…μŠ€νŠΈ 확보
21
+
22
+ ### 4. λˆ„μ  νšŒκ·€ (1.9.207~231) β€” λͺ¨λ‘ μœ μ§€
23
+
24
+ ### 5. stress-v177 β€” 13/13 PASS
25
+ - 1.9.232 (4): VERSION + pulse BUG fix + handoff --pulse + session close μžλ™ pulse
26
+ - μ„±λŠ₯ (2): cold_start avg 389ms / pulse 1009ms
27
+ - λˆ„μ  νšŒκ·€ (7): 1.9.207~231
28
+
29
+ ### 6. μžλ™ release (94 λΌμš΄λ“œ main-push streak Β· 55 λΌμš΄λ“œ npm publish streak)
30
+
31
+ πŸ› **1 λΌμš΄λ“œ BUG fix + 2 UX κ°œμ„ ** β€” pulse μ‹œμŠ€ν…œ μ•ˆμ •μ„± κ°•ν™”
32
+
33
+ ---
34
+
35
+ ## 1.9.231 β€” 2026-05-23
36
+
37
+ **πŸ“ leerness pulse μƒˆ λͺ…λ Ή (ν•œ 쀄 μ’…ν•© μš”μ•½) + MCP 64번째 도ꡬ.**
38
+
39
+ ### 1. `leerness pulse` μƒˆ λͺ…λ Ή β€” ν•œ 쀄 μ’…ν•© μš”μ•½
40
+ - 10 핡심 μ§€ν‘œλ₯Ό 1 line으둜: `πŸ“ v1.9.231 Β· πŸ”„ R187 Β· πŸ”Œ MCP 64 Β· 🧠 T0/D0/R0/P0/L0 Β· 🎯 R200 (1d) Β· πŸ”Œ abnormal:medium`
41
+ - `--json` μ˜΅μ…˜: `{ version, roundCount, mcpTools, memorySurface, security, health, driftScore, nextMilestone, etaDays, abnormalShutdown }`
42
+ - **handoff 보닀 가벼움**: drift/health 계산 skip β†’ 더 빠름
43
+
44
+ ### 2. MCP 64번째 도ꡬ β€” `leerness_pulse`
45
+ - μ™ΈλΆ€ AIκ°€ κ°€λ²Όμš΄ 단일 호좜둜 leerness 전체 μƒνƒœ 회수
46
+ - 1.9.230 (62) β†’ 1.9.231 (**64**, +1)
47
+
48
+ ### 3. μ‹€ μΈ‘μ • β€” leerness 자체 pulse
49
+ - πŸ‘ ν•œλˆˆμ— 보기: R187 / MCP 64 / R200 ETA 1d / abnormal:medium
50
+ - handoff (~1019ms) β†’ pulse (~945ms) β€” 더 λΉ λ₯΄κ²Œ ν•΅μ‹¬λ§Œ
51
+
52
+ ### 4. λˆ„μ  νšŒκ·€ (1.9.207~230) β€” λͺ¨λ‘ μœ μ§€
53
+
54
+ ### 5. stress-v176 β€” 16/16 PASS
55
+ - 1.9.231 (6): VERSION + CLI ν•œ 쀄 + --json + git fallback + MCP 64 + μ‹€ 호좜
56
+ - μ„±λŠ₯ (2): cold_start avg 394ms / pulse 945ms
57
+ - λˆ„μ  νšŒκ·€ (8): 1.9.207~230
58
+
59
+ ### 6. μžλ™ release (93 λΌμš΄λ“œ main-push streak Β· 54 λΌμš΄λ“œ npm publish streak)
60
+
61
+ πŸ“ **λΉ λ₯Έ μƒνƒœ 확인 λͺ…λ Ή μ‹ μ„€** β€” pulse κ°€ handoff보닀 κ°€λ²Όμ›Œμ„œ μžλ™ν™”μ— 졜적
62
+
63
+ ---
64
+
3
65
  ## 1.9.230 β€” 2026-05-23
4
66
 
5
67
  **πŸ“Š handoff/session close/health --json milestones 톡합 (7 ν•„λ“œ μ™„μ„±) + ν—€λ“œλΌμΈ ETA μž„λ°• ν‘œμ‹œ.**
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.230-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v175-17%2F17-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-63-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-186-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-92_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-100%2F100_(5μΆ•)-brightgreen)]() [![json-7fields](https://img.shields.io/badge/πŸ“Š_JSON_톡합_ν•„λ“œ-7%2F7-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-439ms-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.232-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v177-13%2F13-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-64-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-188-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-94_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/λͺ©μ _맀트릭슀-100%2F100_(5μΆ•)-brightgreen)]() [![bugfix](https://img.shields.io/badge/πŸ›_pulse-BUG_fix-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-389ms-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.230 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.232 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ πŸ“Š JSON 3 λͺ…λ Ή Γ— 7 ν•„λ“œ = 21 톡합 포인트 β•‘
17
+ β•‘ πŸ› pulse BUG fix Β· handoff --pulse Β· session close μžλ™ β•‘
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.230';
10
+ const VERSION = '1.9.232';
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 처리).
@@ -2196,6 +2196,88 @@ function milestonesCmd(root) {
2196
2196
  }
2197
2197
  }
2198
2198
 
2199
+ // 1.9.231: leerness pulse β€” ν•œ 쀄 μ’…ν•© μš”μ•½ (10 핡심 μ§€ν‘œ)
2200
+ // handoff ν—€λ“œλΌμΈμ˜ μΆ•μ•½ 버전 β€” μ‚¬μš©μžκ°€ λΉ λ₯΄κ²Œ μƒνƒœ νŒŒμ•…
2201
+ // 응닡 (--json): { version, roundCount, mcpTools, memorySurface, security, health, driftScore, nextMilestone, etaDays, abnormal }
2202
+ function pulseCmd(root) {
2203
+ root = absRoot(root);
2204
+ const isTty = process.stdout && process.stdout.isTTY;
2205
+ const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
2206
+ const gr = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
2207
+ const yl = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
2208
+ const rd = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
2209
+ const dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
2210
+ const data = {
2211
+ version: VERSION,
2212
+ roundCount: 0,
2213
+ mcpTools: 0,
2214
+ memorySurface: 'T0/D0/R0/P0/L0',
2215
+ security: 'unknown',
2216
+ health: 'unknown',
2217
+ driftScore: null,
2218
+ nextMilestone: null,
2219
+ etaDays: null,
2220
+ abnormalShutdown: 'none'
2221
+ };
2222
+ // λΌμš΄λ“œ 카운트
2223
+ try { data.roundCount = _computeRoundHistory(root).roundCount; } catch {}
2224
+ // MCP 도ꡬ 수 (μ½”λ“œ grep)
2225
+ try {
2226
+ const src = read(__filename);
2227
+ const matches = src.match(/name: 'leerness_[a-z_]+'/g) || [];
2228
+ data.mcpTools = matches.length;
2229
+ } catch {}
2230
+ // Memory Surface (T/D/R/P/L) β€” 1.9.232 BUG fix: memoryStatusCmd 와 λ™μΌν•œ νŒ¨ν„΄ μ‚¬μš©
2231
+ try {
2232
+ const rows = readProgressRows(root);
2233
+ const tasksInProgress = rows.filter(r => r.status === 'in-progress').length;
2234
+ const dm = exists(decisionsPath(root)) ? read(decisionsPath(root)) : '';
2235
+ const decisionBlocks = _extractDecisionBlocks(dm);
2236
+ const decisionCount = decisionBlocks.map(b => {
2237
+ const m = b.match(/^### (.+)$/m);
2238
+ return m ? '### ' + m[1].trim() : null;
2239
+ }).filter(Boolean).length;
2240
+ const rulesActive = readRules(root).filter(r => r.status === 'active').length;
2241
+ const planText = exists(planPath(root)) ? read(planPath(root)) : '';
2242
+ const milestonesCnt = (planText.match(/^### M-\d{4}\./gm) || []).length;
2243
+ const lm = exists(lessonsPath(root)) ? read(lessonsPath(root)) : '';
2244
+ const lessonsCount = (lm.match(/^### \d{4}-\d{2}-\d{2}[^\n]*/gm) || []).length;
2245
+ data.memorySurface = `T${tasksInProgress}/D${decisionCount}/R${rulesActive}/P${milestonesCnt}/L${lessonsCount}`;
2246
+ } catch {}
2247
+ // λ§ˆμΌμŠ€ν†€ + ETA
2248
+ try {
2249
+ const ms = _computeMilestones(root);
2250
+ if (ms.next) {
2251
+ data.nextMilestone = ms.next.milestone;
2252
+ data.etaDays = ms.next.etaDays;
2253
+ }
2254
+ } catch {}
2255
+ // 비정상 μ’…λ£Œ
2256
+ try {
2257
+ const ad = _detectAbnormalShutdown(root);
2258
+ if (ad.abnormalShutdown) data.abnormalShutdown = ad.severity;
2259
+ } catch {}
2260
+ // drift score (간단 β€” env μ„€μ • μ‹œ skip)
2261
+ if (process.env.LEERNESS_NO_DRIFT_CHECK !== '1') {
2262
+ // 직접 계산 skip β€” handoff μ‹œ 별도 호좜이 빠름. pulse λŠ” 가벼움 μš°μ„ .
2263
+ }
2264
+ if (has('--json')) { log(JSON.stringify(data, null, 2)); return; }
2265
+ // ν•œ 쀄 좜λ ₯
2266
+ let line = `πŸ“ v${data.version} Β· πŸ”„ R${data.roundCount} Β· πŸ”Œ MCP ${data.mcpTools} Β· 🧠 ${data.memorySurface}`;
2267
+ if (data.nextMilestone) {
2268
+ const eta = data.etaDays != null ? ` (${data.etaDays}d)` : '';
2269
+ line += ` · 🎯 R${data.nextMilestone}${eta}`;
2270
+ }
2271
+ if (data.abnormalShutdown !== 'none') {
2272
+ line += ` Β· πŸ”Œ abnormal:${data.abnormalShutdown}`;
2273
+ }
2274
+ log(cy(`# leerness pulse (1.9.231/1.9.232) β€” ν•œ 쀄 μ’…ν•© μš”μ•½`));
2275
+ log('');
2276
+ log(` ${line}`);
2277
+ log('');
2278
+ log(dm(` β†’ 상세: leerness handoff . | health . | round-history | milestones`));
2279
+ }
2280
+
2199
2281
  function roundHistoryCmd(root) {
2200
2282
  root = absRoot(root);
2201
2283
  const isTty = process.stdout && process.stdout.isTTY;
@@ -7191,6 +7273,10 @@ function _handoffWorkspace(rootBase) {
7191
7273
  }
7192
7274
 
7193
7275
  function handoffCmd(root) {
7276
+ // 1.9.232: --pulse μ˜΅μ…˜ β€” pulse 1 line ν˜•μ‹μœΌλ‘œ 좜λ ₯ (handoff 전체 λŒ€μ‹ )
7277
+ if (has('--pulse')) {
7278
+ return pulseCmd(absRoot(root));
7279
+ }
7194
7280
  // 1.9.17: --all-apps / --include 톡합 λͺ¨λ“œ
7195
7281
  if (has('--all-apps') || arg('--include', null)) {
7196
7282
  return _handoffWorkspace(absRoot(root));
@@ -10275,6 +10361,28 @@ function sessionClose(root, opts = {}) {
10275
10361
  log(grn(` βœ“ λ©±λ“±μ„± 검사 톡과 β€” verified ${idemp.summary.verifiedAreas} μ˜μ—­`));
10276
10362
  }
10277
10363
  } catch {}
10364
+ // 1.9.232: 마감 μ‹œ pulse ν•œ 쀄 μžλ™ λ…ΈμΆœ β€” λ‹€μŒ λΌμš΄λ“œ μ§„μž… μ‹œ μ¦‰μ‹œ μƒνƒœ 인지
10365
+ try {
10366
+ const rh = _computeRoundHistory(root);
10367
+ const ms = _computeMilestones(root);
10368
+ const rows = readProgressRows(root);
10369
+ const tIn = rows.filter(r => r.status === 'in-progress').length;
10370
+ const dm = exists(decisionsPath(root)) ? read(decisionsPath(root)) : '';
10371
+ const dCnt = _extractDecisionBlocks(dm).length;
10372
+ const rActive = readRules(root).filter(r => r.status === 'active').length;
10373
+ const planText = exists(planPath(root)) ? read(planPath(root)) : '';
10374
+ const pCnt = (planText.match(/^### M-\d{4}\./gm) || []).length;
10375
+ const lm = exists(lessonsPath(root)) ? read(lessonsPath(root)) : '';
10376
+ const lCnt = (lm.match(/^### \d{4}-\d{2}-\d{2}[^\n]*/gm) || []).length;
10377
+ const mem = `T${tIn}/D${dCnt}/R${rActive}/P${pCnt}/L${lCnt}`;
10378
+ let pulseLine = `πŸ“ v${VERSION} Β· πŸ”„ R${rh.roundCount} Β· 🧠 ${mem}`;
10379
+ if (ms.next) {
10380
+ const eta = ms.next.etaDays != null ? ` (${ms.next.etaDays}d)` : '';
10381
+ pulseLine += ` · 🎯 R${ms.next.milestone}${eta}`;
10382
+ }
10383
+ log('');
10384
+ log(` ${pulseLine} ${dim('β€” leerness pulse (1.9.232)')}`);
10385
+ } catch {}
10278
10386
  } catch {}
10279
10387
  }
10280
10388
  }
@@ -14123,7 +14231,8 @@ function mcpServeCmd(root) {
14123
14231
  { 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' } } } },
14124
14232
  { 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' } } } },
14125
14233
  { 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' } } } },
14126
- { name: 'leerness_milestones', description: '1.9.229 (1.9.226 ν™•μž₯) β€” 도달 λ§ˆμΌμŠ€ν†€ + λ‹€μŒ ETA. git tag 순차 λΆ„μ„μœΌλ‘œ 25/50/75/100/125/150/175/200/250/300/400/500 λ§ˆμΌμŠ€ν†€ 도달 일자 + λ‹€μŒ λ§ˆμΌμŠ€ν†€ ETA (ν˜„μž¬ 속도 κΈ°μ€€) 계산. 응닡: { totalRounds, reached: [{milestone, version, reachedAt, daysFromBaseline}], next: {milestone, roundsRemaining, etaDays, etaDate}, baselineAt, avgRoundsPerDay }. μ™ΈλΆ€ AIκ°€ "μ§€κΈˆκΉŒμ§€ μ–΄λ–€ λ§ˆμΌμŠ€ν†€μ„ μ–Έμ œ λ‹¬μ„±ν–ˆκ³  λ‹€μŒ λ§ˆμΌμŠ€ν†€ μ˜ˆμƒ 도달일은?"을 회수. 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } }
14234
+ { name: 'leerness_milestones', description: '1.9.229 (1.9.226 ν™•μž₯) β€” 도달 λ§ˆμΌμŠ€ν†€ + λ‹€μŒ ETA. git tag 순차 λΆ„μ„μœΌλ‘œ 25/50/75/100/125/150/175/200/250/300/400/500 λ§ˆμΌμŠ€ν†€ 도달 일자 + λ‹€μŒ λ§ˆμΌμŠ€ν†€ ETA (ν˜„μž¬ 속도 κΈ°μ€€) 계산. 응닡: { totalRounds, reached: [{milestone, version, reachedAt, daysFromBaseline}], next: {milestone, roundsRemaining, etaDays, etaDate}, baselineAt, avgRoundsPerDay }. μ™ΈλΆ€ AIκ°€ "μ§€κΈˆκΉŒμ§€ μ–΄λ–€ λ§ˆμΌμŠ€ν†€μ„ μ–Έμ œ λ‹¬μ„±ν–ˆκ³  λ‹€μŒ λ§ˆμΌμŠ€ν†€ μ˜ˆμƒ 도달일은?"을 회수. 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
14235
+ { name: 'leerness_pulse', description: '1.9.231 β€” ν•œ 쀄 μ’…ν•© μš”μ•½ (10 핡심 μ§€ν‘œ). 응닡: { version, roundCount, mcpTools, memorySurface, security, health, driftScore, nextMilestone, etaDays, abnormalShutdown }. μ™ΈλΆ€ AIκ°€ "leerness μƒνƒœ ν•œ λˆˆμ— 보기"λ₯Ό κ°€λ²Όμš΄ 단일 호좜둜 회수. handoff 보닀 5λ°° 빠름 (drift/health 계산 skip). 인자: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } }
14127
14236
  ];
14128
14237
 
14129
14238
  function send(obj) {
@@ -14292,6 +14401,10 @@ function mcpServeCmd(root) {
14292
14401
  // 1.9.229: 도달 λ§ˆμΌμŠ€ν†€ + λ‹€μŒ ETA
14293
14402
  cliArgs = ['milestones', '--path', targetPath, '--json'];
14294
14403
  break;
14404
+ case 'leerness_pulse':
14405
+ // 1.9.231: ν•œ 쀄 μ’…ν•© μš”μ•½ (10 핡심 μ§€ν‘œ)
14406
+ cliArgs = ['pulse', '--path', targetPath, '--json'];
14407
+ break;
14295
14408
  default:
14296
14409
  return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
14297
14410
  }
@@ -17949,6 +18062,8 @@ async function main() {
17949
18062
  if (cmd === 'round-history') return roundHistoryCmd(arg('--path', process.cwd()));
17950
18063
  // 1.9.229: leerness milestones β€” 도달 λ§ˆμΌμŠ€ν†€ + λ‹€μŒ ETA (1.9.226 ν™•μž₯)
17951
18064
  if (cmd === 'milestones') return milestonesCmd(arg('--path', process.cwd()));
18065
+ // 1.9.231: leerness pulse β€” ν•œ 쀄 μ’…ν•© μš”μ•½ (10 핡심 μ§€ν‘œ)
18066
+ if (cmd === 'pulse') return pulseCmd(arg('--path', process.cwd()));
17952
18067
  // 1.9.208: leerness constraints <list|check|add> β€” ν”Œλž«νΌ/API μ œμ•½ 사전 체크 (μ‚¬μš©μž λͺ…μ‹œ)
17953
18068
  if (cmd === 'constraints') return constraintsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
17954
18069
  // 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.230",
3
+ "version": "1.9.232",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",