leerness 1.27.0 → 1.29.0
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 +88 -0
- package/README.md +4 -4
- package/bin/leerness.js +38 -6
- package/lib/audit.js +5 -0
- package/lib/diagnostics.js +44 -41
- package/lib/drift.js +343 -341
- package/package.json +1 -1
- package/scripts/e2e.js +45 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,93 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.29.0 — 2026-06-16 — 🛡️ [안정화/Stable] drift auto-fix·진단 명령 영어화 안정 minor
|
|
4
|
+
|
|
5
|
+
**🛡️ 안정화(Stable) minor — drift 완전 영어화(버그수정 포함) + 진단 3종 영어화를 npm 공개.** 직전 minor(1.28.0) 이후 누적된 패치 2건(1.28.1 + 1.28.2)을 검증·통합해 배포. R-0011 정책의 20번째 stable minor. 한국어 우선 기본은 그대로.
|
|
6
|
+
|
|
7
|
+
### 이번 minor 통합 (1.28.1~1.28.2)
|
|
8
|
+
- **🐛+🌐 drift --auto-fix 영어화 + 보안신호 판정 버그수정 (1.28.1)**: 1.27.2 가 보안 신호 라벨을 언어화하며 내부 `hasSecurityFired` 가 한국어 라벨 정규식에 결합돼 `--language en` 에서 보안 auto-fix 가 미발동하던 잠복 버그를 언어-안정 필드(`f.file`)로 수정. drift `--auto-fix` 진행 로그 ~21줄 영어화 → `drift check` 완전 영어(출력 + auto-fix).
|
|
9
|
+
- **🌐 진단 모듈 영어화 (1.28.2)**: `doctor`(설치/환경)·`which`(버전 충돌·npx 캐시)·`whats-new`(CHANGELOG 차분) 3종을 영어 opt-in. 기존 위임 가드 보존.
|
|
10
|
+
- **한국어 우선 기본 보존**: 영어는 명시 opt-in. 한국어 출력/내부 호출 무영향(e2e 무회귀).
|
|
11
|
+
|
|
12
|
+
### 잔여 (UR-0010 백로그)
|
|
13
|
+
- capabilities/commands/constraints/install-safety 영어화 · init en seed 템플릿 i18n.
|
|
14
|
+
|
|
15
|
+
### 검증 (회귀 0)
|
|
16
|
+
- **selftest 250/250** · **E2E 368/368** (i18n 행위가드 lens/health/drift/doctor en/ko) · 게시본 클린룸 재실증.
|
|
17
|
+
- minor(1.29.0) — npm 배포(R-0011 stable) + annotated tag(Stable) + GitHub release(latest).
|
|
18
|
+
|
|
19
|
+
## 1.28.2 — 2026-06-16 — CLI 영어화 Phase 10c: 진단 모듈(doctor/which/whats-new) 완전 영어화 (UR-0010)
|
|
20
|
+
|
|
21
|
+
**🌐 설치/버전 진단 3종을 영어로.** 문제 해결 시 자주 쓰는 진단 명령 `doctor`(설치/환경)·`which`(버전 충돌·npx 캐시)·`whats-new`(버전 변경 요약)를 한 모듈(lib/diagnostics.js)에서 완전 영어화.
|
|
22
|
+
|
|
23
|
+
### 변경 (UR-0010 Phase 10c)
|
|
24
|
+
- **lib/diagnostics.js 3 명령 영어화 (DI uiLang)**: doctor(설치/환경 진단·설치 경로·MCP 도구·selftest 통과/실패·셸·정상/문제), which(현재 실행·버전·npm 환경·글로벌 설치·PATH 후보·진단·강제 최신 방법), whats-new(버전 파악 실패/CHANGELOG 없음 에러·신규 명령·플래그·파일·버전별 헤드라인·권장 행동). `t(ko,en)`, ko 인자 verbatim.
|
|
25
|
+
- **3 DI 호출에 uiLang 주입**: doctorCmd/whichCmd(`_uiLang(arg('--path', cwd))`) + whatsNewCmd(`_uiLang(root)`). 기존 1.9.392/1.9.394 위임 가드 문자열 보존(selftest 무회귀).
|
|
26
|
+
- **한국어 기본 유지**: 영어는 명시 opt-in. ko/내부 호출 무영향.
|
|
27
|
+
|
|
28
|
+
### 잔여 (UR-0010 백로그)
|
|
29
|
+
- capabilities/commands/constraints/install-safety 영어화 · init en seed 템플릿 i18n.
|
|
30
|
+
|
|
31
|
+
### 검증 (회귀 0)
|
|
32
|
+
- **selftest 249→250** (진단 영어/한국어 보존 + uiLang 주입 소스가드) · 행위(doctor/which/whats-new `--language en` 한글 0 [Node 탐지] / ko 보존) · **E2E 368/368** (i18n 행위가드에 doctor en/ko 추가).
|
|
33
|
+
- patch(1.28.2) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
34
|
+
|
|
35
|
+
## 1.28.1 — 2026-06-16 — Phase 10b: drift --auto-fix 로그 영어화 + 보안신호 판정 버그 수정 (UR-0010)
|
|
36
|
+
|
|
37
|
+
**🐛+🌐 drift 를 완전 영어로 + 직전 라운드가 심은 버그 수정.** `drift check --auto-fix` 진행 로그를 영어화하면서, 1.27.2 가 보안 신호 라벨을 언어화하며 함께 심은 **내부 판정 버그**를 발견·수정.
|
|
38
|
+
|
|
39
|
+
### 변경
|
|
40
|
+
- **🐛 hasSecurityFired 언어-결합 버그 수정**: 1.27.2 에서 보안 신호 `label` 을 `t(ko,en)` 로 언어화했는데, 내부 `hasSecurityFired` 가 한국어 라벨 정규식(`/보안 위험 \(1\.9\.78\)/`)으로 매칭하고 있어 **`drift check --auto-fix --language en` 에서 보안 auto-fix 가 발동하지 않던** 잠복 버그. 언어-안정 필드(`f.file === '.env / .gitignore'`)로 매칭 변경 → en/ko 모두 정상 발동. (번역된 라벨에 내부 로직이 결합되면 안 된다는 교훈 — [[lesson-adversarial-harden-heuristic]] 의 'valueGroup' 류와 동일.)
|
|
41
|
+
- **🌐 drift --auto-fix 로그 영어화 (~21줄)**: 보안/인코딩/delivered/idempotency/release-cleanup/session-close 자동회복 진행 로그를 `t(ko,en)`. 이로써 `drift check` 가 **완전히** 영어 지원(출력 + auto-fix).
|
|
42
|
+
- **한국어 기본 유지**: 영어는 명시 opt-in. ko 로그/내부 호출 무영향.
|
|
43
|
+
|
|
44
|
+
### 검증 (회귀 0)
|
|
45
|
+
- **selftest 248→249** (afLog 영어/한국어 + 버그수정 소스가드) · 행위(보안 auto-fix en/ko 모두 발동 + en 로그 한글 0 [Node 탐지] + ko 보존) · **E2E 368/368**.
|
|
46
|
+
- patch(1.28.1) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
47
|
+
|
|
48
|
+
## 1.28.0 — 2026-06-15 — 🛡️ [안정화/Stable] 정직성 후속 + drift 영어화 안정 minor
|
|
49
|
+
|
|
50
|
+
**🛡️ 안정화(Stable) minor — 13번째 외부리뷰 정직성 수정 + drift 진단 영어화를 npm 공개.** 직전 minor(1.27.0) 이후 누적된 패치 2건(1.27.1 + 1.27.2)을 검증·통합해 배포. R-0011 정책의 19번째 stable minor. 한국어 우선 기본은 그대로.
|
|
51
|
+
|
|
52
|
+
### 이번 minor 통합 (1.27.1~1.27.2)
|
|
53
|
+
- **🔎 정직성 후속 수정 (1.27.1)**: `audit <미초기화경로>` 가 "미초기화" 선언 후 없는 하네스에 design/reuse 체크를 보고하던 모순 출력 차단(요약/JSON 직행). `verify-claim --run-tests` 가 비-테스트 `--test-cmd`(exit 0, 미파싱)를 `✓ all passed` 로 거짓표기하던 것을 `✓ ran (exit 0) — test count unconfirmed` 로 정직 표기(판정/exit 불변 → FP=0).
|
|
54
|
+
- **🌐 drift check 출력 영어화 (1.27.2)**: `drift check` 기본 출력(경로/상태/신호 표/보안 신호/권장 조치)을 영어 opt-in. `--auto-fix` 진행 로그는 Phase 10b 백로그. 내부 호출(handoff/health)은 ko 기본이라 무영향.
|
|
55
|
+
- **한국어 우선 기본 보존**: 영어는 명시 opt-in. 한국어 출력/내부 JSON 은 그대로(e2e 무회귀).
|
|
56
|
+
|
|
57
|
+
### 잔여 (백로그)
|
|
58
|
+
- drift `--auto-fix` 로그(Phase 10b) · capabilities/commands/doctor/install-safety/constraints 영어화 · init en seed 템플릿 i18n.
|
|
59
|
+
|
|
60
|
+
### 검증 (회귀 0)
|
|
61
|
+
- **selftest 248/248** · **E2E 368/368** (정직성 후속 가드 + i18n 행위가드 lens/health/drift en/ko) · 게시본 클린룸 재실증.
|
|
62
|
+
- minor(1.28.0) — npm 배포(R-0011 stable) + annotated tag(Stable) + GitHub release(latest).
|
|
63
|
+
|
|
64
|
+
## 1.27.2 — 2026-06-15 — CLI 영어화 Phase 10: drift check 출력 영어화 (UR-0010)
|
|
65
|
+
|
|
66
|
+
**🌐 drift 진단 출력을 영어로.** 고빈도 진단 `drift check` 의 **기본 출력**(경로/상태/신호 표/보안 신호/권장 조치)을 영어 opt-in 으로. `--auto-fix` 진행 로그(~25줄)는 정직하게 Phase 10b 로 분리(반쪽 주장 회피).
|
|
67
|
+
|
|
68
|
+
### 변경 (UR-0010 Phase 10)
|
|
69
|
+
- **drift check 출력 영어화 (lib/drift.js, DI uiLang)**: 경로 없음 에러, 표 헤더(`신호/임계/가중치/발화`→`signal/threshold/weight/fired`), 신호 라벨 8종(`session close 누락`→`session close missing`, `current-state 갱신 없음`, `task update 없음`, `progress-tracker 비어있음`, `task-log 갱신 없음`, `보안 위험`→`security risk`, `Feature Graph 미정리`→`unlinked`, `task 0건 sub-app`), 보안 issue 2종, `권장 조치` 블록. `t(ko,en)`, ko 인자 verbatim.
|
|
70
|
+
- **내부 호출 무영향**: handoff/health 가 drift 를 내부 spawn(LEERNESS_INTERNAL, `--language` 없음)할 땐 ko 기본 라벨 — 한국어 출력/JSON 파싱 그대로(무회귀). 라벨은 `--json` 값도 언어 따름(en 시 영어).
|
|
71
|
+
|
|
72
|
+
### 잔여 (UR-0010 Phase 10b+, 백로그)
|
|
73
|
+
- drift `--auto-fix` 진행 로그(~25줄) + capabilities/commands/doctor/install-safety/constraints + init en seed 템플릿 i18n.
|
|
74
|
+
|
|
75
|
+
### 검증 (회귀 0)
|
|
76
|
+
- **selftest 247→248** (drift 영어/한국어 보존 + uiLang 주입 소스가드) · 행위(drift `--language en` 한글 0 / ko 보존 / 내부호출 ko 유지) · **E2E 368/368** (i18n 행위가드에 drift en/ko 추가).
|
|
77
|
+
- patch(1.27.2) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
78
|
+
|
|
79
|
+
## 1.27.1 — 2026-06-15 — 13번째 외부리뷰 정직성 후속: audit 미초기화 모순출력 + verify-claim no-parse 표기
|
|
80
|
+
|
|
81
|
+
**🔎 13번째 외부리뷰의 정직성 잔여 P2/P3 2건 수정(맹신 X 양방향 재현).** 둘 다 leerness 핵심 정체성(정직한 보고)을 직접 건드리는 출력 문제.
|
|
82
|
+
|
|
83
|
+
### 변경
|
|
84
|
+
- **audit 미초기화 경로 모순 출력 차단 (#2)**: `audit <미초기화경로>` 가 "미초기화" 를 선언한 직후 design/reuse 체크를 **없는 하네스에 대해** 보고하던 모순(예: "✓ no duplicate design guide candidates")을 차단 — 미초기화 감지 시 요약/JSON 으로 직행 후 종료. exit code(1)·`--json` 페이로드(not_initialized finding)는 종전과 동일, **정상 프로젝트 audit 은 무영향**(모든 체크 계속).
|
|
85
|
+
- **verify-claim --run-tests no-parse 정직 표기 (#3)**: 비-테스트 `--test-cmd`(예: `echo hi`)가 exit 0 이면서 테스트 비율을 못 파싱한 경우 `✓ all passed` 로 거짓표기하던 것을 `✓ ran (exit 0) — test count unconfirmed`(실행됨, 테스트 수 미확인)로 정직 표기. **메시지만 변경, 판정/exit 불변** → 출력 포맷이 다른 정상 테스트러너의 통과 주장을 거부하지 않음(FP=0). 진짜 N/N 테스트는 계속 `✓ all passed`, 실패(exit≠0)는 계속 `✗ FAIL`.
|
|
86
|
+
|
|
87
|
+
### 검증 (회귀 0)
|
|
88
|
+
- **selftest 246→247** (소스가드; 기존 1.9.421 "audit body=lib" 가드와 자기참조 충돌을 코멘트 앵커로 회피 — [[lesson-selftest-self-reference-trap]] 적용) · 행위(맹신 X 양방향) · **E2E 367→368** (정직성 후속 회귀가드 1건).
|
|
89
|
+
- patch(1.27.1) — npm 미배포(R-0011, GitHub/CHANGELOG 누적). 잔여(init en seed=대형 템플릿 i18n, Phase 10 진단 영어화)는 백로그.
|
|
90
|
+
|
|
3
91
|
## 1.27.0 — 2026-06-15 — 🛡️ [안정화/Stable] 보안 수정 안정 minor (개인키 스캔 FN + placeholder FP)
|
|
4
92
|
|
|
5
93
|
**🛡️ 안정화(Stable) minor — 13번째 외부리뷰에서 확인된 보안 수정을 조기 npm 공개.** 직전 minor(1.26.0) 이후 1.26.1 패치 1건이지만, **보안 FN/FP(거짓 "보안 OK" + CI 파손)는 패치 누적을 기다리기보다 조기 공개가 합리적**이라 단독 minor 로 게시. R-0011 정책의 18번째 stable minor.
|
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ MIT
|
|
|
104
104
|
<!-- leerness:project-readme:start -->
|
|
105
105
|
## Leerness Project Harness
|
|
106
106
|
|
|
107
|
-
이 프로젝트는 Leerness v1.
|
|
107
|
+
이 프로젝트는 Leerness v1.29.0 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
|
|
108
108
|
|
|
109
109
|
### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
|
|
110
110
|
|
|
@@ -158,7 +158,7 @@ leerness memory restore decision <date|title>
|
|
|
158
158
|
|
|
159
159
|
### MCP server (외부 AI 통합)
|
|
160
160
|
|
|
161
|
-
Leerness v1.
|
|
161
|
+
Leerness v1.29.0는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **85개 도구**를 노출:
|
|
162
162
|
|
|
163
163
|
```jsonc
|
|
164
164
|
// 카테고리별
|
|
@@ -179,7 +179,7 @@ Leerness v1.27.0는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code
|
|
|
179
179
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
180
180
|
1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) stress-v* 신규 작성 + 누적 회귀 → 4) e2e 219/219 → 5) npm pack + git tag + GitHub release → 6) main 자동 push (1.9.140+) → 7) session close → 8) 다음 라운드 예약.
|
|
181
181
|
|
|
182
|
-
현재 누적: **70 라운드 (1.9.40 → 1.
|
|
182
|
+
현재 누적: **70 라운드 (1.9.40 → 1.29.0)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
|
|
183
183
|
|
|
184
184
|
### 성능 가이드 (1.9.140 측정)
|
|
185
185
|
|
|
@@ -217,6 +217,6 @@ leerness release pack --close --auto-main-push
|
|
|
217
217
|
- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
|
|
218
218
|
- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
|
|
219
219
|
|
|
220
|
-
Last synced by Leerness v1.
|
|
220
|
+
Last synced by Leerness v1.29.0: 2026-06-16
|
|
221
221
|
<!-- leerness:project-readme:end -->
|
|
222
222
|
|
package/bin/leerness.js
CHANGED
|
@@ -32,7 +32,7 @@ const { _evidenceQuality, _parseEvidenceStats, _shellGuardAnalyze, _claimFileInG
|
|
|
32
32
|
// 1.9.295 (UR-0025 4단계): 정적 데이터 카탈로그 모듈 분리 (비파괴, require-based).
|
|
33
33
|
const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE_CHECKLIST, _DEFAULT_PLATFORM_CONSTRAINTS, _DEFAULT_DOMAIN_CATALOG, _TOOL_CATALOG, _LSP_LANG_PATTERNS, OPTIMISM_PATTERNS, BUILT_IN_PERSONAS, STRINGS, BUILTIN_CATALOG, ROADMAP_STATUS_LABEL, ROADMAP_STATUS_COLOR, SECRET_PATTERNS, MERGE_OVERWRITE_FILES, MINIMAL_SKIP_KEYS, REQUIRED_WORKSPACE_FILES, KEYWORD_STOPWORDS, SKILL_CATALOG_PRESETS } = require('../lib/catalogs'); // 1.9.344/368/369 (UR-0025): catalog 분리 · 1.11.4 (UR-0007): _TOOL_CATALOG
|
|
34
34
|
|
|
35
|
-
const VERSION = '1.
|
|
35
|
+
const VERSION = '1.29.0';
|
|
36
36
|
|
|
37
37
|
// 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
|
|
38
38
|
// 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
|
|
@@ -3820,6 +3820,37 @@ function _selfTestCases() {
|
|
|
3820
3820
|
const retroGuard = bin.includes("failJson(has('--json'), 'invalid_arg'") && bin.includes('Math.min(days, 36500)');
|
|
3821
3821
|
return keyFile && dbVg && phPlaceholder && retroGuard;
|
|
3822
3822
|
} },
|
|
3823
|
+
{ name: '13번째 외부리뷰 정직성 후속 (1.27.1): audit 미초기화 early-return + verify-claim no-parse 표기 (소스 가드)', run: () => {
|
|
3824
|
+
const bin = read(__filename);
|
|
3825
|
+
const aud = read(path.join(path.dirname(__filename), '..', 'lib', 'audit.js'));
|
|
3826
|
+
// 주의: bin 에 'not_'+'initialized' 리터럴을 두면 1.9.421('body 가 lib 로 이동') 가드가 깨짐 → 코멘트 텍스트로 앵커.
|
|
3827
|
+
const auditReturn = aud.includes('// 1.27.1 (13번째 외부리뷰 #2)') && /외부리뷰 #2\)[\s\S]{0,1200}?process\.exitCode = 1;\s*\n\s*return;/.test(aud);
|
|
3828
|
+
const vcMsg = bin.includes("test count unconfirmed") && bin.includes('runResult.parsed ? ');
|
|
3829
|
+
return auditReturn && vcMsg;
|
|
3830
|
+
} },
|
|
3831
|
+
{ name: 'CLI 영어화 Phase 10 (1.27.2, UR-0010): drift check 출력 영어/한국어 보존 + uiLang 주입 (소스 가드)', run: () => {
|
|
3832
|
+
const bin = read(__filename);
|
|
3833
|
+
const dr = read(path.join(path.dirname(__filename), '..', 'lib', 'drift.js'));
|
|
3834
|
+
const injected = bin.includes('uiLang: _uiLang(root), harnessPath: __filename, readProgressRows, planPath, handoffPath, currentStatePath, taskLogPath');
|
|
3835
|
+
const en = dr.includes('| signal | age | threshold | weight | fired |') && dr.includes('session close missing') && dr.includes('recommended actions') && dr.includes('security risk:');
|
|
3836
|
+
const koPreserved = dr.includes('| 신호 | age | 임계 | 가중치 | 발화 |') && dr.includes('session close 누락') && dr.includes('권장 조치'); // ko 인자 보존(e2e ko/내부호출)
|
|
3837
|
+
return injected && en && koPreserved;
|
|
3838
|
+
} },
|
|
3839
|
+
{ name: 'Phase 10b (1.28.1): drift --auto-fix 로그 영어화 + hasSecurityFired 언어안정 매칭 (소스 가드)', run: () => {
|
|
3840
|
+
const dr = read(path.join(path.dirname(__filename), '..', 'lib', 'drift.js'));
|
|
3841
|
+
const bugFix = dr.includes("f.file === '.env / .gitignore'"); // 보안 신호 판정을 언어-안정 file 필드로(라벨 regex 결합 제거)
|
|
3842
|
+
const afLogEn = dr.includes('recovering security signal: running audit --fix') && dr.includes('re-checking...') && dr.includes('auto-fix error:');
|
|
3843
|
+
const afLogKo = dr.includes('보안 신호 회복: audit --fix 자동 실행 중') && dr.includes('재검사 중...'); // ko 인자 보존
|
|
3844
|
+
return bugFix && afLogEn && afLogKo;
|
|
3845
|
+
} },
|
|
3846
|
+
{ name: 'Phase 10c (1.28.2): 진단 모듈(doctor/which/whats-new) 영어/한국어 보존 + uiLang 주입 (소스 가드)', run: () => {
|
|
3847
|
+
const bin = read(__filename);
|
|
3848
|
+
const dg = read(path.join(path.dirname(__filename), '..', 'lib', 'diagnostics.js'));
|
|
3849
|
+
const injected = bin.includes("uiLang: _uiLang(arg('--path', process.cwd())), _selfTestCases") && bin.includes('_diag.whatsNewCmd(root, { VERSION, uiLang: _uiLang(root)');
|
|
3850
|
+
const en = dg.includes('install/environment diagnosis') && dg.includes('## npm environment') && dg.includes('per-version headlines') && dg.includes('how to force the latest');
|
|
3851
|
+
const koPreserved = dg.includes('설치/환경 진단') && dg.includes('## npm 환경') && dg.includes('버전별 헤드라인'); // ko 인자 보존(내부호출/e2e)
|
|
3852
|
+
return injected && en && koPreserved;
|
|
3853
|
+
} },
|
|
3823
3854
|
{ name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
|
|
3824
3855
|
];
|
|
3825
3856
|
}
|
|
@@ -10383,7 +10414,8 @@ function verifyClaimCmd(root, taskId) {
|
|
|
10383
10414
|
// 1.17.4 (UR-0047): 측정 불가는 '통과' 가 아니라 '검증 미수행' — 이전엔 실측 0 인데 ✓ pass(실측≥주장) 모순 표기.
|
|
10384
10415
|
log(` - ${t('테스트 카운트', 'test count')}: ${declaredTestCount == null ? t('⊘ (주장 없음)', '⊘ (none claimed)') : !testMeasured ? t(`⊘ 측정 불가 — 주장 ${declaredTestCount}개 검증 미수행 (pass 아님)`, `⊘ not measurable — claimed ${declaredTestCount} not verified (not a pass)`) : testOk ? t('✓ pass (실측 ≥ 주장)', '✓ pass (measured ≥ claimed)') : t('⚠ 주장보다 적음', '⚠ fewer than claimed')}`);
|
|
10385
10416
|
if (runResult && !runResult.skipped) {
|
|
10386
|
-
|
|
10417
|
+
// 1.27.1 (13번째 외부리뷰 #3): exit 0 인데 테스트 비율을 못 파싱한 경우(예: 비-테스트 --test-cmd)를 '✓ all passed' 로 거짓표기하지 않음 — '실행됨, 테스트 수 미확인' 으로 정직 표기(판정/exit 불변 → 이색 테스트러너 FP 없음).
|
|
10418
|
+
log(` - ${runResult.cmd || 'npm test'} ${t('실행', 'run')}: ${runTestsOk ? (runResult.parsed ? '✓ all passed' : t('✓ 실행됨 (exit 0) — 테스트 수 미확인', '✓ ran (exit 0) — test count unconfirmed')) : '✗ FAIL'}`);
|
|
10387
10419
|
if (declaredPass) log(` - ${t('주장과 실행 결과 일치', 'claimed matches run')}: ${declaredPassMatchesActual ? '✓ pass' : t('⚠ 다름', '⚠ differs')}`);
|
|
10388
10420
|
}
|
|
10389
10421
|
// 1.11.2 (UR-0175): optimism+정직성 — done 주장은 기본 게이팅(claimsChecked). 완화: --lenient.
|
|
@@ -14913,7 +14945,7 @@ function autoUpdateInstall(root) {
|
|
|
14913
14945
|
// 1.9.37: drift detection — 메타파일 staleness 측정으로 "leerness 점점 안 쓰는" 현상 감지
|
|
14914
14946
|
const _drift = require('../lib/drift');
|
|
14915
14947
|
// 1.9.422 (UR-0025/UR-0125 큰 핸들러 모듈화 7번째): driftCheckCmd → lib/drift.js (DI 위임, thin wrapper)
|
|
14916
|
-
function driftCheckCmd(root, opts = {}) { return _drift.driftCheckCmd(root, opts, { VERSION, has, arg, harnessPath: __filename, readProgressRows, planPath, handoffPath, currentStatePath, taskLogPath, envDiff, _usageStatsPath, _readUsageStats, _updateUserRequest, _scanShellScriptsEncoding, _readFeatureGraph, _detectDeliveredRequests, _autoFixIdempotency }); }
|
|
14948
|
+
function driftCheckCmd(root, opts = {}) { return _drift.driftCheckCmd(root, opts, { VERSION, has, arg, uiLang: _uiLang(root), harnessPath: __filename, readProgressRows, planPath, handoffPath, currentStatePath, taskLogPath, envDiff, _usageStatsPath, _readUsageStats, _updateUserRequest, _scanShellScriptsEncoding, _readFeatureGraph, _detectDeliveredRequests, _autoFixIdempotency }); }
|
|
14917
14949
|
|
|
14918
14950
|
// 1.9.69: skill-suggestions.md rolling history 인덱스 — mtime 기반 캐시
|
|
14919
14951
|
// handoff에서 같은 키워드 과거 추천 결과를 즉시 노출 (재매칭 불필요)
|
|
@@ -16098,7 +16130,7 @@ function mcpServeCmd(root) {
|
|
|
16098
16130
|
}
|
|
16099
16131
|
|
|
16100
16132
|
// 1.9.394 (UR-0025): whatsNewCmd 를 lib/diagnostics.js 로 분리 (whats-new 서브시스템 완결 — 파서는 1.9.393 에 pure-utils 로). deps 위임.
|
|
16101
|
-
function whatsNewCmd(root) { return _diag.whatsNewCmd(root, { VERSION, arg, has }); }
|
|
16133
|
+
function whatsNewCmd(root) { return _diag.whatsNewCmd(root, { VERSION, uiLang: _uiLang(root), arg, has }); }
|
|
16102
16134
|
|
|
16103
16135
|
// 1.9.71: .env / .env.example 자동 동기화 — 누락 키 감지 + (옵션) 자동 추가
|
|
16104
16136
|
// 보안 정책: .env의 실제 값은 절대 옮기지 않음. .env.example엔 키만 (빈 값).
|
|
@@ -19717,8 +19749,8 @@ function reviewRequestCmd(root, request) { return _reviewRequest.reviewRequestCm
|
|
|
19717
19749
|
// 1.9.392 (UR-0025 큰 핸들러 모듈화 4번째): doctor/which 진단 핸들러를 lib/diagnostics.js 로 분리.
|
|
19718
19750
|
// harness 는 deps(VERSION · _selfTestCases · _detectShellCtx · _mcpToolCount · has · harnessPath)를 구성해 위임(thin wrapper). 호출부/동작 무변경.
|
|
19719
19751
|
const _diag = require('../lib/diagnostics');
|
|
19720
|
-
function doctorCmd(opts = {}) { return _diag.doctorCmd(opts, { VERSION, _selfTestCases, _detectShellCtx, _mcpToolCount, has, harnessPath: __filename }); }
|
|
19721
|
-
function whichCmd() { return _diag.whichCmd({ VERSION, has, harnessPath: __filename }); }
|
|
19752
|
+
function doctorCmd(opts = {}) { return _diag.doctorCmd(opts, { VERSION, uiLang: _uiLang(arg('--path', process.cwd())), _selfTestCases, _detectShellCtx, _mcpToolCount, has, harnessPath: __filename }); }
|
|
19753
|
+
function whichCmd() { return _diag.whichCmd({ VERSION, uiLang: _uiLang(arg('--path', process.cwd())), has, harnessPath: __filename }); }
|
|
19722
19754
|
|
|
19723
19755
|
// 1.23.1 (UR-0010 Phase 6): 영어 큐레이트 도움말 — 한국어 help 의 줄별 번역이 아니라, 카테고리별로 정리한 별도 영어판.
|
|
19724
19756
|
// 레거시 버전태그(1.9.x) 군더더기를 빼고 영어 사용자가 읽기 쉽게. 전체 전수 목록은 `leerness commands`.
|
package/lib/audit.js
CHANGED
|
@@ -26,6 +26,11 @@ function audit(root, opts = {}, deps = {}) {
|
|
|
26
26
|
failures++;
|
|
27
27
|
fail(`미초기화 또는 존재하지 않는 경로: ${root} (.harness/AGENTS.md 없음 — leerness init 필요)`);
|
|
28
28
|
_finding('not_initialized', 'fail', 'uninitialized or missing path (.harness or AGENTS.md absent)', { root });
|
|
29
|
+
// 1.27.1 (13번째 외부리뷰 #2): 미초기화 시 후속 체크(design/reuse 등)를 없는 하네스에 대해 보고하던 모순 출력 차단 — 요약/JSON 으로 직행 후 종료(exit code/JSON 페이로드는 종전과 동일).
|
|
30
|
+
log(`Audit summary: warnings=${warnings} failures=${failures}`);
|
|
31
|
+
if (jsonMode) { process.stdout.write = _origWrite; process.stdout.write(JSON.stringify({ version: VERSION, root, warnings, failures, fixed, healthy: false, fixApplied: fix, strict: has('--strict'), strictThreshold: has('--strict') ? parseInt(arg('--threshold', '1'), 10) : null, summary: `warnings=${warnings} failures=${failures}`, findings }, null, 2) + '\n'); }
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
return;
|
|
29
34
|
}
|
|
30
35
|
const designCands = ['designguide.md','design-guide.md','docs/designguide.md','docs/design-guide.md','.harness/designguide.md'];
|
|
31
36
|
const dups = designCands.filter(f => exists(path.join(root,f)));
|
package/lib/diagnostics.js
CHANGED
|
@@ -10,7 +10,8 @@ const { log, fail, absRoot, exists, read } = require('./io');
|
|
|
10
10
|
const { parseHarnessVersion, _parseChangelogBetween } = require('./pure-utils');
|
|
11
11
|
|
|
12
12
|
function doctorCmd(opts = {}, deps = {}) {
|
|
13
|
-
const { VERSION, _selfTestCases, _detectShellCtx, _mcpToolCount, has, harnessPath } = deps;
|
|
13
|
+
const { VERSION, uiLang, _selfTestCases, _detectShellCtx, _mcpToolCount, has, harnessPath } = deps;
|
|
14
|
+
const t = (ko, en) => (uiLang === 'en' ? en : ko); // 1.28.2 (UR-0010 Phase 10c)
|
|
14
15
|
const json = opts.json || has('--json');
|
|
15
16
|
// 1) 코어 무결성: selftest 케이스 인라인 실행
|
|
16
17
|
let pass = 0; const failNames = [];
|
|
@@ -35,23 +36,24 @@ function doctorCmd(opts = {}, deps = {}) {
|
|
|
35
36
|
if (json) { process.stdout.write(JSON.stringify(report, null, 2) + '\n'); if (!report.healthy) process.exitCode = 1; return report; }
|
|
36
37
|
const isTty = process.stdout && process.stdout.isTTY;
|
|
37
38
|
const gr = s => isTty ? `\x1b[32m${s}\x1b[0m` : s, rd = s => isTty ? `\x1b[31m${s}\x1b[0m` : s, cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s, dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
38
|
-
log(cy(`# leerness doctor — 설치/환경
|
|
39
|
+
log(cy(t(`# leerness doctor — 설치/환경 진단`, `# leerness doctor — install/environment diagnosis`)));
|
|
39
40
|
log('');
|
|
40
41
|
log(` ${gr('✓')} version ${VERSION} · node ${process.version} · ${process.platform}/${process.arch}`);
|
|
41
|
-
log(` ${gr('✓')} 설치
|
|
42
|
-
log(` ${gr('✓')} MCP
|
|
42
|
+
log(` ${gr('✓')} ${t('설치 경로', 'install path')}: ${dm(harnessPath)}`);
|
|
43
|
+
log(` ${gr('✓')} ${t('MCP 도구', 'MCP tools')}: ${mcpCount}`);
|
|
43
44
|
// 1.13.1 (15th 블라인드 리뷰 P3, Sonnet): pass 수에 '실패' 가 붙어 "209/210 실패"(=209건 실패로 오독)되던 문구 → "통과 N/M (K건 실패)" 로 명확화.
|
|
44
|
-
log(` ${report.selftest.ok ? gr('✓') : rd('✗')} selftest: ${pass}/${total}
|
|
45
|
+
log(` ${report.selftest.ok ? gr('✓') : rd('✗')} selftest: ${pass}/${total} ${t('통과', 'passed')}${report.selftest.ok ? '' : t(` (${total - pass}건 실패)`, ` (${total - pass} failed)`)}`);
|
|
45
46
|
if (!report.selftest.ok) report.selftest.failed.slice(0, 5).forEach(n => log(rd(` ✗ ${n}`)));
|
|
46
|
-
log(` ${gr('✓')}
|
|
47
|
+
log(` ${gr('✓')} ${t('셸', 'shell')}: ${shell || 'unknown'}${psVersion && shell === 'powershell' ? ` (PowerShell ${psVersion})` : ''}`);
|
|
47
48
|
log('');
|
|
48
|
-
log(report.healthy ? gr(' ✓ leerness 설치 정상') : rd(' ✗ 문제 감지 — 재설치: npm i -g leerness@latest · 진단: leerness which'));
|
|
49
|
+
log(report.healthy ? gr(t(' ✓ leerness 설치 정상', ' ✓ leerness install OK')) : rd(t(' ✗ 문제 감지 — 재설치: npm i -g leerness@latest · 진단: leerness which', ' ✗ problem detected — reinstall: npm i -g leerness@latest · diagnose: leerness which')));
|
|
49
50
|
if (!report.healthy) process.exitCode = 1;
|
|
50
51
|
return report;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
function whichCmd(deps = {}) {
|
|
54
|
-
const { VERSION, has, harnessPath } = deps;
|
|
55
|
+
const { VERSION, uiLang, has, harnessPath } = deps;
|
|
56
|
+
const t = (ko, en) => (uiLang === 'en' ? en : ko); // 1.28.2 (UR-0010 Phase 10c)
|
|
55
57
|
const out = {
|
|
56
58
|
version: VERSION,
|
|
57
59
|
runningFrom: harnessPath,
|
|
@@ -91,48 +93,49 @@ function whichCmd(deps = {}) {
|
|
|
91
93
|
// 진단: 글로벌 설치된 leerness 와 현재 실행 버전이 다르면 경고
|
|
92
94
|
out.diagnostics = [];
|
|
93
95
|
if (out.npm.globalInstalled && out.npm.globalInstalled !== VERSION) {
|
|
94
|
-
out.diagnostics.push(`⚠ 글로벌 설치 ${out.npm.globalInstalled} ≠ 현재 실행 ${VERSION} — npx 캐시 또는 PATH 충돌
|
|
95
|
-
out.diagnostics.push(` → 강제 최신: npm i -g leerness@latest / 또는 npx --yes leerness@latest <command>`);
|
|
96
|
+
out.diagnostics.push(t(`⚠ 글로벌 설치 ${out.npm.globalInstalled} ≠ 현재 실행 ${VERSION} — npx 캐시 또는 PATH 충돌 의심`, `⚠ global install ${out.npm.globalInstalled} ≠ running ${VERSION} — suspect npx cache or PATH conflict`));
|
|
97
|
+
out.diagnostics.push(t(` → 강제 최신: npm i -g leerness@latest / 또는 npx --yes leerness@latest <command>`, ` → force latest: npm i -g leerness@latest / or npx --yes leerness@latest <command>`));
|
|
96
98
|
}
|
|
97
99
|
if (out.pathCandidates.length > 1) {
|
|
98
|
-
out.diagnostics.push(`⚠ PATH 에 leerness 가 ${out.pathCandidates.length}개 — 우선순위 충돌
|
|
99
|
-
out.diagnostics.push(` → 명시적 경로 사용: ${out.runningFrom}`);
|
|
100
|
+
out.diagnostics.push(t(`⚠ PATH 에 leerness 가 ${out.pathCandidates.length}개 — 우선순위 충돌 가능`, `⚠ leerness appears ${out.pathCandidates.length}× on PATH — possible precedence conflict`));
|
|
101
|
+
out.diagnostics.push(t(` → 명시적 경로 사용: ${out.runningFrom}`, ` → use the explicit path: ${out.runningFrom}`));
|
|
100
102
|
}
|
|
101
103
|
if (has('--json')) { log(JSON.stringify(out, null, 2)); return; }
|
|
102
104
|
log(`# leerness which (1.9.164)`);
|
|
103
|
-
log(
|
|
104
|
-
log(
|
|
105
|
+
log(`${t('현재 실행', 'running from')}: ${out.runningFrom}`);
|
|
106
|
+
log(`${t('버전', 'version')}: v${out.version}`);
|
|
105
107
|
log(`Node: ${out.nodeVersion} (${out.platform}/${out.arch})`);
|
|
106
108
|
log('');
|
|
107
|
-
log(`## npm
|
|
109
|
+
log(t(`## npm 환경`, `## npm environment`));
|
|
108
110
|
if (out.npm.globalRoot) log(` npm root -g: ${out.npm.globalRoot}`);
|
|
109
|
-
if (out.npm.cacheDir) log(` npm cache: ${out.npm.cacheDir} (npx 옛 버전이 여기 캐싱 — 의심 시 \`npm cache clean --force\`)`);
|
|
110
|
-
if (out.npm.globalInstalled) log(` 글로벌 설치: leerness@${out.npm.globalInstalled}`);
|
|
111
|
-
else log(` 글로벌 설치: (없음 — npx 또는 로컬 경로만 사용 중)`);
|
|
111
|
+
if (out.npm.cacheDir) log(t(` npm cache: ${out.npm.cacheDir} (npx 옛 버전이 여기 캐싱 — 의심 시 \`npm cache clean --force\`)`, ` npm cache: ${out.npm.cacheDir} (npx caches old versions here — if suspect: \`npm cache clean --force\`)`));
|
|
112
|
+
if (out.npm.globalInstalled) log(t(` 글로벌 설치: leerness@${out.npm.globalInstalled}`, ` global install: leerness@${out.npm.globalInstalled}`));
|
|
113
|
+
else log(t(` 글로벌 설치: (없음 — npx 또는 로컬 경로만 사용 중)`, ` global install: (none — using npx or a local path only)`));
|
|
112
114
|
if (out.pathCandidates.length) {
|
|
113
115
|
log('');
|
|
114
|
-
log(`## PATH 후보 (${out.pathCandidates.length}개)`);
|
|
116
|
+
log(t(`## PATH 후보 (${out.pathCandidates.length}개)`, `## PATH candidates (${out.pathCandidates.length})`));
|
|
115
117
|
for (const p of out.pathCandidates) log(` - ${p}`);
|
|
116
118
|
}
|
|
117
119
|
if (out.diagnostics.length) {
|
|
118
120
|
log('');
|
|
119
|
-
log(`## ⚠
|
|
121
|
+
log(t(`## ⚠ 진단`, `## ⚠ diagnostics`));
|
|
120
122
|
for (const d of out.diagnostics) log(` ${d}`);
|
|
121
123
|
} else {
|
|
122
124
|
log('');
|
|
123
|
-
log(`✓ 충돌 없음 (현재 실행 버전 = 글로벌 설치 버전)`);
|
|
125
|
+
log(t(`✓ 충돌 없음 (현재 실행 버전 = 글로벌 설치 버전)`, `✓ no conflict (running version = global install version)`));
|
|
124
126
|
}
|
|
125
127
|
log('');
|
|
126
|
-
log(`💡 강제 최신 실행
|
|
127
|
-
log(` 1) npx --yes leerness@latest <command> # npx 캐시 무시하고 최신
|
|
128
|
-
log(` 2) npm i -g leerness@latest # 글로벌 설치
|
|
129
|
-
log(` 3) npm cache clean --force # npx 캐시 강제 비우기 (의심 시)`);
|
|
128
|
+
log(t(`💡 강제 최신 실행 방법:`, `💡 how to force the latest:`));
|
|
129
|
+
log(t(` 1) npx --yes leerness@latest <command> # npx 캐시 무시하고 최신 다운로드`, ` 1) npx --yes leerness@latest <command> # bypass npx cache, download latest`));
|
|
130
|
+
log(t(` 2) npm i -g leerness@latest # 글로벌 설치 갱신`, ` 2) npm i -g leerness@latest # update the global install`));
|
|
131
|
+
log(t(` 3) npm cache clean --force # npx 캐시 강제 비우기 (의심 시)`, ` 3) npm cache clean --force # force-clear the npx cache (if suspect)`));
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
// 1.9.394 (UR-0025): whats-new — 현재 워크스페이스 버전 → 도구 버전 CHANGELOG 차분(신규 명령/플래그/파일 요약). introspection 핸들러.
|
|
133
135
|
// 순수 파서 _parseChangelogBetween(pure-utils) 사용. deps: VERSION/arg/has. CHANGELOG 경로는 root 우선, 없으면 pkg 자체(lib/../).
|
|
134
136
|
function whatsNewCmd(root, deps = {}) {
|
|
135
|
-
const { VERSION, arg, has } = deps;
|
|
137
|
+
const { VERSION, uiLang, arg, has } = deps;
|
|
138
|
+
const t = (ko, en) => (uiLang === 'en' ? en : ko); // 1.28.2 (UR-0010 Phase 10c)
|
|
136
139
|
root = absRoot(root || process.cwd());
|
|
137
140
|
const fromV = arg('--from', null) || (function () {
|
|
138
141
|
const hv = path.join(root, '.harness', 'HARNESS_VERSION');
|
|
@@ -141,29 +144,29 @@ function whatsNewCmd(root, deps = {}) {
|
|
|
141
144
|
})();
|
|
142
145
|
const toV = arg('--to', null) || VERSION;
|
|
143
146
|
if (!fromV) {
|
|
144
|
-
fail('현재 버전을 파악할 수 없습니다. --from <version> 명시');
|
|
147
|
+
fail(t('현재 버전을 파악할 수 없습니다. --from <version> 명시', 'cannot determine current version. specify --from <version>'));
|
|
145
148
|
return process.exit(1);
|
|
146
149
|
}
|
|
147
150
|
// CHANGELOG.md — 우선 root, 없으면 leerness-pkg 자체 (lib/../CHANGELOG.md = pkg 루트)
|
|
148
151
|
let changelogPath = path.join(root, 'CHANGELOG.md');
|
|
149
152
|
if (!exists(changelogPath)) changelogPath = path.join(__dirname, '..', 'CHANGELOG.md');
|
|
150
153
|
if (!exists(changelogPath)) {
|
|
151
|
-
fail('CHANGELOG.md 없음');
|
|
154
|
+
fail(t('CHANGELOG.md 없음', 'CHANGELOG.md not found'));
|
|
152
155
|
return process.exit(1);
|
|
153
156
|
}
|
|
154
157
|
const diff = _parseChangelogBetween(read(changelogPath), fromV, toV);
|
|
155
158
|
if (has('--json')) { log(JSON.stringify({ from: fromV, to: toV, versions: diff }, null, 2)); return; }
|
|
156
159
|
if (!diff.length) {
|
|
157
160
|
log(`# leerness whats-new (1.9.41)`);
|
|
158
|
-
log(`현재 ${fromV} ↔ 대상 ${toV}: 새 항목 없음 (또는 CHANGELOG에 기록 안 됨)`);
|
|
161
|
+
log(t(`현재 ${fromV} ↔ 대상 ${toV}: 새 항목 없음 (또는 CHANGELOG에 기록 안 됨)`, `current ${fromV} ↔ target ${toV}: no new entries (or not recorded in CHANGELOG)`));
|
|
159
162
|
return;
|
|
160
163
|
}
|
|
161
164
|
log(`# leerness whats-new (1.9.41)`);
|
|
162
|
-
log(`현재 워크스페이스 버전: ${fromV} → 대상: ${toV}`);
|
|
163
|
-
log(`범위: ${diff.length}개 버전 (${diff[0].version} → ${diff[diff.length - 1].version})`);
|
|
165
|
+
log(t(`현재 워크스페이스 버전: ${fromV} → 대상: ${toV}`, `current workspace version: ${fromV} → target: ${toV}`));
|
|
166
|
+
log(t(`범위: ${diff.length}개 버전 (${diff[0].version} → ${diff[diff.length - 1].version})`, `range: ${diff.length} version(s) (${diff[0].version} → ${diff[diff.length - 1].version})`));
|
|
164
167
|
log('');
|
|
165
168
|
// AI 가독 요약 — 각 버전당 한 줄 + 신규 명령/플래그/파일
|
|
166
|
-
log(`## 🆕 신규 명령·플래그·파일 (AI 에이전트는 다음 명령을 우선 시도)`);
|
|
169
|
+
log(t(`## 🆕 신규 명령·플래그·파일 (AI 에이전트는 다음 명령을 우선 시도)`, `## 🆕 new commands·flags·files (AI agents: try these first)`));
|
|
167
170
|
const allCommands = new Set();
|
|
168
171
|
const allFlags = new Set();
|
|
169
172
|
const allFiles = new Set();
|
|
@@ -172,11 +175,11 @@ function whatsNewCmd(root, deps = {}) {
|
|
|
172
175
|
v.newFlags.forEach(f => allFlags.add(f));
|
|
173
176
|
v.newFiles.forEach(f => allFiles.add(f));
|
|
174
177
|
}
|
|
175
|
-
if (allCommands.size) log(` 📌 신규 명령: ${[...allCommands].join(', ')}`);
|
|
176
|
-
if (allFlags.size) log(` 🚩 신규 플래그: ${[...allFlags].join(', ')}`);
|
|
177
|
-
if (allFiles.size) log(` 📄 신규 파일: ${[...allFiles].join(', ')}`);
|
|
178
|
+
if (allCommands.size) log(t(` 📌 신규 명령: ${[...allCommands].join(', ')}`, ` 📌 new commands: ${[...allCommands].join(', ')}`));
|
|
179
|
+
if (allFlags.size) log(t(` 🚩 신규 플래그: ${[...allFlags].join(', ')}`, ` 🚩 new flags: ${[...allFlags].join(', ')}`));
|
|
180
|
+
if (allFiles.size) log(t(` 📄 신규 파일: ${[...allFiles].join(', ')}`, ` 📄 new files: ${[...allFiles].join(', ')}`));
|
|
178
181
|
log('');
|
|
179
|
-
log(`## 📜 버전별
|
|
182
|
+
log(t(`## 📜 버전별 헤드라인`, `## 📜 per-version headlines`));
|
|
180
183
|
for (const v of diff) {
|
|
181
184
|
// body 첫 줄(또는 strong header) 추출
|
|
182
185
|
const firstLine = (v.body.match(/^\*\*([^*]+)\*\*/) || [])[1]
|
|
@@ -184,11 +187,11 @@ function whatsNewCmd(root, deps = {}) {
|
|
|
184
187
|
log(` • ${v.version}${v.date ? ` (${v.date})` : ''} — ${firstLine || '(no headline)'}`);
|
|
185
188
|
}
|
|
186
189
|
log('');
|
|
187
|
-
log(`## 💡 권장
|
|
188
|
-
log(` 1. 위 신규 명령들을 시도해 보세요 (예: \`leerness <명령> --help\`)`);
|
|
189
|
-
log(` 2. 신규 파일들을 읽어 보세요 (예: \`cat .harness/session-workflow.md\`)`);
|
|
190
|
-
log(` 3. AGENTS.md/CLAUDE.md 재독 — migrate가 인스트럭션을 업데이트했을 수
|
|
191
|
-
log(` 4. 상세: \`cat CHANGELOG.md\` 또는 \`leerness whats-new --json\``);
|
|
190
|
+
log(t(`## 💡 권장 행동`, `## 💡 recommended actions`));
|
|
191
|
+
log(t(` 1. 위 신규 명령들을 시도해 보세요 (예: \`leerness <명령> --help\`)`, ` 1. Try the new commands above (e.g. \`leerness <command> --help\`)`));
|
|
192
|
+
log(t(` 2. 신규 파일들을 읽어 보세요 (예: \`cat .harness/session-workflow.md\`)`, ` 2. Read the new files (e.g. \`cat .harness/session-workflow.md\`)`));
|
|
193
|
+
log(t(` 3. AGENTS.md/CLAUDE.md 재독 — migrate가 인스트럭션을 업데이트했을 수 있음`, ` 3. Re-read AGENTS.md/CLAUDE.md — migrate may have updated the instructions`));
|
|
194
|
+
log(t(` 4. 상세: \`cat CHANGELOG.md\` 또는 \`leerness whats-new --json\``, ` 4. Details: \`cat CHANGELOG.md\` or \`leerness whats-new --json\``));
|
|
192
195
|
}
|
|
193
196
|
|
|
194
197
|
module.exports = { doctorCmd, whichCmd, whatsNewCmd };
|