leerness 1.9.83 → 1.9.85
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 +48 -0
- package/README.md +4 -2
- package/bin/harness.js +135 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.85 — 2026-05-20
|
|
4
|
+
|
|
5
|
+
**`leerness health` 새 명령** — 종합 헬스 체크 (drift + 보안 + skill + MCP + 누적 통계).
|
|
6
|
+
|
|
7
|
+
### Added — `leerness health [<path>]`
|
|
8
|
+
- 종합 진단 한 번에:
|
|
9
|
+
- `drift`: level + score + fired 개수
|
|
10
|
+
- `보안`: .env 존재 / .gitignore에 .env 포함 / .env.example 누락 키 / .gitignore 시크릿 패턴 누락
|
|
11
|
+
- `skills`: 설치 수 / skill query 누적 (rolling history)
|
|
12
|
+
- `usage`: 명령 호출 총수 + 종류 / MCP 호출 총수 + 종류 / since
|
|
13
|
+
- `tasks`: progress-tracker 총수 + 상태별 카운트
|
|
14
|
+
- **`issues`** 배열에 발견된 모든 문제 자동 집계.
|
|
15
|
+
- `--json`: 구조화된 JSON 출력 (CI 친화).
|
|
16
|
+
- `--strict`: issue ≥ 1 시 exit 1.
|
|
17
|
+
|
|
18
|
+
### Use Case
|
|
19
|
+
- 사용자: `leerness health .` 한 줄로 워크스페이스 전체 상태 즉시 확인.
|
|
20
|
+
- CI 통합: `leerness health . --strict` 로 보안/drift 문제 자동 감지.
|
|
21
|
+
- 1.9.78 drift + 1.9.75/76/80 보안 + 1.9.70 MCP 통계 + 1.9.79 skill suggest의 모든 신호를 한 곳에 집계.
|
|
22
|
+
|
|
23
|
+
### Verified
|
|
24
|
+
- stress-v31 — health 출력 / --json / --strict / 누적 회귀.
|
|
25
|
+
- e2e 219/219 PASS 유지.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1.9.84 — 2026-05-20
|
|
30
|
+
|
|
31
|
+
**MCP server 17번째 도구 `leerness_skill_list` 추가** (외부 AI에 skill 목록 조회 노출).
|
|
32
|
+
|
|
33
|
+
### Added — MCP 17번째 도구
|
|
34
|
+
- `leerness_skill_list` — 워크스페이스에 설치된 skill 목록 조회.
|
|
35
|
+
- inputSchema: `{ path: string }`
|
|
36
|
+
- 응답: `skill list --json` 결과 (skillpack 출처 + items 배열: id/displayNameKo/source/capabilities/usageCount/lastUsed/lastUpdated)
|
|
37
|
+
- 외부 AI가 사용 가능한 skill을 즉시 인지하여 적절한 능력 활용.
|
|
38
|
+
- `skill list --json` 옵션 신규 추가 (CI 친화).
|
|
39
|
+
- MCP server 도구 카운트: **16 → 17**.
|
|
40
|
+
|
|
41
|
+
### Use Case
|
|
42
|
+
- Claude Code / Cursor 가 작업 시작 시 → `leerness_skill_list` 호출 → 사용 가능한 skill 카탈로그 파악 → 적절한 능력 활용.
|
|
43
|
+
- skill_match와 결합: "이 task에 매칭되는 skill (skill_match) + 전체 skill 카탈로그 (skill_list)" 양방향 활용.
|
|
44
|
+
|
|
45
|
+
### Verified
|
|
46
|
+
- stress-v30 — MCP 17 도구 + skill_list 호출 + 누적 회귀.
|
|
47
|
+
- e2e 219/219 PASS 유지.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
3
51
|
## 1.9.83 — 2026-05-20
|
|
4
52
|
|
|
5
53
|
**MCP server 16번째 도구 `leerness_skill_match` 추가** (1.9.45/50/68 skill match 외부 노출).
|
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,7 +12,7 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
15
|
+
║ v1.9.85 AI Agent Reliability Harness ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · prevent drift ║
|
|
17
17
|
╚══════════════════════════════════════════════════════════════╝
|
|
18
18
|
```
|
|
@@ -433,6 +433,8 @@ npm test # = node ./scripts/e2e.js
|
|
|
433
433
|
|
|
434
434
|
## 변경 이력 (최근)
|
|
435
435
|
|
|
436
|
+
- **1.9.85** — **`leerness health` 새 명령** — drift + 보안 + skill + MCP + 누적 통계 종합 헬스 체크. `--json` / `--strict` 옵션.
|
|
437
|
+
- **1.9.84** — **MCP server 17번째 도구 `leerness_skill_list`** — 외부 AI에 skill 카탈로그 (id/이름/출처/능력/사용 횟수) 조회 노출. `skill list --json` 옵션도 함께 추가.
|
|
436
438
|
- **1.9.83** — **MCP server 16번째 도구 `leerness_skill_match`** — 1.9.45/50/68 skill match를 외부 AI에 노출. rolling history 자동 누적.
|
|
437
439
|
- **1.9.82** — **`drift check --auto-fix` 보안 회복 통합** — 1.9.78 보안 신호 발견 시 `audit --fix` 자동 실행 → `.gitignore` + `.env.example` 동기화 후 재검사. 보안 + 세션 마감 한 번에 자동 회복.
|
|
438
440
|
- **1.9.81** — **`handoff` 통합 헤드라인** — drift level + 보안 상태 + MCP 활동 + skill query + 설치 skill 수를 한 줄로 압축. AI가 세션 시작 즉시 워크스페이스 상태 인지.
|
package/bin/harness.js
CHANGED
|
@@ -6,7 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const cp = require('child_process');
|
|
7
7
|
const readline = require('readline');
|
|
8
8
|
|
|
9
|
-
const VERSION = '1.9.
|
|
9
|
+
const VERSION = '1.9.85';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -769,6 +769,20 @@ function _invalidateSkillsCache(root) {
|
|
|
769
769
|
|
|
770
770
|
function skillList(root) {
|
|
771
771
|
const all = listAllSkills(root);
|
|
772
|
+
// 1.9.84: --json 옵션 (MCP 통합용)
|
|
773
|
+
if (has('--json')) {
|
|
774
|
+
const items = Object.entries(all).map(([id, v]) => ({
|
|
775
|
+
id,
|
|
776
|
+
displayNameKo: v.displayNameKo || id,
|
|
777
|
+
source: v._source,
|
|
778
|
+
capabilities: v.capabilities || [],
|
|
779
|
+
usageCount: v.usage?.count || 0,
|
|
780
|
+
lastUsed: v.usage?.lastUsed || null,
|
|
781
|
+
lastUpdated: v.lastUpdated || null
|
|
782
|
+
}));
|
|
783
|
+
log(JSON.stringify({ skillpack: SKILLPACK_SOURCE, total: items.length, items }, null, 2));
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
772
786
|
if (SKILLPACK_SOURCE !== 'builtin') log(`# skillpack 출처: ${SKILLPACK_SOURCE}${SKILLPACK_META ? ` (${SKILLPACK_META.name} v${SKILLPACK_META.version})` : ''}`);
|
|
773
787
|
else log('# skillpack 미설치 — builtin fallback 사용 (leerness 본 패키지 내장 카탈로그)');
|
|
774
788
|
log('| ID | 한글명 | 출처 | 능력(요약) | 사용횟수 | 최종 |');
|
|
@@ -3384,16 +3398,17 @@ function _banner(opts = {}) {
|
|
|
3384
3398
|
lines.push('');
|
|
3385
3399
|
for (const ln of lines) log(ln);
|
|
3386
3400
|
if (opts.quickStart) {
|
|
3387
|
-
log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.
|
|
3401
|
+
log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.85+ 워크플로)')));
|
|
3388
3402
|
log(' ' + C.green('npx leerness@latest init .') + C.dim(' # 신규 프로젝트 + 외부 AI CLI 설정'));
|
|
3389
3403
|
log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨텍스트 + lessons + 매칭 skill + 이전 history hit (1.9.69)'));
|
|
3390
3404
|
log(' ' + C.green('npx leerness skill match "<query>"') + C.dim(' # 매칭 skill + rolling history 자동 누적 (1.9.68)'));
|
|
3391
3405
|
log(' ' + C.green('npx leerness verify-claim T-0001 --run-tests') + C.dim(' # AI 거짓 완료 자동 검증'));
|
|
3392
3406
|
log(' ' + C.green('npx leerness env check .') + C.dim(' # .env ↔ .env.example 동기화 검사 (1.9.71)'));
|
|
3407
|
+
log(' ' + C.green('npx leerness health .') + C.dim(' # 종합 헬스 체크 — drift + 보안 + skill + MCP (1.9.85)'));
|
|
3393
3408
|
log(' ' + C.green('npx leerness session close .') + C.dim(' # 마감 + 다음 라운드 추천 (default)'));
|
|
3394
3409
|
log('');
|
|
3395
3410
|
log(C.bold(C.cyan(' 🤖 메인 에이전트 (Claude/Cursor/Copilot)용')));
|
|
3396
|
-
log(' ' + C.green('npx leerness mcp serve') + C.dim(' # MCP 서버 —
|
|
3411
|
+
log(' ' + C.green('npx leerness mcp serve') + C.dim(' # MCP 서버 — 17 도구 (skill_list 포함, 1.9.84)'));
|
|
3397
3412
|
log(' ' + C.green('npx leerness agents bench "<task>"') + C.dim(' # 3 CLI 동시 비교'));
|
|
3398
3413
|
log('');
|
|
3399
3414
|
}
|
|
@@ -7336,7 +7351,8 @@ function mcpServeCmd(root) {
|
|
|
7336
7351
|
{ name: 'leerness_task_export', description: '1.9.60/66 — leerness task → Claude Code TodoWrite 호환 JSON (외부 AI 양방향 sync)', inputSchema: { type: 'object', properties: { path: { type: 'string' }, to: { type: 'string' } } } },
|
|
7337
7352
|
{ name: 'leerness_env_check', description: '1.9.71/73 — .env vs .env.example 동기화 검사 (보안: 키만, 값 미노출). exit 1 if 누락 키 있음', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
|
|
7338
7353
|
{ name: 'leerness_brainstorm', description: '1.9.16/72/77 — 누적 컨텍스트(decisions+skills+tasks+rules+evidence+lessons+skillHistory+taskLogFails) 자원 회수. 외부 AI가 새 작업 시작 전 호출', inputSchema: { type: 'object', properties: { topic: { type: 'string' }, path: { type: 'string' }, allApps: { type: 'boolean' } }, required: ['topic'] } },
|
|
7339
|
-
{ name: 'leerness_skill_match', description: '1.9.45/50/83 — 사용자 task 키워드에 매칭되는 설치된 skill 추천 (jaccard 또는 embedding). 1.9.68 rolling history 자동 누적', inputSchema: { type: 'object', properties: { query: { type: 'string' }, path: { type: 'string' }, useEmbedding: { type: 'boolean' } }, required: ['query'] } }
|
|
7354
|
+
{ name: 'leerness_skill_match', description: '1.9.45/50/83 — 사용자 task 키워드에 매칭되는 설치된 skill 추천 (jaccard 또는 embedding). 1.9.68 rolling history 자동 누적', inputSchema: { type: 'object', properties: { query: { type: 'string' }, path: { type: 'string' }, useEmbedding: { type: 'boolean' } }, required: ['query'] } },
|
|
7355
|
+
{ name: 'leerness_skill_list', description: '1.9.84 — 워크스페이스에 설치된 skill 목록 + 사용 횟수 + 출처 (catalog/user). 외부 AI가 사용 가능한 skill 조회', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } }
|
|
7340
7356
|
];
|
|
7341
7357
|
|
|
7342
7358
|
function send(obj) {
|
|
@@ -7384,6 +7400,7 @@ function mcpServeCmd(root) {
|
|
|
7384
7400
|
case 'leerness_env_check': cliArgs = ['env', 'check', targetPath, '--json']; break;
|
|
7385
7401
|
case 'leerness_brainstorm': cliArgs = ['brainstorm', args.topic || '', '--path', targetPath, '--json', ...(args.allApps ? ['--all-apps'] : [])]; break;
|
|
7386
7402
|
case 'leerness_skill_match': cliArgs = ['skill', 'match', args.query || '', '--path', targetPath, '--json', ...(args.useEmbedding ? ['--embedding'] : [])]; break;
|
|
7403
|
+
case 'leerness_skill_list': cliArgs = ['skill', 'list', targetPath, '--json']; break;
|
|
7387
7404
|
default:
|
|
7388
7405
|
return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
|
|
7389
7406
|
}
|
|
@@ -7565,6 +7582,118 @@ function envSyncCmd(root) {
|
|
|
7565
7582
|
for (const k of d.inEnvOnly) log(` + ${k}=`);
|
|
7566
7583
|
}
|
|
7567
7584
|
|
|
7585
|
+
// 1.9.85: leerness health — 종합 헬스 체크 (drift + 보안 + skill + MCP + 누적)
|
|
7586
|
+
function healthCmd(root) {
|
|
7587
|
+
root = absRoot(root || process.cwd());
|
|
7588
|
+
const out = { root, generatedAt: new Date().toISOString(), checks: {} };
|
|
7589
|
+
// 1) drift level
|
|
7590
|
+
try {
|
|
7591
|
+
const r = cp.spawnSync(process.execPath, [__filename, 'drift', 'check', root, '--json'],
|
|
7592
|
+
{ encoding: 'utf8', timeout: 15000, env: { ...process.env, LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '0' } });
|
|
7593
|
+
const j = JSON.parse(r.stdout.trim());
|
|
7594
|
+
out.checks.drift = { level: j.level, score: j.score, firedCount: (j.fired || []).length };
|
|
7595
|
+
} catch { out.checks.drift = { error: 'drift check 실패' }; }
|
|
7596
|
+
// 2) 보안 상태 (env + .gitignore)
|
|
7597
|
+
try {
|
|
7598
|
+
const envPath = path.join(root, '.env');
|
|
7599
|
+
if (exists(envPath)) {
|
|
7600
|
+
const d = envDiff(root);
|
|
7601
|
+
const giText = exists(path.join(root, '.gitignore')) ? read(path.join(root, '.gitignore')) : '';
|
|
7602
|
+
const giLines = giText.split('\n').map(l => l.trim());
|
|
7603
|
+
const envInGi = giLines.includes('.env') || giLines.includes('/.env');
|
|
7604
|
+
const SECRET_PATTERNS = ['.env', '.env.local', '.env.production', '.env.*.local', '*.pem', 'credentials.json'];
|
|
7605
|
+
const missingSecrets = SECRET_PATTERNS.filter(p => !giLines.some(l => l === p || l === '/' + p));
|
|
7606
|
+
out.checks.security = {
|
|
7607
|
+
hasDotEnv: true,
|
|
7608
|
+
envInGitignore: envInGi,
|
|
7609
|
+
envExampleMissing: d.inEnvOnly,
|
|
7610
|
+
gitignoreMissingSecrets: missingSecrets,
|
|
7611
|
+
critical: !envInGi
|
|
7612
|
+
};
|
|
7613
|
+
} else {
|
|
7614
|
+
out.checks.security = { hasDotEnv: false, ok: true };
|
|
7615
|
+
}
|
|
7616
|
+
} catch { out.checks.security = { error: '보안 점검 실패' }; }
|
|
7617
|
+
// 3) skill 수 + skill query 누적
|
|
7618
|
+
try {
|
|
7619
|
+
const all = listAllSkills(root);
|
|
7620
|
+
const skillCount = Object.keys(all).length;
|
|
7621
|
+
let queryCount = 0;
|
|
7622
|
+
const histPath = path.join(root, '.harness', 'skill-suggestions.md');
|
|
7623
|
+
if (exists(histPath)) {
|
|
7624
|
+
queryCount = (read(histPath).match(/^## [\d-]+ [\d:]+ — query/gm) || []).length;
|
|
7625
|
+
}
|
|
7626
|
+
out.checks.skills = { installed: skillCount, queryHistoryCount: queryCount };
|
|
7627
|
+
} catch { out.checks.skills = { error: 'skill 점검 실패' }; }
|
|
7628
|
+
// 4) MCP + 명령 호출 누적
|
|
7629
|
+
try {
|
|
7630
|
+
const stats = _readUsageStats(root);
|
|
7631
|
+
const cmdTotal = Object.values(stats.commands || {}).reduce((s, n) => s + n, 0);
|
|
7632
|
+
const mcpTotal = stats.mcp?.tools ? Object.values(stats.mcp.tools).reduce((s, n) => s + n, 0) : 0;
|
|
7633
|
+
out.checks.usage = {
|
|
7634
|
+
commandTotal: cmdTotal,
|
|
7635
|
+
commandKinds: Object.keys(stats.commands || {}).length,
|
|
7636
|
+
mcpTotal,
|
|
7637
|
+
mcpToolKinds: stats.mcp?.tools ? Object.keys(stats.mcp.tools).length : 0,
|
|
7638
|
+
since: stats.since || null
|
|
7639
|
+
};
|
|
7640
|
+
} catch { out.checks.usage = { error: 'usage 점검 실패' }; }
|
|
7641
|
+
// 5) tasks (progress-tracker)
|
|
7642
|
+
try {
|
|
7643
|
+
const rows = readProgressRows(root);
|
|
7644
|
+
const byStatus = {};
|
|
7645
|
+
for (const r of rows) byStatus[r.status] = (byStatus[r.status] || 0) + 1;
|
|
7646
|
+
out.checks.tasks = { total: rows.length, byStatus };
|
|
7647
|
+
} catch { out.checks.tasks = { error: 'tasks 점검 실패' }; }
|
|
7648
|
+
// 6) issues 요약 (사용자 글로벌 룰 가시화)
|
|
7649
|
+
const issues = [];
|
|
7650
|
+
if (out.checks.drift?.level && !/healthy/.test(out.checks.drift.level)) issues.push(`drift ${out.checks.drift.level}`);
|
|
7651
|
+
if (out.checks.security?.critical) issues.push('🚨 .env가 .gitignore에 누락 (보안 CRITICAL)');
|
|
7652
|
+
if (out.checks.security?.envExampleMissing?.length) issues.push(`.env→.env.example 누락 ${out.checks.security.envExampleMissing.length}건`);
|
|
7653
|
+
if (out.checks.security?.gitignoreMissingSecrets?.length) issues.push(`.gitignore 시크릿 누락 ${out.checks.security.gitignoreMissingSecrets.length}건`);
|
|
7654
|
+
out.issues = issues;
|
|
7655
|
+
out.healthy = issues.length === 0;
|
|
7656
|
+
|
|
7657
|
+
// --strict: issue 있으면 exit 1
|
|
7658
|
+
if (has('--strict') && !out.healthy) process.exitCode = 1;
|
|
7659
|
+
|
|
7660
|
+
if (has('--json')) { log(JSON.stringify(out, null, 2)); return; }
|
|
7661
|
+
log(`# leerness health (1.9.85)`);
|
|
7662
|
+
log(`Date: ${out.generatedAt}`);
|
|
7663
|
+
log(`Status: ${out.healthy ? '✅ healthy' : `⚠ ${issues.length} issues`}`);
|
|
7664
|
+
log('');
|
|
7665
|
+
log(`## drift`);
|
|
7666
|
+
log(` level: ${out.checks.drift?.level || 'n/a'} (score ${out.checks.drift?.score || 0}, fired ${out.checks.drift?.firedCount || 0})`);
|
|
7667
|
+
log('');
|
|
7668
|
+
log(`## 보안`);
|
|
7669
|
+
if (out.checks.security?.hasDotEnv) {
|
|
7670
|
+
log(` .env 존재 · .gitignore에 .env 포함: ${out.checks.security.envInGitignore ? '✓' : '✗ CRITICAL'}`);
|
|
7671
|
+
log(` .env.example 누락 키: ${out.checks.security.envExampleMissing?.length || 0}건`);
|
|
7672
|
+
log(` .gitignore 시크릿 패턴 누락: ${out.checks.security.gitignoreMissingSecrets?.length || 0}건`);
|
|
7673
|
+
} else {
|
|
7674
|
+
log(` .env 없음 (검증 불필요)`);
|
|
7675
|
+
}
|
|
7676
|
+
log('');
|
|
7677
|
+
log(`## skills`);
|
|
7678
|
+
log(` 설치: ${out.checks.skills?.installed || 0}개 · skill query 누적: ${out.checks.skills?.queryHistoryCount || 0}회`);
|
|
7679
|
+
log('');
|
|
7680
|
+
log(`## usage`);
|
|
7681
|
+
log(` 명령 호출: ${out.checks.usage?.commandTotal || 0}회 / ${out.checks.usage?.commandKinds || 0}종`);
|
|
7682
|
+
log(` MCP 호출: ${out.checks.usage?.mcpTotal || 0}회 / ${out.checks.usage?.mcpToolKinds || 0}종 도구`);
|
|
7683
|
+
log(` since: ${out.checks.usage?.since || 'unknown'}`);
|
|
7684
|
+
log('');
|
|
7685
|
+
log(`## tasks`);
|
|
7686
|
+
const tb = out.checks.tasks?.byStatus || {};
|
|
7687
|
+
log(` 총 ${out.checks.tasks?.total || 0}건: ${Object.entries(tb).map(([s, n]) => `${s}=${n}`).join(', ') || '없음'}`);
|
|
7688
|
+
if (issues.length) {
|
|
7689
|
+
log('');
|
|
7690
|
+
log(`## ⚠ Issues (${issues.length})`);
|
|
7691
|
+
for (const i of issues) log(` - ${i}`);
|
|
7692
|
+
log('');
|
|
7693
|
+
log(`💡 자동 회복: leerness drift check --auto-fix · leerness audit --fix`);
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7696
|
+
|
|
7568
7697
|
function usageStatsCmd(root) {
|
|
7569
7698
|
root = absRoot(root || process.cwd());
|
|
7570
7699
|
const stats = _readUsageStats(root);
|
|
@@ -7896,6 +8025,8 @@ async function main() {
|
|
|
7896
8025
|
// 1.9.71: leerness env check / sync — .env vs .env.example 자동 동기화
|
|
7897
8026
|
if (cmd === 'env' && args[1] === 'check') return envCheckCmd(args[2] || arg('--path', process.cwd()));
|
|
7898
8027
|
if (cmd === 'env' && args[1] === 'sync') return envSyncCmd(args[2] || arg('--path', process.cwd()));
|
|
8028
|
+
// 1.9.85: leerness health — 종합 헬스 체크
|
|
8029
|
+
if (cmd === 'health') return healthCmd(args[1] || arg('--path', process.cwd()));
|
|
7899
8030
|
if (cmd === 'whats-new') return whatsNewCmd(args[1] || arg('--path', process.cwd()));
|
|
7900
8031
|
if (cmd === 'reuse' && args[1] === 'autodetect') return reuseAutodetectCmd(args[2] || arg('--path', process.cwd()));
|
|
7901
8032
|
if (cmd === 'setup-agents' || cmd === 'setup' && args[1] === 'agents') return await setupAgentsCmd(args[1] && args[1] !== 'agents' ? args[1] : (args[2] || process.cwd()));
|