leerness 1.24.0 → 1.25.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 +48 -0
- package/README.md +4 -4
- package/bin/leerness.js +91 -22
- package/lib/session-close.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.25.0 — 2026-06-15 — 🛡️ [안정화/Stable] 마감 본문 정직성 + lens 플래그십 영어화 안정 minor
|
|
4
|
+
|
|
5
|
+
**🛡️ 안정화(Stable) minor — 자가 검증으로 잡은 정직성 수정 + 품질 렌즈 영어화를 npm 공개.** 직전 minor(1.24.0) 이후 누적된 패치 2건(1.24.1 + 1.24.2)을 검증·통합해 배포. R-0011 정책의 16번째 stable minor. 한국어 우선 기본은 그대로.
|
|
6
|
+
|
|
7
|
+
### 이번 minor 통합 (1.24.1~1.24.2)
|
|
8
|
+
- **🔎 session close 보고 본문 정직성 수정 (1.24.1)**: 게시된 모든 영어 표면을 `--language en` 으로 실행해 한글 누출을 자동 스캔(맹신 X — 내 'CLOSED' 주장 재실증)한 결과, 1.23.0 "session close 완전 영어" 가 과장임을 발견 → 보고 본문 잔여 영어화(`- 없음`→`- none`, `완료/결정 누적`→`done/decisions accumulated`, roadmap `자동 갱신`→`auto-updated`).
|
|
9
|
+
- **🌐 lens 품질 렌즈 플래그십 영어화 (1.24.2)**: 분야별 자기질문 품질 렌즈 5 도메인(code/design/docs/test/security)에 영어 병렬 카탈로그 추가 + `--language en` 렌더. 영어권 사용자도 완료 선언 전 자가 점검 + 분야간 인과를 활용.
|
|
10
|
+
- **한국어 우선 기본 보존**: 영어는 명시 opt-in. 한국어 원문/렌즈 질문은 한 글자도 안 바뀜(e2e 무회귀).
|
|
11
|
+
|
|
12
|
+
### 잔여 (UR-0010 Phase 9+, 백로그)
|
|
13
|
+
- 진단/정보 명령 본문(health/capabilities/commands/doctor/drift/install-safety/constraints) + 메모리 CRUD 빈상태 메시지 + handoff 본문 + init starter 데이터 — en-leak 스캔 우선순위순 단계적 확대.
|
|
14
|
+
|
|
15
|
+
### 검증 (회귀 0)
|
|
16
|
+
- **selftest 244/244** (정직성 + lens 영어/한국어 보존 소스가드 포함) · 행위(en-leak 스캔: session close 본문·lens en 한글 0 / ko 보존) · **E2E 365/365**.
|
|
17
|
+
- minor(1.25.0) — npm 배포(R-0011 stable) + annotated tag(Stable) + GitHub release(latest) + 게시본 클린룸 재실증.
|
|
18
|
+
|
|
19
|
+
## 1.24.2 — 2026-06-15 — CLI 영어화 Phase 8: lens(품질 렌즈 플래그십) 영어화 (UR-0010)
|
|
20
|
+
|
|
21
|
+
**🌐 품질 렌즈를 영어로.** 남은 한국어 표면을 en-leak 스캔으로 매핑한 뒤, 가장 가치 높은 플래그십 — **분야별 자기질문 품질 렌즈(`leerness lens`)** — 를 영어화. 영어권 사용자도 "완료 선언 전 자가 점검" + 분야간 인과관계를 그대로 활용할 수 있습니다.
|
|
22
|
+
|
|
23
|
+
### 변경 (UR-0010 Phase 8)
|
|
24
|
+
- **lens 영어 병렬 카탈로그**: `LENS_CATALOG` 5 도메인(code/design/docs/test/security)에 `titleEn`/`personaEn`/`questionsEn`/`affectsNoteEn` 추가. 한국어 원문(`questions`/`persona` 등)은 **한 글자도 안 바꿈** — selftest `userVerbatim` 가드 + e2e(ko) 안전.
|
|
25
|
+
- **lensCmd 영어 렌더**: `--language en` 시 헤더/부제/페르소나/질문/↔인과/푸터/unknown 에러 모두 영어. 프로젝트 커스텀 렌즈(.harness/quality-lenses.json)는 영어 필드가 없으면 작성된 텍스트로 graceful fallback, builtin 도메인에 추가한 커스텀 질문은 `questionsEn` 개수 기준으로 분리해 영어 렌더에 append.
|
|
26
|
+
- **한국어 기본 유지**: 영어는 명시 opt-in. 플래그 없으면 한국어 그대로(e2e 무회귀).
|
|
27
|
+
|
|
28
|
+
### 잔여 (UR-0010 Phase 9+, 백로그)
|
|
29
|
+
- 진단/정보 명령 본문(health/capabilities/commands/doctor/drift check/install-safety/constraints) + 메모리 CRUD 빈상태 메시지 + handoff 본문 + init starter 데이터 — en-leak 스캔 우선순위순 단계적 확대.
|
|
30
|
+
|
|
31
|
+
### 검증 (회귀 0)
|
|
32
|
+
- **selftest 243→244** (lens 영어 병렬필드 + ko verbatim + 렌더 영어 분기 소스가드) · 행위(en-leak 재스캔: `lens --language en` 한글 0 / ko 29줄 보존 / unknown 에러 en·ko) · **E2E 365/365**.
|
|
33
|
+
- patch(1.24.2) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
34
|
+
|
|
35
|
+
## 1.24.1 — 2026-06-15 — 정직성 수정: session close 보고 본문 잔여 한국어 영어화 (UR-0010)
|
|
36
|
+
|
|
37
|
+
**🔎 자가 검증으로 발견한 과장 주장 교정.** 게시된 모든 영어 표면을 `--language en` 으로 직접 실행해 한국어(가-힣) 누출을 스캔(맹신 X — 내 'CLOSED' 주장 재실증)한 결과: help/status/group help 는 깨끗했지만, **session close 보고 본문**은 1.23.0 에서 "완전 영어"로 배포했음에도 일부 한국어가 남아 있었습니다. 그 잔여를 영어화.
|
|
38
|
+
|
|
39
|
+
### 변경 (UR-0010)
|
|
40
|
+
- **session close 보고 본문 영어화**: 빈 섹션 표시 `- 없음`→`- none`(rowsToList, 헤더는 이미 영어라 정합↑), 진행 요약 한 줄 `완료 N/M · 결정 N건 누적`→`done N/M · decisions N accumulated`(`_retroOneLine` 에 선택적 lang), roadmap 자동 갱신 로그 `자동 갱신`→`auto-updated`(`_autoRoadmap`, `_uiLang(root)` 기반).
|
|
41
|
+
- **한국어 기본 불변**: 모든 변경은 en 분기에만. ko 는 한 글자도 안 바뀜(e2e 무회귀). `_retroOneLine` 의 기존 호출부(retro 명령)는 lang 미전달 → ko 유지.
|
|
42
|
+
- **검증 방법 공개**: en-leak 스캔(Node `[가-힣]` 탐지 — grep `\x{}` 빌드 한계 우회)으로 재실증. 남은 2줄은 seeded T-0001 + task-add 기본 next-action 값(데이터, Phase 8).
|
|
43
|
+
|
|
44
|
+
### 잔여 (UR-0010 Phase 8+, 백로그)
|
|
45
|
+
- handoff 본문 + 메모리 CRUD/진단 명령 본문(task/decision/audit/gate/scan 사람용 메시지) + init starter 콘텐츠/task-add 기본값 — 단계적 확대.
|
|
46
|
+
|
|
47
|
+
### 검증 (회귀 0)
|
|
48
|
+
- **selftest 242→243** (보고 본문 영어/한국어 보존 소스가드) · 행위(en fresh: `- none / done 0/1 · decisions 0 accumulated / roadmap.html auto-updated`, ko fresh: `- 없음 / 완료 0/1 · 결정 0건 누적 / 자동 갱신`) · **E2E 365/365**.
|
|
49
|
+
- patch(1.24.1) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
50
|
+
|
|
3
51
|
## 1.24.0 — 2026-06-15 — 🛡️ [안정화/Stable] help 표면 전체 영어화 안정 minor
|
|
4
52
|
|
|
5
53
|
**🛡️ 안정화(Stable) minor — `leerness --help` 와 모든 도움말 표면을 영어로 공개.** 직전 minor(1.23.0) 이후 누적된 패치 2건(1.23.1 Phase 6 + 1.23.2 Phase 7)을 검증·통합해 npm 배포. R-0011 정책의 15번째 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.25.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.25.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.24.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.25.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.25.0: 2026-06-15
|
|
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.25.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') 시 호스트 프로세스 오염.
|
|
@@ -3782,6 +3782,26 @@ function _selfTestCases() {
|
|
|
3782
3782
|
const koUsagePreserved = bin.includes('rule add "<텍스트>" --trigger <트리거>'); // ko 맵 불변
|
|
3783
3783
|
return en && koPreserved && groupUsageEn && koUsagePreserved;
|
|
3784
3784
|
} },
|
|
3785
|
+
{ name: '영어화 정직성 (1.24.1, UR-0010): session close 보고 본문(없음/retro/roadmap) 영어/한국어 보존 (소스 가드)', run: () => {
|
|
3786
|
+
const bin = read(__filename);
|
|
3787
|
+
const sc = read(path.join(path.dirname(__filename), '..', 'lib', 'session-close.js'));
|
|
3788
|
+
const rowsEn = sc.includes("t('- 없음', '- none')") && sc.includes('_retroOneLine(agg, uiLang)');
|
|
3789
|
+
const retroEn = bin.includes('function _retroOneLine(agg, lang)') && bin.includes('`done ${done}/${total}') && bin.includes('decisions ${agg.decisionBlocks} accumulated');
|
|
3790
|
+
const roadmapEn = bin.includes('roadmap.html auto-updated (${trigger})');
|
|
3791
|
+
const koPreserved = bin.includes('완료 ${done}/${total}') && bin.includes('roadmap.html 자동 갱신 (${trigger})') && sc.includes("t('- 없음', '- none')"); // ko 인자 보존
|
|
3792
|
+
return rowsEn && retroEn && roadmapEn && koPreserved;
|
|
3793
|
+
} },
|
|
3794
|
+
{ name: 'CLI 영어화 Phase 8 (1.24.2, UR-0010): lens 영어 병렬필드 + 렌더 영어/한국어 보존 (소스 가드)', run: () => {
|
|
3795
|
+
// 카탈로그 영어 병렬필드 + ko verbatim 동시 보존 + 렌더 영어 분기
|
|
3796
|
+
const enFields = LENS_CATALOG.code.questionsEn && LENS_CATALOG.code.questionsEn.length === LENS_CATALOG.code.questions.length
|
|
3797
|
+
&& LENS_CATALOG.code.questionsEn.some(q => q.includes('senior engineer') && q.includes('complex'))
|
|
3798
|
+
&& LENS_CATALOG.design.personaEn.includes('senior designer') && LENS_CATALOG.docs.questionsEn.some(q => q.includes('30 seconds'));
|
|
3799
|
+
const koVerbatim = LENS_CATALOG.code.questions.some(q => q.includes('선임 개발자') && q.includes('복잡'))
|
|
3800
|
+
&& LENS_CATALOG.docs.questions.some(q => q.includes('30초')); // ko 원문 유지(e2e/userVerbatim)
|
|
3801
|
+
const bin = read(__filename);
|
|
3802
|
+
const renderEn = bin.includes('quality self-question lenses (v${VERSION})') && bin.includes("t('페르소나', 'persona')");
|
|
3803
|
+
return enFields && koVerbatim && renderEn;
|
|
3804
|
+
} },
|
|
3785
3805
|
{ name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
|
|
3786
3806
|
];
|
|
3787
3807
|
}
|
|
@@ -4313,51 +4333,89 @@ function pulseCmd(root) {
|
|
|
4313
4333
|
// 1.18.3 (UR-0003 사용자 명시): 분야별 자기질문 품질 렌즈 — AI 가 완료 선언 전 스스로 답해보는 질문 + 분야간 인과관계.
|
|
4314
4334
|
// "선임 개발자가 내 코드를 보고 복잡하다고 느끼지 않을까?" / "선임 디자이너와 일반 사용자가 봤을 때 이쁘고 직관적인가?" (사용자 원문).
|
|
4315
4335
|
// 질문에 "그렇다(통과)"라고 답할 수 없으면 아직 완료가 아님. affects = 이 분야를 바꿨을 때 다시 물어야 할 분야(인과관계).
|
|
4336
|
+
// 1.24.2 (UR-0010 Phase 8): 각 도메인에 영어 병렬 필드(titleEn/personaEn/questionsEn/affectsNoteEn) 추가.
|
|
4337
|
+
// 한국어(title/persona/questions/affectsNote)는 verbatim 유지 — selftest userVerbatim 가드 + e2e(ko) 무회귀.
|
|
4338
|
+
// questionsEn 개수는 builtin questions 와 동일하게 유지(렌더가 커스텀 추가질문을 length 기준으로 분리·append).
|
|
4316
4339
|
const LENS_CATALOG = {
|
|
4317
4340
|
code: {
|
|
4318
4341
|
title: '코드', persona: '선임 개발자',
|
|
4342
|
+
titleEn: 'code quality', personaEn: 'senior engineer',
|
|
4319
4343
|
questions: [
|
|
4320
4344
|
'선임 개발자가 이 코드를 보고 "복잡하다"고 느끼지 않을까? — 가볍고 단순해야 함',
|
|
4321
4345
|
'더 단순한 방법이 있는데 추상화/패턴/옵션을 추가하고 있지 않은가?',
|
|
4322
4346
|
'처음 보는 사람이 5분 안에 이 변경을 이해할 수 있는가?'
|
|
4323
4347
|
],
|
|
4324
|
-
|
|
4348
|
+
questionsEn: [
|
|
4349
|
+
'Would a senior engineer call this code "complex"? — it should be light and simple',
|
|
4350
|
+
'Are you adding abstraction/patterns/options when a simpler way exists?',
|
|
4351
|
+
'Can a newcomer understand this change in 5 minutes?'
|
|
4352
|
+
],
|
|
4353
|
+
affects: ['test', 'docs', 'design'], affectsNote: 'UI 를 만지는 코드 변경이면 design 질문 재확인 필수',
|
|
4354
|
+
affectsNoteEn: 'if the change touches UI, re-check the design questions'
|
|
4325
4355
|
},
|
|
4326
4356
|
design: {
|
|
4327
4357
|
title: '디자인/UX', persona: '선임 디자이너 + 일반 사용자',
|
|
4358
|
+
titleEn: 'design / UX', personaEn: 'senior designer + everyday user',
|
|
4328
4359
|
questions: [
|
|
4329
4360
|
'선임 디자이너가 봤을 때 이쁘고 일관적인가?',
|
|
4330
4361
|
'일반 사용자가 처음 봤을 때 편하고 직관적이며 헷갈리지 않는가?',
|
|
4331
4362
|
'꾸미기 위해 복잡해지고 있지 않은가? — 단순함이 곧 직관'
|
|
4332
4363
|
],
|
|
4333
|
-
|
|
4364
|
+
questionsEn: [
|
|
4365
|
+
'Would a senior designer find it pretty and consistent?',
|
|
4366
|
+
'Is it comfortable, intuitive, and unconfusing for a first-time everyday user?',
|
|
4367
|
+
'Are you adding complexity just to decorate? — simplicity is intuition'
|
|
4368
|
+
],
|
|
4369
|
+
affects: ['code', 'docs'], affectsNote: '디자인 단순화는 보통 코드도 단순하게 만든다 (역도 성립)',
|
|
4370
|
+
affectsNoteEn: 'simplifying design usually simplifies the code too (and vice versa)'
|
|
4334
4371
|
},
|
|
4335
4372
|
docs: {
|
|
4336
4373
|
title: '문서/README', persona: '처음 온 사용자 (비개발자 포함)',
|
|
4374
|
+
titleEn: 'docs / README', personaEn: 'first-time user (incl. non-developers)',
|
|
4337
4375
|
questions: [
|
|
4338
4376
|
'그래서 30초 안에 뭘 해보면 되지?',
|
|
4339
4377
|
'비개발자가 터미널 명령 하나 없이 어떻게 사용하지?',
|
|
4340
4378
|
'기존 도구가 이미 있는데 이걸 쓸 이유가 뭐지?'
|
|
4341
4379
|
],
|
|
4342
|
-
|
|
4380
|
+
questionsEn: [
|
|
4381
|
+
'So, what can I actually try in 30 seconds?',
|
|
4382
|
+
'How does a non-developer use this without a single terminal command?',
|
|
4383
|
+
'Tools already exist — why use this one?'
|
|
4384
|
+
],
|
|
4385
|
+
affects: ['design'], affectsNote: '문서가 어렵다면 보통 제품 흐름(UX) 자체가 어렵다는 신호',
|
|
4386
|
+
affectsNoteEn: 'hard docs usually signal the product flow (UX) itself is hard'
|
|
4343
4387
|
},
|
|
4344
4388
|
test: {
|
|
4345
4389
|
title: '테스트', persona: '검증자',
|
|
4390
|
+
titleEn: 'tests', personaEn: 'verifier',
|
|
4346
4391
|
questions: [
|
|
4347
4392
|
'이 테스트는 실패할 수 있는 테스트인가? (assert(true) 아님)',
|
|
4348
4393
|
'주장한 테스트 개수/통과가 실측과 일치하는가?',
|
|
4349
4394
|
'테스트가 구현을 실제로 import/호출하는가?'
|
|
4350
4395
|
],
|
|
4351
|
-
|
|
4396
|
+
questionsEn: [
|
|
4397
|
+
'Can this test actually fail? (not assert(true))',
|
|
4398
|
+
'Do the claimed test count/pass match the real measured numbers?',
|
|
4399
|
+
'Does the test actually import/call the implementation?'
|
|
4400
|
+
],
|
|
4401
|
+
affects: ['code'], affectsNote: '테스트하기 어렵다면 코드가 복잡하다는 신호 — code 질문으로 돌아갈 것',
|
|
4402
|
+
affectsNoteEn: 'hard-to-test signals complex code — go back to the code questions'
|
|
4352
4403
|
},
|
|
4353
4404
|
security: {
|
|
4354
4405
|
title: '보안', persona: '공격자',
|
|
4406
|
+
titleEn: 'security', personaEn: 'attacker',
|
|
4355
4407
|
questions: [
|
|
4356
4408
|
'시크릿이 코드/커밋에 들어가지 않았는가?',
|
|
4357
4409
|
'이 입력을 악의적으로 주면 어떻게 되는가?',
|
|
4358
4410
|
'권한/경계를 한 단어 비틀기로 우회할 수 있는가?'
|
|
4359
4411
|
],
|
|
4360
|
-
|
|
4412
|
+
questionsEn: [
|
|
4413
|
+
'Are there no secrets in the code/commits?',
|
|
4414
|
+
'What happens if this input is given maliciously?',
|
|
4415
|
+
'Can a one-word twist bypass a permission/boundary?'
|
|
4416
|
+
],
|
|
4417
|
+
affects: ['code', 'test'], affectsNote: '보안 가드를 넣었다면 우회/오탐 테스트가 따라와야 함',
|
|
4418
|
+
affectsNoteEn: 'if you added a security guard, bypass/false-positive tests should follow'
|
|
4361
4419
|
}
|
|
4362
4420
|
};
|
|
4363
4421
|
// 1.19.3 (UR-0003 렌즈 완전판 v3): 프로젝트별 커스텀 렌즈 — .harness/quality-lenses.json 읽기-병합(쓰기 명령 없음, AI/사용자가 편집).
|
|
@@ -4410,24 +4468,32 @@ function lensCmd(domain, opts = {}) {
|
|
|
4410
4468
|
if (domain != null) domain = String(domain).trim().toLowerCase();
|
|
4411
4469
|
// 1.19.3: 내장 + 프로젝트 커스텀(.harness/quality-lenses.json) 병합 catalog.
|
|
4412
4470
|
const root = opts.root || arg('--path', process.cwd());
|
|
4471
|
+
const L = _uiLang(root); const t = (ko, en) => (L === 'en' ? en : ko); // 1.24.2 (UR-0010 Phase 8): lens 영어 opt-in
|
|
4413
4472
|
const catalog = _effectiveLensCatalog(root);
|
|
4414
4473
|
if (domain && !catalog[domain]) {
|
|
4415
|
-
return fail(`알 수 없는 렌즈: ${domain} — 유효값: ${Object.keys(catalog).join(', ')}`);
|
|
4474
|
+
return fail(t(`알 수 없는 렌즈: ${domain} — 유효값: ${Object.keys(catalog).join(', ')}`, `unknown lens: ${domain} — valid: ${Object.keys(catalog).join(', ')}`));
|
|
4416
4475
|
}
|
|
4417
4476
|
const picked = domain ? { [domain]: catalog[domain] } : catalog;
|
|
4418
4477
|
if (jsonMode) { log(JSON.stringify({ ok: true, lenses: picked }, null, 2)); return; }
|
|
4419
4478
|
const hasCustom = Object.values(catalog).some(l => l && (l._custom || l._customAdded));
|
|
4420
|
-
log(`# leerness lens — 분야별 자기질문 품질 렌즈 (v${VERSION})${hasCustom ? ' + 프로젝트 커스텀(.harness/quality-lenses.json)' : ''}`);
|
|
4421
|
-
log(`완료 선언 전 해당 분야 질문에 스스로 답해보세요. "그렇다(통과)"라고 답할 수 없으면 아직 완료가
|
|
4479
|
+
log(t(`# leerness lens — 분야별 자기질문 품질 렌즈 (v${VERSION})${hasCustom ? ' + 프로젝트 커스텀(.harness/quality-lenses.json)' : ''}`, `# leerness lens — quality self-question lenses (v${VERSION})${hasCustom ? ' + project custom (.harness/quality-lenses.json)' : ''}`));
|
|
4480
|
+
log(t(`완료 선언 전 해당 분야 질문에 스스로 답해보세요. "그렇다(통과)"라고 답할 수 없으면 아직 완료가 아닙니다.`, `Before declaring done, answer each domain's questions yourself. If you can't answer "yes (pass)", it's not done yet.`));
|
|
4422
4481
|
for (const [key, l] of Object.entries(picked)) {
|
|
4423
4482
|
log('');
|
|
4424
|
-
|
|
4425
|
-
l.
|
|
4426
|
-
|
|
4483
|
+
const title = (L === 'en' && l.titleEn) ? l.titleEn : l.title;
|
|
4484
|
+
const persona = (L === 'en' && l.personaEn) ? l.personaEn : l.persona;
|
|
4485
|
+
const note = (L === 'en' && l.affectsNoteEn) ? l.affectsNoteEn : l.affectsNote;
|
|
4486
|
+
const cflag = l._custom ? t(' [프로젝트]', ' [project]') : (l._customAdded ? t(' [+프로젝트 질문]', ' [+project questions]') : '');
|
|
4487
|
+
// en: builtin 영어 질문 + (커스텀 추가질문은 questions 의 builtin 개수 이후 — questionsEn 과 동일 개수 기준으로 분리)
|
|
4488
|
+
let qs = l.questions;
|
|
4489
|
+
if (L === 'en' && l.questionsEn) qs = l.questions.length > l.questionsEn.length ? [...l.questionsEn, ...l.questions.slice(l.questionsEn.length)] : l.questionsEn;
|
|
4490
|
+
log(`## ${key} (${title}) — ${t('페르소나', 'persona')}: ${persona}${cflag}`);
|
|
4491
|
+
qs.forEach((q, i) => log(` ${i + 1}. ${q}`));
|
|
4492
|
+
log(t(` ↔ 인과: ${key} 를 바꾸면 → ${(l.affects || []).join(', ') || '(없음)'} 질문도 다시 — ${note}`, ` ↔ causality: change ${key} → re-check ${(l.affects || []).join(', ') || '(none)'} too — ${note}`));
|
|
4427
4493
|
}
|
|
4428
4494
|
log('');
|
|
4429
|
-
log(`사용: leerness lens <${Object.keys(catalog).join('|')}> · 완료 검증과 함께: leerness verify-claim T-XXXX`);
|
|
4430
|
-
if (!hasCustom) log(`프로젝트 커스텀 렌즈: .harness/quality-lenses.json 에 { "domains": { "code": { "questions": ["..."] } } }
|
|
4495
|
+
log(t(`사용: leerness lens <${Object.keys(catalog).join('|')}> · 완료 검증과 함께: leerness verify-claim T-XXXX`, `Usage: leerness lens <${Object.keys(catalog).join('|')}> · with completion check: leerness verify-claim T-XXXX`));
|
|
4496
|
+
if (!hasCustom) log(t(`프로젝트 커스텀 렌즈: .harness/quality-lenses.json 에 { "domains": { "code": { "questions": ["..."] } } } 추가`, `Project custom lenses: add { "domains": { "code": { "questions": ["..."] } } } to .harness/quality-lenses.json`));
|
|
4431
4497
|
}
|
|
4432
4498
|
|
|
4433
4499
|
function commandsCmd(root) {
|
|
@@ -12371,13 +12437,15 @@ function _retroAggregate(root) {
|
|
|
12371
12437
|
};
|
|
12372
12438
|
}
|
|
12373
12439
|
|
|
12374
|
-
function _retroOneLine(agg) {
|
|
12440
|
+
function _retroOneLine(agg, lang) {
|
|
12441
|
+
// 1.24.1 (UR-0010): 선택적 lang — en 시 한 줄 요약 영어. 미지정 시 ko(기존 호출부 무영향).
|
|
12442
|
+
const t = (ko, en) => (lang === 'en' ? en : ko);
|
|
12375
12443
|
const parts = [];
|
|
12376
12444
|
const done = agg.statusCounts.done;
|
|
12377
12445
|
const total = agg.totalTasks;
|
|
12378
|
-
if (total) parts.push(`완료 ${done}/${total} (${Math.round(done / total * 100)}%)`);
|
|
12379
|
-
if (agg.totalSkillUsage) parts.push(`스킬 ${agg.skillUsage.length}종 / 사용 ${agg.totalSkillUsage}회 / 최적화 ${agg.totalOptimizations}
|
|
12380
|
-
if (agg.activeRules) parts.push(`룰 ${agg.activeRules}건 활성 (${agg.verifiedRules} 검증됨)`);
|
|
12446
|
+
if (total) parts.push(t(`완료 ${done}/${total} (${Math.round(done / total * 100)}%)`, `done ${done}/${total} (${Math.round(done / total * 100)}%)`));
|
|
12447
|
+
if (agg.totalSkillUsage) parts.push(t(`스킬 ${agg.skillUsage.length}종 / 사용 ${agg.totalSkillUsage}회 / 최적화 ${agg.totalOptimizations}건`, `skills ${agg.skillUsage.length} / uses ${agg.totalSkillUsage} / optimizations ${agg.totalOptimizations}`));
|
|
12448
|
+
if (agg.activeRules) parts.push(t(`룰 ${agg.activeRules}건 활성 (${agg.verifiedRules} 검증됨)`, `rules ${agg.activeRules} active (${agg.verifiedRules} verified)`));
|
|
12381
12449
|
if (agg.durations.length >= 4) {
|
|
12382
12450
|
const mid = Math.floor(agg.durations.length / 2);
|
|
12383
12451
|
const a = agg.durations.slice(0, mid).reduce((x, y) => x + y, 0) / mid;
|
|
@@ -12385,10 +12453,10 @@ function _retroOneLine(agg) {
|
|
|
12385
12453
|
if (a > 0) {
|
|
12386
12454
|
const delta = ((b - a) / a) * 100;
|
|
12387
12455
|
const sign = delta > 0 ? '+' : '';
|
|
12388
|
-
parts.push(`검증 ${Math.round(a)}ms→${Math.round(b)}ms (${sign}${delta.toFixed(1)}%)`);
|
|
12456
|
+
parts.push(t(`검증 ${Math.round(a)}ms→${Math.round(b)}ms (${sign}${delta.toFixed(1)}%)`, `verify ${Math.round(a)}ms→${Math.round(b)}ms (${sign}${delta.toFixed(1)}%)`));
|
|
12389
12457
|
}
|
|
12390
12458
|
}
|
|
12391
|
-
parts.push(`결정 ${agg.decisionBlocks}건
|
|
12459
|
+
parts.push(t(`결정 ${agg.decisionBlocks}건 누적`, `decisions ${agg.decisionBlocks} accumulated`));
|
|
12392
12460
|
return parts.join(' · ');
|
|
12393
12461
|
}
|
|
12394
12462
|
|
|
@@ -13350,10 +13418,11 @@ function _autoRoadmap(root, trigger) {
|
|
|
13350
13418
|
const outFile = path.resolve(cfg.outFile || path.join(root, 'roadmap.html'));
|
|
13351
13419
|
const data = _roadmapData(root);
|
|
13352
13420
|
writeUtf8(outFile, _roadmapHTML(data));
|
|
13353
|
-
|
|
13421
|
+
const _en = _uiLang(root) === 'en'; // 1.24.1 (UR-0010): roadmap 로그 en
|
|
13422
|
+
log(_en ? `✓ roadmap.html auto-updated (${trigger}) — ${rel(root, outFile)}` : `✓ roadmap.html 자동 갱신 (${trigger}) — ${rel(root, outFile)}`);
|
|
13354
13423
|
return true;
|
|
13355
13424
|
} catch (e) {
|
|
13356
|
-
warn('roadmap 자동 갱신 실패: ' + (e && e.message ? e.message : e));
|
|
13425
|
+
warn((_uiLang(root) === 'en' ? 'roadmap auto-update failed: ' : 'roadmap 자동 갱신 실패: ') + (e && e.message ? e.message : e));
|
|
13357
13426
|
return false;
|
|
13358
13427
|
}
|
|
13359
13428
|
}
|
package/lib/session-close.js
CHANGED
|
@@ -54,7 +54,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
54
54
|
if (_closeSecrets) log(t(` 🚨 마감 보안: 커밋 대상 시크릿 ${_closeSecrets}건 미해소 — clean 아님, leerness scan secrets 확인 후 마감 권장`, ` 🚨 close security: ${_closeSecrets} committed secret(s) unresolved — not clean, run leerness scan secrets before closing`));
|
|
55
55
|
|
|
56
56
|
function rowsToList(arr) {
|
|
57
|
-
if (!arr || !arr.length) return '- 없음';
|
|
57
|
+
if (!arr || !arr.length) return t('- 없음', '- none'); // 1.24.1 (UR-0010): en 보고 본문 정합(헤더는 이미 영어)
|
|
58
58
|
return arr.map(r => `- ${r.id} ${r.request} → next: ${r.nextAction}`).join('\n');
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -215,7 +215,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
215
215
|
writeSessionCounter(root, sc);
|
|
216
216
|
const agg = _retroAggregate(root);
|
|
217
217
|
log(t(`\n## 📈 진행 요약 (session #${sc.count})`, `\n## 📈 Progress summary (session #${sc.count})`));
|
|
218
|
-
log(` ${_retroOneLine(agg)}`);
|
|
218
|
+
log(` ${_retroOneLine(agg, uiLang)}`); // 1.24.1 (UR-0010): 진행 요약 한 줄 en
|
|
219
219
|
// 1.9.132: archive 활동 1줄 요약 — 마감 시점에 DELETE 활동 가시화 (handoff 7번째 회수와 symmetric)
|
|
220
220
|
try {
|
|
221
221
|
const hdSC = path.join(root, '.harness');
|