leerness 1.9.219 โ†’ 1.9.220

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,57 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.220 โ€” 2026-05-22
4
+
5
+ **๐Ÿ”Œ ๋น„์ •์ƒ ์ข…๋ฃŒ ํ›„ ์ž์œจ ์žฌ๊ฐœ ์‹œ์Šคํ…œ (์‚ฌ์šฉ์ž ๋ช…์‹œ).**
6
+
7
+ ### ์‚ฌ์šฉ์ž ๋ช…์‹œ
8
+ > *"์ž์œจ๋ชจ๋“œ์ผ๋•Œ ์ ˆ์ „๋ชจ๋“œ์˜€๊ฑฐ๋‚˜, ์‹œ์Šคํ…œ์ข…๋ฃŒ๋‚˜ AI์—์ด์ „ํŠธ ์„ธ์…˜์ข…๋ฃŒ๋“ฑ์œผ๋กœ ์ž์œจ๊ฐœ๋ฐœ๋ชจ๋“œ๊ฐ€ ๋น„์ •์ƒ์ ์œผ๋กœ ์ข…๋ฃŒ๋˜์—ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ์„ธ์…˜์„ ์ด์–ด๊ฐˆ๋•Œ, ๊ฐ์ง€ํ•˜๊ณ  ์ž‘์—…์ด ์ค‘๋‹จ๋œ์ง€์ ์ด๋‚˜ ๋ˆ„๋ฝ๋œ์ž‘์—…์„ ๊ฐ์ง€ํ•˜๊ณ  ๊ฐœ๋ฐœ์„์ด์–ด๊ฐ€๊ฑฐ๋‚˜ ์ž์œจ๋ชจ๋“œ๋ฅผ ๋‹ค์‹œ ์ง„ํ–‰"*
9
+
10
+ ### 1. `_detectAbnormalShutdown(root)` โ€” 5์‹ ํ˜ธ ์ข…ํ•ฉ ๊ฐ์ง€
11
+ | # | ์‹ ํ˜ธ | ํŠธ๋ฆฌ๊ฑฐ | severity |
12
+ |---|---|---|---|
13
+ | 1 | `last-handoff-stale` | gap > 60min (์ •์ƒ 25min ๋Œ€๋น„) | gap > 240min: high / else medium |
14
+ | 2 | `wakeup-missed` | active-wakeups pending โ†’ 30min+ ์ง€๋‚จ | gap > 120min: high |
15
+ | 3 | `in-progress-stale` | in-progress task + progress-tracker 24h+ stale | high |
16
+ | 4 | `auto-resume-plan-unused` | auto-resume-plan 60min+ ๋ฏธ์‚ฌ์šฉ | ageMin > 240: medium |
17
+ | 5 | `release-branch-pending` | 2+ release/* branch (sync-main ๋ˆ„๋ฝ) | low |
18
+
19
+ ### 2. `leerness session-resume` CLI
20
+ - ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ + 5์‹ ํ˜ธ ๋ถ„์„
21
+ - ์ž๋™ ์žฌ๊ฐœ ๊ฐ€์ด๋“œ ์ถœ๋ ฅ (7๋‹จ๊ณ„)
22
+ - `--json` ์˜ต์…˜ (์™ธ๋ถ€ ์ž๋™ํ™”)
23
+
24
+ ### 3. handoff ํ—ค๋“œ๋ผ์ธ 16๋ฒˆ์งธ ์š”์†Œ
25
+ - ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ ์‹œ: `๐Ÿ”Œ ๋น„์ •์ƒ์ข…๋ฃŒ <severity> (N์‹ ํ˜ธ)`
26
+ - ํ—ค๋“œ๋ผ์ธ ๋ผ๋ฒจ: `1.9.81/93/113/152/162/192/197/204/207/209/215/220`
27
+
28
+ ### 4. ์žฌ๊ฐœ ๊ฐ€์ด๋“œ 7๋‹จ๊ณ„ (์ž๋™ ์ƒ์„ฑ)
29
+ ์‹ ํ˜ธ๋ณ„ ๋งž์ถค ๊ฐ€์ด๋“œ:
30
+ 1. `leerness handoff .` โ€” ํ˜„์žฌ ์ƒํƒœ ์ข…ํ•ฉ
31
+ 2. `leerness resume` โ€” auto-resume-plan ์ ์šฉ (auto-resume-plan-unused ์‹œ)
32
+ 3. `leerness task list --status in-progress` โ€” stale task ๊ฒ€ํ†  (in-progress-stale ์‹œ)
33
+ 4. ScheduleWakeup ์žฌ๋“ฑ๋ก (wakeup-missed ์‹œ)
34
+ 5. `git branch -a` โ†’ `leerness release sync-main` (release-branch-pending ์‹œ)
35
+ 6. `leerness pre-wake-audit` โ€” ๋ˆ„๋ฝ ์ž‘์—… / ์ถฉ๋Œ ์ ๊ฒ€
36
+ 7. `leerness requests audit` โ€” ๋ฏธ๋‹ต ์‚ฌ์šฉ์ž ์š”์ฒญ ํ™•์ธ
37
+
38
+ ### 5. ์‹ค ๊ฒ€์ฆ ์‹œ๋‚˜๋ฆฌ์˜ค
39
+ - **์ •์ƒ ์›Œํฌ์ŠคํŽ˜์ด์Šค** โ†’ `abnormalShutdown: false / severity: none`
40
+ - **wakeup 2024๋ถ„ ์ง€๋‚จ** (์‹œ๋ฎฌ๋ ˆ์ด์…˜) โ†’ `severity: high / wakeup-missed 1์‹ ํ˜ธ + ๊ฐ€์ด๋“œ 4๋‹จ๊ณ„ ์ž๋™ ์ƒ์„ฑ`
41
+
42
+ ### 6. ๋ˆ„์  ํšŒ๊ท€ (1.9.207~219) โ€” ๋ชจ๋‘ ์œ ์ง€
43
+
44
+ ### 7. stress-v165 โ€” 18/18 PASS
45
+ - 1.9.220 (7): VERSION + 5์‹ ํ˜ธ ๋“ฑ๋ก + ์ •์ƒ/๋น„์ •์ƒ ์‹œ๋‚˜๋ฆฌ์˜ค + handoff ํ†ตํ•ฉ + CLI ๋ผ์šฐํŒ…
46
+ - ์„ฑ๋Šฅ (2): cold_start 461ms / MCP 59 ๋„๊ตฌ 424ms
47
+ - ๋ˆ„์  ํšŒ๊ท€ (9): 1.9.207~219
48
+
49
+ ### 8. ์ž๋™ release (82 ๋ผ์šด๋“œ main-push streak ยท 43 ๋ผ์šด๋“œ npm publish streak)
50
+
51
+ ๐ŸŽ‰ **์ž์œจ ๋ชจ๋“œ ๋ณต์›๋ ฅ ๊ฐ•ํ™”** โ€” ์ ˆ์ „/์ข…๋ฃŒ/์„ธ์…˜์ข…๋ฃŒ ๋ฌด๊ด€, ์žฌ์‹œ์ž‘ ์‹œ ์ž๋™ ์ง„๋‹จ + ์žฌ๊ฐœ ๊ฐ€๋Šฅ
52
+
53
+ ---
54
+
3
55
  ## 1.9.219 โ€” 2026-05-22
4
56
 
5
57
  **๐ŸŽ‰ 80 ๋ผ์šด๋“œ ์ž์œจ ๋ชจ๋“œ ๋งˆ์ผ์Šคํ†ค + session-workflow.md ํ†ตํ•ฉ ๊ฐฑ์‹ .**
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.219-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v164-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-59-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-149-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-81_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/๋ชฉ์ _๋งคํŠธ๋ฆญ์Šค-100%2F100_(5์ถ•)-brightgreen)]() [![milestone](https://img.shields.io/badge/๐ŸŽ‰_milestone-80_๋ผ์šด๋“œ-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-618ms-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.220-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v165-18%2F18-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-59-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-150-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-82_rounds-success)]() [![goal-matrix](https://img.shields.io/badge/๋ชฉ์ _๋งคํŠธ๋ฆญ์Šค-100%2F100_(5์ถ•)-brightgreen)]() [![resilience](https://img.shields.io/badge/session_resume-5์‹ ํ˜ธ_์ž๋™๊ฐ์ง€-success)]() [![perf](https://img.shields.io/badge/cold_start-461ms-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.219 AI Agent Reliability Harness + Sandbox โ•‘
15
+ โ•‘ v1.9.220 AI Agent Reliability Harness + Sandbox โ•‘
16
16
  โ•‘ verify ยท remember ยท orchestrate ยท audit ยท sandbox ยท drift โ•‘
17
- โ•‘ ๐ŸŽ‰ 80 ๋ผ์šด๋“œ ์ž์œจ ๋งˆ์ผ์Šคํ†ค ยท 5์ถ• 100/100 ยท MCP 59 ยท ๋ฐฑ๋กœ๊ทธ 0 โ•‘
17
+ โ•‘ ๐Ÿ”Œ ๋น„์ •์ƒ ์ข…๋ฃŒ โ†’ ์ž์œจ ์žฌ๊ฐœ 5์‹ ํ˜ธ ์ž๋™ ๊ฐ์ง€ (์‚ฌ์šฉ์ž ๋ช…์‹œ) โ•‘
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.219';
10
+ const VERSION = '1.9.220';
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 ์ฒ˜๋ฆฌ).
@@ -2251,6 +2251,140 @@ function _saveAndAppendPreWakeReport(root, audit) {
2251
2251
  return audit;
2252
2252
  }
2253
2253
 
2254
+ // 1.9.220: ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ + ์ž์œจ ์žฌ๊ฐœ (์‚ฌ์šฉ์ž ๋ช…์‹œ)
2255
+ // "์ ˆ์ „๋ชจ๋“œ/์‹œ์Šคํ…œ์ข…๋ฃŒ/AI์—์ด์ „ํŠธ ์„ธ์…˜์ข…๋ฃŒ๋กœ ๋น„์ •์ƒ ์ข…๋ฃŒ๋œ ํ›„ ์žฌ์‹คํ–‰ ์‹œ ์ค‘๋‹จ์ง€์ /๋ˆ„๋ฝ์ž‘์—… ๊ฐ์ง€"
2256
+ // 5์‹ ํ˜ธ ์ข…ํ•ฉ ๋ถ„์„:
2257
+ // 1) last-handoff gap > 60min (1.9.199, 25min interval ๊ธฐ๋Œ€ ๋Œ€๋น„ 2.4๋ฐฐ+)
2258
+ // 2) wakeup miss (active-wakeups pending โ†’ 30min+ ์ง€๋‚จ, 1.9.205)
2259
+ // 3) in-progress task 24h+ ๊ฐฑ์‹  ์—†์Œ (stale, progress-tracker mtime)
2260
+ // 4) auto-resume-plan ์กด์žฌ + ageMin > 60min (1.9.203, ์‚ฌ์šฉ ์•ˆ ๋จ)
2261
+ // 5) release/X.X.X branch ์žˆ์Œ + main ๋ฏธ๋จธ์ง€ (release sync-main ๋ˆ„๋ฝ)
2262
+ // ๊ฒฐ๊ณผ: { abnormalShutdown: true/false, signals: [...], severity, resumeGuide }
2263
+ function _detectAbnormalShutdown(root) {
2264
+ const result = {
2265
+ detectedAt: new Date().toISOString(),
2266
+ signals: [],
2267
+ severity: 'none',
2268
+ abnormalShutdown: false,
2269
+ resumeGuide: []
2270
+ };
2271
+ const now = Date.now();
2272
+
2273
+ // 1) last-handoff gap > 60min (์ •์ƒ 25min interval ๋Œ€๋น„)
2274
+ try {
2275
+ const lhFp = path.join(root, '.harness', 'last-handoff.json');
2276
+ if (exists(lhFp)) {
2277
+ const j = JSON.parse(read(lhFp));
2278
+ const last = j.lastAt || (j.history && j.history.length > 0 ? j.history[j.history.length - 1] : null);
2279
+ if (last) {
2280
+ const lastMs = new Date(last).getTime();
2281
+ const gapMin = Math.floor((now - lastMs) / 60000);
2282
+ if (gapMin > 60) {
2283
+ result.signals.push({
2284
+ kind: 'last-handoff-stale',
2285
+ gapMin,
2286
+ detail: `last handoff ${gapMin}๋ถ„ ์ „ (์ •์ƒ 25min ๊ฐ„๊ฒฉ ๋Œ€๋น„ ${Math.round(gapMin/25)}x ์ดˆ๊ณผ) โ€” ์ ˆ์ „/์ข…๋ฃŒ ์˜์‹ฌ`,
2287
+ severity: gapMin > 240 ? 'high' : 'medium'
2288
+ });
2289
+ }
2290
+ }
2291
+ }
2292
+ } catch {}
2293
+
2294
+ // 2) wakeup miss (active-wakeups pending โ†’ 30min+ ์ง€๋‚จ)
2295
+ try {
2296
+ const wkStat = _analyzeWakeupStatus(root);
2297
+ if (wkStat.hasWakeup && wkStat.deltaMin > 30 && wkStat.kind === 'missed') {
2298
+ result.signals.push({
2299
+ kind: 'wakeup-missed',
2300
+ gapMin: wkStat.deltaMin,
2301
+ detail: `wakeup ${wkStat.deltaMin}๋ถ„ ์ง€๋‚จ (status=pending) โ€” ์ž๋™ ์žฌ๊ฐœ ์‹คํŒจ`,
2302
+ severity: wkStat.deltaMin > 120 ? 'high' : 'medium'
2303
+ });
2304
+ }
2305
+ } catch {}
2306
+
2307
+ // 3) in-progress task 24h+ stale (progress-tracker mtime + ํ™œ์„ฑ task ์นด์šดํŠธ)
2308
+ try {
2309
+ const ptPath = path.join(root, '.harness', 'progress-tracker.md');
2310
+ if (exists(ptPath)) {
2311
+ const stat = fs.statSync(ptPath);
2312
+ const ageMin = Math.floor((now - stat.mtimeMs) / 60000);
2313
+ const content = read(ptPath);
2314
+ const inProgress = (content.match(/^\|\s*T-\d{4,}\s*\|\s*in-progress\s*\|/gm) || []).length;
2315
+ if (inProgress > 0 && ageMin > 24 * 60) {
2316
+ result.signals.push({
2317
+ kind: 'in-progress-stale',
2318
+ inProgressCount: inProgress,
2319
+ ageMin,
2320
+ detail: `${inProgress}๊ฑด in-progress task, progress-tracker ${Math.floor(ageMin/60)}h ๊ฐฑ์‹  ์—†์Œ`,
2321
+ severity: 'high'
2322
+ });
2323
+ }
2324
+ }
2325
+ } catch {}
2326
+
2327
+ // 4) auto-resume-plan ์กด์žฌ + ageMin > 60min (์‚ฌ์šฉ ์•ˆ ๋จ)
2328
+ try {
2329
+ const plan = _loadAutoResumePlan(root);
2330
+ if (plan && plan.ageMin > 60) {
2331
+ result.signals.push({
2332
+ kind: 'auto-resume-plan-unused',
2333
+ ageMin: plan.ageMin,
2334
+ nextRound: plan.nextRoundVersion,
2335
+ detail: `auto-resume-plan ${plan.ageMin}๋ถ„ ์ „ ์ž‘์„ฑ (${plan.nextRoundVersion}) โ€” ์‚ฌ์šฉ ์•ˆ ๋จ`,
2336
+ severity: plan.ageMin > 240 ? 'medium' : 'low'
2337
+ });
2338
+ }
2339
+ } catch {}
2340
+
2341
+ // 5) release/X.X.X branch ์žˆ์Œ + main ๋ฏธ๋จธ์ง€ (git ์ƒํƒœ)
2342
+ try {
2343
+ const r = cp.spawnSync('git', ['branch', '--list', 'release/*'], { cwd: root, encoding: 'utf8', timeout: 3000 });
2344
+ if (r.status === 0) {
2345
+ const branches = (r.stdout || '').split('\n').map(s => s.trim().replace(/^\*?\s*/, '')).filter(b => b.startsWith('release/'));
2346
+ if (branches.length >= 2) { // 2๊ฐœ ์ด์ƒ์ด๋ฉด ๋ˆ„๋ฝ ๊ฐ€๋Šฅ์„ฑ
2347
+ result.signals.push({
2348
+ kind: 'release-branch-pending',
2349
+ count: branches.length,
2350
+ recent: branches.slice(-3),
2351
+ detail: `${branches.length}๊ฑด release/* branch (sync-main ๋ˆ„๋ฝ ๊ฐ€๋Šฅ)`,
2352
+ severity: 'low'
2353
+ });
2354
+ }
2355
+ }
2356
+ } catch {}
2357
+
2358
+ // ์ข…ํ•ฉ ํŒ๋‹จ
2359
+ const high = result.signals.filter(s => s.severity === 'high').length;
2360
+ const medium = result.signals.filter(s => s.severity === 'medium').length;
2361
+ if (high > 0) { result.severity = 'high'; result.abnormalShutdown = true; }
2362
+ else if (medium > 0) { result.severity = 'medium'; result.abnormalShutdown = true; }
2363
+ else if (result.signals.length > 0) result.severity = 'low';
2364
+
2365
+ // ์žฌ๊ฐœ ๊ฐ€์ด๋“œ
2366
+ if (result.abnormalShutdown) {
2367
+ result.resumeGuide.push('1. leerness handoff . โ€” ํ˜„์žฌ ์ƒํƒœ ์ข…ํ•ฉ ํ™•์ธ');
2368
+ if (result.signals.some(s => s.kind === 'auto-resume-plan-unused')) {
2369
+ result.resumeGuide.push('2. leerness resume โ€” ์ €์žฅ๋œ auto-resume-plan ์ ์šฉ (1.9.203)');
2370
+ }
2371
+ if (result.signals.some(s => s.kind === 'in-progress-stale')) {
2372
+ result.resumeGuide.push('3. leerness task list --status in-progress โ€” stale task ๊ฒ€ํ†  (drop or ์žฌ๊ฐœ)');
2373
+ }
2374
+ if (result.signals.some(s => s.kind === 'wakeup-missed')) {
2375
+ result.resumeGuide.push('4. ScheduleWakeup ์žฌ๋“ฑ๋ก (์‚ฌ์šฉ์ž ํŠธ๋ฆฌ๊ฑฐ ๋˜๋Š” R-0001 ๋ฃฐ)');
2376
+ }
2377
+ if (result.signals.some(s => s.kind === 'release-branch-pending')) {
2378
+ result.resumeGuide.push('5. git branch -a๋กœ release/* ํ™•์ธ + leerness release sync-main ์žฌ์‹คํ–‰');
2379
+ }
2380
+ result.resumeGuide.push('6. leerness pre-wake-audit โ€” ๋ˆ„๋ฝ ์ž‘์—… / ์ถฉ๋Œ ์ข…ํ•ฉ ์ ๊ฒ€');
2381
+ result.resumeGuide.push('7. leerness requests audit โ€” ๋ฏธ๋‹ต ์‚ฌ์šฉ์ž ์š”์ฒญ ํ™•์ธ');
2382
+ } else {
2383
+ result.resumeGuide.push('์ •์ƒ ์šด์˜ ์ค‘ โ€” ๋น„์ •์ƒ ์ข…๋ฃŒ ์‹ ํ˜ธ ์—†์Œ');
2384
+ }
2385
+ return result;
2386
+ }
2387
+
2254
2388
  // 1.9.210: adaptive wakeup interval (์‚ฌ์šฉ์ž ๋ช…์‹œ)
