leerness 1.9.241 β†’ 1.9.242

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,44 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.242 β€” 2026-05-26
4
+
5
+ **🌐 UR-0014 2단계: env encoding --apply (BOM μžλ™ μΆ”κ°€) + JSON 10 ν•„λ“œ envInfo + drift --auto-fix 톡합.**
6
+
7
+ ### μ‚¬μš©μž λͺ…μ‹œ (UR-0014) β€” 2단계 μžλ™ 회볡
8
+
9
+ 1.9.241 μ—μ„œ κ°μ§€λ§Œ μ œκ³΅ν–ˆλ˜ μœ„ν—˜μ„ 1.9.242 κ°€ **μ‹€μ œ μžλ™ μˆ˜μ •**으둜 ν™•μž₯:
10
+
11
+ ### 1. `leerness env encoding --apply` μžλ™ BOM μΆ”κ°€
12
+ - `.ps1` / `.bat` / `.cmd` / `.sh` 의 μœ„ν—˜ νŒŒμΌμ— UTF-8 BOM (`EF BB BF`) μžλ™ prepend
13
+ - `--auto-fix-bom` 별칭 동일 λ™μž‘
14
+ - κΈ°λ³Έ dry-run μœ μ§€ (--apply λͺ…μ‹œ μ‹œμ—λ§Œ λ³€κ²½) β€” μ•ˆμ „ 원칙
15
+ - 적용 κ²°κ³Ό `result.applied` λ°°μ—΄λ‘œ λ…ΈμΆœ (file/action: utf8-bom-added | failed)
16
+
17
+ ### 2. handoff/session close/health --json **10 ν•„λ“œ** envInfo 톡합
18
+ - JSON 톡합 맀트릭슀 9 β†’ **10 ν•„λ“œ** μ§„ν™” (3 λͺ…λ Ή Γ— 10 = 30 톡합 포인트)
19
+ - `envInfo`: os / isKoreanWindows / codepage / nodeVersion / shellScriptsScanned / encodingRiskCount / encodingRiskFiles[0..5]
20
+ - μ™ΈλΆ€ AI κ°€ ν™˜κ²½ μ»¨ν…μŠ€νŠΈ + 인코딩 μœ„ν—˜μ„ 단일 ν˜ΈμΆœμ—μ„œ 회수
21
+
22
+ ### 3. drift check --auto-fix env encoding BOM 톡합
23
+ - 1.9.82 λ³΄μ•ˆ 회볡 + 1.9.225 delivered + 1.9.236 release cleanup μžλ™ 회볡 νŒ¨ν„΄ ν™•μž₯
24
+ - `drift check --auto-fix` μ‹œ μ…Έ 슀크립트 μœ„ν—˜ μžλ™ BOM μΆ”κ°€
25
+ - log: `🌐 --auto-fix ν™œμ„± (1.9.242) β€” μ…Έ 슀크립트 인코딩 μœ„ν—˜ N건 BOM μžλ™ μΆ”κ°€ 쀑...`
26
+
27
+ ### 4. λˆ„μ  νšŒκ·€ (1.9.207~241) β€” λͺ¨λ‘ μœ μ§€
28
+ - MCP 69 도ꡬ μœ μ§€ (1.9.242 λŠ” μ‹ κ·œ CLI μ˜΅μ…˜ + 톡합, 도ꡬ 증가 X)
29
+ - handoff JSON: userRequestsAudit + preWakeAudit + idempotencyAudit + abnormalShutdown + deliveredRequests + roundHistory + milestones + recentChanges + pyFiles + **envInfo** (10)
30
+
31
+ ### 5. stress-v187 β€” **22/22 PASS Β· 100%**
32
+ - 1.9.242 (8): VERSION + env --apply (격리) + --auto-fix-bom 별칭 + handoff/session close/health 10ν•„λ“œ envInfo + drift --auto-fix BOM 톡합 + envInfo μŠ€ν‚€λ§ˆ
33
+ - μ„±λŠ₯ (2): cold_start avg 371ms Β· env --apply 372ms
34
+ - λˆ„μ  νšŒκ·€ (12): 1.9.207~241
35
+
36
+ ### 6. μžλ™ release (104 λΌμš΄λ“œ main-push streak Β· 65 λΌμš΄λ“œ npm publish streak)
37
+
38
+ 🌐 **UR-0014 μ™„μ „ μžλ™ν™”** β€” 감지 (1.9.241) β†’ μžλ™ μˆ˜μ • (1.9.242)
39
+
40
+ ---
41
+
3
42
  ## 1.9.241 β€” 2026-05-24
