@simplysm/sd-cli 14.1.9 → 14.1.11

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 (264) hide show
  1. package/dist/capacitor/capacitor-icon.js +2 -2
  2. package/dist/capacitor/capacitor-icon.js.map +1 -1
  3. package/dist/capacitor/capacitor-npm-config.d.ts +1 -1
  4. package/dist/capacitor/capacitor-npm-config.d.ts.map +1 -1
  5. package/dist/capacitor/capacitor-npm-config.js +11 -18
  6. package/dist/capacitor/capacitor-npm-config.js.map +1 -1
  7. package/dist/capacitor/capacitor.d.ts +1 -1
  8. package/dist/capacitor/capacitor.js +2 -2
  9. package/dist/capacitor/capacitor.js.map +1 -1
  10. package/dist/commands/check.d.ts.map +1 -1
  11. package/dist/commands/check.js +1 -0
  12. package/dist/commands/check.js.map +1 -1
  13. package/dist/commands/device.js +2 -2
  14. package/dist/commands/device.js.map +1 -1
  15. package/dist/commands/init/generators/root.d.ts.map +1 -1
  16. package/dist/commands/init/generators/root.js +0 -1
  17. package/dist/commands/init/generators/root.js.map +1 -1
  18. package/dist/commands/init/init-client.js +1 -1
  19. package/dist/commands/init/init-client.js.map +1 -1
  20. package/dist/commands/init/init.js +2 -2
  21. package/dist/commands/init/init.js.map +1 -1
  22. package/dist/commands/publish/deployment-phase.d.ts.map +1 -1
  23. package/dist/commands/publish/deployment-phase.js +1 -0
  24. package/dist/commands/publish/deployment-phase.js.map +1 -1
  25. package/dist/commands/publish/npm-publisher.js +3 -3
  26. package/dist/commands/publish/npm-publisher.js.map +1 -1
  27. package/dist/commands/publish/post-publish-phase.d.ts.map +1 -1
  28. package/dist/commands/publish/post-publish-phase.js +1 -0
  29. package/dist/commands/publish/post-publish-phase.js.map +1 -1
  30. package/dist/commands/publish/publish-command.d.ts.map +1 -1
  31. package/dist/commands/publish/publish-command.js +7 -12
  32. package/dist/commands/publish/publish-command.js.map +1 -1
  33. package/dist/commands/publish/version-upgrade.d.ts.map +1 -1
  34. package/dist/commands/publish/version-upgrade.js +50 -0
  35. package/dist/commands/publish/version-upgrade.js.map +1 -1
  36. package/dist/deps/replace-deps/collect-deps.js +4 -4
  37. package/dist/deps/replace-deps/collect-deps.js.map +1 -1
  38. package/dist/deps/replace-deps/replace-deps-resolve.d.ts +4 -12
  39. package/dist/deps/replace-deps/replace-deps-resolve.d.ts.map +1 -1
  40. package/dist/deps/replace-deps/replace-deps-resolve.js +13 -49
  41. package/dist/deps/replace-deps/replace-deps-resolve.js.map +1 -1
  42. package/dist/deps/replace-deps/replace-deps.d.ts +2 -2
  43. package/dist/deps/replace-deps/replace-deps.js +3 -3
  44. package/dist/deps/server-externals/server-production-files.d.ts +3 -3
  45. package/dist/deps/server-externals/server-production-files.d.ts.map +1 -1
  46. package/dist/deps/server-externals/server-production-files.js +24 -17
  47. package/dist/deps/server-externals/server-production-files.js.map +1 -1
  48. package/dist/electron/electron.d.ts.map +1 -1
  49. package/dist/electron/electron.js +6 -11
  50. package/dist/electron/electron.js.map +1 -1
  51. package/dist/engines/BaseEngine.d.ts +1 -0
  52. package/dist/engines/BaseEngine.d.ts.map +1 -1
  53. package/dist/engines/BaseEngine.js +2 -1
  54. package/dist/engines/BaseEngine.js.map +1 -1
  55. package/dist/esbuild/esbuild-config.d.ts +6 -2
  56. package/dist/esbuild/esbuild-config.d.ts.map +1 -1
  57. package/dist/esbuild/esbuild-config.js +4 -3
  58. package/dist/esbuild/esbuild-config.js.map +1 -1
  59. package/dist/esbuild/esbuild-tsc-plugin.d.ts.map +1 -1
  60. package/dist/esbuild/esbuild-tsc-plugin.js +3 -1
  61. package/dist/esbuild/esbuild-tsc-plugin.js.map +1 -1
  62. package/dist/orchestrators/BaseOrchestrator.d.ts.map +1 -1
  63. package/dist/orchestrators/BaseOrchestrator.js +1 -0
  64. package/dist/orchestrators/BaseOrchestrator.js.map +1 -1
  65. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
  66. package/dist/orchestrators/BuildOrchestrator.js +3 -5
  67. package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
  68. package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
  69. package/dist/orchestrators/DevOrchestrator.js +1 -0
  70. package/dist/orchestrators/DevOrchestrator.js.map +1 -1
  71. package/dist/orchestrators/ServerRuntimeManager.d.ts.map +1 -1
  72. package/dist/orchestrators/ServerRuntimeManager.js +4 -0
  73. package/dist/orchestrators/ServerRuntimeManager.js.map +1 -1
  74. package/dist/orchestrators/TypecheckOrchestrator.d.ts.map +1 -1
  75. package/dist/orchestrators/TypecheckOrchestrator.js +4 -6
  76. package/dist/orchestrators/TypecheckOrchestrator.js.map +1 -1
  77. package/dist/runtime/engine-watch-events.d.ts.map +1 -1
  78. package/dist/runtime/engine-watch-events.js +5 -0
  79. package/dist/runtime/engine-watch-events.js.map +1 -1
  80. package/dist/runtime/worker-events.d.ts +1 -0
  81. package/dist/runtime/worker-events.d.ts.map +1 -1
  82. package/dist/sd-cli-entry.d.ts.map +1 -1
  83. package/dist/sd-cli-entry.js +0 -4
  84. package/dist/sd-cli-entry.js.map +1 -1
  85. package/dist/sd-cli.js +2 -0
  86. package/dist/sd-cli.js.map +1 -1
  87. package/dist/typecheck/typecheck-non-package.d.ts.map +1 -1
  88. package/dist/typecheck/typecheck-non-package.js +10 -0
  89. package/dist/typecheck/typecheck-non-package.js.map +1 -1
  90. package/dist/utils/package-utils.d.ts +8 -6
  91. package/dist/utils/package-utils.d.ts.map +1 -1
  92. package/dist/utils/package-utils.js +26 -24
  93. package/dist/utils/package-utils.js.map +1 -1
  94. package/dist/utils/workspace-utils.d.ts +17 -0
  95. package/dist/utils/workspace-utils.d.ts.map +1 -0
  96. package/dist/utils/workspace-utils.js +95 -0
  97. package/dist/utils/workspace-utils.js.map +1 -0
  98. package/dist/workers/client.worker.d.ts +1 -0
  99. package/dist/workers/client.worker.d.ts.map +1 -1
  100. package/dist/workers/client.worker.js +8 -3
  101. package/dist/workers/client.worker.js.map +1 -1
  102. package/dist/workers/library-build.worker.d.ts +1 -0
  103. package/dist/workers/library-build.worker.d.ts.map +1 -1
  104. package/dist/workers/library-build.worker.js +3 -2
  105. package/dist/workers/library-build.worker.js.map +1 -1
  106. package/dist/workers/server-build.worker.d.ts +1 -0
  107. package/dist/workers/server-build.worker.d.ts.map +1 -1
  108. package/dist/workers/server-build.worker.js +12 -12
  109. package/dist/workers/server-build.worker.js.map +1 -1
  110. package/dist/workers/server-esbuild-context.d.ts.map +1 -1
  111. package/dist/workers/server-esbuild-context.js +4 -2
  112. package/dist/workers/server-esbuild-context.js.map +1 -1
  113. package/dist/workers/server-runtime.worker.d.ts +1 -0
  114. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  115. package/dist/workers/server-runtime.worker.js +9 -3
  116. package/dist/workers/server-runtime.worker.js.map +1 -1
  117. package/dist/workers/server-watch-manager.d.ts +1 -1
  118. package/dist/workers/server-watch-manager.d.ts.map +1 -1
  119. package/dist/workers/server-watch-manager.js +2 -2
  120. package/dist/workers/server-watch-manager.js.map +1 -1
  121. package/package.json +11 -11
  122. package/src/capacitor/capacitor-icon.ts +2 -2
  123. package/src/capacitor/capacitor-npm-config.ts +10 -19
  124. package/src/capacitor/capacitor.ts +2 -2
  125. package/src/commands/check.ts +1 -0
  126. package/src/commands/device.ts +2 -2
  127. package/src/commands/init/generators/root.ts +0 -1
  128. package/src/commands/init/init-client.ts +1 -1
  129. package/src/commands/init/init.ts +2 -2
  130. package/src/commands/init/templates/workspace-root/mise.toml.hbs +1 -1
  131. package/src/commands/publish/deployment-phase.ts +1 -0
  132. package/src/commands/publish/npm-publisher.ts +3 -3
  133. package/src/commands/publish/post-publish-phase.ts +1 -0
  134. package/src/commands/publish/publish-command.ts +7 -15
  135. package/src/commands/publish/version-upgrade.ts +51 -0
  136. package/src/deps/replace-deps/collect-deps.ts +4 -4
  137. package/src/deps/replace-deps/replace-deps-resolve.ts +13 -56
  138. package/src/deps/replace-deps/replace-deps.ts +3 -3
  139. package/src/deps/server-externals/server-production-files.ts +31 -18
  140. package/src/electron/electron.ts +7 -13
  141. package/src/engines/BaseEngine.ts +3 -2
  142. package/src/esbuild/esbuild-config.ts +12 -3
  143. package/src/esbuild/esbuild-tsc-plugin.ts +4 -1
  144. package/src/orchestrators/BaseOrchestrator.ts +1 -0
  145. package/src/orchestrators/BuildOrchestrator.ts +3 -5
  146. package/src/orchestrators/DevOrchestrator.ts +1 -0
  147. package/src/orchestrators/ServerRuntimeManager.ts +4 -0
  148. package/src/orchestrators/TypecheckOrchestrator.ts +4 -6
  149. package/src/runtime/engine-watch-events.ts +7 -1
  150. package/src/runtime/worker-events.ts +1 -0
  151. package/src/sd-cli-entry.ts +0 -9
  152. package/src/sd-cli.ts +2 -0
  153. package/src/typecheck/typecheck-non-package.ts +11 -0
  154. package/src/utils/package-utils.ts +30 -23
  155. package/src/utils/workspace-utils.ts +117 -0
  156. package/src/workers/client.worker.ts +9 -4
  157. package/src/workers/library-build.worker.ts +4 -3
  158. package/src/workers/server-build.worker.ts +13 -13
  159. package/src/workers/server-esbuild-context.ts +5 -2
  160. package/src/workers/server-runtime.worker.ts +10 -3
  161. package/src/workers/server-watch-manager.ts +3 -3
  162. package/tests/capacitor/capacitor-build.spec.ts +142 -142
  163. package/tests/capacitor/capacitor-init.spec.ts +181 -181
  164. package/tests/capacitor/capacitor-npm-config.acc.spec.ts +114 -114
  165. package/tests/capacitor/capacitor-npm-config.spec.ts +94 -94
  166. package/tests/commands/publish-manifest.acc.spec.ts +67 -0
  167. package/tests/deps/replace-deps/collect-deps.acc.spec.ts +16 -1
  168. package/tests/deps/replace-deps/replace-deps-resolve.acc.spec.ts +9 -5
  169. package/tests/deps/replace-deps/replace-deps-setup.acc.spec.ts +3 -3
  170. package/tests/deps/server-externals/server-production-files.spec.ts +68 -0
  171. package/tests/electron/electron.spec.ts +608 -608
  172. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-browser.tsbuildinfo +1 -1
  173. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck-node.tsbuildinfo +1 -1
  174. package/tests/ts-compiler/fixtures/non-angular-pkg/.cache/typecheck.tsbuildinfo +1 -1
  175. package/tests/utils/engine-watch-events.spec.ts +17 -0
  176. package/tests/utils/esbuild-config.spec.ts +15 -0
  177. package/tests/utils/package-utils.spec.ts +36 -4
  178. package/tests/utils/replace-deps-watch.acc.spec.ts +4 -4
  179. package/tests/utils/replace-deps-watch.spec.ts +3 -3
  180. package/tests/utils/replace-deps.spec.ts +1 -35
  181. package/tests/utils/workspace-utils.spec.ts +87 -0
  182. package/tests/workers/library-build-worker.spec.ts +1 -1
  183. package/tests/workers/server-esbuild-context.spec.ts +4 -3
  184. package/dist/commands/reinstall.d.ts +0 -13
  185. package/dist/commands/reinstall.d.ts.map +0 -1
  186. package/dist/commands/reinstall.js +0 -56
  187. package/dist/commands/reinstall.js.map +0 -1
  188. package/src/commands/init/templates/workspace-root/pnpm-workspace.yaml +0 -5
  189. package/src/commands/reinstall.ts +0 -63
  190. package/tests/angular/angular-compiler-hmr-removal.verify.md +0 -16
  191. package/tests/angular/onbuild-lint-removal.verify.md +0 -8
  192. package/tests/angular/vite-angular-plugin-sdtscompiler.verify.md +0 -13
  193. package/tests/angular/vite-angular-plugin-vitest.verify.md +0 -20
  194. package/tests/capacitor/capacitor-android-exports.verify.md +0 -11
  195. package/tests/commands/publish-npm-local-split.verify.md +0 -9
  196. package/tests/commands/publish-responsibility-split.verify.md +0 -13
  197. package/tests/commands/publish-set.verify.md +0 -7
  198. package/tests/commands/publish-storage-split.verify.md +0 -8
  199. package/tests/commands/slice3-severity-cleanup.verify.md +0 -12
  200. package/tests/deps/deps-directory-separation.verify.md +0 -15
  201. package/tests/deps/replace-deps/replace-deps-perf.verify.md +0 -15
  202. package/tests/deps/server-externals/mise-toml-parse-intent.verify.md +0 -16
  203. package/tests/electron/electron-symlink-cleanup.verify.md +0 -8
  204. package/tests/engines/engine-duplicate-output-removal.verify.md +0 -10
  205. package/tests/engines/engine-typecheck-selection.verify.md +0 -8
  206. package/tests/engines/esbuild-client-engine.verify.md +0 -15
  207. package/tests/engines/normalize-result.verify.md +0 -9
  208. package/tests/engines/vite-dependency-cleanup.verify.md +0 -24
  209. package/tests/esbuild/esbuild-angular-compiler-plugin-hmr.verify.md +0 -23
  210. package/tests/esbuild/esbuild-angular-compiler-plugin-onload.verify.md +0 -21
  211. package/tests/esbuild/esbuild-angular-compiler-plugin-onstart-extraction.verify.md +0 -16
  212. package/tests/esbuild/esbuild-angular-compiler-plugin-sdtscompiler.verify.md +0 -15
  213. package/tests/esbuild/esbuild-angular-compiler-plugin-stylesheet.verify.md +0 -31
  214. package/tests/esbuild/esbuild-angular-compiler-plugin-worker.verify.md +0 -59
  215. package/tests/esbuild/esbuild-angular-compiler-plugin.verify.md +0 -21
  216. package/tests/esbuild/esbuild-postcss-plugin-chunking.verify.md +0 -17
  217. package/tests/esbuild/esbuild-tsc-plugin-imports.verify.md +0 -13
  218. package/tests/esbuild/esbuild-worker-plugin-node.verify.md +0 -12
  219. package/tests/esbuild/esbuild-worker-plugin.verify.md +0 -7
  220. package/tests/orchestrators/dist-delete-watcher.verify.md +0 -10
  221. package/tests/orchestrators/orchestrator-baseenv.verify.md +0 -10
  222. package/tests/orchestrators/orchestrator-diagnostic-formatting.verify.md +0 -10
  223. package/tests/orchestrators/orchestrator-initializemode-signature.verify.md +0 -9
  224. package/tests/orchestrators/slice1-stdout-to-consola.verify.md +0 -10
  225. package/tests/sd-cli-catch-all.verify.md +0 -7
  226. package/tests/sd-cli-log-tag.verify.md +0 -11
  227. package/tests/ts-compiler/SdTsCompiler-affected-files.verify.md +0 -8
  228. package/tests/ts-compiler/SdTsCompiler-crash-handling.verify.md +0 -24
  229. package/tests/ts-compiler/SdTsCompiler-diagnostics.verify.md +0 -12
  230. package/tests/ts-compiler/SdTsCompiler-emit.verify.md +0 -9
  231. package/tests/ts-compiler/SdTsCompiler.verify.md +0 -41
  232. package/tests/ts-compiler/scss-lint-integration.verify.md +0 -14
  233. package/tests/utils/copy-public-outdir.verify.md +0 -8
  234. package/tests/utils/dev-http-server.verify.md +0 -8
  235. package/tests/utils/engine-watch-events.verify.md +0 -17
  236. package/tests/utils/esbuild-client-config-integration.verify.md +0 -9
  237. package/tests/utils/esbuild-client-config-postcss.verify.md +0 -6
  238. package/tests/utils/esbuild-client-config.verify.md +0 -26
  239. package/tests/utils/esbuild-index-html.verify.md +0 -10
  240. package/tests/utils/esbuild-pwa.verify.md +0 -9
  241. package/tests/utils/esbuild-scss-plugin.verify.md +0 -8
  242. package/tests/utils/hmr-service.verify.md +0 -17
  243. package/tests/utils/lint-core-import-paths.verify.md +0 -10
  244. package/tests/utils/replace-deps-split.verify.md +0 -15
  245. package/tests/utils/replace-deps-watch.verify.md +0 -9
  246. package/tests/utils/server-production-files-import-paths.verify.md +0 -14
  247. package/tests/utils/vite-config-cleanup.verify.md +0 -7
  248. package/tests/workers/build-watch-paths-library.verify.md +0 -10
  249. package/tests/workers/build-watch-paths-ngtsc-server.verify.md +0 -12
  250. package/tests/workers/client-worker-browser-support.verify.md +0 -7
  251. package/tests/workers/client-worker-cleanup.verify.md +0 -8
  252. package/tests/workers/client-worker-initial-build-error.verify.md +0 -7
  253. package/tests/workers/client-worker-initial-build-warnings.verify.md +0 -7
  254. package/tests/workers/client-worker-mtime-incremental.verify.md +0 -10
  255. package/tests/workers/client-worker-onend-sync.verify.md +0 -7
  256. package/tests/workers/client-worker-refactor.verify.md +0 -22
  257. package/tests/workers/client-worker-ts-cache-invalidation.verify.md +0 -12
  258. package/tests/workers/dev-port-file.verify.md +0 -6
  259. package/tests/workers/ngtsc-build-rootnames-refresh.verify.md +0 -8
  260. package/tests/workers/server-build-context-dispose.verify.md +0 -8
  261. package/tests/workers/server-build-worker-plugin.verify.md +0 -9
  262. package/tests/workers/server-build-worker-refactoring.verify.md +0 -14
  263. package/tests/workers/server-esbuild-context-integration.verify.md +0 -10
  264. package/tests/workers/server-esbuild-context-tsc.verify.md +0 -7
