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.
@@ -17,8 +17,8 @@ const THEME_PRESETS_LIST = THEME_PRESET_NAMES.join('|');
17
17
  export const HELP_TEXT = `sh-ui create — sh-ui 프로젝트 스캐폴드 (Next.js / Flutter)
18
18
 
19
19
  사용법:
20
- sh-ui create [name] [options] [--observability <none|sentry>]
21
- sh-ui create add-app [name] [--port <n>] [--platform <next|vite>] [--plugins ..] [--theme ..] [--css ..] [--tauri] [--i18n <react-i18next|none>] [--locales ko,en] [--observability <none|sentry>]
20
+ sh-ui create [name] [options]
21
+ sh-ui create add-app [name] [--port <n>] [--platform <next|vite>] [--plugins ..] [--theme ..] [--css ..] [--i18n <react-i18next|none>] [--locales ko,en]
22
22
  sh-ui create add-component <name> [--app <name>]
23
23
 
24
24
  옵션:
@@ -30,7 +30,6 @@ export const HELP_TEXT = `sh-ui create — sh-ui 프로젝트 스캐폴드 (Next
30
30
  --css <${CSS_FRAMEWORKS_SUPPORTED.join('|')}> CSS 프레임워크. base 파일까지 분기 emit (tailwind/plain/css-modules)
31
31
  --i18n <react-i18next|none> vite 전용 — react-i18next 셋업 emit (i18n config + I18nProvider). 기본 none (v0.92.0+)
32
32
  --locales <ko,en> i18n 활성화 시 생성할 locale 코드 (comma-separated). 기본 'ko,en'
33
- --observability <none|sentry> vite 전용 — Sentry 셋업 emit (@sentry/react + vite-plugin + SentryProvider). 기본 none (v0.93.0+)
34
33
  --yes 디렉토리 덮어쓰기 + 모노레포 기본값 자동 채택
35
34
  --dry-run 파일을 쓰지 않고 작성될 파일 목록만 출력
36
35
  -h, --help 이 도움말
@@ -77,10 +76,8 @@ export async function runCreate(rest) {
77
76
  theme: flags.theme,
78
77
  css: flags.css,
79
78
  platform: flags.platform,
80
- tauri: flags.tauri,
81
79
  i18n: flags.i18n,
82
80
  locales: flags.locales,
83
- observability: flags.observability,
84
81
  });