2255
2389
  // "wakeup 30๋ถ„๋“ฑ ๊ธด ์‹œ๊ฐ„์ด ํ•„์š”์—†๋‹ค๋ฉด ๊ฐ„๊ฒฉ์„ ํƒ€์ดํŠธํ•˜๊ฒŒ ์ž๋™์œผ๋กœ ์กฐ์ ˆํ•˜๋„๋ก"
2256
2390
  // ์‚ฌ์šฉ์ž ํ™œ๋™๋Ÿ‰ ๊ธฐ๋ฐ˜ ๊ถŒ์žฅ interval ๊ณ„์‚ฐ โ†’ ScheduleWakeup ์‹œ ์ž๋™ ์ ์šฉ (R-0001 ๋ฃฐ ์™ธ ๋™์  ๋ณด์ •)
@@ -2920,6 +3054,47 @@ function requestsCmd(root, sub, ...rest) {
2920
3054
  process.exit(1);
2921
3055
  }
2922
3056
 
3057
+ // 1.9.220: leerness session-resume โ€” ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ + ์ž์œจ ์žฌ๊ฐœ ๊ฐ€์ด๋“œ (์‚ฌ์šฉ์ž ๋ช…์‹œ)
3058
+ function sessionResumeCmd(root) {
3059
+ root = absRoot(root);
3060
+ const isTty = process.stdout && process.stdout.isTTY;
3061
+ const cyan = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
3062
+ const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
3063
+ const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
3064
+ const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
3065
+ const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
3066
+
3067
+ const result = _detectAbnormalShutdown(root);
3068
+ if (has('--json')) { log(JSON.stringify(result, null, 2)); return; }
3069
+ log(cyan(`# leerness session-resume (1.9.220) โ€” ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ + ์ž์œจ ์žฌ๊ฐœ`));
3070
+ log(` detected at: ${result.detectedAt}`);
3071
+ log('');
3072
+ if (!result.abnormalShutdown) {
3073
+ log(grn(` โœ“ ๋น„์ •์ƒ ์ข…๋ฃŒ ์‹ ํ˜ธ ์—†์Œ โ€” ์ •์ƒ ์šด์˜ ์ค‘`));
3074
+ if (result.signals.length > 0) {
3075
+ log(dim(` (low-severity ์‹ ํ˜ธ ${result.signals.length}๊ฑด โ€” ๋ฌด์‹œ ๊ฐ€๋Šฅ)`));
3076
+ }
3077
+ log('');
3078
+ log(dim(` โ†’ ํ‰์†Œ๋Œ€๋กœ leerness handoff . ๋กœ ์‹œ์ž‘`));
3079
+ return;
3080
+ }
3081
+ const sevIcon = result.severity === 'high' ? '๐Ÿšจ' : 'โš ';
3082
+ const sevColor = result.severity === 'high' ? red : yel;
3083
+ log(sevColor(` ${sevIcon} ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ โ€” severity: ${result.severity} (signals: ${result.signals.length})`));
3084
+ log('');
3085
+ log(`## ๊ฐ์ง€ ์‹ ํ˜ธ`);
3086
+ for (const s of result.signals) {
3087
+ const icon = s.severity === 'high' ? '๐Ÿšจ' : (s.severity === 'medium' ? 'โš ' : 'โ„น');
3088
+ const c = s.severity === 'high' ? red : (s.severity === 'medium' ? yel : dim);
3089
+ log(c(` ${icon} [${s.kind}] ${s.detail}`));
3090
+ }
3091
+ log('');
3092
+ log(`## ์žฌ๊ฐœ ๊ฐ€์ด๋“œ`);
3093
+ for (const g of result.resumeGuide) {
3094
+ log(` ${g}`);
3095
+ }
3096
+ }
3097
+
2923
3098
  // 1.9.208: leerness constraints <list|check|add> โ€” ํ”Œ๋žซํผ/API ์ œ์•ฝ ์‚ฌ์ „ ์ฒดํฌ CLI (์‚ฌ์šฉ์ž ๋ช…์‹œ)
