@kodevibe/harness 0.11.1 → 0.11.2

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/README.ko.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  > **AI 코딩 에이전트는 세션이 끝나면 모든 것을 잊습니다. kode:harness는 목표, 결정, 실패, 프로젝트 방향을 기억하게 합니다.**
13
13
 
14
- AI 코딩 에이전트를 위한 프로덕션급 가드레일. 컨텍스트 부패를 방지하고, 프로젝트 방향을 강제하며, 세션 간 상태를 유지합니다. **Copilot, Claude, Cursor, Codex, Windsurf, Gemini** 지원. 의존성 제로.
14
+ AI 코딩 에이전트를 위한 pre-1.0 가드레일입니다. 실제 프로젝트 파일럿과 팀 사용을 기준으로 방향, proof, 세션 간 메모리를 유지합니다. 컨텍스트 부패를 방지하고, 프로젝트 방향을 강제하며, 세션 간 상태를 유지합니다. **Copilot, Claude, Cursor, Codex, Windsurf, Gemini** 지원. 의존성 제로.
15
15
 
16
16
  > **에코시스템 내 위치.** kode:harness는 **kode:vibe** 에코시스템의 *실행(execution)* 레이어입니다 — 계획 레이어(PRD / 아키텍처 / ARB)와 인프라 레이어(CI / 런타임) 사이에 위치하며, 코딩 중 AI의 방향을 잡아주는 역할을 합니다. 다른 레이어는 선택이며, kode:harness만 독립적으로 쓸 수 있습니다.
17
17
 
@@ -32,6 +32,8 @@ npx @kodevibe/harness init # IDE 선택
32
32
 
33
33
  끝입니다. 이제 AI는 영속적인 메모리, 방향 가드레일, 자기 교정 루프를 갖게 됩니다.
34
34
 
35
+ 처음이라면 [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)부터 보세요. proof-first 흐름은 [docs/PROOF_LEDGER_WALKTHROUGH.md](docs/PROOF_LEDGER_WALKTHROUGH.md), 팀 도입은 [docs/TEAM_ONBOARDING.md](docs/TEAM_ONBOARDING.md), 설치/제거 안전 경계는 [docs/SAFETY_GUIDE.md](docs/SAFETY_GUIDE.md)에 정리했습니다.
36
+
35
37
  v0.11부터는 **Proof-First Enforcement**가 Common Mode Confidence Loop 위에 추가됩니다. pm은 실행 가능한 proof를 계획해야 하고, lead는 증거 없이 Story를 완료 처리하지 않으며, reviewer는 proof가 없거나 실패하면 커밋 안내 전에 멈추고, state-check는 Proof Ledger 누락을 점검합니다.
36
38
 
37
39
  <details>
@@ -170,6 +172,27 @@ npx @kodevibe/harness validate # state 파일에 실제 내용 확인
170
172
  npx @kodevibe/harness uninstall --dry-run --ide vscode # 안전 제거 미리보기
