oh-my-design-cli 0.1.3 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/post-edit-watch.cjs +99 -0
- package/.claude/hooks/session-end-foldin.cjs +96 -0
- package/.claude/hooks/session-state-loader.cjs +64 -0
- package/.claude/hooks/skill-activation.cjs +75 -0
- package/.claude/settings.json +55 -0
- package/AGENTS.md +111 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +76 -203
- package/README.zh-TW.md +1 -1
- package/agents/AGENT.md +53 -0
- package/agents/omd-3d-blender.md +269 -0
- package/agents/omd-a11y-auditor.md +97 -0
- package/agents/omd-asset-curator.md +260 -0
- package/agents/omd-critic.md +181 -0
- package/agents/omd-master.md +548 -0
- package/agents/omd-microcopy.md +63 -0
- package/agents/omd-persona-tester.md +118 -0
- package/agents/omd-ui-junior.md +129 -0
- package/agents/omd-ux-engineer.md +265 -0
- package/agents/omd-ux-researcher.md +62 -0
- package/agents/omd-ux-writer.md +181 -0
- package/data/opt-out-corpus.json +141 -0
- package/data/reference-fingerprints.json +1495 -0
- package/dist/bin/oh-my-design.js +3 -818
- package/dist/bin/oh-my-design.js.map +1 -1
- package/dist/install-skills-GQPTQF5S.js +420 -0
- package/dist/install-skills-GQPTQF5S.js.map +1 -0
- package/package.json +22 -21
- package/scripts/context.cjs +91 -0
- package/scripts/postinstall.cjs +54 -0
- package/skills/omd-apply/SKILL.md +64 -53
- package/skills/omd-harness/SKILL.md +271 -0
- package/skills/omd-init/SKILL.md +1 -1
- package/skills/omd-learn/SKILL.md +56 -36
- package/skills/omd-remember/SKILL.md +94 -16
- package/skills/omd-sync/SKILL.md +141 -17
- package/dist/chunk-6YNSV3VY.js +0 -35
- package/dist/chunk-6YNSV3VY.js.map +0 -1
- package/dist/chunk-MHFYGZSO.js +0 -337
- package/dist/chunk-MHFYGZSO.js.map +0 -1
- package/dist/chunk-N2JG6N4Q.js +0 -264
- package/dist/chunk-N2JG6N4Q.js.map +0 -1
- package/dist/chunk-OOQQEUGX.js +0 -46
- package/dist/chunk-OOQQEUGX.js.map +0 -1
- package/dist/chunk-OR5DHENY.js +0 -250
- package/dist/chunk-OR5DHENY.js.map +0 -1
- package/dist/customizer-CM76752R.js +0 -8
- package/dist/customizer-CM76752R.js.map +0 -1
- package/dist/index.d.ts +0 -559
- package/dist/index.js +0 -3113
- package/dist/index.js.map +0 -1
- package/dist/init-UMM4XIV5.js +0 -675
- package/dist/init-UMM4XIV5.js.map +0 -1
- package/dist/install-skills-CM6VXFZJ.js +0 -152
- package/dist/install-skills-CM6VXFZJ.js.map +0 -1
- package/dist/learn-33LHKEJA.js +0 -140
- package/dist/learn-33LHKEJA.js.map +0 -1
- package/dist/reference-YMNAOXJQ.js +0 -47
- package/dist/reference-YMNAOXJQ.js.map +0 -1
- package/dist/reference-parser-TM3CJPNE.js +0 -10
- package/dist/reference-parser-TM3CJPNE.js.map +0 -1
- package/dist/remember-UAFA5B2O.js +0 -78
- package/dist/remember-UAFA5B2O.js.map +0 -1
- package/dist/sync-FDYRKNFE.js +0 -417
- package/dist/sync-FDYRKNFE.js.map +0 -1
- package/dist/templates/templates/design-md.hbs +0 -44
- package/dist/templates/templates/partials/agent-prompt-guide.hbs +0 -28
- package/dist/templates/templates/partials/color-palette.hbs +0 -49
- package/dist/templates/templates/partials/component-stylings.hbs +0 -28
- package/dist/templates/templates/partials/depth-elevation.hbs +0 -31
- package/dist/templates/templates/partials/dos-donts.hbs +0 -13
- package/dist/templates/templates/partials/layout.hbs +0 -30
- package/dist/templates/templates/partials/responsive.hbs +0 -25
- package/dist/templates/templates/partials/shadcn-tokens.hbs +0 -64
- package/dist/templates/templates/partials/typography.hbs +0 -43
- package/dist/templates/templates/partials/visual-theme.hbs +0 -26
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: omd:learn
|
|
3
|
-
description: "
|
|
3
|
+
description: ".omd/preferences.md의 status:pending 항목을 DESIGN.md에 정식 merge하고 status를 applied로 플립. '프리퍼런스 정리해줘', 'fold preferences', 'apply all corrections', 「好みをDESIGN.mdに反映」, 「套用偏好」류의 요청에 트리거. 단발성 교정 기록은 omd:remember."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# omd:learn — Preference Fold into DESIGN.md
|
|
7
7
|
|
|
8
|
-
`.omd/preferences.md`에 누적된 `status: pending` 교정사항을 DESIGN.md에 반영하고, 반영된 엔트리의 상태를 `applied`로 플립한다.
|
|
8
|
+
`.omd/preferences.md`에 누적된 `status: pending` 교정사항을 DESIGN.md에 반영하고, 반영된 엔트리의 상태를 `applied`로 플립한다. **CLI 호출 없음** — Read/Edit 툴로 직접 처리.
|
|
9
9
|
|
|
10
10
|
## Phase 1 — 검토
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
`Read .omd/preferences.md` → frontmatter + 엔트리들 파싱:
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
omd
|
|
16
|
-
|
|
14
|
+
- 엔트리 분리: `## ` heading 기준 split
|
|
15
|
+
- 각 엔트리의 `omd-meta` 코드블록에서 `id`, `scope`, `status` 추출
|
|
16
|
+
- `status: pending`만 필터
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
scope별로 그룹화해서 사용자에게 요약:
|
|
19
19
|
|
|
20
|
-
예시 출력 형식:
|
|
21
20
|
```
|
|
22
21
|
components.button (3 pending):
|
|
23
22
|
- CTAs never uppercase (pref_xxx, pref_yyy)
|
|
@@ -27,55 +26,76 @@ spacing (1 pending):
|
|
|
27
26
|
- 8pt grid, not 4pt (pref_aaa)
|
|
28
27
|
```
|
|
29
28
|
|
|
29
|
+
엔트리당 한 줄이 아니라 **scope당 2-3줄로 의도 정리**.
|
|
30
|
+
|
|
30
31
|
## Phase 2 — 사용자 확인
|
|
31
32
|
|
|
32
|
-
"이 교정들을 DESIGN.md에 반영할까요?"
|
|
33
|
+
"이 교정들을 DESIGN.md에 반영할까요?" 묻기. 동의 → Phase 3.
|
|
34
|
+
|
|
35
|
+
거부 → 어떤 scope를 reject할지 묻고 Phase 4 reject 분기로.
|
|
33
36
|
|
|
34
|
-
## Phase 3 — 적용
|
|
37
|
+
## Phase 3 — DESIGN.md 적용
|
|
35
38
|
|
|
36
|
-
1.
|
|
37
|
-
2. scope별로 묶어서 **하나의 coherent edit
|
|
38
|
-
3. Edit 툴로 DESIGN.md의 해당
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
1. `Read DESIGN.md` 로드
|
|
40
|
+
2. scope별로 묶어서 **하나의 coherent edit** 생성 (엔트리당 하나가 아니라 한 scope의 교정들을 종합)
|
|
41
|
+
3. Edit 툴로 DESIGN.md의 해당 섹션 수정:
|
|
42
|
+
- `components.button` → DESIGN.md §8 (Components → Button) 또는 §13 (Components 상세)
|
|
43
|
+
- `color` → §2 (Color Palette)
|
|
44
|
+
- `typography` → §3
|
|
45
|
+
- `spacing` → §4 (Spacing scale)
|
|
46
|
+
- `voice` → §10 (Voice & Tone)
|
|
47
|
+
- `motion` → §15 (Motion & Easing)
|
|
48
|
+
- `visualTheme` → §1 (Visual Theme)
|
|
49
|
+
4. **voice/내러티브 수정 시 DESIGN.md의 기존 문체 preserve** — 교정 내용만 반영, 문장 스타일/길이/톤 유지
|
|
50
|
+
5. **§10-15 (Brand Philosophy 레이어)는 reference voice 보존이 우선** — preference가 §10-15 본문 자체를 다시 쓰라고 하지 않는 한 본문은 건드리지 않고 §1-9의 axes만 수정
|
|
44
51
|
|
|
45
52
|
## Phase 4 — 상태 플립
|
|
46
53
|
|
|
47
|
-
반영한
|
|
54
|
+
반영한 엔트리: 해당 엔트리의 omd-meta 블록을 Edit 툴로:
|
|
55
|
+
- `status: pending` → `status: applied`
|
|
56
|
+
- `applied_at: <ISO timestamp>` 라인 추가
|
|
57
|
+
- (선택) `applied_design_md_hash: <DESIGN.md sha256>` 추가. hash 계산:
|
|
58
|
+
```bash
|
|
59
|
+
node -e "console.log(require('crypto').createHash('sha256').update(require('fs').readFileSync('DESIGN.md')).digest('hex').slice(0,12))"
|
|
60
|
+
```
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
거부한 엔트리:
|
|
63
|
+
- `status: pending` → `status: rejected`
|
|
64
|
+
- `rejected_reason: "<짧은 이유>"` 라인 추가
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
omd learn --mark-rejected <pref_id> --reason "<짧은 이유>"
|
|
57
|
-
```
|
|
66
|
+
상위 엔트리가 누적된 작은 교정을 통합·대체했으면:
|
|
67
|
+
- 작은 엔트리들은 `status: superseded`
|
|
68
|
+
- `superseded_by: <상위 pref_id>` 추가
|
|
58
69
|
|
|
59
70
|
## Phase 5 — 결과 요약
|
|
60
71
|
|
|
61
|
-
한
|
|
72
|
+
한 문단:
|
|
62
73
|
- 반영된 교정 수 (scope별)
|
|
63
74
|
- 거부된 교정 수 + 이유
|
|
64
|
-
- 사용자에게 `.omd/preferences.md` 직접 확인
|
|
75
|
+
- 사용자에게 `.omd/preferences.md` 직접 확인 안내
|
|
65
76
|
|
|
66
|
-
예시:
|
|
67
77
|
```
|
|
68
|
-
|
|
78
|
+
4 preferences applied to DESIGN.md
|
|
69
79
|
- components.button: CTAs never uppercase, primary brand-500
|
|
70
80
|
- spacing: 8pt grid
|
|
71
|
-
|
|
81
|
+
1 rejected (conflicts with base reference radius)
|
|
72
82
|
|
|
73
83
|
Review .omd/preferences.md for details.
|
|
74
84
|
```
|
|
75
85
|
|
|
86
|
+
## 옵션 패턴
|
|
87
|
+
|
|
88
|
+
사용자가 특정 작업만 요청하는 경우:
|
|
89
|
+
|
|
90
|
+
- **"pending만 보여줘"** → Phase 1만, Phase 2-5 생략
|
|
91
|
+
- **"X scope만 반영"** → 해당 scope만 Phase 3에서 처리
|
|
92
|
+
- **"<pref_id>를 applied로 표시"** → Phase 4의 single-entry 플립만
|
|
93
|
+
- **"<pref_id>를 rejected로 표시 + 이유"** → 동일
|
|
94
|
+
|
|
76
95
|
## 금지
|
|
77
96
|
|
|
78
|
-
- LLM으로 엔트리별 개별 diff를 생성하지 말 것 — scope별 합쳐서 하나의 coherent edit
|
|
79
|
-
- DESIGN.md의 section
|
|
80
|
-
- 교정과 관계없는 부분을 "개선"하지 말
|
|
81
|
-
- pending을 건너뛰지 말 것 — 모든 pending에
|
|
97
|
+
- LLM으로 엔트리별 개별 diff를 생성하지 말 것 — scope별 합쳐서 하나의 coherent edit
|
|
98
|
+
- DESIGN.md의 section heading 계층을 바꾸지 말 것
|
|
99
|
+
- 교정과 관계없는 부분을 "개선"하지 말 것
|
|
100
|
+
- pending을 건너뛰지 말 것 — 모든 pending에 applied/rejected/superseded 중 하나로 플립
|
|
101
|
+
- omd-meta 블록 외부 (body) 수정 금지 — 교정 본문은 영구 기록
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: omd:remember
|
|
3
|
-
description: "디자인
|
|
3
|
+
description: "사용자의 디자인 선호·교정을 .omd/preferences.md에 기록. '이거 기억해줘', '앞으로는 이렇게', 'remember this', 'going forward never X', 「覚えておいて」, 「記住這個」류의 발화 또는 omd:apply가 교정을 감지했을 때 트리거. 기록된 내용은 omd:learn으로 DESIGN.md에 정식 반영."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# omd:remember — Preference Logger
|
|
7
7
|
|
|
8
|
-
사용자의 디자인 선호/교정을 `.omd/preferences.md`에 append-only로 기록한다. 나중에 `omd:learn`이 배치로 DESIGN.md에 반영.
|
|
8
|
+
사용자의 디자인 선호/교정을 `.omd/preferences.md`에 append-only로 기록한다. 나중에 `omd:learn`이 배치로 DESIGN.md에 반영. **CLI 호출 없음** — Read/Edit/Write 툴로 직접 처리.
|
|
9
9
|
|
|
10
10
|
## 트리거 발화 패턴
|
|
11
11
|
|
|
@@ -15,30 +15,108 @@ description: "디자인 선호/교정을 .omd/preferences.md 에 append합니다
|
|
|
15
15
|
- "rule of thumb: ..."
|
|
16
16
|
- 사용자가 당신의 디자인 선택을 명시적으로 교정
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## 파일 포맷 (`.omd/preferences.md`)
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
frontmatter + 엔트리 시퀀스. 엔트리 하나당 `## <heading>` + `omd-meta` 코드블록 + body.
|
|
21
21
|
|
|
22
|
+
```
|
|
23
|
+
---
|
|
24
|
+
schema: omd.preferences/v1
|
|
25
|
+
design_md_hash_at_creation: <hash 또는 빈 문자열>
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Preference Log
|
|
29
|
+
|
|
30
|
+
## 2026-04-30T17:48:00.000Z — ctas-never-uppercase
|
|
31
|
+
|
|
32
|
+
```omd-meta
|
|
33
|
+
id: pref_lqxk2_a3f9c1d4
|
|
34
|
+
timestamp: 2026-04-30T17:48:00.000Z
|
|
35
|
+
scope: components.button
|
|
36
|
+
signal: user-statement
|
|
37
|
+
confidence: explicit
|
|
38
|
+
status: pending
|
|
39
|
+
source_agent: claude-code
|
|
40
|
+
source_context: "src/components/Button.tsx"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
CTAs are never uppercase
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 실행 절차
|
|
47
|
+
|
|
48
|
+
### Step 1 — note 정규화
|
|
49
|
+
사용자 발화를 한 문장 영문으로 요약 (예: "앞으로 CTA 대문자 쓰지마" → `CTAs are never uppercase`).
|
|
50
|
+
|
|
51
|
+
### Step 2 — scope 추론
|
|
52
|
+
note 내용에서 다음 매핑 우선순위 사용:
|
|
53
|
+
|
|
54
|
+
| 매칭 키워드 (정규식, case-i) | scope |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `\b(buttons?\|ctas?\|btns?)\b` | `components.button` |
|
|
57
|
+
| `\b(cards?)\b` | `components.card` |
|
|
58
|
+
| `\b(dialogs?\|modals?)\b` | `components.dialog` |
|
|
59
|
+
| `\b(inputs?\|fields?\|forms?)\b` | `components.input` |
|
|
60
|
+
| `\b(nav\|navigation\|headers?\|menus?)\b` | `components.navigation` |
|
|
61
|
+
| `\b(badges?\|chips?\|pills?\|tags?)\b` | `components.badge` |
|
|
62
|
+
| `\b(tables?\|rows?\|cells?)\b` | `components.table` |
|
|
63
|
+
| `\b(dropdowns?\|selects?\|comboboxes?)\b` | `components.dropdown` |
|
|
64
|
+
| `\b(toasts?\|notifications?\|snackbars?)\b` | `components.toast` |
|
|
65
|
+
| `\b(tabs?)\b` | `components.tabs` |
|
|
66
|
+
| `\b(colors?\|palette\|hex\|hue\|saturation\|shades?\|tints?\|gradients?)\b` | `color` |
|
|
67
|
+
| `\b(font\|typography\|typeface\|weight\|leading\|tracking\|letter-?spacing)\b` | `typography` |
|
|
68
|
+
| `\b(spacing\|gap\|padding\|margin\|grid)\b` | `spacing` |
|
|
69
|
+
| `\b(voice\|tone\|copy\|microcopy\|wording\|language)\b` | `voice` |
|
|
70
|
+
| `\b(motion\|animation\|transition\|easing\|duration)\b` | `motion` |
|
|
71
|
+
| `\b(layout\|structure\|hierarchy)\b` | `layout` |
|
|
72
|
+
| `\b(theme\|aesthetic\|vibe\|mood\|look\|feel)\b` | `visualTheme` |
|
|
73
|
+
| (어느 것도 매칭 X) | `visualTheme` |
|
|
74
|
+
|
|
75
|
+
사용자가 명시적으로 scope를 지정했으면 그대로 사용.
|
|
76
|
+
|
|
77
|
+
### Step 3 — id 생성
|
|
78
|
+
형식: `pref_<base36 timestamp>_<8 hex chars>`. Bash로 한 줄:
|
|
22
79
|
```bash
|
|
23
|
-
|
|
80
|
+
node -e "console.log('pref_' + Date.now().toString(36) + '_' + require('crypto').randomBytes(4).toString('hex'))"
|
|
24
81
|
```
|
|
25
82
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
83
|
+
### Step 4 — slug + heading
|
|
84
|
+
```bash
|
|
85
|
+
node -e "console.log(process.argv[1].toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,'').slice(0,40) || 'entry')" "<note>"
|
|
86
|
+
```
|
|
87
|
+
heading: `<ISO timestamp> — <slug>`
|
|
88
|
+
|
|
89
|
+
### Step 5 — 파일 read/append
|
|
90
|
+
1. `Read .omd/preferences.md` — 없으면 frontmatter+header부터 만든다:
|
|
91
|
+
```
|
|
92
|
+
---
|
|
93
|
+
schema: omd.preferences/v1
|
|
94
|
+
design_md_hash_at_creation:
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
# Preference Log
|
|
30
98
|
|
|
31
|
-
|
|
99
|
+
```
|
|
100
|
+
2. 새 엔트리 블록을 **파일 끝에 append** (Edit 툴, old_string은 마지막 라인, new_string은 마지막 라인 + 빈 줄 + 새 엔트리). 또는 Write로 전체 재작성.
|
|
101
|
+
3. 메타 필드:
|
|
102
|
+
- `id`, `timestamp`, `scope` (필수)
|
|
103
|
+
- `signal: user-statement` (디폴트, 사용자가 직접 발화한 경우) 또는 `user-correction` (사용자가 당신의 선택을 교정한 경우)
|
|
104
|
+
- `confidence: explicit` (디폴트, 사용자가 명시적으로 말한 경우) 또는 `inferred` (당신이 사용자 행동에서 추론한 경우)
|
|
105
|
+
- `status: pending` (모든 새 엔트리)
|
|
106
|
+
- `source_agent`: 환경에서 추론 (`claude-code` / `codex` / `opencode` / `cursor`)
|
|
107
|
+
- `source_context`: 관련 파일 경로 또는 PR번호 (있으면 JSON.stringify로 quote)
|
|
32
108
|
|
|
33
|
-
|
|
109
|
+
### Step 6 — 응답
|
|
110
|
+
간결한 한 줄: `Logged ${id} to .omd/preferences.md (scope: ${scope})`
|
|
34
111
|
|
|
35
112
|
## omd:apply 스킬과의 관계
|
|
36
113
|
|
|
37
|
-
- **자동 감지**: 일반 UI 작업 중
|
|
38
|
-
- **명시적 호출**:
|
|
114
|
+
- **자동 감지**: 일반 UI 작업 중 교정 발생 시 `omd:apply`가 이 스킬 트리거
|
|
115
|
+
- **명시적 호출**: 디자인 원칙 선언만 할 때 직접 트리거
|
|
39
116
|
|
|
40
117
|
## 금지
|
|
41
118
|
|
|
42
|
-
- `.omd/preferences.md` 파일을 직접
|
|
43
|
-
- 같은
|
|
44
|
-
- 사용자에게 "기록할까요?" 묻지 말 것 — 감지 즉시 기록 + 간결
|
|
119
|
+
- `.omd/preferences.md` 파일을 frontmatter 외 직접 손대지 말 것 (id 충돌 방지) — 항상 위 절차로
|
|
120
|
+
- 같은 세션 내 동일 내용 중복 기록 금지
|
|
121
|
+
- 사용자에게 "기록할까요?" 묻지 말 것 — 감지 즉시 기록 + 간결 알림
|
|
122
|
+
- frontmatter의 `design_md_hash_at_creation`은 첫 생성 시에만 채움 (이후 절대 수정 X)
|
package/skills/omd-sync/SKILL.md
CHANGED
|
@@ -1,38 +1,162 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: omd:sync
|
|
3
|
-
description: "DESIGN.md
|
|
3
|
+
description: "DESIGN.md 변경분을 CLAUDE.md / AGENTS.md / .cursor/rules/omd-design.mdc shim 3종에 전파. 'shim 갱신', 'drift 확인', 'ship', 'publish', 「shimを更新」, 「同步 CLAUDE.md」류의 요청에 트리거. DESIGN.md가 수정됐는데 shim이 오래됐을 때 자동 감지해 제안하기도 함."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# omd:sync — Shim Maintenance
|
|
7
7
|
|
|
8
|
-
DESIGN.md가 모든 주요 AI 코딩 에이전트
|
|
8
|
+
DESIGN.md가 모든 주요 AI 코딩 에이전트(Claude Code, Codex, OpenCode, Cursor)에게 보이도록 shim 파일 3종을 관리한다. **CLI 호출 없음** — Read/Write/Edit 툴로 직접 처리.
|
|
9
9
|
|
|
10
|
-
## 관리 대상
|
|
10
|
+
## 관리 대상 (3 파일)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
| ID | 경로 | 모드 |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `claude` | `CLAUDE.md` | block (managed marker만) |
|
|
15
|
+
| `agents` | `AGENTS.md` | block (managed marker만) |
|
|
16
|
+
| `cursor` | `.cursor/rules/omd-design.mdc` | whole (전체 파일이 omd 전용) |
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
block 모드는 `<!-- omd:start v=1 hash=<sha256:12> -->` ~ `<!-- omd:end -->` 마커 안만 관리, 나머지 사용자 콘텐츠 보존. whole 모드는 frontmatter 포함 전체 파일이 관리 단위.
|
|
17
19
|
|
|
18
|
-
##
|
|
20
|
+
## 템플릿 (정확히 이 본문 — 절대 paraphrase 금지)
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
### CLAUDE.md body
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
# Design System (oh-my-design)
|
|
26
|
+
|
|
27
|
+
The authoritative brand & UI spec is **@./DESIGN.md**.
|
|
28
|
+
Read before any UI/styling/microcopy/motion work.
|
|
29
|
+
|
|
30
|
+
Preference log (pending corrections): @./.omd/preferences.md
|
|
31
|
+
|
|
32
|
+
Precedence: DESIGN.md > preferences.md > your defaults.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### AGENTS.md body
|
|
36
|
+
|
|
37
|
+
```markdown
|
|
38
|
+
## Design System (oh-my-design)
|
|
39
|
+
|
|
40
|
+
**Before any UI, styling, copy, or motion change, open and read `./DESIGN.md` in full.** It is the authoritative brand/design spec. Treat its tokens, voice, and component rules as binding unless the user overrides in chat.
|
|
41
|
+
|
|
42
|
+
If present, read `./.omd/preferences.md` — pending corrections not yet folded into DESIGN.md. Apply them; flag conflicts.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### .cursor/rules/omd-design.mdc (whole, frontmatter 포함)
|
|
46
|
+
|
|
47
|
+
```mdc
|
|
48
|
+
---
|
|
49
|
+
description: Authoritative brand & UI design system. Read DESIGN.md before UI work.
|
|
50
|
+
globs:
|
|
51
|
+
- "**/*.tsx"
|
|
52
|
+
- "**/*.jsx"
|
|
53
|
+
- "**/*.vue"
|
|
54
|
+
- "**/*.svelte"
|
|
55
|
+
- "**/*.css"
|
|
56
|
+
- "**/*.scss"
|
|
57
|
+
- "**/tailwind.config.*"
|
|
58
|
+
- "**/components/**"
|
|
59
|
+
- "**/app/**/page.*"
|
|
60
|
+
alwaysApply: false
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<!-- omd:start v=1 hash=<HASH> -->
|
|
64
|
+
The authoritative design spec lives at `@DESIGN.md` (repo root). Open and read before generating/modifying UI.
|
|
65
|
+
|
|
66
|
+
Pending preference corrections: `@.omd/preferences.md`.
|
|
67
|
+
|
|
68
|
+
Precedence: DESIGN.md > preferences.md > framework defaults.
|
|
69
|
+
<!-- omd:end -->
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 해시 계산
|
|
73
|
+
|
|
74
|
+
`<HASH>` = sha256 of the body content (마커 제외, body 텍스트만), 12자 hex prefix:
|
|
21
75
|
|
|
22
76
|
```bash
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
77
|
+
node -e "console.log(require('crypto').createHash('sha256').update(process.argv[1]).digest('hex').slice(0,12))" "<body 텍스트>"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
block 모드 마커 형식 정확히:
|
|
81
|
+
```
|
|
82
|
+
<!-- omd:start v=1 hash=ab12cd34ef56 -->
|
|
83
|
+
<body>
|
|
84
|
+
<!-- omd:end -->
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 실행 절차
|
|
88
|
+
|
|
89
|
+
사용자가 어떤 모드를 요청하는지 분기:
|
|
90
|
+
- **인터랙티브 (디폴트)** — drift 발견 시 사용자에게 묻기
|
|
91
|
+
- **--force 의도** ("강제 덮어쓰기") — drift 무시하고 덮어씀
|
|
92
|
+
- **--check 의도** ("상태만 검사") — 파일 상태만 출력, write 안 함
|
|
93
|
+
|
|
94
|
+
각 shim별로:
|
|
95
|
+
|
|
96
|
+
### Step 1 — Read existing
|
|
97
|
+
파일 없으면 → status: `missing`, 새로 write 진행
|
|
98
|
+
파일 있으면 → 내용 파싱
|
|
99
|
+
|
|
100
|
+
### Step 2 — block 모드 파싱
|
|
101
|
+
`<!-- omd:start v=N hash=H -->` 라인 찾기:
|
|
102
|
+
- 없으면 → status: `missing` (block 부재, 사용자 content 외에 새로 추가 필요)
|
|
103
|
+
- 있으면 → marker 사이의 본문 추출. 추출된 본문의 sha256:12를 계산해서 marker의 `hash=H`와 비교
|
|
104
|
+
- 불일치 → status: `drifted` (사용자가 수동 편집함)
|
|
105
|
+
- 일치 + 본문 == 템플릿 → status: `clean`
|
|
106
|
+
- 일치 + 본문 != 템플릿 → status: `out-of-date` (omd 템플릿이 갱신됨)
|
|
107
|
+
|
|
108
|
+
### Step 3 — whole 모드 파싱
|
|
109
|
+
existing 전체 content와 rendered 템플릿 비교:
|
|
110
|
+
- 동일 → `clean`
|
|
111
|
+
- 차이 → `drifted`
|
|
112
|
+
|
|
113
|
+
### Step 4 — drift 처리
|
|
114
|
+
- **인터랙티브**: drift된 shim별로 "${path}는 수동 편집됐어요. 덮어쓸까요? (yes/no/show diff)" 묻기
|
|
115
|
+
- **--force**: drift 무시 덮어씀
|
|
116
|
+
- **--check**: drift 있으면 exit 1 동등 — 사용자에게 "drift detected" 보고 후 종료
|
|
117
|
+
|
|
118
|
+
### Step 5 — Write
|
|
119
|
+
- block 모드: existing 안의 marker block만 새 hash + 새 body로 교체. 마커 외부 사용자 content는 보존
|
|
120
|
+
- whole 모드: 파일 전체를 새 rendered content로 교체. 디렉토리 (`.cursor/rules/`) 없으면 mkdir
|
|
121
|
+
|
|
122
|
+
### Step 6 — sync-lock 갱신
|
|
123
|
+
`.omd/sync.lock.json` 기록 (없으면 만든다):
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"design_md_hash": "<DESIGN.md sha256:12>",
|
|
127
|
+
"targets": {
|
|
128
|
+
"CLAUDE.md": "<hash>",
|
|
129
|
+
"AGENTS.md": "<hash>",
|
|
130
|
+
".cursor/rules/omd-design.mdc": "<hash>"
|
|
131
|
+
},
|
|
132
|
+
"updated_at": "<ISO timestamp>"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
DESIGN.md 해시:
|
|
137
|
+
```bash
|
|
138
|
+
[ -f DESIGN.md ] && node -e "console.log(require('crypto').createHash('sha256').update(require('fs').readFileSync('DESIGN.md')).digest('hex').slice(0,12))"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 결과 보고
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
CLAUDE.md (block) — updated
|
|
145
|
+
AGENTS.md (block) — unchanged
|
|
146
|
+
.cursor/rules/omd-design.mdc — created
|
|
147
|
+
DESIGN.md hash: ab12cd34ef56
|
|
26
148
|
```
|
|
27
149
|
|
|
28
150
|
## 언제 실행하나
|
|
29
151
|
|
|
30
|
-
-
|
|
31
|
-
- 새
|
|
152
|
+
- DESIGN.md 변경 직후 (shim hash 갱신용)
|
|
153
|
+
- 새 프로젝트 첫 도입 (3종 생성)
|
|
32
154
|
- `.claude` / `.cursor` 디렉토리 추가 후
|
|
33
|
-
-
|
|
155
|
+
- "drift 확인" 요청
|
|
34
156
|
|
|
35
157
|
## 금지
|
|
36
158
|
|
|
37
|
-
-
|
|
38
|
-
-
|
|
159
|
+
- 마커 안 본문에 임의 추가/축약 금지 — 위 템플릿 정확히 사용
|
|
160
|
+
- block 모드 파일에서 마커 외부 사용자 content 절대 삭제 금지
|
|
161
|
+
- `.omd/sync.lock.json` 무시 금지 — 항상 갱신
|
|
162
|
+
- DESIGN.md가 없어도 shim은 만들 수 있음 (DESIGN.md 생성 후에 hash만 채움)
|
package/dist/chunk-6YNSV3VY.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/core/agent-detect.ts
|
|
4
|
-
import { existsSync } from "fs";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
function detectCallingAgent() {
|
|
7
|
-
const env = process.env;
|
|
8
|
-
if (env.CLAUDECODE === "1" || env.CLAUDE_CODE === "1" || env.CLAUDE_CODE_TASK_ID) {
|
|
9
|
-
return "claude-code";
|
|
10
|
-
}
|
|
11
|
-
if (env.CODEX_SESSION_ID || env.CODEX || env.OPENAI_CODEX) {
|
|
12
|
-
return "codex";
|
|
13
|
-
}
|
|
14
|
-
if (env.OPENCODE || env.OPENCODE_SESSION) {
|
|
15
|
-
return "opencode";
|
|
16
|
-
}
|
|
17
|
-
if (env.CURSOR_SESSION_ID || env.CURSOR_AGENT) {
|
|
18
|
-
return "cursor";
|
|
19
|
-
}
|
|
20
|
-
return "unknown";
|
|
21
|
-
}
|
|
22
|
-
function detectInstalledAgents(projectRoot) {
|
|
23
|
-
return {
|
|
24
|
-
claudeCode: existsSync(join(projectRoot, ".claude")) || existsSync(join(projectRoot, "CLAUDE.md")),
|
|
25
|
-
codex: existsSync(join(projectRoot, ".codex")) || existsSync(join(projectRoot, "AGENTS.md")) || existsSync(join(projectRoot, "AGENTS.override.md")),
|
|
26
|
-
opencode: existsSync(join(projectRoot, ".opencode")) || existsSync(join(projectRoot, "opencode.json")) || existsSync(join(projectRoot, "opencode.jsonc")),
|
|
27
|
-
cursor: existsSync(join(projectRoot, ".cursor")) || existsSync(join(projectRoot, ".cursorrules"))
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export {
|
|
32
|
-
detectCallingAgent,
|
|
33
|
-
detectInstalledAgents
|
|
34
|
-
};
|
|
35
|
-
//# sourceMappingURL=chunk-6YNSV3VY.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/agent-detect.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport type AgentId = 'claude-code' | 'codex' | 'opencode' | 'cursor' | 'unknown';\n\nexport function detectCallingAgent(): AgentId {\n const env = process.env;\n\n if (env.CLAUDECODE === '1' || env.CLAUDE_CODE === '1' || env.CLAUDE_CODE_TASK_ID) {\n return 'claude-code';\n }\n if (env.CODEX_SESSION_ID || env.CODEX || env.OPENAI_CODEX) {\n return 'codex';\n }\n if (env.OPENCODE || env.OPENCODE_SESSION) {\n return 'opencode';\n }\n if (env.CURSOR_SESSION_ID || env.CURSOR_AGENT) {\n return 'cursor';\n }\n\n return 'unknown';\n}\n\nexport interface AgentPresence {\n claudeCode: boolean;\n codex: boolean;\n opencode: boolean;\n cursor: boolean;\n}\n\nexport function detectInstalledAgents(projectRoot: string): AgentPresence {\n return {\n claudeCode:\n existsSync(join(projectRoot, '.claude')) ||\n existsSync(join(projectRoot, 'CLAUDE.md')),\n codex:\n existsSync(join(projectRoot, '.codex')) ||\n existsSync(join(projectRoot, 'AGENTS.md')) ||\n existsSync(join(projectRoot, 'AGENTS.override.md')),\n opencode:\n existsSync(join(projectRoot, '.opencode')) ||\n existsSync(join(projectRoot, 'opencode.json')) ||\n existsSync(join(projectRoot, 'opencode.jsonc')),\n cursor:\n existsSync(join(projectRoot, '.cursor')) ||\n existsSync(join(projectRoot, '.cursorrules')),\n };\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AAId,SAAS,qBAA8B;AAC5C,QAAM,MAAM,QAAQ;AAEpB,MAAI,IAAI,eAAe,OAAO,IAAI,gBAAgB,OAAO,IAAI,qBAAqB;AAChF,WAAO;AAAA,EACT;AACA,MAAI,IAAI,oBAAoB,IAAI,SAAS,IAAI,cAAc;AACzD,WAAO;AAAA,EACT;AACA,MAAI,IAAI,YAAY,IAAI,kBAAkB;AACxC,WAAO;AAAA,EACT;AACA,MAAI,IAAI,qBAAqB,IAAI,cAAc;AAC7C,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AASO,SAAS,sBAAsB,aAAoC;AACxE,SAAO;AAAA,IACL,YACE,WAAW,KAAK,aAAa,SAAS,CAAC,KACvC,WAAW,KAAK,aAAa,WAAW,CAAC;AAAA,IAC3C,OACE,WAAW,KAAK,aAAa,QAAQ,CAAC,KACtC,WAAW,KAAK,aAAa,WAAW,CAAC,KACzC,WAAW,KAAK,aAAa,oBAAoB,CAAC;AAAA,IACpD,UACE,WAAW,KAAK,aAAa,WAAW,CAAC,KACzC,WAAW,KAAK,aAAa,eAAe,CAAC,KAC7C,WAAW,KAAK,aAAa,gBAAgB,CAAC;AAAA,IAChD,QACE,WAAW,KAAK,aAAa,SAAS,CAAC,KACvC,WAAW,KAAK,aAAa,cAAc,CAAC;AAAA,EAChD;AACF;","names":[]}
|