2924
3099
  // "ํŠน์ • ํ”Œ๋žซํผ์˜ API ... ํ˜ธ์ถœ์†๋„๊ฐ€ ์ดˆ๋‹น 5ํšŒ ์ดํ•˜๋กœ๋งŒ ํ•ด์•ผํ•œ๋‹ค๋Š” ๊ทœ์ •์„ ๋จผ์ € ํ™•์ธ"
2925
3100
  // list โ†’ ๋“ฑ๋ก๋œ ๋ชจ๋“  ํ”Œ๋žซํผ catalog ์ถœ๋ ฅ
@@ -5694,6 +5869,13 @@ function handoff(root) {
5694
5869
  }
5695
5870
  }
5696
5871
  } catch {}
5872
+ // 16) 1.9.220: ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ (์‚ฌ์šฉ์ž ๋ช…์‹œ) โ€” ๊นจ์–ด๋‚จ ์งํ›„ ์ž๋™ ๋…ธ์ถœ
5873
+ try {
5874
+ const ad = _detectAbnormalShutdown(root);
5875
+ if (ad.abnormalShutdown) {
5876
+ parts.push(`๐Ÿ”Œ ๋น„์ •์ƒ์ข…๋ฃŒ ${ad.severity} (${ad.signals.length}์‹ ํ˜ธ)`);
5877
+ }
5878
+ } catch {}
5697
5879
  // 15) 1.9.215: ํ˜„์žฌ ํ™œ์„ฑ task์—์„œ constraints/intent ์ž๋™ ๋ถ„์„ (1.9.208/213 ํ†ตํ•ฉ)
