@simplysm/sd-cli 14.0.10 → 14.0.12

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.
Files changed (266) hide show
  1. package/README.md +58 -253
  2. package/dist/angular/client-transform-stylesheet.js +1 -1
  3. package/dist/angular/client-transform-stylesheet.js.map +1 -1
  4. package/dist/angular/vite-angular-plugin.d.ts +1 -1
  5. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  6. package/dist/angular/vite-angular-plugin.js +60 -34
  7. package/dist/angular/vite-angular-plugin.js.map +1 -1
  8. package/dist/angular/vite-postcss-inline-plugin.d.ts +1 -1
  9. package/dist/angular/vite-postcss-inline-plugin.js +1 -1
  10. package/dist/capacitor/capacitor.d.ts +14 -2
  11. package/dist/capacitor/capacitor.d.ts.map +1 -1
  12. package/dist/capacitor/capacitor.js +131 -17
  13. package/dist/capacitor/capacitor.js.map +1 -1
  14. package/dist/commands/build.d.ts +3 -10
  15. package/dist/commands/build.d.ts.map +1 -1
  16. package/dist/commands/build.js +3 -10
  17. package/dist/commands/build.js.map +1 -1
  18. package/dist/commands/check.js +3 -3
  19. package/dist/commands/check.js.map +1 -1
  20. package/dist/commands/dev.d.ts +3 -9
  21. package/dist/commands/dev.d.ts.map +1 -1
  22. package/dist/commands/dev.js +3 -9
  23. package/dist/commands/dev.js.map +1 -1
  24. package/dist/commands/device.d.ts +13 -0
  25. package/dist/commands/device.d.ts.map +1 -0
  26. package/dist/commands/device.js +53 -0
  27. package/dist/commands/device.js.map +1 -0
  28. package/dist/commands/publish.d.ts +1 -1
  29. package/dist/commands/publish.d.ts.map +1 -1
  30. package/dist/commands/publish.js +18 -26
  31. package/dist/commands/publish.js.map +1 -1
  32. package/dist/commands/replace-deps.d.ts +3 -3
  33. package/dist/commands/replace-deps.d.ts.map +1 -1
  34. package/dist/commands/replace-deps.js +1 -1
  35. package/dist/commands/typecheck.d.ts +4 -3
  36. package/dist/commands/typecheck.d.ts.map +1 -1
  37. package/dist/commands/typecheck.js +5 -11
  38. package/dist/commands/typecheck.js.map +1 -1
  39. package/dist/commands/watch.d.ts +9 -9
  40. package/dist/commands/watch.js +9 -9
  41. package/dist/electron/electron.d.ts.map +1 -1
  42. package/dist/electron/electron.js +42 -3
  43. package/dist/electron/electron.js.map +1 -1
  44. package/dist/engines/BaseEngine.d.ts +1 -1
  45. package/dist/engines/BaseEngine.d.ts.map +1 -1
  46. package/dist/engines/BaseEngine.js +3 -1
  47. package/dist/engines/BaseEngine.js.map +1 -1
  48. package/dist/engines/NgtscEngine.d.ts +7 -7
  49. package/dist/engines/NgtscEngine.d.ts.map +1 -1
  50. package/dist/engines/NgtscEngine.js +3 -3
  51. package/dist/engines/ServerEsbuildEngine.d.ts +7 -7
  52. package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
  53. package/dist/engines/ServerEsbuildEngine.js +3 -3
  54. package/dist/engines/TscEngine.d.ts +7 -7
  55. package/dist/engines/TscEngine.d.ts.map +1 -1
  56. package/dist/engines/TscEngine.js +3 -3
  57. package/dist/engines/ViteEngine.d.ts +1 -1
  58. package/dist/engines/ViteEngine.d.ts.map +1 -1
  59. package/dist/engines/ViteEngine.js +7 -12
  60. package/dist/engines/ViteEngine.js.map +1 -1
  61. package/dist/engines/index.d.ts +5 -5
  62. package/dist/engines/index.js +5 -5
  63. package/dist/engines/types.d.ts +20 -20
  64. package/dist/engines/types.d.ts.map +1 -1
  65. package/dist/infra/ResultCollector.d.ts +9 -9
  66. package/dist/infra/ResultCollector.js +8 -8
  67. package/dist/infra/SignalHandler.d.ts +7 -7
  68. package/dist/infra/SignalHandler.js +7 -7
  69. package/dist/infra/WorkerManager.d.ts +14 -14
  70. package/dist/infra/WorkerManager.js +14 -14
  71. package/dist/orchestrators/BuildOrchestrator.d.ts +25 -25
  72. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  73. package/dist/orchestrators/BuildOrchestrator.js +29 -29
  74. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  75. package/dist/orchestrators/DevWatchOrchestrator.d.ts +7 -7
  76. package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
  77. package/dist/orchestrators/DevWatchOrchestrator.js +35 -57
  78. package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
  79. package/dist/sd-cli-entry.d.ts +2 -2
  80. package/dist/sd-cli-entry.d.ts.map +1 -1
  81. package/dist/sd-cli-entry.js +45 -9
  82. package/dist/sd-cli-entry.js.map +1 -1
  83. package/dist/sd-cli.d.ts +3 -3
  84. package/dist/sd-cli.js +16 -16
  85. package/dist/sd-cli.js.map +1 -1
  86. package/dist/sd-config.types.d.ts +105 -105
  87. package/dist/sd-config.types.d.ts.map +1 -1
  88. package/dist/utils/angular-compiler.js +5 -5
  89. package/dist/utils/angular-compiler.js.map +1 -1
  90. package/dist/utils/build-env.d.ts +1 -1
  91. package/dist/utils/build-env.js +1 -1
  92. package/dist/utils/concurrency.d.ts +7 -7
  93. package/dist/utils/concurrency.js +7 -7
  94. package/dist/utils/copy-public.d.ts +9 -9
  95. package/dist/utils/copy-public.js +17 -17
  96. package/dist/utils/copy-public.js.map +1 -1
  97. package/dist/utils/copy-src.d.ts +9 -9
  98. package/dist/utils/copy-src.js +11 -11
  99. package/dist/utils/copy-src.js.map +1 -1
  100. package/dist/utils/engine-stop.d.ts +8 -9
  101. package/dist/utils/engine-stop.d.ts.map +1 -1
  102. package/dist/utils/engine-stop.js +9 -10
  103. package/dist/utils/engine-stop.js.map +1 -1
  104. package/dist/utils/esbuild-config.d.ts +23 -23
  105. package/dist/utils/esbuild-config.d.ts.map +1 -1
  106. package/dist/utils/esbuild-config.js +25 -25
  107. package/dist/utils/esbuild-config.js.map +1 -1
  108. package/dist/utils/lint-with-program.d.ts +15 -15
  109. package/dist/utils/lint-with-program.d.ts.map +1 -1
  110. package/dist/utils/lint-with-program.js +29 -29
  111. package/dist/utils/lint-with-program.js.map +1 -1
  112. package/dist/utils/ngtsc-build-core.d.ts +8 -8
  113. package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
  114. package/dist/utils/ngtsc-build-core.js +14 -14
  115. package/dist/utils/ngtsc-build-core.js.map +1 -1
  116. package/dist/utils/output-path-rewriter.d.ts +14 -14
  117. package/dist/utils/output-path-rewriter.js +18 -18
  118. package/dist/utils/output-path-rewriter.js.map +1 -1
  119. package/dist/utils/output-utils.d.ts +6 -6
  120. package/dist/utils/output-utils.js +11 -11
  121. package/dist/utils/output-utils.js.map +1 -1
  122. package/dist/utils/package-utils.d.ts +21 -21
  123. package/dist/utils/package-utils.d.ts.map +1 -1
  124. package/dist/utils/package-utils.js +56 -45
  125. package/dist/utils/package-utils.js.map +1 -1
  126. package/dist/utils/replace-deps.d.ts +25 -25
  127. package/dist/utils/replace-deps.d.ts.map +1 -1
  128. package/dist/utils/replace-deps.js +84 -65
  129. package/dist/utils/replace-deps.js.map +1 -1
  130. package/dist/utils/sd-config.d.ts +3 -3
  131. package/dist/utils/sd-config.js +3 -3
  132. package/dist/utils/tsc-build.d.ts +13 -13
  133. package/dist/utils/tsc-build.d.ts.map +1 -1
  134. package/dist/utils/tsc-build.js +9 -9
  135. package/dist/utils/tsc-build.js.map +1 -1
  136. package/dist/utils/tsconfig.d.ts +11 -9
  137. package/dist/utils/tsconfig.d.ts.map +1 -1
  138. package/dist/utils/tsconfig.js +11 -9
  139. package/dist/utils/tsconfig.js.map +1 -1
  140. package/dist/utils/typecheck-non-package.d.ts +5 -6
  141. package/dist/utils/typecheck-non-package.d.ts.map +1 -1
  142. package/dist/utils/typecheck-non-package.js +7 -8
  143. package/dist/utils/typecheck-non-package.js.map +1 -1
  144. package/dist/utils/typecheck-serialization.d.ts +8 -8
  145. package/dist/utils/typecheck-serialization.d.ts.map +1 -1
  146. package/dist/utils/typecheck-serialization.js +12 -16
  147. package/dist/utils/typecheck-serialization.js.map +1 -1
  148. package/dist/utils/vite-config.d.ts +8 -5
  149. package/dist/utils/vite-config.d.ts.map +1 -1
  150. package/dist/utils/vite-config.js +36 -29
  151. package/dist/utils/vite-config.js.map +1 -1
  152. package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
  153. package/dist/utils/vite-scope-watch-plugin.js +1 -1
  154. package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
  155. package/dist/utils/worker-events.d.ts +12 -12
  156. package/dist/utils/worker-events.d.ts.map +1 -1
  157. package/dist/utils/worker-events.js +10 -10
  158. package/dist/utils/worker-events.js.map +1 -1
  159. package/dist/utils/worker-utils.d.ts +12 -13
  160. package/dist/utils/worker-utils.d.ts.map +1 -1
  161. package/dist/utils/worker-utils.js +12 -13
  162. package/dist/utils/worker-utils.js.map +1 -1
  163. package/dist/vitest-plugin.d.ts.map +1 -1
  164. package/dist/vitest-plugin.js +5 -7
  165. package/dist/vitest-plugin.js.map +1 -1
  166. package/dist/workers/client.worker.d.ts +4 -2
  167. package/dist/workers/client.worker.d.ts.map +1 -1
  168. package/dist/workers/client.worker.js +209 -1
  169. package/dist/workers/client.worker.js.map +1 -1
  170. package/dist/workers/library-build.worker.d.ts +1 -1
  171. package/dist/workers/library-build.worker.d.ts.map +1 -1
  172. package/dist/workers/library-build.worker.js +7 -7
  173. package/dist/workers/library-build.worker.js.map +1 -1
  174. package/dist/workers/lint.worker.d.ts +2 -2
  175. package/dist/workers/lint.worker.js +2 -2
  176. package/dist/workers/ngtsc-build.worker.js +30 -30
  177. package/dist/workers/ngtsc-build.worker.js.map +1 -1
  178. package/dist/workers/server-build.worker.d.ts +17 -17
  179. package/dist/workers/server-build.worker.d.ts.map +1 -1
  180. package/dist/workers/server-build.worker.js +46 -46
  181. package/dist/workers/server-build.worker.js.map +1 -1
  182. package/dist/workers/server-runtime.worker.d.ts +7 -7
  183. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  184. package/dist/workers/server-runtime.worker.js +17 -17
  185. package/dist/workers/server-runtime.worker.js.map +1 -1
  186. package/docs/config.md +340 -0
  187. package/docs/publish-configuration-types.md +87 -0
  188. package/docs/pwa-configuration-types.md +55 -0
  189. package/docs/vitest-plugin.md +47 -0
  190. package/package.json +9 -7
  191. package/src/angular/client-transform-stylesheet.ts +1 -1
  192. package/src/angular/vite-angular-plugin.ts +70 -37
  193. package/src/angular/vite-postcss-inline-plugin.ts +1 -1
  194. package/src/capacitor/capacitor.ts +159 -23
  195. package/src/commands/build.ts +3 -10
  196. package/src/commands/check.ts +3 -3
  197. package/src/commands/dev.ts +3 -9
  198. package/src/commands/device.ts +65 -0
  199. package/src/commands/publish.ts +30 -26
  200. package/src/commands/replace-deps.ts +3 -3
  201. package/src/commands/typecheck.ts +7 -13
  202. package/src/commands/watch.ts +9 -9
  203. package/src/electron/electron.ts +49 -4
  204. package/src/engines/BaseEngine.ts +4 -1
  205. package/src/engines/NgtscEngine.ts +7 -7
  206. package/src/engines/ServerEsbuildEngine.ts +7 -7
  207. package/src/engines/TscEngine.ts +7 -7
  208. package/src/engines/ViteEngine.ts +8 -13
  209. package/src/engines/index.ts +5 -5
  210. package/src/engines/types.ts +20 -20
  211. package/src/infra/ResultCollector.ts +9 -9
  212. package/src/infra/SignalHandler.ts +7 -7
  213. package/src/infra/WorkerManager.ts +14 -14
  214. package/src/orchestrators/BuildOrchestrator.ts +37 -37
  215. package/src/orchestrators/DevWatchOrchestrator.ts +37 -61
  216. package/src/sd-cli-entry.ts +51 -9
  217. package/src/sd-cli.ts +16 -16
  218. package/src/sd-config.types.ts +107 -107
  219. package/src/utils/angular-compiler.ts +5 -5
  220. package/src/utils/build-env.ts +1 -1
  221. package/src/utils/concurrency.ts +7 -7
  222. package/src/utils/copy-public.ts +17 -17
  223. package/src/utils/copy-src.ts +11 -11
  224. package/src/utils/engine-stop.ts +9 -10
  225. package/src/utils/esbuild-config.ts +29 -29
  226. package/src/utils/lint-with-program.ts +34 -34
  227. package/src/utils/ngtsc-build-core.ts +17 -17
  228. package/src/utils/output-path-rewriter.ts +18 -18
  229. package/src/utils/output-utils.ts +11 -11
  230. package/src/utils/package-utils.ts +57 -45
  231. package/src/utils/replace-deps.ts +92 -67
  232. package/src/utils/sd-config.ts +3 -3
  233. package/src/utils/tsc-build.ts +18 -18
  234. package/src/utils/tsconfig.ts +11 -9
  235. package/src/utils/typecheck-non-package.ts +7 -8
  236. package/src/utils/typecheck-serialization.ts +13 -15
  237. package/src/utils/vite-config.ts +45 -35
  238. package/src/utils/vite-scope-watch-plugin.ts +6 -1
  239. package/src/utils/worker-events.ts +16 -16
  240. package/src/utils/worker-utils.ts +12 -13
  241. package/src/vitest-plugin.ts +5 -8
  242. package/src/workers/client.worker.ts +236 -2
  243. package/src/workers/library-build.worker.ts +8 -8
  244. package/src/workers/lint.worker.ts +2 -2
  245. package/src/workers/ngtsc-build.worker.ts +31 -31
  246. package/src/workers/server-build.worker.ts +60 -60
  247. package/src/workers/server-runtime.worker.ts +22 -22
  248. package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +1 -0
  249. package/tests/angular/vite-angular-plugin-hmr.spec.ts +78 -0
  250. package/tests/angular/vite-angular-plugin.spec.ts +67 -0
  251. package/tests/capacitor/capacitor-build.spec.ts +6 -4
  252. package/tests/capacitor/capacitor-icon.spec.ts +7 -5
  253. package/tests/capacitor/capacitor-init.spec.ts +120 -10
  254. package/tests/capacitor/capacitor-run.spec.ts +14 -17
  255. package/tests/capacitor/capacitor-workspace.spec.ts +5 -3
  256. package/tests/commands/check.spec.ts +2 -2
  257. package/tests/commands/device.spec.ts +147 -0
  258. package/tests/commands/publish.spec.ts +2 -2
  259. package/tests/commands/typecheck.spec.ts +8 -0
  260. package/tests/electron/electron.spec.ts +12 -10
  261. package/tests/engines/base-engine.spec.ts +37 -0
  262. package/tests/engines/vite-engine.spec.ts +115 -3
  263. package/tests/orchestrators/dev-watch-orchestrator.spec.ts +21 -93
  264. package/tests/utils/vite-config.spec.ts +144 -90
  265. package/tests/workers/client-worker.spec.ts +690 -0
  266. package/tests/workers/server-build-worker.spec.ts +3 -3
