@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.
- package/CLAUDE.md +16 -7
- package/README.en.md +29 -3
- package/README.md +29 -3
- package/dist/cli/auth.d.ts +0 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +1 -18
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/collaborator.d.ts +3 -3
- package/dist/cli/collaborator.js +4 -4
- package/dist/cli/collaborator.js.map +1 -1
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +0 -1
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/init.d.ts +3 -4
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +15 -20
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/remove.d.ts.map +1 -1
- package/dist/cli/commands/remove.js +2 -7
- package/dist/cli/commands/remove.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +10 -10
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/design/design-md-parser.d.ts +25 -0
- package/dist/cli/design/design-md-parser.d.ts.map +1 -0
- package/dist/cli/design/design-md-parser.js +86 -0
- package/dist/cli/design/design-md-parser.js.map +1 -0
- package/dist/cli/design/design-md-parser.test.d.ts +2 -0
- package/dist/cli/design/design-md-parser.test.d.ts.map +1 -0
- package/dist/cli/design/design-md-parser.test.js +149 -0
- package/dist/cli/design/design-md-parser.test.js.map +1 -0
- package/dist/cli/index.js +1 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/postinstall/constants.d.ts.map +1 -1
- package/dist/cli/postinstall/constants.js +12 -11
- package/dist/cli/postinstall/constants.js.map +1 -1
- package/dist/cli/postinstall/main.d.ts.map +1 -1
- package/dist/cli/postinstall/main.js +7 -14
- package/dist/cli/postinstall/main.js.map +1 -1
- package/dist/cli/setup/LegacyMigration.d.ts +3 -3
- package/dist/cli/setup/LegacyMigration.d.ts.map +1 -1
- package/dist/cli/setup/LegacyMigration.js +3 -5
- package/dist/cli/setup/LegacyMigration.js.map +1 -1
- package/dist/cli/setup/ProjectSetup.d.ts +18 -8
- package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
- package/dist/cli/setup/ProjectSetup.js +70 -19
- package/dist/cli/setup/ProjectSetup.js.map +1 -1
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/utils/cli-detector.d.ts +0 -7
- package/dist/cli/utils/cli-detector.d.ts.map +1 -1
- package/dist/cli/utils/cli-detector.js +0 -95
- package/dist/cli/utils/cli-detector.js.map +1 -1
- package/dist/cli/utils.d.ts +1 -1
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +1 -2
- package/dist/cli/utils.js.map +1 -1
- package/dist/infra/lib/memory/MemoryStorage.d.ts +1 -1
- package/dist/infra/lib/memory/MemoryStorage.d.ts.map +1 -1
- package/dist/infra/lib/memory/MemoryStorage.js +2 -3
- package/dist/infra/lib/memory/MemoryStorage.js.map +1 -1
- package/hooks/scripts/__tests__/pre-tool-guard.test.js +1 -1
- package/hooks/scripts/codex-notify.js +49 -0
- package/hooks/scripts/command-log.js +1 -1
- package/hooks/scripts/lib/dispatcher.js +2 -3
- package/hooks/scripts/lib/scope-from-spec.js +2 -4
- package/hooks/scripts/llm-orchestrate.js +2 -7
- package/hooks/scripts/prompt-dispatcher.js +3 -3
- package/hooks/scripts/utils.js +5 -10
- package/package.json +1 -1
- package/skills/docs/SKILL.md +3 -3
- package/skills/test/SKILL.md +8 -8
- package/skills/vibe/SKILL.md +24 -2
- package/skills/vibe.design/SKILL.md +183 -0
- package/skills/vibe.design/heuristics/code-extract.md +100 -0
- package/skills/vibe.design/references/README.md +39 -0
- package/skills/vibe.design/templates/DESIGN.md.template +100 -0
- package/skills/vibe.figma/SKILL.md +17 -1
- package/skills/vibe.review/SKILL.md +7 -0
- package/skills/vibe.run/SKILL.md +19 -0
- package/skills/vibe.test/SKILL.md +4 -4
- package/skills/vibe.verify/SKILL.md +20 -0
- 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
|
|
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
|
|
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
|
|
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.
|
|
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 ||
|
|
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 {
|
package/hooks/scripts/utils.js
CHANGED
|
@@ -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 ||
|
|
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/
|
|
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) `.
|
|
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) →
|
|
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
|
|
93
|
+
* 프로젝트 설정(.vibe/config.json) 읽기 — legacy `.claude/vibe/` fallback 포함
|
|
99
94
|
* @returns {object} 파싱된 config 또는 빈 객체
|
|
100
95
|
*/
|
|
101
96
|
export function readProjectConfig() {
|
package/package.json
CHANGED
package/skills/docs/SKILL.md
CHANGED
|
@@ -106,9 +106,9 @@ graph TD
|
|
|
106
106
|
| CLI | File | Support |
|
|
107
107
|
|---|---|---|
|
|
108
108
|
| Claude Code | `CLAUDE.md` | 100% (Primary) |
|
|
109
|
-
|
|
|
109
|
+
| Codex | `AGENTS.md` | 100% (Primary) |
|
|
110
110
|
|
|
111
|
-
Gemini CLI /
|
|
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`** (
|
|
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
|
|
package/skills/test/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test
|
|
3
|
-
description: vibe 자가검진 본체 — 대상 harness(~/.claude/~/.
|
|
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
|
|
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/`,
|
|
23
|
+
| (empty) | current harness — CC: `~/.claude/`, Codex: `~/.codex/` |
|
|
24
24
|
| `cc` | `~/.claude/` |
|
|
25
|
-
| `
|
|
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
|
-
~/.
|
|
31
|
-
To install:
|
|
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` / `
|
|
122
|
-
2. **Resolve install dir**: `cc` → `~/.claude`, `
|
|
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.
|
package/skills/vibe/SKILL.md
CHANGED
|
@@ -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 ↔
|
|
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
|
-
|
|
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) 로 보강
|