package/src/sd-cli.ts CHANGED
@@ -44,6 +44,7 @@ if (isDev) {
44
44
  const code = err instanceof Error && "code" in err ? (err as NodeJS.ErrnoException).code : undefined;
45
45
  if (code !== "MODULE_NOT_FOUND" && code !== "ERR_MODULE_NOT_FOUND") {
46
46
  logger.warn("replaceDeps 사전 설정 실패:", errNs.message(err));
47
+ logger.debug(`replaceDeps 사전 설정 실패 스택:\n${errNs.stack(err)}`);
47
48
  }
48
49
  }
49
50
  }
@@ -109,5 +110,6 @@ function configureAffinityAndPriority(pid: number): void {
109
110
  "CPU affinity/priority 설정 실패:",
110
111
  errNs.message(err),
111
112
  );
113
+ logger.debug(`CPU affinity/priority 설정 실패 스택:\n${errNs.stack(err)}`);
112
114
  });
113
115
  }
@@ -3,6 +3,7 @@ import ts from "typescript";
3
3
  import { pathx } from "@simplysm/core-node";
4
4
  import { createLogger } from "@simplysm/core-common";
5
5
  import { parseTsconfig } from "../utils/tsconfig";
6
+ import { collectWorkspacePackages } from "../utils/workspace-utils";
6
7
  import { serializeDiagnostic, type SerializedDiagnostic } from "./typecheck-serialization";
