@simplysm/sd-cli 14.0.8 → 14.0.10

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 (254) hide show
  1. package/dist/angular/client-transform-stylesheet.d.ts.map +1 -1
  2. package/dist/angular/client-transform-stylesheet.js.map +1 -1
  3. package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
  4. package/dist/angular/vite-angular-plugin.js +15 -8
  5. package/dist/angular/vite-angular-plugin.js.map +1 -1
  6. package/dist/angular/vite-postcss-inline-plugin.d.ts.map +1 -1
  7. package/dist/angular/vite-postcss-inline-plugin.js.map +1 -1
  8. package/dist/capacitor/capacitor.d.ts.map +1 -1
  9. package/dist/capacitor/capacitor.js +41 -41
  10. package/dist/capacitor/capacitor.js.map +1 -1
  11. package/dist/commands/build.d.ts.map +1 -1
  12. package/dist/commands/build.js.map +1 -1
  13. package/dist/commands/check.d.ts.map +1 -1
  14. package/dist/commands/check.js.map +1 -1
  15. package/dist/commands/dev.d.ts.map +1 -1
  16. package/dist/commands/dev.js.map +1 -1
  17. package/dist/commands/lint.d.ts.map +1 -1
  18. package/dist/commands/lint.js.map +1 -1
  19. package/dist/commands/publish.d.ts.map +1 -1
  20. package/dist/commands/publish.js.map +1 -1
  21. package/dist/commands/replace-deps.d.ts.map +1 -1
  22. package/dist/commands/replace-deps.js.map +1 -1
  23. package/dist/commands/typecheck.d.ts.map +1 -1
  24. package/dist/commands/typecheck.js +12 -12
  25. package/dist/commands/typecheck.js.map +1 -1
  26. package/dist/commands/watch.d.ts.map +1 -1
  27. package/dist/commands/watch.js.map +1 -1
  28. package/dist/electron/electron.d.ts.map +1 -1
  29. package/dist/electron/electron.js +26 -27
  30. package/dist/electron/electron.js.map +1 -1
  31. package/dist/engines/BaseEngine.d.ts +1 -5
  32. package/dist/engines/BaseEngine.d.ts.map +1 -1
  33. package/dist/engines/BaseEngine.js +7 -16
  34. package/dist/engines/BaseEngine.js.map +1 -1
  35. package/dist/engines/NgtscEngine.d.ts.map +1 -1
  36. package/dist/engines/NgtscEngine.js +10 -11
  37. package/dist/engines/NgtscEngine.js.map +1 -1
  38. package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
  39. package/dist/engines/ServerEsbuildEngine.js +10 -11
  40. package/dist/engines/ServerEsbuildEngine.js.map +1 -1
  41. package/dist/engines/TscEngine.d.ts.map +1 -1
  42. package/dist/engines/TscEngine.js +10 -11
  43. package/dist/engines/TscEngine.js.map +1 -1
  44. package/dist/engines/ViteEngine.d.ts.map +1 -1
  45. package/dist/engines/ViteEngine.js +3 -13
  46. package/dist/engines/ViteEngine.js.map +1 -1
  47. package/dist/engines/index.d.ts.map +1 -1
  48. package/dist/engines/index.js.map +1 -1
  49. package/dist/engines/types.d.ts +3 -6
  50. package/dist/engines/types.d.ts.map +1 -1
  51. package/dist/engines/types.js.map +1 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/infra/ResultCollector.d.ts +1 -1
  55. package/dist/infra/ResultCollector.d.ts.map +1 -1
  56. package/dist/infra/ResultCollector.js.map +1 -1
  57. package/dist/infra/SignalHandler.d.ts.map +1 -1
  58. package/dist/infra/SignalHandler.js.map +1 -1
  59. package/dist/infra/WorkerManager.d.ts.map +1 -1
  60. package/dist/infra/WorkerManager.js.map +1 -1
  61. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  62. package/dist/orchestrators/BuildOrchestrator.js +30 -61
  63. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  64. package/dist/orchestrators/DevWatchOrchestrator.d.ts +2 -0
  65. package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
  66. package/dist/orchestrators/DevWatchOrchestrator.js +40 -44
  67. package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
  68. package/dist/sd-cli-entry.d.ts.map +1 -1
  69. package/dist/sd-cli-entry.js +2 -13
  70. package/dist/sd-cli-entry.js.map +1 -1
  71. package/dist/sd-cli.d.ts.map +1 -1
  72. package/dist/sd-cli.js.map +1 -1
  73. package/dist/sd-config.types.d.ts.map +1 -1
  74. package/dist/sd-config.types.js.map +1 -1
  75. package/dist/utils/SdCliReporter.d.ts +18 -0
  76. package/dist/utils/SdCliReporter.d.ts.map +1 -0
  77. package/dist/utils/SdCliReporter.js +144 -0
  78. package/dist/utils/SdCliReporter.js.map +1 -0
  79. package/dist/utils/angular-build.d.ts.map +1 -1
  80. package/dist/utils/angular-build.js.map +1 -1
  81. package/dist/utils/angular-compiler.d.ts.map +1 -1
  82. package/dist/utils/angular-compiler.js +11 -4
  83. package/dist/utils/angular-compiler.js.map +1 -1
  84. package/dist/utils/build-env.d.ts.map +1 -1
  85. package/dist/utils/build-env.js +2 -1
  86. package/dist/utils/build-env.js.map +1 -1
  87. package/dist/utils/concurrency.d.ts.map +1 -1
  88. package/dist/utils/concurrency.js.map +1 -1
  89. package/dist/utils/copy-public.d.ts.map +1 -1
  90. package/dist/utils/copy-public.js +21 -21
  91. package/dist/utils/copy-public.js.map +1 -1
  92. package/dist/utils/copy-src.d.ts.map +1 -1
  93. package/dist/utils/copy-src.js +12 -12
  94. package/dist/utils/copy-src.js.map +1 -1
  95. package/dist/utils/diagnostic-utils.d.ts.map +1 -1
  96. package/dist/utils/diagnostic-utils.js +3 -2
  97. package/dist/utils/diagnostic-utils.js.map +1 -1
  98. package/dist/utils/engine-stop.d.ts.map +1 -1
  99. package/dist/utils/engine-stop.js.map +1 -1
  100. package/dist/utils/esbuild-config.d.ts.map +1 -1
  101. package/dist/utils/esbuild-config.js +2 -0
  102. package/dist/utils/esbuild-config.js.map +1 -1
  103. package/dist/utils/generate-pwa-icons.d.ts.map +1 -1
  104. package/dist/utils/generate-pwa-icons.js.map +1 -1
  105. package/dist/utils/hmr-candidates.d.ts.map +1 -1
  106. package/dist/utils/hmr-candidates.js.map +1 -1
  107. package/dist/utils/lint-utils.d.ts.map +1 -1
  108. package/dist/utils/lint-utils.js.map +1 -1
  109. package/dist/utils/lint-with-program.d.ts.map +1 -1
  110. package/dist/utils/lint-with-program.js +7 -3
  111. package/dist/utils/lint-with-program.js.map +1 -1
  112. package/dist/utils/ngtsc-build-core.d.ts +2 -10
  113. package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
  114. package/dist/utils/ngtsc-build-core.js +16 -15
  115. package/dist/utils/ngtsc-build-core.js.map +1 -1
  116. package/dist/utils/orchestrator-utils.d.ts.map +1 -1
  117. package/dist/utils/orchestrator-utils.js.map +1 -1
  118. package/dist/utils/output-path-rewriter.d.ts.map +1 -1
  119. package/dist/utils/output-path-rewriter.js +7 -7
  120. package/dist/utils/output-path-rewriter.js.map +1 -1
  121. package/dist/utils/output-utils.d.ts.map +1 -1
  122. package/dist/utils/output-utils.js +1 -1
  123. package/dist/utils/output-utils.js.map +1 -1
  124. package/dist/utils/package-utils.d.ts +4 -0
  125. package/dist/utils/package-utils.d.ts.map +1 -1
  126. package/dist/utils/package-utils.js +34 -13
  127. package/dist/utils/package-utils.js.map +1 -1
  128. package/dist/utils/rebuild-manager.d.ts +1 -1
  129. package/dist/utils/rebuild-manager.d.ts.map +1 -1
  130. package/dist/utils/rebuild-manager.js +3 -1
  131. package/dist/utils/rebuild-manager.js.map +1 -1
  132. package/dist/utils/replace-deps.d.ts.map +1 -1
  133. package/dist/utils/replace-deps.js +10 -10
  134. package/dist/utils/replace-deps.js.map +1 -1
  135. package/dist/utils/scss-compiler.d.ts.map +1 -1
  136. package/dist/utils/scss-compiler.js.map +1 -1
  137. package/dist/utils/sd-config.d.ts.map +1 -1
  138. package/dist/utils/sd-config.js +2 -3
  139. package/dist/utils/sd-config.js.map +1 -1
  140. package/dist/utils/tsc-build.d.ts +3 -1
  141. package/dist/utils/tsc-build.d.ts.map +1 -1
  142. package/dist/utils/tsc-build.js +7 -4
  143. package/dist/utils/tsc-build.js.map +1 -1
  144. package/dist/utils/tsconfig.d.ts.map +1 -1
  145. package/dist/utils/tsconfig.js.map +1 -1
  146. package/dist/utils/typecheck-non-package.d.ts.map +1 -1
  147. package/dist/utils/typecheck-non-package.js +10 -5
  148. package/dist/utils/typecheck-non-package.js.map +1 -1
  149. package/dist/utils/typecheck-serialization.d.ts.map +1 -1
  150. package/dist/utils/typecheck-serialization.js.map +1 -1
  151. package/dist/utils/vite-config.d.ts.map +1 -1
  152. package/dist/utils/vite-config.js +2 -1
  153. package/dist/utils/vite-config.js.map +1 -1
  154. package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
  155. package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
  156. package/dist/utils/worker-events.d.ts +1 -1
  157. package/dist/utils/worker-events.d.ts.map +1 -1
  158. package/dist/utils/worker-events.js +1 -0
  159. package/dist/utils/worker-events.js.map +1 -1
  160. package/dist/utils/worker-utils.d.ts +1 -1
  161. package/dist/utils/worker-utils.d.ts.map +1 -1
  162. package/dist/utils/worker-utils.js +3 -1
  163. package/dist/utils/worker-utils.js.map +1 -1
  164. package/dist/vitest-plugin.d.ts.map +1 -1
  165. package/dist/vitest-plugin.js.map +1 -1
  166. package/dist/workers/client.worker.d.ts.map +1 -1
  167. package/dist/workers/client.worker.js +4 -0
  168. package/dist/workers/client.worker.js.map +1 -1
  169. package/dist/workers/library-build.worker.d.ts +2 -10
  170. package/dist/workers/library-build.worker.d.ts.map +1 -1
  171. package/dist/workers/library-build.worker.js +38 -14
  172. package/dist/workers/library-build.worker.js.map +1 -1
  173. package/dist/workers/lint.worker.d.ts.map +1 -1
  174. package/dist/workers/lint.worker.js.map +1 -1
  175. package/dist/workers/ngtsc-build.worker.d.ts.map +1 -1
  176. package/dist/workers/ngtsc-build.worker.js +40 -14
  177. package/dist/workers/ngtsc-build.worker.js.map +1 -1
  178. package/dist/workers/server-build.worker.d.ts +2 -10
  179. package/dist/workers/server-build.worker.d.ts.map +1 -1
  180. package/dist/workers/server-build.worker.js +28 -19
  181. package/dist/workers/server-build.worker.js.map +1 -1
  182. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  183. package/dist/workers/server-runtime.worker.js.map +1 -1
  184. package/package.json +4 -4
  185. package/src/angular/vite-angular-plugin.ts +18 -9
  186. package/src/capacitor/capacitor.ts +41 -41
  187. package/src/commands/typecheck.ts +12 -12
  188. package/src/electron/electron.ts +26 -27
  189. package/src/engines/BaseEngine.ts +8 -19
  190. package/src/engines/NgtscEngine.ts +11 -11
  191. package/src/engines/ServerEsbuildEngine.ts +11 -11
  192. package/src/engines/TscEngine.ts +11 -11
  193. package/src/engines/ViteEngine.ts +3 -14
  194. package/src/engines/types.ts +3 -6
  195. package/src/infra/ResultCollector.ts +1 -1
  196. package/src/orchestrators/BuildOrchestrator.ts +31 -62
  197. package/src/orchestrators/DevWatchOrchestrator.ts +41 -44
  198. package/src/sd-cli-entry.ts +2 -12
  199. package/src/utils/SdCliReporter.ts +177 -0
  200. package/src/utils/angular-compiler.ts +11 -4
  201. package/src/utils/build-env.ts +2 -1
  202. package/src/utils/copy-public.ts +21 -21
  203. package/src/utils/copy-src.ts +12 -12
  204. package/src/utils/diagnostic-utils.ts +3 -2
  205. package/src/utils/esbuild-config.ts +2 -0
  206. package/src/utils/lint-with-program.ts +7 -3
  207. package/src/utils/ngtsc-build-core.ts +18 -18
  208. package/src/utils/output-path-rewriter.ts +7 -7
  209. package/src/utils/output-utils.ts +1 -1
  210. package/src/utils/package-utils.ts +37 -13
  211. package/src/utils/rebuild-manager.ts +4 -2
  212. package/src/utils/replace-deps.ts +10 -10
  213. package/src/utils/sd-config.ts +2 -3
  214. package/src/utils/tsc-build.ts +9 -4
  215. package/src/utils/typecheck-non-package.ts +10 -5
  216. package/src/utils/vite-config.ts +2 -1
  217. package/src/utils/worker-events.ts +2 -1
  218. package/src/utils/worker-utils.ts +3 -1
  219. package/src/workers/client.worker.ts +4 -0
  220. package/src/workers/library-build.worker.ts +48 -18
  221. package/src/workers/ngtsc-build.worker.ts +48 -13
  222. package/src/workers/server-build.worker.ts +30 -23
  223. package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +11 -7
  224. package/tests/angular/vite-angular-plugin-lint.spec.ts +6 -1
  225. package/tests/capacitor/capacitor-build.spec.ts +5 -0
  226. package/tests/capacitor/capacitor-icon.spec.ts +5 -0
  227. package/tests/capacitor/capacitor-init.spec.ts +5 -0
  228. package/tests/capacitor/capacitor-run.spec.ts +5 -0
  229. package/tests/capacitor/capacitor-workspace.spec.ts +5 -0
  230. package/tests/commands/typecheck.spec.ts +20 -31
  231. package/tests/electron/electron.spec.ts +5 -0
  232. package/tests/engines/base-engine.spec.ts +15 -21
  233. package/tests/engines/engine-lint-integration.spec.ts +5 -10
  234. package/tests/engines/ngtsc-engine.spec.ts +27 -41
  235. package/tests/engines/server-esbuild-engine.spec.ts +18 -29
  236. package/tests/engines/tsc-engine.spec.ts +14 -23
  237. package/tests/engines/vite-engine.spec.ts +10 -15
  238. package/tests/infra/result-collector.spec.ts +2 -2
  239. package/tests/orchestrators/build-orchestrator.spec.ts +19 -29
  240. package/tests/orchestrators/dev-watch-orchestrator.spec.ts +110 -95
  241. package/tests/utils/copy-src.spec.ts +25 -19
  242. package/tests/utils/diagnostic-utils.spec.ts +72 -0
  243. package/tests/utils/ngtsc-build-core-angular-compiler.spec.ts +2 -3
  244. package/tests/utils/output-path-rewriter.spec.ts +7 -6
  245. package/tests/utils/output-utils.spec.ts +5 -5
  246. package/tests/utils/rebuild-manager.spec.ts +1 -1
  247. package/tests/utils/sd-config.spec.ts +4 -0
  248. package/tests/utils/tsc-build.spec.ts +23 -5
  249. package/tests/workers/library-build-worker.spec.ts +113 -20
  250. package/tests/workers/ngtsc-build-lint.spec.ts +3 -6
  251. package/tests/workers/ngtsc-build-worker.spec.ts +17 -19
  252. package/tests/workers/server-build-lint.spec.ts +4 -1
  253. package/tests/workers/server-build-worker.spec.ts +19 -22
  254. package/tests/angular/migration-cleanup.spec.ts +0 -59