85
82
  } else if (command === 'add-component') {
86
83
  // 호환 별칭 — 신규 진입점은 `sh-ui add <name>` (bin/sh-ui.mjs 가 walk-up 으로 라우팅).
@@ -97,10 +94,8 @@ export async function runCreate(rest) {
97
94
  arch: flags.arch,
98
95
  theme: flags.theme,
99
96
  css: flags.css,
100
- tauri: flags.tauri,
101
97
  i18n: flags.i18n,
102
98
  locales: flags.locales,
103
- observability: flags.observability,
104
99
  // create 컨텍스트에서는 --app 이 첫 앱 이름 (monorepo). 같은 플래그가
105
100
  // add-component 컨텍스트에서는 대상 앱 선택 — 의미가 컨텍스트마다 다름.
106
101
  appName: flags.app,
@@ -1,9 +1,7 @@
1
- import { sentryPlugin } from './sentry.js';
2
1
  import { nextIntlPlugin } from './nextIntl.js';
3
- import { authJwtPlugin } from './authJwt.js';
4
2
  import { validatePlugins } from './pluginSchema.js';
5
3
 
6
- export const allPlugins = [sentryPlugin, nextIntlPlugin, authJwtPlugin];
4
+ export const allPlugins = [nextIntlPlugin];
7
5
 
8
6
  // 모듈 로드 시점에 모든 플러그인 manifest 검증 — 잘못된 형태가 있으면 즉시 실패.
9
7
  // 예: src/proxy.ts 같은 잘못된 경로, name 이 kebab-case 가 아닌 경우 등.
@@ -130,10 +130,6 @@ export default function Error({
130
130
  }
131
131
  `,
132
132
  },
133
- // auth-jwt 플러그인이 함께 활성화돼 있으면 sign-in 도 locale prefix 안으로 이동.
134
- // auth-jwt 단독일 때 (= 이 transform 이 없을 때) 는 app/sign-in 이 그대로 root 에 남는다.
135
- // `move` 트랜스폼은 from 파일이 없으면 silently skip 이라 auth-jwt 미활성 시 안전한 no-op.
136
- { type: 'move', from: 'app/sign-in/page.tsx', to: 'app/[locale]/sign-in/page.tsx' },
137
133
  {
138
134
  // Next 16 부터 root layout (app/layout.tsx) 은 반드시 <html>/<body> 를 가져야 한다.
139
135
  // next-intl 적용 시에는 [locale] 가 root 역할을 맡으므로, 기본 app/layout.tsx 를 그대로
@@ -40,7 +40,7 @@ const archAwareArray = z.union([z.array(z.any()), archAwareFn]);
40
40
 
41
41
  export const PluginSchema = z.object({
42
42
  name: z.string().regex(/^[a-z][a-z0-9-]*$/, {
43
- message: 'Plugin name must be lowercase kebab-case (e.g., "auth-jwt")',
43
+ message: 'Plugin name must be lowercase kebab-case (e.g., "next-intl")',
44
44
  }),
45
45
  label: z.string().min(1),
46
46
  description: z.string().min(1).optional(),
@@ -314,18 +314,6 @@ export const TEMPLATE_MANIFEST = {
314
314
  ]
315
315
  }
316
316
  },
317
- "tauri-shell": {
318
- "base": [
319
- ".gitignore",
320
- "Cargo.toml",
321
- "README.md",
322
- "build.rs",
323
- "capabilities/default.json",
324
- "src/lib.rs",
325
- "src/main.rs",
326
- "tauri.conf.json"
327
- ]
328
- },
329
317
  "ui-app-template": {
330
318
  "base": [
331
319
  "eslint.config.js",
package/src/mcp.mjs CHANGED
@@ -48,7 +48,6 @@ import {
48
48
  CSS_FRAMEWORKS_SUPPORTED,
49
49
  I18N_LIBRARIES,
50
50
  I18N_DEFAULT_LOCALES,
51
- OBSERVABILITY_PROVIDERS,
52
51
  } from "./constants.js";
53
52
  import { allPlugins } from "./create/plugins/index.js";
54
53
  import { allArchitectures, describeArchOptions } from "./create/architectures/index.js";
@@ -432,7 +431,6 @@ export async function startMcpServer() {
432
431
  {
433
432
  description:
434
433
  "빈 폴더에 sh-ui 프로젝트 스캐폴드 — Next.js (standalone/monorepo) | Vite (standalone/monorepo) | Flutter. " +
435
- "+ vite 인 경우 `tauri: true` 로 Tauri 2.x 데스크탑 셸 (`src-tauri/`) 까지 한 번에 emit (Rust toolchain 필요). " +
436
434
  `FSD 폴더 구조 + 토큰 + sh-ui.config.json 일괄 생성. 사용자가 '새 프로젝트' / '빈 폴더' / '스캐폴드부터' 류 요청을 하면 이 툴 사용 (Bash 로 npx ${cliName} create 직접 호출보다 우선). ` +
437
435
  "**단일 진입점** — theme/plugins/cssFramework/structure 모두 호출 시점에 정해서 한 번에 박는다. 호출 후 sh-ui.config.json/tokens.css 를 손으로 패치하지 말 것 (다음 재스캐폴드 시 유실). " +
438
436
  "산출물: theme 인자가 프리셋이면 sh-ui.config.json 의 theme.base 가 그 이름, base64 면 'custom'. paths.styles · paths.tokens 도 자동 박혀서 sh_ui_add_component 가 사후 패치 없이 동작.",
@@ -461,13 +459,6 @@ export async function startMcpServer() {
461
459
  .describe("부모 디렉토리. 기본 process.cwd()"),
462
460
  force: z.boolean().optional()
463
461
  .describe("기존 디렉토리 덮어쓰기. 기본 false (안전)"),
464
- tauri: z.boolean().optional()
465
- .describe(
466
- "Tauri 2.x 데스크탑 셸 (`src-tauri/`) 함께 emit. platform=vite (standalone/monorepo 둘 다) 일 때만 지원. " +
467
- "monorepo 의 경우 src-tauri/ 는 apps/{appName}/ 안에 emit, devUrl 은 해당 app 의 dev port 와 자동 동기화. " +
468
- "Rust toolchain (`cargo`/`rustc`) 가 시스템에 설치되어 있어야 첫 `pnpm tauri dev` 가 동작. " +
469
- "기본 false.",
470
- ),
471
462
  i18n: z.enum(I18N_LIBRARIES).optional()
472
463
  .describe(
473
464
  "i18n 라이브러리 — platform=vite 일 때만 의미. 'react-i18next' 로 설정 시 i18next + react-i18next + browser-languagedetector + http-backend 셋업 + " +
@@ -478,11 +469,6 @@ export async function startMcpServer() {
478
469
  `i18n 활성화 시 생성할 locale 코드 (comma-separated, 2글자 또는 'ko-KR' 류). 기본 '${I18N_DEFAULT_LOCALES}'. 첫 locale 이 fallbackLng. ` +
479
470
  "i18n='none' 이면 무시.",
480
471
  ),
481
- observability: z.enum(OBSERVABILITY_PROVIDERS).optional()
482
- .describe(
483
- "observability provider — platform=vite 일 때만 의미. 'sentry' 로 설정 시 @sentry/react + " +
484
- "@sentry/vite-plugin 셋업 + SentryProvider + .env.example 자동 emit. GlitchTip self-hosted 도 같은 SDK — DSN 만 변경. 기본 'none'.",
485
- ),
486
472
  // monorepo 첫 앱 이름 — describe_template 와 시그니처 1:1 일치 (v0.96.0+).
487
473
  // standalone 일 땐 무시 (프로젝트 루트가 곧 앱). 미지정 시 'web'.
488
474
  appName: z.string().min(1).optional()
@@ -513,15 +499,6 @@ export async function startMcpServer() {
513
499
  } catch (e) {
514
500
  return { isError: true, content: [{ type: "text", text: e.message }] };
515
501
  }
516
- if (input.tauri && input.platform !== "vite") {
517
- return {
518
- isError: true,
519
- content: [{
520
- type: "text",
521
- text: "tauri: true 는 platform=vite 일 때만 지원합니다 (현재 platform=" + input.platform + ").",
522
- }],
523
- };
524
- }
525
502
  if (input.i18n && input.i18n !== "none" && input.platform !== "vite") {
526
503
  return {
527
504
  isError: true,
@@ -531,15 +508,6 @@ export async function startMcpServer() {
531
508
  }],
532
509
  };
533
510
  }
534
- if (input.observability && input.observability !== "none" && input.platform !== "vite") {
535
- return {
536
- isError: true,
537
- content: [{
538
- type: "text",
539
- text: `observability='${input.observability}' 은 platform=vite 일 때만 지원합니다 (현재 platform=${input.platform}).`,
540
- }],
541
- };
542
- }
543
511
  const targetParent = resolveCwd(input);
544
512
  const targetDir = resolve(targetParent, input.name);
545
513
  if (existsSync(targetDir) && !input.force) {
@@ -565,10 +533,8 @@ export async function startMcpServer() {
565
533
  arch: input.arch,
566
534
  theme: input.theme,
567
535
  css: input.cssFramework,
568
- tauri: input.tauri,
569
536
  i18n: input.i18n,
570
537
  locales: input.locales,
571
- observability: input.observability,
572
538
  appName: input.appName,
573
539
  port: input.port,
574
540
  yes: true, // 사전 검사를 마쳤으니 generator 의 confirm 프롬프트 우회
@@ -589,7 +555,7 @@ export async function startMcpServer() {
589
555
  "사용자가 '앱 추가' / 'monorepo 에 새 앱' / 'add admin app' 류 요청을 하면 이 툴 사용 (Bash 로 npx " + cliName + " add-app 직접 호출보다 우선). " +
590
556
  "v0.65+ 레이아웃 준수 — ui-{name} 은 tokens-only role, 컴포넌트는 sibling ui-core 가 SoT. " +
591
557
  "theme/css 는 새 ui-app 에만 적용 (다른 앱 영향 없음). monorepo 가 아니면 (pnpm-workspace.yaml 없음) 에러. " +
592
- "platform 미지정 시 기존 apps/* 스캔해 추론 (모든 앱이 같은 플랫폼이면 그것으로). vite + tauri:true 면 apps/{name}/src-tauri/ 도 함께 emit.",
558
+ "platform 미지정 시 기존 apps/* 스캔해 추론 (모든 앱이 같은 플랫폼이면 그것으로).",
593
559
  inputSchema: {
594
560
  name: z.string().min(1)
595
561
  .describe("앱 이름 — apps/{name}/ + packages/ui/ui-apps/ui-{name}/ 디렉토리명. 영숫자 + 하이픈."),
@@ -603,8 +569,6 @@ export async function startMcpServer() {
603
569
  .describe("CSS 프레임워크. 기본 plain. 새 앱의 컴포넌트 변종 결정 — 같은 모노레포 내 다른 앱과 다른 값 가능."),
604
570
  platform: z.enum(["next", "vite"]).optional()
605
571
  .describe("플랫폼 — next | vite. 미지정 시 기존 apps/* 의 deps 로 추론 (모든 앱이 같은 플랫폼이면 그것으로, 혼재면 명시 필요)."),
606
- tauri: z.boolean().optional()
607
- .describe("Tauri 2.x 데스크탑 셸 — platform=vite 일 때만 의미. apps/{name}/src-tauri/ 에 emit. 기본 false."),
608
572
  i18n: z.enum(I18N_LIBRARIES).optional()
609
573
  .describe(
610
574
  "i18n 라이브러리 — platform=vite 일 때만 의미. 'react-i18next' 로 설정 시 i18next + react-i18next + " +
@@ -614,11 +578,6 @@ export async function startMcpServer() {
614
578
  .describe(
615
579
  `i18n 활성화 시 생성할 locale 코드 (comma-separated). 기본 '${I18N_DEFAULT_LOCALES}'. 첫 locale 이 fallbackLng. i18n='none' 이면 무시.`,
616
580
  ),
617
- observability: z.enum(OBSERVABILITY_PROVIDERS).optional()
618
- .describe(
619
- "observability provider — platform=vite 일 때만 의미. 'sentry' 로 설정 시 @sentry/react + " +
620
- "@sentry/vite-plugin 셋업 + SentryProvider + .env.example 자동 emit. GlitchTip self-hosted 도 같은 SDK — DSN 만 변경. 기본 'none'.",
621
- ),
622
581
  cwd: z.string().optional()
623
582
  .describe("모노레포 루트 (pnpm-workspace.yaml 있는 곳). 기본 process.cwd()"),
624
583
  },
@@ -629,15 +588,6 @@ export async function startMcpServer() {
629
588
  } catch (e) {
630
589
  return { isError: true, content: [{ type: "text", text: e.message }] };
631
590
  }
632
- if (input.tauri && input.platform === "next") {
633
- return {
634
- isError: true,
635
- content: [{
636
- type: "text",
637
- text: "tauri 는 platform=vite 일 때만 지원합니다. --platform vite 사용 또는 tauri 옵션 제거.",
638
- }],
639
- };
640
- }
641
591
  if (input.i18n && input.i18n !== "none" && input.platform && input.platform !== "vite") {
642
592
  return {
643
593
  isError: true,
@@ -647,15 +597,6 @@ export async function startMcpServer() {
647
597
  }],
648
598
  };
649
599
  }
650
- if (input.observability && input.observability !== "none" && input.platform && input.platform !== "vite") {
651
- return {
652
- isError: true,
653
- content: [{
654
- type: "text",
655
- text: `observability='${input.observability}' 은 platform=vite 일 때만 지원합니다 (현재 platform=${input.platform}).`,
656
- }],
657
- };
658
- }
659
600
  const text = await captureConsole(() =>
660
601
  addApp({
661
602
  name: input.name,
@@ -664,10 +605,8 @@ export async function startMcpServer() {
664
605
  theme: input.theme,
665
606
  css: input.cssFramework,
666
607
  platform: input.platform,
667
- tauri: input.tauri,
668
608
  i18n: input.i18n,
669
609
  locales: input.locales,
670
- observability: input.observability,
671
610
  cwd: resolveCwd(input),
672
611
  }),
673
612
  );
@@ -1017,14 +956,10 @@ export async function startMcpServer() {
1017
956
  .describe("monorepo 첫 앱 이름. 기본 web"),
1018
957
  // vite 전용 — sh_ui_create_project 의 동일 옵션과 1:1 대응. describe ↔ create 가 같은
1019
958
  // file-plan 을 보장하려면 여기서 받아 describeTemplate 에 전달해야 한다 (v0.95.0+).
1020
- tauri: z.boolean().optional()
1021
- .describe("Tauri 2.x 데스크탑 셸 emit (platform=vite 전용). 기본 false"),
1022
959
  i18n: z.enum(I18N_LIBRARIES).optional()
1023
960
  .describe(`i18n 라이브러리 (platform=vite 전용). 옵션: ${I18N_LIBRARIES.join(', ')}. 기본 none`),
1024
961
  locales: z.string().optional()
1025
962
  .describe(`i18n 활성화 시 locale 코드 (comma-separated, 예: "ko,en"). 기본 "${I18N_DEFAULT_LOCALES}"`),
1026
- observability: z.enum(OBSERVABILITY_PROVIDERS).optional()
1027
- .describe(`observability 백엔드 (platform=vite 전용). 옵션: ${OBSERVABILITY_PROVIDERS.join(', ')}. 기본 none`),
1028
963
  },
1029
964
  },
1030
965
  async (input) => {
@@ -1036,10 +971,8 @@ export async function startMcpServer() {
1036
971
  plugins: input.plugins,
1037
972
  cssFramework: input.cssFramework,
1038
973
  appName: input.appName,
1039
- tauri: input.tauri,
1040
974
  i18n: input.i18n,
1041
975
  locales: input.locales,
1042
- observability: input.observability,
1043
976
  });
1044
977
  return jsonResult(result);
1045
978
  } catch (e) {
@@ -3,9 +3,9 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <!-- viewport-fit=cover: iOS safe-area inset / Android edge-to-edge / Tauri mobile 호환 -->
6
+ <!-- viewport-fit=cover: iOS safe-area inset / Android edge-to-edge -->
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
8
- <!-- theme-color: 모바일 브라우저 / PWA / Tauri WebView 의 status bar 톤. dark default 에 맞춰 어두운 톤. -->
8
+ <!-- theme-color: 모바일 브라우저 / PWA 의 status bar 톤. dark default 에 맞춰 어두운 톤. -->
9
9
  <meta name="theme-color" content="#0A0A0A" media="(prefers-color-scheme: dark)" />
10
10
  <meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)" />
11
11
  <title>sh-ui app</title>
@@ -34,8 +34,8 @@
34
34
  --color-sidebar-bg: var(--sidebar-bg);
35
35
  }
36
36
 
37
- /* sh-ui:webview-base-start — 모바일 브라우저 / Tauri WebView / PWA 공통 기본값.
38
- * v0.88.1+: Tauri 통합 + iOS/Android 친화. 사용자가 텍스트 셀렉트 필요한 곳은 input/textarea/
37
+ /* sh-ui:webview-base-start — 모바일 브라우저 / PWA 공통 기본값.
38
+ * iOS/Android 친화. 사용자가 텍스트 셀렉트 필요한 곳은 input/textarea/
39
39
  * contenteditable 에 명시적으로 user-select: text 로 복원. 토큰이 아니라 reset 성 규칙이라
40
40
  * @theme inline 밖에 둠. */
41
41
  @layer base {
@@ -3,9 +3,9 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <!-- viewport-fit=cover: iOS safe-area inset / Android edge-to-edge / Tauri mobile 호환 -->
6
+ <!-- viewport-fit=cover: iOS safe-area inset / Android edge-to-edge -->
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
8
- <!-- theme-color: 모바일 브라우저 / PWA / Tauri WebView 의 status bar 톤. dark default 에 맞춰 어두운 톤. -->
8
+ <!-- theme-color: 모바일 브라우저 / PWA 의 status bar 톤. dark default 에 맞춰 어두운 톤. -->
9
9
  <meta name="theme-color" content="#0A0A0A" media="(prefers-color-scheme: dark)" />
10
10
  <meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)" />
11
11
  <title>sh-ui app</title>
@@ -34,8 +34,8 @@
34
34
  --color-sidebar-bg: var(--sidebar-bg);
35
35
  }
36
36
 
37
- /* sh-ui:webview-base-start — 모바일 브라우저 / Tauri WebView / PWA 공통 기본값.
38
- * v0.88.1+: Tauri 통합 + iOS/Android 친화. 사용자가 텍스트 셀렉트 필요한 곳은 input/textarea/
37
+ /* sh-ui:webview-base-start — 모바일 브라우저 / PWA 공통 기본값.
38
+ * iOS/Android 친화. 사용자가 텍스트 셀렉트 필요한 곳은 input/textarea/
39
39
  * contenteditable 에 명시적으로 user-select: text 로 복원. 토큰이 아니라 reset 성 규칙이라
40
40
  * @theme inline 밖에 둠. */
41
41
  @layer base {