sh-ui-cli 0.114.0 → 0.116.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/bin/sh-ui.mjs CHANGED
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { init } from "../src/init.mjs";
2
+ import { init, HELP_TEXT as INIT_HELP } from "../src/init.mjs";
3
3
  import { add } from "../src/add.mjs";
4
4
  import { list } from "../src/list.mjs";
5
5
  import { remove } from "../src/remove.mjs";
6
6
  import { findShUiContext } from "../src/resolve-context.mjs";
7
+ import { suggest } from "../src/levenshtein.mjs";
8
+ import { KNOWN_COMMANDS } from "../src/commands.mjs";
7
9
 
8
10
  const [, , cmd, ...rest] = process.argv;
9
11
 
@@ -36,6 +38,9 @@ const usage = `사용법:
36
38
  sh-ui mcp MCP 서버(stdio) 시작 — IDE-내 AI용
37
39
  sh-ui mcp init --client <name> IDE MCP 설정 파일에 sh-ui 엔트리 자동 추가
38
40
  (claude-code | cursor | claude-desktop | codex)
41
+
42
+ 각 명령의 상세 옵션은 \`sh-ui <command> --help\` 로 확인.
43
+
39
44
  옵션:
40
45
  --skip-install (add, rename-app) 외부 패키지 자동 설치 생략
41
46
  --diff (add) 파일을 쓰지 않고 변경 내역만 출력
@@ -57,9 +62,18 @@ try {
57
62
  break;
58
63
  }
59
64
  case "init":
65
+ if (rest.includes("--help") || rest.includes("-h")) {
66
+ console.log(INIT_HELP);
67
+ break;
68
+ }
60
69
  await init({ cwd: process.cwd(), args: rest });
61
70
  break;
62
71
  case "add": {
72
+ if (rest.includes("--help") || rest.includes("-h")) {
73
+ const { HELP_TEXT } = await import("../src/add.mjs");
74
+ console.log(HELP_TEXT);
75
+ break;
76
+ }
63
77
  const skipInstall = rest.includes("--skip-install");
64
78
  const diffMode = rest.includes("--diff");
65
79
  const force = rest.includes("--force");
@@ -107,11 +121,21 @@ try {
107
121
  break;
108
122
  }
109
123
  case "list": {
124
+ if (rest.includes("--help") || rest.includes("-h")) {
125
+ const { HELP_TEXT } = await import("../src/list.mjs");
126
+ console.log(HELP_TEXT);
127
+ break;
128
+ }
110
129
  const all = rest.includes("--all");
111
130
  await list({ cwd: process.cwd(), all });
112
131
  break;
113
132
  }
114
133
  case "doctor": {
134
+ if (rest.includes("--help") || rest.includes("-h")) {
135
+ const { HELP_TEXT } = await import("../src/doctor.mjs");
136
+ console.log(HELP_TEXT);
137
+ break;
138
+ }
115
139
  const { doctor } = await import("../src/doctor.mjs");
116
140
  const { existsSync, readdirSync } = await import("node:fs");
117
141
  const { resolve } = await import("node:path");
@@ -157,12 +181,22 @@ try {
157
181
  break;
158
182
  }
159
183
  case "upgrade-cli": {
184
+ if (rest.includes("--help") || rest.includes("-h")) {
185
+ const { HELP_TEXT } = await import("../src/upgrade-cli.mjs");
186
+ console.log(HELP_TEXT);
187
+ break;
188
+ }
160
189
  const apply = rest.includes("--apply");
161
190
  const { runUpgradeCli } = await import("../src/upgrade-cli.mjs");
162
191
  await runUpgradeCli({ cwd: process.cwd(), apply });
163
192
  break;
164
193
  }
165
194
  case "theme": {
195
+ if (rest.includes("--help") || rest.includes("-h")) {
196
+ const { HELP_TEXT } = await import("../src/theme-extract.mjs");
197
+ console.log(HELP_TEXT);
198
+ break;
199
+ }
166
200
  const sub = rest[0];
167
201
  const flags = rest.slice(1);
168
202
  if (sub === "extract") {
@@ -177,6 +211,11 @@ try {
177
211
  break;
178
212
  }
179
213
  case "tokens": {
214
+ if (rest.includes("--help") || rest.includes("-h")) {
215
+ const { HELP_TEXT } = await import("../src/tokens-cmd.mjs");
216
+ console.log(HELP_TEXT);
217
+ break;
218
+ }
180
219
  // sh-ui tokens diff
181
220
  // sh-ui tokens upgrade --apply | --replace
182
221
  const sub = rest[0];
@@ -210,6 +249,12 @@ try {
210
249
  case "mcp": {
211
250
  // `sh-ui mcp init ...` → 설정 파일에 엔트리 추가
212
251
  // `sh-ui mcp` → MCP 서버 시작
252
+ // 단, `sh-ui mcp --help` 는 mcp HELP_TEXT 출력 (mcp init 의 인자 처리는 mcp-init.mjs 가 담당).
253
+ if (rest[0] !== "init" && (rest.includes("--help") || rest.includes("-h"))) {
254
+ const { HELP_TEXT } = await import("../src/mcp.mjs");
255
+ console.log(HELP_TEXT);
256
+ break;
257
+ }
213
258
  if (rest[0] === "init") {
214
259
  const { mcpInit } = await import("../src/mcp-init.mjs");
215
260
  await mcpInit({ cwd: process.cwd(), args: rest.slice(1) });
@@ -220,6 +265,11 @@ try {
220
265
  break;
221
266
  }
222
267
  case "rename-app": {
268
+ if (rest.includes("--help") || rest.includes("-h")) {
269
+ const { HELP_TEXT } = await import("../src/rename-app.mjs");
270
+ console.log(HELP_TEXT);
271
+ break;
272
+ }
223
273
  const yes = rest.includes("--yes");
224
274
  const dryRun = rest.includes("--dry-run");
225
275
  const skipInstall = rest.includes("--skip-install");
@@ -235,6 +285,11 @@ try {
235
285
  break;
236
286
  }
237
287
  case "migrate": {
288
+ if (rest.includes("--help") || rest.includes("-h")) {
289
+ const { HELP_TEXT } = await import("../src/migrate-bundled.mjs");
290
+ console.log(HELP_TEXT);
291
+ break;
292
+ }
238
293
  // sh-ui migrate bundled [--apply] [--bundle <path>]
239
294
  const sub = rest[0];
240
295
  const flags = rest.slice(1);
@@ -251,6 +306,11 @@ try {
251
306
  break;
252
307
  }
253
308
  case "migrate-v065": {
309
+ if (rest.includes("--help") || rest.includes("-h")) {
310
+ const { HELP_TEXT } = await import("../src/migrate-v065.mjs");
311
+ console.log(HELP_TEXT);
312
+ break;
313
+ }
254
314
  const apply = rest.includes("--apply");
255
315
  const skipImportRewrite = rest.includes("--skip-import-rewrite");
256
316
  const { migrateToV065 } = await import("../src/migrate-v065.mjs");
@@ -264,6 +324,11 @@ try {
264
324
  }
265
325
  case "remove":
266
326
  case "rm": {
327
+ if (rest.includes("--help") || rest.includes("-h")) {
328
+ const { HELP_TEXT } = await import("../src/remove.mjs");
329
+ console.log(HELP_TEXT);
330
+ break;
331
+ }
267
332
  const force = rest.includes("--force");
268
333
  const dryRun = rest.includes("--dry-run");
269
334
  const names = rest.filter((a) => !a.startsWith("--"));
@@ -280,10 +345,12 @@ try {
280
345
  case "--help":
281
346
  console.log(usage);
282
347
  break;
283
- default:
284
- console.error(`알 없는 명령: ${cmd}\n`);
348
+ default: {
349
+ const hits = suggest(cmd, KNOWN_COMMANDS);
350
+ console.error(`알 수 없는 명령: ${cmd}` + (hits.length ? ` — 혹시 ${hits.join(", ")}?` : "") + "\n");
285
351
  console.error(usage);
286
352
  process.exit(1);
353
+ }
287
354
  }
288
355
  } catch (err) {
289
356
  console.error(`✗ ${err.message}`);
@@ -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.116.0",
7
+ "date": "2026-06-17",
8
+ "title": "CLI 발견성 — 서브명령 --help + 오타 추천",
9
+ "type": "minor",
10
+ "highlights": [
11
+ "모든 서브명령에 --help — init·add·remove·doctor·tokens·theme·migrate·rename-app·upgrade-cli·mcp 전용 도움말",
12
+ "did-you-mean — 없는 컴포넌트/명령 입력 시 가까운 후보를 '혹시 …?' 로 제안",
13
+ "의존성 없는 levenshtein 유틸 내장 (packages/cli/src/levenshtein.mjs)"
14
+ ],
15
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.116.0"
16
+ },
17
+ {
18
+ "version": "0.115.0",
19
+ "date": "2026-06-01",
20
+ "title": "rich-text-editor — 밑줄·텍스트 컬러·인라인 링크 편집 + compact·focus 툴바 + i18n 라벨",
21
+ "type": "minor",
22
+ "highlights": [
23
+ "**밑줄 + 텍스트 컬러** — Underline 버튼(v3 StarterKit 내장)과 글자색 팔레트를 툴바에 추가. 색은 하드 hex 가 아니라 CSS 변수(`var(--sh-ui-rte-c-moss|red|orange|blue)`)로 저장돼 라이트/다크 테마를 추종한다. 변수 정의부는 `styles.css`/`styles.module.css`(plain·css-modules) 와 런타임 주입 스타일(tailwind) — 세 variant 모두 동일하게 동작. moss 는 accent 토큰과 맞춘 톤.",
24
+ "**인라인 링크 편집** — 기존 `window.prompt` 를 제거하고 툴바 아래로 펼쳐지는 인라인 입력 행으로 교체(URL 입력 + 적용/제거/취소 아이콘, Enter 적용·Esc 취소). 메일 클라이언트식 UX. 읽기 전용일 때만 링크가 클릭으로 열리고(`openOnClick`), 편집 중엔 이탈 방지.",
25
+ "**`compact` + `toolbarMode=\"focus\"`** — `compact` 는 핵심 버튼(굵게·기울임·밑줄·취소선·글자색·링크·목록)만 노출해 좁은 패널에 맞춘다. `toolbarMode=\"focus\"` 는 포커스 전 툴바를 숨겨 인라인 입력처럼 보이게 한다. 포커스 추적은 래퍼의 `focusin`/`focusout`(relatedTarget 가드)으로 처리 — 링크 입력·컬러 스와치로 포커스가 옮겨가도 패널이 닫히지 않는다.",
26
+ "**활성표시 반응성 + i18n** — 툴바를 `useEditorState` 로 트랜잭션마다 구독해 굵게/밑줄 등 활성 상태가 즉시 반영된다(v3 `useEditor` 는 기본적으로 트랜잭션마다 리렌더하지 않음). `labels` prop(`RichTextEditorLabels`)으로 모든 버튼 라벨/툴팁을 현지화 가능 — 누락 키는 영어 기본값으로 폴백.",
27
+ "**의존성** — `@tiptap/extension-text-style` 추가(`TextStyle` + `Color` 제공). 설치: `pnpm add @tiptap/extension-text-style`. 기존 RTE 사용처는 변경 없이 동작(신규 props 전부 optional)."
28
+ ],
29
+ "url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.115.0"
30
+ },
5
31
  {
6
32
  "version": "0.114.0",
7
33
  "date": "2026-05-27",