7
8
 
8
9
  const logger = createLogger("sd:cli:typecheck-non-pkg");
@@ -27,10 +28,20 @@ export function typecheckNonPackageFiles(cwd: string): NonPackageTypecheckResult
27
28
  const parsedConfig = parseTsconfig(cwd);
28
29
  const packagesDir = path.join(cwd, "packages");
29
30
 
31
+ // packages/(배포 대상)가 아닌 워크스페이스(tests/·plugins/·향후 추가분)는 각자 엔진 타입체크가
32
+ // 자기 tsconfig로 담당하므로 루트 sweep에서 제외한다. 루트 tsconfig로 검사하면 그 워크스페이스
33
+ // 고유 옵션(allowImportingTsExtensions 등)이 무시돼 거짓 에러가 난다. 디렉터리명에 의존하지 않는다.
34
+ const nonDeployWorkspaceDirs = collectWorkspacePackages(cwd)
35
+ .filter((ws) => !ws.relPath.startsWith("packages/"))
36
+ .map((ws) => pathx.posixResolve(ws.absPath) + "/");
37
+
30
38
  const isNonPackageFile = (fileName: string): boolean => {
31
39
  const normalized = pathx.posixResolve(fileName);
32
40
  const normalizedPkgDir = pathx.posixResolve(packagesDir);
33
41
 
42
+ // packages/ 가 아닌 워크스페이스 파일 → 엔진이 자기 tsconfig로 담당, sweep 제외
43
+ if (nonDeployWorkspaceDirs.some((dir) => normalized.startsWith(dir))) return false;
44
+
34
45
  // packages/ 디렉토리 외부 파일
35
46
  if (!normalized.startsWith(normalizedPkgDir + "/")) return true;
36
47
 
@@ -3,6 +3,7 @@ import fs from "fs";
3
3
  import { SdError } from "@simplysm/core-common";
4
4
  import { fsx, pathx } from "@simplysm/core-node";
5
5
  import { createLogger } from "@simplysm/core-common";
6
+ import { collectWorkspacePackages } from "./workspace-utils";
6
7
  import type {
7
8
  SdPackageConfig,
8
9
  } from "../sd-config.types";
@@ -19,26 +20,31 @@ export function findPackageRoot(startDir: string): string {
19
20
  }
20
21
 
21
22
  /**
22
- * packages/ 및 tests/ 디렉토리에서 모든 워크스페이스 패키지를 탐색한다.
23
- * 디렉토리명 → 상대 경로의 맵을 반환한다 (예: "orm" → "tests/orm").
23
+ * package.json#workspaces의 모든 워크스페이스 패키지를 탐색한다.
24
+ * 디렉토리명 → 상대 경로의 맵을 반환한다 (예: "orm" → "tests/orm", "sd" → "plugins/sd").
25
+ * packages/·tests/·plugins/ 등 종류를 가리지 않고 포함하며, 배포/검사 대상 구분은 소비자가 relPath로 판단한다.
24
26
  */
25
27
  export function discoverWorkspacePackages(cwd: string): Map<string, string> {
26
28
  logger.debug("워크스페이스 패키지 탐색 시작");
27
29
  const map = new Map<string, string>();
28
- for (const dir of ["packages", "tests"]) {
29
- const baseDir = pathx.posix(path.join(cwd, dir));
30
- if (!fs.existsSync(baseDir)) continue;
31
- for (const entry of fs.readdirSync(baseDir, { withFileTypes: true })) {
32
- if (!entry.isDirectory()) continue;
33
- if (!fs.existsSync(pathx.posix(path.join(baseDir, entry.name, "package.json")))) continue;
34
- if (map.has(entry.name)) {
35
- throw new SdError(
36
- `Duplicate workspace package name: ${entry.name} (${map.get(entry.name)} and ${dir}/${entry.name})`,
37
- );
38
- }
39
- map.set(entry.name, `${dir}/${entry.name}`);
30
+
31
+ const workspacePackages = (() => {
32
+ try {
33
+ return collectWorkspacePackages(cwd);
34
+ } catch {
35
+ return [];
36
+ }
37
+ })();
38
+
39
+ for (const item of workspacePackages) {
40
+ if (map.has(item.dirName)) {
41
+ throw new SdError(
42
+ `Duplicate workspace package name: ${item.dirName} (${map.get(item.dirName)} and ${item.relPath})`,
43
+ );
40
44
  }
45
+ map.set(item.dirName, item.relPath);
41
46
  }
47
+
42
48
  logger.debug(`워크스페이스 패키지 탐색 완료 (${map.size}개)`);
43
49
  return map;
44
50
  }
@@ -57,27 +63,28 @@ export function buildPathMapFromConfig(
57
63
  }
58
64
 
59
65
  /**
60
- * workspace에서 발견된 tests/ 패키지를 sd.config.ts 패키지에 병합한다.
61
- * tests 패키지는 기본적으로 `{ target: "node" }`가 할당된다.
62
- * 모든 패키지의 pathMap(name → 상대 경로)도 함께 구성한다.
63
- * tests 패키지명이 sd.config.ts 패키지명과 충돌하면 SdError를 던진다.
66
+ * workspace에서 발견된 비배포 워크스페이스(packages/ 가 아닌 tests/·plugins/ 등)를 sd.config.ts
67
+ * 패키지에 병합한다. 이들은 빌드 대상이 아니지만 각자 자기 tsconfig로 타입체크하기 위해
68
+ * `{ target: "node" }`가 할당된다. 모든 패키지의 pathMap(name → 상대 경로)도 함께 구성한다.
69
+ * 디렉터리명이 sd.config.ts 패키지명과 충돌하면 SdError를 던진다.
70
+ * 특정 디렉터리명이 아니라 "packages/ 인가"로만 갈라 새 워크스페이스 종류도 자동 포함된다.
64
71
  */
65
72
  export function mergeTestsPackagesIntoConfig(
66
73
  configPackages: Record<string, SdPackageConfig | undefined>,
67
74
  workspacePackages: Map<string, string>,
68
75
  ): { merged: Record<string, SdPackageConfig | undefined>; pathMap: Map<string, string> } {
69
- logger.debug("tests 패키지 병합 시작");
76
+ logger.debug("비배포 워크스페이스 병합 시작");
70
77
  const pathMap = new Map<string, string>();
71
78
  const merged: Record<string, SdPackageConfig | undefined> = { ...configPackages };
72
79
 
73
- // config 패키지의 기본 경로 설정
80
+ // config 패키지(배포 대상)의 기본 경로 설정
74
81
  for (const name of Object.keys(configPackages)) {
75
82
  pathMap.set(name, `packages/${name}`);
76
83
  }
77
84
 
78
- // tests 패키지 추가
85
+ // packages/(배포 대상)가 아닌 워크스페이스 추가
79
86
  for (const [name, relPath] of workspacePackages) {
80
- if (!relPath.startsWith("tests/")) continue;
87
+ if (relPath.startsWith("packages/")) continue;
81
88
 
82
89
  if (name in configPackages) {
83
90
  throw new SdError(
@@ -89,7 +96,7 @@ export function mergeTestsPackagesIntoConfig(
89
96
  pathMap.set(name, relPath);
90
97
  }
91
98
 
92
- logger.debug(`tests 패키지 병합 완료 (총 ${Object.keys(merged).length}개)`);
99
+ logger.debug(`비배포 워크스페이스 병합 완료 (총 ${Object.keys(merged).length}개)`);
93
100
  return { merged, pathMap };
94
101
  }
95
102
 
@@ -0,0 +1,117 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { globSync } from "glob";
4
+ import { pathx } from "@simplysm/core-node";
5
+
6
+ export interface WorkspacePackageDir {
7
+ dirName: string;
8
+ packageName: string;
9
+ relPath: string;
10
+ absPath: string;
11
+ }
12
+
13
+ interface WorkspaceRootPackageJson {
14
+ workspaces?: unknown;
15
+ }
16
+
17
+ interface WorkspacePackageJson {
18
+ name?: unknown;
19
+ }
20
+
21
+ /**
22
+ * root package.json의 workspaces 값을 Bun workspace 패턴 배열로 정규화한다.
23
+ */
24
+ export function parsePackageJsonWorkspaces(workspaces: unknown): string[] {
25
+ const rawPatterns = Array.isArray(workspaces)
26
+ ? workspaces
27
+ : typeof workspaces === "object" && workspaces != null && Array.isArray((workspaces as { packages?: unknown }).packages)
28
+ ? (workspaces as { packages: unknown[] }).packages
29
+ : [];
30
+
31
+ return rawPatterns
32
+ .filter((item): item is string => typeof item === "string")
33
+ .map((item) => item.trim())
34
+ .filter((item) => item !== "");
35
+ }
36
+
37
+ export function readWorkspacePatterns(workspaceRoot: string): string[] {
38
+ const packageJsonPath = path.join(workspaceRoot, "package.json");
39
+ if (!fs.existsSync(packageJsonPath)) return [];
40
+
41
+ const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as WorkspaceRootPackageJson;
42
+ return parsePackageJsonWorkspaces(pkgJson.workspaces);
43
+ }
44
+
45
+ export function findWorkspaceRoot(startDir: string): string | undefined {
46
+ let current = path.resolve(startDir);
47
+ if (fs.existsSync(current) && fs.statSync(current).isFile()) {
48
+ current = path.dirname(current);
49
+ }
50
+
51
+ while (true) {
52
+ if (readWorkspacePatterns(current).length > 0) {
53
+ return pathx.posix(current);
54
+ }
55
+
56
+ const parent = path.dirname(current);
57
+ if (parent === current) return undefined;
58
+ current = parent;
59
+ }
60
+ }
61
+
62
+ function splitWorkspacePatterns(patterns: string[]): { include: string[]; exclude: string[] } {
63
+ const include: string[] = [];
64
+ const exclude: string[] = [];
65
+
66
+ for (const pattern of patterns) {
67
+ if (pattern.startsWith("!")) {
68
+ const excluded = pattern.slice(1).trim();
69
+ if (excluded !== "") exclude.push(excluded);
70
+ } else {
71
+ include.push(pattern);
72
+ }
73
+ }
74
+
75
+ return { include, exclude };
76
+ }
77
+
78
+ /**
79
+ * Bun workspace root의 package.json#workspaces 기준으로 실제 패키지 디렉터리를 수집한다.
80
+ */
81
+ export function collectWorkspacePackages(workspaceRoot: string): WorkspacePackageDir[] {
82
+ const root = pathx.posix(path.resolve(workspaceRoot));
83
+ const patterns = readWorkspacePatterns(root);
84
+ const { include, exclude } = splitWorkspacePatterns(patterns);
85
+ const absDirs = new Set<string>();
86
+
87
+ for (const pattern of include) {
88
+ const matches = globSync(pattern, {
89
+ cwd: root,
90
+ absolute: true,
91
+ nodir: false,
92
+ ignore: exclude,
93
+ });
94
+
95
+ for (const match of matches) {
96
+ const absPath = pathx.posix(path.resolve(match));
97
+ const packageJsonPath = path.join(absPath, "package.json");
98
+ if (!fs.existsSync(packageJsonPath)) continue;
99
+ if (!fs.statSync(absPath).isDirectory()) continue;
100
+ absDirs.add(absPath);
101
+ }
102
+ }
103
+
104
+ return [...absDirs]
105
+ .sort((a, b) => a.localeCompare(b))
106
+ .map((absPath): WorkspacePackageDir => {
107
+ const relPath = pathx.posix(path.relative(root, absPath));
108
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(absPath, "package.json"), "utf-8")) as WorkspacePackageJson;
109
+ const packageName = typeof pkgJson.name === "string" ? pkgJson.name : path.basename(absPath);
110
+ return {
111
+ dirName: path.basename(absPath),
112
+ packageName,
113
+ relPath,
114
+ absPath,
115
+ };
116
+ });
117
+ }
@@ -57,7 +57,7 @@ export interface ClientWorkerEvents extends Record<string, unknown> {
57
57
  buildStart: Record<string, never>;
58
58
  build: ClientBuildResult;
59
59
  serverReady: { port: number };
60
- error: { message: string };
60
+ error: { message: string; stack?: string };
61
61
  }
62
62
 
63
63
  //#endregion
@@ -207,6 +207,7 @@ async function build(info: ClientBuildInfo): Promise<ClientBuildResult> {
207
207
  errors.push(errNs.message(err));
208
208
  }
209
209
  logger.debug(`[${info.name}] client worker build 예외: ${errors.join("\n")}`);
210
+ logger.debug(`[${info.name}] client worker build 예외 스택:\n${errNs.stack(err)}`);
210
211
  return { success: false, errors };
211
212
  }
212
213
  }
@@ -313,8 +314,10 @@ function createDevBuildEndHandler(
313
314
  }
314
315
  } catch (err) {
315
316
  const message = errNs.message(err);
317
+ const stack = errNs.stack(err);
318
+ logger.debug(`client dev build end 예외 스택:\n${stack}`);
316
319
  if (!isInitialBuild) {
317
- sender.send("error", { message });
320
+ sender.send("error", { message, stack });
318
321
  } else {
319
322
  isInitialBuild = false;
320
323
  initialBuildResolve?.({
@@ -423,7 +426,7 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
423
426
  hmrService?.broadcast({ type: "full-reload" });
424
427
  sender.send("build", { success: true });
425
428
  } catch (err) {
426
- sender.send("error", { message: errNs.message(err) });
429
+ sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
427
430
  }
428
431
  });
429
432
 
@@ -437,7 +440,9 @@ async function startWatch(info: ClientBuildInfo): Promise<ClientBuildResult> {
437
440
  return initialResult;
438
441
  } catch (err) {
439
442
  const message = errNs.message(err);
440
- sender.send("error", { message });
443
+ const stack = errNs.stack(err);
444
+ logger.debug(`[${info.name}] client worker startWatch 예외 스택:\n${stack}`);
445
+ sender.send("error", { message, stack });
441
446
  return { success: false, errors: [message] };
442
447
  }
443
448
  }
@@ -36,7 +36,7 @@ export interface CombinedBuildEvent {
36
36
  export interface LibraryBuildWorkerEvents extends Record<string, unknown> {
37
37
  buildStart: Record<string, never>;
38
38
  build: CombinedBuildEvent;
39
- error: { message: string };
39
+ error: { message: string; stack?: string };
40
40
  }
41
41
 
42
42
  //#endregion
@@ -135,6 +135,7 @@ async function build(info: LibraryBuildInfo): Promise<LibraryBuildResult> {
135
135
  } catch (err) {
136
136
  const message = errNs.message(err);
137
137
  logger.debug(`[${info.name}] library worker build 예외 발생: ${message}`);
138
+ logger.debug(`[${info.name}] library worker build 예외 스택:\n${errNs.stack(err)}`);
138
139
  return {
139
140
  build: { success: false, errors: [message], diagnostics: [] },
140
141
  };
@@ -323,11 +324,11 @@ async function startWatch(info: LibraryBuildInfo): Promise<void> {
323
324
  const event = buildWatchEvent(info, result, changedScssFiles);
324
325
  sender.send("build", event);
325
326
  } catch (err) {
326
- sender.send("error", { message: errNs.message(err) });
327
+ sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
327
328
  }
328
329
  });
329
330
  } catch (err) {
330
- sender.send("error", { message: errNs.message(err) });
331
+ sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
331
332
  }
