@simplysm/sd-cli 14.0.5 → 14.0.7

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 (72) hide show
  1. package/dist/commands/check.d.ts.map +1 -1
  2. package/dist/commands/check.js +10 -10
  3. package/dist/commands/check.js.map +1 -1
  4. package/dist/commands/lint.d.ts.map +1 -1
  5. package/dist/commands/lint.js +1 -4
  6. package/dist/commands/lint.js.map +1 -1
  7. package/dist/commands/replace-deps.js +1 -1
  8. package/dist/commands/replace-deps.js.map +1 -1
  9. package/dist/electron/electron.d.ts.map +1 -1
  10. package/dist/electron/electron.js +5 -6
  11. package/dist/electron/electron.js.map +1 -1
  12. package/dist/engines/BaseEngine.d.ts.map +1 -1
  13. package/dist/engines/BaseEngine.js +1 -0
  14. package/dist/engines/BaseEngine.js.map +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  20. package/dist/orchestrators/BuildOrchestrator.js +52 -45
  21. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  22. package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
  23. package/dist/orchestrators/DevWatchOrchestrator.js +32 -26
  24. package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
  25. package/dist/sd-cli.js +1 -1
  26. package/dist/sd-cli.js.map +1 -1
  27. package/dist/utils/esbuild-config.d.ts +7 -2
  28. package/dist/utils/esbuild-config.d.ts.map +1 -1
  29. package/dist/utils/esbuild-config.js +15 -12
  30. package/dist/utils/esbuild-config.js.map +1 -1
  31. package/dist/utils/output-utils.js +1 -1
  32. package/dist/utils/output-utils.js.map +1 -1
  33. package/dist/utils/package-utils.js +3 -3
  34. package/dist/utils/package-utils.js.map +1 -1
  35. package/dist/utils/rebuild-manager.js +3 -3
  36. package/dist/utils/rebuild-manager.js.map +1 -1
  37. package/dist/utils/replace-deps.js +11 -11
  38. package/dist/utils/replace-deps.js.map +1 -1
  39. package/dist/utils/vite-config.d.ts.map +1 -1
  40. package/dist/utils/vite-config.js +1 -2
  41. package/dist/utils/vite-config.js.map +1 -1
  42. package/dist/utils/worker-utils.js +1 -1
  43. package/dist/utils/worker-utils.js.map +1 -1
  44. package/dist/workers/server-build.worker.js +2 -2
  45. package/dist/workers/server-build.worker.js.map +1 -1
  46. package/dist/workers/server-runtime.worker.js +13 -13
  47. package/dist/workers/server-runtime.worker.js.map +1 -1
  48. package/package.json +4 -5
  49. package/src/commands/check.ts +12 -11
  50. package/src/commands/lint.ts +1 -3
  51. package/src/commands/replace-deps.ts +1 -1
  52. package/src/electron/electron.ts +7 -7
  53. package/src/engines/BaseEngine.ts +1 -0
  54. package/src/index.ts +3 -0
  55. package/src/orchestrators/BuildOrchestrator.ts +52 -45
  56. package/src/orchestrators/DevWatchOrchestrator.ts +33 -26
  57. package/src/sd-cli.ts +1 -1
  58. package/src/utils/esbuild-config.ts +16 -12
  59. package/src/utils/output-utils.ts +1 -1
  60. package/src/utils/package-utils.ts +3 -3
  61. package/src/utils/rebuild-manager.ts +3 -3
  62. package/src/utils/replace-deps.ts +11 -11
  63. package/src/utils/vite-config.ts +1 -2
  64. package/src/utils/worker-utils.ts +1 -1
  65. package/src/workers/server-build.worker.ts +2 -2
  66. package/src/workers/server-runtime.worker.ts +13 -13
  67. package/tests/commands/check.spec.ts +11 -26
  68. package/tests/electron/electron.spec.ts +42 -35
  69. package/tests/orchestrators/build-orchestrator.spec.ts +4 -9
  70. package/tests/orchestrators/dev-watch-orchestrator.spec.ts +3 -5
  71. package/tests/utils/esbuild-config.spec.ts +38 -8
  72. package/tests/utils/vite-config.spec.ts +13 -0