171
173
  ```
172
174
 
175
+ 소스 repo maintainer는 결정론 guard와 model-tier 증거 체크도 함께 실행할 수 있습니다:
176
+
177
+ ```bash
178
+ npm run harness:check-pack
179
+ npm run harness:guard:all
180
+ npm run harness:guard:wrap-up -- --quiet
181
+ npm run harness:state-sync
182
+ npm run harness:dependency-scan
183
+ npm run harness:llm-bench:smoke
184
+ ```
185
+
186
+ 릴리즈 증거로 인정하려면 예시 fixture 대신 실제 3개 이상 모델 tier의 sealed result를 `docs/llm-bench-results.json`에 기록한 뒤 실행하세요. 각 run은 `docs/llm-bench-scenarios.json`의 표준 시나리오를 사용해야 하며, `capturedAt`, 일치하는 `promptHash`, `outputHash` 또는 `transcriptHash`가 필요합니다.
187
+
188
+ ```bash
189
+ npm run harness:llm-bench:export
190
+ node scripts/llm-bench.js --collect-results --model-id local-small-2026-06-08 --tier constrained --outputs bench/r10/local-small-2026-06-08 --out docs/llm-bench-results.json --append
191
+ npm run harness:llm-bench:real
192
+ ```
193
+
194
+ 전체 3-model 증거 생성 절차는 `docs/LLM_BENCH_GUIDE.md`를 참고하세요.
195
+
173
196
  ---
174
197
 
175
198
  ## 지원 IDE
@@ -329,6 +352,12 @@ npx @kodevibe/harness init --team
329
352
 
330
353
  ---
331
354
 
355
+ ## 문서
356
+
357
+ 패키지 사용자는 이 README에서 시작하면 됩니다. 저장소 maintainer는 GitHub 전용 [docs/wiki-index.md](https://github.com/AIDD-Projects/harness/blob/main/docs/wiki-index.md)를 source repo 문서 지도로 사용합니다. 기여 가이드, 아키텍처 노트, 릴리스 기록, local docs hub 경계를 연결하되, source repo 안에 active harness instruction을 다시 설치하지 않습니다.
358
+
359
+ ---
360
+
332
361
  ## 왜 만들었나
333
362
 
334
363
  기존 AI 코딩 프레임워크는 **AI가 무엇을 하는지** — 코드 생성, 테스트 실행, 배포에 집중합니다. 하지만 진짜 문제는 능력이 아닙니다. **방향**입니다.
@@ -380,7 +409,7 @@ Bootstrap이 `docs/crew/`, `docs/PM/`, `docs/Analyst/`, `docs/ARB/`에서 crew
380
409
 
381
410
  ## 로드맵
382
411
 
383
- kode:harness는 현재 **v0.11.1** — manifest 기반 안전 제거를 추가해 설치 흔적을 미리보기, 보존, 복원, purge 흐름으로 관리합니다. Common Mode의 proof-first 동작도 계속 강제합니다.
412
+ kode:harness는 현재 **v0.11.2** — v0.11의 proof-first와 uninstall safety 기반 위에 deterministic source-repo guardrail과 manifest-sealed R10 model benchmark workflow를 추가했습니다.
384
413
 
385
414
  | 단계 | 버전 | 상태 | 초점 |
386
415
  |------|------|------|------|
@@ -395,7 +424,8 @@ kode:harness는 현재 **v0.11.1** — manifest 기반 안전 제거를 추가
395
424
  | **Drift Guard & Positioning** | v0.9.7 | ✅ 완료 | `harness/`↔`.github/` drift 가드, reviewer working-proof 게이트, kode:vibe 위치 안내, IDE 선택 가이드, project-brief 예시 |
396
425
  | **Confidence Loop** | v0.10.0 | ✅ 완료 | Goal Card, Quiet Navigator, Evidence-Gated Progress Board, Proof Ledger, QA/content 회귀 테스트 |
397
426
  | **Proof-First Enforcement** | v0.11.0 | ✅ 완료 | Mandatory Proof Plan, lead proof blocker, reviewer proof blocker, state-check Proof Ledger coverage |
398
- | **Uninstall Safety** | v0.11.1 | ✅ 현재 | Manifest 기반 uninstall, state 기본 보존, shared owner 복원, purge cleanup |
427
+ | **Uninstall Safety** | v0.11.1 | ✅ 완료 | Manifest 기반 uninstall, state 기본 보존, shared owner 복원, purge cleanup |
428
+ | **Deterministic Release Guard** | v0.11.2 | ✅ 현재 | R1-R10 guard scripts, package-boundary scan, dependency-map scan, R10 manifest-sealed bench workflow |
399
429
  | **Docs Bridge** | v0.11.1 | 🧪 Experimental | Project Docs Hub Index, docs-bridge 스킬, visibility 경계를 가진 로컬 docs hub 인덱스 |
400
430
  | **Safety & Branding** | v0.9.6 | ✅ 완료 | init overwrite 백업, 배포 파일 pm 네이밍 정리, LICENSE 브랜딩 정리 |
401
431
  | **Validation** | v1.0 | 🔜 다음 | 실사용 검증, 사용자 피드백 수집 |
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  > **Your AI coding agent forgets everything between sessions. kode:harness makes it remember — goals, decisions, failures, and project direction.**
13
13
 
14
- Production-grade guardrails for AI coding agents. Prevents context rot, enforces project direction, and persists state across sessions. Works with **Copilot, Claude, Cursor, Codex, Windsurf, and Gemini**. Zero dependencies.
14
+ Pre-1.0 guardrails for AI coding agents, designed for real project pilots and teams that need direction, proof, and memory across sessions. Prevents context rot, enforces project direction, and persists state across sessions. Works with **Copilot, Claude, Cursor, Codex, Windsurf, and Gemini**. Zero dependencies.
15
15
 
16
16
  > **Where this fits.** kode:harness is the *execution* layer of the **kode:vibe** ecosystem — it sits between a planning layer (PRD / architecture / ARB) and an infrastructure layer (CI / runtime). kode:harness keeps the AI on direction while you code; the other layers are optional. You can use kode:harness alone.
17
17
 
@@ -32,6 +32,8 @@ npx @kodevibe/harness init # pick your IDE
32
32
 
33
33
  That's it. Your AI now has persistent memory, direction guardrails, and self-correction loops.
34
34
 
35
+ New to kode:harness? Start with [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md), then read [docs/PROOF_LEDGER_WALKTHROUGH.md](docs/PROOF_LEDGER_WALKTHROUGH.md) for the proof-first loop. Teams should also read [docs/TEAM_ONBOARDING.md](docs/TEAM_ONBOARDING.md). For install and uninstall trust boundaries, see [docs/SAFETY_GUIDE.md](docs/SAFETY_GUIDE.md).
36
+
35
37
  v0.11 adds **Proof-First Enforcement** on top of the Common Mode Confidence Loop: pm must define runnable proof, lead cannot mark a Story done without passing evidence, reviewer blocks commit guidance when proof is missing or failing, and state-check audits Proof Ledger coverage.
36
38
 
37
39
  <details>
@@ -182,6 +184,27 @@ npx @kodevibe/harness validate # verify state files have real content
182
184
  npx @kodevibe/harness uninstall --dry-run --ide vscode # preview safe removal
183
185
  ```
