byuckchon-frontend-cli 1.10.0 → 2.0.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/README.md CHANGED
@@ -251,6 +251,8 @@ color는 `@theme`의 `--color-*`로, typography는 `@utility text-*`로, motion
251
251
  ```text
252
252
  .github/workflows/eslint-convention-review.yml # 컨벤션 인라인 댓글
253
253
  .github/workflows/pr-check.yml # lint / typecheck / build 통과 여부 (bc init 전용)
254
+ .github/workflows/pr-description.yml # 커밋 내역을 PR 본문에 반영
255
+ .github/pull_request_template.md
254
256
  tools/review.config.mjs
255
257
  ```
256
258
 
@@ -277,6 +279,24 @@ PR이 `dev` 브랜치를 대상으로 할 때, workflow가 기계적으로 판
277
279
  | Convention Review | 파일명, export 방식, boolean 변수명 등 | PR 인라인 `BLOCKING` 또는 `WARNING` 댓글 |
278
280
  | AI 리뷰 | 설계·예외 처리·비즈니스 판단 | 별도 AI 리뷰 workflow에서 구성 |
279
281
 
282
+ ### PR 본문 자동 작성
283
+
284
+ `pr-description.yml` 이 PR 의 커밋을 타입별로 묶어 description 에 채워 넣습니다.
285
+
286
+ ```markdown
287
+ ### ✨ 기능
288
+ - **settings** — tsconfig 프리셋 추가 (a1b2c3d)
289
+
290
+ ### 🐛 수정
291
+ - letterSpacing % → em 변환 (b2c3d4e)
292
+ ```
293
+
294
+ 사람이 쓴 내용은 건드리지 않고 `<!-- byuckchon:commits:start -->` 마커 사이만 갱신하며,
295
+ 커밋을 추가로 푸시하면 목록도 따라 갱신됩니다. 머지 커밋은 제외하고, 컨벤션을 안 지킨
296
+ 커밋은 버리지 않고 "분류 없음"으로 모읍니다.
297
+
298
+ 생성되는 `.github/pull_request_template.md` 에 마커가 미리 들어 있습니다.
299
+
280
300
  같은 지적은 숨김 marker를 기준으로 중복 게시하지 않고, 메시지가 바뀌면 기존 댓글을 갱신합니다.
281
301
  모노레포에서는 workflow와 `tools/`가 루트에 한 번만 존재하며, PR에서 변경된 TypeScript 파일을
282
302
  대상으로 검사합니다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "byuckchon-frontend-cli",
3
- "version": "1.10.0",
3
+ "version": "2.0.0",
4
4
  "description": "Byuckchon Frontend Workbench — project starter + AI chat + codebase RAG + OpenAPI codegen",
5
5
  "type": "module",