4
43
 
5
44
  **🌐 leerness env + ν•œκ΅­μ–΄ PowerShell 인코딩 μœ„ν—˜ 사전 감지 (μ‚¬μš©μž λͺ…μ‹œ UR-0014).**
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.241-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v186-16%2F16-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-69-brightgreen)]() [![cli](https://img.shields.io/badge/CLI_commands-56-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-197-blueviolet)]() [![main-push](https://img.shields.io/badge/πŸŽ‰_main--push_streak-103_rounds-success)]() [![npm-streak](https://img.shields.io/badge/πŸŽ‰_npm--publish-64_streak-success)]() [![encoding](https://img.shields.io/badge/🌐_env_encoding-ν•œκ΅­μ–΄_PS_μœ„ν—˜_감지-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-598ms-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.242-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v187-22%2F22-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-69-brightgreen)]() [![cli](https://img.shields.io/badge/CLI_commands-56-brightgreen)]() [![json-fields](https://img.shields.io/badge/JSON_톡합-10_ν•„λ“œ-blueviolet)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-198-blueviolet)]() [![main-push](https://img.shields.io/badge/πŸŽ‰_main--push_streak-104_rounds-success)]() [![npm-streak](https://img.shields.io/badge/πŸŽ‰_npm--publish-65_streak-success)]() [![encoding](https://img.shields.io/badge/🌐_env_encoding-BOM_μžλ™μΆ”κ°€-blueviolet)]() [![perf](https://img.shields.io/badge/cold_start-371ms-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.241 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.242 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ 🌐 env encoding μœ„ν—˜ 사전 감지 (μ‚¬μš©μž λͺ…μ‹œ UR-0014) β•‘
17
+ β•‘ 🌐 env encoding --apply BOM μžλ™ μΆ”κ°€ (UR-0014 2단계) β•‘
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.241';
10
+ const VERSION = '1.9.242';
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 처리).
@@ -2491,8 +2491,25 @@ function envCmd(root, sub) {
2491
2491
  const dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
2492
2492
  if (sub === 'encoding-check') {
2493
2493
  const result = _scanShellScriptsEncoding(root);
2494
+ // 1.9.242: --apply μ˜΅μ…˜ β€” μœ„ν—˜ νŒŒμΌμ— UTF-8 BOM μžλ™ μΆ”κ°€ (μ‚¬μš©μž λͺ…μ‹œ UR-0014 2단계)
2495
+ const apply = has('--apply') || has('--auto-fix-bom');
2496
+ if (apply) result.applied = [];
2497
+ if (apply && result.atRisk.length > 0) {
2498
+ for (const r of result.atRisk) {
2499
+ try {
2500
+ const fullPath = path.join(root, r.file);
2501
+ const orig = fs.readFileSync(fullPath);
2502
+ const bom = Buffer.from([0xEF, 0xBB, 0xBF]);
2503
+ const fixed = Buffer.concat([bom, orig]);
2504
+ fs.writeFileSync(fullPath, fixed);
2505
+ result.applied.push({ file: r.file, action: 'utf8-bom-added' });
2506
+ } catch (e) {
2507
+ result.applied.push({ file: r.file, action: 'failed', error: e.message });
2508
+ }
2509
+ }
2510
+ }
2494
2511
  if (has('--json')) { log(JSON.stringify(result, null, 2)); return; }
2495
- log(cy(`# leerness env encoding-check (1.9.241, UR-0014) β€” μ…Έ 슀크립트 인코딩 μœ„ν—˜ 감지`));
2512
+ log(cy(`# leerness env encoding-check (1.9.241/242, UR-0014) β€” μ…Έ 슀크립트 인코딩 μœ„ν—˜ 감지`));
2496
2513
  log('');
2497
2514
  log(` μŠ€μΊ”: ${gr(String(result.scanned))} 파일 (.ps1/.bat/.cmd/.sh)`);
2498
2515
  if (result.atRisk.length === 0) {
@@ -2504,7 +2521,14 @@ function envCmd(root, sub) {
2504
2521
  log(dm(` ${r.risk}`));
2505
2522
  });
2506
2523
  log('');
2507
- result.notes.forEach(n => log(yl(` πŸ’‘ ${n}`)));
2524
+ if (apply) {
2525
+ const okCnt = (result.applied || []).filter(a => a.action === 'utf8-bom-added').length;
2526
+ const failCnt = (result.applied || []).filter(a => a.action === 'failed').length;
2527
+ log(gr(` βœ“ UTF-8 BOM μΆ”κ°€ ${okCnt}건${failCnt > 0 ? ` (μ‹€νŒ¨ ${failCnt}건)` : ''} (1.9.242 --apply)`));
2528
+ } else {
2529
+ result.notes.forEach(n => log(yl(` πŸ’‘ ${n}`)));
2530
+ log(dm(` β†’ μžλ™ μˆ˜μ •: leerness env encoding --apply (BOM μžλ™ μΆ”κ°€)`));
2531
+ }
2508
2532
  }
2509
2533
  return;
2510
2534
  }
@@ -6554,6 +6578,20 @@ function handoff(root) {
6554
6578
  totalClasses: analyses.reduce((s, a) => s + a.classes, 0)
6555
6579
  };
6556
6580
  } catch {}
