@spectrabrain/eds 0.4.0 → 0.6.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/AI_CONTEXT.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "specifier": "@spectrabrain/eds/CONSUMER_AGENT.md",
17
17
  "kind": "setup-contract",
18
18
  "required": false,
19
- "when": "First setup: the consumer AGENTS.md has no <!-- EDS:BEGIN --> block; eds doctor exits 1 or 2, eds sync exits 2, or sync recovery is unclear; EDS was upgraded; the user asks to reorganize a prototype into the EVA frontend structure (eds align)"
19
+ "when": "First setup: the consumer AGENTS.md has no <!-- EDS:BEGIN --> block; eds doctor exits 1 or 2, eds sync exits 2, or sync recovery is unclear; the EDS version marker is missing or the installed version differs from it; the user asks to reorganize a prototype into the EVA frontend structure (eds align)"
20
20
  },
21
21
  {
22
22
  "file": "AI.md",
@@ -72,7 +72,7 @@
72
72
  "specifier": "@spectrabrain/eds/CHANGELOG.md",
73
73
  "kind": "changelog",
74
74
  "required": false,
75
- "when": "EDS was upgraded: the installed version is higher than the AGENTS.md EDS:VERSION line"
75
+ "when": "EDS was upgraded, or the AGENTS.md EDS:VERSION marker is missing: read all applicable consumer actions through the installed version"
76
76
  }
77
77
  ],
78
78
  "precedence": [
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @spectrabrain/eds
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 458fbde: 소비처 조치: 없습니다.
8
+
9
+ Button 이름 슬롯의 자동완성 응답을 개선하면서 설치된 `lucide-react`의 전체 icon component 이름과 alias 지원을 유지합니다.
10
+
11
+ ## 0.5.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 5da0d43: 소비처 조치: `npm install @spectrabrain/eds`로 업데이트합니다. 허용된 postinstall이 첫 sync를 준비하며, EDS 버전 marker가 없거나 설치 버전과 다르면 에이전트가 적용할 changelog 조치를 읽고 UI 작업 시작에 `sync:eds`를 실행합니다. 최종 검증 뒤 커밋 직전에 `eds:doctor`를 실행해 `[EDS] synced with` 줄을 확인합니다.
16
+
17
+ Doctor는 `typecheck`·`build`에서 자동 실행하지 않습니다. `init`·sync·postinstall은 이전 EDS가 등록한 Doctor lifecycle hook과 typecheck·build 명령의 Doctor 접두를 정리합니다.
18
+
3
19
  ## 0.4.0
4
20
 
5
21
  ### Minor Changes
package/CONSUMER_AGENT.md CHANGED
@@ -7,7 +7,7 @@
7
7
  `npm run sync:eds`는 sync를 실행한 package 디렉터리(`package.json`이 있는 곳)의 `AGENTS.md`에 managed block을 관리합니다.
8
8
 
9
9
  - 파일이 없으면 만들고, block이 없으면 끝에 추가하며, 있으면 같은 위치에서 갱신합니다. marker 밖의 내용은 보존합니다.
10
- - BEGIN marker 바로 뒤에 설치 버전(`<!-- EDS:VERSION x.y.z -->`)을 기록하고 `npm run ` 접두를 감지한 runner(`pnpm `, `yarn `, `bun run `)로 바꿉니다.
10
+ - BEGIN marker 바로 뒤에 설치 버전(`<!-- EDS:VERSION x.y.z -->`)을 기록하고, 해당 package에서 실행 가능한 sync·doctor 명령을 기록합니다. script가 아직 없거나 소비처 소유 script와 충돌하면 CLI 명령을 씁니다.
11
11
  - marker가 중복되거나 한쪽만 있으면 파일을 쓰지 않고 실패합니다.
12
12
 
13
13
  ```md
@@ -16,13 +16,14 @@
16
16
  ## EVA Design System 사용 규칙
17
17
 
18
18
  - UI 작업 전에 EDS package root(`require.resolve("@spectrabrain/eds/package.json")`의 디렉터리, 보통 `node_modules/@spectrabrain/eds`)의 `QUICKSTART.md`를 읽고 규칙과 완료 기준을 따릅니다. 조건별 문서는 `AI_CONTEXT.json`의 `readOrder`를 따릅니다.
19
- - UI 작업을 끝내기 전에 이 `AGENTS.md`가 있는 디렉터리에서 `npm run eds:doctor`를 실행해 `[EDS] synced with` 줄을 확인합니다. 이 줄이 없으면 `QUICKSTART.md` 「완료 기준」의 순서로 고칩니다.
20
- - UI 작업의 완료 보고에 변경 파일, 사용한 EDS component·token, typecheck·build·doctor 결과를 적습니다.
19
+ - 첫 편집 전에 이 `AGENTS.md`가 있는 디렉터리에서 `npm run sync:eds`를 한 번 실행합니다. sync는 설치 버전과 managed block·생성 파일을 비교해 필요한 파일만 갱신하며, 차이가 없으면 `Already synced`를 출력합니다. 설치 버전이 marker보다 높으면 먼저 해당 버전의 `CHANGELOG.md` 소비처 조치를 읽고 적용합니다. 작업 중 EDS를 설치하거나 업데이트하면 변경 내역을 읽고 다시 실행합니다. typecheck·build 앞에는 실행하지 않습니다.
20
+ - 검증이 끝난 뒤 커밋 직전에 `npm run eds:doctor`를 실행해 `[EDS] synced with` 줄을 확인합니다. 기존 pre-commit hook이 이미 같은 점검을 실행하면 그 결과를 확인하고, 그렇지 않으면 에이전트가 직접 실행합니다. EDS는 typecheck·build lifecycle hook을 등록하지 않습니다.
21
+ - UI 작업의 완료 보고에 변경 파일, 사용한 EDS component·token, typecheck·build 결과와 커밋 전 doctor 결과를 적습니다.
21
22
  - 이 block은 `npm run sync:eds`가 다시 씁니다. 소비처 규칙은 block 밖에 적습니다.
22
23
  <!-- EDS:END -->
23
24
  ```
24
25
 
25
- block은 postinstall이 아니라 `npm run sync:eds`가 넣으며, 소비처 담당자가 저장소의 기존 규칙과 함께 diff를 검토합니다. EDS를 업데이트할 때도 block 안쪽과 버전 줄만 바뀝니다.
26
+ 첫 설치 postinstall은 직접 설치된 앱에서 scripts와 첫 sync를 수행해 block을 만들 수 있습니다. EDS 버전이 기존 marker와 다르거나 기존 block에 marker가 없으면 postinstall이 block과 파일을 갱신하지 않습니다. 에이전트가 marker가 없을 때는 설치 버전까지의 적용 가능한 changelog 조치를, 버전이 다를 때는 이전 marker 이후의 조치를 읽은 뒤 다음 UI 작업 시작에 sync합니다. 소비처 담당자는 생성된 변경을 저장소의 기존 규칙과 함께 검토합니다.
26
27
 
27
28
  block이 전달되는 지시 파일은 도구마다 다릅니다.
28
29
 
@@ -34,15 +35,15 @@ sync와 doctor는 Claude·Gemini 지시 파일이 없거나, `CLAUDE.local.md`
34
35
 
35
36
  ## 첫 setup 절차
36
37
 
37
- 소비처 `AGENTS.md`에 EDS managed block이 없으면 UI 작업보다 먼저 이 절차를 진행합니다. `@spectrabrain/eds`를 dependencies에 선언할 앱 package 디렉터리(그 앱의 `package.json`이 있는 곳)에서 패키지를 설치하고 `init`으로 script 등록과 첫 sync를 실행합니다. `init`은 postinstall 실행 여부와 관계없이 동작하며, 현재 `package.json`이 `@spectrabrain/eds`를 선언하지 않으면 아무것도 쓰지 않고 exit 2로 끝납니다.
38
+ 소비처 담당자는 앱 package에 EDS를 설치하면 됩니다. 직접 앱에서 dependency lifecycle script가 허용되면 postinstall이 scripts와 첫 sync를 준비합니다. pnpm postinstall은 `package.json` script를 수정하지 않으며, 첫 UI 작업 sync가 이를 등록합니다. workspace root나 lifecycle script가 실행되지 않은 경우에는 에이전트가 EDS dependency를 선언한 앱 package에서 `init`을 실행합니다(`npx @spectrabrain/eds init`, `pnpm exec eds init`, `yarn eds init`, `bunx @spectrabrain/eds init`). 이때도 소비처 담당자가 `sync:eds`를 직접 실행할 필요는 없습니다. `init`은 현재 `package.json`이 `@spectrabrain/eds`를 선언하지 않으면 아무것도 쓰지 않고 exit 2로 끝납니다.
38
39
 
39
- | 패키지 매니저 | 실행할 명령 | `init`의 추가 동작 |
40
- | --------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
41
- | npm | `npm install @spectrabrain/eds && npx @spectrabrain/eds init` | npm 12 이상이면 `allowScripts["@spectrabrain/eds"]: true`(이름만, 버전 pin 없음)를 키가 없을 때만 기록합니다. `--no-allow-scripts`로 건너뜁니다. |
42
- | pnpm | `pnpm add @spectrabrain/eds && pnpm exec eds init` | 추가 설정이 필요 없습니다. 설치 중 postinstall은 `init` 안내만 출력합니다. |
43
- | yarn berry(`.yarnrc.yml`이 있거나 `yarn.lock`이 `__metadata:`로 시작) | `yarn add @spectrabrain/eds && yarn eds init` | yarn berry는 `pre`·`post` hook을 실행하지 않으므로 `typecheck`·`build` script 앞에 `eds doctor && `를 붙이라고 안내하며, 그 script를 직접 고치지는 않습니다. `enableScripts`·`dependenciesMeta` 승인은 선택 사항이며 사용자가 결정할 항목으로 완료 보고에 적습니다. |
44
- | yarn classic | `yarn add @spectrabrain/eds && yarn eds init` | 추가 안내가 없습니다. |
45
- | bun | `bun add @spectrabrain/eds && bunx @spectrabrain/eds init` | `trustedDependencies` 승인은 선택 사항이며, bun의 기본 신뢰 목록을 대체하므로 사용자가 결정할 항목으로 완료 보고에 적습니다. |
40
+ | 패키지 매니저 | 소비처가 실행하는 설치 명령 | 설치 후 자동 동작과 에이전트 초기화 |
41
+ | --------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
+ | npm | `npm install @spectrabrain/eds` | 허용된 postinstall이 scripts와 첫 sync를 준비합니다. npm 12 이상은 `allowScripts["@spectrabrain/eds"]: true`(이름만, 버전 pin 없음)가 필요할 수 있으며, `init`이 이 설정을 기록합니다. `--no-allow-scripts`로 건너뜁니다. |
43
+ | pnpm | `pnpm add @spectrabrain/eds` | 허용된 postinstall은 소비처 파일을 sync하지만 script 등록은 보류합니다. 첫 UI 작업의 `pnpm exec eds sync`가 scripts를 등록합니다. |
44
+ | yarn berry(`.yarnrc.yml`이 있거나 `yarn.lock`이 `__metadata:`로 시작) | `yarn add @spectrabrain/eds` | dependency script가 허용된 경우 postinstall이 동작합니다. `enableScripts`·`dependenciesMeta` 승인은 사용자가 결정합니다. 실행되지 않으면 에이전트가 `yarn eds init`을 사용합니다. |
45
+ | yarn classic | `yarn add @spectrabrain/eds` | dependency script가 허용된 경우 postinstall이 동작합니다. 실행되지 않으면 에이전트가 `yarn eds init`을 사용합니다. |
46
+ | bun | `bun add @spectrabrain/eds` | dependency script가 허용된 경우 postinstall이 동작합니다. 실행되지 않으면 에이전트가 `bunx @spectrabrain/eds init`을 사용합니다. `trustedDependencies` 승인은 사용자가 결정합니다. |
46
47
 
47
48
  yarn berry의 기본 Plug'n'Play 설치에는 `node_modules/@spectrabrain/eds`가 없으며 지원 여부는 아직 확인되지 않았습니다. sync와 doctor는 `.pnp.cjs`를 발견하면 `note:`로 알리며, 이때 `nodeLinker`를 바꾸기 전에 저장소 담당자에게 확인합니다.
48
49
 
@@ -59,27 +60,27 @@ EDS CLI는 가장 가까운 lockfile(현재 디렉터리부터 git 루트까지)
59
60
  }
