@su-record/vibe 2.9.1 → 2.9.3

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 (79) hide show
  1. package/CLAUDE.md +31 -10
  2. package/README.ko.md +90 -25
  3. package/README.md +139 -25
  4. package/agents/teams/debug-team.md +70 -0
  5. package/agents/teams/dev-team.md +88 -0
  6. package/agents/teams/docs-team.md +80 -0
  7. package/agents/teams/figma/figma-analyst.md +52 -0
  8. package/agents/teams/figma/figma-architect.md +112 -0
  9. package/agents/teams/figma/figma-auditor.md +82 -0
  10. package/agents/teams/figma/figma-builder.md +100 -0
  11. package/agents/teams/figma-team.md +85 -0
  12. package/agents/teams/fullstack-team.md +83 -0
  13. package/agents/teams/lite-team.md +69 -0
  14. package/agents/teams/migration-team.md +78 -0
  15. package/agents/teams/refactor-team.md +94 -0
  16. package/agents/teams/research-team.md +86 -0
  17. package/agents/teams/review-debate-team.md +125 -0
  18. package/agents/teams/security-team.md +81 -0
  19. package/commands/vibe.analyze.md +324 -170
  20. package/commands/vibe.figma.md +549 -34
  21. package/commands/vibe.harness.md +177 -0
  22. package/commands/vibe.review.md +1 -63
  23. package/commands/vibe.run.md +52 -403
  24. package/commands/vibe.scaffold.md +195 -0
  25. package/commands/vibe.spec.md +373 -1003
  26. package/commands/vibe.trace.md +17 -0
  27. package/commands/vibe.verify.md +19 -10
  28. package/dist/cli/commands/init.d.ts.map +1 -1
  29. package/dist/cli/commands/init.js +29 -1
  30. package/dist/cli/commands/init.js.map +1 -1
  31. package/dist/cli/commands/update.d.ts.map +1 -1
  32. package/dist/cli/commands/update.js +4 -2
  33. package/dist/cli/commands/update.js.map +1 -1
  34. package/dist/cli/postinstall/constants.d.ts +1 -1
  35. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  36. package/dist/cli/postinstall/constants.js +6 -1
  37. package/dist/cli/postinstall/constants.js.map +1 -1
  38. package/dist/cli/setup/ProjectSetup.d.ts +12 -1
  39. package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
  40. package/dist/cli/setup/ProjectSetup.js +259 -72
  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/hooks/scripts/figma-guard.js +220 -0
  47. package/hooks/scripts/figma-refine.js +315 -0
  48. package/hooks/scripts/figma-to-scss.js +394 -0
  49. package/hooks/scripts/figma-validate.js +353 -0
  50. package/package.json +1 -1
  51. package/skills/arch-guard/SKILL.md +1 -1
  52. package/skills/capability-loop/SKILL.md +106 -2
  53. package/skills/chub-usage/SKILL.md +43 -43
  54. package/skills/claude-md-guide/SKILL.md +175 -175
  55. package/skills/design-teach/SKILL.md +33 -33
  56. package/skills/devlog/SKILL.md +38 -38
  57. package/skills/event-comms/SKILL.md +23 -13
  58. package/skills/event-ops/SKILL.md +28 -19
  59. package/skills/event-planning/SKILL.md +13 -1
  60. package/skills/priority-todos/SKILL.md +1 -1
  61. package/skills/vibe.figma/SKILL.md +263 -115
  62. package/skills/vibe.figma/templates/component-spec.md +168 -0
  63. package/skills/vibe.figma.convert/SKILL.md +131 -84
  64. package/skills/vibe.figma.convert/rubrics/conversion-rules.md +12 -0
  65. package/skills/vibe.figma.extract/SKILL.md +148 -108
  66. package/skills/vibe.figma.extract/rubrics/image-rules.md +15 -3
  67. package/skills/vibe.interview/SKILL.md +358 -0
  68. package/skills/vibe.interview/checklists/api.md +101 -0
  69. package/skills/vibe.interview/checklists/feature.md +88 -0
  70. package/skills/vibe.interview/checklists/library.md +95 -0
  71. package/skills/vibe.interview/checklists/mobile.md +89 -0
  72. package/skills/vibe.interview/checklists/webapp.md +97 -0
  73. package/skills/vibe.interview/checklists/website.md +99 -0
  74. package/skills/vibe.plan/SKILL.md +216 -0
  75. package/skills/vibe.spec/SKILL.md +1155 -0
  76. package/{commands/vibe.spec.review.md → skills/vibe.spec.review/SKILL.md} +272 -155
  77. package/vibe/templates/claudemd-template.md +74 -0
  78. package/vibe/templates/constitution-template.md +15 -0
  79. package/vibe/templates/plan-template.md +194 -0
