@su-record/vibe 3.1.0 β†’ 3.2.0

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.
Files changed (123) hide show
  1. package/CLAUDE.md +2 -2
  2. package/README.en.md +6 -4
  3. package/README.md +5 -3
  4. package/dist/__tests__/wiring-integrity.test.d.ts +2 -0
  5. package/dist/__tests__/wiring-integrity.test.d.ts.map +1 -0
  6. package/dist/__tests__/wiring-integrity.test.js +160 -0
  7. package/dist/__tests__/wiring-integrity.test.js.map +1 -0
  8. package/dist/cli/commands/info.d.ts.map +1 -1
  9. package/dist/cli/commands/info.js +2 -1
  10. package/dist/cli/commands/info.js.map +1 -1
  11. package/dist/cli/commands/init.d.ts.map +1 -1
  12. package/dist/cli/commands/init.js +4 -2
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/index.js +102 -128
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/postinstall/claude-agents.d.ts.map +1 -1
  17. package/dist/cli/postinstall/claude-agents.js +0 -5
  18. package/dist/cli/postinstall/claude-agents.js.map +1 -1
  19. package/dist/cli/postinstall/constants.d.ts +6 -0
  20. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  21. package/dist/cli/postinstall/constants.js +42 -60
  22. package/dist/cli/postinstall/constants.js.map +1 -1
  23. package/dist/cli/postinstall/inline-skills.js +2 -2
  24. package/dist/cli/postinstall/inline-skills.js.map +1 -1
  25. package/dist/cli/postinstall/main.d.ts.map +1 -1
  26. package/dist/cli/postinstall/main.js +2 -0
  27. package/dist/cli/postinstall/main.js.map +1 -1
  28. package/dist/cli/postinstall.d.ts +6 -1
  29. package/dist/cli/postinstall.d.ts.map +1 -1
  30. package/dist/cli/postinstall.js +6 -1
  31. package/dist/cli/postinstall.js.map +1 -1
  32. package/dist/cli/setup/GlobalInstaller.d.ts +1 -15
  33. package/dist/cli/setup/GlobalInstaller.d.ts.map +1 -1
  34. package/dist/cli/setup/GlobalInstaller.js +16 -115
  35. package/dist/cli/setup/GlobalInstaller.js.map +1 -1
  36. package/dist/cli/setup/GlobalInstaller.test.d.ts +2 -0
  37. package/dist/cli/setup/GlobalInstaller.test.d.ts.map +1 -0
  38. package/dist/cli/setup/GlobalInstaller.test.js +16 -0
  39. package/dist/cli/setup/GlobalInstaller.test.js.map +1 -0
  40. package/dist/cli/setup/ProjectSetup.js +2 -2
  41. package/dist/cli/setup/ProjectSetup.js.map +1 -1
  42. package/dist/cli/setup.d.ts +1 -1
  43. package/dist/cli/setup.d.ts.map +1 -1
  44. package/dist/cli/setup.js +1 -1
  45. package/dist/cli/setup.js.map +1 -1
  46. package/dist/infra/lib/SkillRepository.js +1 -1
  47. package/dist/infra/lib/evolution/__tests__/integration.test.js +0 -42
  48. package/dist/infra/lib/evolution/__tests__/integration.test.js.map +1 -1
  49. package/hooks/scripts/__tests__/.vibe/command-log.txt +3 -3
  50. package/hooks/scripts/__tests__/clone-behaviors.test.js +33 -1
  51. package/hooks/scripts/__tests__/code-check-memory-write.test.js +81 -0
  52. package/hooks/scripts/__tests__/step-counter.test.js +21 -0
  53. package/hooks/scripts/auto-format.js +2 -11
  54. package/hooks/scripts/auto-test.js +2 -11
  55. package/hooks/scripts/clone-extract.js +146 -10
  56. package/hooks/scripts/code-check.js +27 -55
  57. package/hooks/scripts/lib/glob.js +32 -0
  58. package/hooks/scripts/lib/hook-context.js +19 -2
  59. package/hooks/scripts/post-edit.js +2 -3
  60. package/hooks/scripts/prompt-dispatcher.js +1 -1
  61. package/hooks/scripts/scope-guard.js +3 -42
  62. package/hooks/scripts/sentinel-guard.js +5 -20
  63. package/hooks/scripts/session-start.js +2 -2
  64. package/hooks/scripts/step-counter.js +35 -57
  65. package/package.json +2 -3
  66. package/skills/clone/SKILL.md +10 -216
  67. package/skills/clone/references/capture-rules.md +48 -0
  68. package/skills/clone/references/legal-and-error-recovery.md +40 -0
  69. package/skills/clone/references/refine-rules.md +61 -0
  70. package/skills/clone/references/scaffold-phases.md +59 -0
  71. package/skills/clone/references/setup-and-layout.md +30 -0
  72. package/skills/docs/SKILL.md +39 -4
  73. package/skills/docs/references/api-docs-changelog.md +34 -0
  74. package/skills/docs/references/codemaps-output.md +23 -0
  75. package/{agents/diagrammer.md β†’ skills/docs/references/diagram-spec.md} +2 -15
  76. package/skills/exec-plan/SKILL.md +1 -1
  77. package/skills/exec-plan/templates/plan.md +1 -1
  78. package/skills/handoff/SKILL.md +3 -3
  79. package/skills/handoff/templates/handoff.md +1 -1
  80. package/skills/vibe/SKILL.md +3 -2
  81. package/skills/vibe.analyze/SKILL.md +12 -249
  82. package/skills/vibe.analyze/references/output-templates.md +188 -0
  83. package/skills/vibe.analyze/references/quality-gate.md +93 -0
  84. package/skills/vibe.clone/SKILL.md +14 -1
  85. package/skills/vibe.continue/SKILL.md +32 -0
  86. package/skills/vibe.design/SKILL.md +23 -1
  87. package/skills/vibe.design/references/ui-preview.md +20 -0
  88. package/skills/vibe.docs/SKILL.md +4 -2
  89. package/skills/vibe.figma/SKILL.md +33 -260
  90. package/skills/vibe.figma/references/branch-phases.md +113 -0
  91. package/skills/vibe.figma/references/state-schema.md +42 -0
  92. package/skills/vibe.figma/references/step-algorithms.md +204 -0
  93. package/skills/vibe.image/SKILL.md +62 -0
  94. package/skills/vibe.image/references/image-generation-examples.md +39 -0
  95. package/skills/vibe.reason/SKILL.md +3 -183
  96. package/skills/vibe.reason/references/output-format-template.md +57 -0
  97. package/skills/vibe.reason/references/quality-rubrics.md +94 -0
  98. package/skills/vibe.reason/references/worked-example.md +45 -0
  99. package/skills/vibe.review/SKILL.md +13 -348
  100. package/skills/vibe.review/references/boundary-check.md +25 -0
  101. package/skills/vibe.review/references/output-template.md +74 -0
  102. package/skills/vibe.review/references/quality-gate.md +84 -0
  103. package/skills/vibe.review/references/race-mode.md +117 -0
  104. package/skills/vibe.review/references/worked-examples.md +94 -0
  105. package/vibe/templates/claudemd-template.md +1 -1
  106. package/agents/acceptance-tester.md +0 -56
  107. package/agents/documenter.md +0 -43
  108. package/agents/figma/figma-engineer.md +0 -76
  109. package/dist/cli/postinstall/index.d.ts +0 -23
  110. package/dist/cli/postinstall/index.d.ts.map +0 -1
  111. package/dist/cli/postinstall/index.js +0 -23
  112. package/dist/cli/postinstall/index.js.map +0 -1
  113. package/dist/cli/setup/index.d.ts +0 -9
  114. package/dist/cli/setup/index.d.ts.map +0 -1
  115. package/dist/cli/setup/index.js +0 -12
  116. package/dist/cli/setup/index.js.map +0 -1
  117. package/hooks/scripts/__tests__/.vibe/memories/memories.db +0 -0
  118. package/hooks/scripts/__tests__/.vibe/memories/memories.db-shm +0 -0
  119. package/hooks/scripts/__tests__/.vibe/memories/memories.db-wal +0 -0
  120. package/hooks/scripts/evolution-engine.js +0 -91
  121. package/hooks/scripts/hud-status.js +0 -321
  122. package/hooks/scripts/skill-injector.js +0 -83
  123. package/skills/vibe.utils/SKILL.md +0 -415
