leerness 1.36.42 → 1.36.43
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 +10 -0
- package/README.md +4 -4
- package/bin/leerness.js +129 -1
- package/package.json +1 -1
- package/scripts/e2e.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.36.43 — 2026-07-16 — `leerness enforce` — 사용 강제를 문서에서 커밋 관문으로 (사용자 명시: codex goal 모드가 leerness 미참조)
|
|
4
|
+
|
|
5
|
+
**배경(사용자 실측 버그)**: codex 의 goal 모드처럼 AGENTS.md/CLAUDE.md 를 읽지 않는 에이전트 경로에선 하네스 문서 수준의 지시가 무력하다. 실효 강제는 **어떤 에이전트/모드든 통과해야 하는 보편 관문 = git pre-commit** 에서.
|
|
6
|
+
|
|
7
|
+
- **`leerness enforce install|check|status|remove [--window 24] [--strict]`**: 최근 window 내 handoff 흔적(`last-handoff.json`) 없으면 **커밋 차단** + 정확한 회복 명령(`leerness handoff .`) 안내. `--strict` 는 gate 전체 통과까지 요구. 긴급 우회는 명시적 env(`LEERNESS_ENFORCE_BYPASS=1`) — 무언 우회 없음.
|
|
8
|
+
- **훅은 자기완결 sh**: 설치된 leerness 버전/PATH/네트워크 무의존(`find -mmin` mtime 판정) — 검증 중 **구버전 전역 CLI(1.36.41)가 enforce 를 몰라 오차단하는 실측 함정**을 밟고 재설계한 결과. 기존 pre-commit 훅은 체인 보존(`pre-commit.pre-leerness` 로 이동 후 호출, remove 시 복원).
|
|
9
|
+
- **init/migrate 시 git 저장소면 기본 자동 설치** (사용자 의도: 설치된 프로젝트는 강제) — 옵트아웃 `--no-enforce` / `LEERNESS_NO_ENFORCE=1` / `--minimal`.
|
|
10
|
+
- **실증 사슬 5/5**: 무handoff 커밋 차단 → handoff 후 통과+기존 훅 체인 실행 → 25h 경과 차단 → 명시 우회 → remove 시 기존 훅 복원. init 자동/비-git 무설치/옵트아웃/migrate 획득 4종 추가 실증.
|
|
11
|
+
- **검증**: selftest 313/313, exit 전파형 게이트 e2e(verify-claim 픽스처만 주제 무관 옵트아웃 명시), 게시본 클린룸.
|
|
12
|
+
|
|
3
13
|
## 1.36.42 — 2026-07-16 — 판정 정직화 배치 C — codex 5차 헌트 10건 전건 처분 완결 (#4~#10)
|
|
4
14
|
|
|
5
15
|
- **#4 agent-mode**: 3개 자식 전부 실패해도 "자율 라운드 진행 준비" 선언 + exit 0 — 전부 실패=exit 1, 부분 실패=⚠ 명시, tick/stop 자식 실패 전파, 미지 하위명령 exit 1.
|
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.43 하네스를 사용합니다. 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.43는 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.42는 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.43 릴리스 태그 이력** (수백 라운드) · _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.43: 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.43';
|
|
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') 시 호스트 프로세스 오염.
|
|
@@ -1177,6 +1177,14 @@ async function install(root, opts = {}) {
|
|
|
1177
1177
|
if (!has('--no-auto-roadmap') && !opts.minimal) {
|
|
1178
1178
|
try { _autoRoadmap(root, 'install'); } catch (e) { warn('auto-roadmap 실패: ' + (e && e.message)); }
|
|
1179
1179
|
}
|
|
1180
|
+
// 1.36.43 (사용자 명시): git 저장소면 사용 강제(pre-commit) 기본 설치 — 문서를 읽지 않는 에이전트 경로(codex goal 모드 등)도
|
|
1181
|
+
// 커밋 관문에서 강제. 옵트아웃: --no-enforce / LEERNESS_NO_ENFORCE=1 / --minimal. 이미 설치돼 있으면 멱등(마커 확인).
|
|
1182
|
+
if (!has('--no-enforce') && process.env.LEERNESS_NO_ENFORCE !== '1' && !opts.minimal && exists(path.join(root, '.git'))) {
|
|
1183
|
+
try {
|
|
1184
|
+
const _hp2 = _gitHookPath(root);
|
|
1185
|
+
if (!exists(_hp2) || !read(_hp2).includes(_ENFORCE_MARK)) enforceCmd(root, 'install');
|
|
1186
|
+
} catch (e) { warn('enforce install skipped: ' + (e && e.message)); }
|
|
1187
|
+
}
|
|
1180
1188
|
// 1.9.148: 1.9.32 중복 prompt 제거 (사용자 명시 — CLI 에이전트 prompt 중복).
|
|
1181
1189
|
// resolveInstallOptions (1.9.146) 가 이미 모든 prompt 모은 위치에 통합된 4지선다 prompt 있음.
|
|
1182
1190
|
// 별도 setupAgents 명령은 사용자가 명시적으로 `leerness setup-agents` 호출 시에만.
|
|
@@ -3314,6 +3322,29 @@ function _selfTestCases() {
|
|
|
3314
3322
|
try { const m = _mergeLensCatalog(LENS_CATALOG, { constructor: { title: 'C', persona: 'r', questions: ['q1'] } }); protoOk = !!(m.constructor && Array.isArray(m.constructor.questions) && m.constructor.questions[0] === 'q1'); } catch {}
|
|
3315
3323
|
return amOk && orOk && relOk && toOk && conOk && lensOk && rpJsonOk && preOk && protoOk;
|
|
3316
3324
|
} },
|
|
3325
|
+
{ name: 'enforce 사용 강제 (1.36.43, 사용자 명시 — codex goal 모드 미참조 버그): 자기완결 pre-commit 훅 + 체인 보존 + init 자동설치 — 행위검사', run: () => {
|
|
3326
|
+
const s = read(__filename);
|
|
3327
|
+
const wired = typeof enforceCmd === 'function' && s.includes("cmd === 'enforce'");
|
|
3328
|
+
// 훅 자기완결(구버전 전역 CLI 무의존 — 실측 함정): leerness 호출 없이 find -mmin 으로 판정
|
|
3329
|
+
const selfContained = s.includes('find "$LH" -mmin -"$WIN_MIN"') && s.includes('LEERNESS_ENFORCE_BYPASS');
|
|
3330
|
+
const chainOk = s.includes('pre-commit.pre-leerness');
|
|
3331
|
+
const initAuto = s.includes("!has('--no-enforce') && process.env.LEERNESS_NO_ENFORCE !== '1'");
|
|
3332
|
+
// 행위: 임시 git repo — install→(handoff 無)차단 메시지, mtime 신선→통과 (git 없으면 skip-통과)
|
|
3333
|
+
let behavOk = true;
|
|
3334
|
+
try {
|
|
3335
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), '__leerness_enf_'));
|
|
3336
|
+
const g = cp.spawnSync('git', ['-C', tmp, 'init'], { encoding: 'utf8', timeout: 10000 });
|
|
3337
|
+
if (g.status === 0) {
|
|
3338
|
+
fs.mkdirSync(path.join(tmp, '.harness'), { recursive: true });
|
|
3339
|
+
const save = process.argv; const _w = process.stdout.write;
|
|
3340
|
+
try { process.argv = ['node', 'h', 'enforce', 'install']; process.stdout.write = () => true; enforceCmd(tmp, 'install'); } finally { process.stdout.write = _w; process.argv = save; }
|
|
3341
|
+
const hk = fs.readFileSync(path.join(tmp, '.git', 'hooks', 'pre-commit'), 'utf8');
|
|
3342
|
+
behavOk = hk.includes(_ENFORCE_MARK) && hk.includes('find "$LH"');
|
|
3343
|
+
}
|
|
3344
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
3345
|
+
} catch { behavOk = false; }
|
|
3346
|
+
return wired && selfContained && chainOk && initAuto && behavOk;
|
|
3347
|
+
} },
|
|
3317
3348
|
{ name: 'debug 렌즈 (1.36.27, obra/superpowers systematic-debugging): 자기질문 6문항 ko/en 락스텝 + affects 유효 + route bugfix 힌트 + 파일매핑 미확장 — 행위검사', run: () => {
|
|
3318
3349
|
const d = LENS_CATALOG.debug;
|
|
3319
3350
|
if (!d) return false;
|
|
@@ -4989,6 +5020,102 @@ function shellGuardCmd(root, cmd, opts = {}) {
|
|
|
4989
5020
|
if (analysis.issues.some(i => i.severity === 'error')) process.exitCode = 1;
|
|
4990
5021
|
}
|
|
4991
5022
|
|
|
5023
|
+
// 1.36.43 (사용자 명시): leerness 사용 강제 — 문서(AGENTS.md) 지시는 codex goal 모드처럼 문서를 읽지 않는
|
|
5024
|
+
// 에이전트 경로에서 무력하다(사용자 실측 버그). 어떤 에이전트든 통과해야 하는 보편 관문 = git pre-commit 훅에서 강제:
|
|
5025
|
+
// 최근 handoff 흔적(기본 24h)이 없으면 커밋 차단 + 정확한 회복 명령 안내. --strict 는 gate 전체까지 요구.
|
|
5026
|
+
// 긴급 우회: LEERNESS_ENFORCE_BYPASS=1 (문서화된 명시 우회 — 무언 우회 아님).
|
|
5027
|
+
const _ENFORCE_MARK = '# leerness-enforce v1';
|
|
5028
|
+
function _enforceCfgPath(root) { return path.join(root, '.harness', 'enforce.json'); }
|
|
5029
|
+
function _enforceCfg(root) {
|
|
5030
|
+
const def = { windowHours: 24, strict: false };
|
|
5031
|
+
try { if (exists(_enforceCfgPath(root))) return Object.assign(def, JSON.parse(read(_enforceCfgPath(root)))); } catch {}
|
|
5032
|
+
return def;
|
|
5033
|
+
}
|
|
5034
|
+
function _gitHookPath(root) { return path.join(root, '.git', 'hooks', 'pre-commit'); }
|
|
5035
|
+
function enforceCmd(root, sub) {
|
|
5036
|
+
root = absRoot(root);
|
|
5037
|
+
const json = has('--json');
|
|
5038
|
+
sub = sub || 'status';
|
|
5039
|
+
const hookP = _gitHookPath(root);
|
|
5040
|
+
const chainedP = hookP + '.pre-leerness';
|
|
5041
|
+
if (sub === 'install') {
|
|
5042
|
+
if (!exists(path.join(root, '.git'))) { failJson(json, 'not_a_git_repo', `git 저장소가 아님: ${root} — pre-commit 강제는 git 저장소에서만 가능`); return; }
|
|
5043
|
+
if (!exists(path.join(root, '.harness'))) { failJson(json, 'harness_missing', `leerness 미설치: ${root} — 먼저 leerness init`); return; }
|
|
5044
|
+
const windowHours = Math.max(1, parseInt(arg('--window', '24'), 10) || 24);
|
|
5045
|
+
const strict = has('--strict');
|
|
5046
|
+
mkdirp(path.dirname(_enforceCfgPath(root)));
|
|
5047
|
+
writeUtf8(_enforceCfgPath(root), JSON.stringify({ windowHours, strict, installedAt: now() }, null, 2) + '\n');
|
|
5048
|
+
mkdirp(path.dirname(hookP));
|
|
5049
|
+
// 기존 훅 보존: 우리 것이 아니면 체인 파일로 이동 후 호출
|
|
5050
|
+
if (exists(hookP) && !read(hookP).includes(_ENFORCE_MARK)) {
|
|
5051
|
+
fs.copyFileSync(hookP, chainedP);
|
|
5052
|
+
try { fs.chmodSync(chainedP, 0o755); } catch {}
|
|
5053
|
+
}
|
|
5054
|
+
// 훅은 자기완결 sh — 설치된 leerness 버전/네트워크/PATH 에 무의존(구버전 전역 CLI 가 enforce 를 몰라 오차단하던 실측 함정 회피).
|
|
5055
|
+
// 핵심 체크 = last-handoff.json 의 mtime 이 window 안인지 (find -mmin, git bash 표준).
|
|
5056
|
+
const hook = [
|
|
5057
|
+
'#!/bin/sh',
|
|
5058
|
+
_ENFORCE_MARK + ' — leerness 사용 강제 (제거: leerness enforce remove)',
|
|
5059
|
+
'if [ "$LEERNESS_ENFORCE_BYPASS" = "1" ]; then exit 0; fi',
|
|
5060
|
+
`LH=".harness/last-handoff.json"`,
|
|
5061
|
+
`WIN_MIN=${windowHours * 60}`,
|
|
5062
|
+
'if [ ! -f "$LH" ] || [ -z "$(find "$LH" -mmin -"$WIN_MIN" 2>/dev/null)" ]; then',
|
|
5063
|
+
` echo "🔒 leerness 강제: 최근 ${windowHours}h 내 handoff 흔적 없음 — 커밋 전 실행: leerness handoff ." >&2`,
|
|
5064
|
+
' echo " 긴급 우회(명시): LEERNESS_ENFORCE_BYPASS=1 git commit ..." >&2',
|
|
5065
|
+
' exit 1',
|
|
5066
|
+
'fi',
|
|
5067
|
+
...(strict ? [
|
|
5068
|
+
'if command -v leerness >/dev/null 2>&1; then LEERNESS_INTERNAL=1 leerness gate . || exit 1;',
|
|
5069
|
+
'elif command -v npx >/dev/null 2>&1; then LEERNESS_INTERNAL=1 npx -y leerness gate . || exit 1; fi',
|
|
5070
|
+
] : []),
|
|
5071
|
+
'if [ -f "$(dirname "$0")/pre-commit.pre-leerness" ]; then sh "$(dirname "$0")/pre-commit.pre-leerness" "$@" || exit 1; fi',
|
|
5072
|
+
'',
|
|
5073
|
+
].join('\n');
|
|
5074
|
+
writeUtf8(hookP, hook);
|
|
5075
|
+
try { fs.chmodSync(hookP, 0o755); } catch {}
|
|
5076
|
+
if (json) { log(JSON.stringify({ ok: true, installed: true, windowHours, strict, hook: hookP }, null, 2)); return; }
|
|
5077
|
+
ok(`enforce 설치 — 커밋 전 leerness 사용(최근 ${windowHours}h 내 handoff${strict ? ' + gate 통과' : ''})을 git pre-commit 에서 강제`);
|
|
5078
|
+
log(` 대상: 어떤 에이전트/모드든(codex goal 모드 포함) — 커밋이 보편 관문이라 문서를 안 읽는 경로도 강제됨`);
|
|
5079
|
+
log(` 긴급 우회: LEERNESS_ENFORCE_BYPASS=1 git commit … · 해제: leerness enforce remove`);
|
|
5080
|
+
return;
|
|
5081
|
+
}
|
|
5082
|
+
if (sub === 'check') {
|
|
5083
|
+
if (!exists(path.join(root, '.harness'))) return; // leerness 미설치 저장소 — 강제 대상 아님(무음 통과)
|
|
5084
|
+
const cfg = _enforceCfg(root);
|
|
5085
|
+
const lhf = _lastHandoffPath(root);
|
|
5086
|
+
let lastAt = null;
|
|
5087
|
+
try { if (exists(lhf)) { const j = JSON.parse(read(lhf)); lastAt = j.last || (Array.isArray(j.history) && j.history.length ? j.history[j.history.length - 1] : null); } } catch {}
|
|
5088
|
+
const ageH = lastAt ? (Date.now() - new Date(lastAt).getTime()) / 3600000 : Infinity;
|
|
5089
|
+
if (ageH > cfg.windowHours) {
|
|
5090
|
+
fail(`🔒 leerness 강제: 최근 ${cfg.windowHours}h 내 handoff 흔적 없음${lastAt ? ` (마지막: ${lastAt})` : ''}`);
|
|
5091
|
+
log(` → 커밋 전 실행: leerness handoff . (컨텍스트 적재 + 사용 흔적)`);
|
|
5092
|
+
log(` → 긴급 우회(명시): LEERNESS_ENFORCE_BYPASS=1`);
|
|
5093
|
+
process.exitCode = 1; return;
|
|
5094
|
+
}
|
|
5095
|
+
if (cfg.strict) {
|
|
5096
|
+
const r = cp.spawnSync(process.execPath, [__filename, 'gate', root], { encoding: 'utf8', env: { ...process.env, LEERNESS_INTERNAL: '1' } });
|
|
5097
|
+
if (r.status !== 0) { fail(`🔒 leerness 강제(strict): gate 실패 — 커밋 차단`); process.stdout.write((r.stdout || '').slice(-1500)); process.exitCode = 1; return; }
|
|
5098
|
+
}
|
|
5099
|
+
if (!json) ok(`enforce check 통과 (handoff ${lastAt ? Math.round(ageH * 10) / 10 + 'h 전' : '-'}${cfg.strict ? ' + gate' : ''})`);
|
|
5100
|
+
return;
|
|
5101
|
+
}
|
|
5102
|
+
if (sub === 'remove') {
|
|
5103
|
+
if (exists(hookP) && read(hookP).includes(_ENFORCE_MARK)) {
|
|
5104
|
+
if (exists(chainedP)) { fs.copyFileSync(chainedP, hookP); fs.unlinkSync(chainedP); try { fs.chmodSync(hookP, 0o755); } catch {} }
|
|
5105
|
+
else fs.unlinkSync(hookP);
|
|
5106
|
+
ok('enforce 제거 — pre-commit 훅 해제' + (exists(hookP) ? ' (기존 훅 복원)' : ''));
|
|
5107
|
+
} else log('enforce 훅 없음 — 변경 없음');
|
|
5108
|
+
return;
|
|
5109
|
+
}
|
|
5110
|
+
// status
|
|
5111
|
+
const installed = exists(hookP) && read(hookP).includes(_ENFORCE_MARK);
|
|
5112
|
+
const cfg = _enforceCfg(root);
|
|
5113
|
+
if (json) { log(JSON.stringify({ installed, ...cfg }, null, 2)); return; }
|
|
5114
|
+
log(`# leerness enforce — 사용 강제 (git pre-commit)`);
|
|
5115
|
+
log(` 상태: ${installed ? `🟢 설치됨 (window ${cfg.windowHours}h${cfg.strict ? ' · strict=gate' : ''})` : '⚪ 미설치'}`);
|
|
5116
|
+
log(` ${installed ? '해제: leerness enforce remove' : '설치: leerness enforce install [--window 24] [--strict]'}`);
|
|
5117
|
+
}
|
|
5118
|
+
|
|
4992
5119
|
// 1.36.36 (도그푸딩 실측 후속): `leerness anchors [status|draft [--apply]]` — 정체성앵커(brief Purpose / plan Goal) 미작성 전환 지원.
|
|
4993
5120
|
// 실측: 1.36.19 감지 출하 후에도 실프로젝트 brief 4/7 · Goal 6/7 미작성 — 노출만으론 전환 안 됨. 초안 합성으로 마찰 제거.
|
|
4994
5121
|
// 안전: --apply 는 해당 섹션이 "미작성일 때만" 교체(작성된 내용 절대 불클로버), 초안 표식 주석 명시.
|
|
@@ -22049,6 +22176,7 @@ async function main() {
|
|
|
22049
22176
|
if (cmd === 'milestones') return milestonesCmd(_resolveRoot(args[1]));
|
|
22050
22177
|
// 1.9.231: leerness pulse — 한 줄 종합 요약 (10 핵심 지표)
|
|
22051
22178
|
if (cmd === 'pulse') return pulseCmd(_resolveRoot(args[1]));
|
|
22179
|
+
if (cmd === 'enforce') return enforceCmd(arg('--path', null) || _taskPositionalPath(args, 2) || process.cwd(), args[1]); // 1.36.43: 사용 강제 (git pre-commit)
|
|
22052
22180
|
if (cmd === 'anchors') return anchorsCmd(arg('--path', null) || _taskPositionalPath(args, 1) || process.cwd(), args[1] && !args[1].startsWith('-') ? args[1] : null); // 1.36.36: 정체성앵커 초안
|
|
22053
22181
|
if (cmd === 'toggle') return _tgl.toggleCmd(arg('--path', process.cwd()), args[1], args[2], args[3], { has, VERSION }); // 1.36.30: 기능 토글 (그래프 ⚙ 탭 연동)
|
|
22054
22182
|
if (cmd === 'lens') return lensCmd(args[1]); // 1.18.3 (UR-0003): 분야별 자기질문 품질 렌즈
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.43",
|
|
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",
|
package/scripts/e2e.js
CHANGED
|
@@ -3386,7 +3386,7 @@ total++;
|
|
|
3386
3386
|
const gi = git('init');
|
|
3387
3387
|
if (gi.status !== 0) throw new Error('git 없음'); // git 미설치 환경 → skip(아래 catch 로 ok=false 방지 위해 통과 처리)
|
|
3388
3388
|
git('config', 'user.email', 't@t'); git('config', 'user.name', 't');
|
|
3389
|
-
cp.spawnSync(process.execPath, [CLI, 'init', vDir, '--yes', '--language', 'ko', '--skills', 'recommended'], { encoding: 'utf8', timeout: 30000 });
|
|
3389
|
+
cp.spawnSync(process.execPath, [CLI, 'init', vDir, '--yes', '--language', 'ko', '--skills', 'recommended', '--no-enforce'], { encoding: 'utf8', timeout: 30000 }); // 1.36.43: 이 케이스 주제는 verify-claim — enforce 훅(handoff 없인 커밋 차단)은 옵트아웃
|
|
3390
3390
|
fs.mkdirSync(path.join(vDir, 'src'), { recursive: true });
|
|
3391
3391
|
fs.writeFileSync(path.join(vDir, 'src', 'api.js'), 'v1'); fs.writeFileSync(path.join(vDir, 'old.js'), 'old');
|
|
3392
3392
|
git('add', '-A'); git('commit', '-m', 'init');
|