@@ -5,6 +5,7 @@ import os from "os";
5
5
  import path from "path";
6
6
  import ts from "typescript";
7
7
  import { consola } from "consola";
8
+ import { pathx } from "@simplysm/core-node";
8
9
  import {
9
10
  AngularCompiler,
10
11
  AngularSourceFileCache,
@@ -151,6 +152,7 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
151
152
  ...opts,
152
153
  noEmit: false,
153
154
  declaration: false,
155
+ declarationMap: false,
154
156
  }),
155
157
  });
156
158
 
@@ -173,7 +175,7 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
173
175
  // 영향받은 파일 emit + 캐시 (소스 파일 경로를 key로 사용)
174
176
  emittedFiles.clear();
175
177
  for (const result of compiler.emitAffectedFiles()) {
176
- emittedFiles.set(normalizePath(result.sourceFileName), result.contents);
178
+ emittedFiles.set(pathx.posix(result.sourceFileName), result.contents);
177
179
  }
178
180
  logger.debug(`emit 완료: ${emittedFiles.size}개 파일`);
179
181
 
@@ -223,6 +225,17 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
223
225
  return;
224
226
  }
225
227
 
228
+ // Dependency filter: skip if file is not in the TypeScript program
229
+ const normalizedFile = pathx.posix(file);
230
+ const programFiles = compiler.getTsProgram().getSourceFiles();
231
+ const isInProgram = programFiles.some(
232
+ (sf) => pathx.posix(sf.fileName) === normalizedFile,
233
+ );
234
+ if (!isInProgram) {
235
+ logger.debug(`변경된 파일이 빌드에 포함되지 않아 리빌드 건너뜀: ${normalizedFile}`);
236
+ return;
237
+ }
238
+
226
239
  // 경쟁 조건 방지: 이전 HMR 처리 완료 대기
