@su-record/vibe 2.10.0 → 2.11.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 (85) hide show
  1. package/CLAUDE.md +16 -7
  2. package/README.en.md +29 -3
  3. package/README.md +29 -3
  4. package/dist/cli/auth.d.ts +0 -1
  5. package/dist/cli/auth.d.ts.map +1 -1
  6. package/dist/cli/auth.js +1 -18
  7. package/dist/cli/auth.js.map +1 -1
  8. package/dist/cli/collaborator.d.ts +3 -3
  9. package/dist/cli/collaborator.js +4 -4
  10. package/dist/cli/collaborator.js.map +1 -1
  11. package/dist/cli/commands/info.d.ts.map +1 -1
  12. package/dist/cli/commands/info.js +0 -1
  13. package/dist/cli/commands/info.js.map +1 -1
  14. package/dist/cli/commands/init.d.ts +3 -4
  15. package/dist/cli/commands/init.d.ts.map +1 -1
  16. package/dist/cli/commands/init.js +15 -20
  17. package/dist/cli/commands/init.js.map +1 -1
  18. package/dist/cli/commands/remove.d.ts.map +1 -1
  19. package/dist/cli/commands/remove.js +2 -7
  20. package/dist/cli/commands/remove.js.map +1 -1
  21. package/dist/cli/commands/update.d.ts.map +1 -1
  22. package/dist/cli/commands/update.js +10 -10
  23. package/dist/cli/commands/update.js.map +1 -1
  24. package/dist/cli/design/design-md-parser.d.ts +25 -0
  25. package/dist/cli/design/design-md-parser.d.ts.map +1 -0
  26. package/dist/cli/design/design-md-parser.js +86 -0
  27. package/dist/cli/design/design-md-parser.js.map +1 -0
  28. package/dist/cli/design/design-md-parser.test.d.ts +2 -0
  29. package/dist/cli/design/design-md-parser.test.d.ts.map +1 -0
  30. package/dist/cli/design/design-md-parser.test.js +149 -0
  31. package/dist/cli/design/design-md-parser.test.js.map +1 -0
  32. package/dist/cli/index.js +1 -3
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  35. package/dist/cli/postinstall/constants.js +12 -11
  36. package/dist/cli/postinstall/constants.js.map +1 -1
  37. package/dist/cli/postinstall/main.d.ts.map +1 -1
  38. package/dist/cli/postinstall/main.js +7 -14
  39. package/dist/cli/postinstall/main.js.map +1 -1
  40. package/dist/cli/setup/LegacyMigration.d.ts +3 -3
  41. package/dist/cli/setup/LegacyMigration.d.ts.map +1 -1
  42. package/dist/cli/setup/LegacyMigration.js +3 -5
  43. package/dist/cli/setup/LegacyMigration.js.map +1 -1
  44. package/dist/cli/setup/ProjectSetup.d.ts +18 -8
  45. package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
  46. package/dist/cli/setup/ProjectSetup.js +70 -19
  47. package/dist/cli/setup/ProjectSetup.js.map +1 -1
  48. package/dist/cli/setup.d.ts +1 -1
  49. package/dist/cli/setup.d.ts.map +1 -1
  50. package/dist/cli/setup.js +1 -1
  51. package/dist/cli/setup.js.map +1 -1
  52. package/dist/cli/utils/cli-detector.d.ts +0 -7
  53. package/dist/cli/utils/cli-detector.d.ts.map +1 -1
  54. package/dist/cli/utils/cli-detector.js +0 -95
  55. package/dist/cli/utils/cli-detector.js.map +1 -1
  56. package/dist/cli/utils.d.ts +1 -1
  57. package/dist/cli/utils.d.ts.map +1 -1
  58. package/dist/cli/utils.js +1 -2
  59. package/dist/cli/utils.js.map +1 -1
  60. package/dist/infra/lib/memory/MemoryStorage.d.ts +1 -1
  61. package/dist/infra/lib/memory/MemoryStorage.d.ts.map +1 -1
  62. package/dist/infra/lib/memory/MemoryStorage.js +2 -3
  63. package/dist/infra/lib/memory/MemoryStorage.js.map +1 -1
  64. package/hooks/scripts/__tests__/pre-tool-guard.test.js +1 -1
  65. package/hooks/scripts/codex-notify.js +49 -0
  66. package/hooks/scripts/command-log.js +1 -1
  67. package/hooks/scripts/lib/dispatcher.js +2 -3
  68. package/hooks/scripts/lib/scope-from-spec.js +2 -4
  69. package/hooks/scripts/llm-orchestrate.js +2 -7
  70. package/hooks/scripts/prompt-dispatcher.js +3 -3
  71. package/hooks/scripts/utils.js +5 -10
  72. package/package.json +1 -1
  73. package/skills/docs/SKILL.md +3 -3
  74. package/skills/test/SKILL.md +8 -8
  75. package/skills/vibe/SKILL.md +24 -2
  76. package/skills/vibe.design/SKILL.md +183 -0
  77. package/skills/vibe.design/heuristics/code-extract.md +100 -0
  78. package/skills/vibe.design/references/README.md +39 -0
  79. package/skills/vibe.design/templates/DESIGN.md.template +100 -0
  80. package/skills/vibe.figma/SKILL.md +17 -1
  81. package/skills/vibe.review/SKILL.md +7 -0
  82. package/skills/vibe.run/SKILL.md +19 -0
  83. package/skills/vibe.test/SKILL.md +4 -4
  84. package/skills/vibe.verify/SKILL.md +20 -0
  85. package/vibe/rules/principles/dual-harness-doctrine.md +50 -0