184
186
 
187
+ Source repo maintainers can also run the deterministic guard and model-tier evidence checks:
188
+
189
+ ```bash
190
+ npm run harness:check-pack
191
+ npm run harness:guard:all
192
+ npm run harness:guard:wrap-up -- --quiet
193
+ npm run harness:state-sync
194
+ npm run harness:dependency-scan
195
+ npm run harness:llm-bench:smoke
196
+ ```
197
+
198
+ For release evidence, replace the example fixture with sealed results from at least three real model tiers. Each run must use the standard scenarios in `docs/llm-bench-scenarios.json` and include `capturedAt`, a matching `promptHash`, and `outputHash` or `transcriptHash`.
199
+
200
+ ```bash
201
+ npm run harness:llm-bench:export
202
+ node scripts/llm-bench.js --collect-results --model-id local-small-2026-06-08 --tier constrained --outputs bench/r10/local-small-2026-06-08 --out docs/llm-bench-results.json --append
203
+ npm run harness:llm-bench:real
204
+ ```
205
+
206
+ See `docs/LLM_BENCH_GUIDE.md` for the full three-model evidence workflow.
207
+
185
208
  ## Supported IDEs
186
209
 
187
210
  Not sure which to pick? Use the IDE you already code in — each install path is generated from the same `harness/` source, so the underlying skills/agents are identical:
@@ -315,7 +338,7 @@ These 11 rules are enforced across all skills and agents. They form the quality
315
338
 
316
339
  ## Documentation
317
340
 
