leerness 1.36.44 → 1.36.46
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 +4 -4
- package/bin/leerness.js +75 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.36.46 — 2026-07-16 — JSON 계약 완결 — persona/review/guide (codex 5차 #10 잔여 소진)
|
|
4
|
+
|
|
5
|
+
`--json` 을 광고하면서 마크다운/혼합 출력을 내던 마지막 3종 — MCP·자동화 소비자가 파싱 가능한 **단일 JSON 문서**로:
|
|
6
|
+
|
|
7
|
+
- **`persona show <id> --json`**: `{id, name, description, body}` (종전: 마크다운 방출) + 에러 경로 failJson 구조화.
|
|
8
|
+
- **`review <file> --persona … --json`**: `--emit json` 과 동치화 + **`prompts[]`(실제 리뷰 프롬프트 전문) 포함** — 종전 JSON 은 메타만 있어 소비자가 프롬프트를 재조립해야 했다.
|
|
9
|
+
- **`guide <target> --json`**: 하위 4섹션(impact/reuse/uiConsistency/lessons) 출력을 캡처해 `{target, query, date, sections}` 단일 객체로 집계 (종전: 사람용 헤딩+JSON 파편 혼합).
|
|
10
|
+
- 사람용 출력 3종 모두 무회귀. **이로써 codex 5차 헌트 10건 완전 소진(부분 이연 0).**
|
|
11
|
+
- **검증**: selftest 316/316, 3종 JSON.parse 실측 + 프롬프트 포함 확인, exit 전파형 게이트 e2e, 클린룸.
|
|
12
|
+
|
|
13
|
+
## 1.36.45 — 2026-07-16 — `adapter codex --global` — goal 모드까지 닿는 조건부 전역 지침 (사용자 버그 후속 2층)
|
|
14
|
+
|
|
15
|
+
1.36.43 enforce(커밋 관문)에 이은 **지침층 보완**: codex 는 프로젝트 AGENTS.md 를 안 읽는 모드(goal 모드 — 사용자 실측)에서도 **전역 `~/.codex/AGENTS.md` 는 읽는다**. 여기에 조건부 블록을 설치해 커버.
|
|
16
|
+
|
|
17
|
+
- **`leerness adapter codex --global [--remove]`**: 마커 블록(`leerness:codex-global`)을 전역 AGENTS.md 에 병합 — 핵심은 **조건부**("현재 프로젝트 루트에 `.harness/` 있을 때만 발동, 없으면 무시") 라 비-leerness 프로젝트 무영향. handoff→verify-claim→session close 3계약 안내.
|
|
18
|
+
- 사용자 전역 내용 보존(마커 병합) · 멱등(재실행 중복 0) · `--remove` 로 흔적 없이 해제 — 전부 실측.
|
|
19
|
+
- **goal 모드 대응 스택 완성**: ① 프로젝트 AGENTS.md(읽는 모드) → ② 전역 조건부 지침(안 읽는 모드, 본 릴리스) → ③ pre-commit 강제(1.36.43 — 지침 자체를 무시해도 커밋 차단) → ④ enforce audit + CI gate(우회 감지·하드 차단).
|
|
20
|
+
- **검증**: selftest 315/315, 설치/보존/멱등/제거 사슬 실측, exit 전파형 게이트 e2e, 클린룸.
|
|
21
|
+
|
|
3
22
|
## 1.36.44 — 2026-07-16 — enforce 적대적 하드닝 — FP/우회 자체 헌트 (anti-cheat 출하 후속 규율)
|
|
4
23
|
|
|
5
24
|
1.36.43 enforce 는 anti-cheat 다 — 출하 규율(bypass+FP 헌터)에 따라 자체 적대 헌트를 돌린 결과 3건:
|
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ MIT
|
|
|
121
121
|
<!-- leerness:project-readme:start -->
|
|
122
122
|
## Leerness Project Harness
|
|
123
123
|
|
|
124
|
-
이 프로젝트는 Leerness v1.36.
|
|
124
|
+
이 프로젝트는 Leerness v1.36.46 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
|
|
125
125
|
|
|
126
126
|
### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
|
|
127
127
|
|
|
@@ -175,7 +175,7 @@ leerness memory restore decision <date|title>
|
|
|
175
175
|
|
|
176
176
|
### MCP server (외부 AI 통합)
|
|
177
177
|
|
|
178
|
-
Leerness v1.36.
|
|
178
|
+
Leerness v1.36.46는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
|
|
179
179
|
|
|
180
180
|
```jsonc
|
|
181
181
|
// 카테고리별
|
|
@@ -196,7 +196,7 @@ Leerness v1.36.44는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
|
|
|
196
196
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
197
197
|
1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) 회귀 테스트 갱신 → 4) 전체 e2e 스위트 통과 → 5) npm publish + git tag → 6) main push → 7) session close → 8) 다음 라운드 예약.
|
|
198
198
|
|
|
199
|
-
현재 누적: **v1.9.x → 1.36.
|
|
199
|
+
현재 누적: **v1.9.x → 1.36.46 릴리스 태그 이력** (수백 라운드) · _reports/는 비공개 보존.
|
|
200
200
|
|
|
201
201
|
### 성능 가이드
|
|
202
202
|
|
|
@@ -234,6 +234,6 @@ leerness release pack --close --auto-main-push
|
|
|
234
234
|
- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
|
|
235
235
|
- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
|
|
236
236
|
|
|
237
|
-
Last synced by Leerness v1.36.
|
|
237
|
+
Last synced by Leerness v1.36.46: 2026-07-16
|
|
238
238
|
<!-- leerness:project-readme:end -->
|
|
239
239
|
|
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.46';
|
|
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') 시 호스트 프로세스 오염.
|
|
@@ -3353,6 +3353,21 @@ function _selfTestCases() {
|
|
|
3353
3353
|
const honestOk = s.includes('git commit --no-verify 는 git 설계상 훅을 스킵');
|
|
3354
3354
|
return fpFix && wtOk && auditOk && honestOk;
|
|
3355
3355
|
} },
|
|
3356
|
+
{ name: 'codex 전역 조건부 지침 (1.36.45, goal 모드 커버): adapter codex --global — 마커 병합/보존/멱등/remove (소스가드)', run: () => {
|
|
3357
|
+
const s = read(__filename);
|
|
3358
|
+
const wired = s.includes("tool === 'codex' && has('--global')") && s.includes('leerness:codex-global:start');
|
|
3359
|
+
const conditional = s.includes('`.harness/` 디렉토리가 있을 때만');
|
|
3360
|
+
const mergeOk = s.includes('_mergeReadmeSection(existing, block, START, END)');
|
|
3361
|
+
const removeOk = /has\('--remove'\)[\s\S]{0,400}codex 전역 leerness 블록 제거/.test(s);
|
|
3362
|
+
return wired && conditional && mergeOk && removeOk;
|
|
3363
|
+
} },
|
|
3364
|
+
{ name: 'JSON 계약 완결 (1.36.46, codex 5차 #10 잔여): persona show/review/guide --json 단일 JSON 문서 (소스가드)', run: () => {
|
|
3365
|
+
const s = read(__filename);
|
|
3366
|
+
const personaOk = s.includes("log(JSON.stringify({ id: p.id, name: p.name, description: p.description, body: p.body }, null, 2)); return;");
|
|
3367
|
+
const reviewOk = s.includes("has('--json') ? 'json' : arg('--emit', 'prompt')") && s.includes('prompts: personas.map(p => ({ personaId: p.id, prompt: _mkPrompt(p) }))');
|
|
3368
|
+
const guideOk = /guideCmd[\s\S]{0,600}if \(has\('--json'\)\) \{[\s\S]{0,900}sections/.test(s) && s.includes('uiConsistency: _cap(() => uiConsistency(root))');
|
|
3369
|
+
return personaOk && reviewOk && guideOk;
|
|
3370
|
+
} },
|
|
3356
3371
|
{ name: 'debug 렌즈 (1.36.27, obra/superpowers systematic-debugging): 자기질문 6문항 ko/en 락스텝 + affects 유효 + route bugfix 힌트 + 파일매핑 미확장 — 행위검사', run: () => {
|
|
3357
3372
|
const d = LENS_CATALOG.debug;
|
|
3358
3373
|
if (!d) return false;
|
|
@@ -14116,9 +14131,11 @@ function personaCmd(root, sub, idOrName, ...rest) {
|
|
|
14116
14131
|
return;
|
|
14117
14132
|
}
|
|
14118
14133
|
if (sub === 'show') {
|
|
14119
|
-
if (!idOrName) {
|
|
14134
|
+
if (!idOrName) { failJson(has('--json'), 'missing_arg', 'persona show <id> 필요'); return process.exit(1); }
|
|
14120
14135
|
const p = _resolvePersona(root, idOrName);
|
|
14121
|
-
if (!p) {
|
|
14136
|
+
if (!p) { failJson(has('--json'), 'not_found', `페르소나 없음: ${idOrName}`); return process.exit(1); }
|
|
14137
|
+
// 1.36.46 (codex 5차 #10 잔여): --json 은 단일 JSON 문서 (종전 마크다운 방출)
|
|
14138
|
+
if (has('--json')) { log(JSON.stringify({ id: p.id, name: p.name, description: p.description, body: p.body }, null, 2)); return; }
|
|
14122
14139
|
log(`# ${p.name} (${p.id})`);
|
|
14123
14140
|
log(`\n${p.description}\n`);
|
|
14124
14141
|
log(`---\n${p.body}`);
|
|
@@ -14162,13 +14179,16 @@ function reviewCmd(root, target) {
|
|
|
14162
14179
|
}
|
|
14163
14180
|
|
|
14164
14181
|
// 출력 형식: emit
|
|
14165
|
-
const emit = arg('--emit', 'prompt'); // prompt | md | json
|
|
14182
|
+
const emit = has('--json') ? 'json' : arg('--emit', 'prompt'); // prompt | md | json (1.36.46: --json ≡ --emit json)
|
|
14166
14183
|
|
|
14167
14184
|
if (emit === 'json') {
|
|
14185
|
+
// 1.36.46 (codex 5차 #10 잔여): JSON 에 실제 산출물(프롬프트)까지 — 메타만 주던 종전은 소비자가 재조립해야 했다.
|
|
14186
|
+
const _mkPrompt = (p) => [`# Review Prompt — ${p.name} (${p.id})`, `## 대상: ${target} (${fileSize} bytes)`, `## 페르소나 활성화`, p.body, ``, `## 작업`, `아래 코드를 위 페르소나 관점에서 정밀 리뷰하라. 한국어 보고 ~600단어.`, ``, `## 코드`, '```javascript', fileContent, '```'].join('\n');
|
|
14168
14187
|
log(JSON.stringify({
|
|
14169
14188
|
file: target,
|
|
14170
14189
|
filePath, fileSize,
|
|
14171
|
-
personas: personas.map(p => ({ id: p.id, name: p.name }))
|
|
14190
|
+
personas: personas.map(p => ({ id: p.id, name: p.name })),
|
|
14191
|
+
prompts: personas.map(p => ({ personaId: p.id, prompt: _mkPrompt(p) }))
|
|
14172
14192
|
}, null, 2));
|
|
14173
14193
|
return;
|
|
14174
14194
|
}
|
|
@@ -16788,6 +16808,23 @@ function graphCmd(root) {
|
|
|
16788
16808
|
|
|
16789
16809
|
function guideCmd(root, target) {
|
|
16790
16810
|
root = absRoot(root);
|
|
16811
|
+
// 1.36.46 (codex 5차 #10 잔여): --json 은 하위 4섹션 출력을 캡처해 단일 JSON 으로 집계 (종전: 사람용 헤딩+JSON 파편 혼합).
|
|
16812
|
+
if (has('--json')) {
|
|
16813
|
+
const q0 = target ? path.basename(target, path.extname(target)) : arg('--query', '');
|
|
16814
|
+
const _cap = (fn) => {
|
|
16815
|
+
const _w = process.stdout.write; let out = '';
|
|
16816
|
+
try { process.stdout.write = s => { out += s; return true; }; fn(); } catch (e) { out += `\n(error: ${e.message})`; } finally { process.stdout.write = _w; }
|
|
16817
|
+
return out.trim();
|
|
16818
|
+
};
|
|
16819
|
+
const sections = {
|
|
16820
|
+
impact: target ? _cap(() => impactCmd(root, target)) : null,
|
|
16821
|
+
reuse: q0 ? _cap(() => reuseFind(root, q0)) : null,
|
|
16822
|
+
uiConsistency: _cap(() => uiConsistency(root)),
|
|
16823
|
+
lessons: q0 ? _cap(() => { if (!process.argv.includes('--query')) process.argv.push('--query', q0); lessonsCmd(root); }) : null,
|
|
16824
|
+
};
|
|
16825
|
+
log(JSON.stringify({ target: target || null, query: q0 || null, date: today(), sections }, null, 2));
|
|
16826
|
+
return;
|
|
16827
|
+
}
|
|
16791
16828
|
log(`# 변경 전 가이드 ${target ? `(target: ${target})` : ''}`);
|
|
16792
16829
|
log(`Date: ${today()}\n`);
|
|
16793
16830
|
if (target) {
|
|
@@ -19782,6 +19819,39 @@ function adapterCmd(root, tool, opts = {}) {
|
|
|
19782
19819
|
log(`\n 사용: leerness adapter <tool> [--dry-run]`);
|
|
19783
19820
|
return;
|
|
19784
19821
|
}
|
|
19822
|
+
// 1.36.45 (사용자 버그 후속 — codex goal 모드가 프로젝트 문서를 안 읽음): codex 는 전역 ~/.codex/AGENTS.md 를
|
|
19823
|
+
// 모든 모드에서 읽는다 — 조건부("`.harness/` 있는 프로젝트에서만") 전역 지침을 설치해 goal 모드까지 커버.
|
|
19824
|
+
// 비-leerness 프로젝트 무영향(조건부) + 마커 블록 병합(사용자 전역 내용 보존) + --remove 로 깨끗이 해제.
|
|
19825
|
+
if (tool === 'codex' && has('--global')) {
|
|
19826
|
+
const gf = path.join(os.homedir(), '.codex', 'AGENTS.md');
|
|
19827
|
+
const START = '<!-- leerness:codex-global:start -->';
|
|
19828
|
+
const END = '<!-- leerness:codex-global:end -->';
|
|
19829
|
+
const existing = exists(gf) ? read(gf) : '';
|
|
19830
|
+
if (has('--remove')) {
|
|
19831
|
+
const s = existing.indexOf(START), e = existing.indexOf(END);
|
|
19832
|
+
if (s >= 0 && e >= s) { writeUtf8(gf, (existing.slice(0, s) + existing.slice(e + END.length)).replace(/\n{3,}/g, '\n\n').trim() + '\n'); ok('codex 전역 leerness 블록 제거'); }
|
|
19833
|
+
else log('전역 블록 없음 — 변경 없음');
|
|
19834
|
+
return;
|
|
19835
|
+
}
|
|
19836
|
+
const block = [
|
|
19837
|
+
START,
|
|
19838
|
+
'# leerness — 조건부 지침 (이 블록은 `leerness adapter codex --global` 이 관리)',
|
|
19839
|
+
'',
|
|
19840
|
+
'**현재 작업 중인 프로젝트 루트에 `.harness/` 디렉토리가 있을 때만** 아래를 따른다 (없으면 이 블록 전체 무시):',
|
|
19841
|
+
'1. 작업 시작: `leerness handoff .` — 프로젝트 컨텍스트/활성 룰 적재',
|
|
19842
|
+
'2. 완료 주장 전: `leerness verify-claim <T-ID>` — 증거 검증 (거짓 완료 차단)',
|
|
19843
|
+
'3. 세션 종료: `leerness session close .` — 마감 보고 + 인수인계',
|
|
19844
|
+
'',
|
|
19845
|
+
'이 지침은 모든 Codex 모드(goal 모드 포함)에 적용된다 — 프로젝트 AGENTS.md 를 읽지 않는 모드를 위한 전역 안전망.',
|
|
19846
|
+
END,
|
|
19847
|
+
].join('\n');
|
|
19848
|
+
mkdirp(path.dirname(gf));
|
|
19849
|
+
writeUtf8(gf, _mergeReadmeSection(existing, block, START, END));
|
|
19850
|
+
ok(`codex 전역 지침 설치 — ${gf}`);
|
|
19851
|
+
log(' 조건부: .harness/ 있는 프로젝트에서만 발동 (goal 모드 포함 전 모드 커버)');
|
|
19852
|
+
log(' 해제: leerness adapter codex --global --remove');
|
|
19853
|
+
return;
|
|
19854
|
+
}
|
|
19785
19855
|
const a = ADAPTERS[tool];
|
|
19786
19856
|
if (!a) return fail(`알 수 없는 adapter: ${tool} (가능: ${Object.keys(ADAPTERS).join(', ')})`);
|
|
19787
19857
|
const lang = exists(path.join(root, '.harness/LANGUAGE')) ? read(path.join(root, '.harness/LANGUAGE')).trim() : 'ko';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.46",
|
|
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",
|