byuckchon-frontend-cli 1.9.6 → 1.10.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.
@@ -1,7 +1,10 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
 
4
+ import { versions } from '../constants/versions.js';
5
+ import { readSettingsAsset } from '../utils/settingsAssets.js';
4
6
  import { createApp } from './createApp.js';
7
+ import { scaffoldReviewAutomation } from './scaffoldReviewAutomation.js';
5
8
 
6
9
  /**
7
10
  * 새 pnpm 모노레포를 스캐폴드한다. (marketd-frontend 구조 참고)
@@ -32,6 +35,7 @@ export async function createMonorepo(config) {
32
35
  await writeRootFiles(root, config, scope);
33
36
  await writeConfigTypescript(root, scope);
34
37
  await writeConfigEslint(root, scope);
38
+ await scaffoldReviewAutomation({ projectRoot: root, projectType: 'monorepo' });
35
39
 
36
40
  // 최초 앱 하나만 생성. 이후 추가는 `bc add`.
37
41
  const appName = config.appName;
@@ -71,15 +75,17 @@ async function writeRootFiles(root, config, scope) {
71
75
  typecheck: 'turbo run typecheck',
72
76
  'tokens:build': 'turbo run tokens:build',
73
77
  format:
74
- 'prettier --write "**/*.{ts,tsx,js,jsx,json,md,yml,yaml}" --ignore-path .gitignore',
78
+ 'prettier --write "**/*.{ts,tsx,js,jsx,cjs,json,md,yml,yaml}" --ignore-path .gitignore',
75
79
  'format:check':
76
- 'prettier --check "**/*.{ts,tsx,js,jsx,json,md,yml,yaml}" --ignore-path .gitignore',
80
+ 'prettier --check "**/*.{ts,tsx,js,jsx,cjs,json,md,yml,yaml}" --ignore-path .gitignore',
77
81
  clean: 'turbo run clean && rm -rf node_modules .turbo',
78
82
  preinstall: 'npx only-allow pnpm',
79
83
  // 최초 앱 실행 단축키 (bc add 시 앱마다 추가됨).
80
84
  [config.appName]: `pnpm --filter @${scope}/${config.appName} dev`,
81
85
  },