6581
+ // 1.9.242: envInfo 톡합 (handoff JSON 10번째 톡합 ν•„λ“œ) β€” ν™˜κ²½ + 인코딩 μœ„ν—˜ (UR-0014 2단계)
6582
+ try {
6583
+ const runtimeEnv = _collectRuntimeEnv();
6584
+ const encScan = _scanShellScriptsEncoding(root);
6585
+ result.envInfo = {
6586
+ os: runtimeEnv.os.platform,
6587
+ isKoreanWindows: runtimeEnv.locale.isKoreanWindows || false,
6588
+ codepage: runtimeEnv.locale.codepage || null,
6589
+ nodeVersion: runtimeEnv.node.version,
6590
+ shellScriptsScanned: encScan.scanned,
6591
+ encodingRiskCount: encScan.atRisk.length,
6592
+ encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file)
6593
+ };
6594
+ } catch {}
6557
6595
  } catch {}
6558
6596
  try {
6559
6597
  const pwState = _loadPreWakeReport(root);
@@ -10777,6 +10815,20 @@ function sessionClose(root, opts = {}) {
10777
10815
  totalClasses: analyses.reduce((s, a) => s + a.classes, 0)
10778
10816
  };
10779
10817
  } catch {}
10818
+ // 1.9.242: envInfo 톡합 (session close JSON 10번째 톡합 ν•„λ“œ) β€” UR-0014 2단계
10819
+ try {
10820
+ const runtimeEnv = _collectRuntimeEnv();
10821
+ const encScan = _scanShellScriptsEncoding(root);
10822
+ jsonResult.envInfo = {
10823
+ os: runtimeEnv.os.platform,
10824
+ isKoreanWindows: runtimeEnv.locale.isKoreanWindows || false,
10825
+ codepage: runtimeEnv.locale.codepage || null,
10826
+ nodeVersion: runtimeEnv.node.version,
10827
+ shellScriptsScanned: encScan.scanned,
10828
+ encodingRiskCount: encScan.atRisk.length,
10829
+ encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file)
10830
+ };
10831
+ } catch {}
10780
10832
  } catch {}
10781
10833
  try {
10782
10834
  // 1.9.209: pre-wake-audit μžλ™ μ‹€ν–‰ + μ €μž₯ (sleep μ „ μžλ™ 점검)
@@ -13868,6 +13920,31 @@ function driftCheckCmd(root, opts = {}) {
13868
13920
  log(`⚠ auto-fix λ³΄μ•ˆ 회볡 였λ₯˜: ${e.message}`);
13869
13921
  }
13870
13922
  }
