leerness 1.16.0 → 1.17.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 +47 -0
- package/README.md +5 -5
- package/bin/leerness.js +43 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.17.0 — 2026-06-09 — 🛡️ [안정화/Stable] 외부 클린룸 일관성 안정 minor
|
|
4
|
+
|
|
5
|
+
**🛡️ 안정화(Stable) minor.** 외부 클린룸 리뷰(게시본 무README 신규사용자 관점)에서 도출한 --json·CLI 일관성 개선(1.16.1~1.16.2)을 검증·통합해 npm 공개. R-0011 정책의 8번째 minor. 영상은 HyperFrames "문제→해소" 디자인.
|
|
6
|
+
|
|
7
|
+
### 이번 minor 통합 (1.16.1~1.16.2)
|
|
8
|
+
- **gate `--json` 단일 객체화**: 텍스트+단계JSON 혼재로 파싱 불가하던 것 → `{ok,total,failed,checks}` 단일 JSON(CI/에이전트 소비 가능).
|
|
9
|
+
- **memory search `--json`**: 플래그 무시하던 것 → `{query,total,results}` 구조화.
|
|
10
|
+
- **명령그룹 무인자 일관화**: `rule`/`skill`/`feature`/`memory` 를 하위명령 없이 부르면 "알 수 없는 명령" 대신 **사용법 힌트**(decision/lesson 과 일관, `--json` 구조화).
|
|
11
|
+
- **문서 정합**: `about` 의 메모리 경로 `.leerness/` → `.harness/`(기본 워크스페이스) 정정.
|
|
12
|
+
|
|
13
|
+
### 검증 (회귀 0)
|
|
14
|
+
- **selftest 216 PASS** · **E2E 365/365 PASS** · npm gate=minor_bump. gate/memory --json valid JSON + bare-group 사용법 힌트 행위 재현. (맹신 X: scan --json exit·AKIA 는 비-버그로 판정해 제외.)
|
|
15
|
+
|
|
16
|
+
### 안정화 표시 (R-0006)
|
|
17
|
+
CHANGELOG [안정화/Stable] · git tag (Stable) · GitHub release (Stable) · npm dist-tag `stable` 시도.
|
|
18
|
+
|
|
19
|
+
## 1.16.2 — 2026-06-09 — CLI 일관성: 명령그룹 무인자 → 사용법 힌트 (외부클린룸 UR-0042)
|
|
20
|
+
|
|
21
|
+
**🧭 명령그룹을 하위명령 없이 부르면 친절한 사용법 안내.** 외부 클린룸 리뷰가 지적: `rule`/`skill`/`feature`/`memory` 를 하위명령 없이 부르면 "알 수 없는 명령"(유효 그룹인데 혼란)이 떴음 — `decision`/`lesson` 처럼 사용법 힌트로 통일.
|
|
22
|
+
|
|
23
|
+
### 변경 (UR-0042)
|
|
24
|
+
- bare `rule`/`skill`/`feature`/`memory` → `subcommand_required` + 실제 하위명령 사용법 표시(예: `memory search "<키>" | memory status | …`). `--json` 도 구조화 출력.
|
|
25
|
+
- 기존 동작 보존: 하위명령이 있는 호출(`memory search` 등)은 그대로.
|
|
26
|
+
|
|
27
|
+
### 검증 (회귀 0)
|
|
28
|
+
- **selftest 215→216** · **E2E 365/365** · 4개 그룹 bare 호출 → 사용법 힌트, `memory --json` → `{code:'subcommand_required'}` 행위 재현.
|
|
29
|
+
- patch(1.16.2) — npm 미배포(R-0011, GitHub). 잔여: bare `leerness` 자동 init·hook(UR-0041, 설계 재검토), `--language en` 런타임(UR-0042 잔여).
|
|
30
|
+
|
|
31
|
+
## 1.16.1 — 2026-06-09 — 외부 클린룸 리뷰: --json 일관성 + 문서 정합
|
|
32
|
+
|
|
33
|
+
**🔬 외부 클린룸 리뷰(게시본 1.16.0 설치·README/소스 미참조·신규 사용자 관점, 2모델).** 발굴된 지적을 직접 재현해 진짜만 수정(맹신 X — 비-버그/의도된 동작은 제외).
|
|
34
|
+
|
|
35
|
+
### 수정 (전부 재현 검증)
|
|
36
|
+
- **gate `--json` 단일 객체화 (C2)**: 이전엔 텍스트 헤더 + 단계별 JSON 이 섞여 파싱 불가. 이제 `{ok, total, failed, checks:[{name,ok}]}` 단일 객체(하위 출력 억제). CI/에이전트 소비 가능.
|
|
37
|
+
- **memory search `--json` (C3)**: `--json` 을 무시하고 텍스트만 내던 것 → `{query, total, results:[{file,line,text}]}` 구조화(전 명령 일관).
|
|
38
|
+
- **about 문서 정합 (C4)**: `about` 의 메모리 설명이 `.leerness/` 라 했으나 기본 워크스페이스는 `.harness/` → 정정(선택 state substrate 만 .leerness/).
|
|
39
|
+
|
|
40
|
+
### 비-버그 판정 (맹신 X — 재현했으나 수정 안 함)
|
|
41
|
+
- **scan secrets `--json` exit 코드**: 리뷰는 exit 0 라 했으나 재현 결과 committed 발견 시 exit 1 정상(코드도 `if(committed.length) process.exitCode=1`). gitignored-only(안전) → exit 0 은 의도된 동작.
|
|
42
|
+
- **AWS AKIA 미탐지**: `...EXAMPLE` 포함은 placeholder 가드로 스킵(의도) — 실 키(EXAMPLE 없음)는 정상 탐지.
|
|
43
|
+
|
|
44
|
+
### 잔여(백로그): bare `leerness`(무인자) 자동 init·hook / `--language en` 런타임 미적용 / 서브명령그룹 무인자 동작 일관화.
|
|
45
|
+
|
|
46
|
+
### 검증 (회귀 0)
|
|
47
|
+
- **selftest 214→215** · **E2E 365/365** · gate/memory --json valid JSON + about .harness 행위 재현.
|
|
48
|
+
- patch(1.16.1) — npm 미배포(R-0011, GitHub).
|
|
49
|
+
|
|
3
50
|
## 1.16.0 — 2026-06-09 — 🛡️ [안정화/Stable] 16번째 버그헌트 안정 minor
|
|
4
51
|
|
|
5
52
|
**🛡️ 안정화(Stable) minor.** 16번째 멀티에이전트 버그헌트(8건 발굴·전부 직접 재현)의 코어 수정(1.15.1)을 검증·통합해 npm 공개. R-0011 정책의 7번째 minor. **이 릴리스 영상부터 개선된 "문제→해소" 디자인**(짧은 인트로 + 이전/이제 모션 + 의미 보존 하이라이트)으로 제작됩니다.
|
package/README.md
CHANGED
|
@@ -186,13 +186,13 @@ MIT
|
|
|
186
186
|
<!-- leerness:project-readme:start -->
|
|
187
187
|
## Leerness Project Harness
|
|
188
188
|
|
|
189
|
-
이 프로젝트는 Leerness v1.
|
|
189
|
+
이 프로젝트는 Leerness v1.17.0 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
|
|
190
190
|
|
|
191
191
|
### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
|
|
192
192
|
|
|
193
193
|
Leerness 는 **실행기/코딩 에이전트가 아니라**, 어떤 AI 코딩 에이전트(Claude Code · Codex · Cursor · Goose 등) 위에도 얹는 **범용 운영 레이어**입니다. 5개 공통 계층을 제공합니다:
|
|
194
194
|
|
|
195
|
-
- **기억(Memory)** — 프로젝트 상태/결정/진행을 `.
|
|
195
|
+
- **기억(Memory)** — 프로젝트 상태/결정/진행을 `.harness/` 에 영속화
|
|
196
196
|
- **정책(Policy)** — 8단계 권한 등급 + enforce (read-only→publish), MCP 호출 게이트
|
|
197
197
|
- **인수인계(Handoff)** — 에이전트 간 컨텍스트 표준 전달 + `get_project_context` 1콜 온보딩
|
|
198
198
|
- **검증(Verification)** — 근거 기반 완료 검증으로 허위 완료 차단
|
|
@@ -240,7 +240,7 @@ leerness memory restore decision <date|title>
|
|
|
240
240
|
|
|
241
241
|
### MCP server (외부 AI 통합)
|
|
242
242
|
|
|
243
|
-
Leerness v1.
|
|
243
|
+
Leerness v1.17.0는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **85개 도구**를 노출:
|
|
244
244
|
|
|
245
245
|
```jsonc
|
|
246
246
|
// 카테고리별
|
|
@@ -261,7 +261,7 @@ Leerness v1.16.0는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code
|
|
|
261
261
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
262
262
|
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) 다음 라운드 예약.
|
|
263
263
|
|
|
264
|
-
현재 누적: **70 라운드 (1.9.40 → 1.
|
|
264
|
+
현재 누적: **70 라운드 (1.9.40 → 1.17.0)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
|
|
265
265
|
|
|
266
266
|
### 성능 가이드 (1.9.140 측정)
|
|
267
267
|
|
|
@@ -299,6 +299,6 @@ leerness release pack --close --auto-main-push
|
|
|
299
299
|
- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
|
|
300
300
|
- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
|
|
301
301
|
|
|
302
|
-
Last synced by Leerness v1.
|
|
302
|
+
Last synced by Leerness v1.17.0: 2026-06-09
|
|
303
303
|
<!-- leerness:project-readme:end -->
|
|
304
304
|
|
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.17.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') 시 호스트 프로세스 오염.
|
|
@@ -281,7 +281,7 @@ function managedReadmeBlock(project) {
|
|
|
281
281
|
'',
|
|
282
282
|
'Leerness 는 **실행기/코딩 에이전트가 아니라**, 어떤 AI 코딩 에이전트(Claude Code · Codex · Cursor · Goose 등) 위에도 얹는 **범용 운영 레이어**입니다. 5개 공통 계층을 제공합니다:',
|
|
283
283
|
'',
|
|
284
|
-
'- **기억(Memory)** — 프로젝트 상태/결정/진행을 `.
|
|
284
|
+
'- **기억(Memory)** — 프로젝트 상태/결정/진행을 `.harness/` 에 영속화',
|
|
285
285
|
'- **정책(Policy)** — 8단계 권한 등급 + enforce (read-only→publish), MCP 호출 게이트',
|
|
286
286
|
'- **인수인계(Handoff)** — 에이전트 간 컨텍스트 표준 전달 + `get_project_context` 1콜 온보딩',
|
|
287
287
|
'- **검증(Verification)** — 근거 기반 완료 검증으로 허위 완료 차단',
|
|
@@ -3545,6 +3545,18 @@ function _selfTestCases() {
|
|
|
3545
3545
|
const f2 = src.includes('_cellSafe(r.request)') && src.includes('_cellSafe(r.rule)');
|
|
3546
3546
|
return f1 && f2;
|
|
3547
3547
|
} },
|
|
3548
|
+
{ name: '외부클린룸 C2/C3/C4: gate --json 단일객체 + memory search --json + about .harness 정합 (1.16.1)', run: () => {
|
|
3549
|
+
const src = read(__filename);
|
|
3550
|
+
const c2 = src.includes("const jsonMode = has('--json'); // 외부리뷰 C2") && src.includes('ok: bad === 0, total: checks.length, failed: bad, checks');
|
|
3551
|
+
const c3 = src.includes('// 외부리뷰 C3: --json 일관성') && src.includes('JSON.stringify({ version: VERSION, query, total, includeCode');
|
|
3552
|
+
const _badDir = '.leern' + 'ess/ 에 영속화 (state start'; // 자기참조 회피: 분할 — about state 줄이 .leerness 로 남아있으면 감지
|
|
3553
|
+
const c4 = src.includes('상태/결정/진행을 .harness/ 에 영속화 (task/decision') && !src.includes('상태/결정/진행을 ' + _badDir);
|
|
3554
|
+
return c2 && c3 && c4;
|
|
3555
|
+
} },
|
|
3556
|
+
{ name: '외부클린룸 UR-0042: bare 명령그룹(rule/skill/feature/memory) → 사용법 힌트(unknown command 아님) (1.16.2)', run: () => {
|
|
3557
|
+
const src = read(__filename);
|
|
3558
|
+
return src.includes('const _GROUP_USAGE = {') && src.includes("if (_GROUP_USAGE[cmd] && !args[1])") && src.includes("'subcommand_required'");
|
|
3559
|
+
} },
|
|
3548
3560
|
{ name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
|
|
3549
3561
|
];
|
|
3550
3562
|
}
|
|
@@ -7636,7 +7648,8 @@ function preCheck(root) {
|
|
|
7636
7648
|
|
|
7637
7649
|
function memorySearch(root, query) {
|
|
7638
7650
|
root = absRoot(root);
|
|
7639
|
-
|
|
7651
|
+
const jsonMode = has('--json'); const results = []; // 외부리뷰 C3: --json 일관성(이전엔 --json 무시하고 텍스트만)
|
|
7652
|
+
if (!query) { failJson(jsonMode, 'query_required', 'query required (e.g., memory search "키워드")'); return; }
|
|
7640
7653
|
// 1.13.1 (15th 블라인드 리뷰 P1, Sonnet): lessons.md + rules.md 누락 수정 — memory search 가 5종 메모리 표면을 표방하나 lesson/rule 을 검색 못 해(lesson add/rule add 로 저장한 교훈·룰이 'no matches') 모순감지 핵심 용도가 훼손됐음.
|
|
7641
7654
|
const files = ['.harness/decisions.md','.harness/lessons.md','.harness/rules.md','.harness/task-log.md','.harness/session-handoff.md','.harness/progress-tracker.md','.harness/plan.md','.harness/review-evidence.md','.harness/architecture.md'];
|
|
7642
7655
|
const re = new RegExp(query.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'i');
|
|
@@ -7646,8 +7659,8 @@ function memorySearch(root, query) {
|
|
|
7646
7659
|
const lines = read(p).split('\n');
|
|
7647
7660
|
const hits = lines.map((line, i) => ({ line, i })).filter(x => re.test(x.line));
|
|
7648
7661
|
if (hits.length) {
|
|
7649
|
-
log(`\n# ${f}`);
|
|
7650
|
-
for (const h of hits.slice(0, _parseLimit(arg('--limit','5'),5))) log(` L${h.i+1}: ${h.line.trim()}`);
|
|
7662
|
+
if (!jsonMode) log(`\n# ${f}`);
|
|
7663
|
+
for (const h of hits.slice(0, _parseLimit(arg('--limit','5'),5))) { if (!jsonMode) log(` L${h.i+1}: ${h.line.trim()}`); results.push({ file: f, line: h.i + 1, text: h.line.trim() }); }
|
|
7651
7664
|
total += hits.length;
|
|
7652
7665
|
}
|
|
7653
7666
|
}
|
|
@@ -7668,8 +7681,8 @@ function memorySearch(root, query) {
|
|
|
7668
7681
|
const lines = txt.split('\n');
|
|
7669
7682
|
const hits = lines.map((line, i) => ({ line, i })).filter(x => re.test(x.line));
|
|
7670
7683
|
if (hits.length) {
|
|
7671
|
-
log(`\n# ${rel(root, p)}`);
|
|
7672
|
-
for (const h of hits.slice(0, _parseLimit(arg('--limit','5'),5))) log(` L${h.i+1}: ${h.line.trim().slice(0, 160)}`);
|
|
7684
|
+
if (!jsonMode) log(`\n# ${rel(root, p)}`);
|
|
7685
|
+
for (const h of hits.slice(0, _parseLimit(arg('--limit','5'),5))) { if (!jsonMode) log(` L${h.i+1}: ${h.line.trim().slice(0, 160)}`); results.push({ file: rel(root, p), line: h.i + 1, text: h.line.trim().slice(0, 160) }); }
|
|
7673
7686
|
total += hits.length;
|
|
7674
7687
|
}
|
|
7675
7688
|
}
|
|
@@ -7677,6 +7690,7 @@ function memorySearch(root, query) {
|
|
|
7677
7690
|
walkCodeDir(dp);
|
|
7678
7691
|
}
|
|
7679
7692
|
}
|
|
7693
|
+
if (jsonMode) { log(JSON.stringify({ version: VERSION, query, total, includeCode: has('--include-code'), results }, null, 2)); return; }
|
|
7680
7694
|
if (total === 0) log('(no matches)');
|
|
7681
7695
|
else log(`\n${total} matches${has('--include-code') ? ' (소스 코드 포함)' : ''}`);
|
|
7682
7696
|
}
|
|
@@ -11709,13 +11723,21 @@ async function selfCheck(root) {
|
|
|
11709
11723
|
// 1.9.2: 게이트 5종 한번에 실행 (verify + audit + scan secrets + encoding check + lazy detect).
|
|
11710
11724
|
function gate(root) {
|
|
11711
11725
|
root = absRoot(root);
|
|
11712
|
-
|
|
11726
|
+
const jsonMode = has('--json'); // 외부리뷰 C2: --json 일관성 — 이전엔 텍스트 헤더+단계별 JSON 혼재로 파싱 불가. 단일 객체로 집계.
|
|
11727
|
+
const checks = [];
|
|
11713
11728
|
let bad = 0;
|
|
11729
|
+
if (!jsonMode) log('# leerness gate (5 checks)');
|
|
11714
11730
|
function step(label, fn) {
|
|
11715
|
-
log(`\n## ${label}`);
|
|
11716
11731
|
const code0 = process.exitCode || 0;
|
|
11717
|
-
|
|
11718
|
-
|
|
11732
|
+
if (!jsonMode) log(`\n## ${label}`);
|
|
11733
|
+
const orig = process.stdout.write;
|
|
11734
|
+
if (jsonMode) process.stdout.write = () => true; // 단계 하위출력 억제(JSON 오염 방지) — fn 은 동기, finally 로 복원
|
|
11735
|
+
let threw = null;
|
|
11736
|
+
try { fn(); } catch (e) { threw = e; } finally { if (jsonMode) process.stdout.write = orig; }
|
|
11737
|
+
const failed = threw != null || !!(process.exitCode && process.exitCode !== code0);
|
|
11738
|
+
if (threw && !jsonMode) fail(`${label} threw: ${threw.message}`);
|
|
11739
|
+
if (failed) bad++;
|
|
11740
|
+
checks.push({ name: label, ok: !failed, ...(threw ? { error: threw.message } : {}) });
|
|
11719
11741
|
process.exitCode = 0;
|
|
11720
11742
|
}
|
|
11721
11743
|
step('verify', () => verify(root));
|
|
@@ -11723,6 +11745,7 @@ function gate(root) {
|
|
|
11723
11745
|
step('scan secrets', () => scanSecrets(root));
|
|
11724
11746
|
step('encoding check', () => encodingCheck(root));
|
|
11725
11747
|
step('lazy detect', () => lazyDetect(root));
|
|
11748
|
+
if (jsonMode) { log(JSON.stringify({ version: VERSION, root, ok: bad === 0, total: checks.length, failed: bad, checks }, null, 2)); if (bad) process.exitCode = 1; return; }
|
|
11726
11749
|
log(`\n# gate summary: ${bad} 단계 실패`);
|
|
11727
11750
|
if (bad) process.exitCode = 1;
|
|
11728
11751
|
else ok('all gates passed');
|
|
@@ -16630,7 +16653,7 @@ function _leernessIdentity() {
|
|
|
16630
16653
|
isNot: '실행기/코딩 에이전트가 아님 — 어떤 에이전트 위에도 얹는 공통 운영 계층',
|
|
16631
16654
|
tagline: '어떤 AI 코딩 에이전트에도 적용되는 범용 운영 레이어 — 기억·정책·인수인계·검증·감사',
|
|
16632
16655
|
layers: [
|
|
16633
|
-
{ key: 'memory', ko: '기억', desc: '프로젝트 상태/결정/진행을 .
|
|
16656
|
+
{ key: 'memory', ko: '기억', desc: '프로젝트 상태/결정/진행을 .harness/ 에 영속화 (task/decision/lesson/plan; 선택 state substrate 는 .leerness/)' },
|
|
16634
16657
|
{ key: 'policy', ko: '정책', desc: '8단계 권한 등급 + enforce (read-only→publish), MCP 호출 게이트' },
|
|
16635
16658
|
{ key: 'handoff', ko: '인수인계', desc: '에이전트 간 컨텍스트 표준 전달 (Claude→Codex→Goose), get_project_context 1콜 온보딩' },
|
|
16636
16659
|
{ key: 'verification', ko: '검증', desc: '근거 기반 완료 검증 (verify-claim --require-evidence) — 허위 완료 차단' },
|
|
@@ -19505,6 +19528,14 @@ async function main() {
|
|
|
19505
19528
|
}
|
|
19506
19529
|
// 1.9.306 (UR-0045): 명시적 help 요청은 exit 0, 그 외 미인식 명령은 안내 + exit 1 (실패를 성공으로 오판 방지).
|
|
19507
19530
|
if (cmd === 'help' || cmd === 'commands' || cmd === '--help' || cmd === '-h') { help(); return; }
|
|
19531
|
+
// 1.16.2 (외부클린룸 UR-0042): 유효 명령그룹을 하위명령 없이 부르면 'unknown command'(혼란) 대신 사용법 힌트 — decision/lesson 과 일관.
|
|
19532
|
+
const _GROUP_USAGE = {
|
|
19533
|
+
rule: 'rule add "<텍스트>" --trigger <트리거> | rule list | rule pause/resume/remove <ID> | rule verify',
|
|
19534
|
+
skill: 'skill list | skill add <id> | skill use <id> | skill search "<키>" | skill match "<텍스트>"',
|
|
19535
|
+
feature: 'feature add "<이름>" | feature list | feature show <ID> | feature link <A> <B> | feature impact <ID>',
|
|
19536
|
+
memory: 'memory search "<키>" [--json] | memory status | memory archive | memory restore',
|
|
19537
|
+
};
|
|
19538
|
+
if (_GROUP_USAGE[cmd] && !args[1]) { failJson(has('--json'), 'subcommand_required', `${cmd} 하위명령 필요 — 사용법: leerness ${_GROUP_USAGE[cmd]}`); return; }
|
|
19508
19539
|
// 1.9.437 (11th 외부평가 Codex P2, UR-0138): --json 모드 unknown command 도 순수 JSON.
|
|
19509
19540
|
failJson(has('--json'), 'unknown_command', `알 수 없는 명령: ${cmd} (leerness --help 로 전체 명령 확인)`);
|
|
19510
19541
|
return;
|