leerness 1.36.56 → 1.36.58
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 +20 -0
- package/README.md +4 -4
- package/bin/leerness.js +129 -2
- package/lib/mcp-tools.js +16 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.36.58 — 2026-07-21 — MCP core 프로필 (외부감사 F-09 종결) — R-0001 검수 3회전
|
|
4
|
+
|
|
5
|
+
86종 전체 tools/list(약 45KB)가 세션 시작 토큰/도구 선택 혼선을 키우는 클라이언트용 경량 프로필.
|
|
6
|
+
|
|
7
|
+
- **`leerness mcp serve --profile core`** (또는 `LEERNESS_MCP_PROFILE=core`): 핵심 20종만 노출 — 에이전트 1세션 필수 루프(handoff→기억 CRUD→verify→인수인계) + 상태 substrate + get_project_context/about/brief. 비노출 도구 호출은 -32601 일관 거부(노출=호출가능). **기본 full 무변경**(검수 실측: tools/list 바이트 동일).
|
|
8
|
+
- (검수 Medium) 오타 프로필 fail-open 차단 — core/full 외에는 exit 1 거부(제한 요청의 무언 무력화 방지). (검수 Low) CORE 를 비열거+freeze — for..in/Object.keys 소비자 오인 차단.
|
|
9
|
+
- 검증: 검수 통과 프로브(20종 전원 _mcpToCliArgs 해석·policy 동일 적용·initialize/ping 불변·README 배지 86 유지·CORE 무누출), selftest 331(+1), 게이트.
|
|
10
|
+
- 외부 GPT 감사 백로그 정리: P0 5건 + P1 중 F-04/F-06/F-09 종결 — 잔여 F-05(en 완전 번역)는 규모상 별도 시리즈.
|
|
11
|
+
|
|
12
|
+
## 1.36.57 — 2026-07-21 — integrity check --repair: managed 문서 무결성 복구 (외부감사 F-04) — R-0001 검수 2회전
|
|
13
|
+
|
|
14
|
+
drift(신선도)와 별개로 "파일 자체가 잘리거나 사라진" 손상을 감지/복구. R-0001 codex 검수가 High 2 포함 5건을 지적 — 전건 재현·보정 후 재검(minimal 오판·repair 실패 exit 0 는 검수 없이는 출하됐을 결함).
|
|
15
|
+
|
|
16
|
+
- **`leerness integrity check [--repair] [--force] [--json]`**: 정책-문서 12종(사용자 데이터 표면 제외) — 부재/H1 전무/템플릿 40% 미만 절단 감지. --repair 는 원본 archive 대피(pid+seq 접미, 검수 #4) 후 현재 버전 템플릿 재생성.
|
|
17
|
+
- (검수 #1 High) **minimal 설치 존중**: manifest.minimal 반영 — minimal 이 뺀 6종을 '부재 손상' 오판/재생성하지 않음(6종만 검사).
|
|
18
|
+
- (검수 #2 High) **repair 실패 = exit 1**: 종전엔 복구 실패(EEXIST 등)에도 exit 0.
|
|
19
|
+
- (검수 #3) **오탐 완화**: H1 판정을 "H1 전무"로(제목 번역/개명 무탐), 길이-단독 신호(truncated)는 advisory — --force 없인 복구/exit 비관여(합리적 축약 보호).
|
|
20
|
+
- (검수 #5) unknown 하위명령 JSON 오류 + templateBytes 실제 바이트.
|
|
21
|
+
- 실측: 감사 시나리오(context-routing 절단) 감지→복구, 사용자 추가 편집 무탐, en/ko 라운드트립 클린. selftest 330(+1).
|
|
22
|
+
|
|
3
23
|
## 1.36.56 — 2026-07-21 — 시크릿 스캐너 F-06 (외부감사 P1) + 매 라운드 codex 검수 룰 (R-0001, 사용자 지시)
|
|
4
24
|
|
|
5
25
|
사용자 지시로 영구 룰 R-0001(every-round: 출하 전 codex 교차 검수) 등록 — 이 릴리스가 첫 적용: 1차 구현 → codex 검수가 4건 지적 → 전건 재현 확인 후 보정 → 재검.
|
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ MIT
|
|
|
122
122
|
<!-- leerness:project-readme:start -->
|
|
123
123
|
## Leerness Project Harness
|
|
124
124
|
|
|
125
|
-
이 프로젝트는 Leerness v1.36.
|
|
125
|
+
이 프로젝트는 Leerness v1.36.58 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
|
|
126
126
|
|
|
127
127
|
### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
|
|
128
128
|
|
|
@@ -176,7 +176,7 @@ leerness memory restore decision <date|title>
|
|
|
176
176
|
|
|
177
177
|
### MCP server (외부 AI 통합)
|
|
178
178
|
|
|
179
|
-
Leerness v1.36.
|
|
179
|
+
Leerness v1.36.58는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
|
|
180
180
|
|
|
181
181
|
```jsonc
|
|
182
182
|
// 카테고리별
|
|
@@ -197,7 +197,7 @@ Leerness v1.36.56는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
|
|
|
197
197
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
198
198
|
1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) 회귀 테스트 갱신 → 4) 전체 e2e 스위트 통과 → 5) npm publish + git tag → 6) main push → 7) session close → 8) 다음 라운드 예약.
|
|
199
199
|
|
|
200
|
-
현재 누적: **v1.9.x → 1.36.
|
|
200
|
+
현재 누적: **v1.9.x → 1.36.58 릴리스 태그 이력** (수백 라운드) · _reports/는 비공개 보존.
|
|
201
201
|
|
|
202
202
|
### 성능 가이드
|
|
203
203
|
|
|
@@ -235,6 +235,6 @@ leerness release pack --close --auto-main-push
|
|
|
235
235
|
- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
|
|
236
236
|
- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
|
|
237
237
|
|
|
238
|
-
Last synced by Leerness v1.36.
|
|
238
|
+
Last synced by Leerness v1.36.58: 2026-07-22
|
|
239
239
|
<!-- leerness:project-readme:end -->
|
|
240
240
|
|
package/bin/leerness.js
CHANGED
|
@@ -34,7 +34,7 @@ const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE
|
|
|
34
34
|
const { tokenizeForRank: _tokenizeForRank, expandQuery: _expandQuery, scoreHits: _scoreHits, suggestTerms: _suggestTerms } = require('../lib/search-core'); // 1.36.23: memory search 랭킹 코어(순수·0-deps)
|
|
35
35
|
const { findCorruptedStateJson: _findCorruptedStateJson } = require('../lib/state-integrity'); // 1.36.1 (클린룸 리뷰 FN): .harness/*.json 상태 무결성 (audit/health/check 공유)
|
|
36
36
|
|
|
37
|
-
const VERSION = '1.36.
|
|
37
|
+
const VERSION = '1.36.58';
|
|
38
38
|
|
|
39
39
|
// 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
|
|
40
40
|
// 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
|
|
@@ -5153,6 +5153,45 @@ function _selfTestCases() {
|
|
|
5153
5153
|
const srcOk = read(__filename).includes('_seenAt.has(_valKey)') && read(__filename).includes('_giMatch(fileRel)');
|
|
5154
5154
|
return unknownOk && sameTokenOnce && distinctKept && extlessGuard && srcOk;
|
|
5155
5155
|
} finally { try { fs.rmSync(tmp, { recursive: true, force: true }); } catch {} }
|
|
5156
|
+
} },
|
|
5157
|
+
{ name: 'integrity check/repair (1.36.57, 외부감사 F-04): 절단/부재 감지 → archive 대피 후 템플릿 재생성 · 사용자 추가편집 무탐 — 행위검사', run: () => {
|
|
5158
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), '__leerness_int_'));
|
|
5159
|
+
const _w = process.stdout.write; const saveArgv = process.argv; const saveExit = process.exitCode;
|
|
5160
|
+
try {
|
|
5161
|
+
process.stdout.write = () => true;
|
|
5162
|
+
fs.mkdirSync(path.join(tmp, '.harness'), { recursive: true });
|
|
5163
|
+
const tf = coreFiles(tmp, 'ko', [], {});
|
|
5164
|
+
for (const k of _INTEGRITY_DOCS) fs.mkdirSync(path.dirname(path.join(tmp, k)), { recursive: true }), fs.writeFileSync(path.join(tmp, k), tf[k]);
|
|
5165
|
+
fs.writeFileSync(path.join(tmp, '.harness', 'manifest.json'), '{"language":"ko"}');
|
|
5166
|
+
// 손상 주입: 절단 + 삭제 / 사용자 추가 편집(무탐 대상)
|
|
5167
|
+
fs.writeFileSync(path.join(tmp, '.harness', 'context-routing.md'), 'x');
|
|
5168
|
+
fs.rmSync(path.join(tmp, '.harness', 'guardrails.md'));
|
|
5169
|
+
fs.appendFileSync(path.join(tmp, '.harness', 'testing-strategy.md'), '\n## 커스텀 절차\n- 내 규칙\n');
|
|
5170
|
+
process.argv = ['node', 'x', 'integrity', 'check'];
|
|
5171
|
+
process.exitCode = 0; integrityCmd(tmp);
|
|
5172
|
+
const detected = process.exitCode === 1;
|
|
5173
|
+
process.argv = ['node', 'x', 'integrity', 'check', '--repair'];
|
|
5174
|
+
process.exitCode = 0; integrityCmd(tmp);
|
|
5175
|
+
const routing = fs.readFileSync(path.join(tmp, '.harness', 'context-routing.md'), 'utf8');
|
|
5176
|
+
const repaired = routing.includes('# Context Routing') && fs.existsSync(path.join(tmp, '.harness', 'guardrails.md'));
|
|
5177
|
+
const backed = fs.readdirSync(path.join(tmp, '.harness', 'archive')).some(n => n.startsWith('integrity-context-routing'));
|
|
5178
|
+
const customKept = fs.readFileSync(path.join(tmp, '.harness', 'testing-strategy.md'), 'utf8').includes('커스텀 절차');
|
|
5179
|
+
process.argv = ['node', 'x', 'integrity', 'check'];
|
|
5180
|
+
process.exitCode = 0; integrityCmd(tmp);
|
|
5181
|
+
const cleanAfter = process.exitCode !== 1;
|
|
5182
|
+
return detected && repaired && backed && customKept && cleanAfter;
|
|
5183
|
+
} finally { process.stdout.write = _w; process.argv = saveArgv; process.exitCode = saveExit; try { fs.rmSync(tmp, { recursive: true, force: true }); } catch {} }
|
|
5184
|
+
} },
|
|
5185
|
+
{ name: 'MCP core 프로필 (1.36.58, 외부감사 F-09): CORE 20종 전원 실존 + 필수 루프 포함 + 기본 full 무변경 — 행위검사', run: () => {
|
|
5186
|
+
const m = require('../lib/mcp-tools');
|
|
5187
|
+
const names = new Set(m.map(t => t.name));
|
|
5188
|
+
const allExist = Array.isArray(m.CORE) && m.CORE.length >= 15 && m.CORE.length < m.length && m.CORE.every(n => names.has(n));
|
|
5189
|
+
const loop = ['leerness_handoff', 'leerness_session_close', 'leerness_verify_claim', 'leerness_state_handoff', 'leerness_get_project_context'].every(n => m.CORE.includes(n));
|
|
5190
|
+
// CORE 프로퍼티가 배열 직렬화를 오염하지 않음 (tools/list JSON 에 CORE 미포함)
|
|
5191
|
+
const cleanSer = !JSON.stringify(m).includes('"CORE"');
|
|
5192
|
+
const s = read(__filename);
|
|
5193
|
+
const wired = s.includes("_profile === 'core' ? _ALL_TOOLS.filter") && s.includes("Unknown tool: ${name} (core profile");
|
|
5194
|
+
return allExist && loop && cleanSer && wired;
|
|
5156
5195
|
} }
|
|
5157
5196
|
];
|
|
5158
5197
|
}
|
|
@@ -5526,6 +5565,79 @@ function anchorsCmd(root, sub) {
|
|
|
5526
5565
|
fail(`알 수 없는 하위명령: ${sub} (가능: status, draft [--apply])`);
|
|
5527
5566
|
}
|
|
5528
5567
|
|
|
5568
|
+
// 1.36.57 (외부 GPT 감사 F-04): managed 정책-문서 무결성 점검/복구 — drift(신선도)와 별개로 "파일 자체가
|
|
5569
|
+
// 잘리거나 사라진" 손상을 감지한다. 대상은 사용자가 편집하지 않는 순수 템플릿 문서군만(사용자 데이터 표면 제외 —
|
|
5570
|
+
// plan/progress/brief/decisions 등은 절대 건드리지 않음). 판정은 보수적: 부재 / H1 상실 / 템플릿 대비 40% 미만 크기.
|
|
5571
|
+
// --repair 는 손상 원본을 .harness/archive/ 로 대피 후 현재 버전 템플릿으로 재생성.
|
|
5572
|
+
const _INTEGRITY_DOCS = [
|
|
5573
|
+
'.harness/session-workflow.md', '.harness/context-routing.md', '.harness/writeback-policy.md',
|
|
5574
|
+
'.harness/task-type-map.md', '.harness/protected-files.md', '.harness/guardrails.md',
|
|
5575
|
+
'.harness/consistency-policy.md', '.harness/testing-strategy.md', '.harness/review-checklist.md',
|
|
5576
|
+
'.harness/release-checklist.md', '.harness/session-close-policy.md', '.harness/plan-progress-boundary.md',
|
|
5577
|
+
];
|
|
5578
|
+
function integrityCmd(root) {
|
|
5579
|
+
root = absRoot(root);
|
|
5580
|
+
const json = has('--json');
|
|
5581
|
+
const repair = has('--repair');
|
|
5582
|
+
if (!exists(path.join(root, '.harness'))) { failJson(json, 'harness_missing', `leerness 미설치: ${root} — 먼저 leerness init`); return; }
|
|
5583
|
+
let lang = 'ko', minimal = false;
|
|
5584
|
+
try { const mf = JSON.parse(read(path.join(root, '.harness', 'manifest.json'))); lang = mf.language || 'ko'; minimal = !!mf.minimal; } catch {}
|
|
5585
|
+
// (검수 #1) minimal 설치 존중 — minimal 이 의도적으로 뺀 문서를 '부재 손상'으로 오판/재생성하지 않는다
|
|
5586
|
+
const templates = coreFiles(root, lang, [], { minimal });
|
|
5587
|
+
const docs = _INTEGRITY_DOCS.filter(k => typeof templates[k] === 'string');
|
|
5588
|
+
const findings = []; const repaired = []; let repairFailed = false;
|
|
5589
|
+
const force = has('--force');
|
|
5590
|
+
for (const key of docs) {
|
|
5591
|
+
const tmpl = templates[key];
|
|
5592
|
+
const fp = path.join(root, key);
|
|
5593
|
+
let kind = null;
|
|
5594
|
+
if (!exists(fp)) kind = 'missing';
|
|
5595
|
+
else {
|
|
5596
|
+
let cur = ''; try { cur = read(fp); } catch { kind = 'unreadable'; }
|
|
5597
|
+
if (!kind) {
|
|
5598
|
+
// (검수 #3) H1 상실 = "H1 이 하나도 없음"(정확 일치 아님 — 사용자가 제목을 번역/개명해도 무탐)
|
|
5599
|
+
if (!cur.split('\n').some(l => /^# \S/.test(l.trim()))) kind = 'h1_lost';
|
|
5600
|
+
else if (cur.length < tmpl.length * 0.4) kind = 'truncated';
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
5603
|
+
if (!kind) continue;
|
|
5604
|
+
// (검수 #3) 길이-단독 신호(truncated)는 advisory — --force 없인 복구도 exit 1 도 아님 (합리적 축약 오판 방지)
|
|
5605
|
+
const advisory = kind === 'truncated' && !force;
|
|
5606
|
+
const f = { file: key, kind, advisory, templateBytes: Buffer.byteLength(tmpl, 'utf8') };
|
|
5607
|
+
if (repair && !advisory) {
|
|
5608
|
+
try {
|
|
5609
|
+
if (exists(fp)) {
|
|
5610
|
+
const bakDir = path.join(root, '.harness', 'archive');
|
|
5611
|
+
mkdirp(bakDir);
|
|
5612
|
+
// (검수 #4) 같은 ms 백업 충돌 방지 — pid+시퀀스 접미
|
|
5613
|
+
fs.copyFileSync(fp, path.join(bakDir, `integrity-${path.basename(key)}-${Date.now()}-${process.pid}-${++_integSeq}.bak`));
|
|
5614
|
+
f.backedUp = true;
|
|
5615
|
+
}
|
|
5616
|
+
writeUtf8(fp, tmpl);
|
|
5617
|
+
f.repaired = true; repaired.push(key);
|
|
5618
|
+
} catch (e) { f.repaired = false; f.error = String(e.message || e).slice(0, 120); repairFailed = true; }
|
|
5619
|
+
}
|
|
5620
|
+
findings.push(f);
|
|
5621
|
+
}
|
|
5622
|
+
// (검수 #2) 실패한 repair 는 성공이 아니다 — hard 손상 잔존 또는 복구 실패 시 exit 1 (advisory 는 exit 무영향)
|
|
5623
|
+
const hardLeft = findings.filter(f => !f.advisory && !f.repaired);
|
|
5624
|
+
if (json) {
|
|
5625
|
+
log(JSON.stringify({ ok: !repairFailed && hardLeft.length === 0, checked: docs.length, minimal, findings, repaired }, null, 2));
|
|
5626
|
+
if (repairFailed || hardLeft.length) process.exitCode = 1;
|
|
5627
|
+
return;
|
|
5628
|
+
}
|
|
5629
|
+
log(`# leerness integrity — managed 정책-문서 무결성 (${docs.length}종 검사${minimal ? ' · minimal' : ''})`);
|
|
5630
|
+
if (!findings.length) { ok(' 손상 없음 — 전 문서 구조 정상'); return; }
|
|
5631
|
+
for (const f of findings) {
|
|
5632
|
+
const icon = f.repaired ? '🔧 복구' : (f.advisory ? '⚠ 의심' : '✗ 손상');
|
|
5633
|
+
log(` ${icon} ${f.file} (${f.kind})${f.repaired && f.backedUp ? ' — 원본은 .harness/archive/ 대피' : ''}${f.advisory ? ' — 길이-단독 신호(advisory): 복구하려면 --repair --force' : ''}${f.error ? ` — 복구 실패: ${f.error}` : ''}`);
|
|
5634
|
+
}
|
|
5635
|
+
if (hardLeft.length && !repair) warn(` 복구: leerness integrity check --repair (손상 원본은 archive 로 대피 후 템플릿 재생성)`);
|
|
5636
|
+
if (repairFailed || hardLeft.length) process.exitCode = 1;
|
|
5637
|
+
return;
|
|
5638
|
+
}
|
|
5639
|
+
let _integSeq = 0;
|
|
5640
|
+
|
|
5529
5641
|
// 1.36.28 (codex 미검토표면 헌트 #3 — 데이터 유실 클래스): 손상된 JSON 스토어를 "빈 값"으로 오인해 덮어쓰는 fail-open 방지.
|
|
5530
5642
|
// 파일이 "없음"과 "있으나 손상"을 구분 — 후자는 파싱 실패를 던져 변경(저장)을 거부하고 원본을 보존한다.
|
|
5531
5643
|
// 설계: LOAD 가 아니라 SAVE/변경 진입점에서만 던진다(handoff 등 비변경 읽기 경로는 resilient 유지). state 는
|
|
@@ -6293,6 +6405,7 @@ function commandsCmd(root) {
|
|
|
6293
6405
|
{ cmd: 'review-request "<request>"', desc: '사용자 요청 사전 검토 (1.9.176)' },
|
|
6294
6406
|
{ cmd: 'clarify "<사용자 요청>" [--json]', desc: '요청 모호성 신호 감지 → 사용자에게 물을 질문 생성 (추측 구현 방지) — 1.36.51 UR-0061' },
|
|
6295
6407
|
{ cmd: 'tech [--json]', desc: '기술 프로필 — 개발 언어·연결 서비스 자동 감지 + 마이그레이션/언어전환 이력, 그래프 🛠 탭 표시 — 1.36.53 UR-0062' },
|
|
6408
|
+
{ cmd: 'integrity check [--repair] [--json]', desc: 'managed 정책-문서 12종 무결성(부재/H1 상실/절단) 점검 — --repair: archive 대피 후 템플릿 재생성 — 1.36.57 감사 F-04' },
|
|
6296
6409
|
{ cmd: 'preview add|list|show|approve|revise', desc: '신규 기능 미리보기 승인 워크플로 — approve 전 코드 작성 금지 계약 — 1.36.51 UR-0061' },
|
|
6297
6410
|
{ cmd: 'review <file> --persona <ids>', desc: '페르소나 리뷰 (1.9.29)' },
|
|
6298
6411
|
{ cmd: 'brainstorm "<topic>" [--include-code]', desc: '워크스페이스 회수 + 코드 grep' }
|
|
@@ -18451,7 +18564,13 @@ function mcpServeCmd(root) {
|
|
|
18451
18564
|
root = absRoot(root || process.cwd());
|
|
18452
18565
|
// 노출할 leerness 도구 목록
|
|
18453
18566
|
// 1.9.297 (UR-0025 5단계): MCP 도구 정의를 lib/mcp-tools.js 단일출처로 분리 (Codex #5 regex self-count 영구 해소).
|
|
18454
|
-
const
|
|
18567
|
+
const _ALL_TOOLS = require('../lib/mcp-tools');
|
|
18568
|
+
// 1.36.58 (외부 GPT 감사 F-09): core 프로필 — 86종 전체(약 45KB tools/list)가 세션 시작 토큰/도구 선택 혼선을
|
|
18569
|
+
// 키우는 클라이언트를 위해 핵심 20종만 노출. opt-in(--profile core / LEERNESS_MCP_PROFILE=core), 기본 full 무변경.
|
|
18570
|
+
const _profile = String(arg('--profile', null) || process.env.LEERNESS_MCP_PROFILE || 'full').trim().toLowerCase();
|
|
18571
|
+
// (검수) 오타 프로필이 무언 full 로 새지 않게 — 제한 요청이 조용히 무력화되는 fail-open 차단
|
|
18572
|
+
if (_profile !== 'core' && _profile !== 'full') { fail(`알 수 없는 MCP 프로필: ${_profile} (가능: core, full)`); return process.exit(1); }
|
|
18573
|
+
const TOOLS = _profile === 'core' ? _ALL_TOOLS.filter(t => _ALL_TOOLS.CORE.includes(t.name)) : _ALL_TOOLS;
|
|
18455
18574
|
|
|
18456
18575
|
function send(obj) {
|
|
18457
18576
|
process.stdout.write(JSON.stringify(obj) + '\n');
|
|
@@ -18491,6 +18610,10 @@ function mcpServeCmd(root) {
|
|
|
18491
18610
|
return send({ jsonrpc: '2.0', id, error: { code: -32602, message: 'Invalid params: arguments must be an object' } });
|
|
18492
18611
|
}
|
|
18493
18612
|
const args = _rawArgs || {};
|
|
18613
|
+
// 1.36.58 (F-09): core 프로필에서는 노출 집합 = 호출 가능 집합 (광고 안 한 도구 호출은 unknown 과 동일 처리)
|
|
18614
|
+
if (_profile === 'core' && !TOOLS.some(t => t.name === name)) {
|
|
18615
|
+
return send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown tool: ${name} (core profile — full: leerness mcp serve --profile full)` } });
|
|
18616
|
+
}
|
|
18494
18617
|
// 1.36.39 (#3): 도구 inputSchema 기반 타입 검증 — {"title":{...}} 같은 비문자열이 "[object Object]" 로 영속되던 것 차단.
|
|
18495
18618
|
{
|
|
18496
18619
|
const _td = TOOLS.find(t => t.name === name);
|
|
@@ -22658,6 +22781,10 @@ async function main() {
|
|
|
22658
22781
|
if (cmd === 'anchors') return anchorsCmd(arg('--path', null) || _taskPositionalPath(args, 1) || process.cwd(), args[1] && !args[1].startsWith('-') ? args[1] : null); // 1.36.36: 정체성앵커 초안
|
|
22659
22782
|
if (cmd === 'toggle') return _tgl.toggleCmd(arg('--path', process.cwd()), args[1], args[2], args[3], { has, VERSION }); // 1.36.30: 기능 토글 (그래프 ⚙ 탭 연동)
|
|
22660
22783
|
if (cmd === 'tech') return _tech.techCmd(arg('--path', null) || _taskPositionalPath(args, 2) || process.cwd(), args[1], { has }); // 1.36.53 (UR-0062): 기술 프로필
|
|
22784
|
+
if (cmd === 'integrity') { // 1.36.57 (감사 F-04): managed 문서 무결성 점검/복구
|
|
22785
|
+
if (args[1] && args[1] !== 'check') { failJson(has('--json'), 'unknown_subcommand', `알 수 없는 integrity 하위명령: ${args[1]} (가능: check [--repair] [--force])`); return process.exit(process.exitCode || 1); }
|
|
22786
|
+
return integrityCmd(arg('--path', null) || _taskPositionalPath(args, 2) || process.cwd());
|
|
22787
|
+
}
|
|
22661
22788
|
// 1.36.51 (사용자 요청 UR-0061): 모호성 질문 + 미리보기 승인 워크플로
|
|
22662
22789
|
if (cmd === 'clarify') return _clar.clarifyCmd(arg('--path', process.cwd()), args.slice(1).filter(x => !x.startsWith('-')).join(' '), { has });
|
|
22663
22790
|
if (cmd === 'preview') {
|
package/lib/mcp-tools.js
CHANGED
|
@@ -92,3 +92,19 @@ module.exports = [
|
|
|
92
92
|
{ name: 'leerness_honesty_check', requiredTier: 'read-only', description: '1.9.305 (사용자 명시) — AI 인식론적 정직성 점검. 주장/evidence 텍스트가 (1) 모르는 걸 아는 척(근거 없는 단정), (2) 검증 없는 섣부른 판단(추정+완료 결론), (3) 외부 정보 미수집(API/버전/스펙 언급+수집흔적 없음) 중 무엇에 해당하는지 휴리스틱 탐지. read-only. 에이전트가 자기 주장을 단언 전 self-check. 인자: { path?, taskId?, text? }. 응답: { ok, findings[], dimensions[], highCount }.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, taskId: { type: 'string' }, text: { type: 'string' } } } },
|
|
93
93
|
{ name: 'leerness_brief', requiredTier: 'read-only', description: '1.9.308 (UR-0055) — 프로젝트 청사진 회수. 프로젝트 개요/소개/목적/기능/스택/아키텍처/성공기준/방향이력을 구조화 반환(show) 또는 복사용 blueprint 텍스트(export=true). read-only. 외부 에이전트가 "이 프로젝트가 무엇이고 어디로 가는가"를 1콜로 파악하거나, 신규 프로젝트 계획으로 복사. 인자: { path?, export? }. 응답(show): { project, intro, purpose, features[], stack[], directionHistory[], ... }.', inputSchema: { type: 'object', properties: { path: { type: 'string' }, export: { type: 'boolean' } } } }
|
|
94
94
|
];
|
|
95
|
+
|
|
96
|
+
// 1.36.58 (외부 GPT 감사 F-09): core 프로필 — 세션 시작 토큰/도구 선택 비용을 줄이는 핵심 20종.
|
|
97
|
+
// `leerness mcp serve --profile core` (또는 LEERNESS_MCP_PROFILE=core) 에서 tools/list·tools/call 이 이 집합만 노출.
|
|
98
|
+
// 기본은 full(무변경). 선정 기준: 에이전트 1세션의 필수 루프(컨텍스트 적재→기억 CRUD→검증→인수인계) + 상태 substrate.
|
|
99
|
+
// (검수) 비열거 프로퍼티 — Object.keys/for..in 을 쓰는 미래 소비자가 87번째 '요소'로 오인하지 않게.
|
|
100
|
+
Object.defineProperty(module.exports, 'CORE', {
|
|
101
|
+
enumerable: false,
|
|
102
|
+
value: Object.freeze([
|
|
103
|
+
'leerness_handoff', 'leerness_session_close', 'leerness_get_project_context', 'leerness_about',
|
|
104
|
+
'leerness_task_add', 'leerness_task_update', 'leerness_task_list',
|
|
105
|
+
'leerness_decision_add', 'leerness_lesson_save', 'leerness_lessons', 'leerness_rule_list',
|
|
106
|
+
'leerness_verify_claim', 'leerness_lazy_detect', 'leerness_drift_check', 'leerness_health',
|
|
107
|
+
'leerness_state_show', 'leerness_state_start', 'leerness_state_record', 'leerness_state_handoff',
|
|
108
|
+
'leerness_brief',
|
|
109
|
+
]),
|
|
110
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.58",
|
|
4
4
|
"description": "The AI-coding operations layer that makes \"done\" require evidence — persistent memory, evidence-gated completion checks, and clean handoffs for any AI agent (Claude Code, Codex, Cursor). State lives as plain files in your repo. CLI + MCP, 0 runtime dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|