13923
+ // 1.9.242: drift check --auto-fix 에 env encoding BOM μžλ™ μΆ”κ°€ 톡합 (μ‚¬μš©μž λͺ…μ‹œ UR-0014 2단계)
13924
+ // 1.9.82 νŒ¨ν„΄ ν™•μž₯ β€” drift 회볡 μ‹œ μ…Έ 슀크립트 인코딩 μœ„ν—˜λ„ μžλ™ ν•΄κ²°
13925
+ if (autoFix) {
13926
+ try {
13927
+ const encScan = _scanShellScriptsEncoding(root);
13928
+ if (encScan.atRisk && encScan.atRisk.length > 0) {
13929
+ log('');
13930
+ log(`🌐 --auto-fix ν™œμ„± (1.9.242) β€” μ…Έ 슀크립트 인코딩 μœ„ν—˜ ${encScan.atRisk.length}건 BOM μžλ™ μΆ”κ°€ 쀑...`);
13931
+ let ok = 0;
13932
+ for (const r of encScan.atRisk) {
13933
+ try {
13934
+ const fullPath = path.join(root, r.file);
13935
+ const orig = fs.readFileSync(fullPath);
13936
+ const bom = Buffer.from([0xEF, 0xBB, 0xBF]);
13937
+ const fixed = Buffer.concat([bom, orig]);
13938
+ fs.writeFileSync(fullPath, fixed);
13939
+ ok++;
13940
+ } catch {}
13941
+ }
13942
+ log(`βœ“ UTF-8 BOM μΆ”κ°€ ${ok}/${encScan.atRisk.length}건 (1.9.242 UR-0014)`);
13943
+ }
13944
+ } catch (e) {
13945
+ log(`⚠ env encoding auto-fix 였λ₯˜ (1.9.242): ${e.message}`);
13946
+ }
13947
+ }
13871
13948
  // 1.9.225: drift check --auto-fix 에 delivered νŒ¨ν„΄ μžλ™ 적용 톡합 (1.9.223/224 μ‹œμŠ€ν…œ 회수)
13872
13949
  // μ‚¬μš©μž μš”μ²­μ— "κ΅¬ν˜„ μ™„λ£Œ" νŒ¨ν„΄μ΄ λˆ„μ λ˜λ©΄ κ°€μ§œ λ―Έλ‹΅ μ‹ ν˜Έκ°€ drift score λ₯Ό κ°€μ€‘μ‹œν‚¬ 수 있음 β†’ μžλ™ 정리.
13873
13950
  // 1.9.82 audit --fix νŒ¨ν„΄κ³Ό 동일: --auto-fix μ‹œ μ¦‰μ‹œ 적용, 적용 ν›„ μž¬κ²€μ‚¬.
@@ -17348,6 +17425,20 @@ function healthCmd(root) {
17348
17425
  totalClasses: analyses.reduce((s, a) => s + a.classes, 0)
17349
17426
  };
17350
17427
  } catch { out.pyFiles = { error: 'pyFiles 점검 μ‹€νŒ¨' }; }
17428
+ // 1.9.242: health --json envInfo 톡합 (3 λͺ…λ Ή 10 ν•„λ“œ β€” UR-0014 2단계)
17429
+ try {
17430
+ const runtimeEnv = _collectRuntimeEnv();
17431
+ const encScan = _scanShellScriptsEncoding(root);
17432
+ out.envInfo = {
17433
+ os: runtimeEnv.os.platform,
17434
+ isKoreanWindows: runtimeEnv.locale.isKoreanWindows || false,
17435
+ codepage: runtimeEnv.locale.codepage || null,
17436
+ nodeVersion: runtimeEnv.node.version,
17437
+ shellScriptsScanned: encScan.scanned,
17438
+ encodingRiskCount: encScan.atRisk.length,
17439
+ encodingRiskFiles: encScan.atRisk.slice(0, 5).map(r => r.file)
17440
+ };
17441
+ } catch { out.envInfo = { error: 'envInfo 점검 μ‹€νŒ¨' }; }
17351
17442
  // 1.9.163: 5λŠ₯λ ₯ 맀트릭슀 μžλ™ 평가 (1.9.155 sub-agent 점검 β†’ μ½”λ“œ 기반 μžλ™ν™”)
17352
17443
  // 각 λŠ₯λ ₯을 μ½”λ“œ grep 으둜 κ²€μΆœ β†’ 0~100 점수. μ‚¬μš©μžκ°€ λ§€ health 호좜 μ‹œ leerness 자기 평가 확인.
17353
17444
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.241",
3
+ "version": "1.9.242",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",