leerness 1.36.33 → 1.36.34
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 +9 -0
- package/README.md +4 -4
- package/bin/leerness.js +47 -13
- package/lib/pure-utils.js +13 -0
- package/lib/session-close.js +11 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.36.34 — 2026-07-15 — 판정 정직화 5종 — 도구가 내리는 판정(허용/만료/최신/집계)이 거짓말하지 않도록 (codex 3차 #4/#5/#8/#9/#10)
|
|
4
|
+
|
|
5
|
+
- **#8 policy check**: 차단 판정인데 exit 0 → **exit 1**(CI/스크립트가 판정 신뢰 가능). 손상 policy.json 을 기본값 폴백으로 오답하던 것 → `policy_corrupt` 구조화 에러.
|
|
6
|
+
- **#9 creds check**: null/비객체 레코드 → raw TypeError 크래시, 판독불가 날짜(NaN) → false-ready. → `invalid_credentials_schema` 구조화 판정 exit 1, 판독불가 날짜는 유효로 치지 않음(`unparsable_lastRefreshed`).
|
|
7
|
+
- **#10 session close**: `completed`/`cancelled` 등 별칭·미지 상태가 어느 카테고리에도 안 담겨 마감 보고에서 조용히 소실(3건 중 1건 집계 실측; codex 실측 실프로젝트 13건 누락). → 별칭 정규화(completed/verified→done, cancelled→dropped 등) + 미지 상태 `other` 버킷(집계·handoff 모두 소실 0).
|
|
8
|
+
- **#5 update --check**: 조회 실패(null)를 24h 캐시로 굳혀 다음 실행이 "up to date" 오답 → null 미캐시(다음 실행 재조회, "판정 보류" 명시). `compareVer` prerelease 세그먼트 비교 구현(semver §11 — 종전 beta.10==beta.2) — 숫자/문자/길이 규칙 7케이스 실증, 일반 비교 무회귀.
|
|
9
|
+
- **#4 update --from <tarball>**: Windows shell 이 공백 경로를 재분할해 실패 → 인자 quoting. 이력이 실행 CLI 버전을 기록하던 것 → 설치된 HARNESS_VERSION 재판독.
|
|
10
|
+
- **검증**: selftest 304/304(semver 5케이스 행위 + 배선 5종), 5건 원 재현 before/after, exit 전파형 게이트 e2e, 게시본 클린룸. 이연: #6 deps --run-tests false-green · #7 주석 트레이스 오인(휴리스틱 계열 — 별도 라운드에서 신중 처리).
|
|
11
|
+
|
|
3
12
|
## 1.36.33 — 2026-07-15 — 데이터 보존 5종 — migrate --force 상태 보존 · positional path 클래스 소진 · symlink 미추종 · skill 충돌 가드 · settings 손상 중단 (codex 3차 헌트 + 자체 발견)
|
|
4
13
|
|
|
5
14
|
- **P1 — `migrate --force` 가 사용자 상태를 삭제** (codex 3차 #1): --force 가 progress-tracker/plan/task-log/decisions 등 상태 파일까지 새 템플릿으로 덮어써 활성 task 가 archive 에만 남았다(마커 실측 소실). → force 는 가이드/템플릿 문서에만 적용, 상태 파일 14종은 force 여도 보존(`_USER_STATE`). 실측: --force 후 task 잔존 1 · guideline 은 갱신. **1.36.28 의 마이그레이션 유실 전수 검증을 --force 경로까지 확장 완결.**
|
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.34 하네스를 사용합니다. 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.34는 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.33는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
|
|
|
196
196
|
`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
|
|
197
197
|
1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) stress-v* 신규 작성 + 누적 회귀 → 4) e2e 219/219 → 5) npm pack + git tag + GitHub release → 6) main 자동 push → 7) session close → 8) 다음 라운드 예약.
|
|
198
198
|
|
|
199
|
-
현재 누적: **70 라운드 (1.9.40 → 1.36.
|
|
199
|
+
현재 누적: **70 라운드 (1.9.40 → 1.36.34)** · 매 라운드 GitHub release/태그 생성 · _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.34: 2026-07-15
|
|
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.34';
|
|
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') 시 호스트 프로세스 오염.
|
|
@@ -3150,6 +3150,24 @@ function _selfTestCases() {
|
|
|
3150
3150
|
const copySafe = /function copyRecursiveSafe[\s\S]{0,400}lstatSync/.test(s);
|
|
3151
3151
|
return forceGuard && skillGuard && settingsGuard && symlinkGuard && copySafe;
|
|
3152
3152
|
} },
|
|
3153
|
+
{ name: '판정 정직화 5종 (1.36.34, codex 3차 #4/#5/#8/#9/#10): prerelease semver + 캐시 null 미고착 + policy exit/손상 + creds 스키마 + close 상태 별칭 — 행위검사', run: () => {
|
|
3154
|
+
const p = require('../lib/pure-utils');
|
|
3155
|
+
// #5: prerelease 세그먼트 비교 (종전 0 반환)
|
|
3156
|
+
const semverOk = p.compareVer('1.0.0-beta.10', '1.0.0-beta.2') === 1 && p.compareVer('1.0.0-alpha', '1.0.0-beta') === -1
|
|
3157
|
+
&& p.compareVer('1.0.0-beta', '1.0.0-beta.1') === -1 && p.compareVer('1.0.0', '1.0.0-beta') === 1 && p.compareVer('1.2.3', '1.2.3') === 0;
|
|
3158
|
+
const s = read(__filename);
|
|
3159
|
+
const cacheOk = s.includes('if (latest) writeUpdateCache(root,') && s.includes("cacheFresh(cached, cacheHours) && cached.nextLeerness");
|
|
3160
|
+
// #8: 차단 exit 1 + 손상 policy 구조화 에러
|
|
3161
|
+
const policyOk = s.includes('if (!res.allowed) process.exitCode = 1;') && s.includes("'policy_corrupt'");
|
|
3162
|
+
// #9: creds 스키마 검증 + 판독불가 날짜
|
|
3163
|
+
const credsOk = s.includes("invalid: 'invalid_credentials_schema'") && s.includes('unparsable_lastRefreshed');
|
|
3164
|
+
// #10: session close 별칭 정규화 + other 버킷 (행위)
|
|
3165
|
+
const sc = read(path.join(path.dirname(__filename), '..', 'lib', 'session-close.js'));
|
|
3166
|
+
const closeOk = sc.includes('_STATUS_ALIAS') && sc.includes("completed: 'done'") && sc.includes("cancelled: 'dropped'") && sc.includes('buckets.other.length');
|
|
3167
|
+
// #4: tarball 공백 경로 quoting + 설치 버전 재판독
|
|
3168
|
+
const tarOk = s.includes('const _qw = a =>') && s.includes("read(path.join(root, '.harness', 'HARNESS_VERSION')).trim(); if (_hv) nextLeerness = _hv;");
|
|
3169
|
+
return semverOk && cacheOk && policyOk && credsOk && closeOk && tarOk;
|
|
3170
|
+
} },
|
|
3153
3171
|
{ name: 'debug 렌즈 (1.36.27, obra/superpowers systematic-debugging): 자기질문 6문항 ko/en 락스텝 + affects 유효 + route bugfix 힌트 + 파일매핑 미확장 — 행위검사', run: () => {
|
|
3154
3172
|
const d = LENS_CATALOG.debug;
|
|
3155
3173
|
if (!d) return false;
|
|
@@ -16363,16 +16381,17 @@ async function updateCmd(root, opts = {}) {
|
|
|
16363
16381
|
if (fromTar) { if (!quiet) log(`Local tarball mode: ${fromTar}`); }
|
|
16364
16382
|
else {
|
|
16365
16383
|
const cached = readUpdateCache(root);
|
|
16366
|
-
|
|
16367
|
-
|
|
16384
|
+
// 1.36.34 (codex 3차 #5): 조회 실패(null)를 24h 캐시로 굳히면 다음 실행이 "up to date" 로 오답 — null 은 캐시하지 않고 재시도.
|
|
16385
|
+
if (cacheFresh(cached, cacheHours) && cached.nextLeerness) {
|
|
16386
|
+
nextLeerness = cached.nextLeerness;
|
|
16368
16387
|
if (!quiet) log(`(cached ${Math.round((Date.now() - cached.at) / 60000)}m ago)`);
|
|
16369
|
-
if (!quiet) log(`npm leerness latest: ${cached.nextLeerness
|
|
16388
|
+
if (!quiet) log(`npm leerness latest: ${cached.nextLeerness}`);
|
|
16370
16389
|
} else {
|
|
16371
16390
|
if (!quiet) log('Checking npm registry…');
|
|
16372
16391
|
const latest = await fetchNpmLatest('leerness');
|
|
16373
16392
|
nextLeerness = latest || VERSION;
|
|
16374
|
-
writeUpdateCache(root, { nextLeerness: latest, runningCli: VERSION });
|
|
16375
|
-
if (!quiet) log(`npm leerness latest: ${latest || '(unavailable
|
|
16393
|
+
if (latest) writeUpdateCache(root, { nextLeerness: latest, runningCli: VERSION });
|
|
16394
|
+
if (!quiet) log(`npm leerness latest: ${latest || '(unavailable — 판정 보류, 다음 실행에서 재조회)'}`);
|
|
16376
16395
|
}
|
|
16377
16396
|
}
|
|
16378
16397
|
// What is "current"? canonical=base; legacy plus also rolls into leerness 1.9.0+
|
|
@@ -16403,8 +16422,12 @@ async function updateCmd(root, opts = {}) {
|
|
|
16403
16422
|
if (r.status !== 0) { fail(`delegated migrate exited ${r.status}`); process.exitCode = 1; return; }
|
|
16404
16423
|
} else if (fromTar) {
|
|
16405
16424
|
log(`\nDelegating to npx -p ${fromTar} leerness migrate (local tarball)…`);
|
|
16406
|
-
|
|
16425
|
+
// 1.36.34 (codex 3차 #4): Windows shell:true 는 인자를 공백에서 재분할 — 공백 포함 경로를 따옴표로 보호.
|
|
16426
|
+
const _qw = a => (process.platform === 'win32' && /\s/.test(String(a))) ? `"${a}"` : a;
|
|
16427
|
+
const r = cp.spawnSync('npx', ['-y', '-p', _qw(fromTar), 'leerness', 'migrate', _qw(root), '--yes'], { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
16407
16428
|
if (r.status !== 0) { fail(`delegated migrate exited ${r.status}`); process.exitCode = 1; return; }
|
|
16429
|
+
// 1.36.34 (#4b): 이력에 실행 CLI 버전이 아니라 실제 설치된 버전 기록 — 마이그레이션 후 HARNESS_VERSION 재판독.
|
|
16430
|
+
try { const _hv = read(path.join(root, '.harness', 'HARNESS_VERSION')).trim(); if (_hv) nextLeerness = _hv; } catch {}
|
|
16408
16431
|
} else {
|
|
16409
16432
|
log(`\nRunning in-process migrate (already on latest ${VERSION})…`);
|
|
16410
16433
|
await install(root, { force: false, dry: false, migration: true, nonInteractive: true });
|
|
@@ -18788,7 +18811,11 @@ function policyCmd(root, sub, ...args) {
|
|
|
18788
18811
|
if (sub === 'check') {
|
|
18789
18812
|
const cmd = (args.find(a => a && !a.startsWith('-')) || arg('--cmd', '')).trim();
|
|
18790
18813
|
if (!cmd) return fail('policy check "<command>" 필요');
|
|
18814
|
+
// 1.36.34 (codex 3차 #8): 손상 policy.json 을 기본값으로 조용히 폴백하면 잘못된 허용 판정 — 손상은 구조화 에러 + exit 1.
|
|
18815
|
+
const _pf = _policyFile(root);
|
|
18816
|
+
if (exists(_pf)) { try { JSON.parse(read(_pf)); } catch { failJson(json, 'policy_corrupt', `policy 파일 손상(JSON 파싱 실패): ${_pf} — 복구/삭제 후 재시도`); return; } }
|
|
18791
18817
|
const res = _policyEnforce(root, cmd);
|
|
18818
|
+
if (!res.allowed) process.exitCode = 1; // 1.36.34 (#8): 차단 판정은 exit 1 (CI/스크립트가 판정을 신뢰할 수 있게)
|
|
18792
18819
|
if (json) { log(JSON.stringify({ cmd, ...res }, null, 2)); return; }
|
|
18793
18820
|
log(`# policy check: ${cmd}`);
|
|
18794
18821
|
log(` 요구 등급: ${res.required} · 허용 등급: ${res.allowedTier} · ${res.allowed ? '🟢 허용' : '🔴 차단'}${res.advisory ? ' (advisory — enforce OFF)' : ''}`);
|
|
@@ -20351,11 +20378,18 @@ function credsCheckCmd(root, service) {
|
|
|
20351
20378
|
const targets = service ? (j.services[service] ? { [service]: j.services[service] } : {}) : (j.services || {});
|
|
20352
20379
|
if (!Object.keys(targets).length) { failJson(has('--json'), 'no_service', `등록된 서비스 없음${service ? ` (${service})` : ''}`); return; } // 1.9.404 (UR-0105 잔여): --json 에러 구조화
|
|
20353
20380
|
for (const [name, meta] of Object.entries(targets)) {
|
|
20354
|
-
|
|
20355
|
-
|
|
20356
|
-
|
|
20357
|
-
|
|
20358
|
-
|
|
20381
|
+
// 1.36.34 (codex 3차 #9): 손상 레코드(null/비객체) → raw TypeError 크래시, 파싱 불가 날짜(NaN) → false-ready. 구조화 판정.
|
|
20382
|
+
if (!meta || typeof meta !== 'object' || !Array.isArray(meta.envVars)) {
|
|
20383
|
+
result.services[name] = { envSet: false, missing: [], expired: false, invalid: 'invalid_credentials_schema' };
|
|
20384
|
+
result.ok = false;
|
|
20385
|
+
continue;
|
|
20386
|
+
}
|
|
20387
|
+
const missing = meta.envVars.filter(v => !process.env[v]);
|
|
20388
|
+
const _ts = meta.lastRefreshed ? Date.parse(meta.lastRefreshed) : null;
|
|
20389
|
+
const _badDate = meta.lastRefreshed != null && Number.isNaN(_ts);
|
|
20390
|
+
const expired = _badDate ? true // 판독 불가 날짜는 '유효' 로 치지 않음 (false-ready 방지)
|
|
20391
|
+
: (meta.tokenLifetimeHours && _ts != null ? (Date.now() - _ts) > meta.tokenLifetimeHours * 3600 * 1000 : false);
|
|
20392
|
+
result.services[name] = { envSet: !missing.length, missing, expired, ...(_badDate ? { invalid: 'unparsable_lastRefreshed' } : {}) };
|
|
20359
20393
|
if (missing.length || expired) result.ok = false;
|
|
20360
20394
|
}
|
|
20361
20395
|
if (has('--json')) { log(JSON.stringify(result, null, 2)); if (!result.ok) process.exitCode = 1; return; }
|
|
@@ -20363,7 +20397,7 @@ function credsCheckCmd(root, service) {
|
|
|
20363
20397
|
for (const [name, r] of Object.entries(result.services)) {
|
|
20364
20398
|
if (r.envSet && !r.expired) log(` ✓ ${name}: 사용 준비됨`);
|
|
20365
20399
|
else {
|
|
20366
|
-
log(` ⚠ ${name}: ${r.missing.length ? `누락 ${r.missing.join(',')}` : ''}${r.expired ? ' · 토큰 만료 (재로그인 필요)' : ''}`);
|
|
20400
|
+
log(` ⚠ ${name}: ${r.missing.length ? `누락 ${r.missing.join(',')}` : ''}${r.expired ? ' · 토큰 만료 (재로그인 필요)' : ''}${r.invalid ? ` · 레코드 손상(${r.invalid}) — creds register 로 재등록` : ''}`);
|
|
20367
20401
|
}
|
|
20368
20402
|
}
|
|
20369
20403
|
if (!result.ok) process.exitCode = 1;
|
package/lib/pure-utils.js
CHANGED
|
@@ -23,6 +23,19 @@ function compareVer(a, b) {
|
|
|
23
23
|
const preA = A.includes('-'), preB = B.includes('-');
|
|
24
24
|
if (preA && !preB) return -1;
|
|
25
25
|
if (!preA && preB) return 1;
|
|
26
|
+
// 1.36.34 (codex 3차 #5): 둘 다 pre-release 면 식별자 세그먼트 비교(semver §11) — 종전엔 0 반환이라 beta.10 == beta.2 오답.
|
|
27
|
+
if (preA && preB) {
|
|
28
|
+
const pa = A.slice(A.indexOf('-') + 1).split('.'), pb = B.slice(B.indexOf('-') + 1).split('.');
|
|
29
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
30
|
+
const x = pa[i], y = pb[i];
|
|
31
|
+
if (x === undefined) return -1; // 짧은 쪽이 낮음 (semver: 세그먼트 적은 쪽 <)
|
|
32
|
+
if (y === undefined) return 1;
|
|
33
|
+
const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
|
|
34
|
+
if (nx && ny) { const d = parseInt(x, 10) - parseInt(y, 10); if (d) return d > 0 ? 1 : -1; }
|
|
35
|
+
else if (nx !== ny) return nx ? -1 : 1; // 숫자 < 문자 (semver 규칙)
|
|
36
|
+
else if (x !== y) return x > y ? 1 : -1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
26
39
|
return 0;
|
|
27
40
|
}
|
|
28
41
|
|
package/lib/session-close.js
CHANGED
|
@@ -26,10 +26,19 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
26
26
|
const rows = readProgressRows(root);
|
|
27
27
|
const buckets = {};
|
|
28
28
|
for (const s of STATUSES) buckets[s] = [];
|
|
29
|
-
|
|
29
|
+
// 1.36.34 (codex 3차 #10): 별칭/미지 상태가 어느 카테고리에도 안 담겨 마감 보고에서 조용히 사라짐
|
|
30
|
+
// (completed/cancelled 3건 중 1건만 집계 실측). 별칭은 정규화, 미지는 'other' 버킷으로 — 소실 0.
|
|
31
|
+
const _STATUS_ALIAS = { completed: 'done', complete: 'done', finished: 'done', verified: 'done', cancelled: 'dropped', canceled: 'dropped', cancel: 'dropped', in_progress: 'in-progress', wip: 'in-progress', on_hold: 'on-hold', hold: 'on-hold' };
|
|
32
|
+
buckets.other = [];
|
|
33
|
+
for (const r of rows) {
|
|
34
|
+
const s0 = String(r.status || '').toLowerCase().trim();
|
|
35
|
+
const s = buckets[s0] ? s0 : (_STATUS_ALIAS[s0] && buckets[_STATUS_ALIAS[s0]] ? _STATUS_ALIAS[s0] : 'other');
|
|
36
|
+
buckets[s].push(r);
|
|
37
|
+
}
|
|
30
38
|
// 1.9.103: JSON 결과 누적
|
|
31
39
|
jsonResult.taskCounts = {};
|
|
32
40
|
for (const s of STATUSES) jsonResult.taskCounts[s] = (buckets[s] || []).length;
|
|
41
|
+
if (buckets.other.length) jsonResult.taskCounts.other = buckets.other.length;
|
|
33
42
|
jsonResult.recommendedDirection = (buckets['in-progress'][0]?.request) || (buckets['planned'][0]?.request) || (buckets['requested'][0]?.request) || null;
|
|
34
43
|
jsonResult.nextExactStep = (buckets['in-progress'][0]?.nextAction) || (buckets['planned'][0]?.nextAction) || (buckets['requested'][0]?.nextAction) || null;
|
|
35
44
|
// 1.12.3 (14th 버그헌트 P3, UR-0183): 마감 시 완료 정직성 advisory — done 인데 evidence 가 비었거나 placeholder 인 task 노출(차단 X, 정직성 환기). lazy detect 의 done_no_evidence 휴리스틱과 동일.
|
|
@@ -72,7 +81,7 @@ function sessionClose(root, opts = {}, deps = {}) {
|
|
|
72
81
|
rowsToList(buckets['in-progress']),
|
|
73
82
|
``,
|
|
74
83
|
`## Incomplete / Waiting / On Hold / Blocked`,
|
|
75
|
-
rowsToList([...(buckets['incomplete']||[]), ...(buckets['waiting']||[]), ...(buckets['on-hold']||[]), ...(buckets['blocked']||[])]),
|
|
84
|
+
rowsToList([...(buckets['incomplete']||[]), ...(buckets['waiting']||[]), ...(buckets['on-hold']||[]), ...(buckets['blocked']||[]), ...(buckets.other||[])]), // 1.36.34 (#10): 미지 상태도 소실 없이 표기
|
|
76
85
|
``,
|
|
77
86
|
`## Dropped`,
|
|
78
87
|
rowsToList(buckets['dropped']),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.34",
|
|
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",
|