227
240
  const prevLock = hmrLock;
228
241
  let releaseLock!: () => void;
@@ -248,7 +261,7 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
248
261
 
249
262
  const affectedPaths: string[] = [];
250
263
  for (const result of compiler.emitAffectedFiles()) {
251
- const normalizedPath = normalizePath(result.sourceFileName);
264
+ const normalizedPath = pathx.posix(result.sourceFileName);
252
265
  emittedFiles.set(normalizedPath, result.contents);
253
266
  affectedPaths.push(normalizedPath);
254
267
  }
@@ -259,7 +272,7 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
259
272
  // Convert affected ts.SourceFile set to file name strings for incremental lint
260
273
  const affectedFileNames = new Set<string>();
261
274
  for (const sf of updateResult.affectedFiles) {
262
- affectedFileNames.add(normalizePath(sf.fileName));
275
+ affectedFileNames.add(pathx.posix(sf.fileName));
263
276
  }
264
277
 
265
278
  // Lint execution (if enabled)
@@ -280,7 +293,7 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
280
293
 
281
294
  const affectedSet = new Set(affectedPaths);
282
295
  return modules.filter(
283
- (m) => m.file != null && affectedSet.has(normalizePath(m.file)),
296
+ (m) => m.file != null && affectedSet.has(pathx.posix(m.file)),
284
297
  );