332
333
  }
333
334
 
@@ -92,7 +92,7 @@ export interface ServerCombinedBuildEvent {
92
92
  export interface ServerBuildWorkerEvents extends Record<string, unknown> {
93
93
  buildStart: Record<string, never>;
94
94
  build: ServerCombinedBuildEvent;
95
- error: { message: string };
95
+ error: { message: string; stack?: string };
96
96
  }
97
97
 
98
98
  //#endregion
@@ -169,7 +169,7 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
169
169
  jsResult = await esbuild.build({ ...esbuildOptions, plugins: [createWorkerBundlePlugin(), tscPlugin.plugin] })
170
170
  .then(async (result) => {
171
171
  if (result.outputFiles) {
172
- await writeChangedOutputFiles(result.outputFiles);
172
+ await writeChangedOutputFiles(result.outputFiles, { rewriteJsExtensions: false });
173
173
  }
174
174
  const errors = formatEsbuildMessages(result.errors, "error");
175
175
  const warnings = formatEsbuildMessages(result.warnings, "warning");
@@ -179,11 +179,14 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
179
179
  warnings: warnings.length > 0 ? warnings : undefined,
180
180
  };
181
181
  })
182
- .catch((err) => ({
183
- success: false,
184
- errors: [errNs.message(err)],
185
- warnings: undefined,
186
- }));
182
+ .catch((err) => {
183
+ logger.debug(`[${info.name}] server esbuild build 예외 스택:\n${errNs.stack(err)}`);
184
+ return {
185
+ success: false,
186
+ errors: [errNs.message(err)],
187
+ warnings: undefined,
188
+ };
189
+ });
187
190
 