@@ -21,17 +21,16 @@ import { SignalHandler } from "../infra/SignalHandler";
21
21
  import { createBuildEngine, type BuildEngine, type BuildPackageInfo, type ClientPackageInfo, type ServerPackageInfo } from "../engines/index";
22
22
  import { watchCopySrcFiles } from "../utils/copy-src";
23
23
  import { Capacitor } from "../capacitor/capacitor";
24
- import { Electron } from "../electron/electron";
25
24
  import type * as ServerRuntimeWorkerModule from "../workers/server-runtime.worker";
26
25
  import type { ServerReadyEventData, ErrorEventData } from "../utils/worker-events";
27
26
 
28
27
  /**
29
- * Orchestrator mode
28
+ * Orchestrator 모드
30
29
  */
31
30
  export type OrchestratorMode = "watch" | "dev";
32
31
 
33
32
  /**
34
- * DevWatchOrchestrator options
33
+ * DevWatchOrchestrator 옵션
35
34
  */
36
35
  export interface DevWatchOrchestratorOptions {
37
36
  mode: OrchestratorMode;
@@ -40,26 +39,26 @@ export interface DevWatchOrchestratorOptions {
40
39
  }
41
40
 
42
41
  /**
43
- * Unified Orchestrator for watch and dev modes.
42
+ * watch/dev 모드 통합 Orchestrator
44
43
  *
45
- * - watch: Library(js+dts) + Scripts(watch hook) + copySrc + replaceDeps
46
- * - dev: Server(js+runtime) + client-ready(skip) + replaceDeps
44
+ * - watch: 라이브러리(JS+DTS) + Scripts(watch hook) + copySrc + replaceDeps
45
+ * - dev: 서버(JS+런타임) + 클라이언트 준비(skip) + replaceDeps
47
46
  */
48
47
  export class DevWatchOrchestrator {
49
48
  private readonly _cwd: string;
50
49
  private readonly _options: DevWatchOrchestratorOptions;
51
50
  private readonly _logger;
52
51
 
53
- // Infrastructure
52
+ // 인프라
54
53
  private _resultCollector!: ResultCollector;
55
54
  private _signalHandler!: SignalHandler;
56
55
  private _rebuildManager!: RebuildManager;
57
56
 
58
- // Engines
57
+ // 엔진
59
58
  private readonly _libraryEngines: BuildEngine[] = [];
60
59
  private readonly _serverEngines = new Map<string, BuildEngine>();
61
60
 
62
- // Package info
61
+ // 패키지 정보
63
62
  private _libraryPackages: BuildPackageInfo[] = [];
64
63
  private _serverPackages: Array<{ name: string; dir: string; config: SdServerPackageConfig }> = [];
65
64
  private _watchHookPackages: Array<{ name: string; dir: string; config: SdScriptsPackageConfig | SdBuildPackageConfig }> = [];
@@ -67,13 +66,13 @@ export class DevWatchOrchestrator {
67
66
  private readonly _clientEngines = new Map<string, BuildEngine>();
68
67
  private _serverClientsMap = new Map<string, string[]>();
69
68
 
70
- // Dev mode: runtime workers
69
+ // dev 모드: 런타임 워커
71
70
  private _baseEnv: { VER: string; DEV: string } | undefined;
72
71
  private readonly _serverRuntimeWorkers = new Map<string, WorkerProxy<typeof ServerRuntimeWorkerModule>>();
73
72
  private _printServersTimer: ReturnType<typeof setTimeout> | undefined;
74
73
  private _serverRestartTimer: ReturnType<typeof setTimeout> | undefined;
75
74
 
76
- // Watchers
75
+ // 워처
77
76
  private _copySrcWatchers: FsWatcher[] = [];
78
77
  private readonly _watchHookWatchers: FsWatcher[] = [];
79
78
  private readonly _watchHookChildren = new Map<string, ChildProcess>();
@@ -107,30 +106,30 @@ export class DevWatchOrchestrator {
107
106
  throw err;
108
107
  }
109
108
 
110
- // Build pathMap from config packages only (tests packages are excluded from watch/dev)
109
+ // config 패키지에서 pathMap 빌드 (tests 패키지는 watch/dev에서 제외)
111
110
  this._pathMap = buildPathMapFromConfig(sdConfig.packages);
112
111
 
113
- // Validate targets
112
+ // 대상 유효성 검사
114
113
  validateTargets(this._options.targets, sdConfig.packages);
115
114
 
116
- // Store replaceDeps for engine creation
115
+ // 엔진 생성을 위해 replaceDeps 저장
117
116
  this._replaceDeps = sdConfig.replaceDeps;
118
117
 
119
- // Start watch if replaceDeps config exists
118
+ // replaceDeps 설정이 있으면 watch 시작
120
119
  if (sdConfig.replaceDeps != null) {
121
120
  this._replaceDepWatcher = await watchReplaceDeps(this._cwd, sdConfig.replaceDeps);
122
121
  }
123
122
 
124
- // Prepare VER, DEV environment variables for dev mode
123
+ // dev 모드용 VER, DEV 환경변수 준비
125
124
  if (this._options.mode === "dev") {
126
125
  const version = await getVersion(this._cwd);
127
126
  this._baseEnv = { VER: version, DEV: "true" };
128
127
  }
129
128
 
130
- // Filter by targets
129
+ // 대상으로 필터링
131
130
  const allPackages = filterPackagesByTargets(sdConfig.packages, this._options.targets);
132
131
 
133
- // Classify packages based on mode
132
+ // 모드에 따라 패키지 분류
134
133
  if (this._options.mode === "watch") {
135
134
  const classified = classifyWatchPackages(allPackages, this._cwd, this._pathMap);
136
135
  this._libraryPackages = classified.libraryPackages;
@@ -142,7 +141,7 @@ export class DevWatchOrchestrator {
142
141
  this._serverClientsMap = classified.serverClientsMap;
143
142
  }
144
143
 
145
- // Check if there are packages to process
144
+ // 처리할 패키지가 있는지 확인
146
145
  const totalPackages = this._libraryPackages.length + this._serverPackages.length + this._watchHookPackages.length + this._clientPackages.length;
147
146
  if (totalPackages === 0) {
148
147
  const modeLabel = this._options.mode === "watch" ? "워치" : "개발";
@@ -152,12 +151,12 @@ export class DevWatchOrchestrator {
152
151
 
153
152
  this._hasPackages = true;
154
153
 
155
- // Initialize infrastructure
154
+ // 인프라 초기화
156
155
  this._signalHandler = new SignalHandler();
157
156
  this._resultCollector = new ResultCollector();
158
157
  this._rebuildManager = new RebuildManager(this._logger);
159
158
 
160
- // Batch complete handler
159
+ // 배치 완료 핸들러
161
160
  if (this._options.mode === "watch") {
162
161
  this._rebuildManager.on("batchComplete", (_completedKeys) => {
163
162
  printErrors(this._resultCollector.toMap());
@@ -168,7 +167,7 @@ export class DevWatchOrchestrator {
168
167
  });
169
168
  }
170
169
 
171
- // Create BuildEngines for library packages (watch mode only)
170
+ // 라이브러리 패키지용 BuildEngine 생성 (watch 모드 전용)
172
171
  for (const pkg of this._libraryPackages) {
173
172
  const engine = createBuildEngine(pkg, {
174
173
  cwd: this._cwd,
@@ -179,7 +178,7 @@ export class DevWatchOrchestrator {
179
178
  this._libraryEngines.push(engine);
180
179
  }
181
180
 
182
- // Create BuildEngines for server packages
181
+ // 서버 패키지용 BuildEngine 생성
183
182
  for (const { name, dir, config } of this._serverPackages) {
184
183
  const engineConfig = this._options.mode === "dev"
185
184
  ? { ...config, env: { ...this._baseEnv, ...config.env } }
@@ -197,7 +196,7 @@ export class DevWatchOrchestrator {
197
196
  this._serverEngines.set(name, engine);
198
197
  }
199
198
 
200
- // Create BuildEngines for client packages (dev mode only)
199
+ // 클라이언트 패키지용 BuildEngine 생성 (dev 모드 전용)
201
200
  const resolvedReplaceDeps = this._replaceDepWatcher?.entries.map((e) => ({
202
201
  packageName: e.targetName,
203
202
  sourcePath: e.resolvedSourcePath,
@@ -250,16 +249,16 @@ export class DevWatchOrchestrator {
250
249
 
251
250
  const shutdownTasks: Array<Promise<void>> = [];
252
251
 
253
- // Stop all engines
252
+ // 모든 엔진 중지
254
253
  shutdownTasks.push(...this._libraryEngines.map((e) => e.stop()));
255
254
  shutdownTasks.push(...[...this._serverEngines.values()].map((e) => e.stop()));
256
255
  shutdownTasks.push(...[...this._clientEngines.values()].map((e) => e.stop()));
257
256
 
258
- // Close watchers (watch mode)
257
+ // 워처 종료 (watch 모드)
259
258
  shutdownTasks.push(...this._copySrcWatchers.map((w) => w.close()));
260
259
  shutdownTasks.push(...this._watchHookWatchers.map((w) => w.close()));
261
260
 
262
- // Kill hook child processes
261
+ // hook 자식 프로세스 종료
263
262
  for (const child of this._watchHookChildren.values()) {
264
263
  if (child.exitCode == null) {
265
264
  child.kill();
@@ -267,7 +266,7 @@ export class DevWatchOrchestrator {
267
266
  }
268
267
  this._watchHookChildren.clear();
269
268
 
270
- // Terminate runtime workers (dev mode)
269
+ // 런타임 워커 종료 (dev 모드)
271
270
  shutdownTasks.push(...[...this._serverRuntimeWorkers.values()].map((w) => w.terminate()));
272
271
 
273
272
  await Promise.all(shutdownTasks);
@@ -278,7 +277,7 @@ export class DevWatchOrchestrator {
278
277
  process.stdout.write("✔ 종료 완료\n");
279
278
  }
280
279
 
281
- // --- Watch mode ---
280
+ // --- watch 모드 ---
282
281
 
283
282
  private async _startWatchMode(): Promise<void> {
284
283
  this._logger.debug("watch 모드 시작");
@@ -347,7 +346,7 @@ export class DevWatchOrchestrator {
347
346
  });
348
347
  }
349
348
 
350
- // --- Dev mode ---
349
+ // --- dev 모드 ---
351
350
 
352
351
  private async _startDevMode(): Promise<void> {
353
352
  // Start client and server engines in parallel
@@ -381,7 +380,7 @@ export class DevWatchOrchestrator {
381
380
  }
382
381
  });
383
382
 
384
- // Register standalone client results in ResultCollector
383
+ // 독립 클라이언트 결과를 ResultCollector에 등록
385
384
  for (const { name } of this._clientPackages) {
386
385
  const isServerConnected = [...this._serverClientsMap.values()].some(
387
386
  (clients) => clients.includes(name),
@@ -400,46 +399,23 @@ export class DevWatchOrchestrator {
400
399
  }
401
400
  }
402
401
 
403
- // Start native apps for client packages with capacitor/electron config
402
+ // 클라이언트 패키지의 Capacitor 초기화 (디바이스 실행은 'device' 명령어가 담당)
404
403
  for (const { name, config } of this._clientPackages) {
405
404
  const port = this._getClientPort(name);
406
405
  if (port == null) continue;
407
406
 
408
- const devServerUrl = `http://localhost:${port}`;
409
407
  const pkgDir = pathx.posixResolve(this._cwd, "packages", name);
410
408
 
411
409
  if (config.capacitor != null) {
412
410
  try {
413
411
  const cap = await Capacitor.create(pkgDir, config.capacitor, config.exclude);
414
412
  await cap.initialize();
415
- await cap.run(devServerUrl);
416
413
  } catch (err) {
417
414
  this._logger.error(
418
- `[${name}] Capacitor 실행 실패: ${errNs.message(err)}`,
415
+ `[${name}] Capacitor 초기화 실패: ${errNs.message(err)}`,
419
416
  );
420
417
  }
421
418
  }
422
-
423
- if (config.electron != null) {
424
- void (async () => {
425
- try {
426
- const elc = await Electron.create(pkgDir, config.electron!, config.exclude);
427
- await elc.initialize();
428
- await elc.run(devServerUrl);
429
- } catch (err) {
430
- this._logger.error(
431
- `[${name}] Electron 실행 실패: ${errNs.message(err)}`,
432
- );
433
- this._resultCollector.add({
434
- name,
435
- target: "client",
436
- type: "build",
437
- status: "error",
438
- message: `Electron 실행 실패: ${errNs.message(err)}`,
439
- });
440
- }
441
- })();
442
- }
443
419
  }
444
420
 
445
421
  // Print initial results
@@ -498,13 +474,13 @@ export class DevWatchOrchestrator {
498
474
  }, 300);
499
475
  }
500
476
 
501
- /** Get port from a client engine (duck-typing for ViteEngine.port) */
477
+ /** 클라이언트 엔진에서 포트 가져오기 (ViteEngine.port에 대한 duck-typing) */
502
478
  private _getClientPort(name: string): number | undefined {
503
479
  const engine = this._clientEngines.get(name) as { port?: number } | undefined;
504
480
  return engine?.port;
505
481
  }
506
482
 
507
- /** Collect client ports for a server's connected clients */
483
+ /** 서버에 연결된 클라이언트들의 포트 수집 */
508
484
  private _collectClientPorts(serverName: string): Record<string, number> {
509
485
  const clientPorts: Record<string, number> = {};
510
486
  const connectedClients = this._serverClientsMap.get(serverName) ?? [];
@@ -525,19 +501,19 @@ export class DevWatchOrchestrator {
525
501
  ): Promise<void> {
526
502
  this._logger.debug(`[${serverName}] 서버 런타임 시작: ${mainJsPath}`);
527
503
 
528
- // Terminate existing runtime
504
+ // 기존 런타임 종료
529
505
  const existingRuntime = this._serverRuntimeWorkers.get(serverName);
530
506
  if (existingRuntime != null) {
531
507
  this._logger.info(`[${serverName}] 서버 재시작 중...`);
532
508
  await existingRuntime.terminate();
533
509
  }
534
510
 
535
- // Create and start new runtime worker
511
+ // 런타임 워커 생성 시작
536
512
  const runtimeWorkerPath = import.meta.resolve("../workers/server-runtime.worker");
537
513
  const runtimeWorker = Worker.create<typeof ServerRuntimeWorkerModule>(runtimeWorkerPath);
538
514
  this._serverRuntimeWorkers.set(serverName, runtimeWorker);
539
515
 
540
- // Runtime event handlers
516
+ // 런타임 이벤트 핸들러
541
517
  runtimeWorker.on("serverReady", (readyData) => {
542
518
  const readyEvent = readyData as ServerReadyEventData;
543
519
  this._resultCollector.add({
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /* eslint-disable no-console */
3
3
 
4
- // side-effect: Map/Array prototype extensions (getOrCreate, etc.)
4
+ // 사이드 이펙트: Map/Array prototype 확장 (getOrCreate )
5
5
  import "@simplysm/core-common";
6
6
  import yargs, { type Argv } from "yargs";
7
7
  import { hideBin } from "yargs/helpers";
@@ -23,7 +23,7 @@ EventEmitter.defaultMaxListeners = 100;
23
23
 
24
24
  consola.options.reporters = [new SdCliReporter()];
25
25
 
26
- const COMMAND_NAMES = ["check", "watch", "dev", "build", "publish", "replace-deps"];
26
+ const COMMAND_NAMES = ["check", "watch", "dev", "device", "build", "publish", "replace-deps"];
27
27
 
28
28
  async function collectYargsHelp(argv: string[]): Promise<string> {
29
29
  const lines: string[] = [];
@@ -34,7 +34,7 @@ async function collectYargsHelp(argv: string[]): Promise<string> {
34
34
  try {
35
35
  await createCliParser(argv).exitProcess(false).parse();
36
36
  } catch {
37
- // yargs may throw after help display
37
+ // yargs help 출력 후 throw 있음
38
38
  } finally {
39
39
 
40
40
  console.log = orig;
@@ -43,11 +43,11 @@ async function collectYargsHelp(argv: string[]): Promise<string> {
43
43
  }
44
44
 
45
45
  /**
46
- * Create CLI parser
47
- * @internal exported for testing
46
+ * CLI 파서 생성
47
+ * @internal 테스트용으로 export
48
48
  */
49
49
  export function createCliParser(argv: string[]): Argv {
50
- // Top-level --help/-h (without a subcommand): show comprehensive help for all commands
50
+ // 최상위 --help/-h (서브커맨드 없이): 모든 명령어의 종합 도움말 표시
51
51
  const hasHelp = argv.includes("--help") || argv.includes("-h");
52
52
  const hasCommand = COMMAND_NAMES.some((cmd) => argv.includes(cmd));
53
53
  if (hasHelp && !hasCommand) {
@@ -185,6 +185,41 @@ export function createCliParser(argv: string[]): Argv {
185
185
  });
186
186
  },
187
187
  )
188
+ .command(
189
+ "device",
190
+ "Run native app on device/desktop",
191
+ (cmd) =>
192
+ cmd
193
+ .version(false)
194
+ .hide("help")
195
+ .options({
196
+ "package": {
197
+ type: "string",
198
+ alias: "p",
199
+ description: "Client package name to run",
200
+ demandOption: true,
201
+ },
202
+ "url": {
203
+ type: "string",
204
+ description: "Dev server URL (auto-detected from sd.config.ts if omitted)",
205
+ },
206
+ "opt": {
207
+ type: "string",
208
+ array: true,
209
+ alias: "o",
210
+ description: "Options to pass to sd.config.ts (e.g., -o key=value)",
211
+ default: [] as string[],
212
+ },
213
+ }),
214
+ async (args) => {
215
+ const { runDevice } = await import("./commands/device");
216
+ await runDevice({
217
+ package: args.package,
218
+ url: args.url,
219
+ options: args.opt,
220
+ });
221
+ },
222
+ )
188
223
  .command(
189
224
  "build [targets..]",
190
225
  "Run production build",
@@ -278,11 +313,18 @@ export function createCliParser(argv: string[]): Argv {
278
313
  },
279
314
  )
280
315
  .demandCommand(1, "Please specify a command.")
281
- .strict();
316
+ .strict()
317
+ .fail((msg, err) => {
318
+ if (msg) {
319
+ consola.error(msg);
320
+ process.exit(1);
321
+ }
322
+ throw err;
323
+ });
282
324
  }
283
325
 
284
- // Parse only when executed directly as CLI
285
- // Determine main module in ESM: normalize import.meta.url and process.argv[1] and compare
326
+ // CLI로 직접 실행될 때만 파싱
327
+ // ESM에서 메인 모듈 판별: import.meta.url process.argv[1] 정규화하여 비교
286
328
  const cliEntryPath = process.argv.at(1);
287
329
  if (
288
330
  cliEntryPath != null &&
package/src/sd-cli.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * CLI Launcher
4
+ * CLI 런처
5
5
  *
6
- * .ts execution (dev): apply CPU affinity then directly import sd-cli-entry
7
- * .js execution (production): run replaceDeps then spawn sd-cli-entry in new process
6
+ * .ts 실행 (개발): CPU affinity 적용 sd-cli-entry를 직접 import
7
+ * .js 실행 (프로덕션): replaceDeps 실행 새 프로세스에서 sd-cli-entry 실행
8
8
  */
9
9
 
10
10
  import { cpx } from "@simplysm/core-node";
@@ -17,16 +17,16 @@ const __dirname = path.dirname(__filename);
17
17
  const isDev = path.extname(__filename) === ".ts";
18
18
 
19
19
  if (isDev) {
20
- // Dev mode (.ts): apply affinity then run directly
21
- // Main module detection fails with import only (process.argv[1] ≠ sd-cli-entry)
22
- // so createCliParser must be called explicitly.
20
+ // 개발 모드 (.ts): affinity 적용 직접 실행
21
+ // import만으로는 메인 모듈 판별이 실패하므로 (process.argv[1] ≠ sd-cli-entry)
22
+ // createCliParser 명시적으로 호출해야 한다.
23
23
  configureAffinityAndPriority(process.pid);
24
24
  const { createCliParser } = await import("./sd-cli-entry.js");
25
25
  await createCliParser(process.argv.slice(2)).parse();
26
26
  } else {
27
27
  // Production mode (.js): two-stage execution
28
28
 
29
- // Phase 1: replaceDeps (inlinecopy to installed version)
29
+ // Phase 1: replaceDeps (인라인설치된 버전으로 복사)
30
30
  try {
31
31
  const { loadSdConfig } = await import("./utils/sd-config.js");
32
32
  const { setupReplaceDeps } = await import("./utils/replace-deps.js");
@@ -35,12 +35,12 @@ if (isDev) {
35
35
  await setupReplaceDeps(process.cwd(), sdConfig.replaceDeps);
36
36
  }
37
37
  } catch {
38
- // Skip if sd.config.ts is missing or replaceDeps is not configured
38
+ // sd.config.ts 없거나 replaceDeps 설정되지 않으면 건너뜀
39
39
  }
40
40
 
41
- // Phase 2: Run actual CLI in new process (reset module cache)
41
+ // Phase 2: 실제 CLI 프로세스로 실행 (모듈 캐시 초기화)
42
42
  const cliEntryFilePath = path.join(__dirname, "sd-cli-entry.js");
43
- const subprocess = cpx.exec(
43
+ const subprocess = cpx.spawn(
44
44
  "node",
45
45
  [
46
46
  "--max-old-space-size=8192",
@@ -56,10 +56,10 @@ if (isDev) {
56
56
  }
57
57
 
58
58
  /**
59
- * Calculate CPU affinity mask (exclude front cores)
59
+ * CPU affinity 마스크 계산 (앞쪽 코어 제외)
60
60
  *
61
- * Exclude 1 core per 4 CPUs, then set bits ON for remaining cores.
62
- * Example: 8 cores exclude 2 → 0xFC (cores 2~7)
61
+ * CPU 4개당 1 코어를 제외하고, 나머지 코어의 비트를 ON으로 설정한다.
62
+ * 예시: 8코어 → 2 제외 → 0xFC (코어 2~7)
63
63
  */
64
64
  function calculateAffinityMask(cpuCount: number): string {
65
65
  const exclude = cpuCount <= 1 ? 0 : Math.ceil(cpuCount / 4);
@@ -71,12 +71,12 @@ function calculateAffinityMask(cpuCount: number): string {
71
71
  }
72
72
 
73
73
  /**
74
- * Configure CPU affinity and priority (cross-platform)
74
+ * CPU affinity 우선순위 설정 (크로스 플랫폼)
75
75
  *
76
76
  * - Windows: PowerShell ProcessorAffinity + PriorityClass
77
77
  * - Linux/WSL: taskset + renice
78
78
  *
79
- * Only print warning on failure; does not affect CLI operation.
79
+ * 실패 경고만 출력하며, CLI 동작에는 영향을 주지 않는다.
80
80
  */
81
81
  function configureAffinityAndPriority(pid: number): void {
82
82
  const cpuCount = os.cpus().length;
@@ -94,7 +94,7 @@ function configureAffinityAndPriority(pid: number): void {
94
94
  command = `taskset -p ${mask} ${pid} && renice +10 -p ${pid}`;
95
95
  }
96
96
 
97
- cpx.exec(command, [], { shell: true }).catch((err: unknown) => {
97
+ cpx.spawn(command, [], { shell: true }).catch((err: unknown) => {
98
98
  // eslint-disable-next-line no-console
99
99
  console.warn(
100
100
  "Failed to configure CPU affinity/priority:",