82
86
  devDependencies: {
87
+ // 루트의 prettier.config.mjs 와 tsconfig.base.json 이 직접 참조한다.
88
+ '@byuckchon-frontend/settings': versions['@byuckchon-frontend/settings'],
83
89
  '@types/node': '^22.0.0',
84
90
  eslint: '^9.18.0',
85
91
  'eslint-config-prettier': '^10.1.8',
@@ -100,58 +106,22 @@ packages:
100
106
  `,
101
107
  );
102
108
 
103
- await writeJson(path.join(root, 'turbo.json'), {
104
- $schema: 'https://turborepo.org/schema.json',
105
- ui: 'tui',
106
- globalDependencies: ['tsconfig.base.json', '.env', '.env.*', '!.env*.local'],
107
- globalEnv: ['NODE_ENV', 'CI'],
108
- tasks: {
109
- build: {
110
- dependsOn: ['^build'],
111
- outputs: ['dist/**', 'build/**', '.next/**', '!.next/cache/**', 'out/**'],
112
- inputs: [
113
- '$TURBO_DEFAULT$',
114
- '!**/*.md',
115
- '!**/*.test.ts',
116
- '!**/*.test.tsx',
117
- '!**/*.spec.ts',
118
- '!**/*.spec.tsx',
119
- ],
120
- },
121
- dev: { cache: false, persistent: true },
122
- lint: { dependsOn: ['^build'], outputs: [] },
123
- typecheck: { dependsOn: ['^build'], outputs: ['.tsbuildinfo', '**/*.tsbuildinfo'] },
124
- 'tokens:build': { outputs: ['src/tokens.css'] },
125
- clean: { cache: false },
126
- },
127
- });
109
+ // turbo / .npmrc / .nvmrc 는 참조 문법이 없어서 내용을 복사한다.
110
+ // 이후 settings 가 바뀌면 `npx byuckchon-settings-sync` 로 갱신한다.
111
+ await write(path.join(root, 'turbo.json'), await readSettingsAsset('project/turbo.json'));
128
112
 
113
+ // 공통 옵션은 @byuckchon-frontend/settings 가 관리한다.
114
+ // 이 파일은 모노레포 전용 예외를 얹는 자리로만 남긴다.
129
115
  await writeJson(path.join(root, 'tsconfig.base.json'), {
130
116
  $schema: 'https://json.schemastore.org/tsconfig',
131
- display: `${name} Base`,
117
+ display: `${config.projectName} Base`,
118
+ extends: '@byuckchon-frontend/settings/tsconfig/base.json',
132
119
  compilerOptions: {
133
- target: 'ES2022',
134
- lib: ['ES2022'],
135
- module: 'ESNext',
136
- moduleResolution: 'Bundler',
137
- strict: true,
138
120
  noUncheckedIndexedAccess: true,
139
121
  noImplicitOverride: true,
140
- noFallthroughCasesInSwitch: true,
141
- useUnknownInCatchVariables: true,
142
- exactOptionalPropertyTypes: false,
143
- esModuleInterop: true,
144
122
  allowSyntheticDefaultImports: true,
145
- forceConsistentCasingInFileNames: true,
146
- resolveJsonModule: true,
147
- isolatedModules: true,
148
- verbatimModuleSyntax: false,
149
- skipLibCheck: true,
150
123
  incremental: true,
151
- composite: false,
152
- types: [],
153
124
  },
154
- exclude: ['node_modules', 'dist', 'build', '.turbo', '.next', 'coverage'],
155
125
  });
156
126
 
157
127
  await writeJson(path.join(root, 'tsconfig.json'), {
@@ -160,42 +130,19 @@ packages:
160
130
  include: [],
161
131
  });
162
132
 
163
- await write(
164
- path.join(root, '.npmrc'),
165
- `# pnpm 동작 설정
166
- # React 버전 통일 및 (향후 Expo/RN 도입 대비) hoisted linker 사용.
167
- node-linker=hoisted
168
-
169
- public-hoist-pattern[]=*react*
170
- public-hoist-pattern[]=*@types/*
171
- public-hoist-pattern[]=*eslint*
172
- public-hoist-pattern[]=*prettier*
173
-
174
- strict-peer-dependencies=false
175
- auto-install-peers=true
176
- save-exact=false
177
- save-prefix=^
178
- prefer-frozen-lockfile=true
179
- `,
180
- );
133
+ await write(path.join(root, '.npmrc'), await readSettingsAsset('project/npmrc'));
181
134
 
182
- await write(path.join(root, '.nvmrc'), '20\n');
135
+ await write(path.join(root, '.nvmrc'), await readSettingsAsset('project/nvmrc'));
183
136
 
184
137
  await write(
185
138
  path.join(root, 'prettier.config.mjs'),
186
- `/** @type {import("prettier").Config} */
139
+ `// 포맷 규칙은 @byuckchon-frontend/settings 가 관리합니다.
140
+ // 이 모노레포 전용 예외가 필요하면 펼쳐서 덮어쓰세요.
141
+ import byuckchon from '@byuckchon-frontend/settings/prettier';
142
+
143
+ /** @type {import("prettier").Config} */
187
144
  export default {
188
- semi: true,
189
- singleQuote: true,
190
- trailingComma: 'all',
191
- tabWidth: 2,
192
- printWidth: 100,
193
- arrowParens: 'always',
194
- endOfLine: 'lf',
195
- bracketSpacing: true,
196
- bracketSameLine: false,
197
- jsxSingleQuote: false,
198
- plugins: ['prettier-plugin-tailwindcss'],
145
+ ...byuckchon,
199
146
  overrides: [
200
147
  {
201
148
  files: ['*.json', '*.md', '*.yml', '*.yaml'],
@@ -203,7 +150,7 @@ export default {
203
150
  },
204
151
  ],
205
152
  };
206
- `,
153
+ `
207
154
  );
208
155
 
209
156
  await write(
@@ -311,106 +258,54 @@ async function writeConfigTypescript(root, scope) {
311
258
  const dir = path.join(root, 'packages', 'config-typescript');
312
259
  await fs.mkdir(dir, { recursive: true });
313
260
 
261
+ // 프리셋 본체는 @byuckchon-frontend/settings 가 관리한다.
262
+ // 이 패키지는 모노레포 전용 예외를 얹을 자리로만 남긴다.
314
263
  await writeJson(path.join(dir, 'package.json'), {
315
264
  name: `@${scope}/config-typescript`,
316
265
  version: '0.0.0',
317
266
  private: true,
318
- description: `Shared TypeScript config presets for @${scope} apps & packages`,
267
+ description: 'settings 의 TypeScript 프리셋을 이 모노레포용으로 감싼 패키지',
319
268
  files: ['base.json', 'library.json', 'react.json', 'next.json', 'node.json'],
320
- });
321
-
322
- await writeJson(path.join(dir, 'base.json'), {
323
- $schema: 'https://json.schemastore.org/tsconfig',
324
- display: 'Base',
325
- extends: '../../tsconfig.base.json',
326
- });
327
-
328
- await writeJson(path.join(dir, 'react.json'), {
329
- $schema: 'https://json.schemastore.org/tsconfig',
330
- display: 'React Web (Vite)',
331
- extends: './base.json',
332
- compilerOptions: {
333
- lib: ['ES2022', 'DOM', 'DOM.Iterable'],
334
- jsx: 'react-jsx',
335
- moduleResolution: 'Bundler',
336
- module: 'ESNext',
337
- noEmit: true,
338
- allowImportingTsExtensions: true,
339
- useDefineForClassFields: true,
340
- types: ['vite/client'],
341
- noUncheckedIndexedAccess: false,
342
- },
343
- });
344
-
345
- await writeJson(path.join(dir, 'next.json'), {
346
- $schema: 'https://json.schemastore.org/tsconfig',
347
- display: 'Next.js (App Router)',
348
- extends: './base.json',
349
- compilerOptions: {
350
- lib: ['ES2022', 'DOM', 'DOM.Iterable'],
351
- jsx: 'preserve',
352
- module: 'ESNext',
353
- moduleResolution: 'Bundler',
354
- noEmit: true,
355
- allowJs: true,
356
- incremental: true,
357
- plugins: [{ name: 'next' }],
358
- noUncheckedIndexedAccess: false,
269
+ dependencies: {
270
+ '@byuckchon-frontend/settings': versions['@byuckchon-frontend/settings'],
359
271
  },
360
272
  });
361
273
 
362
- await writeJson(path.join(dir, 'library.json'), {
274
+ const preset = (display, name) => ({
363
275
  $schema: 'https://json.schemastore.org/tsconfig',
364
- display: 'Library (packages/*)',
365
- extends: './base.json',
366
- compilerOptions: {
367
- declaration: true,
368
- declarationMap: true,
369
- sourceMap: true,
370
- outDir: 'dist',
371
- rootDir: 'src',
372
- composite: true,
373
- },
276
+ display,
277
+ extends: `@byuckchon-frontend/settings/tsconfig/${name}.json`,
374
278
  });
375
279
 
376
- await writeJson(path.join(dir, 'node.json'), {
377
- $schema: 'https://json.schemastore.org/tsconfig',
378
- display: 'Node (scripts)',
379
- extends: './base.json',
380
- compilerOptions: {
381
- lib: ['ES2022'],
382
- module: 'NodeNext',
383
- moduleResolution: 'NodeNext',
384
- types: ['node'],
385
- },
386
- });
280
+ await writeJson(path.join(dir, 'base.json'), preset('Base', 'base'));
281
+ await writeJson(path.join(dir, 'react.json'), preset('React Web (Vite)', 'react'));
282
+ await writeJson(path.join(dir, 'next.json'), preset('Next.js (App Router)', 'next'));
283
+ await writeJson(path.join(dir, 'library.json'), preset('Library (packages/*)', 'library'));
284
+ await writeJson(path.join(dir, 'node.json'), preset('Node (scripts)', 'node'));
387
285
  }
388
286
 
389
287
  async function writeConfigEslint(root, scope) {
390
288
  const dir = path.join(root, 'packages', 'config-eslint');
391
289
  await fs.mkdir(dir, { recursive: true });
392
290
 
291
+ // 규칙 본체는 @byuckchon-frontend/settings 가 관리한다.
292
+ // 이 패키지는 모노레포 전용 예외를 얹을 자리로만 남긴다.
393
293
  await writeJson(path.join(dir, 'package.json'), {
394
294
  name: `@${scope}/config-eslint`,
395
295
  version: '0.0.0',
396
296
  private: true,
397
297
  type: 'module',
398
- description: `Shared ESLint flat configs for @${scope} apps & packages`,
298
+ description: 'settings 의 ESLint 프리셋을 이 모노레포용으로 감싼 패키지',
399
299
  main: './base.js',
400
300
  exports: {
401
301
  '.': './base.js',
402
302
  './base': './base.js',
403
303
  './react': './react.js',
304
+ './next': './next.js',
404
305
  },
405
- files: ['base.js', 'react.js'],
306
+ files: ['base.js', 'react.js', 'next.js'],
406
307
  dependencies: {
407
- '@eslint/js': '^9.18.0',
408
- 'eslint-config-prettier': '^10.1.8',
409
- 'eslint-plugin-import': '^2.32.0',
410
- 'eslint-plugin-react': '^7.37.4',
411
- 'eslint-plugin-react-hooks': '^5.1.0',
412
- globals: '^15.14.0',
413
- 'typescript-eslint': '^8.59.1',
308
+ '@byuckchon-frontend/settings': versions['@byuckchon-frontend/settings'],
414
309
  },
415
310
  peerDependencies: {
416
311
  eslint: '^9.0.0',
@@ -418,97 +313,17 @@ async function writeConfigEslint(root, scope) {
418
313
  },
419
314
  });
420
315
 
421
- await write(
422
- path.join(dir, 'base.js'),
423
- `// @ts-check
424
- import js from '@eslint/js';
425
- import tseslint from 'typescript-eslint';
426
- import prettier from 'eslint-config-prettier';
427
- import importPlugin from 'eslint-plugin-import';
428
- import globals from 'globals';
316
+ const reexport = (name, named) => `// 규칙 본체는 @byuckchon-frontend/settings 가 관리합니다.
317
+ // 이 모노레포에만 해당하는 예외는 아래 배열에 이어붙이세요.
318
+ import byuckchon from '@byuckchon-frontend/settings/eslint/${name}';
429
319
 
430
- /**
431
- * 공통 ESLint flat config (TS 베이스).
432
- * @type {import("eslint").Linter.Config[]}
433
- */
434
- export const baseConfig = [
435
- {
436
- ignores: [
437
- '**/node_modules/**',
438
- '**/dist/**',
439
- '**/build/**',
440
- '**/out/**',
441
- '**/.next/**',
442
- '**/.turbo/**',
443
- '**/coverage/**',
444
- '**/*.d.ts',
445
- ],
446
- },
447
- js.configs.recommended,
448
- ...tseslint.configs.recommended,
449
- {
450
- languageOptions: {
451
- ecmaVersion: 2022,
452
- sourceType: 'module',
453
- globals: { ...globals.es2022 },
454
- },
455
- plugins: { import: importPlugin },
456
- rules: {
457
- 'no-console': ['warn', { allow: ['warn', 'error'] }],
458
- '@typescript-eslint/consistent-type-imports': [
459
- 'warn',
460
- { prefer: 'type-imports', fixStyle: 'inline-type-imports' },
461
- ],
462
- '@typescript-eslint/no-unused-vars': [
463
- 'warn',
464
- { argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
465
- ],
466
- },
467
- },
468
- prettier,
469
- ];
470
-
471
- export default baseConfig;
472
- `,
473
- );
474
-
475
- await write(
476
- path.join(dir, 'react.js'),
477
- `// @ts-check
478
- import react from 'eslint-plugin-react';
479
- import reactHooks from 'eslint-plugin-react-hooks';
480
- import globals from 'globals';
320
+ /** @type {import("eslint").Linter.Config[]} */
321
+ export const ${named} = [...byuckchon];
481
322
 
482
- import { baseConfig } from './base.js';
323
+ export default ${named};
324
+ `;
483
325
 
484
- /**
485
- * React (Vite/Next) 앱용 ESLint config.
486
- * @type {import("eslint").Linter.Config[]}
487
- */
488
- export const reactConfig = [
489
- ...baseConfig,
490
- {
491
- files: ['**/*.{js,jsx,ts,tsx}'],
492
- languageOptions: {
493
- globals: { ...globals.browser, ...globals.es2022 },
494
- parserOptions: { ecmaFeatures: { jsx: true } },
495
- },
496
- plugins: { react, 'react-hooks': reactHooks },
497
- settings: { react: { version: 'detect' } },
498
- rules: {
499
- ...react.configs.recommended.rules,
500
- ...react.configs['jsx-runtime'].rules,
501
- ...reactHooks.configs.recommended.rules,
502
- 'react/prop-types': 'off',
503
- 'react/react-in-jsx-scope': 'off',
504
- 'react/no-unescaped-entities': 'off',
505
- 'react-hooks/rules-of-hooks': 'warn',
506
- '@typescript-eslint/no-explicit-any': 'off',
507
- },
508
- },
509
- ];
510
-
511
- export default reactConfig;
512
- `,
513
- );
326
+ await write(path.join(dir, 'base.js'), reexport('base', 'baseConfig'));
327
+ await write(path.join(dir, 'react.js'), reexport('react', 'reactConfig'));
328
+ await write(path.join(dir, 'next.js'), reexport('next', 'nextConfig'));
514
329
  }
@@ -16,17 +16,26 @@ export async function createPackageJson(rootDir, config) {
16
16
  dev: 'vite',
17
17
  build: 'tsc -b && vite build',
18
18
  'tokens:build': 'style-dictionary build --config token.config.js',
19
+ // PR Check workflow 가 lint / typecheck / build 를 각각 호출한다.
20
+ typecheck: 'tsc -b',
19
21
  lint: 'eslint . --ext ts,tsx',
20
22
  preview: 'vite preview',
21
- format: 'prettier --write "src/**/*.{ts,tsx,css}"',
23
+ format:
24
+ 'prettier --write "src/**/*.{ts,tsx,css}" "tools/**/*.{js,cjs,json,md}"',
25
+ 'format:check':
26
+ 'prettier --check "src/**/*.{ts,tsx,css}" "tools/**/*.{js,cjs,json,md}"',
22
27
  }
23
28
  : {
24
29
  dev: 'next dev',
25
30
  build: 'next build',
26
31
  'tokens:build': 'style-dictionary build --config token.config.js',
32
+ typecheck: 'tsc --noEmit',
27
33
  start: 'next start',
28
- lint: 'next lint',
29
- format: 'prettier --write "src/**/*.{ts,tsx,css}"',
34
+ lint: 'eslint .',
35
+ format:
36
+ 'prettier --write "src/**/*.{ts,tsx,css}" "tools/**/*.{js,cjs,json,md}"',
37
+ 'format:check':
38
+ 'prettier --check "src/**/*.{ts,tsx,css}" "tools/**/*.{js,cjs,json,md}"',
30
39
  },
31
40
  dependencies: {
32
41
  react: isReact ? versions.react : versions['next-react'],
@@ -37,9 +46,12 @@ export async function createPackageJson(rootDir, config) {
37
46
  ...(isReact
38
47
  ? {
39
48
  axios: versions.axios,
49
+ 'react-router-dom': versions['react-router-dom'],
40
50
  }
41
51
  : {}),
42
52
  zod: versions.zod,
53
+ clsx: versions.clsx,
54
+ 'tailwind-merge': versions['tailwind-merge'],
43
55
  },
44
56
  devDependencies: {
45
57
  '@types/react': versions['@types/react'],
@@ -47,14 +59,10 @@ export async function createPackageJson(rootDir, config) {
47
59
  '@types/node': versions['@types/node'],
48
60
  '@trivago/prettier-plugin-sort-imports':
49
61
  versions['@trivago/prettier-plugin-sort-imports'],
62
+ // eslint/prettier/tsconfig/tokens 설정과 motion CSS 가 모두 이 패키지를 참조한다.
63
+ // (ESLint 플러그인도 이 패키지가 의존성으로 들고 온다)
64
+ '@byuckchon-frontend/settings': versions['@byuckchon-frontend/settings'],
50
65
  eslint: versions.eslint,
51
- 'eslint-config-expo': versions['eslint-config-expo'],
52
- 'eslint-import-resolver-typescript':
53
- versions['eslint-import-resolver-typescript'],
54
- 'eslint-plugin-import': versions['eslint-plugin-import'],
55
- 'eslint-plugin-react': versions['eslint-plugin-react'],
56
- 'eslint-plugin-react-hooks': versions['eslint-plugin-react-hooks'],
57
- 'eslint-plugin-unused-imports': versions['eslint-plugin-unused-imports'],
58
66
  prettier: versions.prettier,
59
67
  'prettier-plugin-tailwindcss': versions['prettier-plugin-tailwindcss'],
60
68
  'style-dictionary': versions['style-dictionary'],
@@ -63,9 +71,6 @@ export async function createPackageJson(rootDir, config) {
63
71
  ...(isReact
64
72
  ? {
65
73
  '@tailwindcss/vite': versions['@tailwindcss/vite'],
66
- '@typescript-eslint/eslint-plugin':
67
- versions['@typescript-eslint/eslint-plugin'],
68
- '@typescript-eslint/parser': versions['@typescript-eslint/parser'],
69
74
  '@vitejs/plugin-react': versions['@vitejs/plugin-react'],
70
75
  vite: versions.vite,
71
76
  'vite-plugin-svgr': versions['vite-plugin-svgr'],
@@ -74,6 +79,7 @@ export async function createPackageJson(rootDir, config) {
74
79
  '@tailwindcss/postcss': versions['@tailwindcss/postcss'],
75
80
  '@svgr/webpack': versions['@svgr/webpack'],
76
81
  'eslint-config-next': versions['eslint-config-next'],
82
+ '@eslint/eslintrc': versions['@eslint/eslintrc'],
77
83
  }),
78
84
  },
79
85
  };
@@ -1,22 +1,18 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import { exec as execCallback } from 'child_process';
4
- import { promisify } from 'util';
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { exec as execCallback } from "child_process";
4
+ import { promisify } from "util";
5
5
 
6
- import { createBaseFiles } from './createBaseFiles.js';
7
- import { createBcConfig } from './createBcConfig.js';
8
- import { createFolders } from './createFolders.js';
9
- import { createPackageJson } from './createPackageJson.js';
10
- import { createReadme } from './createReadme.js';
11
- import { scaffoldApiConventionDoc } from './apiConventionDoc.js';
6
+ import { createBaseFiles } from "./createBaseFiles.js";
7
+ import { createBcConfig } from "./createBcConfig.js";
8
+ import { createFolders } from "./createFolders.js";
9
+ import { createPackageJson } from "./createPackageJson.js";
10
+ import { createReadme } from "./createReadme.js";
11
+ import { scaffoldApiConventionDoc } from "./apiConventionDoc.js";
12
+ import { scaffoldReviewAutomation } from "./scaffoldReviewAutomation.js";
13
+ import { BYUCKCHON_PACKAGES } from "./install.js";
12
14
 
13
15
  const exec = promisify(execCallback);
14
- const BYUCKCHON_PACKAGES = [
15
- '@byuckchon-frontend/hooks',
16
- '@byuckchon-frontend/utils',
17
- '@byuckchon-frontend/basic-ui',
18
- '@byuckchon-frontend/core',
19
- ];
20
16
 
21
17
  export async function createProject(config) {
22
18
  const rootDir = path.resolve(config.projectName);
@@ -27,10 +23,17 @@ export async function createProject(config) {
27
23
  await createBaseFiles(rootDir, config);
28
24
  await createReadme(rootDir, config);
29
25
  // API 코드 컨벤션 .md 를 프레임워크에 맞는 API 루트(src/api | src/lib/api)에 깐다.
30
- await scaffoldApiConventionDoc({ projectRoot: rootDir, framework: config.framework });
26
+ await scaffoldApiConventionDoc({
27
+ projectRoot: rootDir,
28
+ framework: config.framework,
29
+ });
31
30
  await createBcConfig(rootDir, config);
31
+ await scaffoldReviewAutomation({
32
+ projectRoot: rootDir,
33
+ projectType: "single",
34
+ });
32
35
 
33
36
  // 최신 버전(latest 포함) 의존성을 실제로 설치해 lockfile까지 생성
34
- await exec('npm install', { cwd: rootDir });
35
- await exec(`npm install ${BYUCKCHON_PACKAGES.join(' ')}`, { cwd: rootDir });
37
+ await exec("npm install", { cwd: rootDir });
38
+ await exec(`npm install ${BYUCKCHON_PACKAGES.join(" ")}`, { cwd: rootDir });
36
39
  }
@@ -10,7 +10,7 @@ export async function createReadme(rootDir, config) {
10
10
 
11
11
  | 항목 | 내용 |
12
12
  |------|------|
13
- | Framework | ${isReact ? 'React 19' : 'Next.js 15 (App Router)'} |
13
+ | Framework | ${isReact ? 'React 18' : 'Next.js 15 (App Router)'} |
14
14
  | Language | TypeScript |
15
15
  | Build Tool | ${isReact ? 'Vite' : 'Next.js built-in'} |
16
16
  | Styling | Tailwind CSS |
@@ -47,8 +47,8 @@ src/
47
47
  ├── components/ 재사용 가능한 UI 컴포넌트${
48
48
  isReact
49
49
  ? `
50
- ├── layout/ 레이아웃 컴포넌트
51
- └── page/ 페이지 컴포넌트`
50
+ ├── layouts/ 레이아웃 컴포넌트
51
+ └── pages/ 페이지 컴포넌트`
52
52
  : `
53
53
  └── app/ Next.js App Router (layout, page 등)`
54
54
  }
@@ -61,7 +61,7 @@ ${
61
61
  각 레이어는 아래 방향으로만 import 해야 합니다.
62
62
 
63
63
  \`\`\`
64
- lib → store → api → hooks → context → components → layout → page
64
+ lib → store → api → hooks → context → components → layouts → pages
65
65
  \`\`\`
66
66
 
67
67
  \`assets\`는 모든 레이어에서 자유롭게 참조 가능합니다.`
@@ -10,6 +10,7 @@ export const BYUCKCHON_PACKAGES = [
10
10
  '@byuckchon-frontend/utils',
11
11
  '@byuckchon-frontend/basic-ui',
12
12
  '@byuckchon-frontend/core',
13
+ '@byuckchon-frontend/settings',
13
14
  ];
14
15
 
15
16
  async function hasPnpm() {