@@ -1,91 +0,0 @@
1
- /**
2
- * PostToolUse Hook - Evolution Engine
3
- * Write/Edit 이벀트 ν›„ μΈμ‚¬μ΄νŠΈ μΆ”μΆœ 및 μžλ™ 생성 νŒŒμ΄ν”„λΌμΈ 트리거
4
- */
5
- import { getLibBaseUrl, PROJECT_DIR, projectVibePath } from './utils.js';
6
- import fs from 'fs';
7
- import path from 'path';
8
-
9
- async function main() {
10
- // Evolution ν™œμ„±ν™” μ—¬λΆ€ 확인
11
- const configPath = projectVibePath(PROJECT_DIR, 'config.json');
12
- let config = { mode: 'suggest', enabled: false };
13
-
14
- try {
15
- if (fs.existsSync(configPath)) {
16
- const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
17
- config = {
18
- mode: raw.evolution?.mode || 'suggest',
19
- enabled: raw.evolution?.enabled === true,
20
- };
21
- }
22
- } catch { /* ignore */ }
23
-
24
- if (!config.enabled) return;
25
-
26
- // λΉ„λ™κΈ°λ‘œ νŒŒμ΄ν”„λΌμΈ μ‹€ν–‰ (메인 ν›… 흐름 차단 μ•ˆ 함)
27
- setImmediate(async () => {
28
- try {
29
- const LIB_BASE = getLibBaseUrl();
30
- const [memMod, extractorMod, orchestratorMod] = await Promise.all([
31
- import(`${LIB_BASE}memory/MemoryStorage.js`),
32
- import(`${LIB_BASE}evolution/InsightExtractor.js`),
33
- import(`${LIB_BASE}evolution/EvolutionOrchestrator.js`),
34
- ]);
35
-
36
- const storage = new memMod.MemoryStorage(PROJECT_DIR);
37
-
38
- // Phase 2: μΈμ‚¬μ΄νŠΈ μΆ”μΆœ
39
- const extractor = new extractorMod.InsightExtractor(storage);
40
- const extractResult = extractor.extractFromRecent(20);
41
-
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
- ) {
65
- storage.close();
66
- return;
67
- }
68
-
69
- // Phase 3: config.mode에 따라 생성
70
- if (config.mode === 'suggest' || config.mode === 'auto') {
71
- const orchestrator = new orchestratorMod.EvolutionOrchestrator(storage, {
72
- mode: config.mode,
73
- });
74
- const genResult = orchestrator.generate();
75
-
76
- if (genResult.generated.length > 0) {
77
- const label = config.mode === 'auto' ? 'auto-generated' : 'suggested';
78
- process.stderr.write(
79
- `[Evolution] ${genResult.generated.length} artifacts ${label}\n`
80
- );
81
- }
82
- }
83
-
84
- storage.close();
85
- } catch (e) {
86
- process.stderr.write(`[Evolution] Engine error: ${e.message}\n`);
87
- }
88
- });
89
- }
90
-
91
- main();
@@ -1,321 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * HUD Status Manager
4
- * μ‹€μ‹œκ°„ μƒνƒœ μ‹œκ°ν™” (Claude Code statusline 연동)
5
- */
6
-
7
- import fs from 'fs';
8
- import path from 'path';
9
- import os from 'os';
10
-
11
- // μƒνƒœ μ €μž₯ 경둜
12
- const STATE_DIR = path.join(os.homedir(), '.claude', '.vibe-hud');
13
- const STATE_FILE = path.join(STATE_DIR, 'state.json');
14
-
15
- // Write debounce configuration
16
- const WRITE_DEBOUNCE_MS = 500;
17
- let pendingState = null;
18
- let writeTimer = null;
19
-
20
- // κΈ°λ³Έ μƒνƒœ
21
- const DEFAULT_STATE = {
22
- mode: 'idle', // idle | ultrawork | spec | review
23
- feature: null,
24
- phase: { current: 0, total: 0, name: '' },
25
- agents: [], // μ‹€ν–‰ 쀑인 μ—μ΄μ „νŠΈλ“€
26
- context: { used: 0, total: 200000 }, // μ»¨ν…μŠ€νŠΈ μ‚¬μš©λŸ‰
27
- lastUpdate: null,
28
- };
29
-
30
- // μƒνƒœ μ•„μ΄μ½˜
31
- const MODE_ICONS = {
32
- idle: 'πŸ’€',
33
- ultrawork: 'πŸš€',
34
- spec: 'πŸ“',
35
- review: 'πŸ”',
36
- implementing: 'πŸ”¨',
37
- testing: 'πŸ§ͺ',
38
- error: '❌',
39
- };
40
-
41
- // 건강 μƒνƒœ 색상 (ANSI)
42
- const HEALTH_COLORS = {
43
- good: '\x1b[32m', // 녹색
44
- warning: '\x1b[33m', // λ…Έλž€μƒ‰
45
- critical: '\x1b[31m', // 빨간색
46
- reset: '\x1b[0m',
47
- };
48
-
49
- /**
50
- * μƒνƒœ 디렉토리 μ΄ˆκΈ°ν™”
51
- */
52
- function ensureStateDir() {
53
- if (!fs.existsSync(STATE_DIR)) {
54
- fs.mkdirSync(STATE_DIR, { recursive: true });
55
- }
56
- }
57
-
58
- /**
59
- * ν˜„μž¬ μƒνƒœ λ‘œλ“œ
60
- */
61
- function loadState() {
62
- try {
63
- if (fs.existsSync(STATE_FILE)) {
64
- return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
65
- }
66
- } catch {
67
- // λ¬΄μ‹œ
68
- }
69
- return { ...DEFAULT_STATE };
70
- }
71
-
72
- /**
73
- * μƒνƒœλ₯Ό λ””μŠ€ν¬μ— μ¦‰μ‹œ 기둝
74
- */
75
- function flushState(state) {
76
- ensureStateDir();
77
- state.lastUpdate = new Date().toISOString();
78
- fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
79
- }
80
-
81
- /**
82
- * μƒνƒœ μ €μž₯ (debounced - λΉˆλ²ˆν•œ ν˜ΈμΆœμ„ 병합)
83
- * CLI μ’…λ£Œ μ „ pending writeκ°€ 있으면 flush 됨
84
- */
85
- function saveState(state) {
86
- state.lastUpdate = new Date().toISOString();
87
- pendingState = state;
88
- if (writeTimer) clearTimeout(writeTimer);
89
- writeTimer = setTimeout(() => {
90
- if (pendingState) {
91
- flushState(pendingState);
92
- pendingState = null;
93
- writeTimer = null;
94
- }
95
- }, WRITE_DEBOUNCE_MS);
96
- }
97
-
98
- /**
99
- * μƒνƒœ μ—…λ°μ΄νŠΈ
100
- */
101
- function updateState(updates) {
102
- const state = loadState();
103
- Object.assign(state, updates);
104
- saveState(state);
105
- return state;
106
- }
107
-
108
- /**
109
- * μ»¨ν…μŠ€νŠΈ 건강 μƒνƒœ
110
- */
111
- function getContextHealth(used, total) {
112
- const percentage = (used / total) * 100;
113
- if (percentage >= 90) return 'critical';
114
- if (percentage >= 70) return 'warning';
115
- return 'good';
116
- }
117
-
118
- /**
119
- * μƒνƒœ 라인 포맷 (minimal)
120
- */
121
- function formatMinimal(state) {
122
- const icon = MODE_ICONS[state.mode] || 'πŸ’€';
123
- const phase = state.phase.total > 0
124
- ? `${state.phase.current}/${state.phase.total}`
125
- : '';
126
- return `${icon} ${state.mode}${phase ? ` [${phase}]` : ''}`;
127
- }
128
-
129
- /**
130
- * μƒνƒœ 라인 포맷 (focused - default)
131
- */
132
- function formatFocused(state) {
133
- const icon = MODE_ICONS[state.mode] || 'πŸ’€';
134
- const feature = state.feature ? `: ${state.feature}` : '';
135
- const phase = state.phase.total > 0
136
- ? ` [Phase ${state.phase.current}/${state.phase.total}]`
137
- : '';
138
-
139
- const contextPct = Math.round((state.context.used / state.context.total) * 100);
140
- const contextHealth = getContextHealth(state.context.used, state.context.total);
141
- const contextColor = HEALTH_COLORS[contextHealth];
142
-
143
- return `${icon} ${state.mode}${feature}${phase} | ${contextColor}CTX: ${contextPct}%${HEALTH_COLORS.reset}`;
144
- }
145
-
146
- /**
147
- * μƒνƒœ 라인 포맷 (full)
148
- */
149
- function formatFull(state) {
150
- const lines = [];
151
- const icon = MODE_ICONS[state.mode] || 'πŸ’€';
152
-
153
- lines.push(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
154
- lines.push(`${icon} VIBE HUD`);
155
- lines.push(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
156
-
157
- lines.push(`Mode: ${state.mode}`);
158
- if (state.feature) {
159
- lines.push(`Feature: ${state.feature}`);
160
- }
161
-
162
- if (state.phase.total > 0) {
163
- const progress = Math.round((state.phase.current / state.phase.total) * 100);
164
- const bar = createProgressBar(progress);
165
- lines.push(`Phase: ${state.phase.current}/${state.phase.total} ${state.phase.name}`);
166
- lines.push(` ${bar} ${progress}%`);
167
- }
168
-
169
- if (state.agents.length > 0) {
170
- lines.push(`Agents: ${state.agents.map(a => `${a.name}(${a.model})`).join(', ')}`);
171
- }
172
-
173
- const contextPct = Math.round((state.context.used / state.context.total) * 100);
174
- const contextHealth = getContextHealth(state.context.used, state.context.total);
175
- const contextColor = HEALTH_COLORS[contextHealth];
176
- lines.push(`Context: ${contextColor}${contextPct}%${HEALTH_COLORS.reset} (${state.context.used}/${state.context.total})`);
177
-
178
- lines.push(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
179
-
180
- return lines.join('\n');
181
- }
182
-
183
- /**
184
- * ν”„λ‘œκ·Έλ ˆμŠ€ λ°” 생성
185
- */
186
- function createProgressBar(percentage, width = 20) {
187
- const filled = Math.round((percentage / 100) * width);
188
- const empty = width - filled;
189
- return `[${'β–ˆ'.repeat(filled)}${'β–‘'.repeat(empty)}]`;
190
- }
191
-
192
- /**
193
- * CLI λͺ…λ Ή 처리
194
- */
195
- function handleCommand(args) {
196
- const command = args[0];
197
- const params = args.slice(1);
198
-
199
- switch (command) {
200
- case 'show':
201
- case 'status': {
202
- const format = params[0] || 'focused';
203
- const state = loadState();
204
- if (format === 'minimal') console.log(formatMinimal(state));
205
- else if (format === 'full') console.log(formatFull(state));
206
- else console.log(formatFocused(state));
207
- break;
208
- }
209
-
210
- case 'set': {
211
- const key = params[0];
212
- const value = params[1];
213
- if (key && value !== undefined) {
214
- const updates = {};
215
- // 쀑첩 ν‚€ 처리 (예: phase.current)
216
- if (key.includes('.')) {
217
- const [parent, child] = key.split('.');
218
- const state = loadState();
219
- updates[parent] = { ...(state[parent] || {}), [child]: isNaN(value) ? value : Number(value) };
220
- } else {
221
- updates[key] = isNaN(value) ? value : Number(value);
222
- }
223
- updateState(updates);
224
- console.log(`βœ“ Updated ${key}`);
225
- }
226
- break;
227
- }
228
-
229
- case 'start': {
230
- const mode = params[0] || 'ultrawork';
231
- const feature = params[1] || null;
232
- updateState({
233
- mode,
234
- feature,
235
- phase: { current: 0, total: 0, name: '' },
236
- agents: [],
237
- });
238
- console.log(`πŸš€ Started ${mode}${feature ? `: ${feature}` : ''}`);
239
- break;
240
- }
241
-
242
- case 'phase': {
243
- const current = parseInt(params[0], 10) || 1;
244
- const total = parseInt(params[1], 10) || current;
245
- const name = params.slice(2).join(' ') || '';
246
- updateState({ phase: { current, total, name } });
247
- console.log(`πŸ“ Phase ${current}/${total}${name ? `: ${name}` : ''}`);
248
- break;
249
- }
250
-
251
- case 'agent': {
252
- const action = params[0]; // add | remove | clear
253
- const state = loadState();
254
- if (action === 'add') {
255
- const name = params[1];
256
- const model = params[2] || 'sonnet';
257
- state.agents.push({ name, model, startTime: Date.now() });
258
- saveState(state);
259
- console.log(`πŸ€– Agent added: ${name} (${model})`);
260
- } else if (action === 'remove') {
261
- const name = params[1];
262
- state.agents = state.agents.filter(a => a.name !== name);
263
- saveState(state);
264
- console.log(`πŸ€– Agent removed: ${name}`);
265
- } else if (action === 'clear') {
266
- state.agents = [];
267
- saveState(state);
268
- console.log(`πŸ€– All agents cleared`);
269
- }
270
- break;
271
- }
272
-
273
- case 'context': {
274
- const used = parseInt(params[0], 10) || 0;
275
- const total = parseInt(params[1], 10) || 200000;
276
- updateState({ context: { used, total } });
277
- const pct = Math.round((used / total) * 100);
278
- console.log(`πŸ“Š Context: ${pct}%`);
279
- break;
280
- }
281
-
282
- case 'done':
283
- case 'reset': {
284
- saveState({ ...DEFAULT_STATE });
285
- console.log(`πŸ’€ HUD reset`);
286
- break;
287
- }
288
-
289
- default:
290
- console.log(`
291
- VIBE HUD - Real-time status visualization
292
-
293
- Commands:
294
- show [format] Show current status (minimal|focused|full)
295
- start [mode] [feature] Start tracking (ultrawork|spec|review)
296
- phase <current> <total> [name] Update phase progress
297
- agent add|remove|clear [name] [model] Manage agents
298
- context <used> [total] Update context usage
299
- set <key> <value> Set arbitrary state value
300
- done|reset Reset to idle state
301
-
302
- Examples:
303
- node hud-status.js show full
304
- node hud-status.js start ultrawork "login-feature"
305
- node hud-status.js phase 2 5 "Implementing core"
306
- node hud-status.js agent add "explore-1" haiku
307
- `);
308
- }
309
- }
310
-
311
- // Flush pending state on process exit to avoid data loss
312
- process.on('exit', () => {
313
- if (pendingState) {
314
- flushState(pendingState);
315
- pendingState = null;
316
- }
317
- });
318
-
319
- // 메인 μ‹€ν–‰
320
- const args = process.argv.slice(2);
321
- handleCommand(args);
@@ -1,83 +0,0 @@
1
- /**
2
- * SessionStart Hook - Auto-generated skill/agent/rule μ£Όμž…
3
- * auto/ 디렉토리λ₯Ό μŠ€μΊ”ν•˜μ—¬ .disabledκ°€ μ•„λ‹Œ νŒŒμΌμ„ λ‘œλ“œν•˜κ³  μ‚¬μš©λŸ‰ 좔적
4
- */
5
- import fs from 'fs';
6
- import path from 'path';
7
- import os from 'os';
8
- import { getLibBaseUrl, PROJECT_DIR } from './utils.js';
9
-
10
- const HOME = os.homedir();
11
-
12
- // auto/ 디렉토리 경둜
13
- const AUTO_DIRS = {
14
- 'user-auto': {
15
- skills: path.join(HOME, '.claude', 'vibe', 'skills', 'auto'),
16
- agents: path.join(HOME, '.claude', 'agents', 'auto'),
17
- rules: path.join(HOME, '.claude', 'vibe', 'rules', 'auto'),
18
- },
19
- 'project-auto': {
20
- skills: path.join(PROJECT_DIR, '.claude', 'vibe', 'skills', 'auto'),
21
- agents: path.join(PROJECT_DIR, '.claude', 'agents', 'auto'),
22
- rules: path.join(PROJECT_DIR, '.claude', 'vibe', 'rules', 'auto'),
23
- },
24
- };
25
-
26
- /**
27
- * λ””λ ‰ν† λ¦¬μ—μ„œ .md 파일 μŠ€μΊ” (.disabled μ œμ™Έ)
28
- */
29
- function scanAutoDir(dirPath) {
30
- if (!fs.existsSync(dirPath)) return [];
31
-
32
- return fs.readdirSync(dirPath)
33
- .filter(f => f.endsWith('.md') && !f.endsWith('.disabled'))
34
- .map(f => ({
35
- name: f.replace(/\.md$/, ''),
36
- path: path.join(dirPath, f),
37
- content: fs.readFileSync(path.join(dirPath, f), 'utf8'),
38
- }));
39
- }
40
-
41
- async function main() {
42
- const allSkills = [];
43
-
44
- for (const [source, dirs] of Object.entries(AUTO_DIRS)) {
45
- for (const [type, dirPath] of Object.entries(dirs)) {
46
- const files = scanAutoDir(dirPath);
47
- for (const file of files) {
48
- allSkills.push({ ...file, source, type, generated: true });
49
- }
50
- }
51
- }
52
-
53
- if (allSkills.length === 0) return;
54
-
55
- // μ‚¬μš©λŸ‰ 좔적
56
- try {
57
- const LIB_BASE = getLibBaseUrl();
58
- const [memMod, trackerMod] = await Promise.all([
59
- import(`${LIB_BASE}memory/MemoryStorage.js`),
60
- import(`${LIB_BASE}evolution/UsageTracker.js`),
61
- ]);
62
-
63
- const storage = new memMod.MemoryStorage(PROJECT_DIR);
64
- const tracker = new trackerMod.UsageTracker(storage);
65
-
66
- for (const skill of allSkills) {
67
- tracker.recordUsage({
68
- generationId: skill.name,
69
- event: 'injected',
70
- metadata: { source: skill.source, type: skill.type, generated: skill.generated },
71
- });
72
- }
73
-
74
- storage.close();
75
- } catch {
76
- // 좔적 μ‹€νŒ¨ν•΄λ„ μ£Όμž…μ€ 계속
77
- }
78
-
79
- const summary = allSkills.map(s => `${s.source}/${s.type}/${s.name}`).join(', ');
80
- process.stderr.write(`[Evolution] Injected ${allSkills.length} auto skills: ${summary}\n`);
81
- }
82
-
83
- main();