188
191
  tscErrors = tscPlugin.getErrors() ?? [];
189
192
  tscDiagnostics = tscPlugin.getDiagnostics();
@@ -231,11 +234,8 @@ async function build(info: ServerBuildInfo): Promise<ServerBuildResult> {
231
234
  };
232
235
  } catch (err) {
233
236
  const message = errNs.message(err);
234
- const stack = err instanceof Error ? err.stack : undefined;
235
237
  logger.debug(`[${info.name}] server worker build 예외: ${message}`);
236
- if (stack != null) {
237
- logger.debug(`[${info.name}] 스택 트레이스:\n${stack}`);
238
- }
238
+ logger.debug(`[${info.name}] 스택 트레이스:\n${errNs.stack(err)}`);
239
239
  return {
240
240
  build: { success: false, errors: [message], diagnostics: [] },
241
241
  mainJsPath,
@@ -358,11 +358,11 @@ async function startWatch(info: ServerWatchInfo): Promise<void> {
358
358
  initialExternals: cachedExternal,
359
359
  onBuildStart: () => sender.send("buildStart", {}),
360
360
  onBuild: (result) => sender.send("build", result),
361
- onError: (message) => sender.send("error", { message }),
361
+ onError: (message, stack) => sender.send("error", { message, stack }),
362
362
  rebuild: () => rebuildAll(),
363
363
  });
364
364
  } catch (err) {
365
- sender.send("error", { message: errNs.message(err) });
365
+ sender.send("error", { message: errNs.message(err), stack: errNs.stack(err) });
366
366
  }
