leerness 1.9.142 → 1.9.143
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 +22 -0
- package/README.md +2 -2
- package/bin/harness.js +52 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.143 — 2026-05-20
|
|
4
|
+
|
|
5
|
+
**JSON 4종 featureGraph 통합 완성 + drift check feature 신호** — 1.9.142 session close --json 패턴을 handoff/health에 확장.
|
|
6
|
+
|
|
7
|
+
### Added — handoff --json featureGraph 통합
|
|
8
|
+
- `result.featureGraph = { total, edges, isolated, summary: "F<n>/E<n>[/iso<n>]" }`
|
|
9
|
+
- 외부 AI가 handoff 한 번에 컨텍스트 + memory surface + featureGraph 동시 회수
|
|
10
|
+
|
|
11
|
+
### Added — health --json featureGraph 통합
|
|
12
|
+
- `out.featureGraph = { total, edges, isolated, summary }`
|
|
13
|
+
- JSON 4종 (handoff/memory status/session close/health) featureGraph 일관성 완성 (memorySurface 1.9.123 패턴과 동형)
|
|
14
|
+
|
|
15
|
+
### Added — drift check feature graph 신호 (6번째 신호)
|
|
16
|
+
- 노드 ≥ 3개 + edges == 0 → weight 25
|
|
17
|
+
- 노드 ≥ 3개 + isolated 비율 ≥ 50% → weight 15
|
|
18
|
+
- `drift check --json` `fired` 배열에 노출
|
|
19
|
+
- 사용자 cascade 방지 의지 + 실제 사용 사이 gap 자동 감지
|
|
20
|
+
|
|
21
|
+
### Validation
|
|
22
|
+
- stress-v88: PASS (handoff/health featureGraph + drift 신호 + 누적 회귀)
|
|
23
|
+
- e2e: 219/219 PASS
|
|
24
|
+
|
|
3
25
|
## 1.9.142 — 2026-05-20
|
|
4
26
|
|
|
5
27
|
**Feature Graph 통합 라운드** — 1.9.141 인과관계 시스템을 audit / MCP CRUD / session close 에 통합.
|
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) []() []() []() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
╔══════════════════════════════════════════════════════════════╗
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
15
|
+
║ v1.9.143 AI Agent Reliability Harness ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · prevent drift ║
|
|
17
17
|
╚══════════════════════════════════════════════════════════════╝
|
|
18
18
|
```
|
package/bin/harness.js
CHANGED
|
@@ -6,7 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const cp = require('child_process');
|
|
7
7
|
const readline = require('readline');
|
|
8
8
|
|
|
9
|
-
const VERSION = '1.9.
|
|
9
|
+
const VERSION = '1.9.143';
|
|
10
10
|
const MARK = '<!-- leerness:managed -->';
|
|
11
11
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
12
12
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -2748,6 +2748,22 @@ function handoff(root) {
|
|
|
2748
2748
|
archive: archiveCountsH, // 1.9.130
|
|
2749
2749
|
summary: `T${tasksInProgress}/D${decisionsCount}/R${rulesActive}/P${milestones}/L${lessonsCount}`,
|
|
2750
2750
|
};
|
|
2751
|
+
// 1.9.143: handoff --json featureGraph 통합 (session close 1.9.142 와 동일 패턴)
|
|
2752
|
+
try {
|
|
2753
|
+
const { nodes: fNodesH } = _readFeatureGraph(root);
|
|
2754
|
+
const edgeCount = fNodesH.reduce((s, n) => s + (n.dependsOn?.length || 0) + (n.affects?.length || 0) + (n.coChangesWith?.length || 0), 0);
|
|
2755
|
+
const linkedSet = new Set();
|
|
2756
|
+
for (const n of fNodesH) {
|
|
2757
|
+
for (const x of [...(n.dependsOn||[]), ...(n.affects||[]), ...(n.coChangesWith||[])]) { linkedSet.add(n.id); linkedSet.add(x); }
|
|
2758
|
+
}
|
|
2759
|
+
const isolated = fNodesH.length ? (fNodesH.length - linkedSet.size) : 0;
|
|
2760
|
+
result.featureGraph = {
|
|
2761
|
+
total: fNodesH.length,
|
|
2762
|
+
edges: edgeCount,
|
|
2763
|
+
isolated: Math.max(0, isolated),
|
|
2764
|
+
summary: `F${fNodesH.length}/E${edgeCount}${isolated > 0 ? `/iso${isolated}` : ''}`
|
|
2765
|
+
};
|
|
2766
|
+
} catch {}
|
|
2751
2767
|
} catch {}
|
|
2752
2768
|
log(JSON.stringify(result, null, 2));
|
|
2753
2769
|
return;
|
|
@@ -4582,7 +4598,7 @@ function _banner(opts = {}) {
|
|
|
4582
4598
|
for (const ln of lines) log(ln);
|
|
4583
4599
|
}
|
|
4584
4600
|
if (opts.quickStart) {
|
|
4585
|
-
log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.
|
|
4601
|
+
log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.143+ JSON 4종 featureGraph 통합 완성 + drift 신호 — 73 라운드 자율 누적)')));
|
|
4586
4602
|
log(' ' + C.green('npx leerness@latest init .') + C.dim(' # 신규 프로젝트 + 외부 AI CLI 설정'));
|
|
4587
4603
|
log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨텍스트 + lessons + 매칭 skill + history hit + brainstorm hits + 헤드라인'));
|
|
4588
4604
|
log(' ' + C.green('npx leerness handoff . --quiet') + C.dim(' # 자동화/CI 모드 (1.9.99) — 자동 회수 라인 비활성'));
|
|
@@ -8200,6 +8216,24 @@ function driftCheckCmd(root, opts = {}) {
|
|
|
8200
8216
|
}
|
|
8201
8217
|
}
|
|
8202
8218
|
} catch {}
|
|
8219
|
+
// 1.9.143: Feature Graph 미사용 신호 — 노드는 있는데 edges 비율 낮으면 인과관계 정리 미진
|
|
8220
|
+
try {
|
|
8221
|
+
const { nodes: fGraphNodes } = _readFeatureGraph(root);
|
|
8222
|
+
if (fGraphNodes.length >= 3) {
|
|
8223
|
+
const edgeCount = fGraphNodes.reduce((s, n) => s + (n.dependsOn?.length || 0) + (n.affects?.length || 0) + (n.coChangesWith?.length || 0), 0);
|
|
8224
|
+
const linkedSet = new Set();
|
|
8225
|
+
for (const n of fGraphNodes) {
|
|
8226
|
+
for (const x of [...(n.dependsOn||[]), ...(n.affects||[]), ...(n.coChangesWith||[])]) { linkedSet.add(n.id); linkedSet.add(x); }
|
|
8227
|
+
}
|
|
8228
|
+
const isolatedCount = Math.max(0, fGraphNodes.length - linkedSet.size);
|
|
8229
|
+
const isolatedRatio = isolatedCount / fGraphNodes.length;
|
|
8230
|
+
if (edgeCount === 0 || isolatedRatio >= 0.5) {
|
|
8231
|
+
const fgScore = edgeCount === 0 ? 25 : 15;
|
|
8232
|
+
totalScore += fgScore;
|
|
8233
|
+
fired.push({ file: '.harness/feature-graph.md', ageDays: null, threshold: 0, weight: fgScore, label: `Feature Graph 미정리 (1.9.143): ${fGraphNodes.length} 노드, edges=${edgeCount}, isolated=${isolatedCount}` });
|
|
8234
|
+
}
|
|
8235
|
+
}
|
|
8236
|
+
} catch {}
|
|
8203
8237
|
// 신규 _apps/* 에서 task 0건도 신호로
|
|
8204
8238
|
const appsDir = path.join(root, '_apps');
|
|
8205
8239
|
let appsZeroTask = [];
|
|
@@ -9600,6 +9634,22 @@ function healthCmd(root) {
|
|
|
9600
9634
|
summary: `T${tasksInProgress}/D${decisionsCount}/R${rulesActive}/P${milestones}/L${lessonsCount}`,
|
|
9601
9635
|
};
|
|
9602
9636
|
} catch { out.memorySurface = { error: 'memorySurface 점검 실패' }; }
|
|
9637
|
+
// 1.9.143: health --json featureGraph 통합 (handoff/session close 와 동일 패턴 — JSON 4종 완성)
|
|
9638
|
+
try {
|
|
9639
|
+
const { nodes: fNodesHe } = _readFeatureGraph(root);
|
|
9640
|
+
const edgeCount = fNodesHe.reduce((s, n) => s + (n.dependsOn?.length || 0) + (n.affects?.length || 0) + (n.coChangesWith?.length || 0), 0);
|
|
9641
|
+
const linkedSet = new Set();
|
|
9642
|
+
for (const n of fNodesHe) {
|
|
9643
|
+
for (const x of [...(n.dependsOn||[]), ...(n.affects||[]), ...(n.coChangesWith||[])]) { linkedSet.add(n.id); linkedSet.add(x); }
|
|
9644
|
+
}
|
|
9645
|
+
const isolated = fNodesHe.length ? (fNodesHe.length - linkedSet.size) : 0;
|
|
9646
|
+
out.featureGraph = {
|
|
9647
|
+
total: fNodesHe.length,
|
|
9648
|
+
edges: edgeCount,
|
|
9649
|
+
isolated: Math.max(0, isolated),
|
|
9650
|
+
summary: `F${fNodesHe.length}/E${edgeCount}${isolated > 0 ? `/iso${isolated}` : ''}`
|
|
9651
|
+
};
|
|
9652
|
+
} catch { out.featureGraph = { error: 'featureGraph 점검 실패' }; }
|
|
9603
9653
|
// 6) issues 요약 (사용자 글로벌 룰 가시화)
|
|
9604
9654
|
const issues = [];
|
|
9605
9655
|
if (out.checks.drift?.level && !/healthy/.test(out.checks.drift.level)) issues.push(`drift ${out.checks.drift.level}`);
|