leerness 1.22.0 → 1.24.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 +99 -0
- package/README.md +4 -4
- package/bin/leerness.js +177 -36
- package/lib/session-close.js +48 -46
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,104 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.24.0 — 2026-06-15 — 🛡️ [안정화/Stable] help 표면 전체 영어화 안정 minor
|
|
4
|
+
|
|
5
|
+
**🛡️ 안정화(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. 이제 영어 사용자가 **메인 도움말 → 명령군 그룹 도움말 → 사용법 힌트**까지 막힘없이 읽을 수 있습니다. 한국어 우선 기본은 그대로.
|
|
6
|
+
|
|
7
|
+
### 이번 minor 통합 (1.23.1~1.23.2)
|
|
8
|
+
- **🌐 메인 help 영어 큐레이트판 (Phase 6)**: `--language en` 시 8개 카테고리(Setup·Diagnostics·Verification·Security·Handoff·Memory·Skills·Agents·Reuse·Release·More)로 정리된 영어 도움말. 레거시 버전태그 군더더기를 빼 영어 사용자가 읽기 쉬움. status 잔여(경로 없음/healthyMeaning) + subcommand_required 에러도 영어화.
|
|
9
|
+
- **🌐 그룹 help + 사용법 힌트 영어화 (Phase 7)**: requests/constraints/wakeup-interval/idempotency/intent 의 bare-command 도움말 + `_GROUP_USAGE` 자리표시자(`<text>`/`<trigger>`/`<key>`/`<name>`, 병렬 영어맵).
|
|
10
|
+
- **한국어 우선 기본 보존**: 영어는 명시 opt-in(`--language en`/`LEERNESS_LANG=en`/en init 프로젝트). 플래그 없으면 한국어 — 한국어 help/맵은 한 글자도 안 바뀜(e2e 무회귀로 검증).
|
|
11
|
+
|
|
12
|
+
### 잔여 (UR-0010 Phase 8+, 백로그)
|
|
13
|
+
- 메모리 CRUD/진단 명령 본문 출력(task/decision/audit/gate/scan 등 사람용 메시지) + session-handoff.md 본문 — 단계적 확대.
|
|
14
|
+
|
|
15
|
+
### 검증 (회귀 0)
|
|
16
|
+
- **selftest 242/242** (Phase 6·7 영어/한국어 보존 소스가드 포함) · 행위(en: `SETUP & UPDATE / 5 group headers / <key>`, ko 기본: `Usage: / 한국어 그룹 헤더 / <키>`) · **E2E 365/365**.
|
|
17
|
+
- minor(1.24.0) — npm 배포(R-0011 stable) + annotated tag(Stable) + GitHub release(latest) + 게시본 클린룸 재실증.
|
|
18
|
+
|
|
19
|
+
## 1.23.2 — 2026-06-15 — CLI 영어화 Phase 7: group help 5종 + _GROUP_USAGE 자리표시자 영어화 (UR-0010)
|
|
20
|
+
|
|
21
|
+
**🌐 도움말 표면 패밀리 완성.** Phase 6(메인 `--help`)에 이어, 명령군을 하위명령 없이 부를 때 나오는 **그룹 도움말**과 **사용법 힌트의 자리표시자**까지 영어화 — 메인 help + group help + usage hint 가 모두 언어 선택을 따른다.
|
|
22
|
+
|
|
23
|
+
### 변경 (UR-0010 Phase 7)
|
|
24
|
+
- **group help 5종 영어화**: `requests` / `constraints` / `wakeup-interval` / `idempotency` / `intent` 를 하위명령 없이(또는 `help`) 부를 때의 도움말을 `_t(ko,en)` 분기.
|
|
25
|
+
- **_GROUP_USAGE 자리표시자 영어화**: `<텍스트>`→`<text>`, `<트리거>`→`<trigger>`, `<키>`→`<key>`, `<이름>`→`<name>` — `_GROUP_USAGE_EN` 병렬맵으로(한국어 맵은 한 글자도 안 바꿔 e2e 안전), subcommand_required 에러가 언어별 정확한 사용법 표시.
|
|
26
|
+
- **한국어 기본 유지**: 영어는 명시 opt-in. 플래그 없으면 기존 한국어 그대로(e2e 무회귀).
|
|
27
|
+
|
|
28
|
+
### 잔여 (UR-0010 Phase 8+, 백로그)
|
|
29
|
+
- 메모리 CRUD/진단 명령 본문 출력(task/decision/audit/gate/scan 등 사람용 메시지) + session-handoff.md 본문 — 단계적 확대.
|
|
30
|
+
|
|
31
|
+
### 검증 (회귀 0)
|
|
32
|
+
- **selftest 241→242** (group help 5종 영어+한국어 보존, _GROUP_USAGE_EN 존재 + ko 맵 불변 소스가드) · 행위(en: 5종 영어 헤더 + `<key>`/`<text>`, ko 기본: 5종 한국어 헤더 + `<키>`/`<텍스트>`) · **E2E 365/365**.
|
|
33
|
+
- patch(1.23.2) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
34
|
+
|
|
35
|
+
## 1.23.1 — 2026-06-15 — CLI 영어화 Phase 6: help(영어 큐레이트판) + status/subcommand 에러 영어화 (UR-0010)
|
|
36
|
+
|
|
37
|
+
**🌐 `leerness --help` 와 흔한 에러를 영어로.** 영어 사용자가 가장 먼저 보는 도움말을 — 레거시 버전태그를 줄별로 번역하는 대신 — **카테고리별로 정리한 별도 영어 도움말**로 제공. 한국어 도움말은 그대로 둬서 한국어 기본 경로는 한 글자도 안 바뀜.
|
|
38
|
+
|
|
39
|
+
### 변경 (UR-0010 Phase 6)
|
|
40
|
+
- **help 영어 큐레이트판 (`_helpEn`)**: `--language en`/`LEERNESS_LANG=en` 시 8개 카테고리(Setup·Diagnostics·Verification·Security·Handoff·Memory·Skills·Agents·Reuse·Release·More)로 정리된 영어 도움말. 전체 전수 목록은 `leerness commands` 안내(드리프트 방지).
|
|
41
|
+
- **status 잔여 영어화**: 경로 없음 에러(`path not found`), `--json` 의 `healthyMeaning`(`install-file presence only …`).
|
|
42
|
+
- **subcommand_required 에러 영어화**: 명령군(rule/skill/feature/memory)을 하위명령 없이 부를 때의 `subcommand required — usage: …`.
|
|
43
|
+
- **한국어 기본 유지**: 영어는 명시 opt-in. 플래그 없으면 기존 한국어 도움말/에러 그대로(e2e 무회귀).
|
|
44
|
+
|
|
45
|
+
### 잔여 (UR-0010 Phase 7+, 백로그)
|
|
46
|
+
- `_GROUP_USAGE` 내부 자리표시자(`<텍스트>`/`<트리거>`) + 명령별 하위 help 블록(group help) + session-handoff.md 본문 — 단계적 확대.
|
|
47
|
+
|
|
48
|
+
### 검증 (회귀 0)
|
|
49
|
+
- **selftest 240→241** (help 영어판 존재+핵심 카테고리 포함, ko help 분기 보존, status/subcommand 영어/한국어 소스가드) · 행위(en: `SETUP & UPDATE / path not found / subcommand required`, ko 기본: `Usage: / 경로 없음 / 하위명령 필요`) · **E2E 365/365**.
|
|
50
|
+
- patch(1.23.1) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
51
|
+
|
|
52
|
+
## 1.23.0 — 2026-06-15 — 🛡️ [안정화/Stable] session close 영어 완전화 안정 minor
|
|
53
|
+
|
|
54
|
+
**🛡️ 안정화(Stable) minor — 세션 마감 화면 전체를 영어로 공개.** 직전 minor(1.22.0) 이후 누적된 패치 2건(1.22.1 Phase 4 + 1.22.2 Phase 5)을 검증·통합해 npm 배포. R-0011 정책의 14번째 stable minor. 이로써 **핵심 세션 라이프사이클 — 설치(init) → 시작(handoff) → 검증(verify-claim) → 마감(session close) — 전체가 영어 opt-in 으로 일관**됩니다. 한국어 우선 기본은 그대로.
|
|
55
|
+
|
|
56
|
+
### 이번 minor 통합 (1.22.1~1.22.2)
|
|
57
|
+
- **🌐 session close 마감 보고 영어화 (Phase 4)**: 항상-표시되는 마감 라인 — 완료 정직성/마감 보안 advisory, `활성 룰 없음`→`no active rules`, Required final response sections, `🔚 자동 통합 보고`→`integrated report`(사용자 요청·pre-wake·멱등성·셸 실패 포함). DI 로 `uiLang` 주입.
|
|
58
|
+
- **🌐 session close --suggest/진행요약/cleanup 영어화 (Phase 5)**: 다음 라운드 추천(skill 후보·`drift 상태`→`drift status`·`가장 많이 쓴 명령`→`Most-used commands`·MCP/skill-query 통계), `진행 요약`→`Progress summary`(archive·마일스톤·회고·워크스페이스), 운영 자동정리(release cleanup·인코딩 BOM).
|
|
59
|
+
- **가벼움 정리**: MCP 통계 줄의 `t` 헬퍼 셰도잉(`.map(([t,n])…)` → `[tool,n]`) 제거.
|
|
60
|
+
- **한국어 우선 기본 보존**: 영어는 명시 opt-in(`--language en`/`LEERNESS_LANG=en`/en init 프로젝트). 플래그 없으면 한국어 — e2e 무회귀로 검증.
|
|
61
|
+
|
|
62
|
+
### 잔여 (UR-0010 Phase 6+, 백로그)
|
|
63
|
+
- session-handoff.md / current-state.md 본문(파일에 기록되는 한국어 메모리 아티팩트) + help + status + 그 외 명령 본문 — 단계적 확대.
|
|
64
|
+
|
|
65
|
+
### 검증 (회귀 0)
|
|
66
|
+
- **selftest 240/240** (Phase 4·5 영어/한국어 보존 소스가드 포함) · 행위(en: `integrated report / Next-round suggestions / Progress summary`, ko 기본: `자동 통합 보고 / 다음 라운드 추천 / 진행 요약`) · **E2E 365/365**.
|
|
67
|
+
- minor(1.23.0) — npm 배포(R-0011 stable) + annotated tag(Stable) + GitHub release(latest) + 게시본 클린룸 재실증.
|
|
68
|
+
|
|
69
|
+
## 1.22.2 — 2026-06-15 — CLI 영어화 Phase 5: session close --suggest/진행요약/cleanup 영어화 (UR-0010)
|
|
70
|
+
|
|
71
|
+
**🌐 마감 보고의 나머지 절반까지 영어로.** Phase 4 가 "항상 표시되는" 마감 라인을 영어화했다면, Phase 5 는 **다음 라운드 추천(`--suggest`)·진행 요약·운영 자동정리** 출력을 영어 opt-in 으로 — 마감 화면 전체가 언어 선택을 따른다.
|
|
72
|
+
|
|
73
|
+
### 변경 (UR-0010 Phase 5)
|
|
74
|
+
- **`--suggest` 다음 라운드 추천 영어화**: `다음 라운드 추천`→`Next-round suggestions`, 신규 skill 후보, `drift 상태`→`drift status`, `가장 많이 쓴 명령`→`Most-used commands`, MCP 호출/드문 호출, skill match query 누적 — 전부 `t(ko,en)` 분기.
|
|
75
|
+
- **진행 요약 영어화**: `진행 요약`→`Progress summary`, archive 누적, N세션 마일스톤/자동 회고, 워크스페이스 안내, retro 요약 실패 메시지.
|
|
76
|
+
- **운영 자동정리 영어화**: release/* 정리(`--auto-cleanup-branches`), 셸 스크립트 인코딩 위험 자동 BOM(`--auto-fix-encoding`) 안내.
|
|
77
|
+
- **가벼움 정리**: MCP 통계 줄에서 `t` 헬퍼와 충돌하던 `.map(([t, n]) => …)` 지역 변수를 `tool` 로 rename — 셰도잉 제거(가독성).
|
|
78
|
+
- **한국어 기본 유지**: 영어는 `--language en`/`LEERNESS_LANG=en`/en init 프로젝트에서만. 플래그 없으면 한국어(ko 원문은 `t()` ko 인자로 보존).
|
|
79
|
+
|
|
80
|
+
### 잔여 (UR-0010 Phase 6+, 백로그)
|
|
81
|
+
- session-handoff.md / current-state.md 본문(파일에 기록되는 한국어 메모리 아티팩트) + help + status + 그 외 명령 본문 — 단계적 확대.
|
|
82
|
+
|
|
83
|
+
### 검증 (회귀 0)
|
|
84
|
+
- **selftest 239→240** (Phase 5 영어/한국어 보존 + 셰도잉 제거 소스가드) · 행위(en: `Next-round suggestions / drift status / Most-used commands / Progress summary`, ko 기본: `다음 라운드 추천 / drift 상태 / 가장 많이 쓴 명령 / 진행 요약`) · **E2E 365/365**.
|
|
85
|
+
- patch(1.22.2) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
86
|
+
|
|
87
|
+
## 1.22.1 — 2026-06-15 — CLI 영어화 Phase 4: session close 마감 보고 영어화 (UR-0010)
|
|
88
|
+
|
|
89
|
+
**🌐 세션을 마칠 때 보는 마지막 출력을 영어로.** init 배너(P1)→handoff 헤드라인(P2)→verify-claim(P3)에 이어 **session close 의 항상-표시 마감 보고**를 영어 opt-in 으로 — 핵심 세션 라이프사이클(시작→작업→검증→마감)이 영어로 일관.
|
|
90
|
+
|
|
91
|
+
### 변경 (UR-0010 Phase 4)
|
|
92
|
+
- **session close 마감 보고 영어화 (DI uiLang 주입)**: `_uiLang(root)` 를 session-close DI deps 로 주입 후 항상-표시 라인 `t(ko,en)` 분기 — 완료 정직성/마감 보안 advisory, `활성 룰 없음`→`no active rules`, Required final response sections 목록, `🔚 자동 통합 보고`→`integrated report`(사용자 요청/pre-wake/멱등성/셸 실패 결과 포함). 한국어 기본 유지(영어 명시 opt-in).
|
|
93
|
+
- **한국어 무회귀**: e2e 는 `--language` 없이 ko 로 실행 → 마감 보고 한국어 유지(검증). ko 원문은 `t()` ko 인자로 보존.
|
|
94
|
+
|
|
95
|
+
### 잔여 (UR-0010 Phase 5+, 백로그)
|
|
96
|
+
- session close `--suggest` 상세(skill 후보·drift·MCP/skill-query 통계·진행 요약) + help + status + 그 외 명령 본문 — 단계적 확대.
|
|
97
|
+
|
|
98
|
+
### 검증 (회귀 0)
|
|
99
|
+
- **selftest 238→239** (session close uiLang 주입 + 영어/한국어 보존 소스가드) · 행위(en: `integrated report / no active rules / no user requests`, ko 기본: `자동 통합 보고 / 활성 룰 없음`) · **E2E 365/365**.
|
|
100
|
+
- patch(1.22.1) — npm 미배포(R-0011, GitHub/CHANGELOG 누적).
|
|
101
|
+
|
|
3
102
|
## 1.22.0 — 2026-06-15 — 🛡️ [안정화/Stable] 확장된 영어 지원(헤드라인 + verify-claim) 안정 minor
|
|
4
103
|
|
|
5
104
|
**🛡️ 안정화(Stable) minor — 영어 CLI 커버리지를 핵심 검증 흐름까지 확장해 npm 공개.** 직전 minor(1.21.0) 이후 누적된 패치 2건(1.21.1~1.21.2)을 검증·통합해 배포. R-0011 정책의 13번째 stable minor. 영어 opt-in 표면이 첫 화면(1.21.0)에서 **handoff 헤드라인 + verify-claim 플래그십**까지 확장 — 한국어 우선 기본은 그대로.
|
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.24.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.24.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.22.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.24.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.24.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.24.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') 시 호스트 프로세스 오염.
|
|
@@ -3749,6 +3749,39 @@ function _selfTestCases() {
|
|
|
3749
3749
|
const koPreserved = src.includes('## 종합') && src.includes('구현 실체 (done 기본)'); // ko 원문이 t() ko 인자로 남아 e2e(ko) 무회귀
|
|
3750
3750
|
return en && koPreserved;
|
|
3751
3751
|
} },
|
|
3752
|
+
{ name: 'CLI 영어화 Phase 4 (1.22.1, UR-0010): session close uiLang 주입 + 마감보고 영어/한국어 보존 (소스 가드)', run: () => {
|
|
3753
|
+
const bin = read(__filename);
|
|
3754
|
+
const sc = read(path.join(path.dirname(__filename), '..', 'lib', 'session-close.js'));
|
|
3755
|
+
const injected = bin.includes('uiLang: _uiLang(root), harnessPath: __filename');
|
|
3756
|
+
const en = sc.includes('session close integrated report') && sc.includes('no active rules') && sc.includes('no user requests (UR backlog empty)');
|
|
3757
|
+
const koPreserved = sc.includes('자동 통합 보고') && sc.includes('활성 룰 없음'); // ko 원문 t() ko 인자로 보존(e2e ko 무회귀)
|
|
3758
|
+
return injected && en && koPreserved;
|
|
3759
|
+
} },
|
|
3760
|
+
{ name: 'CLI 영어화 Phase 5 (1.22.2, UR-0010): session close --suggest/진행요약/cleanup 영어/한국어 보존 (소스 가드)', run: () => {
|
|
3761
|
+
const sc = read(path.join(path.dirname(__filename), '..', 'lib', 'session-close.js'));
|
|
3762
|
+
const en = sc.includes('Next-round suggestions') && sc.includes('Progress summary (session') && sc.includes('Most-used commands') && sc.includes('encoding risk(s) auto-fixed');
|
|
3763
|
+
const koPreserved = sc.includes('다음 라운드 추천') && sc.includes('진행 요약 (session') && sc.includes('가장 많이 쓴 명령'); // ko 원문 t() ko 인자로 보존(e2e ko 무회귀)
|
|
3764
|
+
const noShadow = !sc.includes('.map(([t, n]) =>'); // t 헬퍼 셰도잉 제거 확인
|
|
3765
|
+
return en && koPreserved && noShadow;
|
|
3766
|
+
} },
|
|
3767
|
+
{ name: 'CLI 영어화 Phase 6 (1.23.1, UR-0010): help 영어 큐레이트판 + status/subcommand 영어/한국어 보존 (소스 가드)', run: () => {
|
|
3768
|
+
const bin = read(__filename);
|
|
3769
|
+
// en help 가 존재하고 핵심 명령군을 포함 + ko help 분기 보존
|
|
3770
|
+
const enHelp = bin.includes('function _helpEn()') && bin.includes("if (_uiLang(arg('--path', process.cwd())) === 'en') { _helpEn(); return; }");
|
|
3771
|
+
const enCovers = bin.includes('SETUP & UPDATE') && bin.includes('VERIFICATION (evidence-gated') && bin.includes('Full, exhaustive command list');
|
|
3772
|
+
const koPreserved = bin.includes('Leerness v${VERSION}\\n\\nUsage:'); // 한국어 help 원문 유지
|
|
3773
|
+
const statusEn = bin.includes('path not found: ${root}') && bin.includes('install-file presence only');
|
|
3774
|
+
const subEn = bin.includes('subcommand required — usage: leerness');
|
|
3775
|
+
return enHelp && enCovers && koPreserved && statusEn && subEn;
|
|
3776
|
+
} },
|
|
3777
|
+
{ name: 'CLI 영어화 Phase 7 (1.23.2, UR-0010): group help 5종 + _GROUP_USAGE_EN 영어/한국어 보존 (소스 가드)', run: () => {
|
|
3778
|
+
const bin = read(__filename);
|
|
3779
|
+
const en = bin.includes('track missing user requests') && bin.includes('pre-check platform/API constraints') && bin.includes('adaptive wakeup interval') && bin.includes('detect idempotency violations') && bin.includes('infer user intent');
|
|
3780
|
+
const koPreserved = bin.includes('사용자 요청 누락 확인 절차') && bin.includes('플랫폼/API 제약 사전 체크') && bin.includes('멱등성 위반 탐지'); // ko 원문 _t ko 인자로 보존(e2e ko 무회귀)
|
|
3781
|
+
const groupUsageEn = bin.includes('const _GROUP_USAGE_EN = {') && bin.includes('rule add "<text>" --trigger <trigger>') && bin.includes('${_GROUP_USAGE_EN[cmd]}');
|
|
3782
|
+
const koUsagePreserved = bin.includes('rule add "<텍스트>" --trigger <트리거>'); // ko 맵 불변
|
|
3783
|
+
return en && koPreserved && groupUsageEn && koUsagePreserved;
|
|
3784
|
+
} },
|
|
3752
3785
|
{ name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
|
|
3753
3786
|
];
|
|
3754
3787
|
}
|
|
@@ -5283,14 +5316,15 @@ function requestsCmd(root, sub, ...rest) {
|
|
|
5283
5316
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
5284
5317
|
|
|
5285
5318
|
if (!sub || sub === 'help' || sub === '--help') {
|
|
5286
|
-
|
|
5319
|
+
const _L = _uiLang(root); const _t = (ko, en) => _L === 'en' ? en : ko; // 1.23.2 (UR-0010 Phase 7)
|
|
5320
|
+
log(_t(`# leerness requests (1.9.207) — 사용자 요청 누락 확인 절차`, `# leerness requests — track missing user requests`));
|
|
5287
5321
|
log('');
|
|
5288
|
-
log(` audit → 누락 후보 + tracked + stale 보고 (--json 가능)`);
|
|
5289
|
-
log(` add "<text>" → 사용자 요청 수동
|
|
5290
|
-
log(` list → 전체 요청 출력 (--json 가능, --status open|completed|dropped)`);
|
|
5291
|
-
log(` complete <id> → 요청 완료 표시 (예: UR-0003)`);
|
|
5292
|
-
log(` drop <id> → 요청 드롭
|
|
5293
|
-
log(` auto-complete → "Round X.Y.Z — 구현 완료" 패턴 자동 감지 (default: dry-run, --apply 시 적용) [1.9.223]`);
|
|
5322
|
+
log(_t(` audit → 누락 후보 + tracked + stale 보고 (--json 가능)`, ` audit → report missing candidates + tracked + stale (--json)`));
|
|
5323
|
+
log(_t(` add "<text>" → 사용자 요청 수동 기록`, ` add "<text>" → manually record a user request`));
|
|
5324
|
+
log(_t(` list → 전체 요청 출력 (--json 가능, --status open|completed|dropped)`, ` list → list all requests (--json, --status open|completed|dropped)`));
|
|
5325
|
+
log(_t(` complete <id> → 요청 완료 표시 (예: UR-0003)`, ` complete <id> → mark a request completed (e.g. UR-0003)`));
|
|
5326
|
+
log(_t(` drop <id> → 요청 드롭 표시`, ` drop <id> → mark a request dropped`));
|
|
5327
|
+
log(_t(` auto-complete → "Round X.Y.Z — 구현 완료" 패턴 자동 감지 (default: dry-run, --apply 시 적용) [1.9.223]`, ` auto-complete → auto-detect "Round X.Y.Z delivered" patterns (default: dry-run, --apply to apply)`));
|
|
5294
5328
|
return;
|
|
5295
5329
|
}
|
|
5296
5330
|
|
|
@@ -5536,13 +5570,14 @@ function constraintsCmd(root, sub, ...rest) {
|
|
|
5536
5570
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
5537
5571
|
|
|
5538
5572
|
if (!sub || sub === 'help' || sub === '--help') {
|
|
5539
|
-
|
|
5573
|
+
const _L = _uiLang(root); const _t = (ko, en) => _L === 'en' ? en : ko; // 1.23.2 (UR-0010 Phase 7)
|
|
5574
|
+
log(_t(`# leerness constraints (1.9.208) — 플랫폼/API 제약 사전 체크`, `# leerness constraints — pre-check platform/API constraints`));
|
|
5540
5575
|
log('');
|
|
5541
|
-
log(` list → 등록된 모든 플랫폼 catalog 출력 (--json 가능)`);
|
|
5542
|
-
log(` check "<request>" → 사용자 요청에서 플랫폼 매칭 → 제약 보고 (--json 가능)`);
|
|
5576
|
+
log(_t(` list → 등록된 모든 플랫폼 catalog 출력 (--json 가능)`, ` list → list all registered platform catalogs (--json)`));
|
|
5577
|
+
log(_t(` check "<request>" → 사용자 요청에서 플랫폼 매칭 → 제약 보고 (--json 가능)`, ` check "<request>" → match platforms in a request → report constraints (--json)`));
|
|
5543
5578
|
log(` add <id> --constraint "kind:detail" --alias name`);
|
|
5544
5579
|
log('');
|
|
5545
|
-
log(dim(` 예: leerness constraints check "Stripe API 연동 결제 모듈"`));
|
|
5580
|
+
log(dim(_t(` 예: leerness constraints check "Stripe API 연동 결제 모듈"`, ` e.g. leerness constraints check "Stripe API payment integration"`)));
|
|
5546
5581
|
return;
|
|
5547
5582
|
}
|
|
5548
5583
|
|
|
@@ -5722,15 +5757,16 @@ function wakeupIntervalCmd(root, sub, val) {
|
|
|
5722
5757
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
5723
5758
|
|
|
5724
5759
|
if (!sub || sub === 'help' || sub === '--help') {
|
|
5725
|
-
|
|
5760
|
+
const _L = _uiLang(root); const _t = (ko, en) => _L === 'en' ? en : ko; // 1.23.2 (UR-0010 Phase 7)
|
|
5761
|
+
log(_t(`# leerness wakeup-interval (1.9.210) — adaptive wakeup 간격`, `# leerness wakeup-interval — adaptive wakeup interval`));
|
|
5726
5762
|
log('');
|
|
5727
|
-
log(` get → 현재 권장 interval + stats (--json 가능)`);
|
|
5728
|
-
log(` set <secs> → override 설정 (예: leerness wakeup-interval set 900)`);
|
|
5729
|
-
log(` auto → override 해제 + 자동 계산
|
|
5730
|
-
log(` history → 최근 fire 이력
|
|
5731
|
-
log(` record <kind> → fire 기록 (user-trigger / auto / wakeup-miss)`);
|
|
5763
|
+
log(_t(` get → 현재 권장 interval + stats (--json 가능)`, ` get → current recommended interval + stats (--json)`));
|
|
5764
|
+
log(_t(` set <secs> → override 설정 (예: leerness wakeup-interval set 900)`, ` set <secs> → set an override (e.g. leerness wakeup-interval set 900)`));
|
|
5765
|
+
log(_t(` auto → override 해제 + 자동 계산 모드`, ` auto → clear override + auto-compute mode`));
|
|
5766
|
+
log(_t(` history → 최근 fire 이력 출력`, ` history → recent fire history`));
|
|
5767
|
+
log(_t(` record <kind> → fire 기록 (user-trigger / auto / wakeup-miss)`, ` record <kind> → record a fire (user-trigger / auto / wakeup-miss)`));
|
|
5732
5768
|
log('');
|
|
5733
|
-
log(dim(` opt-out: env LEERNESS_FIXED_INTERVAL=1500 (초) 또는 set <secs>`));
|
|
5769
|
+
log(dim(_t(` opt-out: env LEERNESS_FIXED_INTERVAL=1500 (초) 또는 set <secs>`, ` opt-out: env LEERNESS_FIXED_INTERVAL=1500 (seconds) or set <secs>`)));
|
|
5734
5770
|
return;
|
|
5735
5771
|
}
|
|
5736
5772
|
|
|
@@ -6098,15 +6134,16 @@ function idempotencyCmd(root, sub) {
|
|
|
6098
6134
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
6099
6135
|
|
|
6100
6136
|
if (!sub || sub === 'help' || sub === '--help') {
|
|
6101
|
-
|
|
6137
|
+
const _L = _uiLang(root); const _t = (ko, en) => _L === 'en' ? en : ko; // 1.23.2 (UR-0010 Phase 7)
|
|
6138
|
+
log(_t(`# leerness idempotency (1.9.212) — 멱등성 위반 탐지`, `# leerness idempotency — detect idempotency violations`));
|
|
6102
6139
|
log('');
|
|
6103
|
-
log(` audit → 워크스페이스 멱등성 점검 (rules / tasks / user-requests / wakeups) (--json 가능)`);
|
|
6104
|
-
log(` audit --auto-fix → task 완전중복 행 제거 + active 동일텍스트 dropped 처리 + user-request open 중복 정리 (1.9.293)`);
|
|
6140
|
+
log(_t(` audit → 워크스페이스 멱등성 점검 (rules / tasks / user-requests / wakeups) (--json 가능)`, ` audit → check workspace idempotency (rules / tasks / user-requests / wakeups) (--json)`));
|
|
6141
|
+
log(_t(` audit --auto-fix → task 완전중복 행 제거 + active 동일텍스트 dropped 처리 + user-request open 중복 정리 (1.9.293)`, ` audit --auto-fix → remove exact-duplicate tasks + mark same-text active as dropped + dedup open user-requests`));
|
|
6105
6142
|
log('');
|
|
6106
|
-
log(dim(` dedup 적용 영역: ruleAdd / taskAdd (1.9.212) + _recordUserRequest (1.9.207) + _recordWakeup (1.9.205)`));
|
|
6107
|
-
log(dim(` --auto-fix 안전: 완전 동일 행만 제거 / 동일텍스트는 status=dropped 로 보존(id 유지) / git 회복 가능 /
|
|
6108
|
-
log(dim(` 자동화: drift check --auto-fix 가 idempotency 중복도 자동 정리 (1.9.293)`));
|
|
6109
|
-
log(dim(` opt-out: --force 플래그로 dedup 우회
|
|
6143
|
+
log(dim(_t(` dedup 적용 영역: ruleAdd / taskAdd (1.9.212) + _recordUserRequest (1.9.207) + _recordWakeup (1.9.205)`, ` dedup applies to: ruleAdd / taskAdd + _recordUserRequest + _recordWakeup`)));
|
|
6144
|
+
log(dim(_t(` --auto-fix 안전: 완전 동일 행만 제거 / 동일텍스트는 status=dropped 로 보존(id 유지) / git 회복 가능 / 멱등`, ` --auto-fix safety: removes only exact dupes / same-text kept as status=dropped (id preserved) / git-recoverable / idempotent`)));
|
|
6145
|
+
log(dim(_t(` 자동화: drift check --auto-fix 가 idempotency 중복도 자동 정리 (1.9.293)`, ` automation: drift check --auto-fix also dedups idempotency violations`)));
|
|
6146
|
+
log(dim(_t(` opt-out: --force 플래그로 dedup 우회 가능`, ` opt-out: pass --force to bypass dedup`)));
|
|
6110
6147
|
return;
|
|
6111
6148
|
}
|
|
6112
6149
|
|
|
@@ -6173,14 +6210,15 @@ function intentCmd(root, sub, ...rest) {
|
|
|
6173
6210
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
6174
6211
|
|
|
6175
6212
|
if (!sub || sub === 'help' || sub === '--help') {
|
|
6176
|
-
|
|
6213
|
+
const _L = _uiLang(root); const _t = (ko, en) => _L === 'en' ? en : ko; // 1.23.2 (UR-0010 Phase 7)
|
|
6214
|
+
log(_t(`# leerness intent (1.9.213) — 사용자 의도 파악 + scope expansion 게이트`, `# leerness intent — infer user intent + scope-expansion gate`));
|
|
6177
6215
|
log('');
|
|
6178
|
-
log(` classify "<request>" → intent 분류 (precise/broad/default) + 신호 (--json 가능)`);
|
|
6179
|
-
log(` expand "<request>" → 도메인 탐지 + 확장 후보 dry-run (--json 가능)`);
|
|
6180
|
-
log(` domains → 등록된 도메인 catalog 출력 (game/web/api/cli/data)`);
|
|
6216
|
+
log(_t(` classify "<request>" → intent 분류 (precise/broad/default) + 신호 (--json 가능)`, ` classify "<request>" → classify intent (precise/broad/default) + signals (--json)`));
|
|
6217
|
+
log(_t(` expand "<request>" → 도메인 탐지 + 확장 후보 dry-run (--json 가능)`, ` expand "<request>" → detect domain + expansion candidates (dry-run, --json)`));
|
|
6218
|
+
log(_t(` domains → 등록된 도메인 catalog 출력 (game/web/api/cli/data)`, ` domains → list registered domain catalog (game/web/api/cli/data)`));
|
|
6181
6219
|
log('');
|
|
6182
|
-
log(dim(` 3원칙: (1) Always-Off Opt-In (2) Dry-run 기본 (실행 X) (3) 명시 vs 추론 분리
|
|
6183
|
-
log(dim(` 예: leerness intent expand "맵과 캐릭터 + 기본 게임 기능 만들어줘"`));
|
|
6220
|
+
log(dim(_t(` 3원칙: (1) Always-Off Opt-In (2) Dry-run 기본 (실행 X) (3) 명시 vs 추론 분리 라벨링`, ` 3 principles: (1) always-off opt-in (2) dry-run by default (no execution) (3) explicit vs inferred labeling`)));
|
|
6221
|
+
log(dim(_t(` 예: leerness intent expand "맵과 캐릭터 + 기본 게임 기능 만들어줘"`, ` e.g. leerness intent expand "build a map + characters + basic game features"`)));
|
|
6184
6222
|
return;
|
|
6185
6223
|
}
|
|
6186
6224
|
|
|
@@ -7583,8 +7621,9 @@ function route(name) {
|
|
|
7583
7621
|
|
|
7584
7622
|
function status(root) {
|
|
7585
7623
|
root = absRoot(root);
|
|
7624
|
+
const _L = _uiLang(root); const t = (ko, en) => (_L === 'en' ? en : ko); // 1.23.1 (UR-0010 Phase 6)
|
|
7586
7625
|
// 1.9.434 (11th 외부평가 Opus P2, UR-0136): 미존재 경로는 healthy 위조 금지 — failJson + exit 1.
|
|
7587
|
-
if (!exists(root)) { failJson(has('--json'), 'path_not_found', `경로 없음: ${root}`); return; }
|
|
7626
|
+
if (!exists(root)) { failJson(has('--json'), 'path_not_found', t(`경로 없음: ${root}`, `path not found: ${root}`)); return; }
|
|
7588
7627
|
const verF = path.join(root,'.harness/HARNESS_VERSION');
|
|
7589
7628
|
const ver = exists(verF) ? read(verF).trim() : 'not installed';
|
|
7590
7629
|
const lang = exists(path.join(root,'.harness/LANGUAGE')) ? read(path.join(root,'.harness/LANGUAGE')).trim() : 'ko';
|
|
@@ -7595,7 +7634,7 @@ function status(root) {
|
|
|
7595
7634
|
const missing = files.filter(f => !exists(path.join(root,f)));
|
|
7596
7635
|
// 1.9.384 (5번째 외부평가/UR-0085): --json 일관성 — AI 에이전트용 구조화 출력.
|
|
7597
7636
|
// 1.9.418 (9th 외부평가 Codex P2): healthy 의 의미를 명시(설치 파일 존재 ≠ 프로젝트 안전). 프로젝트 안전은 gate/scan secrets 사용.
|
|
7598
|
-
if (has('--json')) { log(JSON.stringify({ version: ver, language: lang, minimal: isMinimal, scope: 'install', total: files.length, present: files.length - missing.length, missing, healthy: missing.length === 0, healthyMeaning: '설치 파일 존재 여부(프로젝트 안전 아님 — 보안/품질은 leerness gate / scan secrets 사용)' }, null, 2)); return; }
|
|
7637
|
+
if (has('--json')) { log(JSON.stringify({ version: ver, language: lang, minimal: isMinimal, scope: 'install', total: files.length, present: files.length - missing.length, missing, healthy: missing.length === 0, healthyMeaning: t('설치 파일 존재 여부(프로젝트 안전 아님 — 보안/품질은 leerness gate / scan secrets 사용)', 'install-file presence only (not project safety — use leerness gate / scan secrets for security/quality)') }, null, 2)); return; }
|
|
7599
7638
|
log(`Leerness: ${ver}${isMinimal ? ' (minimal)' : ''}`);
|
|
7600
7639
|
log(`Files: ${files.length - missing.length}/${files.length}`);
|
|
7601
7640
|
if (missing.length) missing.forEach(x => warn('missing: ' + x));
|
|
@@ -12185,7 +12224,7 @@ function llmBenchRecordCmd(root) {
|
|
|
12185
12224
|
|
|
12186
12225
|
const _sessionClose = require('../lib/session-close');
|
|
12187
12226
|
// 1.9.425 (UR-0025/UR-0125 큰 핸들러 모듈화 10번째): sessionClose → lib/session-close.js (DI 위임)
|
|
12188
|
-
function sessionClose(root, opts = {}) { return _sessionClose.sessionClose(root, opts, { VERSION, STATUSES, MARK, has, arg, harnessPath: __filename, readProgressRows, evidencePath, handoffPath, currentStatePath, taskLogPath, verifyRules, _autoRoadmap, _readUsageStats, readSessionCounter, writeSessionCounter, _retroAggregate, _retroOneLine, retroCmd, _loadDecisions, readRules, planPath, _loadLessons, _readFeatureGraph, _auditUserRequests, _detectDeliveredRequests, _computeRoundHistory, _computeMilestones, _computeRecentChanges, _collectPyFiles, _analyzePyFile, _collectRuntimeEnv, _scanShellScriptsEncoding, _listAPISkills, _matchAPISkills, _loadShellFailures, _shellEnvDrift, _runPreWakeAudit, _saveAndAppendPreWakeReport, _runIdempotencyAudit, _detectAbnormalShutdown, _updateUserRequest, _detectOptimism, _scanCodeForPatterns, _collectSecretFindings }); } // 1.17.6 (UR-0049): 마감 정합 — done 낙관 재확인 + 시크릿 재확인
|
|
12227
|
+
function sessionClose(root, opts = {}) { return _sessionClose.sessionClose(root, opts, { VERSION, STATUSES, MARK, has, arg, uiLang: _uiLang(root), harnessPath: __filename, readProgressRows, evidencePath, handoffPath, currentStatePath, taskLogPath, verifyRules, _autoRoadmap, _readUsageStats, readSessionCounter, writeSessionCounter, _retroAggregate, _retroOneLine, retroCmd, _loadDecisions, readRules, planPath, _loadLessons, _readFeatureGraph, _auditUserRequests, _detectDeliveredRequests, _computeRoundHistory, _computeMilestones, _computeRecentChanges, _collectPyFiles, _analyzePyFile, _collectRuntimeEnv, _scanShellScriptsEncoding, _listAPISkills, _matchAPISkills, _loadShellFailures, _shellEnvDrift, _runPreWakeAudit, _saveAndAppendPreWakeReport, _runIdempotencyAudit, _detectAbnormalShutdown, _updateUserRequest, _detectOptimism, _scanCodeForPatterns, _collectSecretFindings }); } // 1.17.6 (UR-0049): 마감 정합 — done 낙관 재확인 + 시크릿 재확인
|
|
12189
12228
|
|
|
12190
12229
|
function readmeCmd(root) { syncReadme(absRoot(root)); }
|
|
12191
12230
|
function consistencyCheck(root) {
|
|
@@ -19589,7 +19628,102 @@ const _diag = require('../lib/diagnostics');
|
|
|
19589
19628
|
function doctorCmd(opts = {}) { return _diag.doctorCmd(opts, { VERSION, _selfTestCases, _detectShellCtx, _mcpToolCount, has, harnessPath: __filename }); }
|
|
19590
19629
|
function whichCmd() { return _diag.whichCmd({ VERSION, has, harnessPath: __filename }); }
|
|
19591
19630
|
|
|
19631
|
+
// 1.23.1 (UR-0010 Phase 6): 영어 큐레이트 도움말 — 한국어 help 의 줄별 번역이 아니라, 카테고리별로 정리한 별도 영어판.
|
|
19632
|
+
// 레거시 버전태그(1.9.x) 군더더기를 빼고 영어 사용자가 읽기 쉽게. 전체 전수 목록은 `leerness commands`.
|
|
19633
|
+
// 한국어 help() 는 그대로 유지(기본 ko, e2e 무회귀). 영어는 --language en / LEERNESS_LANG=en opt-in.
|
|
19634
|
+
function _helpEn() {
|
|
19635
|
+
log(`Leerness v${VERSION}
|
|
19636
|
+
|
|
19637
|
+
The AI-coding operations layer that makes "done" require evidence.
|
|
19638
|
+
Korean-first by default; this English help shows with --language en or LEERNESS_LANG=en.
|
|
19639
|
+
|
|
19640
|
+
Usage: leerness <command> [path] [options]
|
|
19641
|
+
|
|
19642
|
+
SETUP & UPDATE
|
|
19643
|
+
init [path] [--language auto|ko|en] [--skills recommended|all|a,b] [--minimal] [--yes]
|
|
19644
|
+
Install the .harness/ workspace into your project
|
|
19645
|
+
migrate [path] [--dry-run] [--force] Non-destructive cross-version migration
|
|
19646
|
+
migrate audit|apply|plan [path] [--json] Diagnose / backfill / compare migration
|
|
19647
|
+
update [path] [--check|--yes|--force] Auto-detect version + migrate
|
|
19648
|
+
auto-update install [path] Install the auto-update hook
|
|
19649
|
+
path-setup [--apply] Register the leerness CLI on PATH
|
|
19650
|
+
|
|
19651
|
+
STATUS & DIAGNOSTICS
|
|
19652
|
+
status [path] Install status (files present)
|
|
19653
|
+
health [path] | doctor [path] Install/state diagnostics
|
|
19654
|
+
verify [path] Required-file verification
|
|
19655
|
+
which [--json] Resolve current binary/version (npm cache conflicts)
|
|
19656
|
+
selftest [--json] Core-function integrity self-check (CI-friendly)
|
|
19657
|
+
pulse | milestones | round-history [path] Combined progress metrics
|
|
19658
|
+
whats-new [path] Recent version changes
|
|
19659
|
+
|
|
19660
|
+
VERIFICATION (evidence-gated "done")
|
|
19661
|
+
verify-claim <T-ID> [--run-tests] [--test-cmd "..."] [--json]
|
|
19662
|
+
Check evidence vs reality (stub / fake-test / inflated-count detection)
|
|
19663
|
+
contract verify <spec.md> <impl.js> [--json] Spec <-> implementation match
|
|
19664
|
+
verify-code [path] [--build] [--bench] Run tests/lint/typecheck, record evidence
|
|
19665
|
+
gate [path] One-call CI gate: verify + audit + scan + encoding + lazy
|
|
19666
|
+
lens [code|design|docs|test|security] [--json] Quality self-question lenses
|
|
19667
|
+
|
|
19668
|
+
SECURITY & HYGIENE
|
|
19669
|
+
scan secrets [path] Committed-secret detection
|
|
19670
|
+
encoding check [path] UTF-8 / BOM / CP949 / shell-script encoding
|
|
19671
|
+
audit [path] [--fix] Consistency + plan/progress alignment
|
|
19672
|
+
lazy detect [path] [--auto-track] Anti-laziness evaluation
|
|
19673
|
+
shell-guard "<command>" [--json] Shell-compatibility linter (PowerShell 5.1 etc.)
|
|
19674
|
+
|
|
19675
|
+
HANDOFF & SESSION
|
|
19676
|
+
handoff [path] [--compact] [--all-apps] [--json] Session-start context in one call
|
|
19677
|
+
session close [path] Closing report + auto handoff
|
|
19678
|
+
context [path] [--json] Agent onboarding context
|
|
19679
|
+
retro | insights [path] [--json] Retrospective / cumulative stats
|
|
19680
|
+
|
|
19681
|
+
MEMORY (canonical JSON + markdown projections)
|
|
19682
|
+
task list|add|update|drop|fix-evidence|relink [args]
|
|
19683
|
+
plan show|init|add|drop|progress|sync [args]
|
|
19684
|
+
decision add "<title>" [--reason ...] | decision list|drop <id>
|
|
19685
|
+
lesson save "<text>" [--tag t] | lesson list|drop <id>
|
|
19686
|
+
rule add "<text>" --trigger every-session|every-commit|... | rule list|pause|resume|remove
|
|
19687
|
+
requests audit|add|list|complete|drop User-request tracking (UR-XXXX)
|
|
19688
|
+
memory search "query" [--include-code] [--limit N]
|
|
19689
|
+
memory archive list|restore [args]
|
|
19690
|
+
lessons [--query <k>] | brainstorm "<topic>"
|
|
19691
|
+
|
|
19692
|
+
SKILLS
|
|
19693
|
+
skill list|info <name>|use <id>|remove <id>
|
|
19694
|
+
skill learn <id> --doc <url> --command "..." --capability "..."
|
|
19695
|
+
skill install <SKILL.md|dir|url> | skill discover --preset vercel|anthropic
|
|
19696
|
+
skill consolidate [--threshold 0.3]
|
|
19697
|
+
|
|
19698
|
+
AGENTS & PROVIDERS (opt-in)
|
|
19699
|
+
agents list|check|quota | agents dispatch "<task>" --to <id> | agents multi "<task>"
|
|
19700
|
+
provider list|add|remove [args]
|
|
19701
|
+
setup-agents [path] [--yes]
|
|
19702
|
+
team list|add|show|remove|preview|deploy <id> [...] (deploy is double-gated)
|
|
19703
|
+
|
|
19704
|
+
REUSE & IMPACT
|
|
19705
|
+
reuse autodetect|find|register [args] | reuse-map [path] [--json]
|
|
19706
|
+
impact <target> [--all] | deps <capability> [--run-tests]
|
|
19707
|
+
feature add|link|impact|list|show | graph [path] | guide [target]
|
|
19708
|
+
|
|
19709
|
+
RELEASE & OPS
|
|
19710
|
+
release bump|note|publish|channel|cadence [args]
|
|
19711
|
+
capabilities | install-safety [--json] | permissions list|set | creds list|register|check
|
|
19712
|
+
incident list|show|handle | deploy auto | runs list|show | webhook serve
|
|
19713
|
+
roadmap [path] [--out f.html] | roadmap auto on|off|status
|
|
19714
|
+
|
|
19715
|
+
MORE
|
|
19716
|
+
commands [--json] Full, exhaustive command list
|
|
19717
|
+
help | --help | -h This help
|
|
19718
|
+
--version | -v Version only
|
|
19719
|
+
|
|
19720
|
+
Docs: https://www.npmjs.com/package/leerness | https://leerness.pages.dev
|
|
19721
|
+
`);
|
|
19722
|
+
}
|
|
19723
|
+
|
|
19592
19724
|
function help() {
|
|
19725
|
+
// 1.23.1 (UR-0010 Phase 6): 영어 opt-in 시 큐레이트 영어판. 기본(ko) 은 아래 한국어 help 그대로.
|
|
19726
|
+
if (_uiLang(arg('--path', process.cwd())) === 'en') { _helpEn(); return; }
|
|
19593
19727
|
log(`Leerness v${VERSION}\n\nUsage:\n leerness init [path] [--language auto|ko|en] [--skills recommended|all|a,b]\n leerness migrate [path] [--dry-run] [--force]\n leerness update [path] [--check|--yes|--force|--from <tarball>]\n leerness auto-update install [path]\n leerness status [path]\n leerness verify [path]\n leerness debug [path]\n leerness audit [path]\n leerness check [path]\n leerness scan secrets [path]\n leerness encoding check [path]\n leerness lazy detect [path]\n leerness memory search "query" [--limit 5]\n leerness handoff [path] [--all-apps] [--include p1,p2] [--since 24h|3d] [--compact] [--json] # 1.9.17-22 워크스페이스 (--compact: LLM 시스템 프롬프트용 1줄 요약)\n leerness orchestrate "<목표>" [--agents N] [--model qwen2.5:7b-instruct] [--retry-on-fail K] # 1.9.22 Ollama opt-in (LEERNESS_OLLAMA_BASE_URL 필요)\n leerness llm-bench record --score N --model X [--label L] [--tokens T] # 1.9.22 LLM 벤치 히스토리 누적\n leerness deps <capability> [--run-tests] [--json] # 1.9.24 depends-on 역방향 추적 + 자동 회귀 sweep\n leerness memory search "키" [--include-code] # 1.9.25 소스 코드 본문도 검색 (모순 감지 핵심)\n leerness brainstorm "주제" [--include-code] # 1.9.25 코드 본문 hits 포함\n leerness register-pending "<요청>" [--agent X] [--note Y] # 1.9.25 다중 세션 in-progress 즉시 등록\n leerness optimism-check <T-ID> [--json] # 1.9.26/27 낙관적 표시 감지 (1.9.27: 10 카테고리 + URL/메서드 매핑 + 신뢰도 점수)\n leerness persona list|show <id>|add <id> # 1.9.29 페르소나 카탈로그 (보안/성능/UX/testing/docs 5종 내장)\n leerness review <file> --persona <id1,id2,...> # 1.9.29 도메인 페르소나 리뷰 프롬프트 자동 생성\n leerness agents list|check|quota # 1.9.30/31 외부 AI CLI 가용성 + quota 추정 (claude/codex/agy/copilot)\n leerness agents dispatch "<task>" --to <id> # 1.9.30 활성 CLI 대상 실행 명령 생성 (실 호출 X, 사용자 실행)\n leerness agents multi "<task>" [--only c1,c2] [--write] [--execute] [--timeout 60] # 1.9.152/156 활성 N개 일괄 dispatch (--execute: 실 spawn + consensus)\n leerness provider list|add|remove [args] # 1.9.157 Provider Registry — 사용자 정의 CLI provider 동적 추가 (OpenRouter/Bedrock 흡수)\n leerness agents dispatch "<task>" --multi # 1.9.152 multi 모드 alias (또는 --to all)\n leerness setup-agents [path] [--yes|--no-setup-agents] # 1.9.32 sub-agent CLI 인터랙티브 설정 (.env + 미설치 자동 설치)\n leerness init [path] [--no-stale-check] # 1.9.33 npx 캐시 함정 — 옛 버전 자동 경고 (끄려면 --no-stale-check)\n leerness which [--json] # 1.9.164 진단: 현재 실행 경로/버전 + npm 캐시 + PATH 후보 (구버전 충돌 해결)\n leerness selftest [--json] # 1.9.258 코어 함수 무결성 자가 검증 (설치 손상/부분설치 감지, CI 친화 exit 1)\n leerness shell-guard "<command>" [--json] # 1.9.260 터미널 명령 셸 호환성 린터 (PowerShell 5.1 && 미지원 등 실행 전 감지, UR-0020)\n leerness shell-guard --record --cmd "..." --exit N # 1.9.260 실패한 터미널 명령 기록 → 다음 분석 시 회수\n leerness path-setup [--apply] [--json] # 1.9.254 leerness CLI PATH 자동 등록 (npm global bin 미등록 시)\n leerness web check|screenshot|extract <url> [--out file.png] [--selector "css"] # 1.9.165 playwright bridge (opt-in: npm i -g playwright + permissions.browser)\n leerness pc check|click|type|screenshot [--x N --y N] [--text "s"] [--out f.png] # 1.9.166 robotjs/nut-tree bridge (opt-in: npm i -g robotjs + permissions.mouse/keyboard, ⚠ full 모드 권장)\n leerness lsp check|symbols|references <file/name> [--in dir] [--json] # 1.9.167 LSP 어댑터 MVP (typescript opt-in + regex fallback, 코드 인텔리전스)\n leerness review-request "<request>" [--json] # 1.9.176 사용자 요청 사전 검토 (충돌/재사용/효율/권장 단계 — 사용자 명시)\n leerness contract verify <spec.md> <impl.js> [--json] # 1.9.35 명세 ↔ 구현 일치 검사 (함수/필드)\n leerness reuse autodetect [path] [--apply] [--json] # 1.9.35 src/*.js의 module.exports → reuse-map 후보 등록\n leerness audit [path] [--fix] # 1.9.35 --fix: session-handoff/current-state 자동 갱신\n leerness verify-claim <T-ID> ... [--strict-claims] # 1.9.26 verify-claim에 낙관적 표시 자동 검사 통합
|
|
19594
19728
|
leerness lens [code|design|docs|test|security] [--json] # 1.18.3 분야별 자기질문 품질 렌즈 + 분야간 인과관계 (완료 선언 전 자가 점검)\n leerness reuse-map [path] [--all-apps] [--include p1,p2] [--strict-elements] [--json] # 1.9.18 중복/잠재중복/depends-on\n leerness verify-claim <T-ID> [--path .] [--run-tests] [--json] # 1.9.18-20 evidence 자동 검증 (1.9.20: scenes/scripts 등 도메인 폴더 + jest/mocha 파싱)\n leerness verify-code [path] [--build] [--bench] # 1.9.20 --bench: scripts.bench 추가 실행 + evidence 누적\n leerness session close [path]\n leerness route <task-type>\n leerness self check [path]\n leerness readme sync [path]\n leerness consistency check [path]\n leerness consistency merge-design-guide [path]\n leerness plan show|init|add|drop|progress|sync [args]\n leerness task list|add|update|drop|fix-evidence|relink [args]\n leerness skill list|info <name>\n leerness skill learn <id> --doc <url> --command "..." --capability "..." [--note ...]\n leerness skill use <id> [--note ...]\n leerness skill optimize <id> --before "..." --after "..." [--note ...]\n leerness skill remove <id>\n leerness skill consolidate [--threshold 0.3]\n leerness gate [path] # verify+audit+scan+encoding+lazy
|
|
19595
19729
|
leerness retro [path] [--days 7] [--all-apps] [--include p1,p2] [--json] # 회고 (1.9.13~1.9.16)
|
|
@@ -20039,7 +20173,14 @@ async function main() {
|
|
|
20039
20173
|
feature: 'feature add "<이름>" | feature list | feature show <ID> | feature link <A> <B> | feature impact <ID>',
|
|
20040
20174
|
memory: 'memory search "<키>" [--json] | memory status | memory archive | memory restore',
|
|
20041
20175
|
};
|
|
20042
|
-
|
|
20176
|
+
// 1.23.2 (UR-0010 Phase 7): 영어 자리표시자 병렬맵 — ko 맵은 불변(e2e 안전), en 은 <text>/<trigger>/<key>/<name>.
|
|
20177
|
+
const _GROUP_USAGE_EN = {
|
|
20178
|
+
rule: 'rule add "<text>" --trigger <trigger> | rule list | rule pause/resume/remove <ID> | rule verify',
|
|
20179
|
+
skill: 'skill list | skill add <id> | skill use <id> | skill search "<key>" | skill match "<text>"',
|
|
20180
|
+
feature: 'feature add "<name>" | feature list | feature show <ID> | feature link <A> <B> | feature impact <ID>',
|
|
20181
|
+
memory: 'memory search "<key>" [--json] | memory status | memory archive | memory restore',
|
|
20182
|
+
};
|
|
20183
|
+
if (_GROUP_USAGE[cmd] && !args[1]) { const _gu = _uiLang(arg('--path', process.cwd())) === 'en' ? `${cmd} subcommand required — usage: leerness ${_GROUP_USAGE_EN[cmd]}` : `${cmd} 하위명령 필요 — 사용법: leerness ${_GROUP_USAGE[cmd]}`; failJson(has('--json'), 'subcommand_required', _gu); return; }
|
|
20043
20184
|
// 1.9.437 (11th 외부평가 Codex P2, UR-0138): --json 모드 unknown command 도 순수 JSON.
|
|
20044
20185
|
failJson(has('--json'), 'unknown_command', `알 수 없는 명령: ${cmd} (leerness --help 로 전체 명령 확인)`);
|
|
20045
20186
|
return;
|
package/lib/session-close.js
CHANGED
|
@@ -11,7 +11,9 @@ const { log, ok, warn, fail, failJson, today, now, absRoot, exists, read, readBu
|
|
|
11
11
|
const { _sanitizeFences, _parseArchiveBlocks } = require('./pure-utils');
|
|
12
12
|
|
|
13
13
|
function sessionClose(root, opts = {}, deps = {}) {
|
|
14
|
-
const { VERSION, STATUSES, MARK, has, arg, harnessPath, readProgressRows, evidencePath, handoffPath, currentStatePath, taskLogPath, verifyRules, _autoRoadmap, _readUsageStats, readSessionCounter, writeSessionCounter, _retroAggregate, _retroOneLine, retroCmd, _loadDecisions, readRules, planPath, _loadLessons, _readFeatureGraph, _auditUserRequests, _detectDeliveredRequests, _computeRoundHistory, _computeMilestones, _computeRecentChanges, _collectPyFiles, _analyzePyFile, _collectRuntimeEnv, _scanShellScriptsEncoding, _listAPISkills, _matchAPISkills, _loadShellFailures, _shellEnvDrift, _runPreWakeAudit, _saveAndAppendPreWakeReport, _runIdempotencyAudit, _detectAbnormalShutdown, _updateUserRequest, _detectOptimism, _scanCodeForPatterns, _collectSecretFindings } = deps;
|
|
14
|
+
const { VERSION, STATUSES, MARK, has, arg, uiLang, harnessPath, readProgressRows, evidencePath, handoffPath, currentStatePath, taskLogPath, verifyRules, _autoRoadmap, _readUsageStats, readSessionCounter, writeSessionCounter, _retroAggregate, _retroOneLine, retroCmd, _loadDecisions, readRules, planPath, _loadLessons, _readFeatureGraph, _auditUserRequests, _detectDeliveredRequests, _computeRoundHistory, _computeMilestones, _computeRecentChanges, _collectPyFiles, _analyzePyFile, _collectRuntimeEnv, _scanShellScriptsEncoding, _listAPISkills, _matchAPISkills, _loadShellFailures, _shellEnvDrift, _runPreWakeAudit, _saveAndAppendPreWakeReport, _runIdempotencyAudit, _detectAbnormalShutdown, _updateUserRequest, _detectOptimism, _scanCodeForPatterns, _collectSecretFindings } = deps;
|
|
15
|
+
// 1.22.1 (UR-0010 Phase 4): 마감 보고 UI 언어 — 영어 opt-in, 한국어 기본(uiLang 미주입 시 ko).
|
|
16
|
+
const t = (ko, en) => (uiLang === 'en' ? en : ko);
|
|
15
17
|
root = absRoot(root);
|
|
16
18
|
// 1.10.4 (13th 버그헌트 P2, UR-0167): 경로 없음/디렉토리 아님 → 구조화 에러 + exit 1. mkdir <path>/.harness ENOTDIR 크래시 & 실패를 성공(exit 0)으로 오판하던 문제 차단.
|
|
17
19
|
if (!exists(root) || !fs.statSync(root).isDirectory()) { failJson(!!opts.json || has('--json'), 'path_not_found', `경로 없음 또는 디렉토리 아님: ${root}`); return; }
|
|
@@ -33,7 +35,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
33
35
|
// 1.12.3 (14th 버그헌트 P3, UR-0183): 마감 시 완료 정직성 advisory — done 인데 evidence 가 비었거나 placeholder 인 task 노출(차단 X, 정직성 환기). lazy detect 의 done_no_evidence 휴리스틱과 동일.
|
|
34
36
|
const _doneNoEvidence = (buckets['done'] || []).filter(r => !r.evidence || /^(\s*|user-request|-)$/.test(r.evidence) || /^plan:M-\d{4}\s*$/.test(r.evidence));
|
|
35
37
|
jsonResult.completionHonesty = { doneTotal: (buckets['done'] || []).length, doneWithoutEvidence: _doneNoEvidence.length, ids: _doneNoEvidence.slice(0, 5).map(r => r.id) };
|
|
36
|
-
if (_doneNoEvidence.length) log(` ⚠ 완료 정직성: done ${_doneNoEvidence.length}건 evidence 없음/placeholder (${_doneNoEvidence.slice(0, 3).map(r => r.id).join(', ')}) — verify-claim 권장 (advisory)`);
|
|
38
|
+
if (_doneNoEvidence.length) log(t(` ⚠ 완료 정직성: done ${_doneNoEvidence.length}건 evidence 없음/placeholder (${_doneNoEvidence.slice(0, 3).map(r => r.id).join(', ')}) — verify-claim 권장 (advisory)`, ` ⚠ completion honesty: ${_doneNoEvidence.length} done with no/placeholder evidence (${_doneNoEvidence.slice(0, 3).map(r => r.id).join(', ')}) — verify-claim recommended (advisory)`));
|
|
37
39
|
// 1.17.6 (UR-0049 마감 정합): done 의 미해소 낙관 의심 재확인 — verify-claim 을 건너뛴 거짓 주장(evidence 에 API/DB 주장 있는데 코드 흔적 없음)이
|
|
38
40
|
// 평범한 'done' 으로 마감을 무사 통과하던 것(5축 실증 P2: 거짓 DB 주장이 done 으로 마감, gate 실패 중 'clean' 선언) — 마감이 마지막 관문 역할을 하도록 재확인. advisory.
|
|
39
41
|
let _doneOptimism = [];
|
|
@@ -44,12 +46,12 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
44
46
|
}
|
|
45
47
|
} catch {}
|
|
46
48
|
jsonResult.completionHonesty.optimismUnresolved = _doneOptimism.map(x => ({ id: x.id, kinds: x.suspects.map(s => s.kind) }));
|
|
47
|
-
if (_doneOptimism.length) log(` ⚠ 완료 정직성: done ${_doneOptimism.length}건 낙관 의심 미해소 (${_doneOptimism.slice(0, 3).map(x => x.id).join(', ')}) — evidence 주장 vs 코드 흔적 불일치, 마감 전 verify-claim 재확인 권장 (advisory)`);
|
|
49
|
+
if (_doneOptimism.length) log(t(` ⚠ 완료 정직성: done ${_doneOptimism.length}건 낙관 의심 미해소 (${_doneOptimism.slice(0, 3).map(x => x.id).join(', ')}) — evidence 주장 vs 코드 흔적 불일치, 마감 전 verify-claim 재확인 권장 (advisory)`, ` ⚠ completion honesty: ${_doneOptimism.length} done with unresolved optimism (${_doneOptimism.slice(0, 3).map(x => x.id).join(', ')}) — evidence claim vs code trace mismatch, re-check with verify-claim before closing (advisory)`));
|
|
48
50
|
// 1.17.6 (UR-0049): 마감 보안 재확인 — 커밋 대상 시크릿이 살아있으면 'clean' 으로 마감하지 않도록 표면화. advisory(차단 X).
|
|
49
51
|
let _closeSecrets = 0;
|
|
50
52
|
try { if (_collectSecretFindings) _closeSecrets = ((_collectSecretFindings(root) || {}).committed || []).length; } catch {}
|
|
51
53
|
jsonResult.closeSecurity = { committedSecrets: _closeSecrets };
|
|
52
|
-
if (_closeSecrets) log(` 🚨 마감 보안: 커밋 대상 시크릿 ${_closeSecrets}건 미해소 — clean 아님, leerness scan secrets 확인 후 마감
|
|
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`));
|
|
53
55
|
|
|
54
56
|
function rowsToList(arr) {
|
|
55
57
|
if (!arr || !arr.length) return '- 없음';
|
|
@@ -119,7 +121,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
119
121
|
const ruleResults = verifyRules(root);
|
|
120
122
|
jsonResult.rules = ruleResults.map(r => ({ id: r.id, trigger: r.trigger, verified: r.verified, note: r.note }));
|
|
121
123
|
log('\n## ⚡ User Rules verification');
|
|
122
|
-
if (!ruleResults.length) log('- 활성 룰 없음');
|
|
124
|
+
if (!ruleResults.length) log(t('- 활성 룰 없음', '- no active rules'));
|
|
123
125
|
else {
|
|
124
126
|
log('| ID | Trigger | Rule | Verified | Note |');
|
|
125
127
|
log('|---|---|---|---|---|');
|
|
@@ -127,7 +129,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
127
129
|
for (const r of ruleResults) log(`| ${r.id} | ${r.trigger} | ${r.rule.slice(0, 40)} | ${ic[r.verified] || '?'} | ${r.note} |`);
|
|
128
130
|
}
|
|
129
131
|
log('\n## Required final response sections');
|
|
130
|
-
log('- 완료 작업\n- 진행 중 작업\n- 미완료/예정/대기/보류/차단/드랍 작업\n- 검증 결과\n- 추천 방향\n- 다음 정확한 작업\n- ⚡ 활성 룰별 검증 결과');
|
|
132
|
+
log(t('- 완료 작업\n- 진행 중 작업\n- 미완료/예정/대기/보류/차단/드랍 작업\n- 검증 결과\n- 추천 방향\n- 다음 정확한 작업\n- ⚡ 활성 룰별 검증 결과', '- Completed tasks\n- In-progress tasks\n- Incomplete/planned/waiting/on-hold/blocked/dropped tasks\n- Verification results\n- Recommended direction\n- Next exact step\n- ⚡ Per-rule verification results'));
|
|
131
133
|
ok(`session-handoff.md and current-state.md updated`);
|
|
132
134
|
// 1.9.12: session close 끝에 roadmap.html 자동 갱신
|
|
133
135
|
_autoRoadmap(root, 'session-close');
|
|
@@ -139,15 +141,15 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
139
141
|
const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
140
142
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
141
143
|
log('');
|
|
142
|
-
log(cy('## 💡 다음 라운드 추천 (1.9.57 --suggest)'));
|
|
144
|
+
log(cy(t('## 💡 다음 라운드 추천 (1.9.57 --suggest)', '## 💡 Next-round suggestions (--suggest)')));
|
|
143
145
|
// 1) skill suggest
|
|
144
146
|
try {
|
|
145
147
|
const r = cp.spawnSync(process.execPath, [harnessPath, 'skill', 'suggest', '--path', root, '--min', '3', '--json'],
|
|
146
148
|
{ encoding: 'utf8', timeout: 15000, env: { ...process.env, LEERNESS_INTERNAL: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '1' } });
|
|
147
149
|
const j = JSON.parse(r.stdout);
|
|
148
150
|
if (j.candidates && j.candidates.length) {
|
|
149
|
-
log(dim(' 📌 신규 skill 후보 (Hermes-style 자동 학습):'));
|
|
150
|
-
for (const c of j.candidates.slice(0, 3)) log(` • ${c.keyword} (${c.count}회 등장, 출처: ${c.source})`);
|
|
151
|
+
log(dim(t(' 📌 신규 skill 후보 (Hermes-style 자동 학습):', ' 📌 New skill candidates (Hermes-style auto-learning):')));
|
|
152
|
+
for (const c of j.candidates.slice(0, 3)) log(t(` • ${c.keyword} (${c.count}회 등장, 출처: ${c.source})`, ` • ${c.keyword} (seen ${c.count}x, source: ${c.source})`));
|
|
151
153
|
jsonResult.skillCandidates = j.candidates.slice(0, 5);
|
|
152
154
|
}
|
|
153
155
|
} catch {}
|
|
@@ -157,8 +159,8 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
157
159
|
{ encoding: 'utf8', timeout: 15000, env: { ...process.env, LEERNESS_INTERNAL: '1', LEERNESS_NO_PROMPT: '1', LEERNESS_NO_DRIFT_CHECK: '0' } });
|
|
158
160
|
const j = JSON.parse(r.stdout.trim());
|
|
159
161
|
if (j.level) {
|
|
160
|
-
log(dim(` 🩺 drift 상태: ${j.level} ${j.score}/200`));
|
|
161
|
-
if (j.fired && j.fired.length) log(dim(` 🔥 ${j.fired.length}건 임계 초과 — \`leerness drift check\`
|
|
162
|
+
log(dim(t(` 🩺 drift 상태: ${j.level} ${j.score}/200`, ` 🩺 drift status: ${j.level} ${j.score}/200`)));
|
|
163
|
+
if (j.fired && j.fired.length) log(dim(t(` 🔥 ${j.fired.length}건 임계 초과 — \`leerness drift check\` 상세`, ` 🔥 ${j.fired.length} over threshold — \`leerness drift check\` for details`)));
|
|
162
164
|
jsonResult.drift = { level: j.level, score: j.score, fired: (j.fired || []).map(f => ({ label: f.label, weight: f.weight })) };
|
|
163
165
|
}
|
|
164
166
|
} catch {}
|
|
@@ -167,7 +169,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
167
169
|
const stats = _readUsageStats(root);
|
|
168
170
|
const entries = Object.entries(stats.commands || {}).sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
169
171
|
if (entries.length) {
|
|
170
|
-
log(dim(` 📊 가장 많이 쓴 명령: ${entries.map(([c, n]) => `${c}(${n})`).join(', ')}`));
|
|
172
|
+
log(dim(t(` 📊 가장 많이 쓴 명령: ${entries.map(([c, n]) => `${c}(${n})`).join(', ')}`, ` 📊 Most-used commands: ${entries.map(([c, n]) => `${c}(${n})`).join(', ')}`)));
|
|
171
173
|
jsonResult.topCommands = entries.map(([command, count]) => ({ command, count }));
|
|
172
174
|
}
|
|
173
175
|
// 1.9.74: MCP tools/call 통계 + rare 도구 노출
|
|
@@ -175,10 +177,10 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
175
177
|
const mcpEntries = Object.entries(stats.mcp.tools).sort((a, b) => b[1] - a[1]);
|
|
176
178
|
if (mcpEntries.length) {
|
|
177
179
|
const mcpTotal = mcpEntries.reduce((s, [, n]) => s + n, 0);
|
|
178
|
-
log(dim(` 🔌 MCP 호출 (1.9.74): 총 ${mcpTotal}회, top: ${mcpEntries.slice(0, 3).map(([
|
|
180
|
+
log(dim(t(` 🔌 MCP 호출 (1.9.74): 총 ${mcpTotal}회, top: ${mcpEntries.slice(0, 3).map(([tool, n]) => `${tool}(${n})`).join(', ')}`, ` 🔌 MCP calls: ${mcpTotal} total, top: ${mcpEntries.slice(0, 3).map(([tool, n]) => `${tool}(${n})`).join(', ')}`)));
|
|
179
181
|
const threshold = Math.max(1, Math.floor(mcpTotal * 0.05));
|
|
180
|
-
const rare = mcpEntries.filter(([, n]) => n <= threshold).map(([
|
|
181
|
-
if (rare.length && mcpTotal >= 5) log(dim(` 💡 드물게 호출된 MCP: ${rare.slice(0, 4).join(', ')}`));
|
|
182
|
+
const rare = mcpEntries.filter(([, n]) => n <= threshold).map(([tool]) => tool);
|
|
183
|
+
if (rare.length && mcpTotal >= 5) log(dim(t(` 💡 드물게 호출된 MCP: ${rare.slice(0, 4).join(', ')}`, ` 💡 Rarely-called MCP: ${rare.slice(0, 4).join(', ')}`)));
|
|
182
184
|
jsonResult.mcpStats = { total: mcpTotal, top: mcpEntries.slice(0, 5).map(([tool, count]) => ({ tool, count })), rare: rare.slice(0, 10) };
|
|
183
185
|
}
|
|
184
186
|
}
|
|
@@ -198,8 +200,8 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
198
200
|
const counts = {};
|
|
199
201
|
for (const q of queries) counts[q] = (counts[q] || 0) + 1;
|
|
200
202
|
const topQueries = Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
201
|
-
log(dim(` 📒 skill match query 누적 (1.9.74): 총 ${queries.length}회 / 종류 ${Object.keys(counts).length}
|
|
202
|
-
for (const [q, n] of topQueries) log(dim(` • "${q.slice(0, 50)}"${n > 1 ? ` (${n}회)` : ''}`));
|
|
203
|
+
log(dim(t(` 📒 skill match query 누적 (1.9.74): 총 ${queries.length}회 / 종류 ${Object.keys(counts).length}개`, ` 📒 skill match queries: ${queries.length} total / ${Object.keys(counts).length} distinct`)));
|
|
204
|
+
for (const [q, n] of topQueries) log(dim(` • "${q.slice(0, 50)}"${n > 1 ? t(` (${n}회)`, ` (${n}x)`) : ''}`));
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
} catch {}
|
|
@@ -212,7 +214,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
212
214
|
sc.lastCloseAt = now();
|
|
213
215
|
writeSessionCounter(root, sc);
|
|
214
216
|
const agg = _retroAggregate(root);
|
|
215
|
-
log(`\n## 📈 진행 요약 (session #${sc.count})`);
|
|
217
|
+
log(t(`\n## 📈 진행 요약 (session #${sc.count})`, `\n## 📈 Progress summary (session #${sc.count})`));
|
|
216
218
|
log(` ${_retroOneLine(agg)}`);
|
|
217
219
|
// 1.9.132: archive 활동 1줄 요약 — 마감 시점에 DELETE 활동 가시화 (handoff 7번째 회수와 symmetric)
|
|
218
220
|
try {
|
|
@@ -227,17 +229,17 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
if (arc.total > 0) {
|
|
230
|
-
log(` 🗑 archive 누적: D${arc.d}/L${arc.l}/P${arc.p} (${arc.total}건) — 복원 후보: leerness memory archive list`);
|
|
232
|
+
log(t(` 🗑 archive 누적: D${arc.d}/L${arc.l}/P${arc.p} (${arc.total}건) — 복원 후보: leerness memory archive list`, ` 🗑 archive total: D${arc.d}/L${arc.l}/P${arc.p} (${arc.total}) — restore via: leerness memory archive list`));
|
|
231
233
|
}
|
|
232
234
|
} catch {}
|
|
233
235
|
if (sc.count % 5 === 0) {
|
|
234
|
-
log(`\n## 🔄 ${sc.count}세션 마일스톤 — 자동 회고 (5세션마다)`);
|
|
236
|
+
log(t(`\n## 🔄 ${sc.count}세션 마일스톤 — 자동 회고 (5세션마다)`, `\n## 🔄 ${sc.count}-session milestone — auto retro (every 5 sessions)`));
|
|
235
237
|
retroCmd(root);
|
|
236
238
|
sc.lastDeepRetroAt = now();
|
|
237
239
|
writeSessionCounter(root, sc);
|
|
238
240
|
} else {
|
|
239
241
|
const left = 5 - (sc.count % 5);
|
|
240
|
-
log(` 💡 ${left}세션 후 자동 깊은 회고 — \`leerness retro\`로 즉시 실행
|
|
242
|
+
log(t(` 💡 ${left}세션 후 자동 깊은 회고 — \`leerness retro\`로 즉시 실행 가능`, ` 💡 deep retro in ${left} session(s) — run \`leerness retro\` now to trigger immediately`));
|
|
241
243
|
}
|
|
242
244
|
// 1.9.16: 워크스페이스 안내 (다른 leerness 프로젝트가 있으면)
|
|
243
245
|
try {
|
|
@@ -253,11 +255,11 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
253
255
|
} catch {}
|
|
254
256
|
}
|
|
255
257
|
}
|
|
256
|
-
if (wsCount > 0) log(` 🌐 워크스페이스에 ${wsCount}개 다른 leerness 프로젝트 — \`leerness retro --all-apps\`로 통합
|
|
258
|
+
if (wsCount > 0) log(t(` 🌐 워크스페이스에 ${wsCount}개 다른 leerness 프로젝트 — \`leerness retro --all-apps\`로 통합 회고`, ` 🌐 ${wsCount} other leerness project(s) in workspace — \`leerness retro --all-apps\` for combined retro`));
|
|
257
259
|
jsonResult.workspacePeers = wsCount;
|
|
258
260
|
} catch {}
|
|
259
261
|
} catch (e) {
|
|
260
|
-
warn('retro 요약 실패: ' + (e && e.message ? e.message : e));
|
|
262
|
+
warn(t('retro 요약 실패: ', 'retro summary failed: ') + (e && e.message ? e.message : e));
|
|
261
263
|
jsonResult.retroSummaryError = e && e.message ? e.message : String(e);
|
|
262
264
|
}
|
|
263
265
|
} finally {
|
|
@@ -481,7 +483,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
481
483
|
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
482
484
|
|
|
483
485
|
log('');
|
|
484
|
-
log(`## 🔚 session close 자동 통합 보고 (1.9.217)`);
|
|
486
|
+
log(t(`## 🔚 session close 자동 통합 보고 (1.9.217)`, `## 🔚 session close integrated report`));
|
|
485
487
|
// 1.9.207 + 1.9.223 (delivered 패턴 자동 권장) + 1.9.224 (--auto-apply-delivered 옵션)
|
|
486
488
|
try {
|
|
487
489
|
const reqAudit = _auditUserRequests(root);
|
|
@@ -496,17 +498,17 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
496
498
|
const u = _updateUserRequest(root, c.id, { status: 'completed', autoCompletedAt: new Date().toISOString(), autoCompleteReason: 'session-close-auto-apply-1.9.224' });
|
|
497
499
|
if (u) ok++;
|
|
498
500
|
}
|
|
499
|
-
log(grn(` ✓ delivered 패턴 ${ok}건 자동 완료 (--auto-apply-delivered 1.9.224)`));
|
|
501
|
+
log(grn(t(` ✓ delivered 패턴 ${ok}건 자동 완료 (--auto-apply-delivered 1.9.224)`, ` ✓ ${ok} delivered pattern(s) auto-completed (--auto-apply-delivered)`)));
|
|
500
502
|
} else {
|
|
501
|
-
log(yel(` 📥 delivered 패턴 ${delivered.candidates.length}건 (1.9.223) — 자동 완료
|
|
502
|
-
log(dim(` → leerness requests auto-complete --apply (수동) 또는 session close --auto-apply-delivered (1.9.224)`));
|
|
503
|
+
log(yel(t(` 📥 delivered 패턴 ${delivered.candidates.length}건 (1.9.223) — 자동 완료 가능`, ` 📥 ${delivered.candidates.length} delivered pattern(s) — auto-completable`)));
|
|
504
|
+
log(dim(t(` → leerness requests auto-complete --apply (수동) 또는 session close --auto-apply-delivered (1.9.224)`, ` → leerness requests auto-complete --apply (manual) or session close --auto-apply-delivered`)));
|
|
503
505
|
}
|
|
504
506
|
} else if (missCnt > 0) {
|
|
505
|
-
log(red(` ⚠ 미답 사용자 요청 ${missCnt}건 (task-log/plan/decisions 매칭 안 됨)`));
|
|
507
|
+
log(red(t(` ⚠ 미답 사용자 요청 ${missCnt}건 (task-log/plan/decisions 매칭 안 됨)`, ` ⚠ ${missCnt} unanswered user request(s) (no task-log/plan/decisions match)`)));
|
|
506
508
|
} else if (reqAudit.open > 0) {
|
|
507
|
-
log(grn(` ✓ 사용자 요청 ${reqAudit.open}건 모두 tracked`));
|
|
509
|
+
log(grn(t(` ✓ 사용자 요청 ${reqAudit.open}건 모두 tracked`, ` ✓ all ${reqAudit.open} user request(s) tracked`)));
|
|
508
510
|
} else {
|
|
509
|
-
log(dim(` ℹ 사용자 요청 없음 (UR 백로그 비어있음)`));
|
|
511
|
+
log(dim(t(` ℹ 사용자 요청 없음 (UR 백로그 비어있음)`, ` ℹ no user requests (UR backlog empty)`)));
|
|
510
512
|
}
|
|
511
513
|
} catch {}
|
|
512
514
|
// 1.9.209
|
|
@@ -516,11 +518,11 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
516
518
|
_saveAndAppendPreWakeReport(root, audit);
|
|
517
519
|
const sum = audit.summary;
|
|
518
520
|
if (sum.criticalCount > 0) {
|
|
519
|
-
log(red(` 🚨 pre-wake-audit: critical ${sum.criticalCount} (다음 깨어남 시 점검 필요)`));
|
|
521
|
+
log(red(t(` 🚨 pre-wake-audit: critical ${sum.criticalCount} (다음 깨어남 시 점검 필요)`, ` 🚨 pre-wake-audit: critical ${sum.criticalCount} (check before next wake)`)));
|
|
520
522
|
} else if (sum.warningCount > 0) {
|
|
521
523
|
log(yel(` ⚠ pre-wake-audit: warning ${sum.warningCount}`));
|
|
522
524
|
} else {
|
|
523
|
-
log(grn(` ✓ pre-wake-audit: clean (sleep 안전)`));
|
|
525
|
+
log(grn(t(` ✓ pre-wake-audit: clean (sleep 안전)`, ` ✓ pre-wake-audit: clean (safe to sleep)`)));
|
|
524
526
|
}
|
|
525
527
|
}
|
|
526
528
|
} catch {}
|
|
@@ -529,10 +531,10 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
529
531
|
const idemp = _runIdempotencyAudit(root);
|
|
530
532
|
const v = idemp.summary.totalViolations;
|
|
531
533
|
if (v > 0) {
|
|
532
|
-
log(red(` ⚠ 멱등성 위반 ${v}건 (high: ${idemp.summary.highSeverity})`));
|
|
533
|
-
log(dim(` → leerness idempotency audit 으로 상세
|
|
534
|
+
log(red(t(` ⚠ 멱등성 위반 ${v}건 (high: ${idemp.summary.highSeverity})`, ` ⚠ ${v} idempotency violation(s) (high: ${idemp.summary.highSeverity})`)));
|
|
535
|
+
log(dim(t(` → leerness idempotency audit 으로 상세 확인`, ` → see details with leerness idempotency audit`)));
|
|
534
536
|
} else {
|
|
535
|
-
log(grn(` ✓ 멱등성 검사 통과 — verified ${idemp.summary.verifiedAreas}
|
|
537
|
+
log(grn(t(` ✓ 멱등성 검사 통과 — verified ${idemp.summary.verifiedAreas} 영역`, ` ✓ idempotency check passed — ${idemp.summary.verifiedAreas} area(s) verified`)));
|
|
536
538
|
}
|
|
537
539
|
} catch {}
|
|
538
540
|
// 1.9.264: 셸 실패 메모리 + 환경 변동 요약 (UR-0020) — 마감 시 이번 세션 셸 실패를 회고에 노출
|
|
@@ -541,13 +543,13 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
541
543
|
const drift = _shellEnvDrift(root);
|
|
542
544
|
const driftN = drift && drift.changes ? drift.changes.length : 0;
|
|
543
545
|
if (sf.failures.length > 0 || driftN > 0) {
|
|
544
|
-
if (driftN > 0) log(yel(` ⚠ 환경 버전 변동 ${driftN}건 — 다음 세션 셸 실패 기록 재검토
|
|
546
|
+
if (driftN > 0) log(yel(t(` ⚠ 환경 버전 변동 ${driftN}건 — 다음 세션 셸 실패 기록 재검토 권장`, ` ⚠ ${driftN} environment version change(s) — review shell-failure log next session`)));
|
|
545
547
|
if (sf.failures.length > 0) {
|
|
546
|
-
log(yel(` 🐚 셸 실패 누적 ${sf.failures.length}건 — 다음 handoff 가 자동
|
|
547
|
-
log(dim(` → 명령 실행 전 점검: leerness shell-guard "<command>"`));
|
|
548
|
+
log(yel(t(` 🐚 셸 실패 누적 ${sf.failures.length}건 — 다음 handoff 가 자동 노출`, ` 🐚 ${sf.failures.length} accumulated shell failure(s) — surfaced by next handoff`)));
|
|
549
|
+
log(dim(t(` → 명령 실행 전 점검: leerness shell-guard "<command>"`, ` → check before running: leerness shell-guard "<command>"`)));
|
|
548
550
|
}
|
|
549
551
|
} else {
|
|
550
|
-
log(grn(` ✓ 셸 실패 기록 없음 (터미널 호환성 양호)`));
|
|
552
|
+
log(grn(t(` ✓ 셸 실패 기록 없음 (터미널 호환성 양호)`, ` ✓ no shell-failure records (terminal compatibility OK)`)));
|
|
551
553
|
}
|
|
552
554
|
} catch {}
|
|
553
555
|
// 1.9.237: session close --auto-cleanup-branches — 50+ release/* branches 시 자동 정리
|
|
@@ -575,11 +577,11 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
575
577
|
const r = cp.spawnSync('git', ['branch', '-d', b], { cwd: root, encoding: 'utf8' });
|
|
576
578
|
if (r.status === 0) okCnt++;
|
|
577
579
|
}
|
|
578
|
-
log(grn(` ✓ release 정리 ${okCnt}/${toDelete.length}건 (--auto-cleanup-branches 1.9.237, keep 10)`));
|
|
580
|
+
log(grn(t(` ✓ release 정리 ${okCnt}/${toDelete.length}건 (--auto-cleanup-branches 1.9.237, keep 10)`, ` ✓ release cleanup ${okCnt}/${toDelete.length} (--auto-cleanup-branches, keep 10)`)));
|
|
579
581
|
} else {
|
|
580
|
-
log(yel(` 🗑 release/* merged ${merged.length}개 (50+) — cleanup 가능 (1.9.235)`));
|
|
581
|
-
log(dim(` → leerness release cleanup --apply --keep 10 (수동)`));
|
|
582
|
-
log(dim(` → 또는 session close --auto-cleanup-branches (1.9.237 자동)`));
|
|
582
|
+
log(yel(t(` 🗑 release/* merged ${merged.length}개 (50+) — cleanup 가능 (1.9.235)`, ` 🗑 ${merged.length} merged release/* branches (50+) — cleanup available`)));
|
|
583
|
+
log(dim(t(` → leerness release cleanup --apply --keep 10 (수동)`, ` → leerness release cleanup --apply --keep 10 (manual)`)));
|
|
584
|
+
log(dim(t(` → 또는 session close --auto-cleanup-branches (1.9.237 자동)`, ` → or session close --auto-cleanup-branches (auto)`)));
|
|
583
585
|
}
|
|
584
586
|
}
|
|
585
587
|
}
|
|
@@ -602,10 +604,10 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
602
604
|
ok++;
|
|
603
605
|
} catch {}
|
|
604
606
|
}
|
|
605
|
-
log(grn(` ✓ 인코딩 위험 ${ok}/${encScan.atRisk.length}건 UTF-8 BOM 자동 추가 (--auto-fix-encoding 1.9.243)`));
|
|
607
|
+
log(grn(t(` ✓ 인코딩 위험 ${ok}/${encScan.atRisk.length}건 UTF-8 BOM 자동 추가 (--auto-fix-encoding 1.9.243)`, ` ✓ ${ok}/${encScan.atRisk.length} encoding risk(s) auto-fixed with UTF-8 BOM (--auto-fix-encoding)`)));
|
|
606
608
|
} else {
|
|
607
|
-
log(yel(` ⚠ 셸 스크립트 인코딩 위험 ${encScan.atRisk.length}건 (1.9.241) — 자동 회복
|
|
608
|
-
log(dim(` → leerness env encoding --apply (수동) 또는 session close --auto-fix-encoding (1.9.243 자동)`));
|
|
609
|
+
log(yel(t(` ⚠ 셸 스크립트 인코딩 위험 ${encScan.atRisk.length}건 (1.9.241) — 자동 회복 가능`, ` ⚠ ${encScan.atRisk.length} shell-script encoding risk(s) — auto-fixable`)));
|
|
610
|
+
log(dim(t(` → leerness env encoding --apply (수동) 또는 session close --auto-fix-encoding (1.9.243 자동)`, ` → leerness env encoding --apply (manual) or session close --auto-fix-encoding (auto)`)));
|
|
609
611
|
}
|
|
610
612
|
}
|
|
611
613
|
} catch {}
|