60
61
  ```
61
62
 
62
- - `sync:eds`·`eds:doctor`가 없으면 등록합니다. 같은 이름의 script가 `eds sync`·`eds doctor`를 포함하면(예: `EDS_DOCTOR=warn eds doctor`) 그대로 두고, 다른 명령이면 덮어쓰지 않고 안내만 출력하며 `eds doctor`가 `scripts:` 항목으로 보고합니다. 이전 EDS 버전이 등록한 알려진 명령은 새 명령으로 바꿉니다.
63
- - 소비처에 `typecheck`·`build` script가 있으면 대응하는 `pretypecheck`·`prebuild` hook이 없는 경우에만 `eds doctor`를 등록합니다. 이미 다른 pre-hook이 있으면 그대로 두고, 출력된 명령대로 기존 hook 앞에 `eds doctor && `를 붙입니다.
64
- - npm 10·11과, `init`이 `allowScripts`를 기록한 npm 12 이상에서는 EDS의 `postinstall`이 설치 중에 같은 script를 등록하고 다른 파일은 쓰지 않습니다. 소비처 `package.json`에 `workspaces`가 있으면 등록하지 않고 앱 package 안에서 `init`을 실행하도록 안내하며, pnpm 설치에서는 pnpm이 설치 중의 `package.json` 편집을 버리므로 `pnpm exec eds init`을 안내합니다.
63
+ - `sync:eds`·`eds:doctor`가 없으면 `init`·sync·postinstall이 등록합니다. 같은 이름의 script가 `eds sync`·`eds doctor`를 포함하면(예: `EDS_DOCTOR=warn eds doctor`) 그대로 두고, 다른 명령이면 덮어쓰지 않고 안내만 출력하며 `eds doctor`가 `scripts:` 항목으로 보고합니다. 이전 EDS 버전이 등록한 알려진 명령은 새 명령으로 바꿉니다.
64
+ - `init`·sync·postinstall은 Doctor를 typecheck·build lifecycle에 등록하지 않습니다. 이전 EDS가 만든 `pretypecheck`·`prebuild: "eds doctor"`를 제거하고, typecheck·build 또는 해당 pre-hook이 `eds doctor && <기존 명령>`으로 시작하면 Doctor 접두만 제거해 기존 명령을 보존합니다.
65
+ - postinstall은 직접 설치된 앱에서 `sync:eds`·`eds:doctor`를 등록하고 첫 설치 sync로 managed block·생성 CSS·Tailwind import를 준비합니다. 기존 marker와 설치 버전이 다르거나 기존 block에 marker가 없으면 changelog 조치를 보존하기 위해 파일 sync를 미루고 script 정리만 합니다. 소비처 `package.json`에 `workspaces`가 있으면 루트가 앱인지 단정할 수 없어 건너뜁니다. pnpm은 lifecycle 중 `package.json` 편집을 버리므로 파일만 sync하고, 첫 UI 작업의 `pnpm exec eds sync`에서 scripts를 등록합니다.
65
66
  - `--no-sync`는 script만 등록하고(npm 12 이상은 `allowScripts`도 기록) sync는 실행하지 않습니다(`npx @spectrabrain/eds init --no-sync`).
66
67
  - `init --print-ci github` 또는 `--print-ci gitlab`(예: `npx @spectrabrain/eds init --print-ci github`)은 이 저장소의 패키지 매니저로 install과 `eds doctor`를 실행하는 CI job snippet을 출력합니다. 저장소 루트가 EDS package이면 그대로 붙입니다. workspace package에서는 GitHub Actions의 `working-directory`를 지정하거나 GitLab의 install·doctor 명령 앞에 `cd <앱 package 경로> &&`를 붙입니다. 출력 snippet에는 이 경로가 포함되지 않습니다.
67
68
 
68
- 설치와 sync는 `npm run eds:doctor`가 `[EDS] synced with` 줄을 출력하면 확인됩니다. `pretypecheck`·`prebuild` hook은 `init` 또는 `postinstall`이 등록하며, doctor는 hook 자체를 검사하지 않습니다. 기존 hook을 건너뛰었다는 안내가 나오면 `eds doctor && `를 기존 명령 앞에 붙입니다. 담당자가 첫 sync 전에 `CLAUDE.md`·`AGENTS.md`에 넣은 EDS 안내 줄(`README.md` 「설치」)이 남아 있으면 block과 겹치므로 지웁니다. 같은 이름의 다른 script를 바꾸거나 marker 밖 기존 내용을 고쳐야 할 때는 쓰기 전에 사용자에게 확인합니다.
69
+ 에이전트는 첫 편집 전에 한 번 sync하고, 이후 UI 작업 시작과 EDS 설치·업데이트 뒤에도 sync합니다. marker와 생성물이 최신이면 sync는 `Already synced`로 끝납니다. typecheck·build는 Doctor를 실행하지 않습니다. Doctor는 최종 검증 뒤 커밋 직전에 실행하며, 기존 pre-commit hook이 같은 점검을 이미 실행하면 그 결과를 확인하고 그렇지 않으면 에이전트가 직접 실행합니다. 새 hook manager는 설치하지 않습니다. 담당자가 첫 sync 전에 `CLAUDE.md`·`AGENTS.md`에 넣은 EDS 안내 줄(`README.md` 「설치」)이 남아 있으면 block과 겹치므로 지웁니다. 같은 이름의 다른 script를 바꾸거나 marker 밖 기존 내용을 고쳐야 할 때는 쓰기 전에 사용자에게 확인합니다.
69
70
 
70
71
  ## Tailwind root 결정
71
72
 
72
73
  `eds sync`와 `eds doctor`는 환경 변수 `EDS_TAILWIND_ROOT`, 소비처 `package.json`의 `eds.tailwindRoot`, 자동 검출 순서로 Tailwind root CSS를 정합니다. 자동 검출은 `@import "tailwindcss"`(`tailwindcss/theme.css`·`tailwindcss/utilities.css`, `@import url("tailwindcss")` 포함)가 있는 CSS 파일 하나를 root로 쓰며, 주석 안의 import와 `node_modules`·`dist`·`build`·`coverage`·`storybook-static`, 점(`.`)으로 시작하는 디렉터리는 제외합니다.
73
74
 
74
75
  - 후보가 2개 이상이면 아무 파일도 쓰지 않고 exit 2로 끝납니다. 사용자에게 root를 확인하고, 후보마다 앱 진입점(예: `src/main.tsx`)이 그 파일을 import하는지 찾아 함께 알립니다.
75
- - 확인한 root는 `EDS_TAILWIND_ROOT=<root CSS 경로> npm run sync:eds`로 한 번 지정합니다(예: `EDS_TAILWIND_ROOT=src/app/styles/index.css npm run sync:eds`). sync는 이 경로를 소비처 `package.json`의 `"eds": { "tailwindRoot": "…" }`에 저장하므로 이후 doctor·sync·hook은 환경 변수 없이 같은 root를 씁니다.
76
+ - 확인한 root는 `EDS_TAILWIND_ROOT=<root CSS 경로> npm run sync:eds`로 한 번 지정합니다(예: `EDS_TAILWIND_ROOT=src/app/styles/index.css npm run sync:eds`). sync는 이 경로를 소비처 `package.json`의 `"eds": { "tailwindRoot": "…" }`에 저장하므로 이후 doctor·sync가 환경 변수 없이 같은 root를 씁니다.
76
77
  - `EDS_TAILWIND_ROOT`나 저장된 경로가 없는 파일을 가리키면 exit 2입니다.
77
78
  - 후보가 없고 지정도 없으면 Tailwind를 쓰지 않는 저장소로 보고 Tailwind 배선을 건너뜁니다. 이때 sync는 `AGENTS.md` managed block과, 파일이 있을 때 `CLAUDE.md`·`GEMINI.md`의 import만 갱신합니다. doctor는 Tailwind 항목 대신 `note:` 한 줄을 출력하고 EDS font import는 계속 점검합니다. Tailwind를 쓰지 않는 저장소는 앱 진입점(예: `src/main.tsx`)에서 `@spectrabrain/eds/styles.css`를 import합니다.
78
79
  - CSS가 `@tailwind` 지시어를 쓰는 Tailwind CSS v3 저장소도 후보가 없는 것으로 보고, sync와 doctor가 `Tailwind CSS v3 detected` note를 출력합니다. 이 저장소에서는 `EDS_TAILWIND_ROOT`를 지정하지 않고(v3 파일을 가리키면 exit 2) 앱 진입점의 `styles.css` import와 `var(--eds-*)`·`cssVar()`를 쓰며, Tailwind CSS v4 업그레이드는 사용자에게 확인한 뒤 진행합니다.
79
80
 
80
81
  ## sync가 쓰는 파일
81
82
 
82
- sync는 모든 변경을 먼저 계산하고, 계산 중 하나라도 실패하면 어떤 파일도 바꾸지 않습니다. 쓰는 내용은 다음과 같습니다.
83
+ 전체 sync는 `sync:eds`·`eds:doctor` script가 빠졌으면 등록하고, 이전 EDS Doctor lifecycle hook과 typecheck·build 접두를 정리합니다. 소비처가 덧붙인 접미 명령은 보존합니다. `--only` sync는 지정한 대상만 동기화하며 script 등록과 Doctor 정리는 하지 않습니다. 파일 변경은 모두 먼저 계산하고, 계산 중 하나라도 실패하면 어떤 파일도 바꾸지 않습니다. 쓰는 파일은 다음과 같습니다.
83
84
 
84
85
  1. `src/styles/eds-tokens.css`를 생성하고, Tailwind root의 마지막 Tailwind import 바로 다음 줄에 `@import "@spectrabrain/eds/styles.css";`와 생성 CSS의 상대 경로 `@import`를 추가합니다. 이미 있는 import는 다시 추가하지 않습니다. 생성 CSS의 `@theme inline`에는 공개 color alias와 `--font-sans: var(--eds-typography-body1-fontFamily);`가 들어갑니다. Typography utility도 함께 생성됩니다. root CSS 예시는 `TAILWIND_V4.md`에 있습니다.
85
86
  2. `src/` 아래 JS·TS 파일에서 `eds-tokens.css`를 import하는 줄을 제거합니다. Tailwind는 JS에서 import한 CSS를 compile하지 않기 때문입니다.
@@ -88,7 +89,7 @@ sync는 모든 변경을 먼저 계산하고, 계산 중 하나라도 실패하
88
89
 
89
90
  `@spectrabrain/eds/styles.css`는 CSS나 JS·TS 소스가 이미 import하고 있으면 다시 추가하지 않습니다. `tokens.css`·`components.css`·`fonts.css`가 모두 import되어 있어도 같으며, `tokens.css`와 `components.css`만 있고 `fonts.css`가 없으면 root에 `@import "@spectrabrain/eds/fonts.css";`를 추가합니다.
90
91
 
91
- `npm run sync:eds -- --only tailwind`와 `npm run sync:eds -- --only agents`는 해당 부분만 쓰고, `--dry-run`은 쓸 경로만 출력합니다. 두 옵션을 써도 Tailwind root 판정과 marker 검사는 모두 수행하므로, root 후보가 2개 이상이면 `--only agents`도 exit 2로 끝납니다. 파일을 쓴 sync는 쓴 파일을 `[EDS] wrote <경로>` 줄로 나열한 뒤 그 파일을 변경에 포함하고 doctor를 실행하라는 줄로 끝나고, 바꿀 것이 없으면 `Already synced`로 끝납니다.
92
+ `npm run sync:eds -- --only tailwind`와 `npm run sync:eds -- --only agents`는 해당 부분만 동기화하며 script 등록과 Doctor 정리는 하지 않습니다. `--dry-run`은 변경할 `package.json` script와 파일 경로를 출력하고 파일은 쓰지 않습니다. 두 옵션을 써도 Tailwind root 판정과 marker 검사는 모두 수행하므로, root 후보가 2개 이상이면 `--only agents`도 exit 2로 끝납니다. 파일을 쓴 sync는 쓴 파일을 `[EDS] wrote <경로>` 줄로 나열한 뒤 커밋 전에 doctor를 실행하라는 줄로 끝나고, 바꿀 것이 없으면 `Already synced`로 끝납니다.
92
93
 
93
94
  ## font 정책
94
95
 
@@ -100,9 +101,9 @@ EDS text style은 font family `Pretendard`를 참조하며, 이 family는 `@spec
100
101
 
