triflux 0.0.1 → 2.0.1
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-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +23 -0
- package/.mcp.json +3 -0
- package/LICENSE +21 -0
- package/README.ko.md +276 -0
- package/README.md +276 -1
- package/bin/tfx-doctor.mjs +8 -0
- package/bin/tfx-setup.mjs +8 -0
- package/bin/triflux.mjs +707 -0
- package/hooks/hooks.json +17 -0
- package/hud/hud-qos-status.mjs +1380 -0
- package/package.json +46 -7
- package/scripts/cli-route.sh +937 -0
- package/scripts/mcp-check.mjs +88 -0
- package/scripts/setup.mjs +215 -0
- package/skills/auto-verify/SKILL.md +145 -0
- package/skills/manage-skills/SKILL.md +192 -0
- package/skills/tfx-auto/SKILL.md +658 -0
- package/skills/tfx-codex/SKILL.md +61 -0
- package/skills/tfx-gemini/SKILL.md +78 -0
- package/skills/tfx-setup/SKILL.md +97 -0
- package/skills/verify-implementation/SKILL.md +138 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// MCP 인벤토리 — 백그라운드 비동기 실행
|
|
3
|
+
// Codex/Gemini의 MCP 서버 상태를 캐싱하여 cli-route.sh가 동적 힌트 생성에 사용
|
|
4
|
+
//
|
|
5
|
+
// 출력: ~/.claude/cache/mcp-inventory.json
|
|
6
|
+
// 사용: cli-route.sh의 get_mcp_hint()에서 읽음
|
|
7
|
+
|
|
8
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { execSync } from "child_process";
|
|
12
|
+
|
|
13
|
+
const CACHE_DIR = join(homedir(), ".claude", "cache");
|
|
14
|
+
const CACHE_FILE = join(CACHE_DIR, "mcp-inventory.json");
|
|
15
|
+
|
|
16
|
+
function getCodexMcp() {
|
|
17
|
+
try {
|
|
18
|
+
const output = execSync("codex mcp list", {
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
timeout: 15000,
|
|
21
|
+
stdio: ["pipe", "pipe", "ignore"], // stderr 무시 (Windows 호환)
|
|
22
|
+
});
|
|
23
|
+
// 테이블 파싱: 첫 줄 헤더, 이후 줄에서 Name과 Status 추출
|
|
24
|
+
const lines = output.trim().split(/\r?\n/).filter(l => l.trim());
|
|
25
|
+
if (lines.length < 2) return [];
|
|
26
|
+
|
|
27
|
+
const servers = [];
|
|
28
|
+
for (let i = 1; i < lines.length; i++) {
|
|
29
|
+
const cols = lines[i].split(/\s{2,}/);
|
|
30
|
+
if (cols.length >= 2) {
|
|
31
|
+
const name = cols[0].trim();
|
|
32
|
+
// Status는 마지막에서 2번째 컬럼 근처
|
|
33
|
+
const statusMatch = lines[i].match(/\b(enabled|disabled)\b/i);
|
|
34
|
+
const status = statusMatch ? statusMatch[1].toLowerCase() : "unknown";
|
|
35
|
+
if (name && !name.startsWith("-")) {
|
|
36
|
+
servers.push({ name, status });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return servers;
|
|
41
|
+
} catch {
|
|
42
|
+
return null; // codex 미설치 또는 타임아웃
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getGeminiMcp() {
|
|
47
|
+
try {
|
|
48
|
+
const settingsPath = join(homedir(), ".gemini", "settings.json");
|
|
49
|
+
if (!existsSync(settingsPath)) return null;
|
|
50
|
+
|
|
51
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
52
|
+
const mcpServers = settings.mcpServers || {};
|
|
53
|
+
return Object.keys(mcpServers).map(name => ({
|
|
54
|
+
name,
|
|
55
|
+
status: "configured",
|
|
56
|
+
}));
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function main() {
|
|
63
|
+
if (!existsSync(CACHE_DIR)) mkdirSync(CACHE_DIR, { recursive: true });
|
|
64
|
+
|
|
65
|
+
const inventory = {
|
|
66
|
+
timestamp: new Date().toISOString(),
|
|
67
|
+
codex: { available: false, servers: [] },
|
|
68
|
+
gemini: { available: false, servers: [] },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Codex MCP
|
|
72
|
+
const codexServers = getCodexMcp();
|
|
73
|
+
if (codexServers !== null) {
|
|
74
|
+
inventory.codex.available = true;
|
|
75
|
+
inventory.codex.servers = codexServers;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Gemini MCP
|
|
79
|
+
const geminiServers = getGeminiMcp();
|
|
80
|
+
if (geminiServers !== null) {
|
|
81
|
+
inventory.gemini.available = true;
|
|
82
|
+
inventory.gemini.servers = geminiServers;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
writeFileSync(CACHE_FILE, JSON.stringify(inventory, null, 2));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
main();
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// triflux 세션 시작 시 자동 설정 스크립트
|
|
3
|
+
// - cli-route.sh를 ~/.claude/scripts/에 동기화
|
|
4
|
+
// - hud-qos-status.mjs를 ~/.claude/hud/에 동기화
|
|
5
|
+
// - skills/를 ~/.claude/skills/에 동기화
|
|
6
|
+
|
|
7
|
+
import { copyFileSync, mkdirSync, readFileSync, writeFileSync, readdirSync, existsSync, chmodSync, unlinkSync } from "fs";
|
|
8
|
+
import { join, dirname } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
|
|
11
|
+
const PLUGIN_ROOT = dirname(dirname(new URL(import.meta.url).pathname)).replace(/^\/([A-Z]:)/, "$1");
|
|
12
|
+
const CLAUDE_DIR = join(homedir(), ".claude");
|
|
13
|
+
|
|
14
|
+
// ── 파일 동기화 ──
|
|
15
|
+
|
|
16
|
+
const SYNC_MAP = [
|
|
17
|
+
{
|
|
18
|
+
src: join(PLUGIN_ROOT, "scripts", "cli-route.sh"),
|
|
19
|
+
dst: join(CLAUDE_DIR, "scripts", "cli-route.sh"),
|
|
20
|
+
label: "cli-route.sh",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
src: join(PLUGIN_ROOT, "hud", "hud-qos-status.mjs"),
|
|
24
|
+
dst: join(CLAUDE_DIR, "hud", "hud-qos-status.mjs"),
|
|
25
|
+
label: "hud-qos-status.mjs",
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
function getVersion(filePath) {
|
|
30
|
+
try {
|
|
31
|
+
const content = readFileSync(filePath, "utf8");
|
|
32
|
+
const match = content.match(/VERSION\s*=\s*"([^"]+)"/);
|
|
33
|
+
return match ? match[1] : null;
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let synced = 0;
|
|
40
|
+
|
|
41
|
+
for (const { src, dst, label } of SYNC_MAP) {
|
|
42
|
+
if (!existsSync(src)) continue;
|
|
43
|
+
|
|
44
|
+
const dstDir = dirname(dst);
|
|
45
|
+
if (!existsSync(dstDir)) {
|
|
46
|
+
mkdirSync(dstDir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!existsSync(dst)) {
|
|
50
|
+
copyFileSync(src, dst);
|
|
51
|
+
try { chmodSync(dst, 0o755); } catch {}
|
|
52
|
+
synced++;
|
|
53
|
+
} else {
|
|
54
|
+
const srcVersion = getVersion(src);
|
|
55
|
+
const dstVersion = getVersion(dst);
|
|
56
|
+
if (srcVersion && dstVersion && srcVersion !== dstVersion) {
|
|
57
|
+
copyFileSync(src, dst);
|
|
58
|
+
try { chmodSync(dst, 0o755); } catch {}
|
|
59
|
+
synced++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── 스킬 동기화 ──
|
|
65
|
+
|
|
66
|
+
const skillsSrc = join(PLUGIN_ROOT, "skills");
|
|
67
|
+
const skillsDst = join(CLAUDE_DIR, "skills");
|
|
68
|
+
|
|
69
|
+
if (existsSync(skillsSrc)) {
|
|
70
|
+
for (const name of readdirSync(skillsSrc)) {
|
|
71
|
+
const src = join(skillsSrc, name, "SKILL.md");
|
|
72
|
+
if (!existsSync(src)) continue;
|
|
73
|
+
|
|
74
|
+
const dstDir = join(skillsDst, name);
|
|
75
|
+
const dst = join(dstDir, "SKILL.md");
|
|
76
|
+
|
|
77
|
+
if (!existsSync(dstDir)) mkdirSync(dstDir, { recursive: true });
|
|
78
|
+
|
|
79
|
+
if (!existsSync(dst)) {
|
|
80
|
+
copyFileSync(src, dst);
|
|
81
|
+
synced++;
|
|
82
|
+
} else {
|
|
83
|
+
const srcContent = readFileSync(src, "utf8");
|
|
84
|
+
const dstContent = readFileSync(dst, "utf8");
|
|
85
|
+
if (srcContent !== dstContent) {
|
|
86
|
+
copyFileSync(src, dst);
|
|
87
|
+
synced++;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── settings.json statusLine 자동 설정 ──
|
|
94
|
+
|
|
95
|
+
const settingsPath = join(CLAUDE_DIR, "settings.json");
|
|
96
|
+
const hudPath = join(CLAUDE_DIR, "hud", "hud-qos-status.mjs");
|
|
97
|
+
|
|
98
|
+
if (existsSync(hudPath)) {
|
|
99
|
+
try {
|
|
100
|
+
let settings = {};
|
|
101
|
+
if (existsSync(settingsPath)) {
|
|
102
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// statusLine이 없거나 hud-qos-status.mjs를 가리키지 않는 경우에만 설정
|
|
106
|
+
const currentCmd = settings.statusLine?.command || "";
|
|
107
|
+
if (!currentCmd.includes("hud-qos-status.mjs")) {
|
|
108
|
+
const nodePath = process.execPath.replace(/\\/g, "/");
|
|
109
|
+
const hudForward = hudPath.replace(/\\/g, "/");
|
|
110
|
+
|
|
111
|
+
// Windows: 경로에 공백이 있으면 큰따옴표 감싸기
|
|
112
|
+
const nodeRef = nodePath.includes(" ") ? `"${nodePath}"` : nodePath;
|
|
113
|
+
const hudRef = hudForward.includes(" ") ? `"${hudForward}"` : hudForward;
|
|
114
|
+
|
|
115
|
+
settings.statusLine = {
|
|
116
|
+
type: "command",
|
|
117
|
+
command: `${nodeRef} ${hudRef}`,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
121
|
+
synced++;
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
// settings.json 파싱 실패 시 무시 — 기존 설정 보존
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── HUD 에러 캐시 자동 클리어 (업데이트/재설치 시) ──
|
|
129
|
+
|
|
130
|
+
const cacheDir = join(CLAUDE_DIR, "cache");
|
|
131
|
+
const staleFiles = [
|
|
132
|
+
"claude-usage-cache.json",
|
|
133
|
+
".claude-refresh-lock",
|
|
134
|
+
"codex-rate-limits-cache.json",
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
for (const name of staleFiles) {
|
|
138
|
+
const fp = join(cacheDir, name);
|
|
139
|
+
if (!existsSync(fp)) continue;
|
|
140
|
+
try {
|
|
141
|
+
const content = readFileSync(fp, "utf8");
|
|
142
|
+
const parsed = JSON.parse(content);
|
|
143
|
+
// 에러 상태이거나 락 파일이면 삭제 → 새 세션에서 fresh start
|
|
144
|
+
if (parsed.error || name.startsWith(".")) {
|
|
145
|
+
unlinkSync(fp);
|
|
146
|
+
synced++;
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
// 파싱 실패 파일도 삭제
|
|
150
|
+
try { unlinkSync(fp); } catch {}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── MCP 인벤토리 백그라운드 갱신 ──
|
|
155
|
+
|
|
156
|
+
import { spawn } from "child_process";
|
|
157
|
+
|
|
158
|
+
const mcpCheck = join(PLUGIN_ROOT, "scripts", "mcp-check.mjs");
|
|
159
|
+
if (existsSync(mcpCheck)) {
|
|
160
|
+
const child = spawn(process.execPath, [mcpCheck], {
|
|
161
|
+
detached: true,
|
|
162
|
+
stdio: "ignore",
|
|
163
|
+
});
|
|
164
|
+
child.unref(); // 부모 프로세스와 분리 — 비동기 실행
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ── postinstall 배너 (npm install 시에만 출력) ──
|
|
168
|
+
|
|
169
|
+
if (process.env.npm_lifecycle_event === "postinstall") {
|
|
170
|
+
const G = "\x1b[32m";
|
|
171
|
+
const C = "\x1b[36m";
|
|
172
|
+
const Y = "\x1b[33m";
|
|
173
|
+
const D = "\x1b[2m";
|
|
174
|
+
const B = "\x1b[1m";
|
|
175
|
+
const R = "\x1b[0m";
|
|
176
|
+
|
|
177
|
+
const ver = (() => {
|
|
178
|
+
try {
|
|
179
|
+
return JSON.parse(readFileSync(join(PLUGIN_ROOT, "package.json"), "utf8")).version;
|
|
180
|
+
} catch { return "?"; }
|
|
181
|
+
})();
|
|
182
|
+
|
|
183
|
+
console.log(`
|
|
184
|
+
${B}╔═══════════════════════════════════════════════╗${R}
|
|
185
|
+
${B}║${R} ${C}triflux${R} ${D}v${ver}${R} ${B}— Setup Complete${R} ${B}║${R}
|
|
186
|
+
${B}╚═══════════════════════════════════════════════╝${R}
|
|
187
|
+
|
|
188
|
+
${G}✓${R} cli-route.sh → ~/.claude/scripts/
|
|
189
|
+
${G}✓${R} hud-qos-status → ~/.claude/hud/
|
|
190
|
+
${G}✓${R} ${synced > 0 ? synced + " files synced" : "all files up to date"}
|
|
191
|
+
${G}✓${R} HUD statusLine → settings.json
|
|
192
|
+
|
|
193
|
+
${B}Commands:${R}
|
|
194
|
+
${C}triflux${R} setup 파일 동기화 + HUD 설정
|
|
195
|
+
${C}triflux${R} doctor CLI 진단 (Codex/Gemini 확인)
|
|
196
|
+
${C}triflux${R} list 설치된 스킬 목록
|
|
197
|
+
${C}triflux${R} update 최신 버전으로 업데이트
|
|
198
|
+
|
|
199
|
+
${B}Shortcuts:${R}
|
|
200
|
+
${C}tfx${R} triflux 축약
|
|
201
|
+
${C}tfx-setup${R} triflux setup
|
|
202
|
+
${C}tfx-doctor${R} triflux doctor
|
|
203
|
+
|
|
204
|
+
${B}Skills (Claude Code):${R}
|
|
205
|
+
${C}/tfx-auto${R} "작업" 자동 분류 + 병렬 실행
|
|
206
|
+
${C}/tfx-codex${R} "작업" Codex 전용 모드
|
|
207
|
+
${C}/tfx-gemini${R} "작업" Gemini 전용 모드
|
|
208
|
+
${C}/tfx-setup${R} HUD 설정 + 진단
|
|
209
|
+
|
|
210
|
+
${Y}!${R} 세션 재시작 후 스킬이 활성화됩니다
|
|
211
|
+
${D}https://github.com/tellang/triflux${R}
|
|
212
|
+
`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
process.exit(0);
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: auto-verify
|
|
3
|
+
description: OMC 실행 모드 완료 후 자동으로 verify 스킬을 생성/업데이트하고, 통합 검증을 실행합니다. autopilot/team/ralph 완료 시점 또는 커밋 전에 사용.
|
|
4
|
+
argument-hint: "[선택사항: skip-manage | skip-verify | full]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# auto-verify — OMC 연동 자동 검증
|
|
8
|
+
|
|
9
|
+
## 목적
|
|
10
|
+
|
|
11
|
+
OMC 워크플로우(autopilot, team, ralph, executor 등) 완료 후 **한 번의 호출로** 스킬 관리 + 검증을 자동 수행합니다:
|
|
12
|
+
|
|
13
|
+
1. `/manage-skills` 실행 → 세션 변경사항 기반 verify 스킬 자동 생성/업데이트
|
|
14
|
+
2. `/verify-implementation` 실행 → 생성된 스킬 포함 전체 검증
|
|
15
|
+
3. 이슈 발견 시 수정 제안 → 사용자 승인 → 재검증
|
|
16
|
+
|
|
17
|
+
## OMC 호환
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
[OMC 실행 모드]
|
|
21
|
+
│
|
|
22
|
+
├─ /autopilot 완료 후 → /auto-verify
|
|
23
|
+
├─ /team team-verify 단계 → /auto-verify
|
|
24
|
+
├─ /ralph 각 이터레이션 후 → /auto-verify
|
|
25
|
+
├─ executor/deep-executor 완료 후 → /auto-verify
|
|
26
|
+
└─ 커밋 전 (수동) → /auto-verify
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**OMC team-verify 단계에서의 실행 순서:**
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
team-verify:
|
|
33
|
+
1. /auto-verify ← 프로젝트 고유 규칙 검증 (이 스킬)
|
|
34
|
+
2. OMC verifier (sonnet) ← 범용 완료성 검증
|
|
35
|
+
3. OMC code-reviewer (opus) ← 심층 코드 리뷰 (20+ 파일 시)
|
|
36
|
+
4. ask_codex (security) ← 보안 분석 (MCP, 필요 시)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 워크플로우
|
|
40
|
+
|
|
41
|
+
### Step 1: 모드 감지 및 옵션 파싱
|
|
42
|
+
|
|
43
|
+
인수 확인:
|
|
44
|
+
- `skip-manage`: manage-skills 단계 건너뛰기 (이미 실행한 경우)
|
|
45
|
+
- `skip-verify`: verify-implementation 건너뛰기 (스킬 업데이트만)
|
|
46
|
+
- `full` 또는 인수 없음: 전체 실행 (기본값)
|
|
47
|
+
|
|
48
|
+
현재 OMC 상태 확인 (선택적):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# OMC 실행 모드 상태 확인 (있으면 컨텍스트로 활용)
|
|
52
|
+
cat .omc/state/team-state.json 2>/dev/null
|
|
53
|
+
cat .omc/state/autopilot-state.json 2>/dev/null
|
|
54
|
+
cat .omc/state/ralph-state.json 2>/dev/null
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Step 2: 변경사항 규모 평가
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 변경된 파일 수 확인
|
|
61
|
+
git diff HEAD --name-only | wc -l
|
|
62
|
+
git diff main...HEAD --name-only 2>/dev/null | wc -l
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
규모에 따른 동작 조정:
|
|
66
|
+
- **소규모 (1-5 파일)**: manage-skills + verify-implementation 순차 실행
|
|
67
|
+
- **중규모 (6-20 파일)**: manage-skills 실행 → verify-implementation 실행
|
|
68
|
+
- **대규모 (20+ 파일)**: manage-skills 실행 → verify-implementation 실행 후 OMC code-reviewer 권장
|
|
69
|
+
|
|
70
|
+
### Step 3: manage-skills 실행
|
|
71
|
+
|
|
72
|
+
`skip-manage`가 아닌 경우:
|
|
73
|
+
|
|
74
|
+
1. `/manage-skills` 스킬의 워크플로우를 실행
|
|
75
|
+
2. 새로 생성/업데이트된 스킬 목록 기록
|
|
76
|
+
3. CLAUDE.md Skills 테이블 동기화 확인
|
|
77
|
+
|
|
78
|
+
**표시:**
|
|
79
|
+
|
|
80
|
+
```markdown
|
|
81
|
+
## 스킬 관리 완료
|
|
82
|
+
|
|
83
|
+
- 분석된 파일: N개
|
|
84
|
+
- 새 스킬 생성: X개 (verify-<name1>, verify-<name2>)
|
|
85
|
+
- 기존 스킬 업데이트: Y개
|
|
86
|
+
- 면제: Z개
|
|
87
|
+
|
|
88
|
+
다음 단계: 통합 검증 실행...
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Step 4: verify-implementation 실행
|
|
92
|
+
|
|
93
|
+
`skip-verify`가 아닌 경우:
|
|
94
|
+
|
|
95
|
+
1. `/verify-implementation` 스킬의 워크플로우를 실행
|
|
96
|
+
2. Step 3에서 새로 생성된 스킬도 포함하여 전체 검증
|
|
97
|
+
3. 통합 리포트 생성
|
|
98
|
+
|
|
99
|
+
### Step 5: OMC 에이전트 연계 권장
|
|
100
|
+
|
|
101
|
+
검증 결과에 따라 OMC 에이전트 후속 작업을 권장:
|
|
102
|
+
|
|
103
|
+
```markdown
|
|
104
|
+
## 추가 권장 사항
|
|
105
|
+
|
|
106
|
+
| 조건 | 권장 액션 |
|
|
107
|
+
|------|----------|
|
|
108
|
+
| 보안 관련 이슈 발견 | `ask_codex`(security-reviewer, xhigh)로 심층 분석 |
|
|
109
|
+
| 아키텍처 위반 발견 | `ask_codex`(architect, high)로 구조 리뷰 |
|
|
110
|
+
| UI/프론트 이슈 발견 | `ask_gemini`(designer)로 UI 리뷰 |
|
|
111
|
+
| 20+ 파일 변경 | OMC `/code-review`로 전체 리뷰 |
|
|
112
|
+
| 이슈 없음 | 커밋 준비 완료 ✓ |
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Step 6: 최종 보고서
|
|
116
|
+
|
|
117
|
+
```markdown
|
|
118
|
+
## Auto-Verify 완료
|
|
119
|
+
|
|
120
|
+
### 스킬 관리
|
|
121
|
+
- 새 스킬: X개 | 업데이트: Y개
|
|
122
|
+
|
|
123
|
+
### 검증 결과
|
|
124
|
+
| 스킬 | 상태 | 이슈 |
|
|
125
|
+
|------|------|------|
|
|
126
|
+
| verify-<name> | PASS/FAIL | N개 |
|
|
127
|
+
|
|
128
|
+
### 전체: PASS ✓ / X개 이슈 발견
|
|
129
|
+
### 다음 단계: [커밋 준비 완료 | 이슈 수정 필요 | OMC 심층 리뷰 권장]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 예외사항
|
|
133
|
+
|
|
134
|
+
1. **OMC 실행 모드 상태 파일 없음** — 정상 (독립 실행 지원)
|
|
135
|
+
2. **verify 스킬 0개** — manage-skills만 실행하여 최초 스킬 생성
|
|
136
|
+
3. **git 이력 없음** — 현재 파일 전체 스캔으로 fallback
|
|
137
|
+
4. **MCP 미사용 환경** — OMC 에이전트 권장만 표시, MCP 권장 생략
|
|
138
|
+
|
|
139
|
+
## 관련 파일
|
|
140
|
+
|
|
141
|
+
| File | Purpose |
|
|
142
|
+
|------|---------|
|
|
143
|
+
| `.claude/skills/manage-skills/SKILL.md` | 스킬 생성/관리 |
|
|
144
|
+
| `.claude/skills/verify-implementation/SKILL.md` | 통합 검증 실행 |
|
|
145
|
+
| `CLAUDE.md` | Skills 섹션 (자동 동기화 대상) |
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: manage-skills
|
|
3
|
+
description: 세션 변경사항을 분석하여 검증 스킬 누락을 탐지합니다. 기존 스킬을 동적으로 탐색하고, 새 스킬을 생성하거나 기존 스킬을 업데이트한 뒤 CLAUDE.md를 관리합니다.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
argument-hint: "[선택사항: 특정 스킬 이름 또는 집중할 영역]"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# manage-skills — 세션 기반 스킬 유지보수
|
|
9
|
+
|
|
10
|
+
## 목적
|
|
11
|
+
|
|
12
|
+
현재 세션에서 변경된 내용을 분석하여 검증 스킬의 드리프트를 탐지하고 수정합니다:
|
|
13
|
+
|
|
14
|
+
1. **커버리지 누락** — 어떤 verify 스킬에서도 참조하지 않는 변경된 파일
|
|
15
|
+
2. **유효하지 않은 참조** — 삭제되거나 이동된 파일을 참조하는 스킬
|
|
16
|
+
3. **누락된 검사** — 기존 검사에서 다루지 않는 새로운 패턴/규칙
|
|
17
|
+
4. **오래된 값** — 더 이상 일치하지 않는 설정값 또는 탐지 명령어
|
|
18
|
+
|
|
19
|
+
## OMC 호환
|
|
20
|
+
|
|
21
|
+
이 스킬은 OMC(oh-my-claudecode) 에이전트 시스템과 **보완적**으로 작동합니다:
|
|
22
|
+
|
|
23
|
+
- **OMC verifier**: 세션 단위 일회성 검증 (매번 코드 분석)
|
|
24
|
+
- **verify 스킬**: 프로젝트별 영구 규칙 기반 검증 (누적 지식)
|
|
25
|
+
- OMC `code-reviewer`, `quality-reviewer` 등은 범용 리뷰 → verify 스킬은 **프로젝트 고유 규칙** 검증
|
|
26
|
+
- 두 시스템을 함께 사용 시: verify 스킬로 프로젝트 규칙 검증 → OMC verifier로 일반 품질 검증
|
|
27
|
+
|
|
28
|
+
**MCP-First 환경 적용**: verify 스킬의 리포트를 Codex/Gemini CLI에 전달하여 심층 분석 위임 가능.
|
|
29
|
+
|
|
30
|
+
## 실행 시점
|
|
31
|
+
|
|
32
|
+
- 새로운 패턴이나 규칙을 도입하는 기능을 구현한 후
|
|
33
|
+
- 기존 verify 스킬을 수정하고 일관성을 점검하고 싶을 때
|
|
34
|
+
- PR 전에 verify 스킬이 변경된 영역을 커버하는지 확인할 때
|
|
35
|
+
- 검증 실행 시 예상했던 이슈를 놓쳤을 때
|
|
36
|
+
- 주기적으로 스킬을 코드베이스 변화에 맞춰 정렬할 때
|
|
37
|
+
|
|
38
|
+
## 등록된 검증 스킬
|
|
39
|
+
|
|
40
|
+
현재 프로젝트에 등록된 검증 스킬 목록입니다. 새 스킬 생성/삭제 시 이 목록을 업데이트합니다.
|
|
41
|
+
|
|
42
|
+
(아직 등록된 검증 스킬이 없습니다)
|
|
43
|
+
|
|
44
|
+
<!-- 스킬이 추가되면 아래 형식으로 등록:
|
|
45
|
+
| 스킬 | 설명 | 커버 파일 패턴 |
|
|
46
|
+
|------|------|---------------|
|
|
47
|
+
| `verify-example` | 예시 검증 | `src/example/**/*.ts` |
|
|
48
|
+
-->
|
|
49
|
+
|
|
50
|
+
## 워크플로우
|
|
51
|
+
|
|
52
|
+
### Step 1: 세션 변경사항 분석
|
|
53
|
+
|
|
54
|
+
현재 세션에서 변경된 모든 파일을 수집합니다:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 커밋되지 않은 변경사항
|
|
58
|
+
git diff HEAD --name-only
|
|
59
|
+
|
|
60
|
+
# 현재 브랜치의 커밋 (main에서 분기된 경우)
|
|
61
|
+
git log --oneline main..HEAD 2>/dev/null
|
|
62
|
+
|
|
63
|
+
# main에서 분기된 이후의 모든 변경사항
|
|
64
|
+
git diff main...HEAD --name-only 2>/dev/null
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
중복을 제거한 목록으로 합칩니다. 선택적 인수로 스킬 이름이나 영역이 지정된 경우 관련 파일만 필터링합니다.
|
|
68
|
+
|
|
69
|
+
**표시:** 최상위 디렉토리(첫 1-2 경로 세그먼트) 기준으로 파일을 그룹화합니다:
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
## 세션 변경사항 감지
|
|
73
|
+
|
|
74
|
+
**이 세션에서 N개 파일 변경됨:**
|
|
75
|
+
|
|
76
|
+
| 디렉토리 | 파일 |
|
|
77
|
+
|----------|------|
|
|
78
|
+
| src/components | `Button.tsx`, `Modal.tsx` |
|
|
79
|
+
| src/server | `router.ts`, `handler.ts` |
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Step 2: 등록된 스킬과 변경 파일 매핑
|
|
83
|
+
|
|
84
|
+
**등록된 검증 스킬** 섹션에 나열된 스킬을 참조하여 파일-스킬 매핑을 구축합니다.
|
|
85
|
+
|
|
86
|
+
등록된 스킬이 0개인 경우, Step 4로 바로 이동합니다. 모든 변경 파일이 "UNCOVERED"로 처리됩니다.
|
|
87
|
+
|
|
88
|
+
등록된 스킬이 1개 이상인 경우, 각 스킬의 SKILL.md를 읽고 Related Files, Workflow 섹션에서 파일 경로 패턴을 추출합니다.
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
### 파일 → 스킬 매핑
|
|
92
|
+
|
|
93
|
+
| 스킬 | 트리거 파일 | 액션 |
|
|
94
|
+
|------|-----------|------|
|
|
95
|
+
| verify-api | `router.ts`, `handler.ts` | CHECK |
|
|
96
|
+
| (스킬 없음) | `package.json` | UNCOVERED |
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Step 3: 커버리지 갭 분석
|
|
100
|
+
|
|
101
|
+
영향받은 각 스킬에 대해 SKILL.md를 읽고 점검합니다:
|
|
102
|
+
|
|
103
|
+
1. **누락된 파일 참조** — 관련 변경 파일이 Related Files에 없는 경우
|
|
104
|
+
2. **오래된 탐지 명령어** — grep/glob 패턴이 현재 파일 구조와 일치하는지
|
|
105
|
+
3. **커버되지 않은 새 패턴** — 스킬이 검사하지 않는 새로운 규칙
|
|
106
|
+
4. **삭제된 파일의 잔여 참조** — 존재하지 않는 파일 참조
|
|
107
|
+
5. **변경된 값** — 특정 값(식별자, 설정 키)이 수정되었는지
|
|
108
|
+
|
|
109
|
+
### Step 4: CREATE vs UPDATE 결정
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
커버되지 않은 각 파일 그룹에 대해:
|
|
113
|
+
IF 기존 스킬의 도메인과 관련:
|
|
114
|
+
→ UPDATE (커버리지 확장)
|
|
115
|
+
ELIF 3개+ 관련 파일이 공통 패턴 공유:
|
|
116
|
+
→ CREATE (새 verify 스킬)
|
|
117
|
+
ELSE:
|
|
118
|
+
→ 면제 (스킬 불필요)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`AskUserQuestion`으로 사용자에게 확인합니다.
|
|
122
|
+
|
|
123
|
+
### Step 5: 기존 스킬 업데이트
|
|
124
|
+
|
|
125
|
+
**규칙:**
|
|
126
|
+
- 추가/수정만 — 작동하는 기존 검사는 절대 제거하지 않음
|
|
127
|
+
- Related Files 테이블에 새 파일 경로 추가
|
|
128
|
+
- 새 탐지 명령어 추가
|
|
129
|
+
- 삭제 확인된 파일의 참조 제거
|
|
130
|
+
- 변경된 값 업데이트
|
|
131
|
+
|
|
132
|
+
### Step 6: 새 스킬 생성
|
|
133
|
+
|
|
134
|
+
**반드시 사용자에게 스킬 이름 확인 후 생성.**
|
|
135
|
+
|
|
136
|
+
**이름 규칙:**
|
|
137
|
+
- `verify-`로 시작 (예: `verify-auth`, `verify-api`)
|
|
138
|
+
- kebab-case 사용
|
|
139
|
+
|
|
140
|
+
**필수 섹션:**
|
|
141
|
+
- Frontmatter: name, description
|
|
142
|
+
- **Purpose** — 2-5개 검증 카테고리
|
|
143
|
+
- **When to Run** — 3-5개 트리거 조건
|
|
144
|
+
- **Related Files** — 실제 파일 경로 테이블 (`ls`로 검증)
|
|
145
|
+
- **Workflow** — 검사 단계 (도구, 패턴, PASS/FAIL 기준, 수정 방법)
|
|
146
|
+
- **Output Format** — 마크다운 테이블
|
|
147
|
+
- **Exceptions** — 2-3개 면제 케이스
|
|
148
|
+
|
|
149
|
+
**연관 파일 자동 업데이트:**
|
|
150
|
+
1. `manage-skills/SKILL.md` — 등록된 검증 스킬 테이블
|
|
151
|
+
2. `verify-implementation/SKILL.md` — 실행 대상 스킬 테이블
|
|
152
|
+
3. `CLAUDE.md` — Skills 섹션 테이블
|
|
153
|
+
|
|
154
|
+
### Step 7: 검증
|
|
155
|
+
|
|
156
|
+
1. 수정된 SKILL.md 다시 읽어 마크다운 형식 확인
|
|
157
|
+
2. Related Files 경로 존재 확인: `ls <path> 2>/dev/null || echo "MISSING"`
|
|
158
|
+
3. 탐지 명령어 드라이런으로 문법 검증
|
|
159
|
+
4. 등록 테이블 동기화 확인
|
|
160
|
+
|
|
161
|
+
### Step 8: 요약 보고서
|
|
162
|
+
|
|
163
|
+
```markdown
|
|
164
|
+
## 세션 스킬 유지보수 보고서
|
|
165
|
+
|
|
166
|
+
### 분석된 변경 파일: N개
|
|
167
|
+
### 업데이트된 스킬: X개
|
|
168
|
+
### 생성된 스킬: Y개
|
|
169
|
+
### 업데이트된 연관 파일: [목록]
|
|
170
|
+
### 미커버 변경사항: [면제 사유]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 관련 파일
|
|
174
|
+
|
|
175
|
+
| File | Purpose |
|
|
176
|
+
|------|---------|
|
|
177
|
+
| `.claude/skills/verify-implementation/SKILL.md` | 통합 검증 스킬 |
|
|
178
|
+
| `.claude/skills/manage-skills/SKILL.md` | 이 파일 |
|
|
179
|
+
| `CLAUDE.md` | 프로젝트 지침 (Skills 섹션) |
|
|
180
|
+
|
|
181
|
+
## 예외사항
|
|
182
|
+
|
|
183
|
+
다음은 **문제가 아닙니다**:
|
|
184
|
+
|
|
185
|
+
1. **Lock 파일 및 생성된 파일** — `package-lock.json`, `yarn.lock`, 빌드 출력물
|
|
186
|
+
2. **일회성 설정 변경** — 버전 범프, 린터 설정 사소한 변경
|
|
187
|
+
3. **문서 파일** — `README.md`, `CHANGELOG.md`, `LICENSE`
|
|
188
|
+
4. **테스트 픽스처** — `fixtures/`, `test-data/` 디렉토리
|
|
189
|
+
5. **CLAUDE.md 자체** — 문서 업데이트이며 코드 패턴이 아님
|
|
190
|
+
6. **벤더/서드파티 코드** — `vendor/`, `node_modules/`
|
|
191
|
+
7. **CI/CD 설정** — `.github/`, `Dockerfile`
|
|
192
|
+
8. **AI 설정 파일** — `.claude/`, `.omc/`, `.codex/`, `.gemini/` (OMC 호환)
|