@@ -112,7 +112,6 @@ function resolveModel(providerName, config) {
112
112
  *
113
113
  * true인 경우:
114
114
  * - vibe-codex: ANTHROPIC_BASE_URL이 localhost (프록시 모드)
115
- * - coco: ~/.coco/ 존재 또는 COCO_HOME 설정
116
115
  * - 명시적: VIBE_SECONDARY_LLM=claude
117
116
  */
118
117
  function useClaudeAsSecondary() {
@@ -121,10 +120,6 @@ function useClaudeAsSecondary() {
121
120
  // 2. vibe-codex 프록시 모드
122
121
  const baseUrl = process.env.ANTHROPIC_BASE_URL || '';
123
122
  if (baseUrl.includes('localhost') || baseUrl.includes('127.0.0.1')) return true;
124
- // 3. coco 환경
125
- if (process.env.COCO_HOME) return true;
126
- const cocoDir = path.join(os.homedir(), '.coco');
127
- if (fs.existsSync(cocoDir)) return true;
128
123
  return false;
129
124
  }
130
125
 
@@ -601,10 +596,10 @@ async function main() {
601
596
  // 명시적 claude 호출
602
597
  providerChain = ['claude', 'gemini'];
603
598
  } else if (isGpt) {
604
- // GPT 주관 → claude fallback (vibe-codex/coco), gemini fallback (직접 모드)
599
+ // GPT 주관 → claude fallback (vibe-codex), gemini fallback (직접 모드)
605
600
  providerChain = claudeSecondary ? [provider, 'claude'] : [provider, 'gemini'];
606
601
  } else {
607
- // gemini 주관 → claude fallback (vibe-codex/coco), gpt fallback (직접 모드)
602
+ // gemini 주관 → claude fallback (vibe-codex), gpt fallback (직접 모드)
608
603
  providerChain = claudeSecondary ? ['gemini', 'claude'] : ['gemini', 'gpt'];
609
604
  }
610
605
 
@@ -42,11 +42,11 @@ try {
42
42
 
43
43
  if (!prompt) process.exit(0);
44
44
 
45
- // 레거시 SSOT 통합 — `/vibe.*` 진입 시 `.claude/vibe/`·`.coco/vibe/` → `.vibe/` 자동 이동.
45
+ // 레거시 SSOT 통합 — `/vibe.*` 진입 시 `.claude/vibe/` → `.vibe/` 자동 이동.
46
46
  // `vibe init`/`update` 와 동일한 `consolidateLegacyVibe` (dist/cli/setup/LegacyMigration.js) 를 직접 재사용. Idempotent.
47
47
  if (/^\s*\/vibe\b/i.test(prompt)) {
48
48
  try {
49
- const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.COCO_PROJECT_DIR || process.cwd();
49
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
50
50
  const utils = await import('./utils.js');
51
51
  const CLI_BASE = utils.getCliBaseUrl();
52
52
  const { consolidateLegacyVibe } = await import(`${CLI_BASE}setup/LegacyMigration.js`);
@@ -183,7 +183,7 @@ if (!matched) {
183
183
  setImmediate(async () => {
184
184
  try {
185
185
  const utils = await import('./utils.js');
186
- const projectDir = process.env.CLAUDE_PROJECT_DIR || process.env.COCO_PROJECT_DIR || '.';
186
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || '.';
187
187
  const configPath = utils.projectVibePath(projectDir, 'config.json');
188
188
  let gapEnabled = true;
189
189
  try {
@@ -17,7 +17,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
17
  const DETECTED_VIBE_PATH = path.resolve(__dirname, '..', '..');
18
18
 
19
19
  export const VIBE_PATH = process.env.VIBE_PATH || DETECTED_VIBE_PATH;
20
- export const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.env.COCO_PROJECT_DIR || '.';
20
+ export const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || '.';
21
21
 
22
22
  // ~/.vibe/ 디렉토리 경로
23
23
  const VIBE_HOME_DIR = path.join(os.homedir(), '.vibe');
@@ -25,16 +25,14 @@ const VIBE_HOME_DIR = path.join(os.homedir(), '.vibe');
25
25
  /**
26
26
  * 프로젝트 내 Vibe 에셋 루트 해석.
27
27
  *
28
- * 신규 SSOT: `<project>/.vibe/` — CLI(Claude/coco)와 무관한 공용 디렉토리.
28
+ * 신규 SSOT: `<project>/.vibe/` — CLI(Claude/Codex)와 무관한 공용 디렉토리.
29
29
  * Legacy fallback:
30
30
  * - `<project>/.claude/vibe/` (Claude Code 프로젝트 초기화 흔적)
31
- * - `<project>/.coco/vibe/` (coco 프로젝트 초기화 흔적)
32
31
  *
33
32
  * 해석 규칙 — **읽기**(lookup) 시:
34
33
  * 1) `.vibe/` 가 존재하면 그 경로
35
34
  * 2) `.claude/vibe/` 가 존재하면 그 경로
36
- * 3) `.coco/vibe/` 존재하면 그 경로
37
- * 4) 아무것도 없으면 기본값 `.vibe/` (생성 대상)
35
+ * 3) 아무것도 없으면 기본값 `.vibe/` (생성 대상)
38
36
  *
39
37
  * **쓰기**(write) 시에는 항상 새 SSOT 인 `.vibe/` 로 수렴시키는 것이 원칙이지만,
40
38
  * 기존 프로젝트의 legacy 파일이 있으면 해당 위치에 쓰는 것이 덜 파괴적이다.
@@ -48,8 +46,6 @@ export function projectVibeRoot(projectDir = PROJECT_DIR) {
48
46
  if (fs.existsSync(vibeRoot)) return vibeRoot;
49
47
  const claudeVibe = path.join(projectDir, '.claude', 'vibe');
50
48
  if (fs.existsSync(claudeVibe)) return claudeVibe;
51
- const cocoVibe = path.join(projectDir, '.coco', 'vibe');
52
- if (fs.existsSync(cocoVibe)) return cocoVibe;
53
49
  } catch { /* ignore */ }
54
50
  return path.join(projectDir, '.vibe');
55
51
  }
@@ -66,14 +62,13 @@ export function projectVibePath(projectDir = PROJECT_DIR, ...sub) {
66
62
 
67
63
  /**
68
64
  * 프로젝트 메모리 DB 디렉토리 해석.
69
- * `.vibe/memories/` (신규) → `.claude/memories/` (legacy Claude) → `.coco/memories/` (legacy coco) → 기본 `.vibe/memories/`
65
+ * `.vibe/memories/` (신규) → `.claude/memories/` (legacy Claude) → 기본 `.vibe/memories/`
70
66
  */
71
67
  export function projectMemoryDir(projectDir = PROJECT_DIR) {
72
68
  try {
73
69
  const candidates = [
74
70
  path.join(projectDir, '.vibe', 'memories'),
75
71
  path.join(projectDir, '.claude', 'memories'),
76
- path.join(projectDir, '.coco', 'memories'),
77
72
  ];
78
73
  for (const c of candidates) if (fs.existsSync(c)) return c;
79
74
  } catch { /* ignore */ }
@@ -95,7 +90,7 @@ export function readVibeConfig() {
95
90
  }
96
91
 
97
92
  /**
98
- * 프로젝트 설정(.vibe/config.json) 읽기 — legacy `.claude/vibe/`, `.coco/vibe/` fallback 포함
93
+ * 프로젝트 설정(.vibe/config.json) 읽기 — legacy `.claude/vibe/` fallback 포함
99
94
  * @returns {object} 파싱된 config 또는 빈 객체
100
95
  */
101
96
  export function readProjectConfig() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
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",
@@ -106,9 +106,9 @@ graph TD
106
106
  | CLI | File | Support |
107
107
  |---|---|---|
108
108
  | Claude Code | `CLAUDE.md` | 100% (Primary) |
109
- | coco | `AGENTS.md` | 100% (Primary) |
109
+ | Codex | `AGENTS.md` | 100% (Primary) |
110
110
 
111
- Gemini CLI / Codex CLI / Cursor are not supported — do not generate or check `GEMINI.md`.
111
+ Gemini CLI / Cursor are not supported — do not generate or check `GEMINI.md`.
112
112
 
113
113
  **Source of truth:**
114
114
  - **`CLAUDE.md` is the content SSOT.** Always edit it first; `AGENTS.md` is a regenerated derivative.
@@ -120,7 +120,7 @@ Gemini CLI / Codex CLI / Cursor are not supported — do not generate or check `
120
120
  2. **For `AGENTS.md`**:
121
121
  - **If missing** → create by cloning `CLAUDE.md` + applying CLI substitution (below).
122
122
  - **If exists** → regenerate from current `CLAUDE.md` + substitution, preserving user-specific additions outside the VIBE block.
123
- 3. **CLI substitution for `AGENTS.md`** (coco): `Claude Code` → `coco` · `~/.claude/` → `~/.coco/` · `.claude/` → `.coco/` · `CLAUDE.md` → `AGENTS.md`. `CLAUDE.md` itself gets no substitution.
123
+ 3. **CLI substitution for `AGENTS.md`** (Codex): `Claude Code` → `Codex` · `~/.claude/` → `~/.codex/` · `.claude/` → `.codex/` · `CLAUDE.md` → `AGENTS.md`. `CLAUDE.md` itself gets no substitution.
124
124
  4. **Validate every touched file (whether newly created or modified)** via the `claude-md-guide` → `agents-md` skill chain — see validation block below. **Never write or save without running this step.**
125
125
  5. Report per file: created / updated / skipped / validation warnings.
126
126
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: test
3
- description: vibe 자가검진 본체 — 대상 harness(~/.claude/~/.coco)의 모든 command/skill/hook/agent 프로빙 → pass/fail 리포트 → ~/.vibe/test-reports/.
3
+ description: vibe 자가검진 본체 — 대상 harness(~/.claude/~/.codex)의 모든 command/skill/hook/agent 프로빙 → pass/fail 리포트 → ~/.vibe/test-reports/.
4
4
  when_to_use: /vibe.test 진입점에서 체인 호출. 직접 호출 금지.
5
5
  user-invocable: false
6
6
  tier: core
@@ -12,7 +12,7 @@ Probe every shipped vibe surface in one install dir and emit a pass/fail report.
12
12
 
13
13
  ## Why this exists
14
14
 
15
- When vibe ships new commands, skills, hooks, or agents, one side (CC or coco) can end up out of sync with the other, frontmatter can drift, and hook tests can silently break. `/vibe.test` is the single mechanical check: does every surface in the target install actually load and pass its own tests?
15
+ When vibe ships new commands, skills, hooks, or agents, one side (CC or Codex) can end up out of sync with the other, frontmatter can drift, and hook tests can silently break. `/vibe.test` is the single mechanical check: does every surface in the target install actually load and pass its own tests?
16
16
 
17
17
  ## Target harness
18
18
 
@@ -20,15 +20,15 @@ The argument selects which install dir to probe:
20
20
 
21
21
  | Arg | Probed dir |
22
22
  |---|---|
23
- | (empty) | current harness — CC: `~/.claude/`, coco: `~/.coco/` |
23
+ | (empty) | current harness — CC: `~/.claude/`, Codex: `~/.codex/` |
24
24
  | `cc` | `~/.claude/` |
25
- | `coco` | `~/.coco/` |
25
+ | `codex` | `~/.codex/` |
26
26
 
27
27
  If the target dir does not exist, print a clear message and exit with guidance (not an error). Example:
28
28
 
29
29
  ```
30
- ~/.coco/ not found — coco isn't installed on this machine.
31
- To install: pnpm add -g @su-record/vibe-coco
30
+ ~/.codex/ not found — Codex isn't installed on this machine.
31
+ To install: npm i -g @openai/codex
32
32
  ```
33
33
 
34
34
  ## Probes
@@ -118,8 +118,8 @@ If `failed` is empty, replace the Failures section with `_All probes passed._`.
118
118
 
119
119
  ## Steps
120
120
 
121
- 1. **Resolve target**: argument (`cc` / `coco` / empty). Empty → detect current harness (`$CLAUDE_PROJECT_DIR` set → `cc`; else fall back to `cc`).
122
- 2. **Resolve install dir**: `cc` → `~/.claude`, `coco` → `~/.coco`. If missing → print guidance + exit.
121
+ 1. **Resolve target**: argument (`cc` / `codex` / empty). Empty → detect current harness (`$CLAUDE_PROJECT_DIR` set → `cc`; else fall back to `cc`).
122
+ 2. **Resolve install dir**: `cc` → `~/.claude`, `codex` → `~/.codex`. If missing → print guidance + exit.
123
123
  3. **Read `vibe_version`** from `package.json` in the current repo.
124
124
  4. **Walk each category**, run its check, append `{ name, status, error? }` to `probes.<category>`.
125
125
  5. **Compute** `summary` counts and the flat `failed[]` list.
@@ -26,6 +26,8 @@ user-invocable: true
26
26
 
27
27
  - **단일 슬래시 진입점**: `/vibe` 하나로 모든 워크플로 시작. 다른 `/vibe.*` 도 그대로 존재하지만 power user 가 명시적으로 phase 호출하고 싶을 때 쓰는 advanced 경로.
28
28
  - **동적 파이프라인**: 의도/입력 종류에 따라 매번 다른 스킬 체인 구성. 미리 정해진 고정 흐름 아님.
29
+ - **무제한 라우팅**: 라우팅 표는 빠른 경로일 뿐 닫힌 화이트리스트가 아니다. 설치된 모든 `vibe.*` 스킬이 라우팅 후보이며, 표에 없는 요구사항도 description 기반 의미 매칭으로 처리한다 (Catch-all).
30
+ - **하네스 정규화 (추론 앞단)**: vibe는 CC(추론)·Codex(직역) 어느 하네스의 암묵적 동작에도 의존하지 않는다. `/vibe`가 모호한 NL을 **명시적·직역 가능한 지시로 먼저 전개**하고, 하위 skill은 모호한 입력을 받지 않는다. 이로써 모든 하네스에서 동일 결과 + CC급 편의를 제공한다. 전문: `vibe/rules/principles/dual-harness-doctrine.md`.
29
31
  - **Smart Resume**: `.vibe/{interviews,plans,specs,features}/` 감지하여 "이어서 진행?" 자동 제안.
30
32
  - **1회 승인 게이트**: 파이프라인을 설계해서 사용자에게 보여주고 OK 받은 뒤 실행. `ultrawork` 키워드 있으면 skip.
31
33
  - **위임자 역할**: `/vibe` 본인은 코드를 직접 쓰지 않는다. 라우팅·설계·실행 위임만 한다.
@@ -61,12 +63,26 @@ user-invocable: true
61
63
  | **scaffold** | "프로젝트 만들기", "셋업", "초기 구조" | scaffold |
62
64
  | **docs sync** | "문서 갱신", "README", "AGENTS.md" | docs |
63
65
  | **analyze** | "분석", "조사", "이건 뭐야" + 파일/URL | analyze |
66
+ | **reason** | "추론", "깊게 생각", "트레이드오프", "어떻게 접근" 등 복잡한 사고 요청 | reason |
67
+ | **event** | "이벤트", "커뮤니티", "D-Day", "행사 자동화" | event |
64
68
  | **harness check** | "하네스", "환경 점검" | harness |
65
- | **test self** | "vibe 테스트", "CC ↔ coco 비교" | test |
69
+ | **test self** | "vibe 테스트", "CC ↔ Codex 비교" | test |
66
70
  | **utils** | "이어서", "메모리", "체크포인트" | utils |
67
71
 
68
72
  복수 의도면 우선순위: resume > figma-driven > new feature > 기타.
69
73
 
74
+ > **⚠️ 위 표는 닫힌 화이트리스트가 아니라 "흔한 케이스 빠른 경로"다.** 표에 없는 요구사항이라도 막지 말고 **Catch-all 라우팅**(아래)으로 처리한다.
75
+
76
+ ### Catch-all 라우팅 (표에 없는 의도)
77
+
78
+ 입력이 위 표 어느 행과도 명확히 매칭되지 않으면:
79
+
80
+ 1. **의미 매칭**: 사용 가능한 모든 `vibe.*` 스킬의 `description` 을 읽어 요구사항과 의미적으로 가장 가까운 스킬을 고른다. (표는 참고용일 뿐, 실제 라우팅 후보는 설치된 전체 `vibe.*`)
81
+ 2. **복합 설계**: 단일 스킬로 안 되면 여러 스킬을 조합한 파이프라인을 동적으로 설계한다.
82
+ 3. **되묻기는 최후**: 어떤 스킬과도 매칭이 안 될 때만 사용자에게 "어떤 작업인지" 명확화 질문을 한다.
83
+
84
+ > 새 `vibe.*` 스킬이 추가되어 위 표에 행이 없더라도, Catch-all 이 description 기반으로 자동 라우팅하므로 기능이 막히지 않는다. 표 누락 = 기능 제한이 되어선 안 된다.
85
+
70
86
  ### Phase 2: Smart Resume 감지
71
87
 
72
88
  ```
@@ -91,7 +107,13 @@ user-invocable: true
91
107
 
92
108
  ### Phase 3: 파이프라인 설계
93
109
 
94
- 분류된 의도 + resume 상태 + magic keyword 를 종합해 실행 계획 작성:
110
+ **먼저 입력을 정규화한다 (하네스 무관 명시화):**
111
+
112
+ - **예시·placeholder 표기**: 사용자가 설명용으로 던진 예시 텍스트를 실데이터로 넘기지 않는다. `<예시>`, `[채워넣을 값]` 로 명시. (직역 하네스가 그대로 데이터로 쓰는 것 방지)
113
+ - **research 명시**: 조사가 필요하면 파이프라인에 명시적 탐색 단계를 넣는다. planning mode 같은 하네스 스위치에 의존하지 않는다.
114
+ - **도메인 지식 흡수**: 사용자가 준 라이브러리·함수·파일 위치를 SPEC 입력으로 전달한다.
115
+
116
+ 이어서 분류된 의도 + resume 상태 + magic keyword 를 종합해 실행 계획 작성:
95
117
 
96
118
  ```
97
119
  📋 Pipeline Plan
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: vibe.design
3
+ description: DESIGN.md(시각 품질 SSOT) 생성·검증·드리프트 검사·동기화. Figma 독립.
4
+ argument-hint: "init [--from=interview|code|reference|figma] | lint | verify | sync"
5
+ user-invocable: true
6
+ ---
7
+
8
+ # /vibe.design
9
+
10
+ **vibe 의 세 번째 SSOT — 시각 품질 계약 문서(`DESIGN.md`)** 의 라이프사이클을 전담한다.
11
+
12
+ > `CLAUDE.md`(코드) · `AGENTS.md`(빌드) 에 이은 시각 규약. **Figma 에 종속되지 않는다** — Figma 는 4 가지 입력 소스 중 하나.
13
+
14
+ ## Usage
15
+
16
+ ```
17
+ /vibe.design init # 인터뷰 (디폴트)
18
+ /vibe.design init --from=interview # 대화형 9 섹션 작성
19
+ /vibe.design init --from=code # 기존 코드 토큰 역추출
20
+ /vibe.design init --from=reference --reference=linear # awesome-design-md 시드 선택
21
+ /vibe.design init --from=figma --file=<key> # /vibe.figma 위임 (옵션)
22
+ /vibe.design lint # Stitch 9 섹션 완전성 검증
23
+ /vibe.design verify [--files=<glob>] # 구현 ↔ DESIGN.md hex 드리프트 (v1)
24
+ /vibe.design sync # Figma 연결 시 양방향 동기화 (Should, Phase 2)
25
+ ```
26
+
27
+ ## Philosophy
28
+
29
+ - **Figma 독립**: 모든 서브커맨드는 Figma 없이 동작. Figma 연결 시에만 sync 활성.
30
+ - **권유 > 강제**: DESIGN.md 부재 = 안내 메시지 1 회. `/vibe.run` · `/vibe.verify` 는 막지 않는다.
31
+ - **Stitch 9 섹션 표준**: 외부 에이전트 호환 (Google Stitch, awesome-design-md 생태계).
32
+ - **버전 frontmatter**: `<!-- design-md-version: 1 -->` 로 미래 호환.
33
+ - **루트 배치**: `CLAUDE.md` · `AGENTS.md` 와 동일하게 프로젝트 루트.
34
+
35
+ ## Process
36
+
37
+ > **⏱️ Timer**: 시작 시 `getCurrentTime` 호출, `{start_time}` 으로 기록.
38
+
39
+ ### Subcommand: `init`
40
+
41
+ **진입 조건**: 프로젝트 루트에 `DESIGN.md` 없음 (있으면 덮어쓰기 확인).
42
+
43
+ **경로 결정**:
44
+
45
+ | `--from` | 동작 |
46
+ |---------|------|
47
+ | 미지정 / `interview` | 대화형 9 섹션 인터뷰 (디폴트) |
48
+ | `code` | 기존 코드에서 토큰 역추출 → 인터뷰 보강 |
49
+ | `reference` | `--reference=<slug>` 로 시드 카탈로그 선택 → §1·§2·§3 시드 + §4–§9 단축 인터뷰 |
50
+ | `figma` | `/vibe.figma --emit-design-md` 위임 (Figma MCP 필요) |
51
+
52
+ **공통 출력**:
53
+ - 위치: `<프로젝트 루트>/DESIGN.md`
54
+ - 첫 줄: `<!-- design-md-version: 1 -->`
55
+ - 9 H2 섹션 (Visual Theme / Color Palette / Typography / Components / Layout / Depth / Do's & Don'ts / Responsive / Agent Prompt Guide)
56
+ - 템플릿: `templates/DESIGN.md.template`
57
+
58
+ #### `--from=interview` 흐름
59
+
60
+ 1. 사용자가 9 섹션을 순차 답변 (브랜드 톤, 컬러, 폰트, 컴포넌트 스타일, 그리드, 그림자/뎁스, 금기, 브레이크포인트, 에이전트 가이드)
61
+ 2. 빈 섹션은 템플릿 기본값(주석) 으로 채움
62
+ 3. `DESIGN.md` 저장 + `lint` 자동 실행 → P1 없으면 성공
63
+
64
+ #### `--from=code` 흐름
65
+
66
+ 1. `.vibe/config.json` 의 `stacks[].type` 으로 추출기 결정 (`heuristics/code-extract.md`)
67
+ 2. v1 필수 패턴: **Tailwind config / CSS custom properties / styled-components theme**
68
+ 3. 추출된 토큰을 §2·§3·§4 시드로 사용
69
+ 4. 나머지 6 섹션은 단축 인터뷰 (≤3 질문) 또는 템플릿 기본값
70
+
71
+ #### `--from=reference` 흐름
72
+
73
+ 1. `references/README.md` 시드 카탈로그에서 `--reference=<slug>` 매칭 (`linear`, `vercel`, `stripe` …)
74
+ 2. 시드의 `style-preset` 한 줄 (예: `"minimal, neutral grays + electric purple accent, Inter Display"`) 로 §1·§2·§3 기본값 채움
75
+ 3. §4–§9 는 단축 인터뷰 (≤3 질문)
76
+ 4. 네트워크 차단 환경에서도 동작 (시드는 로컬 시드)
77
+
78
+ #### `--from=figma` 흐름
79
+
80
+ 1. `/vibe.figma --emit-design-md --file=<key>` 호출 (위임)
81
+ 2. 산출물(`DESIGN.md`) 받아서 lint 통과 확인
82
+
83
+ ### Subcommand: `lint`
84
+
85
+ **입력**: 프로젝트 루트 `DESIGN.md`
86
+
87
+ **체크**:
88
+ - 9 섹션 모두 존재 (`lintMissingSections` from `design-md-parser.ts`)
89
+ - frontmatter 버전 주석 존재
90
+ - §2 (Color Palette) 에 최소 1 개 hex 토큰
91
+ - §9 (Agent Prompt Guide) 비어있지 않음
92
+
93
+ **출력**:
94
+ ```
95
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
96
+ ✅ DESIGN.md lint PASS
97
+ 9 sections, 12 color tokens, version 1
98
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
99
+ ```
100
+
101
+ 또는:
102
+
103
+ ```
104
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
105
+ ❌ DESIGN.md lint FAIL (P1: 2)
106
+ Missing: Typography, Responsive
107
+ → Run /vibe.design init to regenerate, or edit DESIGN.md
108
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
109
+ ```
110
+
111
+ **성능 목표**: <200ms (100 줄 DESIGN.md 기준).
112
+
113
+ ### Subcommand: `verify`
114
+
115
+ **입력**:
116
+ - 프로젝트 루트 `DESIGN.md` (없으면 안내 후 종료)
117
+ - `--files=<glob>` (기본: 최근 변경 파일 — `/vibe.verify` 의 changed-files 정책 따름)
118
+
119
+ **체크 (v1 범위)**:
120
+ - `extractHexTokens(DESIGN.md)` → 허용 토큰 셋
121
+ - `findHardcodedColors(files, allowed)` → 허용 셋 밖 hex = P1 후보
122
+
123
+ **v1 비범위** (Phase 2+):
124
+ - spacing / font-family 드리프트
125
+ - HSL/RGB/named color
126
+ - Tailwind arbitrary value `bg-[#xxxxxx]`
127
+
128
+ **출력**:
129
+ ```
130
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
131
+ ✅ DESIGN.md verify PASS (32 files scanned)
132
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
133
+ ```
134
+
135
+ 또는:
136
+
137
+ ```
138
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
139
+ ❌ DESIGN.md verify FAIL (P1: 3 hex drifts)
140
+ src/Button.tsx:42 #FF5733 not in DESIGN.md tokens
141
+ src/Card.tsx:18 #123456 not in DESIGN.md tokens
142
+ src/Nav.tsx:7 #ABCDEF not in DESIGN.md tokens
143
+ → Add to DESIGN.md §2 Color Palette, or replace with token
144
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
145
+ ```
146
+
147
+ **성능 목표**: <1s / 100 파일.
148
+
149
+ ### Subcommand: `sync` (Should, Phase 2)
150
+
151
+ **진입 조건**: `~/.vibe/config.json#figma.token` 존재 + `--file=<key>` 또는 프로젝트에 figma 연결 메타.
152
+
153
+ **v1 동작**: "Phase 2 에서 활성됩니다. 현재는 `/vibe.figma --emit-design-md` 를 사용하세요." 메시지 후 종료.
154
+
155
+ ## Integration
156
+
157
+ | Skill | 통합 지점 |
158
+ |------|---------|
159
+ | `/vibe.run` | UI 스택 진입 시 `DESIGN.md` 없으면 `### DESIGN.md Gate` 에서 권유 (ultrawork 시 silent skip) |
160
+ | `/vibe.verify` | `### 3.2 Visual Drift Detection` 에서 `vibe.design verify` 호출 — P1 → fail |
161
+ | `/vibe.review` | `### Phase 2.5 Visual P1 Baseline` 에서 DESIGN.md 우선, 없으면 WCAG AA 폴백 |
162
+ | `/vibe.figma` | WRITE 는 DESIGN.md 읽어 톤·팔레트 우선, READ 는 `--emit-design-md` 플래그로 출력 |
163
+
164
+ ## Figma Credential Handling (init/sync only)
165
+
166
+ - 토큰 출처: `~/.vibe/config.json#figma.token` (chmod 0o600)
167
+ - 메모리 외 노출 금지. 로그에는 마지막 4 자만 노출 (`****abc1`)
168
+ - `--from=figma` · `sync` 외 서브커맨드는 토큰 읽지 않음
169
+
170
+ ## Output
171
+
172
+ | 파일 | 생성/수정 |
173
+ |-----|---------|
174
+ | `<root>/DESIGN.md` | `init` / `sync` |
175
+ | 콘솔 리포트 | `lint` / `verify` |
176
+
177
+ ## Heuristics & References
178
+
179
+ - 코드 역추출 패턴: `heuristics/code-extract.md`
180
+ - 시드 카탈로그: `references/README.md`
181
+ - 템플릿: `templates/DESIGN.md.template`
182
+
183
+ ARGUMENTS: $ARGUMENTS
@@ -0,0 +1,100 @@
1
+ # vibe.design — Code Extract Heuristics
2
+
3
+ `/vibe.design init --from=code` 가 기존 코드에서 시각 토큰을 역추출할 때 따르는 패턴.
4
+
5
+ ## v1 Required Patterns
6
+
7
+ v1 에서 **반드시 동작**해야 하는 추출기 (테스트 픽스처 보장):
8
+
9
+ ### 1. Tailwind config
10
+
11
+ 대상: `tailwind.config.{ts,js,cjs,mjs}` · `tailwind.config.*` · `app.config.ts` (Nuxt)
12
+
13
+ ```ts
14
+ // tailwind.config.ts
15
+ export default {
16
+ theme: {
17
+ extend: {
18
+ colors: {
19
+ primary: '#5E6AD2',
20
+ accent: '#10B981',
21
+ },
22
+ fontFamily: {
23
+ sans: ['Inter', 'system-ui'],
24
+ },
25
+ spacing: { '18': '4.5rem' },
26
+ },
27
+ },
28
+ };
29
+ ```
30
+
31
+ 추출 결과:
32
+ - `§2 Color Palette` ← `theme.extend.colors.*`
33
+ - `§3 Typography` ← `theme.extend.fontFamily.*`
34
+ - `§5 Layout spacing scale` ← `theme.extend.spacing.*`
35
+
36
+ ### 2. CSS custom properties (CSS variables)
37
+
38
+ 대상: `**/*.css` · `**/*.scss` 의 `:root { --... }`
39
+
40
+ ```css
41
+ :root {
42
+ --color-primary: #5E6AD2;
43
+ --color-bg: #FFFFFF;
44
+ --font-sans: 'Inter', sans-serif;
45
+ --space-md: 16px;
46
+ }
47
+ ```
48
+
49
+ 추출 결과:
50
+ - `--color-*` → `§2 Color Palette` (semantic 이름 유지)
51
+ - `--font-*` → `§3 Typography`
52
+ - `--space-*` · `--size-*` → `§5 Layout`
53
+ - `--shadow-*` · `--elevation-*` → `§6 Depth`
54
+
55
+ ### 3. styled-components theme
56
+
57
+ 대상: `**/theme.{ts,tsx,js}` · `ThemeProvider` 의 `theme={...}`
58
+
59
+ ```ts
60
+ export const theme = {
61
+ colors: { primary: '#5E6AD2', bg: '#FFFFFF' },
62
+ typography: { fontFamily: 'Inter, sans-serif' },
63
+ spacing: [4, 8, 16, 24, 32],
64
+ };
65
+ ```
66
+
67
+ 추출 결과: 위 CSS-vars 와 동일 매핑.
68
+
69
+ ## Documented-only Patterns (v1 비범위, Phase 2+)
70
+
71
+ 문서로만 정리. 실제 추출기는 Phase 2 에서 구현.
72
+
73
+ | 패턴 | 위치 | Phase 2 계획 |
74
+ |-----|------|------------|
75
+ | PostCSS custom properties | `postcss.config.*` + `@custom-media` | Tailwind 추출기 확장 |
76
+ | SCSS variables | `**/*.scss` 의 `$variable` | CSS-vars 추출기 확장 |
77
+ | Emotion theme | `@emotion/react` ThemeProvider | styled-components 추출기 확장 |
78
+ | Vanilla Extract | `*.css.ts` `createTheme` | 신규 추출기 |
79
+ | Panda CSS / Linaria | `panda.config.ts` / `*.linaria.ts` | 신규 추출기 |
80
+ | Flutter ThemeData | `theme.dart` | 모바일 트랙 (Phase 3) |
81
+ | iOS asset catalog | `*.xcassets/Colors.xcassets` | 모바일 트랙 (Phase 3) |
82
+ | Android styles.xml | `res/values/colors.xml` | 모바일 트랙 (Phase 3) |
83
+
84
+ ## Stack 매핑
85
+
86
+ `.vibe/config.json#stacks[].type` 으로 추출기 선택:
87
+
88
+ | Stack | v1 활성 추출기 |
89
+ |------|--------------|
90
+ | `typescript-react` / `typescript-nextjs` | Tailwind + CSS-vars + styled-components |
91
+ | `typescript-vue` / `typescript-nuxt` | Tailwind + CSS-vars |
92
+ | `typescript-svelte` / `typescript-astro` | Tailwind + CSS-vars |
93
+ | `typescript-angular` | CSS-vars (Tailwind 옵션) |
94
+ | `typescript-react-native` | styled-components (Theme 객체) |
95
+ | `dart-flutter` · `swift-ios` · `kotlin-android` | (Phase 3 — 문서만) |
96
+
97
+ ## Fallback
98
+
99
+ 추출 실패 또는 토큰 0 개 → 인터뷰 모드로 자동 폴백 (`--from=interview` 처럼 동작).
100
+ 사용자에게 한 줄 안내: "코드에서 토큰을 찾지 못해 인터뷰로 전환합니다."
@@ -0,0 +1,39 @@
1
+ # vibe.design — Reference Seeds
2
+
3
+ `awesome-design-md` 생태계에서 추출한 **로컬 시드 카탈로그**. 네트워크 없이도
4
+ `/vibe.design init --from=reference --reference=<slug>` 으로 §1·§2·§3 기본값을 시드한다.
5
+
6
+ 각 시드의 `style-preset` 컬럼은 한 문장으로 시각 무드를 요약하며, init 시 §1 Visual
7
+ Theme + §2 Color Palette 의 primary/accent + §3 Typography family 의 기본값으로 변환된다.
8
+ 나머지 §4–§9 는 단축 인터뷰(≤3 질문) 로 채운다.
9
+
10
+ ## Catalog
11
+
12
+ | Slug | Style Preset | 주된 무드 |
13
+ |------|--------------|----------|
14
+ | `linear` | minimal, neutral grays + electric purple accent (#5E6AD2), Inter Display | 도구·정확·조용 |
15
+ | `vercel` | mono-light, pure black/white + zinc neutrals, Geist Sans | 미니멀·기술 |
16
+ | `stripe` | clean white + indigo accent (#635BFF), Sohne / Inter | 신뢰·전문 |
17
+ | `notion` | warm off-white (#FBFBFA) + charcoal text, system serif + sans | 따뜻·문서 |
18
+ | `github` | crisp white/dark + GitHub blue (#0969DA), system-ui | 개발자·정보밀도 |
19
+ | `apple` | premium white + space gray, SF Pro / system | 프리미엄·여백 |
20
+ | `figma` | dark canvas + multi-color accents, Inter | 창의·툴링 |
21
+ | `tailwind` | white + sky/cyan accent (#06B6D4), Inter | 유틸·교육 |
22
+ | `posthog` | playful peach + dark navy, Matter SQ | 친근·실험 |
23
+ | `supabase` | dark + emerald accent (#3ECF8E), Custom Sans | 모던·DB |
24
+ | `arc` | iridescent gradients + soft pastels, Inter Display | 미래·브라우저 |
25
+ | `clerk` | white + purple/violet accent, Inter | 인증·SaaS |
26
+
27
+ ## Adding a new seed
28
+
29
+ 1. 카탈로그 표에 한 줄 추가 (slug · style-preset · 무드)
30
+ 2. `style-preset` 은 한 문장: `<intensity>, <palette>, <font family>`
31
+ 3. 라이선스: 시드는 시각 규약 텍스트만 보유 (브랜드 로고/이미지 미포함)
32
+
33
+ ## How `init --from=reference` uses these
34
+
35
+ 1. `--reference=<slug>` 매칭 → `style-preset` 추출
36
+ 2. `style-preset` 의 palette 토큰 → `DESIGN.md §2 Color Palette` 의 primary/accent 시드
37
+ 3. font family → `§3 Typography` 의 Family 시드
38
+ 4. intensity 문구 → `§1 Visual Theme` 의 한 문단 초안
39
+ 5. `§4–§9` 는 단축 인터뷰 (컴포넌트 radius, spacing scale, breakpoints) 로 보강