101
102
  `eds doctor`는 `@spectrabrain/eds/styles.css`와 `@spectrabrain/eds/fonts.css`가 CSS·JS·TS 어디에서도 import되지 않으면 `missing:`으로 보고합니다. HTML·CSS에서 EDS import 밖에 `Pretendard`를 언급하는 줄이 있으면 `note:`를 출력하며, 이 줄은 exit code에 영향을 주지 않습니다.
102
103
 
103
- ## `eds:doctor` 점검
104
+ ## 커밋 전 `eds:doctor` 점검
104
105
 
105
- `npm run eds:doctor`는 파일을 쓰지 않고 sync 상태, `sync:eds`·`eds:doctor` 등록, EDS font import를 점검합니다. Tailwind CSS v4 root가 있으면 소스의 `eds-*` class 이름도 확인합니다. doctor는 `pretypecheck`·`prebuild` hook을 검사하지 않습니다. `init` 또는 `postinstall`이 등록한 hook은 typecheck·build 전에 같은 점검을 실행합니다. yarn berry는 이 hook을 실행하지 않으므로 `typecheck`·`build` 앞에 붙인 `eds doctor`가 같은 역할을 합니다.
106
+ `npm run eds:doctor`는 파일을 쓰지 않고 sync 상태, `sync:eds`·`eds:doctor` 등록, EDS font import를 점검합니다. Tailwind CSS v4 root가 있으면 소스의 `eds-*` class 이름도 확인합니다. typecheck·build 명령에는 연결하지 않으며, 에이전트가 최종 검증을 마친 뒤 커밋 직전에 실행합니다. 기존 pre-commit hook이 Doctor를 실행하면 그 결과를 확인하고, 그렇지 않으면 에이전트가 직접 한 번 실행합니다. `init`·postinstall은 Git hook manager를 설치하거나 만들지 않습니다. `init --print-ci`가 출력하는 CI job은 별도 안전망입니다.
106
107
 
