leerness 1.9.295 → 1.9.296
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 +19 -0
- package/README.md +18 -6
- package/bin/harness.js +70 -2
- package/package.json +1 -1
- package/scripts/e2e.js +24 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.296 — 2026-06-04 — UR-0030: 정체성 = AI 에이전트 운영 레이어 (leerness about verb)
|
|
4
|
+
|
|
5
|
+
**🧭 GPT-5.5 범용 하네스 전략의 정체성 정립 — leerness 는 "실행기"가 아니라 어떤 AI 코딩 에이전트 위에도 얹는 "운영 레이어"임을 조회 가능·테스트 가능한 형태로 명문화.**
|
|
6
|
+
|
|
7
|
+
### 배경
|
|
8
|
+
GPT-5.5 범용 하네스 리뷰: leerness 의 정체성을 "AI 에이전트 운영 레이어(Memory+Policy+Handoff+Verification+Audit 공통 계층)"로 포지셔닝 권고(UR-0030). 하위 구현(MCP-first/state schema/adapters/tiers)은 이미 완료됐으나, **정체성 자체가 코드/문서에서 명시적으로 조회 가능하지 않았음**.
|
|
9
|
+
|
|
10
|
+
### 구현 (UR-0030)
|
|
11
|
+
1. **`leerness about [--json]` (alias `identity`) CLI 신설** — 정체성을 구조화 노출: identity("AI 에이전트 운영 레이어") / isNot(실행기 아님) / 5계층(기억·정책·인수인계·검증·감사) / complements(AGENTS.md 보완) / entryPoints / surface(동적: MCP 도구수·어댑터·provider·런타임의존성 0).
|
|
12
|
+
2. **MCP `leerness_about` (81번째 도구)** — read-only. 어떤 에이전트든 "이 도구가 무엇이고 무엇을 보완하는가"를 1콜로 파악.
|
|
13
|
+
3. **`_leernessIdentity()` 단일 출처** — about CLI / MCP / README 정체성 섹션이 공유(동적 표면 데이터는 ADAPTERS/_mcpToolCount/EXTERNAL_AGENTS 에서 합성).
|
|
14
|
+
4. **README 정체성 섹션** — managedReadmeBlock 에 "정체성 — AI 에이전트 운영 레이어" 섹션 추가(5계층 + AGENTS.md 보완 관계 명시). readme sync 로 자동 propagate.
|
|
15
|
+
5. selftest 43→44 · e2e 240→241. MCP 배지 80→81 자동 동기화.
|
|
16
|
+
|
|
17
|
+
### 검증
|
|
18
|
+
- **selftest 44/44 PASS** · **E2E 241/241 PASS** (회귀 0).
|
|
19
|
+
- 실측: `about --json` → identity/5계층/surface(MCP 81·어댑터 9·provider 10·deps 0). MCP tools/list 81개에 `leerness_about` 노출. README 정체성 섹션 생성.
|
|
20
|
+
- B(1.9.288) 도구수 정합 가드가 배지 stale(80 vs 81) 즉시 검출 → sync 정합(Codex #5 가드 정상).
|
|
21
|
+
|
|
3
22
|
## 1.9.295 — 2026-06-04 — UR-0025 (4단계): 잔여 정적 카탈로그 → lib/catalogs.js — 데이터 추출 단계 완료 ✅
|
|
4
23
|
|
|
5
24
|
**🧩 모놀리스 분리 4단계 — 잔여 정적 데이터 카탈로그 5종을 비파괴 분리. 이로써 leerness 의 모든 정적 데이터 카탈로그가 lib/ 모듈로 외부화됨(데이터 추출 단계 완료).**
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **AI 코딩 에이전트의 거짓 완료·중복·망각·충돌을 막아주는 검수·기억·협업 CLI 하네스.**
|
|
4
4
|
> **A CLI harness that stops AI coding agents from faking completion, duplicating work, forgetting context, and colliding.**
|
|
5
5
|
|
|
6
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []()
|
|
7
7
|
|
|
8
8
|
```
|
|
9
9
|
╔══════════════════════════════════════════════════════════════╗
|
|
@@ -471,7 +471,19 @@ MIT — © leerness contributors
|
|
|
471
471
|
<!-- leerness:project-readme:start -->
|
|
472
472
|
## Leerness Project Harness
|
|
473
473
|
|
|
474
|
-
이 프로젝트는 Leerness v1.9.
|
|
474
|
+
이 프로젝트는 Leerness v1.9.296 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
|
|
475
|
+
|
|
476
|
+
### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
|
|
477
|
+
|
|
478
|
+
Leerness 는 **실행기/코딩 에이전트가 아니라**, 어떤 AI 코딩 에이전트(Claude Code · Codex · Cursor · Goose 등) 위에도 얹는 **범용 운영 레이어**입니다. 5개 공통 계층을 제공합니다:
|
|
479
|
+
|
|
480
|
+
- **기억(Memory)** — 프로젝트 상태/결정/진행을 `.leerness/` 에 영속화
|
|
481
|
+
- **정책(Policy)** — 8단계 권한 등급 + enforce (read-only→publish), MCP 호출 게이트
|
|
482
|
+
- **인수인계(Handoff)** — 에이전트 간 컨텍스트 표준 전달 + `get_project_context` 1콜 온보딩
|
|
483
|
+
- **검증(Verification)** — 근거 기반 완료 검증으로 허위 완료 차단
|
|
484
|
+
- **감사(Audit)** — drift/idempotency/secret/encoding 자동 감사 + self-heal
|
|
485
|
+
|
|
486
|
+
AGENTS.md(정적 지침)을 **대체하지 않고 보완**합니다 — 정적 규칙은 AGENTS.md, 동적 상태·검증·인수인계는 leerness. 정체성 조회: `leerness about` (MCP `leerness_about`).
|
|
475
487
|
|
|
476
488
|
### Core Commands
|
|
477
489
|
|
|
@@ -513,7 +525,7 @@ leerness memory restore decision <date|title>
|
|
|
513
525
|
|
|
514
526
|
### MCP server (외부 AI 통합)
|
|
515
527
|
|
|
516
|
-
Leerness v1.9.
|
|
528
|
+
Leerness v1.9.296는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **81개 도구**를 노출:
|
|
517
529
|
|
|
518
530
|
```jsonc
|
|
519
531
|
// 카테고리별
|
|
@@ -526,7 +538,7 @@ Leerness v1.9.295는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
|
|
|
526
538
|
// • Workflow: session_close / agents_list / task_export / env_check / usage_stats / reuse_map / whats_new
|
|
527
539
|
|
|
528
540
|
// MCP server 실행: leerness mcp serve
|
|
529
|
-
// tools/list 응답:
|
|
541
|
+
// tools/list 응답: 81 도구
|
|
530
542
|
```
|
|
531
543
|
|
|
532
544
|
### Autonomous mode (자율 모드)
|
|
@@ -534,7 +546,7 @@ Leerness v1.9.295는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
|
|
|
534
546
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
535
547
|
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) 다음 라운드 예약.
|
|
536
548
|
|
|
537
|
-
현재 누적: **70 라운드 (1.9.40 → 1.9.
|
|
549
|
+
현재 누적: **70 라운드 (1.9.40 → 1.9.296)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
|
|
538
550
|
|
|
539
551
|
### 성능 가이드 (1.9.140 측정)
|
|
540
552
|
|
|
@@ -572,6 +584,6 @@ leerness release pack --close --auto-main-push
|
|
|
572
584
|
- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
|
|
573
585
|
- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
|
|
574
586
|
|
|
575
|
-
Last synced by Leerness v1.9.
|
|
587
|
+
Last synced by Leerness v1.9.296: 2026-06-04
|
|
576
588
|
<!-- leerness:project-readme:end -->
|
|
577
589
|
|
package/bin/harness.js
CHANGED
|
@@ -12,7 +12,7 @@ const { _isSecretKey, compareVer, parseHarnessVersion, _classifyCJK, _riskLabel,
|
|
|
12
12
|
// 1.9.295 (UR-0025 4단계): 정적 데이터 카탈로그 모듈 분리 (비파괴, require-based).
|
|
13
13
|
const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE_CHECKLIST } = require('../lib/catalogs');
|
|
14
14
|
|
|
15
|
-
const VERSION = '1.9.
|
|
15
|
+
const VERSION = '1.9.296';
|
|
16
16
|
|
|
17
17
|
// 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
|
|
18
18
|
// 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
|
|
@@ -288,6 +288,18 @@ function managedReadmeBlock(project) {
|
|
|
288
288
|
'',
|
|
289
289
|
`이 프로젝트는 Leerness v${VERSION} 하네스를 사용합니다. AI 에이전트는 작업 전 \`leerness handoff\`로 컨텍스트를 적재하고, 작업 후 \`leerness check\`/\`leerness audit\`/\`leerness session close\`를 수행해야 합니다.`,
|
|
290
290
|
'',
|
|
291
|
+
'### 정체성 — AI 에이전트 운영 레이어 (UR-0030)',
|
|
292
|
+
'',
|
|
293
|
+
'Leerness 는 **실행기/코딩 에이전트가 아니라**, 어떤 AI 코딩 에이전트(Claude Code · Codex · Cursor · Goose 등) 위에도 얹는 **범용 운영 레이어**입니다. 5개 공통 계층을 제공합니다:',
|
|
294
|
+
'',
|
|
295
|
+
'- **기억(Memory)** — 프로젝트 상태/결정/진행을 `.leerness/` 에 영속화',
|
|
296
|
+
'- **정책(Policy)** — 8단계 권한 등급 + enforce (read-only→publish), MCP 호출 게이트',
|
|
297
|
+
'- **인수인계(Handoff)** — 에이전트 간 컨텍스트 표준 전달 + `get_project_context` 1콜 온보딩',
|
|
298
|
+
'- **검증(Verification)** — 근거 기반 완료 검증으로 허위 완료 차단',
|
|
299
|
+
'- **감사(Audit)** — drift/idempotency/secret/encoding 자동 감사 + self-heal',
|
|
300
|
+
'',
|
|
301
|
+
'AGENTS.md(정적 지침)을 **대체하지 않고 보완**합니다 — 정적 규칙은 AGENTS.md, 동적 상태·검증·인수인계는 leerness. 정체성 조회: `leerness about` (MCP `leerness_about`).',
|
|
302
|
+
'',
|
|
291
303
|
'### Core Commands',
|
|
292
304
|
'',
|
|
293
305
|
'```bash',
|
|
@@ -3004,6 +3016,7 @@ function _selfTestCases() {
|
|
|
3004
3016
|
{ name: '_canonicalProgressHeader + idempotency auto-fix (근본 복제버그 fix 1.9.293)', run: () => { const h = _canonicalProgressHeader(); const headerOk = /leernessRole: progress-tracker/.test(h) && /\| ID \| Status \| Request \|/.test(h) && /\|---\|/.test(h); const src = read(__filename); const fnOk = typeof _autoFixIdempotency === 'function'; const noWholeTextFallback = /if \(idx < 0\) return _canonicalProgressHeader\(\);/.test(src); const driftWired = /_autoFixIdempotency\(root\)/.test(src) && /idempotency 중복/.test(src); return headerOk && fnOk && noWholeTextFallback && driftWired; } },
|
|
3005
3017
|
{ name: 'lib/role-catalog: ROLE/PROVIDER/ALIASES/PROMPTS 모듈 단일출처 분리 (UR-0025 1.9.294)', run: () => { const m = require('../lib/role-catalog'); return m.ROLE_CATALOG === ROLE_CATALOG && m._PROVIDER_MODEL_CATALOG === _PROVIDER_MODEL_CATALOG && m._ROLE_ALIASES === _ROLE_ALIASES && m._AGENT_ROLE_PROMPTS === _AGENT_ROLE_PROMPTS && Object.keys(m.ROLE_CATALOG).length === 7 && Object.keys(m._PROVIDER_MODEL_CATALOG).length === 10 && !/const ROLE_CATALOG = \{/.test(read(__filename)); } },
|
|
3006
3018
|
{ name: 'lib/catalogs: CAPABILITY/ADAPTERS/REUSE 모듈 단일출처 분리 (UR-0025 1.9.295)', run: () => { const m = require('../lib/catalogs'); return m.CAPABILITY_SURFACE === CAPABILITY_SURFACE && m.ADAPTERS === ADAPTERS && m.REUSE_CATEGORIES === REUSE_CATEGORIES && m.REUSE_CHECKLIST === REUSE_CHECKLIST && m.POWERFUL_COMMANDS === POWERFUL_COMMANDS && Object.keys(m.CAPABILITY_SURFACE).length === 6 && !/const CAPABILITY_SURFACE = \{/.test(read(__filename)); } },
|
|
3019
|
+
{ name: 'about: 정체성 verb(AI 운영 레이어) + MCP leerness_about 등록 (UR-0030 1.9.296)', run: () => { const id = _leernessIdentity(); const src = read(__filename); return typeof aboutCmd === 'function' && /운영 레이어/.test(id.identity) && id.layers.length === 5 && id.surface.mcpTools >= 81 && /name: 'leerness_about'/.test(src) && /case 'leerness_about':/.test(src) && /cmd === 'about' \|\| cmd === 'identity'/.test(src); } },
|
|
3007
3020
|
{ name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
|
|
3008
3021
|
];
|
|
3009
3022
|
}
|
|
@@ -16634,7 +16647,8 @@ function mcpServeCmd(root) {
|
|
|
16634
16647
|
{ name: 'leerness_state_record', description: '1.9.279 (UR-0031) — record_file_change / record_decision. 진행 중 run 에 변경 파일/명령/테스트/결정을 누적. 인자: { path?, filesChanged? (콤마), filesRead?, commands?, tests?, errors?, decision? }. 응답: { recorded, run }.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, filesChanged: { type: 'string' }, filesRead: { type: 'string' }, commands: { type: 'string' }, tests: { type: 'string' }, errors: { type: 'string' }, decision: { type: 'string' } } } },
|
|
16635
16648
|
{ name: 'leerness_state_verify', description: '1.9.279 (UR-0031) — request_verification / verify_done. 현재 run 의 검증 결과 기록. 인자: { path?, result (required: "pass"|"fail"), note? }. 응답: { verified, result, run }.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, result: { type: 'string', enum: ['pass', 'fail'] }, note: { type: 'string' } }, required: ['result'] } },
|
|
16636
16649
|
{ name: 'leerness_state_handoff', description: '1.9.279 (UR-0031) — create_handoff / make_handoff. 현재 run 을 마감하고 다음 에이전트용 .leerness/handoff/latest.{md,json} 작성 (Claude→Goose→Codex 인수인계 표준). 인자: { path?, summary (required) }. 응답: { handoff, run }.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, summary: { type: 'string' } }, required: ['summary'] } },
|
|
16637
|
-
{ name: 'leerness_get_project_context', description: '1.9.292 (UR-0031) — get_project_context. 외부 에이전트가 작업 시작 전 단 1콜로 "지금 무엇을 알아야 하는가"를 파악하는 집약 컨텍스트. 여러 소스(현재 작업/미답 사용자 요청/최근 결정/활성 룰/next-actions/memory surface/프로젝트 의도)를 한 번에 구조화 회수. read-only. 인자: { path? }. 응답: { version, project, currentTask, openRequests, recentDecisions, activeRules, nextActions, memory }.', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } }
|
|
16650
|
+
{ name: 'leerness_get_project_context', description: '1.9.292 (UR-0031) — get_project_context. 외부 에이전트가 작업 시작 전 단 1콜로 "지금 무엇을 알아야 하는가"를 파악하는 집약 컨텍스트. 여러 소스(현재 작업/미답 사용자 요청/최근 결정/활성 룰/next-actions/memory surface/프로젝트 의도)를 한 번에 구조화 회수. read-only. 인자: { path? }. 응답: { version, project, currentTask, openRequests, recentDecisions, activeRules, nextActions, memory }.', inputSchema: { type: 'object', properties: { path: { type: 'string' } } } },
|
|
16651
|
+
{ name: 'leerness_about', description: '1.9.296 (UR-0030) — leerness 정체성/포지셔닝 회수. leerness 가 무엇인가: "AI 에이전트 운영 레이어"(실행기 아님) — 기억·정책·인수인계·검증·감사 5계층. read-only. 어떤 에이전트든 "이 도구가 무엇이고 무엇을 보완하는가"를 1콜로 파악. 응답: { identity, isNot, tagline, layers[], complements, entryPoints, surface }.', inputSchema: { type: 'object', properties: {} } }
|
|
16638
16652
|
];
|
|
16639
16653
|
|
|
16640
16654
|
function send(obj) {
|
|
@@ -16887,6 +16901,9 @@ function mcpServeCmd(root) {
|
|
|
16887
16901
|
case 'leerness_get_project_context':
|
|
16888
16902
|
cliArgs = ['context', '--path', targetPath, '--json'];
|
|
16889
16903
|
break;
|
|
16904
|
+
case 'leerness_about':
|
|
16905
|
+
cliArgs = ['about', '--json'];
|
|
16906
|
+
break;
|
|
16890
16907
|
default:
|
|
16891
16908
|
return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name}` } });
|
|
16892
16909
|
}
|
|
@@ -18104,6 +18121,56 @@ function _splitList(v) { return String(v || '').split(',').map(s => s.trim()).fi
|
|
|
18104
18121
|
// 1.9.292 (UR-0031): get_project_context — 외부 에이전트 온보딩용 단일 집약 컨텍스트.
|
|
18105
18122
|
// 1콜로 현재 작업/미답 요청/최근 결정/활성 룰/next-actions/memory/프로젝트 의도를 구조화 회수.
|
|
18106
18123
|
// MCP leerness_get_project_context 가 이 명령(--json)을 호출. handoff(인간용 장문)와 달리 기계 친화 lean payload.
|
|
18124
|
+
// 1.9.296 (UR-0030, GPT-5.5 범용 하네스 전략): leerness 정체성 = 'AI 에이전트 운영 레이어'.
|
|
18125
|
+
// 실행기가 아니라 기억·정책·인수인계·검증·감사의 공통 계층. 어떤 AI 코딩 에이전트 위에도 얹힌다.
|
|
18126
|
+
// _leernessIdentity() 단일 출처 — about 명령 / MCP leerness_about / README 정체성 섹션이 공유.
|
|
18127
|
+
function _leernessIdentity() {
|
|
18128
|
+
let adapterIds = [];
|
|
18129
|
+
try { adapterIds = Object.keys(ADAPTERS); } catch {}
|
|
18130
|
+
let providerCount = 0;
|
|
18131
|
+
try { providerCount = EXTERNAL_AGENTS.length; } catch {}
|
|
18132
|
+
return {
|
|
18133
|
+
name: 'leerness',
|
|
18134
|
+
version: VERSION,
|
|
18135
|
+
identity: 'AI 에이전트 운영 레이어 (AI agent operating layer)',
|
|
18136
|
+
isNot: '실행기/코딩 에이전트가 아님 — 어떤 에이전트 위에도 얹는 공통 운영 계층',
|
|
18137
|
+
tagline: '어떤 AI 코딩 에이전트에도 적용되는 범용 운영 레이어 — 기억·정책·인수인계·검증·감사',
|
|
18138
|
+
layers: [
|
|
18139
|
+
{ key: 'memory', ko: '기억', desc: '프로젝트 상태/결정/진행을 .leerness/ 에 영속화 (state start|record|verify|handoff)' },
|
|
18140
|
+
{ key: 'policy', ko: '정책', desc: '8단계 권한 등급 + enforce (read-only→publish), MCP 호출 게이트' },
|
|
18141
|
+
{ key: 'handoff', ko: '인수인계', desc: '에이전트 간 컨텍스트 표준 전달 (Claude→Codex→Goose), get_project_context 1콜 온보딩' },
|
|
18142
|
+
{ key: 'verification', ko: '검증', desc: '근거 기반 완료 검증 (verify-claim --require-evidence) — 허위 완료 차단' },
|
|
18143
|
+
{ key: 'audit', ko: '감사', desc: 'drift/idempotency/secret/encoding 자동 감사 + self-heal (--auto-fix)' }
|
|
18144
|
+
],
|
|
18145
|
+
complements: 'AGENTS.md(정적 지침)을 대체하지 않고 보완 — 정적 규칙/명령/금지는 AGENTS.md, 동적 상태·기억·검증·인수인계는 leerness',
|
|
18146
|
+
entryPoints: { context: 'leerness context (MCP get_project_context)', mcp: 'leerness mcp serve', adapter: 'leerness adapter <tool>' },
|
|
18147
|
+
surface: { mcpTools: _mcpToolCount(), adapters: adapterIds, providers: providerCount, runtimeDeps: 0, offlineFirst: true }
|
|
18148
|
+
};
|
|
18149
|
+
}
|
|
18150
|
+
function aboutCmd(opts = {}) {
|
|
18151
|
+
const id = _leernessIdentity();
|
|
18152
|
+
if (opts.json || has('--json')) { process.stdout.write(JSON.stringify(id, null, 2) + '\n'); return id; }
|
|
18153
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
18154
|
+
const cy = s => isTty ? `\x1b[36m${s}\x1b[0m` : s;
|
|
18155
|
+
const gr = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
18156
|
+
const dm = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
18157
|
+
log(cy(`# ${id.name} v${id.version} — ${id.identity}`));
|
|
18158
|
+
log('');
|
|
18159
|
+
log(` ${id.tagline}`);
|
|
18160
|
+
log(dm(` ✗ ${id.isNot}`));
|
|
18161
|
+
log('');
|
|
18162
|
+
log(gr('## 5 운영 계층 (Memory · Policy · Handoff · Verification · Audit)'));
|
|
18163
|
+
id.layers.forEach(l => log(` • ${l.ko} (${l.key}) — ${l.desc}`));
|
|
18164
|
+
log('');
|
|
18165
|
+
log(gr('## 보완 관계'));
|
|
18166
|
+
log(` ${id.complements}`);
|
|
18167
|
+
log('');
|
|
18168
|
+
log(gr('## 진입점'));
|
|
18169
|
+
Object.values(id.entryPoints).forEach(e => log(dm(` • ${e}`)));
|
|
18170
|
+
log('');
|
|
18171
|
+
log(`표면: MCP ${id.surface.mcpTools} 도구 · 어댑터 ${id.surface.adapters.length} · provider ${id.surface.providers} · 런타임 의존성 ${id.surface.runtimeDeps} · offline-first ${id.surface.offlineFirst ? '✓' : '✗'}`);
|
|
18172
|
+
return id;
|
|
18173
|
+
}
|
|
18107
18174
|
function contextCmd(root, opts = {}) {
|
|
18108
18175
|
root = absRoot(root);
|
|
18109
18176
|
const rows = readProgressRows(root);
|
|
@@ -21350,6 +21417,7 @@ async function main() {
|
|
|
21350
21417
|
// 1.9.278 (UR-0032): leerness state <show|start|record|verify|handoff> — .leerness/ 구조화 상태 substrate
|
|
21351
21418
|
if (cmd === 'state') return stateCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
21352
21419
|
if (cmd === 'context') return contextCmd(arg('--path', process.cwd()), { json: has('--json') });
|
|
21420
|
+
if (cmd === 'about' || cmd === 'identity') return aboutCmd({ json: has('--json') });
|
|
21353
21421
|
// 1.9.281 (UR-0034): leerness policy <show|set|check> — 권한 등급 (opt-in enforced)
|
|
21354
21422
|
if (cmd === 'policy') return policyCmd(arg('--path', process.cwd()), args[1], ...args.slice(2));
|
|
21355
21423
|
// 1.9.285 (UR-0023): leerness reuse-check "<기능>" — 외부 OSS 빌드 vs 재사용 결정 게이트 (오프라인)
|
package/package.json
CHANGED
package/scripts/e2e.js
CHANGED
|
@@ -3225,5 +3225,29 @@ total++;
|
|
|
3225
3225
|
if (!ok) failed++;
|
|
3226
3226
|
}
|
|
3227
3227
|
|
|
3228
|
+
// 1.9.296 회귀 (UR-0030): leerness about — 정체성(AI 운영 레이어) verb + MCP + README 섹션
|
|
3229
|
+
total++;
|
|
3230
|
+
{
|
|
3231
|
+
let ok = false;
|
|
3232
|
+
try {
|
|
3233
|
+
const r = cp.spawnSync(process.execPath, [CLI, 'about', '--json'], { cwd: tmp, encoding: 'utf8', timeout: 20000 });
|
|
3234
|
+
const j = JSON.parse(r.stdout);
|
|
3235
|
+
const structOk = r.status === 0 && /운영 레이어/.test(j.identity) && Array.isArray(j.layers) && j.layers.length === 5 &&
|
|
3236
|
+
j.layers.every(l => l.key && l.ko && l.desc) && j.complements && j.surface && typeof j.surface.mcpTools === 'number' &&
|
|
3237
|
+
j.surface.runtimeDeps === 0 && /AGENTS\.md/.test(j.complements);
|
|
3238
|
+
// MCP tools/list 에 leerness_about 노출 (81 도구)
|
|
3239
|
+
const ml = cp.spawnSync(process.execPath, [CLI, 'mcp', 'serve'], { cwd: tmp, encoding: 'utf8', timeout: 15000, input: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list' }) + '\n' });
|
|
3240
|
+
const names = JSON.parse(ml.stdout.split('\n').filter(Boolean)[0]).result.tools.map(t => t.name);
|
|
3241
|
+
const mcpOk = names.includes('leerness_about') && names.length >= 81;
|
|
3242
|
+
// README 정체성 섹션: readme sync 후 tmp/README.md 에 섹션 생성 확인
|
|
3243
|
+
cp.spawnSync(process.execPath, [CLI, 'readme', 'sync', tmp], { cwd: tmp, encoding: 'utf8', timeout: 20000 });
|
|
3244
|
+
const rd = fs.existsSync(path.join(tmp, 'README.md')) ? fs.readFileSync(path.join(tmp, 'README.md'), 'utf8') : '';
|
|
3245
|
+
const readmeOk = /정체성 — AI 에이전트 운영 레이어/.test(rd);
|
|
3246
|
+
ok = structOk && mcpOk && readmeOk;
|
|
3247
|
+
} catch {}
|
|
3248
|
+
console.log(ok ? '✓ B(1.9.296) leerness about: 정체성 verb + MCP leerness_about(81) + README 섹션 (UR-0030)' : '✗ about 정체성 verb 실패');
|
|
3249
|
+
if (!ok) failed++;
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3228
3252
|
console.log(`\nE2E result: ${total - failed}/${total} passed · ${((Date.now() - _e2eStart) / 1000).toFixed(0)}s`);
|
|
3229
3253
|
if (failed > 0) process.exit(1);
|