318
- See [docs/reference.md](docs/reference.md) for detailed descriptions of every skill, agent, rule, and state file.
341
+ Package users can start with this README. Repository maintainers can use the GitHub-only [docs/wiki-index.md](https://github.com/AIDD-Projects/harness/blob/main/docs/wiki-index.md) as the source repo documentation map; it links the contribution guide, architecture notes, release history, and local docs hub boundaries without installing active harness instructions into this repo.
319
342
 
320
343
  ## Why We Built This
321
344
 
@@ -366,7 +389,7 @@ It adds a Project Docs Hub Index to `project-brief.md` with each local source, r
366
389
 
367
390
  ## Roadmap
368
391
 
369
- kode:harness is at **v0.11.1** — adds manifest-based safe uninstall so generated IDE files can be previewed, preserved, restored, or purged intentionally. Common Mode proof-first behavior remains enforceable.
392
+ kode:harness is at **v0.11.2** — adds deterministic source-repo guardrails and a manifest-sealed R10 model benchmark workflow on top of the v0.11 proof-first and uninstall safety foundation.
370
393
 
371
394
  | Phase | Version | Status | Focus |
372
395
  |---|---|---|---|
@@ -381,7 +404,8 @@ kode:harness is at **v0.11.1** — adds manifest-based safe uninstall so generat
381
404
  | **Drift Guard & Positioning** | v0.9.7 | ✅ Done | `harness/`↔`.github/` drift detector, reviewer working-proof gate, kode:vibe positioning, IDE selection guide, project-brief example |
382
405
  | **Confidence Loop** | v0.10.0 | ✅ Done | Goal Card, Quiet Navigator, Evidence-Gated Progress Board, Proof Ledger, QA/content regression tests |
383
406
  | **Proof-First Enforcement** | v0.11.0 | ✅ Complete | Mandatory Proof Plan, lead proof blockers, reviewer proof blockers, state-check Proof Ledger coverage |
384
- | **Uninstall Safety** | v0.11.1 | ✅ Current | Manifest-based uninstall, default state preservation, shared owner restore, purge cleanup |
407
+ | **Uninstall Safety** | v0.11.1 | ✅ Complete | Manifest-based uninstall, default state preservation, shared owner restore, purge cleanup |
408
+ | **Deterministic Release Guard** | v0.11.2 | ✅ Current | R1-R10 guard scripts, package-boundary scan, dependency-map scan, R10 manifest-sealed bench workflow |
385
409
  | **Docs Bridge** | v0.11.1 | 🧪 Experimental | Project Docs Hub Index, docs-bridge skill, local docs hub index with visibility boundaries |
386
410
  | **Safety & Branding** | v0.9.6 | ✅ Done | init overwrite backups, shipped pm naming cleanup, LICENSE branding cleanup |
387
411
  | **Validation** | v1.0 | 🔜 Next | Real-world project adoption, user feedback collection |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kodevibe/harness",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "kode:harness — harness engineering for keeping every developer's AI aligned on one project direction.",
5
5
  "keywords": [
6
6
  "llm",
@@ -46,8 +46,17 @@
46
46
  },
47
47
  "scripts": {
48
48
  "test": "node --test tests/*.test.js",
49
+ "harness:check-pack": "node scripts/check-public-pack.js",
49
50
  "harness:check-drift": "node scripts/check-harness-drift.js",
50
- "harness:sync": "node bin/cli.js init --ide vscode --batch --dir . --overwrite"
51
+ "harness:dependency-scan": "node scripts/check-dependency-map.js",
52
+ "harness:guard": "node scripts/harness-guard.js",
53
+ "harness:guard:all": "node scripts/harness-guard.js --all",
54
+ "harness:guard:wrap-up": "node scripts/harness-guard.js --wrap-up",
55
+ "harness:llm-bench": "node scripts/llm-bench.js",
56
+ "harness:llm-bench:export": "node scripts/llm-bench.js --export-prompts --scenarios docs/llm-bench-scenarios.json --out bench/r10",
57
+ "harness:llm-bench:smoke": "node scripts/llm-bench.js docs/llm-bench-results.example.json",
58
+ "harness:llm-bench:real": "node scripts/llm-bench.js docs/llm-bench-results.json --require-real",
59
+ "harness:state-sync": "node scripts/harness-guard.js --state-sync"
51
60
  },
52
61
  "publishConfig": {
53
62
  "access": "public"
@@ -0,0 +1,194 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const SOURCE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs']);
7
+ const DEFAULT_ROOTS = ['src', 'app', 'lib', 'packages', 'services'];
8
+ const SKIP_DIRS = new Set(['.git', '.harness', 'node_modules', 'dist', 'build', 'coverage', '.next', '.turbo']);
9
+
10
+ function toPosix(file) {
11
+ return String(file || '').replace(/\\/g, '/');
12
+ }
13
+
14
+ function stripCodeComments(content) {
15
+ return String(content || '')
16
+ .replace(/\/\*[\s\S]*?\*\//g, '')
17
+ .replace(/(^|[^:])\/\/.*$/gm, '$1');
18
+ }
19
+
20
+ function isSourceFile(file) {
21
+ return SOURCE_EXTENSIONS.has(path.extname(file));
22
+ }
23
+
24
+ function walkSourceFiles(cwd, roots = DEFAULT_ROOTS) {
25
+ const files = [];
26
+
27
+ function walk(dir) {
28
+ if (!fs.existsSync(dir)) return;
29
+ for (const name of fs.readdirSync(dir)) {
30
+ if (SKIP_DIRS.has(name)) continue;
31
+ const full = path.join(dir, name);
32
+ const st = fs.statSync(full);
33
+ if (st.isDirectory()) walk(full);
34
+ else if (st.isFile() && isSourceFile(full)) files.push(toPosix(path.relative(cwd, full)));
35
+ }
36
+ }
37
+
38
+ for (const root of roots) walk(path.join(cwd, root));
39
+ return files.sort();
40
+ }
41
+
42
+ function moduleKeyForFile(file) {
43
+ const parts = toPosix(file).split('/').filter(Boolean);
44
+ if (parts.length === 0) return '';
45
+ if (parts[0] === 'packages' || parts[0] === 'services') {
46
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0];
47
+ }
48
+ if (DEFAULT_ROOTS.includes(parts[0])) {
49
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0];
50
+ }
51
+ return parts[0];
52
+ }
53
+
54
+ function extractLocalSpecifiers(content) {
55
+ const clean = stripCodeComments(content);
56
+ const specs = [];
57
+ const patterns = [
58
+ /\bimport\s+(?:[^'"]+\s+from\s+)?['"]([^'"]+)['"]/g,
59
+ /\bexport\s+[^'"]+\s+from\s+['"]([^'"]+)['"]/g,
60
+ /\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
61
+ /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
62
+ ];
63
+ for (const re of patterns) {
64
+ for (const match of clean.matchAll(re)) {
65
+ const spec = match[1];
66
+ if (spec.startsWith('.')) specs.push(spec);
67
+ }
68
+ }
69
+ return specs;
70
+ }
71
+
72
+ function normalizeRelativeTarget(fromFile, specifier) {
73
+ const fromDir = path.posix.dirname(toPosix(fromFile));
74
+ return path.posix.normalize(path.posix.join(fromDir, specifier));
75
+ }
76
+
77
+ function scanDependencyGraph({ cwd = process.cwd(), files = null, roots = DEFAULT_ROOTS } = {}) {
78
+ const sourceFiles = files ? files.filter(isSourceFile).map(toPosix).sort() : walkSourceFiles(cwd, roots);
79
+ const modules = new Map();
80
+
81
+ for (const file of sourceFiles) {
82
+ const module = moduleKeyForFile(file);
83
+ if (!module) continue;
84
+ if (!modules.has(module)) modules.set(module, { module, files: new Set(), dependsOn: new Set() });
85
+ modules.get(module).files.add(file);
86
+
87
+ const abs = path.join(cwd, file);
88
+ if (!fs.existsSync(abs)) continue;
89
+ const content = fs.readFileSync(abs, 'utf8');
90
+ for (const spec of extractLocalSpecifiers(content)) {
91
+ const target = normalizeRelativeTarget(file, spec);
92
+ const dep = moduleKeyForFile(target);
93
+ if (dep && dep !== module) modules.get(module).dependsOn.add(dep);
94
+ }
95
+ }
96
+
97
+ return [...modules.values()]
98
+ .map((entry) => ({
99
+ module: entry.module,
100
+ files: [...entry.files].sort(),
101
+ dependsOn: [...entry.dependsOn].sort(),
102
+ }))
103
+ .sort((a, b) => a.module.localeCompare(b.module));
104
+ }
105
+
106
+ function markdownTableRows(section) {
107
+ const lines = String(section || '').split('\n').map((line) => line.trim()).filter((line) => line.startsWith('|'));
108
+ if (lines.length < 2) return [];
109
+ const headers = lines[0].replace(/^\|/, '').replace(/\|$/, '').split('|').map((cell) => cell.trim());
110
+ return lines.slice(2)
111
+ .filter((line) => !/^\|\s*[-:|\s]+\|?$/.test(line))
112
+ .map((line) => {
113
+ const cells = line.replace(/^\|/, '').replace(/\|$/, '').split('|').map((cell) => cell.trim());
114
+ const row = {};
115
+ headers.forEach((header, i) => { row[header] = cells[i] || ''; });
116
+ row.__raw = line;
117
+ return row;
118
+ });
119
+ }
120
+
121
+ function section(content, header) {
122
+ const re = new RegExp(`^##\\s+${header}\\s*$`, 'm');
123
+ const match = re.exec(content);
124
+ if (!match) return '';
125
+ const rest = content.slice(match.index + match[0].length);
126
+ const next = /^##\s+/m.exec(rest);
127
+ return next ? rest.slice(0, next.index) : rest;
128
+ }
129
+
130
+ function splitDepends(value) {
131
+ return String(value || '')
132
+ .replace(/`/g, '')
133
+ .split(/(?:<br\s*\/?>|[,;]|\s{2,})/i)
134
+ .map((item) => item.trim())
135
+ .filter((item) => item && !/^[-–—]$/.test(item) && !/^n\/a$/i.test(item) && !/^none$/i.test(item));
136
+ }
137
+
138
+ function parseDependencyMap(content) {
139
+ const body = section(content, 'Module Registry')
140
+ || section(content, 'Module Dependency Map')
141
+ || section(content, 'Module Map')
142
+ || content;
143
+ return markdownTableRows(body)
144
+ .map((row) => ({
145
+ module: row.Module || row.module || '',
146
+ dependsOn: splitDepends(row['Depends On'] || row.Depends || row.Dependencies || ''),
147
+ raw: row.__raw,
148
+ }))
149
+ .filter((row) => row.module);
150
+ }
151
+
152
+ function checkDependencyMapCoverage({ graph = [], dependencyMap = '' } = {}) {
153
+ const violations = [];
154
+ const rows = parseDependencyMap(dependencyMap);
155
+ const rowByModule = new Map(rows.map((row) => [row.module, row]));
156
+
157
+ for (const item of graph) {
158
+ const row = rowByModule.get(item.module);
159
+ if (!row) {
160
+ violations.push({
161
+ check: 'dependency-scan',
162
+ severity: 'error',
163
+ line: 0,
164
+ message: `Module ${item.module} exists in source files but is missing from dependency-map.md (R7 source dependency scan).`,
165
+ });
166
+ continue;
167
+ }
168
+ const mapped = row.dependsOn.join(' ');
169
+ for (const dep of item.dependsOn) {
170
+ if (!mapped.includes(dep)) {
171
+ violations.push({
172
+ check: 'dependency-scan',
173
+ severity: 'error',
174
+ line: 0,
175
+ message: `Module ${item.module} imports ${dep}, but dependency-map.md does not list it in Depends On (R7 source dependency scan).`,
176
+ });
177
+ }
178
+ }
179
+ }
180
+
181
+ return violations;
182
+ }
183
+
184
+ module.exports = {
185
+ DEFAULT_ROOTS,
186
+ isSourceFile,
187
+ walkSourceFiles,
188
+ moduleKeyForFile,
189
+ extractLocalSpecifiers,
190
+ normalizeRelativeTarget,
191
+ scanDependencyGraph,
192
+ parseDependencyMap,
193
+ checkDependencyMapCoverage,
194
+ };