5698
5880
  try {
5699
5881
  // progress-tracker.md ์˜ ์ฒซ active task request ์ถ”์ถœ
@@ -5732,7 +5914,7 @@ function handoff(root) {
5732
5914
  if (parts.length) {
5733
5915
  const isTty = process.stdout && process.stdout.isTTY;
5734
5916
  const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
5735
- log(cy(`๐Ÿ“Š ํ—ค๋“œ๋ผ์ธ (1.9.81/93/113/152/162/192/197/204/207/209/215): ${parts.join(' ยท ')}`));
5917
+ log(cy(`๐Ÿ“Š ํ—ค๋“œ๋ผ์ธ (1.9.81/93/113/152/162/192/197/204/207/209/215/220): ${parts.join(' ยท ')}`));
5736
5918
  }
5737
5919
  } catch {}
5738
5920
  }
@@ -17197,6 +17379,8 @@ async function main() {
17197
17379
  if (cmd === 'resume') return resumeCmd(arg('--path', process.cwd()));
17198
17380
  // 1.9.207: leerness requests <audit|add|list|complete|drop> โ€” ์‚ฌ์šฉ์ž ์š”์ฒญ ๋ˆ„๋ฝ ํ™•์ธ ์ ˆ์ฐจ (์‚ฌ์šฉ์ž ๋ช…์‹œ)
17199
17381
  if (cmd === 'requests') return requestsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
17382
+ // 1.9.220: leerness session-resume โ€” ๋น„์ •์ƒ ์ข…๋ฃŒ ๊ฐ์ง€ + ์ž์œจ ์žฌ๊ฐœ ๊ฐ€์ด๋“œ (์‚ฌ์šฉ์ž ๋ช…์‹œ)
17383
+ if (cmd === 'session-resume') return sessionResumeCmd(arg('--path', process.cwd()));
17200
17384
  // 1.9.208: leerness constraints <list|check|add> โ€” ํ”Œ๋žซํผ/API ์ œ์•ฝ ์‚ฌ์ „ ์ฒดํฌ (์‚ฌ์šฉ์ž ๋ช…์‹œ)
17201
17385
  if (cmd === 'constraints') return constraintsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
17202
17386
  // 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.219",
3
+ "version": "1.9.220",
4
4
  "description": "Leerness: ๋น„ํŒŒ๊ดด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ์ž๋™ ๋ฒ„์ „ ๊ฐ์ง€ยท์—…๋ฐ์ดํŠธ, ๊ณ„ํš/์ง„ํ–‰/ํ•ธ๋“œ์˜คํ”„ ์ž๋™ํ™”, ๊ฒŒ์œผ๋ฆ„ยท์‹œํฌ๋ฆฟยท์ธ์ฝ”๋”ฉ ์ž๋™ ๊ฐ€๋“œ, Claude Code ์Šฌ๋ž˜์‹œ ํ†ตํ•ฉ์„ ๊ฐ–์ถ˜ ํ•œ๊ตญ์–ด ์šฐ์„  AI ๊ฐœ๋ฐœ ํ•˜๋„ค์Šค.",
5
5
  "keywords": [
6
6
  "leerness",