@@ -0,0 +1,353 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * figma-validate.js — SCSS vs sections.json 대조 검증
5
+ *
6
+ * Usage:
7
+ * node figma-validate.js <scss-dir> <sections.json> [--section=<name>]
8
+ *
9
+ * 검증 항목:
10
+ * 1. SCSS의 모든 CSS 속성이 sections.json에 근거하는가
11
+ * 2. sections.json의 CSS 속성이 SCSS에 누락되지 않았는가
12
+ * 3. 금지 패턴 감지 (커스텀 함수, aspect-ratio 등)
13
+ * 4. 이미지 파일명 kebab-case 확인
14
+ *
15
+ * 출력: JSON { status, errors[], summary }
16
+ */
17
+
18
+ import fs from 'fs';
19
+ import path from 'path';
20
+
21
+ // ─── Helpers ────────────────────────────────────────────────────────
22
+
23
+ function camelToKebab(str) {
24
+ return str.replace(/([A-Z])/g, '-$1').toLowerCase();
25
+ }
26
+
27
+ function parseSCSS(scssContent) {
28
+ // 간이 SCSS 파서: 셀렉터 → CSS 속성 맵 추출
29
+ const blocks = {};
30
+ let currentSelector = null;
31
+ const lines = scssContent.split('\n');
32
+
33
+ for (const line of lines) {
34
+ const trimmed = line.trim();
35
+
36
+ // 빈 줄, 코멘트 스킵
37
+ if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) continue;
38
+
39
+ // 셀렉터 열기
40
+ const selectorMatch = trimmed.match(/^([.&][a-zA-Z0-9_-][a-zA-Z0-9_-]*(?:__[a-zA-Z0-9_-]+(?:-[a-zA-Z0-9_-]+)*)?)\s*\{/);
41
+ if (selectorMatch) {
42
+ currentSelector = selectorMatch[1];
43
+ if (!blocks[currentSelector]) blocks[currentSelector] = {};
44
+ continue;
45
+ }
46
+
47
+ // 블록 닫기
48
+ if (trimmed === '}') {
49
+ currentSelector = null;
50
+ continue;
51
+ }
52
+
53
+ // CSS 속성
54
+ if (currentSelector && trimmed.includes(':') && trimmed.endsWith(';')) {
55
+ const colonIdx = trimmed.indexOf(':');
56
+ const prop = trimmed.slice(0, colonIdx).trim();
57
+ const value = trimmed.slice(colonIdx + 1).replace(/;$/, '').trim();
58
+ blocks[currentSelector][prop] = value;
59
+ }
60
+ }
61
+
62
+ return blocks;
63
+ }
64
+
65
+ // ─── Forbidden Pattern Detection ────────────────────────────────────
66
+
67
+ const FORBIDDEN_PATTERNS = [
68
+ { pattern: /@function\s/, id: 'custom-function', msg: '@function 자체 정의 금지' },
69
+ { pattern: /@mixin\s/, id: 'custom-mixin', msg: '@mixin 자체 정의 금지 (기존 @use만 허용)' },
70
+ { pattern: /aspect-ratio\s*:/, id: 'aspect-ratio', msg: 'aspect-ratio는 tree.json에 없는 속성' },
71
+ { pattern: /clamp\s*\(/, id: 'clamp', msg: 'clamp()는 font-size 외 사용 금지' },
72
+ { pattern: /\d+vw/, id: 'vw-unit', msg: 'vw 단위 사용 금지 (스태틱 구현)' },
73
+ { pattern: /@media\s/, id: 'media-query', msg: '@media 금지 (스태틱 구현)' },
74
+ { pattern: /@include\s/, id: 'include', msg: '@include 사용 시 기존 프로젝트 믹스인만 허용' },
75
+ ];
76
+
77
+ function detectForbidden(scssContent, filePath) {
78
+ const errors = [];
79
+ const lines = scssContent.split('\n');
80
+
81
+ for (let i = 0; i < lines.length; i++) {
82
+ const line = lines[i];
83
+ for (const { pattern, id, msg } of FORBIDDEN_PATTERNS) {
84
+ if (pattern.test(line)) {
85
+ // clamp in font-size is allowed
86
+ if (id === 'clamp' && line.includes('font-size')) continue;
87
+ errors.push({
88
+ priority: 'P1',
89
+ file: filePath,
90
+ line: i + 1,
91
+ type: `forbidden-${id}`,
92
+ actual: line.trim(),
93
+ message: msg
94
+ });
95
+ }
96
+ }
97
+ }
98
+
99
+ return errors;
100
+ }
101
+
102
+ // ─── CSS Value Comparison ───────────────────────────────────────────
103
+
104
+ function collectCSSFromTree(node, sectionClass, parentPath, result) {
105
+ const css = node.css || {};
106
+ const children = node.children || [];
107
+ const name = node.name || '';
108
+ const type = node.type || '';
109
+
110
+ // BG 프레임 스킵
111
+ const nameLower = name.toLowerCase();
112
+ if (nameLower === 'bg' || nameLower.endsWith('-bg') || nameLower.startsWith('bg-')) return;
113
+
114
+ // 클래스명 재현 (figma-to-scss.js와 동일 로직)
115
+ let cls = name
116
+ .replace(/[^a-zA-Z0-9\s_-]/g, '')
117
+ .replace(/[\s_]+/g, '-')
118
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
119
+ .toLowerCase()
120
+ .replace(/-+/g, '-')
121
+ .replace(/^-|-$/g, '') || null;
122
+
123
+ if (!cls) {
124
+ const idx = parentPath ? parentPath.split('-').length : 0;
125
+ if (type === 'TEXT') cls = `text-${idx}`;
126
+ else if (type === 'VECTOR') cls = `vector-${idx}`;
127
+ else if (type === 'RECTANGLE') cls = `rect-${idx}`;
128
+ else cls = `el-${idx}`;
129
+ }
130
+
131
+ const currentPath = parentPath ? `${parentPath}-${cls}` : cls;
132
+ const selector = `.${sectionClass}__${currentPath}`;
133
+
134
+ // CSS 속성 저장 (kebab 변환)
135
+ if (Object.keys(css).length > 0) {
136
+ const kebabCSS = {};
137
+ for (const [prop, value] of Object.entries(css)) {
138
+ if (prop.startsWith('_')) continue;
139
+ kebabCSS[camelToKebab(prop)] = String(value);
140
+ }
141
+ result[selector] = kebabCSS;
142
+ }
143
+
144
+ // 자식 재귀
145
+ const seenClasses = new Set();
146
+ for (const child of children) {
147
+ const childName = child.name || '';
148
+ const childLower = childName.toLowerCase();
149
+ if (childLower === 'bg' || childLower.endsWith('-bg') || childLower.startsWith('bg-')) continue;
150
+
151
+ let childCls = childName
152
+ .replace(/[^a-zA-Z0-9\s_-]/g, '')
153
+ .replace(/[\s_]+/g, '-')
154
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
155
+ .toLowerCase()
156
+ .replace(/-+/g, '-')
157
+ .replace(/^-|-$/g, '') || null;
158
+ if (!childCls) childCls = `${child.type?.toLowerCase() || 'el'}-0`;
159
+
160
+ if (seenClasses.has(childCls)) continue;
161
+ seenClasses.add(childCls);
162
+ collectCSSFromTree(child, sectionClass, currentPath, result);
163
+ }
164
+ }
165
+
166
+ function compareCSSValues(scssBlocks, treeCSS, filePath) {
167
+ const errors = [];
168
+
169
+ // SCSS에 있지만 tree에 없는 속성 (임의 추가)
170
+ for (const [selector, props] of Object.entries(scssBlocks)) {
171
+ if (!selector.startsWith('.')) continue;
172
+ const treeProps = treeCSS[selector];
173
+
174
+ for (const [prop, value] of Object.entries(props)) {
175
+ // background-image url, background-size 등은 이미지 처리에서 추가됨
176
+ if (prop === 'background-image' || prop === 'background-size' ||
177
+ prop === 'background-position' || prop === 'background-repeat') continue;
178
+ // imageRef 주석 스킵
179
+ if (prop.startsWith('//')) continue;
180
+
181
+ if (!treeProps || !(prop in treeProps)) {
182
+ errors.push({
183
+ priority: 'P2',
184
+ file: filePath,
185
+ type: 'extra-property',
186
+ selector,
187
+ property: prop,
188
+ actual: value,
189
+ message: `SCSS에 있지만 sections.json에 없는 속성: ${prop}: ${value}`
190
+ });
191
+ } else if (treeProps[prop] !== value) {
192
+ errors.push({
193
+ priority: 'P1',
194
+ file: filePath,
195
+ type: 'value-mismatch',
196
+ selector,
197
+ property: prop,
198
+ expected: treeProps[prop],
199
+ actual: value,
200
+ message: `값 불일치: ${prop} expected="${treeProps[prop]}" actual="${value}"`
201
+ });
202
+ }
203
+ }
204
+ }
205
+
206
+ // tree에 있지만 SCSS에 없는 속성 (누락)
207
+ for (const [selector, props] of Object.entries(treeCSS)) {
208
+ const scssProps = scssBlocks[selector];
209
+ if (!scssProps) {
210
+ errors.push({
211
+ priority: 'P1',
212
+ file: filePath,
213
+ type: 'missing-selector',
214
+ selector,
215
+ message: `sections.json에 있지만 SCSS에 없는 셀렉터: ${selector}`
216
+ });
217
+ continue;
218
+ }
219
+ for (const [prop] of Object.entries(props)) {
220
+ if (!(prop in scssProps)) {
221
+ errors.push({
222
+ priority: 'P1',
223
+ file: filePath,
224
+ type: 'missing-property',
225
+ selector,
226
+ property: prop,
227
+ expected: props[prop],
228
+ message: `SCSS에 누락된 속성: ${selector} { ${prop}: ${props[prop]} }`
229
+ });
230
+ }
231
+ }
232
+ }
233
+
234
+ return errors;
235
+ }
236
+
237
+ // ─── Image Filename Check ───────────────────────────────────────────
238
+
239
+ function checkImageFilenames(scssContent, filePath) {
240
+ const errors = [];
241
+ const urlRegex = /url\(['"]?([^'")\s]+)['"]?\)/g;
242
+ let match;
243
+
244
+ while ((match = urlRegex.exec(scssContent)) !== null) {
245
+ const imgPath = match[1];
246
+ const filename = path.basename(imgPath, path.extname(imgPath));
247
+
248
+ // 해시 파일명 감지 (16자 이상 hex)
249
+ if (/^[0-9a-f]{16,}$/.test(filename)) {
250
+ errors.push({
251
+ priority: 'P1',
252
+ file: filePath,
253
+ type: 'hash-filename',
254
+ actual: imgPath,
255
+ message: `해시 파일명 금지: ${imgPath} → kebab-case로 변경 필요`
256
+ });
257
+ }
258
+ }
259
+
260
+ return errors;
261
+ }
262
+
263
+ // ─── Main ───────────────────────────────────────────────────────────
264
+
265
+ function main() {
266
+ const args = process.argv.slice(2);
267
+ if (args.length < 2) {
268
+ console.error('Usage: node figma-validate.js <scss-dir> <sections.json> [--section=<name>]');
269
+ process.exit(1);
270
+ }
271
+
272
+ const scssDir = args[0];
273
+ const sectionsFile = args[1];
274
+ let sectionFilter = '';
275
+
276
+ for (const arg of args.slice(2)) {
277
+ if (arg.startsWith('--section=')) sectionFilter = arg.slice(10);
278
+ }
279
+
280
+ // 입력 읽기
281
+ const data = JSON.parse(fs.readFileSync(sectionsFile, 'utf-8'));
282
+ let sections = data.sections || [];
283
+
284
+ if (sectionFilter) {
285
+ sections = sections.filter(s => s.name === sectionFilter);
286
+ }
287
+
288
+ const allErrors = [];
289
+
290
+ for (const section of sections) {
291
+ const sectionClass = section.name
292
+ .replace(/[^a-zA-Z0-9\s_-]/g, '')
293
+ .replace(/[\s_]+/g, '-')
294
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
295
+ .toLowerCase()
296
+ .replace(/-+/g, '-')
297
+ .replace(/^-|-$/g, '');
298
+
299
+ const scssFile = path.join(scssDir, `_${sectionClass}.scss`);
300
+ if (!fs.existsSync(scssFile)) {
301
+ allErrors.push({
302
+ priority: 'P1',
303
+ type: 'missing-file',
304
+ expected: scssFile,
305
+ message: `SCSS 파일 없음: ${scssFile}`
306
+ });
307
+ continue;
308
+ }
309
+
310
+ const scssContent = fs.readFileSync(scssFile, 'utf-8');
311
+
312
+ // 1. 금지 패턴 검사
313
+ allErrors.push(...detectForbidden(scssContent, scssFile));
314
+
315
+ // 2. 이미지 파일명 검사
316
+ allErrors.push(...checkImageFilenames(scssContent, scssFile));
317
+
318
+ // 3. CSS 값 대조
319
+ const scssBlocks = parseSCSS(scssContent);
320
+ const treeCSS = {};
321
+
322
+ // 루트 섹션 CSS
323
+ const rootSelector = `.${sectionClass}`;
324
+ if (section.css && Object.keys(section.css).length > 0) {
325
+ treeCSS[rootSelector] = {};
326
+ for (const [prop, value] of Object.entries(section.css)) {
327
+ if (!prop.startsWith('_')) treeCSS[rootSelector][camelToKebab(prop)] = String(value);
328
+ }
329
+ }
330
+
331
+ // 자식 CSS 재귀 수집
332
+ for (const child of (section.children || [])) {
333
+ collectCSSFromTree(child, sectionClass, '', treeCSS);
334
+ }
335
+
336
+ allErrors.push(...compareCSSValues(scssBlocks, treeCSS, scssFile));
337
+ }
338
+
339
+ // 결과 출력
340
+ const p1 = allErrors.filter(e => e.priority === 'P1').length;
341
+ const p2 = allErrors.filter(e => e.priority === 'P2').length;
342
+
343
+ const result = {
344
+ status: p1 === 0 ? 'PASS' : 'FAIL',
345
+ errors: allErrors,
346
+ summary: { p1, p2, total: allErrors.length }
347
+ };
348
+
349
+ console.log(JSON.stringify(result, null, 2));
350
+ process.exit(p1 > 0 ? 1 : 0);
351
+ }
352
+
353
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.9.1",
3
+ "version": "2.9.3",
4
4
  "description": "AI Coding Framework for Claude Code — 56 agents, 45 skills, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
@@ -178,4 +178,4 @@ The test generator reads this file and adds custom rules to the test suite.
178
178
  - `vibe init` → auto-detect and generate initial arch-guard tests
179
179
  - `vibe update` → refresh rules if directory structure changed
180
180
  - Pre-commit hook → run arch-guard tests before commit
181
- - `/vibe.review` → architecture-reviewer checks against arch-rules.json
181
+ - `vibe.review` (skill) → architecture-reviewer checks against arch-rules.json
@@ -107,6 +107,92 @@ Based on classification, build the appropriate artifact:
107
107
  4. If the capability is a test, verify it FAILS without the fix
108
108
  ```
109
109
 
110
+ **Termination branches:**
111
+ - ✅ **Capability prevents the failure** → Step 5 PERSIST
112
+ - ❌ **Capability does NOT prevent the failure** → Step 4.5 ESCALATE (re-diagnose or ask user)
113
+
114
+ ### Step 4.5: ESCALATE — When VERIFY Fails
115
+
116
+ > **Problem**: The built capability didn't actually prevent the failure. This usually means the initial diagnosis was wrong (picked `Tool` when it needed `Guardrail`), or the failure has multiple missing capabilities.
117
+ >
118
+ > **Do NOT silently proceed** — a sub-standard capability log pollutes `.claude/vibe/capabilities-log.md` and the failure will recur.
119
+
120
+ **Escalation loop:**
121
+
122
+ ```python
123
+ tried = [current_diagnosis.category] # e.g., ["Tool"]
124
+
125
+ while True:
126
+ # Re-diagnose excluding already-tried categories
127
+ next_diagnosis = diagnose(failure, exclude=tried)
128
+
129
+ if next_diagnosis is None:
130
+ # All 5 categories (Tool/Guardrail/Abstraction/Documentation/Feedback) exhausted
131
+ escalate_to_user(failure, tried)
132
+ break
133
+
134
+ if next_diagnosis.category in tried:
135
+ # Stuck: diagnose keeps returning the same category
136
+ escalate_to_user(failure, tried)
137
+ break
138
+
139
+ tried.append(next_diagnosis.category)
140
+ capability = build(next_diagnosis)
141
+
142
+ if verify(capability, failure):
143
+ persist(capability)
144
+ return # Success — go to Step 5
145
+
146
+ # Still failing — next iteration
147
+ ```
148
+
149
+ **User escalation prompt (interactive mode):**
150
+
151
+ ```
152
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
153
+ ⚠️ CAPABILITY LOOP STUCK
154
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
155
+
156
+ Failure: {original failure description}
157
+
158
+ Tried capabilities (all failed to prevent the failure):
159
+ ❌ Tool: {what was built, why it didn't work}
160
+ ❌ Guardrail: {what was built, why it didn't work}
161
+ ❌ Documentation: {what was built, why it didn't work}
162
+
163
+ Automated diagnosis has run out of angles. This failure may require
164
+ human judgment (process issue, cross-category solution, or external factor).
165
+
166
+ How would you like to proceed?
167
+ 1. Suggest a different angle (e.g., "this is a process issue", "needs Tool+Guardrail combination")
168
+ → Attempt custom approach per user instruction, then enter next verify
169
+ 2. "manual" — resolve this failure via manual intervention, end capability loop
170
+ (record "escalated to manual" in capabilities-log.md)
171
+ 3. "abort" — give up, record failure only
172
+ (record "diagnosis exhausted" in capabilities-log.md, do not halt the rest of the workflow)
173
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
174
+ ```
175
+
176
+ **ultrawork mode exception:**
177
+
178
+ ```python
179
+ if ultrawork_mode:
180
+ # Skip user prompt: try all 5 categories in sequence, record final state
181
+ all_tried_exhausted = exhaust_all_categories(failure, tried)
182
+ record_failure_to_log(
183
+ status="diagnosis_exhausted",
184
+ tried=all_tried_exhausted,
185
+ failure=failure
186
+ )
187
+ return # Proceed without blocking downstream workflow
188
+ ```
189
+
190
+ **Rollback of failed builds:**
191
+
192
+ - Each failed capability build should be rolled back before trying the next category (unless it's non-destructive documentation).
193
+ - For code additions (tool/guardrail/abstraction): `git checkout -- {files}` or delete created files.
194
+ - For docs-only additions: leave in place (low risk) but note in escalation prompt.
195
+
110
196
  ### Step 5: PERSIST — Record for Future Reference
111
197
 
112
198
  Save the capability-building decision:
@@ -126,11 +212,14 @@ Update `.claude/vibe/capabilities-log.md`:
126
212
  ```markdown
127
213
  ## {date} — {capability-name}
128
214
 
215
+ **Status**: resolved | escalated_to_manual | diagnosis_exhausted
129
216
  **Failure**: {what happened}
130
217
  **Missing**: {what capability was absent}
131
- **Built**: {what was created}
218
+ **Tried**: {list of categories attempted, e.g., [Tool, Guardrail]}
219
+ **Built**: {what was created (if resolved)}
132
220
  **Files**: {list}
133
- **Prevents**: {what class of failures this prevents}
221
+ **Prevents**: {what class of failures this prevents (if resolved)}
222
+ **Notes**: {for escalated/exhausted — what the user decided or what remains unsolved}
134
223
  ```
135
224
 
136
225
  ## Decision Tree
@@ -152,6 +241,21 @@ Agent failed
152
241
 
153
242
  └─ Did the agent not KNOW it was wrong?
154
243
  YES → Build feedback (types/errors/tests)
244
+
245
+
246
+ VERIFY: Does the built capability actually prevent the failure?
247
+
248
+ ├─ YES → PERSIST (log as "resolved")
249
+
250
+ └─ NO → ESCALATE (Step 4.5)
251
+
252
+ ├─ Other categories untried? → Re-diagnose with exclusion list
253
+ │ → BUILD next category → VERIFY
254
+
255
+ └─ All categories tried OR same diagnosis loops:
256
+
257
+ ├─ Interactive: Ask user (custom angle / manual / abort)
258
+ └─ ultrawork: Auto-record "diagnosis_exhausted" → continue
155
259
  ```
156
260
 
157
261
  ## Anti-patterns
@@ -1,86 +1,86 @@
1
1
  ---
2
2
  name: chub-usage
3
3
  tier: optional
4
- description: "Context Hub (chub) — 검수된 최신 API 문서 조회. 외부 API/SDK 코드 작성 training data 대신 최신 문서를 기반으로 정확한 코드 작성."
4
+ description: "Context Hub (chub) — fetch vetted, up-to-date API documentation. Write accurate code based on the latest docs instead of training data when working with external APIs/SDKs."
5
5
  triggers: [chub, context hub, API docs, latest API, deprecated API, SDK documentation, api reference, 최신 문서]
6
6
  priority: 65
7
7
  ---
8
8
 
9
9
  # Context Hub (chub) Usage
10
10
 
11
- 외부 API/SDK 코드 작성 검수된 최신 문서를 가져오는 스킬.
12
- Training data의 지식 컷오프 문제를 해결합니다.
11
+ A skill for fetching vetted, up-to-date documentation before writing external API/SDK code.
12
+ Solves the knowledge cutoff problem inherent in training data.
13
13
 
14
14
  ## Why?
15
15
 
16
16
  | Problem | Solution |
17
17
  |---------|----------|
18
- | Training data 의존 → deprecated API 사용 | chub get → 검수된 최신 문서 기반 코드 |
19
- | 검색노이즈 섞인 결과 | chub search → 큐레이션된 문서만 |
20
- | 세션마다 같은 실수 반복 | chub annotate → 학습 누적 |
18
+ | Relying on training data → using deprecated APIs | chub get → code based on vetted latest docs |
19
+ | Web searchnoisy results | chub search → curated docs only |
20
+ | Repeating the same mistakes every session | chub annotate → accumulated learnings |
21
21
 
22
22
  ## When to Use
23
23
 
24
24
  | Situation | Example |
25
25
  |-----------|---------|
26
- | 외부 API 코드 작성 | "Stripe 결제 연동해줘" |
27
- | SDK 최신 버전 확인 | "OpenAI 최신 모델 호출" |
28
- | 공식 문서 필요 | "Supabase auth 설정" |
29
- | Deprecated 패턴 방지 | "Firebase v10 마이그레이션" |
26
+ | Writing external API code | "Integrate Stripe payments" |
27
+ | Checking latest SDK version | "Call the latest OpenAI model" |
28
+ | Need official documentation | "Set up Supabase auth" |
29
+ | Preventing deprecated patterns | "Firebase v10 migration" |
30
30
 
31
31
  ## Workflow
32
32
 
33
33
  ```
34
- 외부 API/SDK 코드 작성 요청
34
+ Request to write external API/SDK code
35
35
 
36
- Step 0: chub 설치 확인 (없으면 자동 설치)
36
+ Step 0: Check if chub is installed (auto-install if not)
37
37
 
38
- Step 1: chub search "<라이브러리명>"
38
+ Step 1: chub search "<library name>"
39
39
 
40
40
  Step 2: chub get <id> --lang ts
41
41
 
42
- Step 3: 문서 기반 코드 작성
42
+ Step 3: Write code based on the docs
43
43
 
44
- Step 4: gotcha 발견 chub annotate
44
+ Step 4: chub annotate when a gotcha is discovered
45
45
  ```
46
46
 
47
- ## Step 0 — 자동 설치 (Auto-install)
47
+ ## Step 0 — Auto-install
48
48
 
49
- **스킬 실행 반드시 먼저 수행한다.**
49
+ **Always perform this step before running the skill.**
50
50
 
51
51
  ```bash
52
- # 1. chub 존재 여부 확인
52
+ # 1. Check if chub exists
53
53
  which chub || command -v chub
54
54
  ```
55
55
 
56
- chub 없으면 자동 설치를 시도한다:
56
+ If chub is not found, attempt automatic installation:
57
57
 
58
58
  ```bash
59
59
  npm install -g @aisuite/chub
60
60
  ```
61
61
 
62
- 설치 실패 `npx @aisuite/chub`로 대체 실행한다:
62
+ If installation fails, fall back to running via `npx @aisuite/chub`:
63
63
 
64
64
  ```bash
65
- # search 예시
65
+ # search example
66
66
  npx @aisuite/chub search "stripe"
67
- # get 예시
67
+ # get example
68
68
  npx @aisuite/chub get stripe/api --lang ts
69
69
  ```
70
70
 
71
- `npx`도 실패하면 context7 또는 Web Search 폴백한다 (Fallback Chain 참조).
71
+ If `npx` also fails, fall back to context7 or Web Search (see Fallback Chain).
72
72
 
73
73
  ## Usage
74
74
 
75
- ### Step 1 — 문서 검색
75
+ ### Step 1 — Search for docs
76
76
 
77
77
  ```bash
78
78
  chub search "stripe"
79
79
  chub search "openai"
80
- chub search "" # 전체 목록 확인
80
+ chub search "" # View full list
81
81
  ```
82
82
 
83
- ### Step 2 — 최신 문서 fetch
83
+ ### Step 2 — Fetch latest docs
84
84
 
85
85
  ```bash
86
86
  chub get stripe/api --lang ts
@@ -88,26 +88,26 @@ chub get openai/chat --lang py
88
88
  chub get supabase/auth --lang js
89
89
  ```
90
90
 
91
- ### Step 3 — 문서 기반 코드 작성
91
+ ### Step 3 — Write code based on the docs
92
92
 
93
- fetch한 문서 내용을 기반으로 정확한 코드 작성.
94
- **절대 training data 의존하지 않는다. 문서 먼저, 코드 나중.**
93
+ Write accurate code based on the fetched documentation.
94
+ **Never rely on training data. Docs first, code second.**
95
95
 
96
- ### Step 4 — 학습 내용 기록
96
+ ### Step 4 — Record learnings
97
97
 
98
- 작업 발견한 gotcha, workaround, 버전 이슈:
98
+ Gotchas, workarounds, and version issues discovered during work:
99
99
 
100
100
  ```bash
101
- chub annotate stripe/api "한국 결제는 pg 파라미터 필수"
102
- chub annotate openai/chat "streaming에서 tool_calls는 delta로 옴"
103
- chub annotate firebase/auth "v10에서 getAuth() import 경로 변경"
101
+ chub annotate stripe/api "pg parameter is required for Korean payments"
102
+ chub annotate openai/chat "tool_calls in streaming comes as delta"
103
+ chub annotate firebase/auth "getAuth() import path changed in v10"
104
104
  ```
105
105
 
106
- Annotation은 로컬 저장, 다음 세션에서 `chub get` 자동으로 같이 나옴.
106
+ Annotations are stored locally and automatically included the next time you run `chub get`.
107
107
 
108
108
  ## Implementation Pattern (Subagent)
109
109
 
110
- 컨텍스트 블로트 방지를 위해 서브에이전트에서 실행:
110
+ Run via subagent to prevent context bloat:
111
111
 
112
112
  ```
113
113
  Task tool call:
@@ -116,24 +116,24 @@ Task tool call:
116
116
  - 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."
117
117
  ```
118
118
 
119
- 서브에이전트가 chub 호출을 처리하고 요약만 반환 메인 컨텍스트 깨끗하게 유지.
119
+ The subagent handles the chub calls and returns only a summary keeping the main context clean.
120
120
 
121
121
  ## Supported APIs (1,000+)
122
122
 
123
- OpenAI, Anthropic, Stripe, Firebase, Supabase, Vercel, AWS S3, Cloudflare Workers, Auth0, Clerk 등.
123
+ OpenAI, Anthropic, Stripe, Firebase, Supabase, Vercel, AWS S3, Cloudflare Workers, Auth0, Clerk, and more.
124
124
 
125
125
  ```bash
126
- chub search # 인자 없이 실행하면 전체 목록 확인 가능
126
+ chub search # Run without arguments to view the full list
127
127
  ```
128
128
 
129
129
  ## Fallback Chain
130
130
 
131
131
  ```
132
- which chub 실패
132
+ which chub fails
133
133
 
134
- npm install -g @aisuite/chub (자동 시도)
134
+ npm install -g @aisuite/chub (auto attempt)
135
135
 
136
- 실패 npx @aisuite/chub <command> (임시 실행)
136
+ On failure: npx @aisuite/chub <command> (temporary execution)
137
137
 
138
- npx 실패 context7 또는 Web Search fallback
138
+ If npx also fails: context7 or Web Search fallback
139
139
  ```