@@ -141,9 +141,9 @@ export class BuildOrchestrator {
141
141
  * - Prepare environment variables
142
142
  */
143
143
  async initialize(): Promise<void> {
144
- this._logger.debug("build started", { targets: this._options.targets });
144
+ this._logger.debug("빌드 시작", { targets: this._options.targets });
145
145
 
146
- // Load sd.config.ts and validate targets
146
+ // sd.config.ts 로드 대상 유효성 검사
147
147
  try {
148
148
  this._sdConfig = await loadAndValidateConfig({
149
149
  cwd: this._cwd,
@@ -151,18 +151,19 @@ export class BuildOrchestrator {
151
151
  options: this._options.options,
152
152
  targets: this._options.targets,
153
153
  });
154
- this._logger.debug("sd.config.ts loaded");
154
+ this._logger.debug("sd.config.ts 로드 완료");
155
155
  } catch (err) {
156
- this._logger.error(`sd.config.ts load failed: ${err instanceof Error ? err.message : err}`);
156
+ this._logger.error(`sd.config.ts 로드 실패: ${err instanceof Error ? err.message : err}`);
157
157
  process.exitCode = 1;
158
158
  throw err;
159
159
  }
160
160
 
161
- // Prepare VER and DEV environment variables
161
+ // 환경변수 준비 (VER, DEV)
162
162
  const version = await getVersion(this._cwd);
163
163
  this._baseEnv = { VER: version, DEV: "false" };
164
+ this._logger.debug("환경변수 준비 완료", { VER: version, DEV: "false" });
164
165
 
165
- // Classify packages
166
+ // 패키지 분류
166
167
  this._classified = classifyPackages(this._sdConfig.packages, this._options.targets);
167
168
  this._allPackageNames = [
168
169
  ...this._classified.buildPackages.map((p) => p.name),
@@ -171,12 +172,12 @@ export class BuildOrchestrator {
171
172
  ];
172
173
 
173
174
  if (this._allPackageNames.length === 0) {
174
- process.stdout.write("✔ No packages to build.\n");
175
+ process.stdout.write("✔ 빌드할 패키지가 없습니다.\n");
175
176
  return;
176
177
  }
177
178
 
178
- this._logger.debug("package classification complete", {
179
- buildPackages: this._classified.buildPackages.map((p) => p.name),
179
+ this._logger.debug("패키지 분류 완료", {
180
+ buildPackages: this._classified.buildPackages.map((p) => `${p.name} (${p.config.target})`),
180
181
  serverPackages: this._classified.serverPackages.map((p) => p.name),
181
182
  clientPackages: this._classified.clientPackages.map((p) => p.name),
182
183
  });
@@ -213,13 +214,13 @@ export class BuildOrchestrator {
213
214
  getNewLine: () => ts.sys.newLine,
214
215
  };
215
216
 
216
- // Phase 1: Clean (must complete before build writes to dist)
217
- this._logger.start("Clean");
217
+ // Phase 1: dist 클린
218
+ this._logger.start(`dist 폴더 정리 중... (${this._allPackageNames.length}개 패키지)`);
218
219
  await cleanDistFolders(this._cwd, this._allPackageNames);
219
- this._logger.success("Clean");
220
+ this._logger.success("dist 폴더 정리 완료");
220
221
 
221
- // Phase 2: Build (lint runs inside each engine)
222
- this._logger.start("Build");
222
+ // Phase 2: 빌드
223
+ const concurrency = getMaxConcurrency();
223
224
 
224
225
  // Create list of build tasks
225
226
  const buildTasks: Array<() => Promise<void>> = [];
@@ -229,7 +230,7 @@ export class BuildOrchestrator {
229
230
  const pkgDir = path.join(this._cwd, "packages", name);
230
231
 
231
232
  buildTasks.push(async () => {
232
- this._logger.debug(`${name} (${config.target}) started`);
233
+ this._logger.debug(`[${name}] (${config.target}) 빌드 시작`);
233
234
  const engine = createBuildEngine(
234
235
  { name, dir: pkgDir, config },
235
236
  { cwd: this._cwd },
@@ -238,7 +239,7 @@ export class BuildOrchestrator {
238
239
  try {
239
240
  const engineResult = await engine.run({ js: true, dts: true, lint: true });
240
241
 
241
- // Handle JS build results
242
+ // JS 빌드 결과 처리
242
243
  results.push({
243
244
  name,
244
245
  target: config.target,
@@ -249,7 +250,7 @@ export class BuildOrchestrator {
249
250
  });
250
251
  if (!engineResult.js.success) state.hasError = true;
251
252
 
252
- // Handle DTS results
253
+ // DTS 결과 처리
253
254
  const diagnostics = engineResult.dts.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
254
255
  results.push({
255
256
  name,
@@ -261,7 +262,7 @@ export class BuildOrchestrator {
261
262
  });
262
263
  if (!engineResult.dts.success) state.hasError = true;
263
264
 
264
- // Handle lint results
265
+ // 린트 결과 처리
265
266
  if (engineResult.lint != null) {
266
267
  results.push({
267
268
  name,
@@ -277,11 +278,12 @@ export class BuildOrchestrator {
277
278
  await engine.stop();
278
279
  }
279
280
 
280
- // Copy copySrc files
281
+ // copySrc 파일 복사
281
282
  if (config.copySrc != null && config.copySrc.length > 0) {
283
+ this._logger.debug(`[${name}] copySrc 파일 복사 중 (${config.copySrc.length}개)`);
282
284
  await copySrcFiles(pkgDir, config.copySrc);
283
285
  }
284
- this._logger.debug(`${name} (${config.target}) completed`);
286
+ this._logger.debug(`[${name}] (${config.target}) 빌드 완료`);
285
287
  });
286
288
  }
287
289
 
@@ -290,7 +292,7 @@ export class BuildOrchestrator {
290
292
  const pkgDir = path.join(this._cwd, "packages", name);
291
293
 
292
294
  buildTasks.push(async () => {
293
- this._logger.debug(`${name} (server) started`);
295
+ this._logger.debug(`[${name}] (server) 빌드 시작`);
294
296
  const engine = createBuildEngine(
295
297
  { name, dir: pkgDir, config: { ...config, env: { ...baseEnv, ...config.env } } },
296
298
  { cwd: this._cwd },
@@ -299,7 +301,7 @@ export class BuildOrchestrator {
299
301
  try {
300
302
  const engineResult = await engine.run({ js: true, dts: false, lint: true });
301
303
 
302
- // Handle JS build results
304
+ // JS 빌드 결과 처리
303
305
  results.push({
304
306
  name,
305
307
  target: "server",
@@ -310,7 +312,7 @@ export class BuildOrchestrator {
310
312
  });
311
313
  if (!engineResult.js.success) state.hasError = true;
312
314
 
313
- // Handle DTS/typecheck results
315
+ // DTS/타입체크 결과 처리
314
316
  const diagnostics = engineResult.dts.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
315
317
  results.push({
316
318
  name,
@@ -322,7 +324,7 @@ export class BuildOrchestrator {
322
324
  });
323
325
  if (!engineResult.dts.success) state.hasError = true;
324
326
 
325
- // Handle lint results
327
+ // 린트 결과 처리
326
328
  if (engineResult.lint != null) {
327
329
  results.push({
328
330
  name,
@@ -337,7 +339,7 @@ export class BuildOrchestrator {
337
339
  } finally {
338
340
  await engine.stop();
339
341
  }
340
- this._logger.debug(`${name} (server) completed`);
342
+ this._logger.debug(`[${name}] (server) 빌드 완료`);
341
343
  });
342
344
  }
343
345
 
@@ -346,7 +348,7 @@ export class BuildOrchestrator {
346
348
  const pkgDir = path.join(this._cwd, "packages", name);
347
349
 
348
350
  buildTasks.push(async () => {
349
- this._logger.debug(`${name} (client) started`);
351
+ this._logger.debug(`[${name}] (client) 빌드 시작`);
350
352
  const engine = createBuildEngine(
351
353
  { name, dir: pkgDir, config: { ...config, env: { ...baseEnv, ...config.env } } },
352
354
  { cwd: this._cwd },
@@ -355,7 +357,7 @@ export class BuildOrchestrator {
355
357
  try {
356
358
  const engineResult = await engine.run({ js: true, dts: false, lint: true });
357
359
 
358
- // Handle JS build results
360
+ // JS 빌드 결과 처리
359
361
  results.push({
360
362
  name,
361
363
  target: "client",
@@ -366,7 +368,7 @@ export class BuildOrchestrator {
366
368
  });
367
369
  if (!engineResult.js.success) state.hasError = true;
368
370
 
369
- // Handle DTS results (always success for client)
371
+ // DTS 결과 처리
370
372
  const diagnostics = engineResult.dts.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
371
373
  results.push({
372
374
  name,
@@ -378,7 +380,7 @@ export class BuildOrchestrator {
378
380
  });
379
381
  if (!engineResult.dts.success) state.hasError = true;
380
382
 
381
- // Handle lint results
383
+ // 린트 결과 처리
382
384
  if (engineResult.lint != null) {
383
385
  results.push({
384
386
  name,
@@ -390,27 +392,31 @@ export class BuildOrchestrator {
390
392
  if (!engineResult.lint.success) state.hasError = true;
391
393
  }
392
394
 
393
- // Native builds (only when JS build succeeds)
395
+ // 네이티브 빌드 (JS 빌드 성공 시에만 실행)
394
396
  if (engineResult.js.success) {
395
397
  const distPath = path.join(pkgDir, "dist");
396
398
  const nativeBuildPromises: Array<Promise<void>> = [];
397
399
 
398
400
  if (config.capacitor != null) {
401
+ this._logger.debug(`[${name}] Capacitor 네이티브 빌드 시작`);
399
402
  nativeBuildPromises.push(
400
403
  (async () => {
401
404
  const cap = await Capacitor.create(pkgDir, config.capacitor!, config.exclude);
402
405
  await cap.initialize();
403
406
  await cap.build(distPath);
407
+ this._logger.debug(`[${name}] Capacitor 네이티브 빌드 완료`);
404
408
  })(),
405
409
  );
406
410
  }
407
411
 
408
412
  if (config.electron != null) {
413
+ this._logger.debug(`[${name}] Electron 네이티브 빌드 시작`);
409
414
  nativeBuildPromises.push(
410
415
  (async () => {
411
416
  const elc = await Electron.create(pkgDir, config.electron!, config.exclude);
412
417
  await elc.initialize();
413
418
  await elc.build(distPath);
419
+ this._logger.debug(`[${name}] Electron 네이티브 빌드 완료`);
414
420
  })(),
415
421
  );
416
422
  }
@@ -422,7 +428,7 @@ export class BuildOrchestrator {
422
428
  state.hasError = true;
423
429
  const err = nativeResult.reason;
424
430
  this._logger.error(
425
- `${name} native build failed: ${err instanceof Error ? err.message : String(err)}`,
431
+ `[${name}] 네이티브 빌드 실패: ${err instanceof Error ? err.message : String(err)}`,
426
432
  );
427
433
  }
428
434
  }
@@ -431,19 +437,18 @@ export class BuildOrchestrator {
431
437
  } finally {
432
438
  await engine.stop();
433
439
  }
434
- this._logger.debug(`${name} (client) completed`);
440
+ this._logger.debug(`[${name}] (client) 빌드 완료`);
435
441
  });
436
442
  }
437
443
 
438
- // Run all builds with concurrency limit (lint runs inside each engine)
439
- const concurrency = getMaxConcurrency();
440
- this._logger.debug(`빌드 실행 (${buildTasks.length}개 작업, 동시성: ${concurrency})`);
444
+ this._logger.start(`빌드 실행 중... (${buildTasks.length}개 작업, 동시성: ${concurrency})`);
445
+ this._logger.debug("빌드 작업 목록", { tasks: buildTasks.length, concurrency });
441
446
  const buildResults = await runWithConcurrency(buildTasks, concurrency);
442
447
  for (const settledResult of buildResults) {
443
448
  if (settledResult.status === "rejected") {
444
449
  const err = settledResult.reason;
445
450
  const stack = err instanceof Error ? err.stack : undefined;
446
- this._logger.error("Unexpected error during build", {
451
+ this._logger.error("빌드 예기치 않은 에러", {
447
452
  error: String(err),
448
453
  });
449
454
  if (stack != null) {
@@ -452,24 +457,24 @@ export class BuildOrchestrator {
452
457
  state.hasError = true;
453
458
  }
454
459
  }
455
- this._logger.success("Build");
460
+ this._logger.success("빌드 실행 완료");
456
461
 
457
- // Output results
462
+ // 결과 출력
458
463
  const allDiagnostics: ts.Diagnostic[] = [];
459
464
  for (const result of results) {
460
465
  const typeLabel = result.type === "dts" ? "dts" : result.type === "lint" ? "lint" : result.target;
461
466
 
462
- // Output warnings
467
+ // 경고 출력
463
468
  if (result.warnings != null) {
464
469
  this._logger.warn(formatBuildMessages(result.name, typeLabel, result.warnings));
465
470
  }
466
471
 
467
- // Output errors
472
+ // 에러 출력
468
473
  if (!result.success) {
469
474
  if (result.errors != null) {
470
475
  this._logger.error(formatBuildMessages(result.name, typeLabel, result.errors));
471
476
  } else {
472
- this._logger.error(`${result.name} (${typeLabel})`);
477
+ this._logger.error(`[${result.name}] (${typeLabel}) 실패`);
473
478
  }
474
479
  }
475
480
  if (result.diagnostics != null) {
@@ -477,18 +482,20 @@ export class BuildOrchestrator {
477
482
  }
478
483
  }
479
484
 
480
- // Output diagnostics (deduplicated)
485
+ // 진단 정보 출력 (중복 제거)
481
486
  if (allDiagnostics.length > 0) {
482
487
  const uniqueDiagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics);
483
488
  const message = ts.formatDiagnosticsWithColorAndContext(uniqueDiagnostics, formatHost);
484
489
  process.stdout.write(message);
485
490
  }
486
491
 
487
- // Output result log
492
+ // 최종 결과 로그
493
+ const errorCount = results.filter((r) => !r.success).length;
494
+ const warningCount = results.filter((r) => r.warnings != null).length;
488
495
  if (state.hasError) {
489
- this._logger.error("Build failed");
496
+ this._logger.error("빌드 에러 발생", { errorCount, warningCount });
490
497
  } else {
491
- this._logger.info("Build completed");
498
+ this._logger.info("빌드 완료", { errorCount, warningCount });
492
499
  }
493
500
 
494
501
  return state.hasError;
@@ -90,9 +90,9 @@ export class DevWatchOrchestrator {
90
90
  }
91
91
 
92
92
  async initialize(): Promise<void> {
93
- this._logger.debug(`${this._options.mode} start`, { targets: this._options.targets });
93
+ this._logger.debug(`${this._options.mode} 시작`, { targets: this._options.targets });
94
94
 
95
- // Load sd.config.ts
95
+ // sd.config.ts 로드
96
96
  let sdConfig: SdConfig;
97
97
  try {
98
98
  sdConfig = await loadSdConfig({
@@ -100,9 +100,9 @@ export class DevWatchOrchestrator {
100
100
  dev: true,
101
101
  options: this._options.options,
102
102
  });
103
- this._logger.debug("sd.config.ts loaded");
103
+ this._logger.debug("sd.config.ts 로드 완료");
104
104
  } catch (err) {
105
- this._logger.error(`Failed to load sd.config.ts: ${err instanceof Error ? err.message : err}`);
105
+ this._logger.error(`sd.config.ts 로드 실패: ${err instanceof Error ? err.message : err}`);
106
106
  process.exitCode = 1;
107
107
  throw err;
108
108
  }
@@ -147,8 +147,8 @@ export class DevWatchOrchestrator {
147
147
  // Check if there are packages to process
148
148
  const totalPackages = this._libraryPackages.length + this._serverPackages.length + this._watchHookPackages.length + this._clientPackages.length;
149
149
  if (totalPackages === 0) {
150
- const modeLabel = this._options.mode === "watch" ? "watch" : "develop";
151
- process.stdout.write(`⚠ No packages to ${modeLabel}.\n`);
150
+ const modeLabel = this._options.mode === "watch" ? "워치" : "개발";
151
+ process.stdout.write(`⚠ ${modeLabel} 대상 패키지가 없습니다.\n`);
152
152
  return;
153
153
  }
154
154
 
@@ -245,7 +245,7 @@ export class DevWatchOrchestrator {
245
245
  return;
246
246
  }
247
247
 
248
- process.stdout.write("⏳ Shutting down...\n");
248
+ process.stdout.write("⏳ 종료 중...\n");
249
249
 
250
250
  const shutdownTasks: Array<Promise<void>> = [];
251
251
 
@@ -274,7 +274,7 @@ export class DevWatchOrchestrator {
274
274
  this._watchHookWatchers.length = 0;
275
275
  this._replaceDepWatcher?.dispose();
276
276
 
277
- process.stdout.write("✔ Done\n");
277
+ process.stdout.write("✔ 종료 완료\n");
278
278
  }
279
279
 
280
280
  // --- Watch mode ---
@@ -289,12 +289,19 @@ export class DevWatchOrchestrator {
289
289
  }
290
290
 
291
291
  // Start all engines
292
- this._logger.start("Running initial build...");
293
- const watchPromises: Array<Promise<void>> = [];
294
- watchPromises.push(...this._libraryEngines.map((e) => e.startWatch({ js: true, dts: true, lint: true })));
292
+ const total = this._libraryEngines.length;
293
+ this._logger.start(`초기 빌드 실행 중... (${total}개 패키지)`);
294
+ let completed = 0;
295
+
296
+ const watchPromises = this._libraryEngines.map(async (engine, i) => {
297
+ const pkgName = this._libraryPackages[i].name;
298
+ await engine.startWatch({ js: true, dts: true, lint: true });
299
+ completed++;
300
+ this._logger.info(` [${completed}/${total}] ${pkgName} 완료`);
301
+ });
295
302
 
296
303
  await Promise.allSettled(watchPromises);
297
- this._logger.success("Initial build completed");
304
+ this._logger.success("초기 빌드 실행 완료");
298
305
 
299
306
  // Print initial build results
300
307
  printErrors(this._resultCollector.toMap());
@@ -314,7 +321,7 @@ export class DevWatchOrchestrator {
314
321
  });
315
322
  this._watchHookWatchers.push(watcher);
316
323
 
317
- this._logger.success(`Watch hook started: ${pkg.name}`);
324
+ this._logger.success(`워치 시작됨: ${pkg.name}`);
318
325
  }
319
326
  }
320
327
 
@@ -329,11 +336,11 @@ export class DevWatchOrchestrator {
329
336
  this._watchHookChildren.set(pkgName, child);
330
337
 
331
338
  child.on("error", (err) => {
332
- this._logger.error(`Watch hook error (${pkgName}): ${err.message}`);
339
+ this._logger.error(`[${pkgName}] 워치 훅 에러: ${err.message}`);
333
340
  });
334
341
  child.on("close", (code) => {
335
342
  if (code !== 0 && code !== null) {
336
- this._logger.warn(`Watch hook (${pkgName}) exited with code ${String(code)}`);
343
+ this._logger.warn(`[${pkgName}] 워치 훅이 코드 ${String(code)}로 종료됨`);
337
344
  }
338
345
  });
339
346
  }
@@ -342,7 +349,7 @@ export class DevWatchOrchestrator {
342
349
 
343
350
  private async _startDevMode(): Promise<void> {
344
351
  // Start client and server engines in parallel
345
- this._logger.debug("Starting initial build (Promise.allSettled)");
352
+ this._logger.debug("초기 빌드 시작");
346
353
  const initialBuildPromises: Array<{ name: string; promise: Promise<void> }> = [];
347
354
 
348
355
  for (const [name, engine] of this._clientEngines) {
@@ -366,9 +373,9 @@ export class DevWatchOrchestrator {
366
373
  initialResults.forEach((result, index) => {
367
374
  const taskName = initialBuildPromises[index].name;
368
375
  if (result.status === "rejected") {
369
- this._logger.debug(`[${taskName}] Initial build failed:`, result.reason);
376
+ this._logger.debug(`[${taskName}] 초기 빌드 실패:`, result.reason);
370
377
  } else {
371
- this._logger.debug(`[${taskName}] Initial build completed`);
378
+ this._logger.debug(`[${taskName}] 초기 빌드 완료`);
372
379
  }
373
380
  });
374
381
 
@@ -400,7 +407,7 @@ export class DevWatchOrchestrator {
400
407
  try {
401
408
  await this._startServerRuntime(name, mainJsPath, { ...this._baseEnv, ...config.env }, clientPorts);
402
409
  } catch (err) {
403
- this._logger.error(`[${name}] Error starting Server Runtime:`, errNs.message(err));
410
+ this._logger.error(`[${name}] 서버 런타임 시작 실패:`, errNs.message(err));
404
411
  this._resultCollector.add({
405
412
  name,
406
413
  target: "server",
@@ -427,7 +434,7 @@ export class DevWatchOrchestrator {
427
434
  await cap.run(devServerUrl);
428
435
  } catch (err) {
429
436
  this._logger.error(
430
- `[${name}] Capacitor run failed: ${errNs.message(err)}`,
437
+ `[${name}] Capacitor 실행 실패: ${errNs.message(err)}`,
431
438
  );
432
439
  }
433
440
  }
@@ -440,14 +447,14 @@ export class DevWatchOrchestrator {
440
447
  await elc.run(devServerUrl);
441
448
  } catch (err) {
442
449
  this._logger.error(
443
- `[${name}] Electron run failed: ${errNs.message(err)}`,
450
+ `[${name}] Electron 실행 실패: ${errNs.message(err)}`,
444
451
  );
445
452
  this._resultCollector.add({
446
453
  name,
447
454
  target: "client",
448
455
  type: "build",
449
456
  status: "error",
450
- message: `Electron run failed: ${errNs.message(err)}`,
457
+ message: `Electron 실행 실패: ${errNs.message(err)}`,
451
458
  });
452
459
  }
453
460
  })();
@@ -469,7 +476,7 @@ export class DevWatchOrchestrator {
469
476
  restartPromises.push(
470
477
  this._startServerRuntime(name, mainJsPath, { ...this._baseEnv, ...config.env }, clientPorts)
471
478
  .catch((err: unknown) => {
472
- this._logger.error(`[${name}] Error starting Server Runtime:`, errNs.message(err));
479
+ this._logger.error(`[${name}] 서버 런타임 시작 실패:`, errNs.message(err));
473
480
  this._resultCollector.add({
474
481
  name,
475
482
  target: "server",
@@ -519,12 +526,12 @@ export class DevWatchOrchestrator {
519
526
  env?: Record<string, string>,
520
527
  clientPorts?: Record<string, number>,
521
528
  ): Promise<void> {
522
- this._logger.debug(`[${serverName}] _startServerRuntime: ${mainJsPath}`);
529
+ this._logger.debug(`[${serverName}] 서버 런타임 시작: ${mainJsPath}`);
523
530
 
524
531
  // Terminate existing runtime
525
532
  const existingRuntime = this._serverRuntimeWorkers.get(serverName);
526
533
  if (existingRuntime != null) {
527
- this._logger.info(`[${serverName}] Restarting server...`);
534
+ this._logger.info(`[${serverName}] 서버 재시작 중...`);
528
535
  await existingRuntime.terminate();
529
536
  }
530
537
 
@@ -560,7 +567,7 @@ export class DevWatchOrchestrator {
560
567
  runtimeWorker
561
568
  .start({ mainJsPath, clientPorts, env })
562
569
  .catch((err: unknown) => {
563
- this._logger.error(`[${serverName}] Server Runtime Worker crashed:`, errNs.message(err));
570
+ this._logger.error(`[${serverName}] 서버 런타임 워커 비정상 종료:`, errNs.message(err));
564
571
  this._resultCollector.add({
565
572
  name: serverName,
566
573
  target: "server",
package/src/sd-cli.ts CHANGED
@@ -31,7 +31,7 @@ if (isDev) {
31
31
  const { loadSdConfig } = await import("./utils/sd-config.js");
32
32
  const { setupReplaceDeps } = await import("./utils/replace-deps.js");
33
33
  const sdConfig = await loadSdConfig({ cwd: process.cwd(), dev: false, options: [] });
34
- if (sdConfig.replaceDeps != null) {
34
+ if (process.argv[2] !== "replace-deps" && sdConfig.replaceDeps != null) {
35
35
  await setupReplaceDeps(process.cwd(), sdConfig.replaceDeps);
36
36
  }
37
37
  } catch {
@@ -57,22 +57,29 @@ export interface ServerEsbuildOptions {
57
57
  dev?: boolean;
58
58
  }
59
59
 
60
+ /**
61
+ * Generate a JS banner snippet that merges env vars into process.env at runtime.
62
+ * Uses ??= so that runtime ENV (e.g. `DEV=false node server.js`) takes precedence
63
+ * over build-time defaults.
64
+ */
65
+ export function createEnvBanner(env?: Record<string, string>): string {
66
+ if (env == null || Object.keys(env).length === 0) return "";
67
+ return `for(const[__k,__v]of Object.entries(${JSON.stringify(env)})){process.env[__k]??=__v;}`;
68
+ }
69
+
60
70
  /**
61
71
  * Create esbuild config for Server build
62
72
  *
63
73
  * Used for server package builds
64
74
  * - bundle: true (single bundle with all dependencies)
65
75
  * - minify: true (minify for code protection)
66
- * - banner: createRequire shim for CJS package require() support
67
- * - Replace env with define option (process.env.KEY format)
76
+ * - banner: createRequire shim for CJS package require() support + env injection
68
77
  */
69
78
  export function createServerEsbuildOptions(options: ServerEsbuildOptions): esbuild.BuildOptions {
70
- const define: Record<string, string> = {};
71
- if (options.env != null) {
72
- for (const [key, value] of Object.entries(options.env)) {
73
- define[`process.env.${key}`] = JSON.stringify(value);
74
- }
75
- }
79
+ const envBanner = createEnvBanner(options.env);
80
+ const bannerJs =
81
+ "import { createRequire } from 'module'; const require = createRequire(import.meta.url);" +
82
+ envBanner;
76
83
 
77
84
  return {
78
85
  entryPoints: options.entryPoints,
@@ -82,11 +89,8 @@ export function createServerEsbuildOptions(options: ServerEsbuildOptions): esbui
82
89
  platform: "node",
83
90
  target: "node20",
84
91
  bundle: true,
85
- banner: {
86
- js: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);",
87
- },
92
+ banner: { js: bannerJs },
88
93
  external: options.external,
89
- define,
90
94
  tsconfig: path.join(options.pkgDir, "tsconfig.json"),
91
95
  logLevel: "silent",
92
96
  };
@@ -25,7 +25,7 @@ export function printErrors(results: Map<string, BuildResult>): void {
25
25
  if (result.message != null && result.message !== "") {
26
26
  consola.error(formatBuildMessages(result.name, typeLabel, [result.message]));
27
27
  } else {
28
- consola.error(`${result.name} (${typeLabel})`);
28
+ consola.error(`[${result.name}] (${typeLabel}) 실패`);
29
29
  }
30
30
  }
31
31
  }
@@ -113,7 +113,7 @@ export function collectDeps(
113
113
  replaceDepsConfig?: Record<string, string>,
114
114
  ): DepsResult {
115
115
  const startTime = performance.now();
116
- logger.debug("[collectDeps] Starting dependency collection...");
116
+ logger.debug("의존성 수집 시작");
117
117
  const rootPkgJsonPath = path.join(cwd, "package.json");
118
118
  const rootPkgJson = JSON.parse(fs.readFileSync(rootPkgJsonPath, "utf-8")) as { name: string };
119
119
  const scopeMatch = rootPkgJson.name.match(/^(@[^/]+)\//);
@@ -170,7 +170,7 @@ export function collectDeps(
170
170
 
171
171
  traverse(pkgDir);
172
172
  logger.debug(
173
- `[collectDeps] Done: workspace=${String(workspaceDeps.length)}, replace=${String(replaceDeps.length)} (${Math.round(performance.now() - startTime)}ms)`,
173
+ `의존성 수집 완료: workspace=${String(workspaceDeps.length)}, replace=${String(replaceDeps.length)} (${Math.round(performance.now() - startTime)}ms)`,
174
174
  );
175
175
  return { workspaceDeps, replaceDeps };
176
176
  }
@@ -347,7 +347,7 @@ export function classifyDevPackages(
347
347
  serverClientsMap.set(clientConfig.server, clients);
348
348
  } else {
349
349
  process.stdout.write(
350
- `⚠ Client "${name}" server "${clientConfig.server}" not in dev targets running as standalone.\n`,
350
+ `⚠ 클라이언트 "${name}" 서버 "${clientConfig.server}" dev 대상에 없어 독립 실행됩니다.\n`,
351
351
  );
352
352
  }
353
353
  }
@@ -45,7 +45,7 @@ export class RebuildManager extends EventEmitter<RebuildManagerEvents> {
45
45
 
46
46
  const tasks = Array.from(batchBuilds.entries());
47
47
  const titles = tasks.map(([, { title }]) => title).join(", ");
48
- this._logger.start(`Rebuilding... (${titles})`);
48
+ this._logger.start(`리빌드 실행 중... (${titles})`);
49
49
 
50
50
  const results = await Promise.allSettled(tasks.map(([, { promise }]) => promise));
51
51
 
@@ -54,11 +54,11 @@ export class RebuildManager extends EventEmitter<RebuildManagerEvents> {
54
54
  const failed = results.filter((r): r is PromiseRejectedResult => r.status === "rejected");
55
55
  if (failed.length > 0) {
56
56
  for (const result of failed) {
57
- this._logger.error("Error during rebuild", { error: String(result.reason) });
57
+ this._logger.error("리빌드 에러 발생", { error: String(result.reason) });
58
58
  }
59
59
  }
60
60
 
61
- this._logger.success(`Rebuild completed (${titles})`);
61
+ this._logger.success(`리빌드 실행 완료 (${titles})`);
62
62
 
63
63
  this.emit("batchComplete");
64
64