leerness 1.9.240 β 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 +84 -0
- package/README.md +3 -3
- package/bin/harness.js +274 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,89 @@
|
|
|
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
|
+
|
|
42
|
+
## 1.9.241 β 2026-05-24
|
|
43
|
+
|
|
44
|
+
**π leerness env + νκ΅μ΄ PowerShell μΈμ½λ© μν μ¬μ κ°μ§ (μ¬μ©μ λͺ
μ UR-0014).**
|
|
45
|
+
|
|
46
|
+
### μ¬μ©μ λͺ
μ (UR-0014)
|
|
47
|
+
> *"leerness μ€μΉ νλ‘μ νΈμμ PowerShell/ν°λ―Έλ νκ΅μ΄ μΈμ½λ© μ€λ₯ μ¬μ κ°μ§ β OS/μΈμ΄μ€μ /νλμ¨μ΄/ν°λ―Έλ/SW λ²μ λ°μ΄ν° μμ§λ‘ κ°λ°/ν
μ€νΈ/λλ²κΉ
μ νκ²½ νΈνμ± λ³΄μ₯"*
|
|
48
|
+
|
|
49
|
+
λ°°κ²½: μ¬μ©μκ° `3d-map-maker` νλ‘μ νΈμμ `npm run setup` β `setup.ps1` νμ± μ€λ₯ (νκ΅μ΄ + BOM μλ UTF-8 β PowerShell CP949 μ€μΈμ)
|
|
50
|
+
|
|
51
|
+
### 1. `leerness env summary` μ λͺ
λ Ή (1.9.145 envCheck μ λ³κ°)
|
|
52
|
+
- νκ²½ μ’
ν© μΆλ ₯: OS / Node / Locale / νκ΅μ΄ Windows κ°μ§ / Hardware / Terminal (PowerShell λ²μ ) / Tools (git/npm/python)
|
|
53
|
+
- `chcp` μΆλ ₯μΌλ‘ μ½λνμ΄μ§ μλ κ°μ§ (949 = νκ΅μ΄)
|
|
54
|
+
- `--json` μ΅μ
|
|
55
|
+
- μ κ· helper: `_collectRuntimeEnv()` (κΈ°μ‘΄ `_detectEnvironment` μ λͺ
λͺ
λΆλ¦¬)
|
|
56
|
+
|
|
57
|
+
### 2. `leerness env encoding` μ λͺ
λ Ή β μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν κ°μ§
|
|
58
|
+
- `.ps1` / `.bat` / `.cmd` / `.sh` μλ μ€μΊ
|
|
59
|
+
- BOM μλ λΉ-ASCII λ°μ΄νΈ κ²μΆ (μ¬κ·, 4096 byte μ΄λ΄)
|
|
60
|
+
- μν μ: `Windows νκ΅μ΄ PowerShell μμ CP949 λ‘ μ€μΈμ κ°λ₯ (BOM μΆκ° κΆμ₯)`
|
|
61
|
+
- ν΄κ²°μ±
μλ μ μ (UTF-8 BOM μΆκ° λλ `$OutputEncoding` μ€μ )
|
|
62
|
+
|
|
63
|
+
### 3. handoff body μλ λ
ΈμΆ
|
|
64
|
+
- `## β μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν N건 (1.9.241, UR-0014)` λ³Έλ¬Έ μΉμ
|
|
65
|
+
- top 3 μν νμΌ + ν΄κ²° μλ΄ (BOM μΆκ°)
|
|
66
|
+
- `leerness env encoding` κ°μ΄λ μλ
|
|
67
|
+
|
|
68
|
+
### 4. MCP 69λ²μ§Έ λꡬ β `leerness_env_info`
|
|
69
|
+
- μΈλΆ AI κ° νκ²½ νΈνμ± μ¬μ μΈμ§ β μΈμ½λ© μ€λ₯ μλ°©
|
|
70
|
+
- `encodingCheck: true` μ΅μ
μ μ
Έ μ€ν¬λ¦½νΈ μ€μΊ
|
|
71
|
+
- MCP 68 β **69** (+1)
|
|
72
|
+
|
|
73
|
+
### 5. λμ νκ· (1.9.207~240) β λͺ¨λ μ μ§
|
|
74
|
+
- κΈ°μ‘΄ `_detectEnvironment(root)` (1.9.145) μ μΆ©λ μμ΄ κ³΅μ‘΄
|
|
75
|
+
|
|
76
|
+
### 6. stress-v186 β 16/16 PASS
|
|
77
|
+
- 1.9.241 (7): VERSION + env summary + JSON + encoding μν κ°μ§ + μμ μ μν 0 + handoff body + MCP 69
|
|
78
|
+
- μ±λ₯ (1): cold_start avg 598ms
|
|
79
|
+
- λμ νκ· (8): 1.9.207~240
|
|
80
|
+
|
|
81
|
+
### 7. μλ release (103 λΌμ΄λ main-push streak Β· 64 λΌμ΄λ npm publish streak)
|
|
82
|
+
|
|
83
|
+
π **νκ΅μ΄ Windows νκ²½ νΈνμ± λ³΄κ°** β μ¬μ©μ λ³΄κ³ .ps1 νμ± μ€λ₯ κ°μ μΌμ΄μ€ μ¬μ κ°μ§
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
3
87
|
## 1.9.240 β 2026-05-24
|
|
4
88
|
|
|
5
89
|
**π UR-0013 2λ¨κ³: handoff/session close/health --json pyFiles (9 νλ) + ν€λλΌμΈ μλ.**
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **AI μ½λ© μμ΄μ νΈμ κ±°μ§ μλ£Β·μ€λ³΅Β·λ§κ°Β·μΆ©λμ λ§μμ£Όλ κ²μΒ·κΈ°μ΅Β·νμ
CLI νλ€μ€.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []() []() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
β βββ ββββββ ββββββ ββββββββββββββββββββββββ ββββββββ β
|
|
13
13
|
β βββββββββββββββββββββββββββ ββββββ ββββββββββββββββββββββ β
|
|
14
14
|
β βββββββββββββββββββββββββββ ββββββ βββββββββββββββββββββ β
|
|
15
|
-
β v1.9.
|
|
15
|
+
β v1.9.242 AI Agent Reliability Harness + Sandbox β
|
|
16
16
|
β verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β
|
|
17
|
-
β
|
|
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.
|
|
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 μ²λ¦¬).
|
|
@@ -2376,6 +2376,181 @@ function _computeRecentChanges(root, limit = 5) {
|
|
|
2376
2376
|
return items;
|
|
2377
2377
|
}
|
|
2378
2378
|
|
|
2379
|
+
// 1.9.241: νκ²½ μ 보 μ’
ν© μμ§ + μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν κ°μ§ (μ¬μ©μ λͺ
μ UR-0014)
|
|
2380
|
+
// μ¬μ©μ λ³΄κ³ : Windows + νκ΅μ΄ PowerShell μμ .ps1 UTF-8 (no BOM) νμΌμ΄ CP949 λ‘ μλͺ» μΈμλμ΄ νμ± μ€λ₯
|
|
2381
|
+
// ν΄κ²°: leerness κ° νκ²½ μ 보 + μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ©μ μ¬μ κ°μ§ β handoff body κ²½κ³
|
|
2382
|
+
// μ£Όμ: κΈ°μ‘΄ _detectEnvironment (1.9.145) μ λͺ
λͺ
μΆ©λ β _collectRuntimeEnv λ‘ λΆλ¦¬
|
|
2383
|
+
function _collectRuntimeEnv() {
|
|
2384
|
+
const env = {
|
|
2385
|
+
os: { platform: os.platform(), release: os.release(), arch: os.arch() },
|
|
2386
|
+
node: { version: process.version, exe: process.execPath },
|
|
2387
|
+
locale: {
|
|
2388
|
+
LANG: process.env.LANG || null,
|
|
2389
|
+
LC_ALL: process.env.LC_ALL || null,
|
|
2390
|
+
LC_CTYPE: process.env.LC_CTYPE || null,
|
|
2391
|
+
// Windows νκ΅μ΄ νκ²½ detect
|
|
2392
|
+
OEMCP: process.env.OEMCP || null, // CP949 = 949
|
|
2393
|
+
isKoreanWindows: false
|
|
2394
|
+
},
|
|
2395
|
+
hardware: {
|
|
2396
|
+
cpus: os.cpus().length,
|
|
2397
|
+
memGB: Math.round(os.totalmem() / 1024 / 1024 / 1024),
|
|
2398
|
+
hostname: os.hostname()
|
|
2399
|
+
},
|
|
2400
|
+
terminal: {
|
|
2401
|
+
isTTY: !!(process.stdout && process.stdout.isTTY),
|
|
2402
|
+
term: process.env.TERM || null,
|
|
2403
|
+
shell: process.env.SHELL || process.env.ComSpec || null,
|
|
2404
|
+
powershell: null
|
|
2405
|
+
},
|
|
2406
|
+
tools: { git: null, npm: null, python: null, python3: null }
|
|
2407
|
+
};
|
|
2408
|
+
// νκ΅μ΄ Windows κ°μ§
|
|
2409
|
+
try {
|
|
2410
|
+
if (env.os.platform === 'win32') {
|
|
2411
|
+
// chcp μΆλ ₯μΌλ‘ μ½λνμ΄μ§ νμΈ
|
|
2412
|
+
const r = cp.spawnSync('chcp', [], { encoding: 'utf8', shell: true, timeout: 3000 });
|
|
2413
|
+
const m = (r.stdout || '').match(/(\d{3,4})/);
|
|
2414
|
+
if (m) {
|
|
2415
|
+
const cp_num = parseInt(m[1], 10);
|
|
2416
|
+
env.locale.codepage = cp_num;
|
|
2417
|
+
if (cp_num === 949 || cp_num === 51949) env.locale.isKoreanWindows = true;
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
} catch {}
|
|
2421
|
+
// PowerShell κ°μ§
|
|
2422
|
+
try {
|
|
2423
|
+
if (env.os.platform === 'win32') {
|
|
2424
|
+
const r = cp.spawnSync('powershell', ['-NoProfile', '-Command', '$PSVersionTable.PSVersion.Major'], { encoding: 'utf8', timeout: 5000 });
|
|
2425
|
+
if (r.status === 0) env.terminal.powershell = (r.stdout || '').trim().split('\n')[0];
|
|
2426
|
+
}
|
|
2427
|
+
} catch {}
|
|
2428
|
+
// λꡬ λ²μ κ°μ§
|
|
2429
|
+
for (const [tool, cmd] of [['git', 'git --version'], ['npm', 'npm --version'], ['python', 'python --version'], ['python3', 'python3 --version']]) {
|
|
2430
|
+
try {
|
|
2431
|
+
const r = cp.spawnSync(cmd.split(' ')[0], cmd.split(' ').slice(1), { encoding: 'utf8', shell: true, timeout: 3000 });
|
|
2432
|
+
if (r.status === 0) {
|
|
2433
|
+
const v = (r.stdout || r.stderr || '').trim().split('\n')[0];
|
|
2434
|
+
env.tools[tool] = v;
|
|
2435
|
+
}
|
|
2436
|
+
} catch {}
|
|
2437
|
+
}
|
|
2438
|
+
return env;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// μ
Έ μ€ν¬λ¦½νΈ (.ps1/.bat/.cmd/.sh) μΈμ½λ© μν κ°μ§
|
|
2442
|
+
// μν μκ·Έλ: νκ΅μ΄ (λλ λΉ-ASCII) λ¬Έμ + BOM μμ + Windows νκ²½
|
|
2443
|
+
function _scanShellScriptsEncoding(root) {
|
|
2444
|
+
const result = { scanned: 0, atRisk: [], notes: [] };
|
|
2445
|
+
function walk(dir, depth = 0) {
|
|
2446
|
+
if (depth > 3) return; // λ무 κΉμ΄ λ€μ΄κ°μ§ μμ
|
|
2447
|
+
let entries;
|
|
2448
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
2449
|
+
for (const e of entries) {
|
|
2450
|
+
const fp = path.join(dir, e.name);
|
|
2451
|
+
if (e.isDirectory()) {
|
|
2452
|
+
if (/^(node_modules|\.git|__pycache__|venv|\.venv|dist|build)$/.test(e.name)) continue;
|
|
2453
|
+
walk(fp, depth + 1);
|
|
2454
|
+
} else if (e.isFile() && /\.(ps1|bat|cmd|sh)$/i.test(e.name)) {
|
|
2455
|
+
result.scanned++;
|
|
2456
|
+
try {
|
|
2457
|
+
const buf = fs.readFileSync(fp);
|
|
2458
|
+
const hasBOM = buf.length >= 3 && buf[0] === 0xEF && buf[1] === 0xBB && buf[2] === 0xBF;
|
|
2459
|
+
// λΉ-ASCII (β₯ 0x80) λ°μ΄νΈ μ‘΄μ¬ μ¬λΆ κ²μ¬
|
|
2460
|
+
let nonAscii = false;
|
|
2461
|
+
for (let i = 0; i < Math.min(buf.length, 4096); i++) {
|
|
2462
|
+
if (buf[i] >= 0x80) { nonAscii = true; break; }
|
|
2463
|
+
}
|
|
2464
|
+
if (nonAscii && !hasBOM) {
|
|
2465
|
+
result.atRisk.push({
|
|
2466
|
+
file: path.relative(root, fp),
|
|
2467
|
+
ext: path.extname(fp),
|
|
2468
|
+
hasBOM: false,
|
|
2469
|
+
nonAscii: true,
|
|
2470
|
+
risk: 'Windows νκ΅μ΄ PowerShell μμ CP949 λ‘ μ€μΈμ κ°λ₯ (BOM μΆκ° κΆμ₯)'
|
|
2471
|
+
});
|
|
2472
|
+
}
|
|
2473
|
+
} catch {}
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
walk(root);
|
|
2478
|
+
if (result.atRisk.length > 0) {
|
|
2479
|
+
result.notes.push('ν΄κ²°: νμΌ μμμ UTF-8 BOM μΆκ° (EF BB BF) λλ .ps1 첫 μ€μ $OutputEncoding/[Console]::OutputEncoding μ€μ ');
|
|
2480
|
+
}
|
|
2481
|
+
return result;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
function envCmd(root, sub) {
|
|
2485
|
+
root = absRoot(root);
|
|
2486
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
2487
|
+
const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
2488
|
+
const gr = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
2489
|
+
const yl = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
2490
|
+
const rd = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
2491
|
+
const dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
2492
|
+
if (sub === 'encoding-check') {
|
|
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
|
+
}
|
|
2511
|
+
if (has('--json')) { log(JSON.stringify(result, null, 2)); return; }
|
|
2512
|
+
log(cy(`# leerness env encoding-check (1.9.241/242, UR-0014) β μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν κ°μ§`));
|
|
2513
|
+
log('');
|
|
2514
|
+
log(` μ€μΊ: ${gr(String(result.scanned))} νμΌ (.ps1/.bat/.cmd/.sh)`);
|
|
2515
|
+
if (result.atRisk.length === 0) {
|
|
2516
|
+
log(gr(` β μΈμ½λ© μν μμ`));
|
|
2517
|
+
} else {
|
|
2518
|
+
log(rd(` β μν ${result.atRisk.length}건 (BOM μλ λΉ-ASCII):`));
|
|
2519
|
+
result.atRisk.slice(0, 10).forEach(r => {
|
|
2520
|
+
log(` β’ ${r.file}`);
|
|
2521
|
+
log(dm(` ${r.risk}`));
|
|
2522
|
+
});
|
|
2523
|
+
log('');
|
|
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
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
return;
|
|
2534
|
+
}
|
|
2535
|
+
// default: env summary
|
|
2536
|
+
const env = _collectRuntimeEnv();
|
|
2537
|
+
if (has('--json')) { log(JSON.stringify(env, null, 2)); return; }
|
|
2538
|
+
log(cy(`# leerness env (1.9.241, UR-0014) β νκ²½ μ’
ν©`));
|
|
2539
|
+
log('');
|
|
2540
|
+
log(` π» OS: ${gr(env.os.platform)} ${env.os.release} (${env.os.arch})`);
|
|
2541
|
+
log(` π¦ Node: ${gr(env.node.version)}`);
|
|
2542
|
+
log(` π Locale: LANG=${env.locale.LANG || 'unset'} Β· CP=${env.locale.codepage || 'unknown'}${env.locale.isKoreanWindows ? yl(' (νκ΅μ΄ Windows)') : ''}`);
|
|
2543
|
+
log(` π₯ Hardware: ${env.hardware.cpus} CPUs Β· ${env.hardware.memGB} GB RAM`);
|
|
2544
|
+
log(` π± Terminal: TTY=${env.terminal.isTTY}${env.terminal.powershell ? ` Β· PowerShell v${env.terminal.powershell}` : ''}`);
|
|
2545
|
+
log(` π§ Tools:`);
|
|
2546
|
+
for (const [k, v] of Object.entries(env.tools)) {
|
|
2547
|
+
log(` ${v ? gr('β') : dm('β')} ${k}: ${v || dm('not found')}`);
|
|
2548
|
+
}
|
|
2549
|
+
log('');
|
|
2550
|
+
log(dm(` β μΈμ½λ© κ²μ¬: leerness env encoding-check (μ
Έ μ€ν¬λ¦½νΈ .ps1/.bat μν κ°μ§)`));
|
|
2551
|
+
log(dm(` β JSON μΆλ ₯: leerness env --json`));
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2379
2554
|
// 1.9.231: leerness pulse β ν μ€ μ’
ν© μμ½ (10 ν΅μ¬ μ§ν)
|
|
2380
2555
|
// handoff ν€λλΌμΈμ μΆμ½ λ²μ β μ¬μ©μκ° λΉ λ₯΄κ² μν νμ
|
|
2381
2556
|
// μλ΅ (--json): { version, roundCount, mcpTools, memorySurface, security, health, driftScore, nextMilestone, etaDays, abnormal }
|
|
@@ -6403,6 +6578,20 @@ function handoff(root) {
|
|
|
6403
6578
|
totalClasses: analyses.reduce((s, a) => s + a.classes, 0)
|
|
6404
6579
|
};
|
|
6405
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 {}
|
|
6406
6595
|
} catch {}
|
|
6407
6596
|
try {
|
|
6408
6597
|
const pwState = _loadPreWakeReport(root);
|
|
@@ -6743,6 +6932,27 @@ function handoff(root) {
|
|
|
6743
6932
|
}
|
|
6744
6933
|
} catch {}
|
|
6745
6934
|
|
|
6935
|
+
// 1.9.241: handoff body μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν κ°μ§ (μ¬μ©μ λͺ
μ UR-0014)
|
|
6936
|
+
// νκ΅μ΄ Windows + .ps1/.bat λΉ-ASCII + BOM μμ β CP949 μ€μΈμ μν
|
|
6937
|
+
try {
|
|
6938
|
+
const scan = _scanShellScriptsEncoding(root);
|
|
6939
|
+
if (scan.atRisk && scan.atRisk.length > 0) {
|
|
6940
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
6941
|
+
const rd5 = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
6942
|
+
const yl5 = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
6943
|
+
const dm5 = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
6944
|
+
log('');
|
|
6945
|
+
log(rd5(`## β μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν ${scan.atRisk.length}건 (1.9.241, UR-0014)`));
|
|
6946
|
+
scan.atRisk.slice(0, 3).forEach(r => {
|
|
6947
|
+
log(yl5(` β’ ${r.file}`));
|
|
6948
|
+
log(dm5(` ${r.risk}`));
|
|
6949
|
+
});
|
|
6950
|
+
if (scan.atRisk.length > 3) log(dm5(` ... +${scan.atRisk.length - 3}건 λ`));
|
|
6951
|
+
log(dm5(` β μμΈ: leerness env encoding`));
|
|
6952
|
+
log(dm5(` β ν΄κ²°: νμΌ μμμ UTF-8 BOM (EF BB BF) μΆκ°`));
|
|
6953
|
+
}
|
|
6954
|
+
} catch {}
|
|
6955
|
+
|
|
6746
6956
|
// 1.9.237: handoff λ³Έλ¬Έ release/* λμ κ²½κ³ β 50+ branches merged μ μλ μλ΄
|
|
6747
6957
|
// 1.9.220 λΉμ μμ’
λ£ release-branch-pending μ νΈμ λ³Έλ¬Έ λ³΄κ° (handoff ν€λλΌμΈμ βπ λΉμ μμ’
λ£β λ§ νμ)
|
|
6748
6958
|
try {
|
|
@@ -10605,6 +10815,20 @@ function sessionClose(root, opts = {}) {
|
|
|
10605
10815
|
totalClasses: analyses.reduce((s, a) => s + a.classes, 0)
|
|
10606
10816
|
};
|
|
10607
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 {}
|
|
10608
10832
|
} catch {}
|
|
10609
10833
|
try {
|
|
10610
10834
|
// 1.9.209: pre-wake-audit μλ μ€ν + μ μ₯ (sleep μ μλ μ κ²)
|
|
@@ -13696,6 +13920,31 @@ function driftCheckCmd(root, opts = {}) {
|
|
|
13696
13920
|
log(`β auto-fix 보μ ν볡 μ€λ₯: ${e.message}`);
|
|
13697
13921
|
}
|
|
13698
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
|
+
}
|
|
13699
13948
|
// 1.9.225: drift check --auto-fix μ delivered ν¨ν΄ μλ μ μ© ν΅ν© (1.9.223/224 μμ€ν
νμ)
|
|
13700
13949
|
// μ¬μ©μ μμ²μ "ꡬν μλ£" ν¨ν΄μ΄ λμ λλ©΄ κ°μ§ λ―Έλ΅ μ νΈκ° drift score λ₯Ό κ°μ€μν¬ μ μμ β μλ μ 리.
|
|
13701
13950
|
// 1.9.82 audit --fix ν¨ν΄κ³Ό λμΌ: --auto-fix μ μ¦μ μ μ©, μ μ© ν μ¬κ²μ¬.
|
|
@@ -14743,7 +14992,8 @@ function mcpServeCmd(root) {
|
|
|
14743
14992
|
{ name: 'leerness_commands', description: '1.9.233 β μΉ΄ν
κ³ λ¦¬νλ μ 체 CLI λͺ
λ Ή λͺ©λ‘ (9 μΉ΄ν
κ³ λ¦¬). μλ΅: { version, totalCommands, categories: { status, task, memory, audit, workflow, release, skill, bridge, config } }. μΈλΆ AIκ° "leerness κ° μ 곡νλ λͺ
λ Ήμ΄ λκ° μλ"λ₯Ό μ§μ νμ. λ§€λ΄μΌ/λμλ§ λμ μμ±. μΈμ: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
|
|
14744
14993
|
{ name: 'leerness_release_cleanup', description: '1.9.236 (1.9.235 μλ νμ) β local release/* branches μ 리. main μ mergeλ κ²λ§ ν보 (unmerged 보νΈ, νμ¬ branch 보νΈ). μλ΅: { apply, keep, total, merged, unmerged, deleteCount, toDelete[], recent[], unmergedSample[] }. μΈλΆ AIκ° "μ΄μ λμ release branches μ 리 κ°λ₯?"μ νμ. κΈ°λ³Έ dry-run, apply: true μμλ§ μ€ μμ . μΈμ: { path?, apply? (default false), keep? (default 5) }', inputSchema: { type: 'object', properties: { path: { type: 'string' }, apply: { type: 'boolean' }, keep: { type: 'number' } } } },
|
|
14745
14994
|
{ name: 'leerness_py_check', description: '1.9.239 (μ¬μ©μ λͺ
μ UR-0013) β Python νμΌ λΆμ. μμ‘΄μ± 0 regex fallback. .md μΈ .py λ leerness μΈμ§. μλ΅: { totalFiles, totalLOC, totalImports, totalFuncs, totalClasses, totalTodos, biggest: [{ file, loc, funcs, classes }] }. μΈλΆ AIκ° "μ΄ νλ‘μ νΈ Python νλ©΄μ΄ μΌλ§λ λλ"λ₯Ό νμ. μΈμ: { path? }', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
|
|
14746
|
-
{ name: 'leerness_agent_mode', description: '1.9.239 (μ¬μ©μ λͺ
μ UR-0013) β μμ¨ λͺ¨λ μ μ© ν΅ν© λͺ
λ Ή. start: handoff + drift --auto-fix + session-resume --auto-fix (μ§μ
). tick: pulse ν μ€ (λ§€ λΌμ΄λ). stop: session close --auto-apply-delivered --auto-cleanup-branches (λ§κ°). μΈλΆ AI κ° μμ¨ λΌμ΄λ μ§μ
/λ§€ λΌμ΄λ/λ§κ°μ λ¨μΌ νΈμΆλ‘ μν. μΈμ: { path?, sub (required: "start"|"tick"|"stop"|"help") }', inputSchema: { type: 'object', properties: { path: { type: 'string' }, sub: { type: 'string', enum: ['start', 'tick', 'stop', 'help'] } }, required: ['sub'] } }
|
|
14995
|
+
{ name: 'leerness_agent_mode', description: '1.9.239 (μ¬μ©μ λͺ
μ UR-0013) β μμ¨ λͺ¨λ μ μ© ν΅ν© λͺ
λ Ή. start: handoff + drift --auto-fix + session-resume --auto-fix (μ§μ
). tick: pulse ν μ€ (λ§€ λΌμ΄λ). stop: session close --auto-apply-delivered --auto-cleanup-branches (λ§κ°). μΈλΆ AI κ° μμ¨ λΌμ΄λ μ§μ
/λ§€ λΌμ΄λ/λ§κ°μ λ¨μΌ νΈμΆλ‘ μν. μΈμ: { path?, sub (required: "start"|"tick"|"stop"|"help") }', inputSchema: { type: 'object', properties: { path: { type: 'string' }, sub: { type: 'string', enum: ['start', 'tick', 'stop', 'help'] } }, required: ['sub'] } },
|
|
14996
|
+
{ name: 'leerness_env_info', description: '1.9.241 (μ¬μ©μ λͺ
μ UR-0014) β νκ²½ μ’
ν© μ 보 νμ. OS / μΈμ΄ (LANG, μ½λνμ΄μ§) / νκ΅μ΄ Windows / νλμ¨μ΄ / ν°λ―Έλ (TTY, PowerShell λ²μ ) / λꡬ λ²μ (git, npm, python). μΈλΆ AI κ° νκ²½ νΈνμ±μ 미리 μΈμ§ β μΈμ½λ© μ€λ₯ μλ°©. μλ΅: { os, node, locale, hardware, terminal, tools }. μΈμ: { path?, encodingCheck? }. encodingCheck: true μ μ
Έ μ€ν¬λ¦½νΈ (.ps1/.bat/.cmd/.sh) BOM μλ λΉ-ASCII μν κ°μ§', inputSchema: { type: 'object', properties: { path: { type: 'string' }, encodingCheck: { type: 'boolean' } } } }
|
|
14747
14997
|
];
|
|
14748
14998
|
|
|
14749
14999
|
function send(obj) {
|
|
@@ -14928,6 +15178,10 @@ function mcpServeCmd(root) {
|
|
|
14928
15178
|
// 1.9.239 (UR-0013): μμ¨ λͺ¨λ ν΅ν© (start/tick/stop)
|
|
14929
15179
|
cliArgs = ['agent-mode', String(args.sub || 'help'), '--path', targetPath];
|
|
14930
15180
|
break;
|
|
15181
|
+
case 'leerness_env_info':
|
|
15182
|
+
// 1.9.241 (UR-0014): νκ²½ μ’
ν© + μΈμ½λ© μν κ°μ§
|
|
15183
|
+
cliArgs = ['env', args.encodingCheck === true ? 'encoding' : 'summary', '--path', targetPath, '--json'];
|
|
15184
|
+
break;
|
|
14931
15185
|
case 'leerness_release_cleanup':
|
|
14932
15186
|
// 1.9.236 (1.9.235): local release/* branches μ 리
|
|
14933
15187
|
cliArgs = ['release', 'cleanup', '--json'];
|
|
@@ -17171,6 +17425,20 @@ function healthCmd(root) {
|
|
|
17171
17425
|
totalClasses: analyses.reduce((s, a) => s + a.classes, 0)
|
|
17172
17426
|
};
|
|
17173
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 μ κ² μ€ν¨' }; }
|
|
17174
17442
|
// 1.9.163: 5λ₯λ ₯ λ§€νΈλ¦μ€ μλ νκ° (1.9.155 sub-agent μ κ² β μ½λ κΈ°λ° μλν)
|
|
17175
17443
|
// κ° λ₯λ ₯μ μ½λ grep μΌλ‘ κ²μΆ β 0~100 μ μ. μ¬μ©μκ° λ§€ health νΈμΆ μ leerness μκΈ° νκ° νμΈ.
|
|
17176
17444
|
try {
|
|
@@ -18616,6 +18884,10 @@ async function main() {
|
|
|
18616
18884
|
if (cmd === 'py-check') return pyCheckCmd(arg('--path', process.cwd()));
|
|
18617
18885
|
// 1.9.239: leerness agent-mode <start|tick|stop> β μμ¨ λͺ¨λ μ μ© ν΅ν© λͺ
λ Ή (μ¬μ©μ λͺ
μ UR-0013)
|
|
18618
18886
|
if (cmd === 'agent-mode') return agentModeCmd(arg('--path', process.cwd()), args[1]);
|
|
18887
|
+
// 1.9.241: leerness env summary|encoding β νκ²½ μ’
ν© + μ
Έ μ€ν¬λ¦½νΈ μΈμ½λ© μν (μ¬μ©μ λͺ
μ UR-0014)
|
|
18888
|
+
// κΈ°μ‘΄ env check/sync/detect (1.9.71) μ μΆ©λνμ§ μμ β summary/encoding μ κ· μλΈ
|
|
18889
|
+
if (cmd === 'env' && (args[1] === 'summary' || args[1] === 'encoding' || args[1] === 'encoding-check'))
|
|
18890
|
+
return envCmd(arg('--path', process.cwd()), args[1] === 'summary' ? null : 'encoding-check');
|
|
18619
18891
|
// 1.9.208: leerness constraints <list|check|add> β νλ«νΌ/API μ μ½ μ¬μ μ²΄ν¬ (μ¬μ©μ λͺ
μ)
|
|
18620
18892
|
if (cmd === 'constraints') return constraintsCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
18621
18893
|
// 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.
|
|
3
|
+
"version": "1.9.242",
|
|
4
4
|
"description": "Leerness: λΉνκ΄΄ λ§μ΄κ·Έλ μ΄μ
, μλ λ²μ κ°μ§Β·μ
λ°μ΄νΈ, κ³ν/μ§ν/νΈλμ€ν μλν, κ²μΌλ¦Β·μν¬λ¦ΏΒ·μΈμ½λ© μλ κ°λ, Claude Code μ¬λμ ν΅ν©μ κ°μΆ νκ΅μ΄ μ°μ AI κ°λ° νλ€μ€.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|