367
367
  }
368
368
 
@@ -1,6 +1,6 @@
1
1
  import type ts from "typescript";
2
2
  import esbuild from "esbuild";
3
- import { err as errNs } from "@simplysm/core-common";
3
+ import { createLogger, err as errNs } from "@simplysm/core-common";
4
4
  import { formatEsbuildMessages } from "../utils/output-utils";
5
5
  import {
6
6
  createServerEsbuildOptions,
@@ -12,6 +12,8 @@ import type { SerializedDiagnostic } from "../typecheck/typecheck-serialization"
12
12
  import type { LintWithProgramResult } from "../lint/lint-with-program";
13
13
  import { createWorkerBundlePlugin } from "../esbuild/esbuild-worker-plugin";
14
14
 
15
+ const logger = createLogger("sd:cli:server-esbuild-context");
16
+
15
17
  /**
16
18
  * esbuild watch context 생성 옵션
17
19
  */
@@ -87,6 +89,7 @@ export async function rebuild(): Promise<{
87
89
  try {
88
90
  result = await context.rebuild();
89
91
  } catch (err) {
92
+ logger.debug(`server esbuild rebuild 예외 스택:\n${errNs.stack(err)}`);
90
93
  const tscErrors = tscPlugin?.getErrors() ?? [];
91
94
  const allErrors = [errNs.message(err), ...tscErrors];
92
95
  return {
@@ -101,7 +104,7 @@ export async function rebuild(): Promise<{
101
104
  }
102
105
 
103
106
  if (result.outputFiles) {
104
- await writeChangedOutputFiles(result.outputFiles);
107
+ await writeChangedOutputFiles(result.outputFiles, { rewriteJsExtensions: false });
105
108
  }
106
109
 
107
110
  const esbuildErrors = formatEsbuildMessages(result.errors, "error");
@@ -32,6 +32,7 @@ export interface ServerRuntimeReadyEvent {
32
32
  */
33
33
  export interface ServerRuntimeErrorEvent {
34
34
  message: string;
35
+ stack?: string;
35
36
  }
36
37
 
37
38
  /**
@@ -73,18 +74,22 @@ async function cleanup(): Promise<void> {
73
74
  // 서버 listen() 이후 발생하는 런타임 에러를 잡아 커스텀 "error" 이벤트로 전송
74
75
  // (이 핸들러 없이는 워커가 크래시해도 빌드 Promise가 resolve되지 않아 프로세스가 중단될 수 있다)
75
76
  process.on("uncaughtException", (err) => {
76
- logger.error("서버 런타임 미처리 에러", err);
77
+ logger.error("서버 런타임 미처리 에러", errNs.message(err));
78
+ logger.debug(`서버 런타임 미처리 에러 스택:\n${errNs.stack(err)}`);
77
79
  sender.send("error", {
78
80
  message: errNs.message(err),
81
+ stack: errNs.stack(err),
79
82
  });
80
83
  // 이벤트 전송 후 종료할 수 있도록 대기
81
84
  setTimeout(() => process.exit(1), 500);
82
85
  });
83
86
 
84
87
  process.on("unhandledRejection", (reason) => {
85
- logger.error("서버 런타임 미처리 Promise 거부", reason);
88
+ logger.error("서버 런타임 미처리 Promise 거부", errNs.message(reason));
89
+ logger.debug(`서버 런타임 미처리 Promise 거부 스택:\n${errNs.stack(reason)}`);
86
90
  sender.send("error", {
87
91
  message: errNs.message(reason),
92
+ stack: errNs.stack(reason),
88
93
  });
89
94
  // 이벤트 전송 후 종료할 수 있도록 대기
90
95
  setTimeout(() => process.exit(1), 500);
@@ -195,9 +200,11 @@ async function start(info: ServerRuntimeStartInfo): Promise<void> {
195
200
 
196
201
  sender.send("serverReady", { port: server.options.port });
197
202
  } catch (err) {
198
- logger.error("서버 런타임 시작 실패", err);
203
+ logger.error("서버 런타임 시작 실패", errNs.message(err));
204
+ logger.debug(`서버 런타임 시작 실패 스택:\n${errNs.stack(err)}`);
199
205
  sender.send("error", {
200
206
  message: errNs.message(err),
207
+ stack: errNs.stack(err),
201
208
  });
202
209
  }
203
210
  }
@@ -25,7 +25,7 @@ export interface ServerWatchLoopConfig {
25
25
  /** 빌드 완료 이벤트 콜백 */
26
26
  onBuild: (result: { build: { success: boolean; errors?: string[]; warnings?: string[] }; mainJsPath: string }) => void;
27
27
  /** 에러 이벤트 콜백 */
28
- onError: (message: string) => void;
28
+ onError: (message: string, stack?: string) => void;
29
29
  /** 리빌드 실행 콜백 */
30
30
  rebuild: () => Promise<{ build: { success: boolean; errors?: string[]; warnings?: string[] }; mainJsPath: string }>;
31
31
  }
@@ -99,7 +99,7 @@ export async function startServerWatchLoop(config: ServerWatchLoopConfig): Promi
99
99
 
100
100
  const hasRelevantChange = changes.some((c) => {
101
101
  if (metafileAbsPaths.has(c.path)) return true;
102
- // pnpm symlink 경로와 esbuild resolved 경로 불일치 대응
102
+ // package manager symlink 경로와 esbuild resolved 경로 불일치 대응
103
103
  try {
104
104
  const realPath = pathx.posix(fs.realpathSync(c.path));
105
105
  return metafileAbsPaths.has(realPath);
@@ -116,7 +116,7 @@ export async function startServerWatchLoop(config: ServerWatchLoopConfig): Promi
116
116
  logger.debug("변경된 파일이 빌드에 포함되지 않아 리빌드 건너뜀");
117
117
  }
118
118
  } catch (err) {
119
- config.onError(errNs.message(err));
119
+ config.onError(errNs.message(err), errNs.stack(err));
120
120
  }
121
121
  });
122
122