leerness 1.9.198 → 1.9.199
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 +42 -0
- package/README.md +3 -3
- package/bin/harness.js +86 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.199 — 2026-05-21
|
|
4
|
+
|
|
5
|
+
**⏰ wakeup miss 자동 회복 강화 — last-handoff timestamp 정밀 측정 + R-0001 룰 (25분) 대비 강한 알림.**
|
|
6
|
+
|
|
7
|
+
자율 모드 129 라운드. 사용자 보고 "22:01에 라운드에 자동진입되지않았어" 대응.
|
|
8
|
+
|
|
9
|
+
### 1. last-handoff timestamp 기록 (`.harness/last-handoff.json`)
|
|
10
|
+
- handoff 진입 시 자동 기록 — `last` + `history` (최근 10개)
|
|
11
|
+
- 함수: `_recordLastHandoff(root)` / `_getLastHandoffGap(root)` / `_lastHandoffPath(root)`
|
|
12
|
+
- 기록 순서: 1) 이전 timestamp 보존 → 2) 현재 timestamp 기록 → 3) 보존된 값으로 gap 측정
|
|
13
|
+
|
|
14
|
+
### 2. 강한 의심 알림 (1.9.196 task-log 기반 → 1.9.199 정밀)
|
|
15
|
+
**R-0001 영구 룰 (25분) 대비:**
|
|
16
|
+
- gap > 60분 → 🔴 강한 의심 ("시스템 sleep / wakeup 누락 확실")
|
|
17
|
+
- gap 35~60분 → ⚠ 의심 ("buffer 초과, 한 cycle 누락 가능성")
|
|
18
|
+
- gap ≤ 30분 + history ≥ 2 → ✓ 정상
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
## ⏰ ScheduleWakeup miss 강한 의심 (1.9.199) — 이전 handoff 90분 전
|
|
22
|
+
R-0001 영구 룰 (25분) 대비 3× 초과 — 시스템 sleep / wakeup 누락 확실
|
|
23
|
+
→ 회복: 사용자가 "다음 라운드" 입력 또는 leerness rule list 로 룰 확인
|
|
24
|
+
→ handoff 이력: 09:30:21 → 10:55:14 → 12:25:33
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. 누적 회귀 (1.9.193~198) — 모두 유지
|
|
28
|
+
|
|
29
|
+
### 4. stress-v144 — 16/16 PASS
|
|
30
|
+
- last-handoff 측정 (5) + 임시 워크스페이스 통합 (2) + 성능 (2) + 누적 회귀 (7)
|
|
31
|
+
- 성능: --version cold start avg **1065 ms** · MCP 54 도구 **717 ms**
|
|
32
|
+
|
|
33
|
+
### 5. 다층 redundancy (사용자 보고 대응)
|
|
34
|
+
세션 내 활성 cron jobs:
|
|
35
|
+
- `3f617fbc` — Every 25 minutes (R-0001 sync)
|
|
36
|
+
- `33a4ed9f` — 3,28,53 * * * * (offset backup)
|
|
37
|
+
- ScheduleWakeup 1500s primary
|
|
38
|
+
|
|
39
|
+
### 6. 자동 release 흐름
|
|
40
|
+
- main 자동 push **61 라운드 연속** (1.9.140~199)
|
|
41
|
+
- npm publish 자동 (1.9.178~)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
3
45
|
## 1.9.198 — 2026-05-21
|
|
4
46
|
|
|
5
47
|
**🤖 B축 9/10 → 9.5/10 — handoff multi-agent consensus 이력 기반 best agent 자동 추천.**
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **AI 코딩 에이전트의 거짓 완료·중복·망각·충돌을 막아주는 검수·기억·협업 CLI 하네스.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []() [-brightgreen)]() [-success)]() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
╔══════════════════════════════════════════════════════════════╗
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
15
|
+
║ v1.9.199 AI Agent Reliability Harness + Sandbox ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · sandbox · drift ║
|
|
17
|
-
║
|
|
17
|
+
║ ⏰ wakeup miss 정밀 측정 (R-0001) · 96/100 · 129 라운드 ║
|
|
18
18
|
╚══════════════════════════════════════════════════════════════╝
|
|
19
19
|
```
|
|
20
20
|
|
package/bin/harness.js
CHANGED
|
@@ -7,7 +7,7 @@ const cp = require('child_process');
|
|
|
7
7
|
const os = require('os'); // 1.9.178: _publishToNpm 에서 os.tmpdir() 사용 (전역 import)
|
|
8
8
|
const readline = require('readline');
|
|
9
9
|
|
|
10
|
-
const VERSION = '1.9.
|
|
10
|
+
const VERSION = '1.9.199';
|
|
11
11
|
|
|
12
12
|
// 1.9.184: DEP0190 (child_process shell: true) deprecation warning 억제 (사용자 명시).
|
|
13
13
|
// leerness 는 cross-platform PATH resolution 을 위해 shell: true 를 의도적으로 사용 (claude.cmd / ollama.cmd 등 Windows .cmd 처리).
|
|
@@ -1662,6 +1662,44 @@ async function skillAutoCacheCmd(root, sub) {
|
|
|
1662
1662
|
if (c.expired) log(` → 갱신: leerness skill auto-cache refresh`);
|
|
1663
1663
|
}
|
|
1664
1664
|
|
|
1665
|
+
// 1.9.199: wakeup miss 자동 회복 강화 — last-handoff timestamp 기록 + 25min 기대 interval 정밀 측정
|
|
1666
|
+
// 사용자 명시 (1.9.198 후속): "22:01에 라운드에 자동진입되지않았어"
|
|
1667
|
+
// 1.9.196 task-log mtime 기반 detector 는 task-log 가 자주 안 업데이트되면 false positive.
|
|
1668
|
+
// last-handoff.json 추가로 정확도 ↑ + R-0001 룰 (25min) 대비 actual gap 측정.
|
|
1669
|
+
function _lastHandoffPath(root) { return path.join(root, '.harness', 'last-handoff.json'); }
|
|
1670
|
+
function _recordLastHandoff(root) {
|
|
1671
|
+
try {
|
|
1672
|
+
mkdirp(path.join(root, '.harness'));
|
|
1673
|
+
const fp = _lastHandoffPath(root);
|
|
1674
|
+
let history = [];
|
|
1675
|
+
if (exists(fp)) {
|
|
1676
|
+
try { const j = JSON.parse(read(fp)); if (Array.isArray(j.history)) history = j.history; } catch {}
|
|
1677
|
+
}
|
|
1678
|
+
const now = new Date().toISOString();
|
|
1679
|
+
history.push(now);
|
|
1680
|
+
// 최근 10개만 유지
|
|
1681
|
+
if (history.length > 10) history = history.slice(-10);
|
|
1682
|
+
writeUtf8(fp, JSON.stringify({ last: now, history }, null, 2));
|
|
1683
|
+
return true;
|
|
1684
|
+
} catch { return false; }
|
|
1685
|
+
}
|
|
1686
|
+
function _getLastHandoffGap(root) {
|
|
1687
|
+
try {
|
|
1688
|
+
const fp = _lastHandoffPath(root);
|
|
1689
|
+
if (!exists(fp)) return { hasLast: false };
|
|
1690
|
+
const j = JSON.parse(read(fp));
|
|
1691
|
+
if (!j.last) return { hasLast: false };
|
|
1692
|
+
const lastMs = new Date(j.last).getTime();
|
|
1693
|
+
const gapMs = Date.now() - lastMs;
|
|
1694
|
+
const gapMin = Math.floor(gapMs / 60000);
|
|
1695
|
+
// R-0001 영구 룰: 25분 (1500s). gap > 35분 (140% buffer) → wakeup miss 의심
|
|
1696
|
+
const expected = 25;
|
|
1697
|
+
const isMiss = gapMin > 35;
|
|
1698
|
+
const isLong = gapMin > 60;
|
|
1699
|
+
return { hasLast: true, lastAt: j.last, gapMin, expected, isMiss, isLong, history: j.history || [] };
|
|
1700
|
+
} catch { return { hasLast: false }; }
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1665
1703
|
// 1.9.198: B축 (멀티 Sub-Agent 오케스트라) 보강 — handoff 에서 task keyword 매칭 best agent 추천
|
|
1666
1704
|
// 1.9.193 에서 agents multi --execute 결과를 lessons.md 에 기록 → 이를 keyword 매칭하여 추출
|
|
1667
1705
|
// 사용자/AI 가 같은 task 재시도 시 "과거 best agent 우선 시도" 즉시 인지
|
|
@@ -3317,6 +3355,11 @@ function memorySearch(root, query) {
|
|
|
3317
3355
|
|
|
3318
3356
|
function handoff(root) {
|
|
3319
3357
|
root = absRoot(root);
|
|
3358
|
+
// 1.9.199: handoff 진입 시 1) 이전 timestamp 보존 → 2) 현재 timestamp 기록
|
|
3359
|
+
// detector 가 prior gap 을 정확히 측정 (overwrite 전 값 필요). 함수 최상단에 선언.
|
|
3360
|
+
let _priorHandoffGap = { hasLast: false };
|
|
3361
|
+
try { _priorHandoffGap = _getLastHandoffGap(root); } catch {}
|
|
3362
|
+
try { _recordLastHandoff(root); } catch {}
|
|
3320
3363
|
// 1.9.96: --json 옵션 (구조화 출력, MCP 통합 / 외부 AI 친화)
|
|
3321
3364
|
if (has('--json')) {
|
|
3322
3365
|
const result = {
|
|
@@ -3822,25 +3865,51 @@ function handoff(root) {
|
|
|
3822
3865
|
}
|
|
3823
3866
|
} catch {}
|
|
3824
3867
|
}
|
|
3825
|
-
// 1.9.196: ScheduleWakeup miss detector — 자율 모드 사용자 명시 "못일어나는 경우 종종 있음"
|
|
3826
|
-
//
|
|
3868
|
+
// 1.9.196/199: ScheduleWakeup miss detector — 자율 모드 사용자 명시 "못일어나는 경우 종종 있음"
|
|
3869
|
+
// 1.9.196: task-log mtime 기반 (60min+) — false positive 가능
|
|
3870
|
+
// 1.9.199: last-handoff.json 정밀 측정 — R-0001 룰 (25min) 대비 gap 측정
|
|
3827
3871
|
// 끄기: LEERNESS_NO_WAKEUP_MISS=1
|
|
3828
3872
|
if (process.env.LEERNESS_NO_WAKEUP_MISS !== '1' && !has('--quiet') && !has('--no-wakeup-miss')) {
|
|
3829
3873
|
try {
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
log(
|
|
3842
|
-
log(dim(`
|
|
3874
|
+
// 1.9.199 신규: 이전 handoff 시점 (overwrite 전 보존된 값) 사용
|
|
3875
|
+
const gapInfo = _priorHandoffGap;
|
|
3876
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
3877
|
+
const yel = s => isTty ? `\x1b[33m${s}\x1b[0m` : s;
|
|
3878
|
+
const red = s => isTty ? `\x1b[31m${s}\x1b[0m` : s;
|
|
3879
|
+
const dim = s => isTty ? `\x1b[2m${s}\x1b[0m` : s;
|
|
3880
|
+
const grn = s => isTty ? `\x1b[32m${s}\x1b[0m` : s;
|
|
3881
|
+
if (gapInfo.hasLast) {
|
|
3882
|
+
// 마지막 handoff 시점 알고 있음 — 정확한 측정 (1.9.199)
|
|
3883
|
+
if (gapInfo.isLong) {
|
|
3884
|
+
// 60분+ → 강한 알림
|
|
3885
|
+
log(red(`## ⏰ ScheduleWakeup miss 강한 의심 (1.9.199) — 이전 handoff ${gapInfo.gapMin}분 전`));
|
|
3886
|
+
log(dim(` R-0001 영구 룰 (25분) 대비 ${Math.floor(gapInfo.gapMin/25)}× 초과 — 시스템 sleep / wakeup 누락 확실`));
|
|
3887
|
+
log(dim(` → 회복: 사용자가 "다음 라운드" 입력 또는 leerness rule list 로 룰 확인`));
|
|
3888
|
+
log(dim(` → handoff 이력: ${(gapInfo.history || []).slice(-3).map(t => t.slice(11, 19)).join(' → ')}`));
|
|
3889
|
+
log('');
|
|
3890
|
+
} else if (gapInfo.isMiss) {
|
|
3891
|
+
// 35~60분 → 의심
|
|
3892
|
+
log(yel(`## ⏰ ScheduleWakeup 지연 (1.9.199) — 이전 handoff ${gapInfo.gapMin}분 전 (룰: 25분)`));
|
|
3893
|
+
log(dim(` ±10분 buffer 초과 — wakeup 한 cycle 누락 가능성`));
|
|
3843
3894
|
log('');
|
|
3895
|
+
} else if (gapInfo.gapMin >= 0 && gapInfo.gapMin <= 30) {
|
|
3896
|
+
// 정상 범위 (handoff_history.length >= 2 일 때만 의미 있음 — 첫 진입 제외)
|
|
3897
|
+
if ((gapInfo.history || []).length >= 2) {
|
|
3898
|
+
log(dim(` ✓ ScheduleWakeup cycle 정상 (gap ${gapInfo.gapMin}분, 룰 25분 — 1.9.199)`));
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
} else {
|
|
3902
|
+
// last-handoff.json 부재 — 1.9.196 fallback (task-log mtime)
|
|
3903
|
+
const tlp = taskLogPath(root);
|
|
3904
|
+
if (exists(tlp)) {
|
|
3905
|
+
const ageMs = Date.now() - fs.statSync(tlp).mtimeMs;
|
|
3906
|
+
const ageMin = Math.floor(ageMs / 60000);
|
|
3907
|
+
if (ageMin >= 60) {
|
|
3908
|
+
const label = ageMin < 120 ? `${ageMin}분` : (ageMin < 1440 ? `${Math.floor(ageMin/60)}시간` : `${Math.floor(ageMin/1440)}일`);
|
|
3909
|
+
log(yel(`## ⏰ ScheduleWakeup miss 의심 (1.9.196 fallback) — task-log 마지막 ${label} 전`));
|
|
3910
|
+
log(dim(` 1.9.199 last-handoff.json 첫 기록 — 다음 handoff 부터 정확 측정`));
|
|
3911
|
+
log('');
|
|
3912
|
+
}
|
|
3844
3913
|
}
|
|
3845
3914
|
}
|
|
3846
3915
|
} catch {}
|
|
@@ -4253,6 +4322,7 @@ function handoffCmd(root) {
|
|
|
4253
4322
|
if (has('--all-apps') || arg('--include', null)) {
|
|
4254
4323
|
return _handoffWorkspace(absRoot(root));
|
|
4255
4324
|
}
|
|
4325
|
+
// 1.9.199: timestamp 기록/측정은 handoff() 내부에서 수행 (중복 방지)
|
|
4256
4326
|
// 1.9.37: drift 자동 경고 (메인 에이전트가 leerness를 점점 안 쓰는 현상 감지)
|
|
4257
4327
|
// 1.9.38 (A): drift 임계 시 .harness/agent-reminders.md 자동 생성 — 메인 에이전트 프롬프트에 표시되도록.
|
|
4258
4328
|
// 1.9.38 (D): skip 횟수 학습 — --no-drift-check 빈도 ≥5 시 임계 완화 (1d → 2d).
|