285
298
  } catch (err) {
286
299
  const message = err instanceof Error ? err.message : String(err);
@@ -295,7 +308,7 @@ export function sdAngularPlugin(options: SdAngularPluginOptions): Plugin {
295
308
  async transform(_code, id) {
296
309
  if (!id.endsWith(".ts") && !id.endsWith(".tsx")) return;
297
310
 
298
- const normalizedId = normalizePath(id);
311
+ const normalizedId = pathx.posix(id);
299
312
  const emittedContent = emittedFiles.get(normalizedId);
300
313
  if (emittedContent == null) return;
301
314
 
@@ -407,10 +420,6 @@ function angularComponentMiddleware(
407
420
  };
408
421
  }
409
422
 
410
- function normalizePath(p: string): string {
411
- return p.replace(/\\/g, "/");
412
- }
413
-
414
423
  function reportDiagnostics(diagnostics: DiagnosticResult): void {
415
424
  for (const error of diagnostics.errors) {
416
425
  const loc =
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import path from "path";
4
4
  import { symlink } from "fs/promises";
5
5
  import { createRequire } from "module";
6
- import { cpx, fsx } from "@simplysm/core-node";
6
+ import { cpx, fsx, pathx } from "@simplysm/core-node";
7
7
  import { env } from "@simplysm/core-common";
8
8
  import { consola } from "consola";
9
9
  import type { SdCapacitorConfig } from "../sd-config.types.js";
@@ -52,7 +52,7 @@ export class Capacitor {
52
52
  ) {
53
53
  this._platforms = Object.keys(this._config.platform ?? {});
54
54
  this._npmConfig = npmConfig;
55
- this._capPath = path.resolve(this._pkgPath, ".capacitor");
55
+ this._capPath = pathx.posixResolve(this._pkgPath, ".capacitor");
56
56
  }
57
57
 
58
58
  /**
@@ -65,7 +65,7 @@ export class Capacitor {
65
65
  ): Promise<Capacitor> {
66
66
  Capacitor._validateConfig(config);
67
67
 
68
- const npmConfig = await fsx.readJson<NpmConfig>(path.resolve(pkgPath, "package.json"));
68
+ const npmConfig = await fsx.readJson<NpmConfig>(pathx.posixResolve(pkgPath, "package.json"));
69
69
  return new Capacitor(pkgPath, config, npmConfig, exclude ?? []);
70
70
  }
71
71
 
@@ -170,7 +170,7 @@ export class Capacitor {
170
170
  * 동시 실행 방지 잠금 획득
171
171
  */
172
172
  private async _acquireLock(): Promise<void> {
173
- const lockPath = path.resolve(this._capPath, Capacitor._LOCK_FILE_NAME);
173
+ const lockPath = pathx.posixResolve(this._capPath, Capacitor._LOCK_FILE_NAME);
174
174
  await fsx.mkdir(this._capPath);
175
175
  try {
176
176
  await fs.promises.writeFile(lockPath, String(process.pid), { flag: "wx" });
@@ -194,7 +194,7 @@ export class Capacitor {
194
194
  * 동시 실행 방지 잠금 해제
195
195
  */
196
196
  private async _releaseLock(): Promise<void> {
197
- const lockPath = path.resolve(this._capPath, Capacitor._LOCK_FILE_NAME);
197
+ const lockPath = pathx.posixResolve(this._capPath, Capacitor._LOCK_FILE_NAME);
198
198
  await fsx.rm(lockPath);
199
199
  }
200
200
 
@@ -236,7 +236,7 @@ export class Capacitor {
236
236
  */
237
237
  private async _initCap(): Promise<boolean> {
238
238
  const { depChanged, workspacePlugins } = await this._setupNpmConf();
239
- const nodeModulesExists = await fsx.exists(path.resolve(this._capPath, "node_modules"));
239
+ const nodeModulesExists = await fsx.exists(pathx.posixResolve(this._capPath, "node_modules"));
240
240
 
241
241
  if (!depChanged && nodeModulesExists) {
242
242
  // 의존성 미변경이어도 workspace 플러그인 symlink는 항상 갱신
@@ -252,16 +252,16 @@ export class Capacitor {
252
252
  await this._linkWorkspacePlugins(workspacePlugins);
253
253
 
254
254
  // 멱등성: capacitor.config.ts가 없을 때만 cap init 실행
255
- const configPath = path.resolve(this._capPath, "capacitor.config.ts");
255
+ const configPath = pathx.posixResolve(this._capPath, "capacitor.config.ts");
256
256
  if (!(await fsx.exists(configPath))) {
257
257
  await this._execCap(["init", this._config.appId, this._config.appId]);
258
258
  }
259
259
 
260
260
  // 기본 www/index.html 생성
261
- const wwwPath = path.resolve(this._capPath, "www");
261
+ const wwwPath = pathx.posixResolve(this._capPath, "www");
262
262
  await fsx.mkdir(wwwPath);
263
263
  await fsx.write(
264
- path.resolve(wwwPath, "index.html"),
264
+ pathx.posixResolve(wwwPath, "index.html"),
265
265
  "<!DOCTYPE html><html><head></head><body></body></html>",
266
266
  );
267
267
 
@@ -272,7 +272,7 @@ export class Capacitor {
272
272
  * package.json 설정
273
273
  */
274
274
  private async _setupNpmConf(): Promise<{ depChanged: boolean; workspacePlugins: string[] }> {
275
- const projNpmConfigPath = path.resolve(this._findWorkspaceRoot(), "package.json");
275
+ const projNpmConfigPath = pathx.posixResolve(this._findWorkspaceRoot(), "package.json");
276
276
 
277
277
  // 루트 package.json 존재 확인
278
278
  if (!(await fsx.exists(projNpmConfigPath))) {
@@ -281,7 +281,7 @@ export class Capacitor {
281
281
 
282
282
  const projNpmConfig = await fsx.readJson<NpmConfig>(projNpmConfigPath);
283
283
 
284
- const capNpmConfPath = path.resolve(this._capPath, "package.json");
284
+ const capNpmConfPath = pathx.posixResolve(this._capPath, "package.json");
285
285
  const orgCapNpmConf: NpmConfig = (await fsx.exists(capNpmConfPath))
286
286
  ? await fsx.readJson<NpmConfig>(capNpmConfPath)
287
287
  : { name: "", version: "" };
@@ -371,7 +371,7 @@ export class Capacitor {
371
371
  * capacitor.config.ts 생성
372
372
  */
373
373
  private async _writeCapConf(): Promise<void> {
374
- const confPath = path.resolve(this._capPath, "capacitor.config.ts");
374
+ const confPath = pathx.posixResolve(this._capPath, "capacitor.config.ts");
375
375
 
376
376
  // 플러그인 옵션 생성
377
377
  const pluginOptions: Record<string, Record<string, unknown>> = {};
@@ -411,7 +411,7 @@ export default config;
411
411
  */
412
412
  private async _addPlatforms(): Promise<void> {
413
413
  for (const platform of this._platforms) {
414
- const platformPath = path.resolve(this._capPath, platform);
414
+ const platformPath = pathx.posixResolve(this._capPath, platform);
415
415
  if (await fsx.exists(platformPath)) {
416
416
  Capacitor._logger.debug(`플랫폼이 이미 존재합니다: ${platform}`);
417
417
  continue;
@@ -427,7 +427,7 @@ export default config;
427
427
  private async _setupIcon(): Promise<void> {
428
428
  if (this._config.icon == null) return;
429
429
 
430
- const iconPath = path.resolve(this._pkgPath, this._config.icon);
430
+ const iconPath = pathx.posixResolve(this._pkgPath, this._config.icon);
431
431
 
432
432
  if (!(await fsx.exists(iconPath))) {
433
433
  Capacitor._logger.warn(`아이콘 파일을 찾을 수 없습니다: ${iconPath}`);
@@ -447,9 +447,9 @@ export default config;
447
447
  .toBuffer();
448
448
 
449
449
  // 1024x1024 투명 캔버스에 합성
450
- const assetsDir = path.resolve(this._capPath, "assets");
450
+ const assetsDir = pathx.posixResolve(this._capPath, "assets");
451
451
  await fsx.mkdir(assetsDir);
452
- const logoPath = path.resolve(assetsDir, "logo.png");
452
+ const logoPath = pathx.posixResolve(assetsDir, "logo.png");
453
453
 
454
454
  await sharp({
455
455
  create: {
@@ -493,7 +493,7 @@ export default config;
493
493
  * Android 네이티브 설정 구성
494
494
  */
495
495
  private async _configureAndroid(): Promise<void> {
496
- const androidPath = path.resolve(this._capPath, "android");
496
+ const androidPath = pathx.posixResolve(this._capPath, "android");
497
497
 
498
498
  // Android 디렉토리 존재 확인
499
499
  if (!(await fsx.exists(androidPath))) {
@@ -510,7 +510,7 @@ export default config;
510
510
  * JAVA_HOME 경로 설정 (gradle.properties)
511
511
  */
512
512
  private async _configureAndroidJavaHomePath(androidPath: string): Promise<void> {
513
- const gradlePropsPath = path.resolve(androidPath, "gradle.properties");
513
+ const gradlePropsPath = pathx.posixResolve(androidPath, "gradle.properties");
514
514
 
515
515
  if (!(await fsx.exists(gradlePropsPath))) {
516
516
  Capacitor._logger.warn(`gradle.properties 파일을 찾을 수 없습니다: ${gradlePropsPath}`);
@@ -555,12 +555,12 @@ export default config;
555
555
  * Android SDK 경로 설정 (local.properties)
556
556
  */
557
557
  private async _configureAndroidSdkPath(androidPath: string): Promise<void> {
558
- const localPropsPath = path.resolve(androidPath, "local.properties");
558
+ const localPropsPath = pathx.posixResolve(androidPath, "local.properties");
559
559
 
560
560
  const sdkPath = await this._findAndroidSdk();
561
561
  if (sdkPath != null) {
562
562
  // Gradle 호환: 항상 forward slash 사용
563
- await fsx.write(localPropsPath, `sdk.dir=${sdkPath.replace(/\\/g, "/")}\n`);
563
+ await fsx.write(localPropsPath, `sdk.dir=${pathx.posix(sdkPath)}\n`);
564
564
  } else {
565
565
  throw new Error(
566
566
  "Android SDK를 찾을 수 없습니다.\n" +
@@ -580,8 +580,8 @@ export default config;
580
580
  }
581
581
 
582
582
  const candidates = [
583
- path.resolve((env["LOCALAPPDATA"] as string | undefined) ?? "", "Android/Sdk"),
584
- path.resolve((env["HOME"] as string | undefined) ?? "", "Android/Sdk"),
583
+ pathx.posixResolve((env["LOCALAPPDATA"] as string | undefined) ?? "", "Android/Sdk"),
584
+ pathx.posixResolve((env["HOME"] as string | undefined) ?? "", "Android/Sdk"),
585
585
  "C:/Program Files/Android/Sdk",
586
586
  "C:/Android/Sdk",
587
587
  ];
@@ -602,7 +602,7 @@ export default config;
602
602
  * XML 구조가 변경되면 정규식이 실패할 수 있음.
603
603
  */
604
604
  private async _configureAndroidManifest(androidPath: string): Promise<void> {
605
- const manifestPath = path.resolve(androidPath, "app/src/main/AndroidManifest.xml");
605
+ const manifestPath = pathx.posixResolve(androidPath, "app/src/main/AndroidManifest.xml");
606
606
 
607
607
  if (!(await fsx.exists(manifestPath))) {
608
608
  throw new Error(`AndroidManifest.xml 파일을 찾을 수 없습니다: ${manifestPath}`);
@@ -674,7 +674,7 @@ export default config;
674
674
  * build.gradle 수정 (서명 설정 제외)
675
675
  */
676
676
  private async _configureAndroidBuildGradle(androidPath: string): Promise<void> {
677
- const buildGradlePath = path.resolve(androidPath, "app/build.gradle");
677
+ const buildGradlePath = pathx.posixResolve(androidPath, "app/build.gradle");
678
678
 
679
679
  if (!(await fsx.exists(buildGradlePath))) {
680
680
  throw new Error(`build.gradle 파일을 찾을 수 없습니다: ${buildGradlePath}`);
@@ -754,7 +754,7 @@ export default config;
754
754
  * WebView가 이 URL에서 웹 에셋을 로드하여 Hot Reload가 동작한다.
755
755
  */
756
756
  private async _updateServerUrl(url: string): Promise<void> {
757
- const configPath = path.resolve(this._capPath, "capacitor.config.ts");
757
+ const configPath = pathx.posixResolve(this._capPath, "capacitor.config.ts");
758
758
  let content = await fsx.read(configPath);
759
759
 
760
760
  if (content.includes("url:")) {
@@ -791,7 +791,7 @@ export default config;
791
791
  const signConfig = this._config.platform?.android?.sign;
792
792
  if (!isDebug && signConfig != null) {
793
793
  await this._configureSigningConfig(
794
- path.resolve(this._capPath, "android"),
794
+ pathx.posixResolve(this._capPath, "android"),
795
795
  signConfig,
796
796
  );
797
797
  } else if (!isDebug) {
@@ -817,16 +817,16 @@ export default config;
817
817
  sign: import("../sd-config.types.js").SdCapacitorSignConfig,
818
818
  ): Promise<void> {
819
819
  // keystore 파일 확인 및 복사
820
- const keystoreSrc = path.resolve(this._pkgPath, sign.keystore);
820
+ const keystoreSrc = pathx.posixResolve(this._pkgPath, sign.keystore);
821
821
  if (!(await fsx.exists(keystoreSrc))) {
822
822
  throw new Error(`keystore 파일을 찾을 수 없습니다: ${keystoreSrc}`);
823
823
  }
824
824
 
825
- const keystoreDest = path.resolve(androidPath, "app", "android.keystore");
825
+ const keystoreDest = pathx.posixResolve(androidPath, "app", "android.keystore");
826
826
  await fsx.copy(keystoreSrc, keystoreDest);
827
827
 
828
828
  // build.gradle에 signingConfigs 추가
829
- const buildGradlePath = path.resolve(androidPath, "app/build.gradle");
829
+ const buildGradlePath = pathx.posixResolve(androidPath, "app/build.gradle");
830
830
  let content = await fsx.read(buildGradlePath);
831
831
 
832
832
  // 이미 signingConfigs가 있으면 스킵
@@ -872,11 +872,11 @@ export default config;
872
872
  gradleTask = "assembleRelease";
873
873
  }
874
874
 
875
- const androidPath = path.resolve(this._capPath, "android");
875
+ const androidPath = pathx.posixResolve(this._capPath, "android");
876
876
  const isWindows = process.platform === "win32";
877
877
  const gradlew = isWindows
878
- ? path.resolve(androidPath, "gradlew.bat")
879
- : path.resolve(androidPath, "gradlew");
878
+ ? pathx.posixResolve(androidPath, "gradlew.bat")
879
+ : pathx.posixResolve(androidPath, "gradlew");
880
880
 
881
881
  await this._exec(gradlew, [gradleTask, "--no-daemon"], androidPath);
882
882
  }
@@ -891,7 +891,7 @@ export default config;
891
891
  ): Promise<void> {
892
892
  const ext = isBundle ? "aab" : "apk";
893
893
  const outputType = isBundle ? "bundle" : "apk";
894
- const androidBuildPath = path.resolve(
894
+ const androidBuildPath = pathx.posixResolve(
895
895
  this._capPath,
896
896
  "android/app/build/outputs",
897
897
  outputType,
@@ -899,7 +899,7 @@ export default config;
899
899
  );
900
900
 
901
901
  // 빌드 산출물 찾기
902
- const candidates = await fsx.glob(path.resolve(androidBuildPath, `app-*.${ext}`));
902
+ const candidates = await fsx.glob(pathx.posixResolve(androidBuildPath, `app-*.${ext}`));
903
903
  if (candidates.length === 0) {
904
904
  throw new Error(`빌드 산출물을 찾을 수 없습니다: ${androidBuildPath}`);
905
905
  }
@@ -907,8 +907,8 @@ export default config;
907
907
  const isUnsigned = builtFile.includes("unsigned");
908
908
 
909
909
  // 출력 디렉토리 생성
910
- const androidOutPath = path.resolve(outPath, "android");
911
- const updatesPath = path.resolve(androidOutPath, "updates");
910
+ const androidOutPath = pathx.posixResolve(outPath, "android");
911
+ const updatesPath = pathx.posixResolve(androidOutPath, "updates");
912
912
  await fsx.mkdir(androidOutPath);
913
913
  await fsx.mkdir(updatesPath);
914
914
 
@@ -918,8 +918,8 @@ export default config;
918
918
  const versionedName = `${this._npmConfig.version}.${ext}`;
919
919
 
920
920
  // 복사
921
- await fsx.copy(builtFile, path.resolve(androidOutPath, latestName));
922
- await fsx.copy(builtFile, path.resolve(updatesPath, versionedName));
921
+ await fsx.copy(builtFile, pathx.posixResolve(androidOutPath, latestName));
922
+ await fsx.copy(builtFile, pathx.posixResolve(updatesPath, versionedName));
923
923
  }
924
924
 
925
925
  //#endregion
@@ -933,13 +933,13 @@ export default config;
933
933
  private async _linkWorkspacePlugins(plugins: string[]): Promise<void> {
934
934
  if (plugins.length === 0) return;
935
935
 
936
- const require = createRequire(path.resolve(this._pkgPath, "package.json"));
936
+ const require = createRequire(pathx.posixResolve(this._pkgPath, "package.json"));
937
937
 
938
938
  for (const plugin of plugins) {
939
939
  const pluginPkgJsonPath = require.resolve(`${plugin}/package.json`);
940
940
  const pluginDir = path.dirname(pluginPkgJsonPath);
941
941
 
942
- const linkPath = path.resolve(this._capPath, "node_modules", ...plugin.split("/"));
942
+ const linkPath = pathx.posixResolve(this._capPath, "node_modules", ...plugin.split("/"));
943
943
 
944
944
  // scope 디렉토리 생성 (예: @simplysm/)
945
945
  await fsx.mkdir(path.dirname(linkPath));
@@ -964,7 +964,7 @@ export default config;
964
964
  if (parent === dir) {
965
965
  throw new Error(`워크스페이스 루트를 찾을 수 없습니다: ${this._pkgPath}`);
966
966
  }
967
- if (existsSync(path.join(parent, "pnpm-workspace.yaml"))) {
967
+ if (existsSync(pathx.posixResolve(parent, "pnpm-workspace.yaml"))) {
968
968
  return parent;
969
969
  }
970
970
  dir = parent;
@@ -1,6 +1,6 @@
1
1
  import ts from "typescript";
2
- import path from "path";
3
2
  import { err as errNs } from "@simplysm/core-common";
3
+ import { pathx } from "@simplysm/core-node";
4
4
  import { consola } from "consola";
5
5
  import type { SdConfig } from "../sd-config.types";
6
6
  import { loadSdConfig } from "../utils/sd-config";
@@ -136,7 +136,7 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
136
136
  for (const env of envs) {
137
137
  typecheckTasks.push({
138
138
  name,
139
- dir: path.join(cwd, relPath),
139
+ dir: pathx.posixResolve(cwd, relPath),
140
140
  config: typecheckConfig,
141
141
  env,
142
142
  });
@@ -182,9 +182,10 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
182
182
  js: false,
183
183
  dts: false,
184
184
  env: task.env,
185
+ includeTests: true,
185
186
  ...(options.lint === true ? { lint: true } : {}),
186
187
  });
187
- logger.debug(`[${label}] 타입체크 ${result.dts.success ? "완료" : "실패"}`);
188
+ logger.debug(`[${label}] 타입체크 ${result.build.success ? "완료" : "실패"}`);
188
189
  return result;
189
190
  } catch (err) {
190
191
  const message = errNs.message(err);
@@ -195,8 +196,7 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
195
196
  }
196
197
  return {
197
198
  success: false,
198
- js: { success: true, errors: [], warnings: [] },
199
- dts: {
199
+ build: {
200
200
  success: false,
201
201
  errors: [`[${label}] ${message}`],
202
202
  warnings: [],
@@ -217,14 +217,14 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
217
217
  for (const settled of results) {
218
218
  if (settled.status !== "fulfilled") continue;
219
219
  const engineResult = settled.value;
220
- const dtsDiags = engineResult.dts.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
221
- allDiagnostics.push(...dtsDiags);
220
+ const buildDiags = engineResult.build.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
221
+ allDiagnostics.push(...buildDiags);
222
222
  // 역직렬화된 진단 정보에서 에러/경고 수 집계
223
223
  // 숫자 카테고리 값 사용 (ts.DiagnosticCategory: Error=1, Warning=0)
224
- totalErrorCount += dtsDiags.filter((d) => d.category === 1).length;
225
- totalWarningCount += dtsDiags.filter((d) => d.category === 0).length;
226
- if (!engineResult.dts.success && dtsDiags.length === 0) {
227
- for (const errMsg of engineResult.dts.errors) {
224
+ totalErrorCount += buildDiags.filter((d) => d.category === 1).length;
225
+ totalWarningCount += buildDiags.filter((d) => d.category === 0).length;
226
+ if (!engineResult.build.success && buildDiags.length === 0) {
227
+ for (const errMsg of engineResult.build.errors) {
228
228
  allDiagnostics.push({
229
229
  category: 1,
230
230
  code: 0,
@@ -234,7 +234,7 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
234
234
  length: undefined,
235
235
  });
236
236
  }
237
- totalErrorCount += engineResult.dts.errors.length || 1;
237
+ totalErrorCount += engineResult.build.errors.length || 1;
238
238
  }
239
239
 
240
240
  // Lint 결과 수집
@@ -1,8 +1,7 @@
1
- import path from "path";
2
1
  import os from "os";
3
2
  import fs from "fs";
4
3
  import module from "module";
5
- import { cpx, fsx } from "@simplysm/core-node";
4
+ import { cpx, fsx, pathx } from "@simplysm/core-node";
6
5
  import { consola } from "consola";
7
6
  import type { SdElectronConfig } from "../sd-config.types.js";
8
7
  import { createEnvBanner } from "../utils/esbuild-config.js";
@@ -25,7 +24,7 @@ export class Electron {
25
24
  private readonly _npmConfig: NpmConfig,
26
25
  private readonly _exclude: string[],
27
26
  ) {
28
- this._electronPath = path.resolve(this._pkgPath, ".electron");
27
+ this._electronPath = pathx.posixResolve(this._pkgPath, ".electron");
29
28
  }
30
29
 
31
30
  static async create(
@@ -35,7 +34,7 @@ export class Electron {
35
34
  ): Promise<Electron> {
36
35
  Electron._validateConfig(config);
37
36
 
38
- const npmConfig = await fsx.readJson<NpmConfig>(path.resolve(pkgPath, "package.json"));
37
+ const npmConfig = await fsx.readJson<NpmConfig>(pathx.posixResolve(pkgPath, "package.json"));
39
38
  return new Electron(pkgPath, config, npmConfig, exclude ?? []);
40
39
  }
41
40
 
@@ -46,7 +45,7 @@ export class Electron {
46
45
  }
47
46
 
48
47
  private _localBin(name: string): string {
49
- return path.resolve(this._pkgPath, "node_modules/.bin", name);
48
+ return pathx.posixResolve(this._pkgPath, "node_modules/.bin", name);
50
49
  }
51
50
 
52
51
  private async _exec(
@@ -56,7 +55,7 @@ export class Electron {
56
55
  env?: Record<string, string>,
57
56
  ): Promise<string> {
58
57
  Electron._logger.debug(`실행: ${cmd} ${args.join(" ")}`);
59
- const { stdout: result } = await cpx.exec(cmd, args, { cwd, env });
58
+ const { stdout: result } = await cpx.exec(cmd, args, { cwd, env, shell: true });
60
59
  Electron._logger.debug(`결과: ${result}`);
61
60
  return result;
62
61
  }
@@ -64,7 +63,7 @@ export class Electron {
64
63
  //#region Public Methods
65
64
 
66
65
  async initialize(): Promise<void> {
67
- const srcPath = path.resolve(this._electronPath, "src");
66
+ const srcPath = pathx.posixResolve(this._electronPath, "src");
68
67
 
69
68
  await this._setupPackageJson(srcPath);
70
69
  await this._exec("npm", ["install"], srcPath);
@@ -76,12 +75,12 @@ export class Electron {
76
75
  }
77
76
 
78
77
  async run(url: string): Promise<void> {
79
- const srcPath = path.resolve(this._electronPath, "src");
78
+ const srcPath = pathx.posixResolve(this._electronPath, "src");
80
79
 
81
80
  await this.initialize();
82
81
 
83
82
  const esbuild = await import("esbuild");
84
- const entryPoint = path.resolve(this._pkgPath, "src/electron-main.ts");
83
+ const entryPoint = pathx.posixResolve(this._pkgPath, "src/electron-main.ts");
85
84
 
86
85
  if (!(await fsx.exists(entryPoint))) {
87
86
  throw new Error(`electron-main.ts 파일을 찾을 수 없습니다: ${entryPoint}`);
@@ -115,7 +114,7 @@ export class Electron {
115
114
 
116
115
  const ctx = await esbuild.context({
117
116
  entryPoints: [entryPoint],
118
- outfile: path.resolve(srcPath, "electron-main.js"),
117
+ outfile: pathx.posixResolve(srcPath, "electron-main.js"),
119
118
  platform: "node",
120
119
  target: "node20",
121
120
  format: "cjs",
@@ -178,7 +177,7 @@ export class Electron {
178
177
  }
179
178
 
180
179
  async build(outPath: string): Promise<void> {
181
- const srcPath = path.resolve(this._electronPath, "src");
180
+ const srcPath = pathx.posixResolve(this._electronPath, "src");
182
181
 
183
182
  await this._bundleMainProcess(srcPath);
184
183
  await this._copyWebAssets(outPath, srcPath);
@@ -224,7 +223,7 @@ export class Electron {
224
223
  packageJson["scripts"] = { postinstall: this._config.postInstallScript };
225
224
  }
226
225
 
227
- await fsx.writeJson(path.resolve(srcPath, "package.json"), packageJson, { space: 2 });
226
+ await fsx.writeJson(pathx.posixResolve(srcPath, "package.json"), packageJson, { space: 2 });
228
227
  }
229
228
 
230
229
  //#endregion
@@ -233,7 +232,7 @@ export class Electron {
233
232
 
234
233
  private async _bundleMainProcess(outDir: string): Promise<void> {
235
234
  const esbuild = await import("esbuild");
236
- const entryPoint = path.resolve(this._pkgPath, "src/electron-main.ts");
235
+ const entryPoint = pathx.posixResolve(this._pkgPath, "src/electron-main.ts");
237
236
 
238
237
  if (!(await fsx.exists(entryPoint))) {
239
238
  throw new Error(`electron-main.ts 파일을 찾을 수 없습니다: ${entryPoint}`);
@@ -248,7 +247,7 @@ export class Electron {
248
247
 
249
248
  await esbuild.build({
250
249
  entryPoints: [entryPoint],
251
- outfile: path.resolve(outDir, "electron-main.js"),
250
+ outfile: pathx.posixResolve(outDir, "electron-main.js"),
252
251
  platform: "node",
253
252
  target: "node20",
254
253
  format: "cjs",
@@ -267,16 +266,16 @@ export class Electron {
267
266
  for (const item of items) {
268
267
  if (item === "electron") continue;
269
268
 
270
- const source = path.resolve(outPath, item);
271
- const dest = path.resolve(srcPath, item);
269
+ const source = pathx.posixResolve(outPath, item);
270
+ const dest = pathx.posixResolve(srcPath, item);
272
271
  await fsx.copy(source, dest);
273
272
  }
274
273
  }
275
274
 
276
275
  private static _canCreateSymlink(): boolean {
277
276
  const tmpDir = os.tmpdir();
278
- const testTarget = path.join(tmpDir, "sd-electron-symlink-test-target.txt");
279
- const testLink = path.join(tmpDir, "sd-electron-symlink-test-link.txt");
277
+ const testTarget = pathx.posixResolve(tmpDir, "sd-electron-symlink-test-target.txt");
278
+ const testLink = pathx.posixResolve(tmpDir, "sd-electron-symlink-test-link.txt");
280
279
 
281
280
  try {
282
281
  fs.writeFileSync(testTarget, "test");
@@ -297,7 +296,7 @@ export class Electron {
297
296
  );
298
297
  }
299
298
 
300
- const distPath = path.resolve(this._electronPath, "dist");
299
+ const distPath = pathx.posixResolve(this._electronPath, "dist");
301
300
 
302
301
  const builderConfig: Record<string, unknown> = {
303
302
  appId: this._config.appId,
@@ -317,10 +316,10 @@ export class Electron {
317
316
  };
318
317
 
319
318
  if (this._config.installerIcon != null) {
320
- builderConfig["icon"] = path.resolve(this._pkgPath, this._config.installerIcon);
319
+ builderConfig["icon"] = pathx.posixResolve(this._pkgPath, this._config.installerIcon);
321
320
  }
322
321
 
323
- const configFilePath = path.resolve(this._electronPath, "builder-config.json");
322
+ const configFilePath = pathx.posixResolve(this._electronPath, "builder-config.json");
324
323
  await fsx.writeJson(configFilePath, builderConfig, { space: 2 });
325
324
 
326
325
  await this._exec(
@@ -331,8 +330,8 @@ export class Electron {
331
330
  }
332
331
 
333
332
  private async _copyBuildOutput(outPath: string): Promise<void> {
334
- const distPath = path.resolve(this._electronPath, "dist");
335
- const electronOutPath = path.resolve(outPath, "electron");
333
+ const distPath = pathx.posixResolve(this._electronPath, "dist");
334
+ const electronOutPath = pathx.posixResolve(outPath, "electron");
336
335
  await fsx.mkdir(electronOutPath);
337
336
 
338
337
  const rawName = this._npmConfig.description ?? this._npmConfig.name;
@@ -341,7 +340,7 @@ export class Electron {
341
340
  const isPortable = this._config.portable === true;
342
341
 
343
342
  // exe 파일 동적 탐색 — Setup 또는 portable exe를 우선 선택
344
- const allExeFiles = await fsx.glob(path.resolve(distPath, "*.exe"));
343
+ const allExeFiles = await fsx.glob(pathx.posixResolve(distPath, "*.exe"));
345
344
  if (allExeFiles.length === 0) {
346
345
  Electron._logger.warn(`빌드 산출물(.exe)을 찾을 수 없습니다: ${distPath}`);
347
346
  return;
@@ -351,11 +350,11 @@ export class Electron {
351
350
  allExeFiles.find((f) => f.toLowerCase().includes(keyword.toLowerCase())) ?? allExeFiles[0];
352
351
 
353
352
  const latestFileName = `${safeName}${isPortable ? "-portable" : ""}-latest.exe`;
354
- await fsx.copy(sourcePath, path.resolve(electronOutPath, latestFileName));
353
+ await fsx.copy(sourcePath, pathx.posixResolve(electronOutPath, latestFileName));
355
354
 
356
- const updatesPath = path.resolve(electronOutPath, "updates");
355
+ const updatesPath = pathx.posixResolve(electronOutPath, "updates");
357
356
  await fsx.mkdir(updatesPath);
358
- await fsx.copy(sourcePath, path.resolve(updatesPath, `${version}.exe`));
357
+ await fsx.copy(sourcePath, pathx.posixResolve(updatesPath, `${version}.exe`));
359
358
  }
360
359
 
361
360
  //#endregion