@su-record/vibe 2.8.41 → 2.8.44
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/CLAUDE.md +1 -0
- package/dist/cli/postinstall/constants.d.ts.map +1 -1
- package/dist/cli/postinstall/constants.js +1 -0
- package/dist/cli/postinstall/constants.js.map +1 -1
- package/dist/infra/lib/VerificationLoop.d.ts +62 -0
- package/dist/infra/lib/VerificationLoop.d.ts.map +1 -1
- package/dist/infra/lib/VerificationLoop.js +115 -0
- package/dist/infra/lib/VerificationLoop.js.map +1 -1
- package/dist/infra/lib/evolution/GuardAnalyzer.d.ts +44 -0
- package/dist/infra/lib/evolution/GuardAnalyzer.d.ts.map +1 -0
- package/dist/infra/lib/evolution/GuardAnalyzer.js +116 -0
- package/dist/infra/lib/evolution/GuardAnalyzer.js.map +1 -0
- package/dist/infra/lib/evolution/HookTraceReader.d.ts +45 -0
- package/dist/infra/lib/evolution/HookTraceReader.d.ts.map +1 -0
- package/dist/infra/lib/evolution/HookTraceReader.js +108 -0
- package/dist/infra/lib/evolution/HookTraceReader.js.map +1 -0
- package/dist/infra/lib/evolution/index.d.ts +4 -0
- package/dist/infra/lib/evolution/index.d.ts.map +1 -1
- package/dist/infra/lib/evolution/index.js +3 -0
- package/dist/infra/lib/evolution/index.js.map +1 -1
- package/hooks/scripts/evolution-engine.js +23 -1
- package/hooks/scripts/pre-tool-guard.js +9 -0
- package/hooks/scripts/sentinel-guard.js +3 -0
- package/hooks/scripts/utils.js +38 -0
- package/package.json +1 -1
- package/skills/chub-usage/SKILL.md +115 -0
- package/skills/vibe.figma/SKILL.md +42 -42
- package/skills/vibe.figma/templates/component-index.md +126 -0
- package/skills/vibe.figma/templates/remapped-tree.md +277 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// HookTraceReader — JSONL hook trace 파일 읽기 및 집계
|
|
2
|
+
// Guard hooks가 ~/.vibe/hook-traces.jsonl에 기록한 로그를 읽고 분석
|
|
3
|
+
import { readFileSync, existsSync } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
const TRACE_FILENAME = 'hook-traces.jsonl';
|
|
7
|
+
const MIN_CLUSTER_SIZE = 3;
|
|
8
|
+
/**
|
|
9
|
+
* hook-traces.jsonl 파일 경로 반환
|
|
10
|
+
*/
|
|
11
|
+
function getTracePath() {
|
|
12
|
+
const home = os.homedir();
|
|
13
|
+
return path.join(home, '.vibe', TRACE_FILENAME);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* JSONL 파일에서 최근 N일간 trace 항목 읽기
|
|
17
|
+
*/
|
|
18
|
+
export function readTraces(daysBack = 7) {
|
|
19
|
+
const tracePath = getTracePath();
|
|
20
|
+
if (!existsSync(tracePath))
|
|
21
|
+
return [];
|
|
22
|
+
const cutoff = new Date();
|
|
23
|
+
cutoff.setDate(cutoff.getDate() - daysBack);
|
|
24
|
+
const cutoffIso = cutoff.toISOString();
|
|
25
|
+
const raw = readFileSync(tracePath, 'utf-8');
|
|
26
|
+
const traces = [];
|
|
27
|
+
for (const line of raw.split('\n')) {
|
|
28
|
+
if (!line.trim())
|
|
29
|
+
continue;
|
|
30
|
+
try {
|
|
31
|
+
const entry = JSON.parse(line);
|
|
32
|
+
if (entry.ts >= cutoffIso) {
|
|
33
|
+
traces.push(entry);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// 깨진 줄 무시
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return traces;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 사유 문자열을 정규화 (파일 경로, 명령어 세부 사항 제거)
|
|
44
|
+
*/
|
|
45
|
+
function normalizeReason(reason) {
|
|
46
|
+
return reason
|
|
47
|
+
.replace(/\/[\w/._-]+/g, '<path>')
|
|
48
|
+
.replace(/`[^`]+`/g, '<cmd>')
|
|
49
|
+
.replace(/:\s+.*$/, '')
|
|
50
|
+
.trim();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Trace 목록을 패턴별로 클러스터링
|
|
54
|
+
*/
|
|
55
|
+
export function clusterTraces(traces) {
|
|
56
|
+
const actionable = traces.filter(t => t.decision !== 'allow');
|
|
57
|
+
const groups = new Map();
|
|
58
|
+
for (const trace of actionable) {
|
|
59
|
+
const key = `${trace.hook}:${normalizeReason(trace.reason)}`;
|
|
60
|
+
const group = groups.get(key) ?? [];
|
|
61
|
+
group.push(trace);
|
|
62
|
+
groups.set(key, group);
|
|
63
|
+
}
|
|
64
|
+
const clusters = [];
|
|
65
|
+
for (const [, group] of groups) {
|
|
66
|
+
if (group.length < MIN_CLUSTER_SIZE)
|
|
67
|
+
continue;
|
|
68
|
+
const sorted = group.sort((a, b) => a.ts.localeCompare(b.ts));
|
|
69
|
+
const tools = [...new Set(group.map(t => t.tool))];
|
|
70
|
+
clusters.push({
|
|
71
|
+
pattern: normalizeReason(group[0].reason),
|
|
72
|
+
hook: group[0].hook,
|
|
73
|
+
decision: group[0].decision,
|
|
74
|
+
count: group.length,
|
|
75
|
+
tools,
|
|
76
|
+
firstSeen: sorted[0].ts,
|
|
77
|
+
lastSeen: sorted[sorted.length - 1].ts,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return clusters.sort((a, b) => b.count - a.count);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 전체 통계 + 클러스터 분석 수행
|
|
84
|
+
*/
|
|
85
|
+
export function analyzeTraces(daysBack = 7) {
|
|
86
|
+
const traces = readTraces(daysBack);
|
|
87
|
+
const byHook = {};
|
|
88
|
+
const byTool = {};
|
|
89
|
+
let blockCount = 0;
|
|
90
|
+
let warnCount = 0;
|
|
91
|
+
for (const t of traces) {
|
|
92
|
+
byHook[t.hook] = (byHook[t.hook] ?? 0) + 1;
|
|
93
|
+
byTool[t.tool] = (byTool[t.tool] ?? 0) + 1;
|
|
94
|
+
if (t.decision === 'block')
|
|
95
|
+
blockCount++;
|
|
96
|
+
if (t.decision === 'warn')
|
|
97
|
+
warnCount++;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
totalTraces: traces.length,
|
|
101
|
+
blockCount,
|
|
102
|
+
warnCount,
|
|
103
|
+
byHook,
|
|
104
|
+
byTool,
|
|
105
|
+
clusters: clusterTraces(traces),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=HookTraceReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HookTraceReader.js","sourceRoot":"","sources":["../../../../src/infra/lib/evolution/HookTraceReader.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,4 +32,8 @@ export { DeprecationDetector } from './DeprecationDetector.js';
|
|
|
32
32
|
export type { DeprecationCandidate, DeprecationReport } from './DeprecationDetector.js';
|
|
33
33
|
export { ParityTester, PARITY_THRESHOLDS } from './ParityTester.js';
|
|
34
34
|
export type { ParityTestResult, ModelVersion, EvalComparison } from './ParityTester.js';
|
|
35
|
+
export { readTraces, clusterTraces, analyzeTraces } from './HookTraceReader.js';
|
|
36
|
+
export type { HookTrace, TraceCluster, TraceStats } from './HookTraceReader.js';
|
|
37
|
+
export { GuardAnalyzer } from './GuardAnalyzer.js';
|
|
38
|
+
export type { GuardAnalysisResult } from './GuardAnalyzer.js';
|
|
35
39
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/evolution/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGnH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC7G,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,YAAY,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EACV,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAC3D,UAAU,EAAE,YAAY,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EACV,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,GAC3E,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,YAAY,EACV,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,eAAe,GAC3E,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGxF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/infra/lib/evolution/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGnH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC7G,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,YAAY,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EACV,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAC3D,UAAU,EAAE,YAAY,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EACV,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,GAC3E,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,YAAY,EACV,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,eAAe,GAC3E,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGxF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxF,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAChF,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -26,4 +26,7 @@ export { DescriptionOptimizer } from './DescriptionOptimizer.js';
|
|
|
26
26
|
export { DeprecationDetector } from './DeprecationDetector.js';
|
|
27
27
|
// Phase 5b: Model Parity Testing
|
|
28
28
|
export { ParityTester, PARITY_THRESHOLDS } from './ParityTester.js';
|
|
29
|
+
// Phase 6: Harness Self-Improvement (Hook Trace Analysis)
|
|
30
|
+
export { readTraces, clusterTraces, analyzeTraces } from './HookTraceReader.js';
|
|
31
|
+
export { GuardAnalyzer } from './GuardAnalyzer.js';
|
|
29
32
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/infra/lib/evolution/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,2BAA2B;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAG/D,8BAA8B;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,2BAA2B;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,kCAAkC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAIrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAIjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/infra/lib/evolution/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,2BAA2B;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAG/D,8BAA8B;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,2BAA2B;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,kCAAkC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAIrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAIjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGpE,0DAA0D;AAC1D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -39,7 +39,29 @@ async function main() {
|
|
|
39
39
|
const extractor = new extractorMod.InsightExtractor(storage);
|
|
40
40
|
const extractResult = extractor.extractFromRecent(20);
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
// Phase 2b: Guard trace 분석 (하네스 자기 개선)
|
|
43
|
+
let guardInsightCount = 0;
|
|
44
|
+
try {
|
|
45
|
+
const guardMod = await import(`${LIB_BASE}evolution/GuardAnalyzer.js`);
|
|
46
|
+
const insightMod = await import(`${LIB_BASE}evolution/InsightStore.js`);
|
|
47
|
+
const insightStore = new insightMod.InsightStore(storage);
|
|
48
|
+
const guardAnalyzer = new guardMod.GuardAnalyzer(insightStore);
|
|
49
|
+
const guardResult = guardAnalyzer.analyze(7);
|
|
50
|
+
guardInsightCount = guardResult.newInsights.length;
|
|
51
|
+
if (guardInsightCount > 0) {
|
|
52
|
+
process.stderr.write(
|
|
53
|
+
`[Evolution] Guard analysis: ${guardInsightCount} new insights from hook traces\n`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
process.stderr.write(`[Evolution] Guard analysis skipped: ${e.message}\n`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
extractResult.newInsights.length === 0 &&
|
|
62
|
+
extractResult.mergedInsights.length === 0 &&
|
|
63
|
+
guardInsightCount === 0
|
|
64
|
+
) {
|
|
43
65
|
storage.close();
|
|
44
66
|
return;
|
|
45
67
|
}
|
|
@@ -139,6 +139,8 @@ const toolInput = stdinPayload?.tool_input
|
|
|
139
139
|
: JSON.stringify(stdinPayload.tool_input))
|
|
140
140
|
: (process.argv[3] || process.env.TOOL_INPUT || '');
|
|
141
141
|
|
|
142
|
+
import { logHookDecision } from './utils.js';
|
|
143
|
+
|
|
142
144
|
const validation = validateCommand(toolName, toolInput);
|
|
143
145
|
const output = formatOutput(toolName, validation);
|
|
144
146
|
|
|
@@ -146,5 +148,12 @@ if (output) {
|
|
|
146
148
|
console.log(output);
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
// Hook trace logging
|
|
152
|
+
if (!validation.allowed) {
|
|
153
|
+
logHookDecision('pre-tool-guard', toolName, 'block', validation.warnings.join('; '));
|
|
154
|
+
} else if (validation.warnings.length > 0) {
|
|
155
|
+
logHookDecision('pre-tool-guard', toolName, 'warn', validation.warnings.join('; '));
|
|
156
|
+
}
|
|
157
|
+
|
|
149
158
|
// Exit code: 0 = allowed, 2 = denied (claw-code 규약), 1 = 레거시 호환
|
|
150
159
|
process.exit(validation.allowed ? 0 : 2);
|
|
@@ -118,9 +118,12 @@ const toolInput = stdinPayload?.tool_input
|
|
|
118
118
|
: JSON.stringify(stdinPayload.tool_input))
|
|
119
119
|
: (process.argv[3] || process.env.TOOL_INPUT || '');
|
|
120
120
|
|
|
121
|
+
import { logHookDecision } from './utils.js';
|
|
122
|
+
|
|
121
123
|
const result = guard(toolName, toolInput);
|
|
122
124
|
|
|
123
125
|
if (result) {
|
|
126
|
+
logHookDecision('sentinel-guard', toolName, 'block', result.reason);
|
|
124
127
|
console.log(JSON.stringify(result));
|
|
125
128
|
process.exit(2); // deny 규약
|
|
126
129
|
}
|
package/hooks/scripts/utils.js
CHANGED
|
@@ -146,3 +146,41 @@ export function getToolsBaseUrl() {
|
|
|
146
146
|
export function getLibBaseUrl() {
|
|
147
147
|
return getPackageUrl(path.join('dist', 'infra', 'lib'), 'gpt-api.js');
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
// ─── Hook Trace Logging ───
|
|
151
|
+
|
|
152
|
+
const HOOK_TRACE_PATH = path.join(VIBE_HOME_DIR, 'hook-traces.jsonl');
|
|
153
|
+
const MAX_TRACE_SIZE_BYTES = 5 * 1024 * 1024; // 5MB rotation
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Guard/Hook 결정 사항을 JSONL로 로깅
|
|
157
|
+
* evolution GuardAnalyzer가 이 로그를 분석해 하네스 자기 개선에 활용
|
|
158
|
+
*
|
|
159
|
+
* @param {string} hookName - 훅 이름 (e.g., 'sentinel-guard', 'pre-tool-guard')
|
|
160
|
+
* @param {string} toolName - 대상 도구 (e.g., 'Bash', 'Write')
|
|
161
|
+
* @param {'allow'|'block'|'warn'} decision - 판정 결과
|
|
162
|
+
* @param {string} reason - 판정 사유
|
|
163
|
+
*/
|
|
164
|
+
export function logHookDecision(hookName, toolName, decision, reason) {
|
|
165
|
+
try {
|
|
166
|
+
// 로그 로테이션: 5MB 초과 시 이전 파일 교체
|
|
167
|
+
if (fs.existsSync(HOOK_TRACE_PATH)) {
|
|
168
|
+
const stat = fs.statSync(HOOK_TRACE_PATH);
|
|
169
|
+
if (stat.size > MAX_TRACE_SIZE_BYTES) {
|
|
170
|
+
const rotated = HOOK_TRACE_PATH + '.prev';
|
|
171
|
+
try { fs.unlinkSync(rotated); } catch { /* ignore */ }
|
|
172
|
+
fs.renameSync(HOOK_TRACE_PATH, rotated);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const entry = JSON.stringify({
|
|
177
|
+
ts: new Date().toISOString(),
|
|
178
|
+
hook: hookName,
|
|
179
|
+
tool: toolName,
|
|
180
|
+
decision,
|
|
181
|
+
reason,
|
|
182
|
+
project: PROJECT_DIR,
|
|
183
|
+
});
|
|
184
|
+
fs.appendFileSync(HOOK_TRACE_PATH, entry + '\n');
|
|
185
|
+
} catch { /* 트레이스 실패가 훅 실행을 방해해선 안 됨 */ }
|
|
186
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: chub-usage
|
|
3
|
+
tier: optional
|
|
4
|
+
description: "Context Hub (chub) — 검수된 최신 API 문서 조회. 외부 API/SDK 코드 작성 시 training data 대신 최신 문서를 기반으로 정확한 코드 작성."
|
|
5
|
+
triggers: [chub, context hub, API docs, latest API, deprecated API, SDK documentation, api reference, 최신 문서]
|
|
6
|
+
priority: 65
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Context Hub (chub) Usage
|
|
10
|
+
|
|
11
|
+
외부 API/SDK 코드 작성 전 검수된 최신 문서를 가져오는 스킬.
|
|
12
|
+
Training data의 지식 컷오프 문제를 해결합니다.
|
|
13
|
+
|
|
14
|
+
## Why?
|
|
15
|
+
|
|
16
|
+
| Problem | Solution |
|
|
17
|
+
|---------|----------|
|
|
18
|
+
| Training data에 의존 → deprecated API 사용 | chub get → 검수된 최신 문서 기반 코드 |
|
|
19
|
+
| 웹 검색 → 노이즈 섞인 결과 | chub search → 큐레이션된 문서만 |
|
|
20
|
+
| 세션마다 같은 실수 반복 | chub annotate → 학습 누적 |
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g @aisuite/chub
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## When to Use
|
|
29
|
+
|
|
30
|
+
| Situation | Example |
|
|
31
|
+
|-----------|---------|
|
|
32
|
+
| 외부 API 코드 작성 | "Stripe 결제 연동해줘" |
|
|
33
|
+
| SDK 최신 버전 확인 | "OpenAI 최신 모델 호출" |
|
|
34
|
+
| 공식 문서 필요 | "Supabase auth 설정" |
|
|
35
|
+
| Deprecated 패턴 방지 | "Firebase v10 마이그레이션" |
|
|
36
|
+
|
|
37
|
+
## Workflow
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
외부 API/SDK 코드 작성 요청
|
|
41
|
+
↓
|
|
42
|
+
Step 1: chub search "<라이브러리명>"
|
|
43
|
+
↓
|
|
44
|
+
Step 2: chub get <id> --lang ts
|
|
45
|
+
↓
|
|
46
|
+
Step 3: 문서 기반 코드 작성
|
|
47
|
+
↓
|
|
48
|
+
Step 4: gotcha 발견 시 chub annotate
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### Step 1 — 문서 검색
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
chub search "stripe"
|
|
57
|
+
chub search "openai"
|
|
58
|
+
chub search "" # 전체 목록 확인
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Step 2 — 최신 문서 fetch
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
chub get stripe/api --lang ts
|
|
65
|
+
chub get openai/chat --lang py
|
|
66
|
+
chub get supabase/auth --lang js
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Step 3 — 문서 기반 코드 작성
|
|
70
|
+
|
|
71
|
+
fetch한 문서 내용을 기반으로 정확한 코드 작성.
|
|
72
|
+
**절대 training data에 의존하지 않는다. 문서 먼저, 코드 나중.**
|
|
73
|
+
|
|
74
|
+
### Step 4 — 학습 내용 기록
|
|
75
|
+
|
|
76
|
+
작업 중 발견한 gotcha, workaround, 버전 이슈:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
chub annotate stripe/api "한국 결제는 pg 파라미터 필수"
|
|
80
|
+
chub annotate openai/chat "streaming에서 tool_calls는 delta로 옴"
|
|
81
|
+
chub annotate firebase/auth "v10에서 getAuth() import 경로 변경"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Annotation은 로컬 저장, 다음 세션에서 `chub get` 시 자동으로 같이 나옴.
|
|
85
|
+
|
|
86
|
+
## Implementation Pattern (Subagent)
|
|
87
|
+
|
|
88
|
+
컨텍스트 블로트 방지를 위해 서브에이전트에서 실행:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Task tool call:
|
|
92
|
+
- subagent_type: Explore
|
|
93
|
+
- model: haiku
|
|
94
|
+
- prompt: "Run `chub search <library>` then `chub get <id> --lang <lang>` to fetch latest API documentation for [topic]. Return only the relevant API usage examples, key changes from previous versions, and any annotations."
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
서브에이전트가 chub 호출을 처리하고 요약만 반환 → 메인 컨텍스트 깨끗하게 유지.
|
|
98
|
+
|
|
99
|
+
## Supported APIs (1,000+)
|
|
100
|
+
|
|
101
|
+
OpenAI, Anthropic, Stripe, Firebase, Supabase, Vercel, AWS S3, Cloudflare Workers, Auth0, Clerk 등.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
chub search # 인자 없이 실행하면 전체 목록 확인 가능
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Fallback Chain
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
chub 설치 안 됨
|
|
111
|
+
↓
|
|
112
|
+
Prompt: npm install -g @aisuite/chub
|
|
113
|
+
↓
|
|
114
|
+
If still unavailable: context7 또는 Web Search fallback
|
|
115
|
+
```
|
|
@@ -36,44 +36,44 @@ Figma 트리가 코드의 원천이다. 스크린샷은 검증용이다.
|
|
|
36
36
|
|
|
37
37
|
```
|
|
38
38
|
/vibe.figma
|
|
39
|
+
입력: 모든 URL을 한번에 받는다
|
|
40
|
+
Storyboard: https://figma.com/...?node-id=aaa (있으면)
|
|
41
|
+
MO Design: https://figma.com/...?node-id=xxx
|
|
42
|
+
PC Design: https://figma.com/...?node-id=yyy (있으면)
|
|
43
|
+
|
|
39
44
|
→ Phase 0: Setup (스택 감지, 디렉토리 생성, 기존 자산 인덱싱)
|
|
40
45
|
→ Phase 1: Storyboard (스토리보드 → 기능 스펙 문서 작성, 파일 생성 없음)
|
|
41
|
-
→ Phase 2: 재료 확보 (
|
|
42
|
-
→ Phase 3:
|
|
43
|
-
→ Phase
|
|
44
|
-
→ Phase
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
브레이크포인트별 작업 구조:
|
|
46
|
+
→ Phase 2: 재료 확보 (모든 BP의 트리 + 노드 렌더링 이미지 + 스크린샷)
|
|
47
|
+
→ Phase 3: 리매핑 (tree.json → remapped.json, BP 간 노드 매칭 + CSS diff)
|
|
48
|
+
→ Phase 4: 순차 코드 생성 (remapped.json → 섹션별 HTML+SCSS)
|
|
49
|
+
→ Phase 5: 컴파일 게이트 (tsc → build → dev 확인)
|
|
50
|
+
→ Phase 6: 시각 검증 루프 (렌더링 vs 스크린샷 비교 → 수정)
|
|
51
|
+
|
|
52
|
+
작업 디렉토리 구조:
|
|
49
53
|
각 Figma URL의 ROOT name에서 폴더명 추출 (kebab-case):
|
|
50
54
|
"MO_Main ..." → /tmp/{feature}/mo-main/
|
|
51
55
|
"PC_Main ..." → /tmp/{feature}/pc-main/
|
|
52
56
|
|
|
53
57
|
/tmp/{feature}/
|
|
54
|
-
├── mo-main/ ←
|
|
55
|
-
│ ├── tree.json
|
|
56
|
-
│ ├── bg/
|
|
57
|
-
│ ├── content/
|
|
58
|
-
│ └── sections/
|
|
59
|
-
├── pc-main/ ← 두 번째 URL (데스크탑)
|
|
58
|
+
├── mo-main/ ← 모바일 Phase 2 추출 결과
|
|
60
59
|
│ ├── tree.json
|
|
61
|
-
│ ├── bg/
|
|
62
|
-
│ ├── content/
|
|
63
|
-
│ └── sections/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
│ ├── bg/ ← BG 프레임 렌더링
|
|
61
|
+
│ ├── content/ ← 콘텐츠 노드 렌더링
|
|
62
|
+
│ └── sections/ ← Phase 4 검증용 스크린샷
|
|
63
|
+
├── pc-main/ ← 데스크탑 Phase 2 추출 결과
|
|
64
|
+
│ └── (동일 구조)
|
|
65
|
+
└── remapped.json ← Phase 3 리매핑 결과 (모든 BP 통합)
|
|
66
|
+
|
|
67
|
+
remapped.json이 Phase 4의 유일한 입력.
|
|
68
|
+
→ BP 간 노드 매칭 완료
|
|
69
|
+
→ CSS diff (mo/pc) 포함
|
|
70
|
+
→ 이미지 렌더링 파일 경로 포함
|
|
71
|
+
→ Phase 4에서 바로 코드 생성 가능
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
2. SCSS diff
|
|
73
|
-
→ 같은 값: 기본 스타일
|
|
74
|
-
→ 다른 값: @media 오버라이드
|
|
75
|
-
3. 토큰 diff → 합집합 정리
|
|
76
|
-
4. /tmp/ 임시 폴더 → 프로젝트 디렉토리에 최종 배치
|
|
73
|
+
코드 출력: 프로젝트 디렉토리에 직접 배치
|
|
74
|
+
components/{feature}/HeroSection.vue
|
|
75
|
+
styles/{feature}/layout/_hero.scss (모바일 기본 + @media PC)
|
|
76
|
+
styles/{feature}/components/_hero.scss
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
---
|
|
@@ -202,7 +202,7 @@ Phase 5 공통화:
|
|
|
202
202
|
- question: "스토리보드 Figma URL을 입력해주세요. (없으면 '없음')"
|
|
203
203
|
- options 제공 금지 — 자유 텍스트 입력만 허용
|
|
204
204
|
|
|
205
|
-
"없음" 응답 시 →
|
|
205
|
+
"없음" 응답 시 → 스토리보드 분석 스킵
|
|
206
206
|
|
|
207
207
|
### 1-1. 스토리보드 분석
|
|
208
208
|
|
|
@@ -238,8 +238,8 @@ URL에서 fileKey, nodeId 추출
|
|
|
238
238
|
|
|
239
239
|
```
|
|
240
240
|
❌ Phase 1에서 코드 파일을 생성하지 않는다.
|
|
241
|
-
→ Phase 1 HTML 구조와 Phase
|
|
242
|
-
→ Phase
|
|
241
|
+
→ Phase 1 HTML 구조와 Phase 4 트리 매핑이 충돌하면 이중 작업
|
|
242
|
+
→ Phase 4에서 remapped.json 기반으로 코드를 생성
|
|
243
243
|
|
|
244
244
|
✅ Phase 1의 출력물은 기능 스펙 문서 (텍스트):
|
|
245
245
|
|
|
@@ -283,7 +283,7 @@ Phase 1 완료 조건:
|
|
|
283
283
|
□ 공통 컴포넌트가 식별되어 있다
|
|
284
284
|
□ 파일을 하나도 생성하지 않았다
|
|
285
285
|
|
|
286
|
-
Phase
|
|
286
|
+
Phase 4에서 이 스펙 + remapped.json을 합쳐서 코드를 생성한다.
|
|
287
287
|
```
|
|
288
288
|
|
|
289
289
|
---
|
|
@@ -425,7 +425,7 @@ UI 요소 → vw 비례:
|
|
|
425
425
|
|
|
426
426
|
---
|
|
427
427
|
|
|
428
|
-
## Phase
|
|
428
|
+
## Phase 3: 리매핑 (tree.json → remapped.json)
|
|
429
429
|
|
|
430
430
|
**URL 2개 이상일 때만 실행. 단일 URL이면 Phase 3으로 건너뜀.**
|
|
431
431
|
**프레임 간 공통 요소를 식별하여 공유 컴포넌트로 추출한다.**
|
|
@@ -466,7 +466,7 @@ UI 요소 → vw 비례:
|
|
|
466
466
|
|
|
467
467
|
---
|
|
468
468
|
|
|
469
|
-
## Phase
|
|
469
|
+
## Phase 4: 순차 코드 생성
|
|
470
470
|
|
|
471
471
|
**Phase 1에서 만든 컴포넌트에 Phase 2의 재료로 디자인을 입힌다.**
|
|
472
472
|
**스크린샷을 보면서 퍼즐을 맞추듯 조립한다.**
|
|
@@ -688,11 +688,11 @@ URL 있으면:
|
|
|
688
688
|
|
|
689
689
|
---
|
|
690
690
|
|
|
691
|
-
## Phase
|
|
691
|
+
## Phase 5: 컴파일 게이트
|
|
692
692
|
|
|
693
693
|
**Phase 3 퍼즐 조립 완료 후, 브라우저 검증 전에 컴파일 성공을 보장한다.**
|
|
694
694
|
**컴파일 에러는 스킵 불가 — 반드시 수정 또는 사용자 보고.**
|
|
695
|
-
**Phase
|
|
695
|
+
**Phase 5 실패 시 Phase 4 진행 불가 (hard gate).**
|
|
696
696
|
|
|
697
697
|
```
|
|
698
698
|
자동 반복: 컴파일 성공까지. 최대 3라운드.
|
|
@@ -705,7 +705,7 @@ Phase 3 시작 전에 기존 프로젝트의 에러를 캡처:
|
|
|
705
705
|
1. 타입 체크 베이스라인: (3.5-1에서 선택한 동일 명령 사용) > /tmp/{feature}/baseline-typecheck.txt 2>&1
|
|
706
706
|
2. 빌드 베이스라인: npm run build > /tmp/{feature}/baseline-build.txt 2>&1
|
|
707
707
|
|
|
708
|
-
Phase
|
|
708
|
+
Phase 5에서는 baseline에 없는 **새로 발생한 에러만** 수정 대상.
|
|
709
709
|
baseline에 존재하던 에러는 무시하고 별도 보고 ("기존 에러 {N}개 유지").
|
|
710
710
|
vibe.figma가 생성/수정한 파일 외의 에러는 자동 수정 금지.
|
|
711
711
|
```
|
|
@@ -783,13 +783,13 @@ vibe.figma가 생성/수정한 파일 외의 에러는 자동 수정 금지.
|
|
|
783
783
|
컴파일 게이트 결과 보고:
|
|
784
784
|
|
|
785
785
|
✅ 통과:
|
|
786
|
-
"Phase
|
|
786
|
+
"Phase 5: 컴파일 게이트 PASS (라운드 {N})"
|
|
787
787
|
- tsc: 0 errors
|
|
788
788
|
- build: success
|
|
789
789
|
- dev server: running on localhost:{port}
|
|
790
790
|
|
|
791
791
|
❌ 실패 (3라운드 후):
|
|
792
|
-
"Phase
|
|
792
|
+
"Phase 5: 컴파일 게이트 FAIL"
|
|
793
793
|
- 남은 에러 목록 (파일, 줄, 메시지)
|
|
794
794
|
- 시도한 수정 내역
|
|
795
795
|
- 사용자 수동 수정 필요
|
|
@@ -798,7 +798,7 @@ vibe.figma가 생성/수정한 파일 외의 에러는 자동 수정 금지.
|
|
|
798
798
|
|
|
799
799
|
---
|
|
800
800
|
|
|
801
|
-
## Phase
|
|
801
|
+
## Phase 6: 시각 검증 루프
|
|
802
802
|
|
|
803
803
|
**Puppeteer + CDP로 실제 렌더링 결과를 확인하며 자동 수정한다.**
|
|
804
804
|
**사람이 브라우저 보면서 고치는 것과 동일한 루프.**
|
|
@@ -812,7 +812,7 @@ vibe.figma가 생성/수정한 파일 외의 에러는 자동 수정 금지.
|
|
|
812
812
|
|
|
813
813
|
```
|
|
814
814
|
1. dev 서버 시작:
|
|
815
|
-
Phase
|
|
815
|
+
Phase 5에서 이미 시작된 dev 서버 사용 (재시작 불필요)
|
|
816
816
|
→ localhost:{port} 확인
|
|
817
817
|
|
|
818
818
|
2. Puppeteer 브라우저 시작:
|