6
6
  "engines": {
@@ -163,11 +163,12 @@ async function applyMonorepoConventions(appDir, config, scope) {
163
163
  compilerOptions: {
164
164
  // 공통 옵션은 config-typescript → settings 프리셋에 있다.
165
165
  tsBuildInfoFile: './node_modules/.tmp/tsconfig.tsbuildinfo',
166
- baseUrl: '.',
166
+ // baseUrl 은 TypeScript 7 에서 제거 대상이다.
167
+ // 생략하면 paths 가 이 tsconfig 파일 위치 기준으로 해석되므로 ./ 을 붙인다.
167
168
  paths: {
168
- '@/*': ['src/*'],
169
- '@icons/*': ['src/assets/icons/*'],
170
- '@images/*': ['src/assets/images/*'],
169
+ '@/*': ['./src/*'],
170
+ '@icons/*': ['./src/assets/icons/*'],
171
+ '@images/*': ['./src/assets/images/*'],
171
172
  },
172
173
  },
173
174
  include: ['src', 'vite.config.ts'],
@@ -183,7 +184,7 @@ async function applyMonorepoConventions(appDir, config, scope) {
183
184
  {
184
185
  extends: `@${scope}/config-typescript/next.json`,
185
186
  compilerOptions: {
186
- baseUrl: '.',
187
+ // baseUrl 없이 paths 만 쓴다. (TypeScript 7 에서 baseUrl 제거)
187
188
  paths: { '@/*': ['./src/*'] },
188
189
  },
189
190
  include: [
@@ -26,6 +26,116 @@ import { defineTokenConfig } from "@byuckchon-frontend/settings/tokens";
26
26
  export default defineTokenConfig();
27
27
  `;
28
28
 
29
+ // ─── AI 에이전트 가이드 ────────────────────────────────────────────────────────
30
+
31
+ /**
32
+ * AGENTS.md 를 만든다. Codex 와 bc chat 이 이 이름을 기본으로 찾고,
33
+ * CLAUDE.md 는 이 파일을 import 하는 한 줄짜리로 둬서 문서를 하나만 관리한다.
34
+ *
35
+ * 매 세션 컨텍스트에 실리므로 짧게 유지한다. 상세 API 는 각 패키지 README 로 넘긴다.
36
+ */
37
+ export function agentsDoc(framework) {
38
+ const isReact = framework === "react";
39
+
40
+ return `# 작업 규칙
41
+
42
+ 이 프로젝트에서 코드를 작성할 때 지켜야 할 것들입니다.
43
+
44
+ ## 1. 사내 패키지를 먼저 쓴다
45
+
46
+ 직접 구현하기 전에 아래 패키지에 이미 있는지 **반드시 먼저 확인하세요.**
47
+ 같은 기능을 새로 만들면 유지보수 비용이 프로젝트 수만큼 늘어납니다.
48
+
49
+ | 패키지 | 무엇이 있나 |
50
+ | --- | --- |
51
+ | \`@byuckchon-frontend/hooks\` | useDebounce, useThrottle, useTimer, useInfiniteScroll, useIntersectionObserver, useDetectClose, useAutoFocus, useFileUpload, usePagination, usePullToRefresh, useScrollTop, useCheckList, useMonthCalendar, useVisibilityEvent, usePasswordVisibility, useImpressionRef, useInstallPWA, useScrollToSelectedItem |
52
+ | \`@byuckchon-frontend/utils\` | 포맷(formatData), 검증(validate), 에러 처리(handleError), 쿼리 파라미터(filterParams), userAgent, sanitizeHtml, dateUtils, editorUtils |
53
+ | \`@byuckchon-frontend/core\` | Overlay, ErrorBoundary, SanitizeHtmlRender |
54
+ | \`@byuckchon-frontend/basic-ui\` | Accordion, Input, Checkbox, Toggle, Dropdown, Table, Tooltip, Pagination, Calendar, BottomSheet, Breadcrumb, Modal(Alert·Confirm·Choice), ToastMessage, UIThemeProvider |
55
+ | \`@byuckchon-frontend/settings\` | ESLint / Prettier / tsconfig 프리셋, 모션 토큰, 디자인 토큰 변환 |
56
+
57
+ **작업 순서**
58
+
59
+ 1. 위 표에서 찾아본다
60
+ 2. 애매하면 실제 export 를 확인한다 — 위 목록은 스냅샷이라 최신이 아닐 수 있다
61
+ \`\`\`bash
62
+ cat node_modules/@byuckchon-frontend/hooks/dist/index.d.ts
63
+ \`\`\`
64
+ 3. 없으면 그때 직접 구현한다
65
+
66
+ 없는 걸 억지로 끼워 맞추지는 마세요. 쓰임이 다르면 직접 만드는 게 맞습니다.
67
+
68
+ ## 2. 설정 파일은 직접 고치지 않는다
69
+
70
+ \`eslint.config.js\`, \`prettier.config.js\`, \`tsconfig.*.json\`, \`token.config.js\` 는
71
+ \`@byuckchon-frontend/settings\` 를 참조만 합니다. 규칙 본체는 node_modules 안에 있습니다.
72
+
73
+ 예외가 필요하면 **덮어쓰지 말고 뒤에 이어붙이세요.**
74
+
75
+ \`\`\`js
76
+ // eslint.config.js — 배열 뒤쪽이 이깁니다
77
+ import byuckchon from '@byuckchon-frontend/settings/eslint/react';
78
+
79
+ export default [
80
+ ...byuckchon,
81
+ { rules: { '@typescript-eslint/no-explicit-any': 'warn' } },
82
+ ];
83
+ \`\`\`
84
+
85
+ \`.vscode/settings.json\`, \`.nvmrc\`${isReact ? "" : ""} 같은 파일은 \`npx byuckchon-settings-sync\` 로 갱신합니다.
86
+
87
+ ## 3. 커밋 메시지
88
+
89
+ \`\`\`
90
+ <type>: <요약>
91
+ \`\`\`
92
+
93
+ \`feat\` \`fix\` \`refactor\` \`perf\` \`style\` \`docs\` \`test\` \`chore\`
94
+
95
+ **리뷰어가 확인해야 할 것은 커밋 본문에 남깁니다.** PR 본문의 "리뷰 포인트"로 자동 수집됩니다.
96
+
97
+ \`\`\`
98
+ feat: 주문 목록 API 연동
99
+
100
+ NOTE: 응답 스키마가 미확정이라 types/order.ts 에 any 가 남아 있습니다
101
+ TODO: 에러 처리 미구현 — 백엔드 에러 코드 확정 후 작업 예정
102
+ \`\`\`
103
+
104
+ 확신이 없거나, 임시로 둔 코드가 있거나, 리뷰어의 판단이 필요하면 **반드시 남기세요.**
105
+ 말없이 넘어가면 리뷰에서 놓칩니다.
106
+
107
+ ## 4. 브랜치 이름
108
+
109
+ \`\`\`
110
+ <type>/<작업 요약>/<작업자>
111
+ feature/update-mypage-style/hyuk
112
+ \`\`\`
113
+
114
+ PR 제목은 첫 토막이 대괄호로 자동으로 붙습니다. → \`[feature] 마이페이지 디자인 적용\`
115
+
116
+ ## 5. 폴더 구조
117
+
118
+ ${
119
+ isReact
120
+ ? `\`\`\`
121
+ src/lib 공용 로직·유틸 src/store 전역 상태
122
+ src/api API 호출 src/hooks 커스텀 훅
123
+ src/context Context src/components 컴포넌트
124
+ src/layouts 레이아웃 src/pages 페이지
125
+ src/assets 이미지·아이콘
126
+ \`\`\``
127
+ : `\`\`\`
128
+ src/app App Router src/components 컴포넌트
129
+ src/lib 공용 로직·유틸 src/hooks 커스텀 훅
130
+ src/providers Provider src/constant 상수
131
+ src/assets 이미지·아이콘
132
+ \`\`\``
133
+ }
134
+
135
+ 경로 별칭은 \`@/\` 를 씁니다. (\`@/lib/utils/cn\`)
136
+ `;
137
+ }
138
+
29
139
  // ─── 공통 설정 파일 ────────────────────────────────────────────────────────────
30
140
 
31
141
  async function createPrettierConfig(rootDir) {
@@ -213,11 +323,12 @@ export default defineConfig({
213
323
  extends: "@byuckchon-frontend/settings/tsconfig/react.json",
214
324
  compilerOptions: {
215
325
  tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
216
- baseUrl: ".",
326
+ // baseUrl 은 TypeScript 7 에서 제거 대상이다.
327
+ // 생략하면 paths 가 이 tsconfig 파일 위치 기준으로 해석되므로 ./ 을 붙인다.
217
328
  paths: {
218
- "@/*": ["src/*"],
219
- "@icons/*": ["src/assets/icons/*"],
220
- "@images/*": ["src/assets/images/*"],
329
+ "@/*": ["./src/*"],
330
+ "@icons/*": ["./src/assets/icons/*"],
331
+ "@images/*": ["./src/assets/images/*"],
221
332
  },
222
333
  },
223
334
  include: ["src"],
@@ -245,6 +356,8 @@ export default defineConfig({
245
356
  );
246
357
 
247
358
  await write(path.join(rootDir, ".nvmrc"), await readSettingsAsset("project/nvmrc"));
359
+ await write(path.join(rootDir, "AGENTS.md"), agentsDoc("react"));
360
+ await write(path.join(rootDir, "CLAUDE.md"), "@AGENTS.md\n");
248
361
 
249
362
  await createPrettierConfig(rootDir);
250
363
  await createEslintConfig(rootDir);
@@ -360,7 +473,7 @@ export default nextConfig;
360
473
  {
361
474
  extends: "@byuckchon-frontend/settings/tsconfig/next.json",
362
475
  compilerOptions: {
363
- baseUrl: ".",
476
+ // baseUrl 없이 paths 만 쓴다. (TypeScript 7 에서 baseUrl 제거)
364
477
  paths: { "@/*": ["./src/*"] },
365
478
  },
366
479
  include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
@@ -372,6 +485,8 @@ export default nextConfig;
372
485
  );
373
486
 
374
487
  await write(path.join(rootDir, ".nvmrc"), await readSettingsAsset("project/nvmrc"));
488
+ await write(path.join(rootDir, "AGENTS.md"), agentsDoc("next"));
489
+ await write(path.join(rootDir, "CLAUDE.md"), "@AGENTS.md\n");
375
490
 
376
491
  await createPrettierConfig(rootDir);
377
492
  await createNextEslintConfig(rootDir);
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
 
4
4
  import { versions } from '../constants/versions.js';
5
5
  import { readSettingsAsset } from '../utils/settingsAssets.js';
6
+ import { agentsDoc } from './createBaseFiles.js';
6
7
  import { createApp } from './createApp.js';
7
8
  import { scaffoldReviewAutomation } from './scaffoldReviewAutomation.js';
8
9
 
@@ -134,6 +135,10 @@ packages:
134
135
 
135
136
  await write(path.join(root, '.nvmrc'), await readSettingsAsset('project/nvmrc'));
136
137
 
138
+ // AI 에이전트 가이드 — 루트에 두면 모든 앱에서 공통으로 읽힌다.
139
+ await write(path.join(root, 'AGENTS.md'), agentsDoc(config.framework));
140
+ await write(path.join(root, 'CLAUDE.md'), '@AGENTS.md\n');
141
+
137
142
  await write(
138
143
  path.join(root, 'prettier.config.mjs'),
139
144
  `// 포맷 규칙은 @byuckchon-frontend/settings 가 관리합니다.
@@ -74,7 +74,7 @@ async function copyFileIfAllowed(source, target, overwrite) {
74
74
  * @param {'single' | 'monorepo'} args.projectType 생성할 프로젝트 유형
75
75
  * @param {boolean} [args.overwrite=true] 기존 파일을 템플릿으로 덮어쓸지
76
76
  * @param {string[]} [args.exclude=[]] 제외할 워크플로 이름 (확장자·유형 접미사 제외)
77
- * @returns {Promise<{ toolsDir: string, workflows: string[] }>}
77
+ * @returns {Promise<{ toolsDir: string, workflows: string[], pullRequestTemplate: boolean }>}
78
78
  */
79
79
  export async function scaffoldReviewAutomation({
80
80
  projectRoot,
@@ -111,5 +111,16 @@ export async function scaffoldReviewAutomation({
111
111
  if (copied) copiedWorkflows.push(target);
112
112
  }
113
113
 
114
- return { toolsDir: toolsTargetDir, workflows: copiedWorkflows };
114
+ // PR 템플릿 — 커밋 내역이 채워질 마커를 품고 있다.
115
+ const pullRequestTemplate = await copyFileIfAllowed(
116
+ path.join(TEMPLATE_ROOT, 'github', 'pull_request_template.md'),
117
+ path.join(projectRoot, '.github', 'pull_request_template.md'),
118
+ overwrite,
119
+ );
120
+
121
+ return {
122
+ toolsDir: toolsTargetDir,
123
+ workflows: copiedWorkflows,
124
+ pullRequestTemplate,
125
+ };
115
126
  }
@@ -0,0 +1,30 @@
1
+ ## 작업 내용
2
+
3
+ <!-- 무엇을, 왜 바꿨는지 적어주세요. -->
4
+
5
+ ## 확인 사항
6
+
7
+ <!-- 리뷰어가 중점적으로 봐야 할 부분이 있다면 적어주세요. -->
8
+
9
+ ## 테스트
10
+
11
+ - [ ] 로컬에서 동작 확인
12
+ - [ ] `lint` / `typecheck` / `build` 통과
13
+
14
+ <!--
15
+ 아래 마커 사이는 워크플로가 자동으로 채웁니다. 직접 수정하지 마세요.
16
+
17
+ - 커밋 내역: 커밋 메시지 첫 줄을 타입별로 묶습니다. (feat / fix / docs ...)
18
+ - 리뷰 포인트: 커밋 본문에 NOTE: 또는 TODO: 로 적은 줄을 모읍니다.
19
+
20
+ feat: 주문 목록 API 연동
21
+
22
+ NOTE: 응답 스키마가 미확정이라 any 가 남아 있습니다
23
+ TODO: 에러 처리 미구현
24
+
25
+ PR 제목은 브랜치명의 첫 토막이 대괄호로 붙습니다.
26
+ feature/update-mypage-style/hyuk + "마이페이지 디자인 적용"
27
+ → "[feature] 마이페이지 디자인 적용"
28
+ -->
29
+ <!-- byuckchon:commits:start -->
30
+ <!-- byuckchon:commits:end -->
@@ -0,0 +1,58 @@
1
+ # PR 본문에 커밋 내역을 자동으로 채워 넣습니다.
2
+ #
3
+ # 사람이 쓴 내용은 건드리지 않고, 아래 마커 사이만 갱신합니다.
4
+ # <!-- byuckchon:commits:start --> ~ <!-- byuckchon:commits:end -->
5
+ # 마커가 없으면 본문 끝에 한 번 덧붙입니다. (PR 템플릿이 없어도 동작)
6
+ #
7
+ # 커밋 메시지를 `feat:` `fix:` 처럼 쓰면 타입별로 묶이고,
8
+ # 컨벤션을 안 지킨 커밋은 "분류 없음"으로 모입니다.
9
+ #
10
+ # 커밋 본문에 NOTE: 또는 TODO: 로 적은 줄은 "리뷰 포인트"로 따로 모입니다.
11
+ # AI 로 코드를 짤 때 "여긴 리뷰어가 봐야 한다"를 남겨두는 용도로 쓰세요.
12
+ #
13
+ # PR 제목에는 브랜치명의 첫 토막이 대괄호로 붙습니다.
14
+ # feature/update-mypage-style/hyuk + "마이페이지 디자인 적용"
15
+ # → "[feature] 마이페이지 디자인 적용"
16
+ # 사람이 쓴 제목은 그대로 두고 앞에만 붙이며, 이미 대괄호가 있으면 건드리지 않습니다.
17
+ #
18
+ # 복사된 파일이므로 프로젝트 소유입니다. 대상 브랜치 등은 자유롭게 수정하세요.
19
+
20
+ name: PR Description
21
+
22
+ on:
23
+ pull_request:
24
+ types: [opened, synchronize, reopened]
25
+ branches:
26
+ - dev
27
+
28
+ concurrency:
29
+ group: pr-description-${{ github.event.pull_request.number }}
30
+ cancel-in-progress: true
31
+
32
+ jobs:
33
+ describe:
34
+ name: 커밋 내역 반영
35
+ # changeset 릴리즈 PR 처럼 봇이 연 PR 은 본문을 그대로 둔다.
36
+ if: ${{ !endsWith(github.event.pull_request.user.login, '[bot]') }}
37
+ runs-on: ubuntu-latest
38
+ permissions:
39
+ contents: read
40
+ pull-requests: write
41
+
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+
45
+ - uses: actions/setup-node@v4
46
+ with:
47
+ node-version-file: .nvmrc
48
+
49
+ - name: PR 본문 갱신
50
+ env:
51
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52
+ REPO: ${{ github.repository }}
53
+ PR_NUMBER: ${{ github.event.pull_request.number }}
54
+ run: |
55
+ # 프로젝트가 고정한 settings 버전을 그대로 사용합니다.
56
+ # (전체 의존성 설치 없이 이 패키지만 받아 실행)
57
+ VERSION=$(node -p "const p=require('./package.json'); (p.devDependencies?.['@byuckchon-frontend/settings'] ?? p.dependencies?.['@byuckchon-frontend/settings'] ?? 'latest')")
58
+ npx --yes --package "@byuckchon-frontend/settings@${VERSION}" byuckchon-pr-description