sh-ui-cli 0.96.3 → 0.98.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 +1 -1
- package/data/changelog/versions.json +26 -0
- package/package.json +1 -1
- package/src/api.d.ts +0 -4
- package/src/constants.js +0 -5
- package/src/create/cli-args.js +2 -6
- package/src/create/describeTemplate.js +3 -51
- package/src/create/generator.js +12 -816
- package/src/create/index.mjs +2 -7
- package/src/create/plugins/index.js +1 -3
- package/src/create/plugins/nextIntl.js +0 -4
- package/src/create/plugins/pluginSchema.js +1 -1
- package/src/create/templateManifest.js +0 -12
- package/src/mcp.mjs +1 -68
- package/templates/vite-standalone/_arch/flat/index.html +2 -2
- package/templates/vite-standalone/_arch/flat/src/lib/styles/globals.css +2 -2
- package/templates/vite-standalone/_arch/fsd/index.html +2 -2
- package/templates/vite-standalone/_arch/fsd/src/shared/styles/globals.css +2 -2
- package/src/create/plugins/authJwt.js +0 -420
- package/src/create/plugins/sentry.js +0 -467
- package/templates/tauri-shell/Cargo.toml +0 -21
- package/templates/tauri-shell/README.md +0 -49
- package/templates/tauri-shell/build.rs +0 -3
- package/templates/tauri-shell/capabilities/default.json +0 -12
- package/templates/tauri-shell/src/lib.rs +0 -8
- package/templates/tauri-shell/src/main.rs +0 -6
- package/templates/tauri-shell/tauri.conf.json +0 -29
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ npx sh-ui-cli create
|
|
|
22
22
|
|
|
23
23
|
# 비대화형 (에이전트 / CI)
|
|
24
24
|
npx sh-ui-cli create my-app --platform next --structure standalone --yes
|
|
25
|
-
npx sh-ui-cli create my-app --platform next --structure monorepo --plugins
|
|
25
|
+
npx sh-ui-cli create my-app --platform next --structure monorepo --plugins next-intl --yes
|
|
26
26
|
npx sh-ui-cli create my-app --platform flutter --yes
|
|
27
27
|
```
|
|
28
28
|
|
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$description": "sh-ui 릴리즈 노트 단일 소스. docs(React)와 showcase(Flutter)가 함께 읽는다. 새 릴리즈마다 맨 앞에 추가.",
|
|
4
4
|
"versions": [
|
|
5
|
+
{
|
|
6
|
+
"version": "0.98.0",
|
|
7
|
+
"date": "2026-05-16",
|
|
8
|
+
"title": "auth-jwt · sentry 플러그인 제거 — 스캐폴더에서 두 통합 완전 삭제 (breaking)",
|
|
9
|
+
"type": "minor",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"**`sentry` 플러그인 + `--observability` 옵션 제거 (breaking)** — Next 의 `--plugins sentry` 와 vite 전용 `--observability sentry` 를 둘 다 삭제. `sh_ui_create_project` · `sh_ui_add_app` · `sh_ui_describe_template` 의 `observability` 인자, `DescribeTemplateOptions.observability` 타입, `emitSentry()` 도 함께 제거. 이제 `--observability` 는 '알 수 없는 플래그', `--plugins sentry` 는 '알 수 없는 플러그인' 으로 거부된다.",
|
|
12
|
+
"**`auth-jwt` 플러그인 제거 (breaking)** — `--plugins auth-jwt` 및 auth-jwt+next-intl proxy.ts 병합 로직 삭제. `next-intl` 단독 scaffold 는 자체 proxy.ts 를 그대로 emit (회귀 가드 smoke 유지).",
|
|
13
|
+
"**유지: i18n / next-intl** — `--plugins next-intl` 과 vite `--i18n react-i18next` / `--locales` 는 그대로. 스캐폴더 플러그인은 이제 `next-intl` 단일. Sentry/JWT 는 프로젝트마다 설정이 갈려 baked-in scaffold 가치가 낮고, 특히 Sentry 의 Next 통합은 버전 churn 유지보수 부채라 의도적으로 축소.",
|
|
14
|
+
"**마이그레이션** — Sentry 가 필요하면 생성 후 공식 `@sentry/nextjs` 또는 `@sentry/react` 를 직접 추가. 인증은 프로젝트 백엔드 명세에 맞춰 직접 구성. docs `/plugins/sentry`·`/plugins/auth-jwt` 페이지 및 `/create` UI 토글 제거, smoke 시나리오 정리."
|
|
15
|
+
],
|
|
16
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.98.0"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"version": "0.97.0",
|
|
20
|
+
"date": "2026-05-16",
|
|
21
|
+
"title": "Tauri 통합 제거 — 스캐폴더에서 src-tauri/ shell 및 --tauri 옵션 삭제 (breaking)",
|
|
22
|
+
"type": "minor",
|
|
23
|
+
"highlights": [
|
|
24
|
+
"**`--tauri` / MCP `tauri` 옵션 제거 (breaking)** — `sh-ui-cli create` / `add-app` 의 `--tauri` 플래그, `sh_ui_create_project` · `sh_ui_add_app` · `sh_ui_describe_template` 의 `tauri` 인자, `DescribeTemplateOptions.tauri` 타입을 모두 삭제. 이제 `--tauri` 는 '알 수 없는 플래그' 에러로 거부된다.",
|
|
25
|
+
"**`tauri-shell` 템플릿 + `emitTauri`/`patchViteForTauri` 삭제** — `src-tauri/` (Cargo.toml·tauri.conf.json·Rust 소스) 를 더 이상 emit 하지 않는다. `@tauri-apps/*` 의존성·`tauri:dev`/`tauri:build` scripts·`src-tauri/target/` gitignore 주입도 제거. Tauri 가 필요하면 공식 `@tauri-apps/cli init` 을 직접 쓰면 된다 (vite 의 `dist/` 표준 산출물과 그대로 호환).",
|
|
26
|
+
"**docs `/create` UI 정리** — Tauri 데스크탑 셸 토글 제거, `/api/template-content` 의 src-tauri resolve 분기 삭제. vite 의 mobile/PWA 친화 디폴트(`viewport-fit=cover`·`theme-color`·webview reset)는 그대로 유지 — Tauri 전용이 아니라 일반 모바일 하드닝이라 보존.",
|
|
27
|
+
"**smoke 정리** — tauri 전용 시나리오(V7a–f, V12–14) 삭제, all-options 가드(V20a)는 i18n+sentry 조합으로 축소 유지. 마이그레이션: `--tauri` 쓰던 사용자는 플래그를 빼고 생성 후 `@tauri-apps/cli init` 으로 desktop shell 을 별도 추가."
|
|
28
|
+
],
|
|
29
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.97.0"
|
|
30
|
+
},
|
|
5
31
|
{
|
|
6
32
|
"version": "0.96.3",
|
|
7
33
|
"date": "2026-05-16",
|
package/package.json
CHANGED
package/src/api.d.ts
CHANGED
|
@@ -139,14 +139,10 @@ export interface DescribeTemplateOptions {
|
|
|
139
139
|
projectName?: string;
|
|
140
140
|
/** monorepo 첫 앱 이름. 기본 'web'. */
|
|
141
141
|
appName?: string;
|
|
142
|
-
/** platform=vite + structure=standalone 일 때 Tauri 2.x 셸(`src-tauri/`) 동시 emit. */
|
|
143
|
-
tauri?: boolean;
|
|
144
142
|
/** vite 전용 — react-i18next opt-in. v0.92.0+ */
|
|
145
143
|
i18n?: 'none' | 'react-i18next';
|
|
146
144
|
/** i18n 활성화 시 생성할 locale 코드 (comma-separated). 기본 'ko,en' */
|
|
147
145
|
locales?: string;
|
|
148
|
-
/** vite 전용 — Sentry observability opt-in. v0.93.0+ */
|
|
149
|
-
observability?: 'none' | 'sentry';
|
|
150
146
|
}
|
|
151
147
|
|
|
152
148
|
export interface DescribeTemplateGroup {
|
package/src/constants.js
CHANGED
|
@@ -60,8 +60,3 @@ export const INIT_DEFAULTS = {
|
|
|
60
60
|
export const I18N_LIBRARIES = ['none', 'react-i18next'];
|
|
61
61
|
export const I18N_DEFAULT = 'none';
|
|
62
62
|
export const I18N_DEFAULT_LOCALES = 'ko,en';
|
|
63
|
-
|
|
64
|
-
// ─── observability (vite preset 전용 — v0.93.0+) ───
|
|
65
|
-
// 'none' 디폴트 — opt-in 으로 @sentry/react + @sentry/vite-plugin 설치 + 셋업.
|
|
66
|
-
// GlitchTip self-hosted 도 같은 SDK — DSN 만 변경. 향후 bugsnag 등 추가 시 enum 확장.
|
|
67
|
-
export const OBSERVABILITY_PROVIDERS = ['none', 'sentry'];
|
package/src/create/cli-args.js
CHANGED
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
CSS_FRAMEWORKS_SUPPORTED,
|
|
5
5
|
CSS_FRAMEWORKS_PLANNED,
|
|
6
6
|
I18N_LIBRARIES,
|
|
7
|
-
OBSERVABILITY_PROVIDERS,
|
|
8
7
|
} from '../constants.js';
|
|
9
8
|
import { allPlugins } from './plugins/index.js';
|
|
10
9
|
import { allArchitectures } from './architectures/index.js';
|
|
@@ -14,8 +13,8 @@ const VALID_STRUCTURES = CREATE_STRUCTURES;
|
|
|
14
13
|
const VALID_PLUGINS = allPlugins.map((p) => p.name);
|
|
15
14
|
const VALID_ARCHES = allArchitectures.map((a) => a.name);
|
|
16
15
|
|
|
17
|
-
const VALUE_FLAGS = ['platform', 'structure', 'plugins', 'theme', 'app', 'css', 'arch', 'port', 'i18n', 'locales'
|
|
18
|
-
const BOOL_FLAGS = ['yes', 'help', 'dry-run'
|
|
16
|
+
const VALUE_FLAGS = ['platform', 'structure', 'plugins', 'theme', 'app', 'css', 'arch', 'port', 'i18n', 'locales'];
|
|
17
|
+
const BOOL_FLAGS = ['yes', 'help', 'dry-run'];
|
|
19
18
|
|
|
20
19
|
const SUBCOMMANDS = ['add-app', 'add-component'];
|
|
21
20
|
|
|
@@ -80,9 +79,6 @@ export const parseArgs = (argv) => {
|
|
|
80
79
|
if (name === 'i18n' && !I18N_LIBRARIES.includes(value)) {
|
|
81
80
|
throw new Error(`--i18n 은 ${I18N_LIBRARIES.join('/')} 중 하나여야 함 (받은 값: ${value})`);
|
|
82
81
|
}
|
|
83
|
-
if (name === 'observability' && !OBSERVABILITY_PROVIDERS.includes(value)) {
|
|
84
|
-
throw new Error(`--observability 는 ${OBSERVABILITY_PROVIDERS.join('/')} 중 하나여야 함 (받은 값: ${value})`);
|
|
85
|
-
}
|
|
86
82
|
if (name === 'css' && !CSS_FRAMEWORKS_SUPPORTED.includes(value)) {
|
|
87
83
|
// planned 값은 '곧 옵니다' 신호로 분기 — 사용자 의도가 더 명확히 전달.
|
|
88
84
|
if (CSS_FRAMEWORKS_PLANNED.includes(value)) {
|
|
@@ -31,14 +31,12 @@ import { CSS_FRAMEWORK_DEFAULT } from '../constants.js';
|
|
|
31
31
|
* @property {'next'|'flutter'|'vite'} [platform]
|
|
32
32
|
* @property {'standalone'|'monorepo'} [structure] next/vite 일 때만 의미
|
|
33
33
|
* @property {string} [arch] next 일 때 'fsd'|'flat'|'mes'
|
|
34
|
-
* @property {string[]} [plugins] ['
|
|
34
|
+
* @property {string[]} [plugins] ['next-intl']
|
|
35
35
|
* @property {'tailwind'|'plain'|'css-modules'} [cssFramework]
|
|
36
36
|
* @property {string} [projectName]
|
|
37
37
|
* @property {string} [appName] monorepo 첫 앱 이름. 기본 'web'
|
|
38
|
-
* @property {boolean} [tauri] platform=vite (standalone/monorepo 둘 다) 일 때 Tauri 2.x 셸 같이 emit
|
|
39
38
|
* @property {'none'|'react-i18next'} [i18n] vite 전용 — react-i18next 셋업
|
|
40
39
|
* @property {string} [locales] i18n 활성화 시 생성할 locale 코드 (comma-separated, default 'ko,en')
|
|
41
|
-
* @property {'none'|'sentry'} [observability] vite 전용 — Sentry 셋업 (v0.93.0+)
|
|
42
40
|
*/
|
|
43
41
|
|
|
44
42
|
/**
|
|
@@ -66,10 +64,8 @@ export function describeTemplate(opts = {}) {
|
|
|
66
64
|
plugins: pluginNames = [],
|
|
67
65
|
cssFramework = CSS_FRAMEWORK_DEFAULT,
|
|
68
66
|
appName: rawAppName = 'web',
|
|
69
|
-
tauri = false,
|
|
70
67
|
i18n = 'none',
|
|
71
68
|
locales = 'ko,en',
|
|
72
|
-
observability = 'none',
|
|
73
69
|
} = opts;
|
|
74
70
|
|
|
75
71
|
if (platform === 'flutter') {
|
|
@@ -97,14 +93,6 @@ export function describeTemplate(opts = {}) {
|
|
|
97
93
|
makeGroup('base', '베이스 (vite-standalone)', baseFiles),
|
|
98
94
|
makeGroup('arch', `Arch (${safeArchName})`, archFiles),
|
|
99
95
|
];
|
|
100
|
-
if (tauri) {
|
|
101
|
-
const tauriTpl = TEMPLATE_MANIFEST['tauri-shell'];
|
|
102
|
-
if (!tauriTpl) {
|
|
103
|
-
throw new Error("Template manifest missing entry for 'tauri-shell'.");
|
|
104
|
-
}
|
|
105
|
-
const tauriFiles = tauriTpl.base.map((p) => `src-tauri/${p}`);
|
|
106
|
-
groups.push(makeGroup('tauri', 'Tauri 셸 (src-tauri/)', tauriFiles));
|
|
107
|
-
}
|
|
108
96
|
if (i18n === 'react-i18next') {
|
|
109
97
|
const isFsd = safeArchName === 'fsd';
|
|
110
98
|
const i18nBase = isFsd ? 'src/shared/i18n' : 'src/lib/i18n';
|
|
@@ -118,17 +106,6 @@ export function describeTemplate(opts = {}) {
|
|
|
118
106
|
];
|
|
119
107
|
groups.push(makeGroup('i18n', `i18n (${i18n})`, i18nFiles));
|
|
120
108
|
}
|
|
121
|
-
if (observability === 'sentry') {
|
|
122
|
-
const isFsd = safeArchName === 'fsd';
|
|
123
|
-
const obsBase = isFsd ? 'src/shared/observability' : 'src/lib/observability';
|
|
124
|
-
const providersBase = isFsd ? 'src/app/providers' : 'src/components/providers';
|
|
125
|
-
groups.push(makeGroup('sentry', `Sentry observability`, [
|
|
126
|
-
`${obsBase}/sentry.ts`,
|
|
127
|
-
`${obsBase}/index.ts`,
|
|
128
|
-
`${providersBase}/SentryProvider.tsx`,
|
|
129
|
-
'.env.example',
|
|
130
|
-
]));
|
|
131
|
-
}
|
|
132
109
|
return finalize(groups);
|
|
133
110
|
}
|
|
134
111
|
|
|
@@ -170,15 +147,6 @@ export function describeTemplate(opts = {}) {
|
|
|
170
147
|
),
|
|
171
148
|
));
|
|
172
149
|
|
|
173
|
-
if (tauri) {
|
|
174
|
-
const tauriTpl = TEMPLATE_MANIFEST['tauri-shell'];
|
|
175
|
-
if (!tauriTpl) {
|
|
176
|
-
throw new Error("Template manifest missing entry for 'tauri-shell'.");
|
|
177
|
-
}
|
|
178
|
-
const tauriFiles = tauriTpl.base.map((p) => `apps/${appName}/src-tauri/${p}`);
|
|
179
|
-
groups.push(makeGroup('tauri', `Tauri 셸 (apps/${appName}/src-tauri/)`, tauriFiles));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
150
|
if (i18n === 'react-i18next') {
|
|
183
151
|
const isFsd = safeArchName === 'fsd';
|
|
184
152
|
const i18nBase = isFsd ? 'src/shared/i18n' : 'src/lib/i18n';
|
|
@@ -193,18 +161,6 @@ export function describeTemplate(opts = {}) {
|
|
|
193
161
|
groups.push(makeGroup('i18n', `i18n (${i18n}, apps/${appName}/)`, i18nFiles));
|
|
194
162
|
}
|
|
195
163
|
|
|
196
|
-
if (observability === 'sentry') {
|
|
197
|
-
const isFsd = safeArchName === 'fsd';
|
|
198
|
-
const obsBase = isFsd ? 'src/shared/observability' : 'src/lib/observability';
|
|
199
|
-
const providersBase = isFsd ? 'src/app/providers' : 'src/components/providers';
|
|
200
|
-
groups.push(makeGroup('sentry', `Sentry observability (apps/${appName}/)`, [
|
|
201
|
-
`apps/${appName}/${obsBase}/sentry.ts`,
|
|
202
|
-
`apps/${appName}/${obsBase}/index.ts`,
|
|
203
|
-
`apps/${appName}/${providersBase}/SentryProvider.tsx`,
|
|
204
|
-
`apps/${appName}/.env.example`,
|
|
205
|
-
]));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
164
|
return finalize(groups);
|
|
209
165
|
}
|
|
210
166
|
|
|
@@ -299,13 +255,9 @@ function buildNextGroups({ prefix, templateKey, arch, plugins, cssFramework }) {
|
|
|
299
255
|
// generator.js applyCssFrameworkVariant 와 동일한 분기 — intl 활성 시 [locale]/, 아니면 app/.
|
|
300
256
|
if (cssFramework === 'css-modules') {
|
|
301
257
|
const intlActive = plugins.some((p) => p.name === 'next-intl');
|
|
302
|
-
const sentryActive = plugins.some((p) => p.name === 'sentry');
|
|
303
258
|
const cssPaths = [];
|
|
304
259
|
const pageDir = intlActive ? 'app/[locale]' : 'app';
|
|
305
260
|
cssPaths.push(`${prefix}${pageDir}/page.module.css`);
|
|
306
|
-
if (sentryActive) {
|
|
307
|
-
cssPaths.push(`${prefix}${pageDir}/error.module.css`);
|
|
308
|
-
}
|
|
309
261
|
groups.push(makeGroup(
|
|
310
262
|
'css',
|
|
311
263
|
'CSS: css-modules 변종',
|
|
@@ -356,7 +308,7 @@ function applyMovesAndDeletes(groups, moves, deletes) {
|
|
|
356
308
|
const added = [];
|
|
357
309
|
for (const { from, to } of moves) {
|
|
358
310
|
const removed = removeFromAllGroups(groups, from);
|
|
359
|
-
// 원본이 어디에도 없었다면 (
|
|
311
|
+
// 원본이 어디에도 없었다면 (move 소스가 현재 file-plan 에 없음) — 새로
|
|
360
312
|
// 추가하지 않는다. generator.js 의 `if (await fs.pathExists(fromPath))` 시맨틱.
|
|
361
313
|
if (removed) added.push(to);
|
|
362
314
|
}
|
|
@@ -426,7 +378,7 @@ function finalize(groups) {
|
|
|
426
378
|
* 현재 규칙:
|
|
427
379
|
* - basename 이 정확히 'gitignore' 인 경로 → '.gitignore' 로 prefix dot 추가.
|
|
428
380
|
* (npm publish 가 .gitignore 를 strip 하므로 템플릿엔 점 없이 두고 emit 후 dot-prefix.)
|
|
429
|
-
* - 이미 '.gitignore' 인
|
|
381
|
+
* - 이미 '.gitignore' 인 경로는 그대로.
|
|
430
382
|
*
|
|
431
383
|
* 미래에 다른 fs-level rename 이 추가되면 여기에 같이 등록 (describeTemplate 의
|
|
432
384
|
* file-plan ↔ create_project 의 실제 emit 1:1 정합성 유지).
|