107
108
  | exit | 의미 |
108
109
  | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -120,7 +121,7 @@ EDS text style은 font family `Pretendard`를 참조하며, 이 family는 `@spec
120
121
  | `unknown: <파일:줄> <class>` | 공개 token이 없는 `eds-*` class입니다. Tailwind는 이런 class를 조용히 버리므로 `src/styles/eds-tokens.css`에 있는 class로 고칩니다. EDS class는 color token의 `<utility>-eds-<이름>`과 typography utility `eds-typography-<style>`입니다. padding·margin·gap·radius에는 Tailwind CSS v4 기본 utility를 씁니다. |
121
122
  | `invalid:` | `AGENTS.md`의 EDS marker가 중복되거나 한쪽만 있습니다. sync는 이 상태를 고치지 않습니다. 출력에 적힌 줄에서 BEGIN 한 줄과 그 뒤의 END 한 줄만 남기고 나머지 marker 줄을 지운 뒤 sync를 다시 실행합니다. |
122
123
 
123
- `npm run eds:doctor -- --warn`과 `EDS_DOCTOR=warn`은 같은 출력에 warn mode 경고를 더하고 exit 0으로 끝나며, `EDS_DOCTOR=off`는 출력 없이 exit 0으로 끝납니다. 이 설정은 hook을 잠시 풀어야 할 때 사용자가 쓰는 것이며, 이 상태의 exit 0은 완료가 아닙니다.
124
+ `npm run eds:doctor -- --warn`과 `EDS_DOCTOR=warn`은 같은 출력에 warn mode 경고를 더하고 exit 0으로 끝나며, `EDS_DOCTOR=off`는 출력 없이 exit 0으로 끝납니다. 이 설정은 로컬 진단에만 사용하며, 이 상태의 exit 0은 완료가 아닙니다.
124
125
 
125
126
  `npm run eds:doctor -- --scan`은 Tailwind 기본 팔레트(`text-red-500`), `white`·`black`, 임의 색(`bg-[#…]`) class를 `raw: <파일:줄> <class>` 줄로 나열합니다. 정보 제공용이라 exit code를 바꾸지 않습니다. `unknown:`과 `raw:` 검사는 Tailwind CSS v4 root가 있는 저장소에서 Tailwind class만 봅니다. CSS·inline style의 `var(--eds-*)` 참조는 검사하지 않습니다.
126
127
 
@@ -156,7 +157,7 @@ EDS 버전을 올렸으면 다음 순서로 진행합니다.
156
157
 
157
158
  1. sync 전에 `AGENTS.md`의 `<!-- EDS:VERSION x.y.z -->` 줄에서 이전 버전을 확인합니다. 이미 sync했다면 `git diff AGENTS.md`의 삭제된 버전 줄에서 확인합니다.
158
159
  2. package root의 `CHANGELOG.md`(`@spectrabrain/eds/CHANGELOG.md`)에서 이전 버전보다 높은 절만 읽고, 각 항목이 요구하는 소비처 조치를 모두 적용합니다. 새 항목은 `소비처 조치:`로 시작합니다.
159
- 3. `npm run sync:eds`로 Tailwind root의 import, 공개 token alias, managed block과 버전 줄을 갱신하고, `npm run eds:doctor`가 `[EDS] synced with` 줄을 출력하는지 확인합니다.
160
+ 3. `npm run sync:eds`로 Tailwind root의 import, 공개 token alias, managed block과 버전 줄을 갱신합니다.
160
161
  4. 제거되거나 이름이 바뀐 token은 `CHANGELOG.md`에서 이름을 확인하고, Tailwind class는 doctor의 `unknown:` 항목에서, `cssVar()` 호출은 typecheck 오류에서, CSS·inline style의 `var(--eds-<이름>)`은 `tokens.json`의 `cssVariable` mapping과 대조해 고칩니다. dotted public name은 CSS reference에서만 점을 escape합니다. 새로 쓸 수 있는 class는 `src/styles/eds-tokens.css`의 diff에서 확인합니다.
161
162
 
162
- 생성 CSS의 header나 `AGENTS.md`의 버전 줄이 설치된 버전과 다르면 doctor가 `stale:`로 보고하므로, sync를 빠뜨린 업데이트는 `pretypecheck`·`prebuild` hook(yarn berry는 `typecheck`·`build` 앞의 `eds doctor`)에서 드러납니다. 작업 보고에는 올린 EDS 버전, 적용한 소비처 조치, 바뀐 파일, 새로 쓸 수 있는 class, 제거되거나 이름이 바뀐 공개 token, 검증 결과를 남깁니다.
163
+ 생성 CSS의 header나 `AGENTS.md`의 버전 줄이 설치된 버전과 다르면 sync가 해당 파일을 갱신합니다. 에이전트는 UI 작업을 시작할 때 한 번 sync를 실행하고, `Already synced`이면 추가 파일 변경 없이 진행합니다. sync를 빠뜨린 업데이트는 커밋 전 doctor가 `stale:`로 보고합니다. typecheck·build와 다른 최종 검증을 마친 뒤 doctor를 마지막으로 실행하고, 작업 보고에는 올린 EDS 버전, 적용한 소비처 조치, 바뀐 파일, 새로 쓸 수 있는 class, 제거되거나 이름이 바뀐 공개 token, 검증 결과를 남깁니다.
@@ -244,4 +244,4 @@ export function ConfirmDeleteAccountButton({
244
244
 
245
245
  ## 점검
246
246
 
247
- - 프론트엔드 코드를 바꾼 작업은 완료 전에 `format:check`·`lint`·`typecheck`·`build` script와 `npx @spectrabrain/eds align --check`가 모두 exit 0이고, `eds:doctor`가 `[EDS] synced with` 줄을 출력해야 합니다. `npm run`·`npx`는 저장소의 패키지 매니저 형식(예: `pnpm exec eds align --check`)으로 바꿔 실행합니다. `--check`의 출력 종류와 exit code는 `CONSUMER_AGENT.md` 「프로토타입 정렬」에 있습니다.
247
+ - 프론트엔드 코드를 바꾼 작업은 `format:check`·`lint`·`typecheck`·`build` script와 `npx @spectrabrain/eds align --check`가 모두 exit 0이어야 합니다. Doctor는 이 명령에 연결하지 않고 최종 검증 뒤 커밋 직전에 실행해 `[EDS] synced with` 줄을 확인합니다. `npm run`·`npx`는 저장소의 패키지 매니저 형식(예: `pnpm exec eds align --check`)으로 바꿔 실행합니다. `--check`의 출력 종류와 exit code는 `CONSUMER_AGENT.md` 「프로토타입 정렬」에 있습니다.
package/QUICKSTART.md CHANGED
@@ -20,13 +20,13 @@
20
20
 
21
21
  ## 완료 기준
22
22
 
23
- 1. `npm run eds:doctor`가 `[EDS] synced with`를 출력해야 합니다. 실패하면 각 줄의 조치(`unknown:` 포함)를 따라 `scripts:` → sync → 나머지 순서로 고칩니다. 자세한 절차는 `CONSUMER_AGENT.md`의 doctor 표를 따릅니다.
24
- 2. 있는 `typecheck`·`build` script는 exit 0이어야 합니다. 없는 script는 추가하지 말고 기존 검증 명령을 씁니다. EDS와 sync한 Tailwind CSS v4 root가 있을 때는 `npm run eds:doctor -- --scan`의 `raw:`에 바꾼 파일이 없어야 합니다.
25
- 3. 완료 보고에 변경 파일, EDS component·token, typecheck·build·doctor 결과를 적습니다. script가 없으면 그렇게 밝힙니다.
23
+ 1. 있는 `typecheck`·`build` script는 exit 0이어야 합니다. Tailwind CSS v4에서는 `eds:doctor -- --scan`의 `raw:`에 바꾼 파일이 없어야 합니다.
24
+ 2. 최종 검증 뒤 커밋 직전에 `npm run eds:doctor`를 실행해 `[EDS] synced with`를 확인합니다. 실패하면 `CONSUMER_AGENT.md` Doctor 표(`unknown:` 포함)의 조치를 따릅니다.
25
+ 3. 완료 보고에 변경 파일, EDS component·token, typecheck·build 결과와 doctor 결과를 적습니다. script가 없으면 그렇게 밝힙니다.
26
26
 
27
27
  ## 명령
28
28
 
29
- `npm run eds:doctor`는 읽기 전용 점검입니다. `npm run sync:eds`는 `AGENTS.md` managed block을 갱신하며, Tailwind CSS v4 root가 있으면 생성 CSS와 token alias도 갱신합니다. `npx @spectrabrain/eds init`은 기본 script 등록을 시도합니다. `typecheck`·`build` script가 있고 대응 hook이 없으면 `eds doctor` hook을 추가하며, 첫 sync도 실행합니다. runner는 소비처 형식으로 바꿉니다(`pnpm`·`yarn`·`bun run`, init은 `pnpm exec eds init`·`yarn eds init`·`bunx @spectrabrain/eds init`).
29
+ 직접 앱 설치의 허용된 postinstall은 첫 sync를 준비합니다. 에이전트는 UI 작업 시작에 `npm run sync:eds`를 한 번 실행합니다. marker가 없으면 설치 버전까지, 있으면 marker 이후의 `CHANGELOG.md` 소비처 조치를 적용한 뒤 sync합니다. 최신이면 `Already synced`로 끝납니다. 매 typecheck·build 전에는 실행하지 않습니다. Doctor는 읽기 전용이며 최종 검증 뒤 커밋 직전에만 실행합니다. postinstall이 생략되었거나 workspace root에서 설치했다면 소비 앱에서 패키지 매니저에 맞는 `init`을 실행합니다(`npx @spectrabrain/eds init`, `pnpm exec eds init`, `yarn eds init`, `bunx @spectrabrain/eds init`).
30
30
 
31
31
  ## 더 읽을 문서
32
32
 
package/README.md CHANGED
@@ -8,14 +8,15 @@ EVA 서비스의 일관된 UI/UX를 위한 React 웹 디자인 시스템입니
8
8
 
9
9
  ~~~sh
10
10
  npm install @spectrabrain/eds
11
- npx @spectrabrain/eds init
12
11
  ~~~
13
12
 
14
- `init`은 소비처 `package.json`에 `sync:eds`·`eds:doctor` 기본 script 등록을 시도합니다. `typecheck`·`build` script가 있으면 대응하는 doctor hook도 기존 hook이 없을 때만 등록한 뒤 첫 sync를 실행합니다. EDS를 업데이트한 뒤 `npm run sync:eds`로 `AGENTS.md` managed block을 갱신하고, Tailwind CSS v4 root가 있으면 CSS import·token alias도 갱신합니다. `npm run eds:doctor`로 동기화 상태를 확인합니다. pnpm·yarn·bun의 명령은 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「첫 setup 절차」를 따릅니다. `npx`에는 항상 `@spectrabrain/eds`를 적습니다. npm의 unscoped `eds`는 다른 패키지입니다.
13
+ 허용된 postinstall은 직접 설치된 앱에서 첫 sync를 준비합니다. pnpm은 설치 중 `package.json` 변경을 보존하지 않으므로 script 등록은 첫 UI 작업의 sync로 미룹니다. EDS를 업데이트했을 때 설치 버전과 `AGENTS.md` marker가 다르거나 기존 block에 marker가 없으면 postinstall은 block을 보존해 AI 에이전트가 changelog 조치를 먼저 읽고 다음 UI 작업 시작에 sync하게 합니다. postinstall이 실행되지 않거나 dependency가 workspace root에 hoist된 경우에는 에이전트가 소비 앱에서 `init`으로 setup합니다. 소비처 사용자는 별도로 `sync:eds`를 실행하지 않습니다.
14
+
15
+ AI 에이전트는 UI 작업 시작에 한 번 `sync:eds`를 실행해 설치 버전과 managed block·생성 파일을 맞춥니다. 최신이면 파일을 쓰지 않습니다. Doctor는 typecheck·build에 연결하지 않고, 최종 검증 뒤 커밋 직전에 실행합니다. package manager별 fallback은 [CONSUMER_AGENT.md](CONSUMER_AGENT.md) 「첫 setup 절차」를 따릅니다. `npx`에는 항상 `@spectrabrain/eds`를 적습니다. npm의 unscoped `eds`는 다른 패키지입니다.
15
16
 
16
17
  소비처 AI와 자동화 도구는 UI 작업 전에 [QUICKSTART.md](QUICKSTART.md)를 읽습니다. 나머지 문서는 [AI_CONTEXT.json](AI_CONTEXT.json)의 조건에 해당할 때만 읽습니다.
17
18
 
18
- 첫 sync 전에 AI가 `QUICKSTART.md`를 읽게 하려면 사용하는 도구가 읽는 루트 지시 파일에 다음 한 줄을 임시로 넣습니다(Codex는 `AGENTS.md`, Claude Code는 `CLAUDE.md`, Gemini CLI는 `GEMINI.md`). sync가 managed block을 추가하면 임시 줄을 지웁니다. pnpm·yarn·bun에서는 `npm run`을 해당 runner로 바꿉니다.
19
+ postinstall이 실행되지 않은 저장소에서 에이전트가 EDS 지시를 읽지 못하면, 사용하는 도구의 루트 지시 파일에 아래 한 줄을 임시로 넣습니다(Codex는 `AGENTS.md`, Claude Code는 `CLAUDE.md`, Gemini CLI는 `GEMINI.md`). 에이전트가 `init`으로 managed block을 추가하면 임시 줄을 지웁니다.
19
20
 
20
21
  > package.json에 `@spectrabrain/eds`가 있으면 UI 작업 전에 EDS package root의 `QUICKSTART.md`를 읽고 규칙과 완료 기준을 따릅니다. package root는 `require.resolve("@spectrabrain/eds/package.json")`로 찾습니다.
21
22
 
@@ -113,7 +114,7 @@ EDS는 Tailwind preset·plugin을 제공하지 않습니다. Tailwind CSS v4 저
113
114
  | `@spectrabrain/eds/TOKEN_CONTEXT.md` | semantic token의 역할과 화면 맥락입니다. |
114
115
  | `@spectrabrain/eds/TAILWIND_V4.md` | Tailwind CSS v4에서 공개 token을 연결하는 설치 가이드입니다. |
115
116
  | `@spectrabrain/eds/FRONTEND_CONVENTIONS.md` | EVA 프론트엔드의 구조·라이브러리·코드 패턴·개발 규칙입니다. `eds align`의 기준입니다. |
116
- | `eds` CLI (`npx @spectrabrain/eds init`) | 소비처 setup CLI입니다. `init`은 기본 script 등록을 시도하고 첫 동기화를 실행합니다. `npm run sync:eds`는 동기화합니다. `npm run eds:doctor`는 동기화 상태와 font import를 읽기 전용 점검하고, Tailwind CSS v4 root가 있으면 `eds-*` class 이름도 확인합니다. `npx @spectrabrain/eds align`은 프로토타입 정렬 계획과 점검을 실행합니다. 모듈로 import하지 않습니다. |
117
+ | `eds` CLI (`npx @spectrabrain/eds init`) | 소비처 setup CLI입니다. `init`은 기본 script를 등록하고 첫 동기화를 실행합니다. 에이전트는 UI 작업 전에 `sync:eds`를 한 번 실행합니다. `eds:doctor`는 커밋 직전에 동기화 상태와 font import를 읽기 전용 점검하고, Tailwind CSS v4 root가 있으면 `eds-*` class 이름도 확인합니다. `npx @spectrabrain/eds align`은 프로토타입 정렬 계획과 점검을 실행합니다. 모듈로 import하지 않습니다. |
117
118
  | `@spectrabrain/eds/components/Button/README.md` | Button 개요·사용 맥락·공개 API 문서입니다. |
118
119
  | `@spectrabrain/eds/components/Button/spec.json` | Button 공개 API와 접근성 계약을 위한 manifest입니다. |
119
120
  | `@spectrabrain/eds/llms.txt` | AI 문서 읽기 순서입니다. |
package/TAILWIND_V4.md CHANGED
@@ -10,7 +10,7 @@ CSS 진입점은 `@spectrabrain/eds/styles.css` 하나를 권장합니다. 개
10
10
 
11
11
  1. 「adapter 선택」 표에서 저장소에 맞는 행 하나를 골라 설치하고 연결합니다.
12
12
  2. 기존 앱 전역 CSS를 Tailwind root로 씁니다. 전체 import 구성은 `@import "tailwindcss";`를, 분할 구성은 `@import "tailwindcss/theme.css";`와 `@import "tailwindcss/utilities.css";`를 같은 파일에 둡니다.
13
- 3. `npm run sync:eds`를 실행합니다. script가 없으면 `npx @spectrabrain/eds init`을 실행합니다(패키지 매니저별 명령은 `CONSUMER_AGENT.md` 「첫 setup 절차」). init을 2단계보다 먼저 실행했다면 2단계 뒤에 sync를 다시 실행합니다.
13
+ 3. 직접 앱 설치에서 허용된 postinstall이 첫 sync를 하지 않았다면 AI 에이전트가 `npm run sync:eds`를 실행합니다. script가 없으면 `CONSUMER_AGENT.md` 「첫 setup 절차」의 `init` 명령(예: `npx @spectrabrain/eds init`)을 사용합니다. EDS 업데이트 뒤에는 changelog 조치를 적용하고 UI 작업 시작에 한 번 sync합니다.
14
14
  4. 「완료 기준」을 확인합니다.
15
15
 
16
16
  CSS가 `@tailwind` 지시어를 쓰는 Tailwind CSS v3 저장소는 이 절차 대신 `CONSUMER_AGENT.md` 「Tailwind root 결정」을 따릅니다.
@@ -82,7 +82,7 @@ sync는 설치된 package의 공개 `@spectrabrain/eds/tokens.json`에서 token
82
82
  - padding·margin·gap·radius에는 Tailwind CSS v4 기본 utility를 씁니다. 예: `p-4`, `m-2`, `gap-3`, `rounded-lg`. EDS token 별칭은 색상과 typography에만 생성합니다. 선택 기준은 `TOKEN_CONTEXT.md`를 따릅니다.
83
83
  - `@theme`의 EDS alias는 sync가 생성한 `var(--eds-*)` 참조만 두고, EDS를 업데이트할 때마다 `npm run sync:eds`로 다시 생성합니다.
84
84
  - `eds-tokens.css`는 `@theme`·`@utility`를 담으므로 Tailwind root CSS에서만 import합니다. `@spectrabrain/eds/styles.css`와 `eds-tokens.css`는 각각 한 곳에서만 import합니다.
85
- - `src/styles/eds-tokens.css`는 생성물이지만 저장소에 commit합니다. install은 이 파일을 만들지 않으므로, 파일이 없으면 Tailwind root의 `@import`가 깨지고, `pretypecheck`·`prebuild` hook(yarn berry는 `typecheck`·`build` 앞의 `eds doctor`)과 `--print-ci` CI job의 `eds doctor`가 `missing:`으로 실패합니다.
85
+ - `src/styles/eds-tokens.css`는 생성물이지만 저장소에 commit합니다. 설치 postinstall이나 에이전트의 UI 작업 시작 sync가 파일을 만듭니다. 커밋 전 doctor나 `--print-ci` CI job은 파일이 없으면 `missing:`으로 실패합니다. Doctor는 typecheck·build에는 연결되지 않습니다.
86
86
 
87
87
  ## Tailwind root 지정
88
88
 
@@ -94,7 +94,7 @@ EDS_TAILWIND_ROOT=src/app/styles/index.css npm run sync:eds
94
94
 
95
95
  ## 완료 기준
96
96
 
97
- 1. `npm run eds:doctor`가 `[EDS] synced with` 줄을 출력하고, 출력에 `No Tailwind root CSS found`·`Tailwind CSS v3 detected` note가 없습니다.
97
+ 1. 커밋 직전 `npm run eds:doctor`가 `[EDS] synced with` 줄을 출력하고, 출력에 `No Tailwind root CSS found`·`Tailwind CSS v3 detected` note가 없습니다.
98
98
  2. Vite 저장소는 `vite.config.*`의 `plugins`에 `@tailwindcss/vite`의 `tailwindcss()`가 있고, 그 밖의 저장소는 PostCSS 설정에 `@tailwindcss/postcss`가 있습니다. doctor는 이 연결을 점검하지 않습니다.
99
99
  3. `@spectrabrain/eds/styles.css`는 Tailwind root CSS나 앱 진입점 가운데 한 곳에서만 import됩니다.
100
100
 
@@ -643,8 +643,6 @@ export function renderPlan({
643
643
  ]),
644
644
  "",
645
645
  "완료 기준: " +
646
- code(commands.run("eds:doctor")) +
647
- "가 `[EDS] synced with` 줄을 출력하고 " +
648
646
  code(commands.run("build")) +
649
647
  "가 exit 0이며, Vite가 " +
650
648
  minimumVersions.vite +
@@ -692,7 +690,7 @@ export function renderPlan({
692
690
  " - `components.json`: `aliases`와 `tailwind.css`만 템플릿 값으로 바꾸고 `style`·`baseColor`는 유지합니다.",
693
691
  " - `package.json` scripts: `package.scripts.json`에서 없는 script만 추가하고, 추가한 뒤 " +
694
692
  code(commands.eds("init --no-sync")) +
695
- "로 `pretypecheck`·`prebuild` hook을 등록합니다. backend를 실행하는 script는 바꾸지 않습니다.",
693
+ "로 `sync:eds`·`eds:doctor`를 등록합니다. typecheck·build script에는 Doctor를 넣지 않습니다. backend를 실행하는 script는 바꾸지 않습니다.",
696
694
  " - 이전 lint·format 설정(`.eslintrc*`, `biome.json`, 중복 Prettier 설정)은 규칙을 옮긴 뒤 정리합니다" +
697
695
  (replacedCategories.has("lint-format") ? "(패키지 제거는 4단계)." : ".") +
698
696
  " 테스트·mock·다국어 파일과 설정은 그대로 둡니다. 기준선에 있던 항목을 바꾸지 않고 적용할 수 없으면 멈추고 사용자에게 확인합니다.",
@@ -714,11 +712,8 @@ export function renderPlan({
714
712
  ]
715
713
  .map(code)
716
714
  .join("·") +
717
- "가 exit 0입니다. 기존 `build.outDir`·`base`·`server.proxy`가 병합 전과 같고, " +
718
- (packageManager.berry
719
- ? "`typecheck` script가 `eds doctor && `로 시작하며"
720
- : "`package.json`의 `pretypecheck`가 `eds doctor`를 실행하며") +
721
- ", 「기준선」에 typecheck·lint 결과가 있습니다.",
715
+ "가 exit 0입니다. 기존 `build.outDir`·`base`·`server.proxy`가 병합 전과 같고, typecheck·build script에는 Doctor를 연결하지 않습니다. " +
716
+ "「기준선」에 typecheck·lint 결과가 있습니다.",
722
717
  "",
723
718
  "### 4. 라이브러리 정렬",
724
719
  "",
@@ -846,12 +841,11 @@ export function renderPlan({
846
841
  commands.run("lint"),
847
842
  commands.run("typecheck"),
848
843
  commands.run("build"),
849
- commands.run("eds:doctor"),
850
844
  alignCheck,
851
845
  ]
852
846
  .map(code)
853
847
  .join(", ") +
854
- "을 실행해 모두 exit 0이고 " +
848
+ "을 실행해 모두 exit 0인지 확인합니다. Doctor는 커밋 직전에 마지막으로 실행해 " +
855
849
  code(commands.run("eds:doctor")) +
856
850
  "가 `[EDS] synced with` 줄을 출력하는지 확인합니다.",
857
851
  backendImportsViteConfig && backendStartScript !== null
@@ -375,7 +375,7 @@ function conventionsPathFrom(packageDirectory, gitRoot, packageRoot) {
375
375
  }
376
376
 
377
377
  function verificationCommands(commands) {
378
- return ["format:check", "lint", "typecheck", "build", "eds:doctor"]
378
+ return ["format:check", "lint", "typecheck", "build"]
379
379
  .map((script) => commands.run(script))
380
380
  .join(", ");
381
381
  }
@@ -899,10 +899,12 @@ function runCheck({
899
899
  log(
900
900
  "[EDS] Also required: " +
901
901
  verificationCommands(commands) +
902
- " (each must exit 0, and eds:doctor must print [EDS] synced with)" +
902
+ " (each must exit 0). Before committing, run " +
903
+ commands.run("eds:doctor") +
904
+ " and confirm [EDS] synced with" +
903
905
  (state === null
904
906
  ? "."
905
- : ", then step 8 of " +
907
+ : ". Then complete step 8 of " +
906
908
  shown(alignDirectory + "/" + planFileName) +
907
909
  ".")
908
910
  );
package/consumer/cli.mjs CHANGED
@@ -8,9 +8,9 @@ const usage = [
8
8
  "Usage: eds <command> [options]",
9
9
  "",
10
10
  "Commands:",
11
- " init Add sync:eds and eds:doctor when missing; add pretypecheck/prebuild when target scripts exist",
12
- " and hooks are missing; write allowScripts on npm 12+, then sync in the package declaring @spectrabrain/eds",
13
- " sync Generate src/styles/eds-tokens.css, wire the Tailwind root CSS and update AGENTS.md",
11
+ " init Add sync:eds and eds:doctor when missing; remove obsolete Doctor lifecycle commands;",
12
+ " write allowScripts on npm 12+, then sync in the package declaring @spectrabrain/eds",
13
+ " sync Ensure EDS scripts, remove old Doctor lifecycle commands, wire Tailwind CSS and update AGENTS.md",
14
14
  " and the @AGENTS.md import in CLAUDE.md (or .claude/CLAUDE.md) and GEMINI.md when they exist",
15
15
  " (without a Tailwind root only those change); notes say when an agent may not load the block",
16
16
  " doctor Check sync status and the EDS font import; with a Tailwind CSS v4 root, also check that each eds-*",
@@ -20,8 +20,8 @@ const usage = [
20
20
  "",
21
21
  "Options:",
22
22
  " --only tailwind|agents sync: apply only that part",
23
- " --dry-run Print the files sync, init or align would write without writing them",
24
- " --no-sync init: register scripts only",
23
+ " --dry-run Print files and package scripts sync, init or align would change without writing them",
24
+ " --no-sync init: skip file sync but still register and migrate scripts",
25
25
  " --no-allow-scripts init: do not write allowScripts to package.json on npm 12+",
26
26
  " --print-ci github|gitlab init: print a CI job that runs eds doctor with this repository's package manager",
27
27
  " --warn doctor: report findings but exit 0 (same as EDS_DOCTOR=warn)",
@@ -33,7 +33,7 @@ const usage = [
33
33
  "",
34
34
  "Environment:",
35
35
  " EDS_TAILWIND_ROOT=src/index.css Tailwind root CSS when it cannot be detected (needed once: sync records",
36
- " it in package.json \"eds\": { \"tailwindRoot\" }, which doctor and the hooks reuse)",
36
+ " it in package.json \"eds\": { \"tailwindRoot\" }, which sync and doctor reuse)",
37
37
  " EDS_DOCTOR=warn|off Downgrade or silence doctor failures",
38
38
  ].join("\n");
39
39
 
@@ -149,7 +149,7 @@ export function findTailwindRoot(
149
149
  "Could not identify one Tailwind root CSS file (found " + found.length + ": " + found.join(", ") + "). " +
150
150
  "Ask the user which of these is the app's Tailwind root, then run " + tailwindRootEnvironmentVariable + "=<that file> " +
151
151
  runnerCommand(packageManager, "sync:eds") + " once. sync records the choice in package.json as \"" + consumerConfigField +
152
- "\": { \"" + tailwindRootConfigKey + "\": \"<that file>\" } so doctor and the hooks reuse it.",
152
+ "\": { \"" + tailwindRootConfigKey + "\": \"<that file>\" } so doctor and sync reuse it.",
153
153
  2,
154
154
  );
155
155
  }
package/consumer/init.mjs CHANGED
@@ -77,7 +77,7 @@ export function renderCiSnippet(target, packageManager) {
77
77
  }
78
78
 
79
79
  // npm 12+ blocks dependency install scripts unless package.json allows them. A name-only entry keeps
80
- // the EDS postinstall running on later installs and upgrades without re-approval.
80
+ // the EDS postinstall available for script maintenance and first-sync bootstrap.
81
81
  function writeAllowScripts(consumerRoot, { log, dryRun }) {
82
82
  const packagePath = path.join(consumerRoot, "package.json");
83
83
  const source = fs.readFileSync(packagePath, "utf8");
@@ -98,7 +98,7 @@ function writeAllowScripts(consumerRoot, { log, dryRun }) {
98
98
  }
99
99
  consumerPackage[allowScriptsField] = { ...(existing ?? {}), [packageName]: true };
100
100
  writeConsumerPackageJson(packagePath, source, consumerPackage);
101
- log("[EDS] wrote " + allowScriptsField + "[\"" + packageName + "\"] = true to package.json so npm " + minimumAllowScriptsNpmMajor + "+ runs the EDS postinstall on later installs.");
101
+ log("[EDS] wrote " + allowScriptsField + "[\"" + packageName + "\"] = true to package.json so npm " + minimumAllowScriptsNpmMajor + "+ can run the EDS postinstall on later installs.");
102
102
  return true;
103
103
  }
104
104
 
@@ -113,24 +113,23 @@ function printInstallScriptGuidance(consumerRoot, packageManager, { log, dryRun,
113
113
  }
114
114
  } else if (major === null) {
115
115
  log("[EDS] The npm version is unknown because init did not run through npm. If this project uses npm " + minimumAllowScriptsNpmMajor +
116
- "+, run " + approveCommand + ", or rerun " + cliCommand(packageManager, "init") + " so init can write " + allowScriptsField + ".");
116
+ "+, run " + approveCommand + ", or rerun " + cliCommand(packageManager, "init") + " so init can enable the EDS postinstall.");
117
117
  }
118
118
  return;
119
119
  }
120
- // The postinstall only re-registers the scripts init has just written, so approving it is optional everywhere
121
- // except npm 12+, where init records the approval itself.
120
+ // Install hooks are optional in package managers that require dependency build approval.
122
121
  if (name === "pnpm") {
123
- log("[EDS] pnpm: the scripts are registered, so the EDS postinstall needs no build approval. After upgrading EDS, run " +
124
- runnerCommand(packageManager, syncScriptName) + ".");
122
+ log("[EDS] pnpm: postinstall can sync EDS files but does not persist package.json script edits. The coding agent registers them with " +
123
+ cliCommand(packageManager, "sync") + " at the start of its next UI task.");
125
124
  return;
126
125
  }
127
126
  if (name === "bun") {
128
- log("[EDS] Optional (bun): to let the EDS postinstall re-register the scripts on later installs, add \"trustedDependencies\": [\"" +
127
+ log("[EDS] Optional (bun): to let the EDS postinstall bootstrap files and maintain scripts, add \"trustedDependencies\": [\"" +
129
128
  packageName + "\"] to package.json. It replaces bun's default trusted list, so this is the project owner's decision.");
130
129
  return;
131
130
  }
132
131
  if (name === "yarn" && berry) {
133
- log("[EDS] Optional (Yarn 2+): to let the EDS postinstall re-register the scripts on later installs, keep enableScripts: true in .yarnrc.yml " +
132
+ log("[EDS] Optional (Yarn 2+): to let the EDS postinstall bootstrap files and maintain scripts, keep enableScripts: true in .yarnrc.yml " +
134
133
  "or add \"dependenciesMeta\": { \"" + packageName + "\": { \"built\": true } } to package.json.");
135
134
  }
136
135
  }
@@ -159,7 +158,7 @@ export function runInit({
159
158
  1,
160
159
  );
161
160
  }
162
- // A workspace root or a parent folder can resolve a hoisted EDS; the scripts, hooks and AGENTS.md belong to the
161
+ // A workspace root or a parent folder can resolve a hoisted EDS; the scripts and AGENTS.md belong to the
163
162
  // app package that declares it.
164
163
  const consumerPackage = readPackageJson(consumerRoot);
165
164
  const declared = ["dependencies", "devDependencies", "optionalDependencies"].some((field) => consumerPackage?.[field]?.[packageName] !== undefined);
@@ -182,5 +181,5 @@ export function runInit({
182
181
  log("[EDS] Run " + registered.syncRunCommand + " to finish setup.");
183
182
  return 0;
184
183
  }
185
- return runSync({ consumerRoot, env, dryRun, log });
184
+ return runSync({ consumerRoot, env, dryRun, ensureScripts: false, log });
186
185
  }
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { renderRunnerCommands } from "./paths.mjs";
3
+ import { renderRunnerCommands, runnerCommand } from "./paths.mjs";
4
4
 
5
5
  export const beginMarker = "<!-- EDS:BEGIN -->";
6
6
  export const endMarker = "<!-- EDS:END -->";
@@ -21,13 +21,19 @@ export function readTemplateBlock(packageRoot) {
21
21
 
22
22
  // The template is written for npm; the rendered block uses the consumer's package-manager runner
23
23
  // (pnpm, yarn, bun run) so the commands an agent reads work in that repository.
24
- export function renderBlock(template, version, packageManager = null) {
24
+ export function renderBlock(template, version, packageManager = null, commands = null) {
25
25
  const versionLine = "<!-- EDS:VERSION " + version + " -->";
26
26
  const withoutVersion = template.replace(/^<!-- EDS:VERSION \S+ -->\r?\n/m, "");
27
27
  if (!withoutVersion.startsWith(beginMarker)) {
28
28
  throw new Error("CONSUMER_AGENT.md managed block must start with " + beginMarker + ".");
29
29
  }
30
- const body = renderRunnerCommands(withoutVersion.slice(beginMarker.length), packageManager);
30
+ let body = renderRunnerCommands(withoutVersion.slice(beginMarker.length), packageManager);
31
+ if (commands?.sync) {
32
+ body = body.replaceAll(runnerCommand(packageManager, "sync:eds"), commands.sync);
33
+ }
34
+ if (commands?.doctor) {
35
+ body = body.replaceAll(runnerCommand(packageManager, "eds:doctor"), commands.doctor);
36
+ }
31
37
  return beginMarker + "\n" + versionLine + body;
32
38
  }
33
39