@simplysm/sd-cli 14.0.11 → 14.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -253
- package/dist/angular/client-transform-stylesheet.js +1 -1
- package/dist/angular/client-transform-stylesheet.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts +4 -2
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +73 -36
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/angular/vite-postcss-inline-plugin.d.ts +1 -1
- package/dist/angular/vite-postcss-inline-plugin.js +1 -1
- package/dist/capacitor/capacitor.d.ts +20 -2
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +155 -28
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/build.d.ts +3 -10
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +3 -10
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/check.js +3 -3
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -9
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +3 -9
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/device.d.ts +3 -3
- package/dist/commands/device.js +5 -5
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/publish.d.ts +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +24 -26
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/replace-deps.d.ts +3 -3
- package/dist/commands/replace-deps.d.ts.map +1 -1
- package/dist/commands/replace-deps.js +1 -1
- package/dist/commands/typecheck.d.ts +4 -3
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +5 -11
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/commands/watch.d.ts +9 -9
- package/dist/commands/watch.js +9 -9
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +42 -3
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.d.ts +1 -1
- package/dist/engines/BaseEngine.d.ts.map +1 -1
- package/dist/engines/BaseEngine.js +3 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.d.ts +7 -7
- package/dist/engines/NgtscEngine.d.ts.map +1 -1
- package/dist/engines/NgtscEngine.js +3 -3
- package/dist/engines/ServerEsbuildEngine.d.ts +7 -7
- package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +3 -3
- package/dist/engines/TscEngine.d.ts +7 -7
- package/dist/engines/TscEngine.d.ts.map +1 -1
- package/dist/engines/TscEngine.js +3 -3
- package/dist/engines/ViteEngine.d.ts +7 -1
- package/dist/engines/ViteEngine.d.ts.map +1 -1
- package/dist/engines/ViteEngine.js +13 -12
- package/dist/engines/ViteEngine.js.map +1 -1
- package/dist/engines/index.d.ts +9 -5
- package/dist/engines/index.d.ts.map +1 -1
- package/dist/engines/index.js +7 -5
- package/dist/engines/index.js.map +1 -1
- package/dist/engines/types.d.ts +20 -20
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/infra/ResultCollector.d.ts +9 -9
- package/dist/infra/ResultCollector.js +8 -8
- package/dist/infra/SignalHandler.d.ts +7 -7
- package/dist/infra/SignalHandler.js +7 -7
- package/dist/infra/WorkerManager.d.ts +14 -14
- package/dist/infra/WorkerManager.js +14 -14
- package/dist/orchestrators/BuildOrchestrator.d.ts +25 -25
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +34 -30
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts +7 -7
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +34 -34
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +2 -2
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +15 -8
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.d.ts +3 -3
- package/dist/sd-cli.js +16 -16
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +105 -105
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/angular-compiler.js +5 -5
- package/dist/utils/angular-compiler.js.map +1 -1
- package/dist/utils/build-env.d.ts +1 -1
- package/dist/utils/build-env.js +1 -1
- package/dist/utils/concurrency.d.ts +7 -7
- package/dist/utils/concurrency.js +7 -7
- package/dist/utils/copy-public.d.ts +9 -9
- package/dist/utils/copy-public.js +17 -17
- package/dist/utils/copy-public.js.map +1 -1
- package/dist/utils/copy-src.d.ts +9 -9
- package/dist/utils/copy-src.js +11 -11
- package/dist/utils/copy-src.js.map +1 -1
- package/dist/utils/engine-stop.d.ts +8 -9
- package/dist/utils/engine-stop.d.ts.map +1 -1
- package/dist/utils/engine-stop.js +9 -10
- package/dist/utils/engine-stop.js.map +1 -1
- package/dist/utils/esbuild-config.d.ts +23 -23
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +25 -25
- package/dist/utils/esbuild-config.js.map +1 -1
- package/dist/utils/lint-with-program.d.ts +15 -15
- package/dist/utils/lint-with-program.d.ts.map +1 -1
- package/dist/utils/lint-with-program.js +29 -29
- package/dist/utils/lint-with-program.js.map +1 -1
- package/dist/utils/ngtsc-build-core.d.ts +8 -8
- package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
- package/dist/utils/ngtsc-build-core.js +14 -14
- package/dist/utils/ngtsc-build-core.js.map +1 -1
- package/dist/utils/output-path-rewriter.d.ts +14 -14
- package/dist/utils/output-path-rewriter.js +18 -18
- package/dist/utils/output-path-rewriter.js.map +1 -1
- package/dist/utils/output-utils.d.ts +6 -6
- package/dist/utils/output-utils.js +11 -11
- package/dist/utils/output-utils.js.map +1 -1
- package/dist/utils/package-utils.d.ts +21 -21
- package/dist/utils/package-utils.d.ts.map +1 -1
- package/dist/utils/package-utils.js +56 -45
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/replace-deps.d.ts +25 -25
- package/dist/utils/replace-deps.d.ts.map +1 -1
- package/dist/utils/replace-deps.js +84 -65
- package/dist/utils/replace-deps.js.map +1 -1
- package/dist/utils/sd-config.d.ts +3 -3
- package/dist/utils/sd-config.js +3 -3
- package/dist/utils/tsc-build.d.ts +13 -13
- package/dist/utils/tsc-build.d.ts.map +1 -1
- package/dist/utils/tsc-build.js +9 -9
- package/dist/utils/tsc-build.js.map +1 -1
- package/dist/utils/tsconfig.d.ts +11 -9
- package/dist/utils/tsconfig.d.ts.map +1 -1
- package/dist/utils/tsconfig.js +11 -9
- package/dist/utils/tsconfig.js.map +1 -1
- package/dist/utils/typecheck-non-package.d.ts +5 -6
- package/dist/utils/typecheck-non-package.d.ts.map +1 -1
- package/dist/utils/typecheck-non-package.js +7 -8
- package/dist/utils/typecheck-non-package.js.map +1 -1
- package/dist/utils/typecheck-serialization.d.ts +8 -8
- package/dist/utils/typecheck-serialization.d.ts.map +1 -1
- package/dist/utils/typecheck-serialization.js +12 -16
- package/dist/utils/typecheck-serialization.js.map +1 -1
- package/dist/utils/vite-config.d.ts +12 -5
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +95 -41
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.d.ts.map +1 -1
- package/dist/utils/vite-scope-watch-plugin.js +1 -1
- package/dist/utils/vite-scope-watch-plugin.js.map +1 -1
- package/dist/utils/worker-events.d.ts +12 -12
- package/dist/utils/worker-events.d.ts.map +1 -1
- package/dist/utils/worker-events.js +10 -10
- package/dist/utils/worker-events.js.map +1 -1
- package/dist/utils/worker-utils.d.ts +12 -13
- package/dist/utils/worker-utils.d.ts.map +1 -1
- package/dist/utils/worker-utils.js +12 -13
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js +5 -7
- package/dist/vitest-plugin.js.map +1 -1
- package/dist/workers/client.worker.d.ts +8 -2
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +215 -6
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts +1 -1
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +7 -7
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/lint.worker.d.ts +2 -2
- package/dist/workers/lint.worker.js +2 -2
- package/dist/workers/ngtsc-build.worker.js +30 -30
- package/dist/workers/ngtsc-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts +17 -17
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +46 -46
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-runtime.worker.d.ts +7 -7
- package/dist/workers/server-runtime.worker.d.ts.map +1 -1
- package/dist/workers/server-runtime.worker.js +17 -17
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/docs/config.md +340 -0
- package/docs/publish-configuration-types.md +87 -0
- package/docs/pwa-configuration-types.md +55 -0
- package/docs/vitest-plugin.md +47 -0
- package/package.json +9 -7
- package/src/angular/client-transform-stylesheet.ts +1 -1
- package/src/angular/vite-angular-plugin.ts +89 -39
- package/src/angular/vite-postcss-inline-plugin.ts +1 -1
- package/src/capacitor/capacitor.ts +185 -38
- package/src/commands/build.ts +3 -10
- package/src/commands/check.ts +3 -3
- package/src/commands/dev.ts +3 -9
- package/src/commands/device.ts +5 -5
- package/src/commands/publish.ts +30 -26
- package/src/commands/replace-deps.ts +3 -3
- package/src/commands/typecheck.ts +7 -13
- package/src/commands/watch.ts +9 -9
- package/src/electron/electron.ts +49 -4
- package/src/engines/BaseEngine.ts +4 -1
- package/src/engines/NgtscEngine.ts +7 -7
- package/src/engines/ServerEsbuildEngine.ts +7 -7
- package/src/engines/TscEngine.ts +7 -7
- package/src/engines/ViteEngine.ts +18 -13
- package/src/engines/index.ts +11 -5
- package/src/engines/types.ts +20 -20
- package/src/infra/ResultCollector.ts +9 -9
- package/src/infra/SignalHandler.ts +7 -7
- package/src/infra/WorkerManager.ts +14 -14
- package/src/orchestrators/BuildOrchestrator.ts +42 -38
- package/src/orchestrators/DevWatchOrchestrator.ts +36 -36
- package/src/sd-cli-entry.ts +15 -8
- package/src/sd-cli.ts +16 -16
- package/src/sd-config.types.ts +107 -107
- package/src/utils/angular-compiler.ts +5 -5
- package/src/utils/build-env.ts +1 -1
- package/src/utils/concurrency.ts +7 -7
- package/src/utils/copy-public.ts +17 -17
- package/src/utils/copy-src.ts +11 -11
- package/src/utils/engine-stop.ts +9 -10
- package/src/utils/esbuild-config.ts +29 -29
- package/src/utils/lint-with-program.ts +34 -34
- package/src/utils/ngtsc-build-core.ts +17 -17
- package/src/utils/output-path-rewriter.ts +18 -18
- package/src/utils/output-utils.ts +11 -11
- package/src/utils/package-utils.ts +57 -45
- package/src/utils/replace-deps.ts +92 -67
- package/src/utils/sd-config.ts +3 -3
- package/src/utils/tsc-build.ts +18 -18
- package/src/utils/tsconfig.ts +11 -9
- package/src/utils/typecheck-non-package.ts +7 -8
- package/src/utils/typecheck-serialization.ts +13 -15
- package/src/utils/vite-config.ts +108 -46
- package/src/utils/vite-scope-watch-plugin.ts +6 -1
- package/src/utils/worker-events.ts +16 -16
- package/src/utils/worker-utils.ts +12 -13
- package/src/vitest-plugin.ts +5 -8
- package/src/workers/client.worker.ts +246 -7
- package/src/workers/library-build.worker.ts +8 -8
- package/src/workers/lint.worker.ts +2 -2
- package/src/workers/ngtsc-build.worker.ts +31 -31
- package/src/workers/server-build.worker.ts +60 -60
- package/src/workers/server-runtime.worker.ts +22 -22
- package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +1 -0
- package/tests/angular/vite-angular-plugin-hmr.spec.ts +78 -0
- package/tests/angular/vite-angular-plugin.spec.ts +67 -0
- package/tests/capacitor/capacitor-build.spec.ts +93 -11
- package/tests/capacitor/capacitor-icon.spec.ts +7 -5
- package/tests/capacitor/capacitor-init.spec.ts +124 -10
- package/tests/capacitor/capacitor-run.spec.ts +14 -17
- package/tests/capacitor/capacitor-workspace.spec.ts +5 -3
- package/tests/commands/check.spec.ts +2 -2
- package/tests/commands/publish.spec.ts +2 -2
- package/tests/commands/typecheck.spec.ts +8 -0
- package/tests/electron/electron.spec.ts +12 -10
- package/tests/engines/base-engine.spec.ts +37 -0
- package/tests/engines/vite-engine.spec.ts +115 -3
- package/tests/utils/vite-config.spec.ts +162 -90
- package/tests/workers/client-worker.spec.ts +690 -0
- package/tests/workers/server-build-worker.spec.ts +3 -3
|
@@ -5,7 +5,7 @@ import { symlink } from "fs/promises";
|
|
|
5
5
|
import { createRequire } from "module";
|
|
6
6
|
import { cpx, fsx, pathx } from "@simplysm/core-node";
|
|
7
7
|
import { env } from "@simplysm/core-common";
|
|
8
|
-
import { consola } from "consola";
|
|
8
|
+
import { consola, LogLevels } from "consola";
|
|
9
9
|
import type { SdCapacitorConfig } from "../sd-config.types.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -91,9 +91,7 @@ export class Capacitor {
|
|
|
91
91
|
const platforms = Object.keys(config.platform);
|
|
92
92
|
for (const p of platforms) {
|
|
93
93
|
if (p !== "android") {
|
|
94
|
-
throw new CapacitorConfigError(
|
|
95
|
-
`지원하지 않는 플랫폼입니다: ${p} (현재 android만 지원)`,
|
|
96
|
-
);
|
|
94
|
+
throw new CapacitorConfigError(`지원하지 않는 플랫폼입니다: ${p} (현재 android만 지원)`);
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
97
|
}
|
|
@@ -109,47 +107,65 @@ export class Capacitor {
|
|
|
109
107
|
* 5. cap sync 또는 cap copy 실행
|
|
110
108
|
*/
|
|
111
109
|
async initialize(): Promise<void> {
|
|
110
|
+
Capacitor._logger.debug("initialize 시작");
|
|
112
111
|
await this._acquireLock();
|
|
113
112
|
|
|
114
113
|
try {
|
|
115
114
|
// 외부 도구 검증
|
|
115
|
+
Capacitor._logger.debug("외부 도구 검증 시작");
|
|
116
116
|
await this._validateTools();
|
|
117
|
+
Capacitor._logger.debug("외부 도구 검증 완료");
|
|
117
118
|
|
|
118
119
|
// 1. Capacitor 프로젝트 초기화
|
|
120
|
+
Capacitor._logger.debug("Capacitor 프로젝트 초기화 시작");
|
|
119
121
|
const changed = await this._initCap();
|
|
122
|
+
Capacitor._logger.debug(`Capacitor 프로젝트 초기화 완료 (changed: ${changed})`);
|
|
120
123
|
|
|
121
124
|
// 2. Capacitor 설정 파일 생성
|
|
125
|
+
Capacitor._logger.debug("Capacitor 설정 파일 생성 시작");
|
|
122
126
|
await this._writeCapConf();
|
|
127
|
+
Capacitor._logger.debug("Capacitor 설정 파일 생성 완료");
|
|
123
128
|
|
|
124
129
|
// 3. 플랫폼 관리 (멱등성: 이미 존재하면 스킵)
|
|
130
|
+
Capacitor._logger.debug("플랫폼 추가 시작");
|
|
125
131
|
await this._addPlatforms();
|
|
132
|
+
Capacitor._logger.debug("플랫폼 추가 완료");
|
|
126
133
|
|
|
127
134
|
// 4. 아이콘 처리
|
|
135
|
+
Capacitor._logger.debug("아이콘 처리 시작");
|
|
128
136
|
await this._setupIcon();
|
|
137
|
+
Capacitor._logger.debug("아이콘 처리 완료");
|
|
129
138
|
|
|
130
139
|
// 5. Android 네이티브 설정 구성
|
|
131
140
|
if (this._platforms.includes("android")) {
|
|
141
|
+
Capacitor._logger.debug("Android 네이티브 설정 시작");
|
|
132
142
|
await this._configureAndroid();
|
|
143
|
+
Capacitor._logger.debug("Android 네이티브 설정 완료");
|
|
133
144
|
}
|
|
134
145
|
|
|
135
146
|
// 6. 웹 에셋 동기화
|
|
136
147
|
if (changed) {
|
|
148
|
+
Capacitor._logger.debug("cap sync 시작 (의존성 변경됨)");
|
|
137
149
|
await this._execCap(["sync"]);
|
|
150
|
+
Capacitor._logger.debug("cap sync 완료");
|
|
138
151
|
} else {
|
|
152
|
+
Capacitor._logger.debug("cap copy 시작");
|
|
139
153
|
await this._execCap(["copy"]);
|
|
154
|
+
Capacitor._logger.debug("cap copy 완료");
|
|
140
155
|
}
|
|
141
156
|
} finally {
|
|
142
157
|
await this._releaseLock();
|
|
158
|
+
Capacitor._logger.debug("initialize 완료");
|
|
143
159
|
}
|
|
144
160
|
}
|
|
145
161
|
|
|
146
162
|
//#region Private - 명령어 실행
|
|
147
163
|
|
|
148
164
|
/**
|
|
149
|
-
* Capacitor CLI 명령어를
|
|
165
|
+
* Capacitor CLI 명령어를 pnpm exec로 실행
|
|
150
166
|
*/
|
|
151
167
|
private async _execCap(args: string[]): Promise<string> {
|
|
152
|
-
return this._exec("
|
|
168
|
+
return this._exec("pnpm", ["exec", "cap", ...args], this._capPath);
|
|
153
169
|
}
|
|
154
170
|
|
|
155
171
|
/**
|
|
@@ -157,7 +173,11 @@ export class Capacitor {
|
|
|
157
173
|
*/
|
|
158
174
|
private async _exec(command: string, args: string[], cwd: string): Promise<string> {
|
|
159
175
|
Capacitor._logger.debug(`명령어 실행: ${command} ${args.join(" ")}`);
|
|
160
|
-
const
|
|
176
|
+
const isDebug = consola.level >= LogLevels.debug;
|
|
177
|
+
const { stdout } = await cpx.spawn(command, args, {
|
|
178
|
+
cwd,
|
|
179
|
+
...(isDebug ? { stdio: ["ignore", "inherit", "inherit"] } : {}),
|
|
180
|
+
});
|
|
161
181
|
Capacitor._logger.debug(`실행 결과: ${stdout}`);
|
|
162
182
|
return stdout;
|
|
163
183
|
}
|
|
@@ -215,6 +235,7 @@ export class Capacitor {
|
|
|
215
235
|
"2. ANDROID_HOME 또는 ANDROID_SDK_ROOT 환경 변수를 설정하세요.",
|
|
216
236
|
);
|
|
217
237
|
}
|
|
238
|
+
Capacitor._logger.debug(`Android SDK 경로: ${sdkPath}`);
|
|
218
239
|
|
|
219
240
|
// Java 확인 (android 플랫폼인 경우에만)
|
|
220
241
|
if (this._platforms.includes("android")) {
|
|
@@ -223,6 +244,8 @@ export class Capacitor {
|
|
|
223
244
|
Capacitor._logger.warn(
|
|
224
245
|
"Java 21을 찾을 수 없습니다. Gradle이 내장 JDK를 사용하거나 빌드가 실패할 수 있습니다.",
|
|
225
246
|
);
|
|
247
|
+
} else {
|
|
248
|
+
Capacitor._logger.debug(`Java 21 경로: ${javaPath}`);
|
|
226
249
|
}
|
|
227
250
|
}
|
|
228
251
|
}
|
|
@@ -235,36 +258,47 @@ export class Capacitor {
|
|
|
235
258
|
* Capacitor 프로젝트 기본 초기화 (package.json, npm install, cap init)
|
|
236
259
|
*/
|
|
237
260
|
private async _initCap(): Promise<boolean> {
|
|
261
|
+
Capacitor._logger.debug("package.json 설정 시작");
|
|
238
262
|
const { depChanged, workspacePlugins } = await this._setupNpmConf();
|
|
239
263
|
const nodeModulesExists = await fsx.exists(pathx.posixResolve(this._capPath, "node_modules"));
|
|
264
|
+
Capacitor._logger.debug(`depChanged: ${depChanged}, nodeModulesExists: ${nodeModulesExists}`);
|
|
240
265
|
|
|
241
266
|
if (!depChanged && nodeModulesExists) {
|
|
242
267
|
// 의존성 미변경이어도 workspace 플러그인 symlink는 항상 갱신
|
|
268
|
+
Capacitor._logger.debug("의존성 변경 없음, workspace 플러그인 symlink만 갱신");
|
|
243
269
|
await this._linkWorkspacePlugins(workspacePlugins);
|
|
244
270
|
return false;
|
|
245
271
|
}
|
|
246
272
|
|
|
247
|
-
//
|
|
248
|
-
const
|
|
249
|
-
|
|
273
|
+
// pnpm-workspace.yaml 생성 (상위 workspace 탐색 차단)
|
|
274
|
+
const workspaceYamlPath = pathx.posixResolve(this._capPath, "pnpm-workspace.yaml");
|
|
275
|
+
if (!(await fsx.exists(workspaceYamlPath))) {
|
|
276
|
+
await fsx.write(workspaceYamlPath, "");
|
|
277
|
+
}
|
|
278
|
+
const lockfilePath = pathx.posixResolve(this._capPath, "pnpm-lock.yaml");
|
|
279
|
+
if (!(await fsx.exists(lockfilePath))) {
|
|
280
|
+
await fsx.write(lockfilePath, "");
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// pnpm install + 빌드 스크립트 승인
|
|
284
|
+
Capacitor._logger.debug("pnpm install 시작");
|
|
285
|
+
await this._exec("pnpm", ["install"], this._capPath);
|
|
286
|
+
await this._exec("pnpm", ["approve-builds", "--all"], this._capPath);
|
|
287
|
+
Capacitor._logger.debug("pnpm install 완료");
|
|
250
288
|
|
|
251
289
|
// workspace 플러그인 symlink
|
|
290
|
+
Capacitor._logger.debug("workspace 플러그인 symlink 시작");
|
|
252
291
|
await this._linkWorkspacePlugins(workspacePlugins);
|
|
292
|
+
Capacitor._logger.debug("workspace 플러그인 symlink 완료");
|
|
253
293
|
|
|
254
294
|
// 멱등성: capacitor.config.ts가 없을 때만 cap init 실행
|
|
255
295
|
const configPath = pathx.posixResolve(this._capPath, "capacitor.config.ts");
|
|
256
296
|
if (!(await fsx.exists(configPath))) {
|
|
297
|
+
Capacitor._logger.debug("cap init 시작");
|
|
257
298
|
await this._execCap(["init", this._config.appId, this._config.appId]);
|
|
299
|
+
Capacitor._logger.debug("cap init 완료");
|
|
258
300
|
}
|
|
259
301
|
|
|
260
|
-
// 기본 www/index.html 생성
|
|
261
|
-
const wwwPath = pathx.posixResolve(this._capPath, "www");
|
|
262
|
-
await fsx.mkdir(wwwPath);
|
|
263
|
-
await fsx.write(
|
|
264
|
-
pathx.posixResolve(wwwPath, "index.html"),
|
|
265
|
-
"<!DOCTYPE html><html><head></head><body></body></html>",
|
|
266
|
-
);
|
|
267
|
-
|
|
268
302
|
return true;
|
|
269
303
|
}
|
|
270
304
|
|
|
@@ -465,8 +499,9 @@ export default config;
|
|
|
465
499
|
|
|
466
500
|
// capacitor-assets로 모든 해상도 아이콘/스플래시 생성
|
|
467
501
|
await this._exec(
|
|
468
|
-
"
|
|
502
|
+
"pnpm",
|
|
469
503
|
[
|
|
504
|
+
"exec",
|
|
470
505
|
"capacitor-assets",
|
|
471
506
|
"generate",
|
|
472
507
|
"--iconBackgroundColor",
|
|
@@ -500,10 +535,29 @@ export default config;
|
|
|
500
535
|
throw new Error(`Android 프로젝트 디렉토리를 찾을 수 없습니다: ${androidPath}`);
|
|
501
536
|
}
|
|
502
537
|
|
|
538
|
+
Capacitor._logger.debug("JAVA_HOME 설정 시작");
|
|
503
539
|
await this._configureAndroidJavaHomePath(androidPath);
|
|
540
|
+
Capacitor._logger.debug("JAVA_HOME 설정 완료");
|
|
541
|
+
|
|
542
|
+
Capacitor._logger.debug("Android SDK 경로 설정 시작");
|
|
504
543
|
await this._configureAndroidSdkPath(androidPath);
|
|
544
|
+
Capacitor._logger.debug("Android SDK 경로 설정 완료");
|
|
545
|
+
|
|
546
|
+
Capacitor._logger.debug("AndroidManifest.xml 설정 시작");
|
|
505
547
|
await this._configureAndroidManifest(androidPath);
|
|
548
|
+
Capacitor._logger.debug("AndroidManifest.xml 설정 완료");
|
|
549
|
+
|
|
550
|
+
Capacitor._logger.debug("루트 build.gradle Kotlin 플러그인 설정 시작");
|
|
551
|
+
await this._configureAndroidRootBuildGradle(androidPath);
|
|
552
|
+
Capacitor._logger.debug("루트 build.gradle Kotlin 플러그인 설정 완료");
|
|
553
|
+
|
|
554
|
+
Capacitor._logger.debug("build.gradle 설정 시작");
|
|
506
555
|
await this._configureAndroidBuildGradle(androidPath);
|
|
556
|
+
Capacitor._logger.debug("build.gradle 설정 완료");
|
|
557
|
+
|
|
558
|
+
Capacitor._logger.debug("styles.xml 설정 시작");
|
|
559
|
+
await this._configureAndroidStyles(androidPath);
|
|
560
|
+
Capacitor._logger.debug("styles.xml 설정 완료");
|
|
507
561
|
}
|
|
508
562
|
|
|
509
563
|
/**
|
|
@@ -574,7 +628,9 @@ export default config;
|
|
|
574
628
|
* Android SDK 경로 탐색
|
|
575
629
|
*/
|
|
576
630
|
private async _findAndroidSdk(): Promise<string | undefined> {
|
|
577
|
-
const androidHome =
|
|
631
|
+
const androidHome =
|
|
632
|
+
(env["ANDROID_HOME"] as string | undefined) ??
|
|
633
|
+
(env["ANDROID_SDK_ROOT"] as string | undefined);
|
|
578
634
|
if (androidHome != null && (await fsx.exists(androidHome))) {
|
|
579
635
|
return androidHome;
|
|
580
636
|
}
|
|
@@ -670,6 +726,28 @@ export default config;
|
|
|
670
726
|
await fsx.write(manifestPath, content);
|
|
671
727
|
}
|
|
672
728
|
|
|
729
|
+
/**
|
|
730
|
+
* 루트 build.gradle에 Kotlin Gradle 플러그인 classpath 추가
|
|
731
|
+
*/
|
|
732
|
+
private async _configureAndroidRootBuildGradle(androidPath: string): Promise<void> {
|
|
733
|
+
const rootBuildGradlePath = pathx.posixResolve(androidPath, "build.gradle");
|
|
734
|
+
|
|
735
|
+
if (!(await fsx.exists(rootBuildGradlePath))) {
|
|
736
|
+
Capacitor._logger.warn(`루트 build.gradle 파일을 찾을 수 없습니다: ${rootBuildGradlePath}`);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
let content = await fsx.read(rootBuildGradlePath);
|
|
741
|
+
|
|
742
|
+
if (!content.includes("kotlin-gradle-plugin")) {
|
|
743
|
+
content = content.replace(
|
|
744
|
+
/classpath 'com\.android\.tools\.build:gradle:[^']+'/,
|
|
745
|
+
`$&\n classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.20'`,
|
|
746
|
+
);
|
|
747
|
+
await fsx.write(rootBuildGradlePath, content);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
673
751
|
/**
|
|
674
752
|
* build.gradle 수정 (서명 설정 제외)
|
|
675
753
|
*/
|
|
@@ -710,6 +788,51 @@ export default config;
|
|
|
710
788
|
await fsx.write(buildGradlePath, content);
|
|
711
789
|
}
|
|
712
790
|
|
|
791
|
+
/**
|
|
792
|
+
* styles.xml의 스플래시 테마 수정
|
|
793
|
+
*
|
|
794
|
+
* 1. Theme.SplashScreen parent → Theme.AppCompat.DayNight.NoActionBar
|
|
795
|
+
* Theme.SplashScreen은 android:windowBackground에 compat_splash_screen을 설정하여
|
|
796
|
+
* android:background(@drawable/splash)와 이중 표시를 발생시킨다.
|
|
797
|
+
* installSplashScreen()을 호출하지 않으므로 Theme.SplashScreen 기능이 불필요하다.
|
|
798
|
+
*
|
|
799
|
+
* 2. android:background → android:windowBackground
|
|
800
|
+
* android:background는 View 레벨 속성으로 AppCompat 뷰 계층의 여러 View에 상속되어
|
|
801
|
+
* 동일한 splash 로고가 다중 레이어에 중복 렌더링된다.
|
|
802
|
+
* android:windowBackground는 Window의 DecorView에만 적용되어 단일 렌더링을 보장한다.
|
|
803
|
+
*/
|
|
804
|
+
private async _configureAndroidStyles(androidPath: string): Promise<void> {
|
|
805
|
+
const stylesPath = pathx.posixResolve(androidPath, "app/src/main/res/values/styles.xml");
|
|
806
|
+
|
|
807
|
+
if (!(await fsx.exists(stylesPath))) {
|
|
808
|
+
Capacitor._logger.warn(`styles.xml 파일을 찾을 수 없습니다: ${stylesPath}`);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
let content = await fsx.read(stylesPath);
|
|
813
|
+
let changed = false;
|
|
814
|
+
|
|
815
|
+
if (content.includes('parent="Theme.SplashScreen"')) {
|
|
816
|
+
content = content.replace(
|
|
817
|
+
'parent="Theme.SplashScreen"',
|
|
818
|
+
'parent="Theme.AppCompat.DayNight.NoActionBar"',
|
|
819
|
+
);
|
|
820
|
+
changed = true;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (content.includes('"android:background">@drawable/splash')) {
|
|
824
|
+
content = content.replace(
|
|
825
|
+
'"android:background">@drawable/splash',
|
|
826
|
+
'"android:windowBackground">@drawable/splash',
|
|
827
|
+
);
|
|
828
|
+
changed = true;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (changed) {
|
|
832
|
+
await fsx.write(stylesPath, content);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
713
836
|
//#endregion
|
|
714
837
|
|
|
715
838
|
//#region Public — 기기 실행
|
|
@@ -719,28 +842,35 @@ export default config;
|
|
|
719
842
|
*
|
|
720
843
|
* 1. capacitor.config.ts에 server.url 설정 (Hot Reload용)
|
|
721
844
|
* 2. cap copy — 웹 에셋 동기화
|
|
722
|
-
* 3. cap run — 기기에서 앱 실행
|
|
845
|
+
* 3. cap run — 기기에서 앱 실행
|
|
723
846
|
*/
|
|
724
847
|
async run(url: string): Promise<void> {
|
|
848
|
+
Capacitor._logger.debug(`server.url 설정: ${url}`);
|
|
725
849
|
await this._updateServerUrl(url);
|
|
726
850
|
|
|
727
851
|
for (const platform of this._platforms) {
|
|
852
|
+
Capacitor._logger.debug(`[${platform}] cap copy 시작`);
|
|
728
853
|
await this._execCap(["copy", platform]);
|
|
854
|
+
Capacitor._logger.debug(`[${platform}] cap copy 완료`);
|
|
729
855
|
|
|
730
856
|
try {
|
|
857
|
+
Capacitor._logger.debug(`[${platform}] cap run 시작`);
|
|
731
858
|
await this._execCap(["run", platform]);
|
|
859
|
+
Capacitor._logger.debug(`[${platform}] cap run 완료`);
|
|
732
860
|
} catch (err) {
|
|
733
861
|
if (platform === "android") {
|
|
734
|
-
Capacitor._logger.
|
|
862
|
+
Capacitor._logger.debug(`[${platform}] adb kill-server 시작`);
|
|
735
863
|
try {
|
|
736
864
|
await this._exec("adb", ["kill-server"], this._capPath);
|
|
737
|
-
|
|
738
|
-
|
|
865
|
+
Capacitor._logger.debug(`[${platform}] adb kill-server 완료`);
|
|
866
|
+
} catch (adbErr) {
|
|
867
|
+
const adbErrMsg = adbErr instanceof Error ? adbErr.message : String(adbErr);
|
|
868
|
+
Capacitor._logger.debug(
|
|
869
|
+
`[${platform}] adb kill-server 실패 (무시): ${adbErrMsg}`,
|
|
870
|
+
);
|
|
739
871
|
}
|
|
740
|
-
await this._execCap(["run", platform]);
|
|
741
|
-
} else {
|
|
742
|
-
throw err;
|
|
743
872
|
}
|
|
873
|
+
throw err;
|
|
744
874
|
}
|
|
745
875
|
}
|
|
746
876
|
}
|
|
@@ -779,30 +909,40 @@ export default config;
|
|
|
779
909
|
* 4. 빌드 산출물 복사
|
|
780
910
|
*/
|
|
781
911
|
async build(outPath: string): Promise<void> {
|
|
912
|
+
Capacitor._logger.debug("build 시작");
|
|
913
|
+
|
|
782
914
|
// 1. 웹 에셋 동기화
|
|
915
|
+
Capacitor._logger.debug("cap copy 시작");
|
|
783
916
|
await this._execCap(["copy"]);
|
|
917
|
+
Capacitor._logger.debug("cap copy 완료");
|
|
784
918
|
|
|
785
919
|
// 2. 빌드 타입 결정
|
|
786
920
|
const isDebug = this._config.debug === true;
|
|
787
921
|
const isBundle = this._config.platform?.android?.bundle === true;
|
|
788
922
|
const buildType = isDebug ? "debug" : "release";
|
|
923
|
+
Capacitor._logger.debug(`빌드 타입: ${buildType}, bundle: ${isBundle}`);
|
|
789
924
|
|
|
790
925
|
// 3. 서명 설정
|
|
791
926
|
const signConfig = this._config.platform?.android?.sign;
|
|
792
927
|
if (!isDebug && signConfig != null) {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
);
|
|
928
|
+
Capacitor._logger.debug("서명 설정 시작");
|
|
929
|
+
await this._configureSigningConfig(pathx.posixResolve(this._capPath, "android"), signConfig);
|
|
930
|
+
Capacitor._logger.debug("서명 설정 완료");
|
|
797
931
|
} else if (!isDebug) {
|
|
798
932
|
Capacitor._logger.warn("서명 설정이 없어 unsigned 빌드가 생성됩니다.");
|
|
799
933
|
}
|
|
800
934
|
|
|
801
935
|
// 4. Gradle 빌드
|
|
936
|
+
Capacitor._logger.debug("Gradle 빌드 시작");
|
|
802
937
|
await this._buildAndroid(buildType, isBundle);
|
|
938
|
+
Capacitor._logger.debug("Gradle 빌드 완료");
|
|
803
939
|
|
|
804
940
|
// 5. 빌드 산출물 복사
|
|
941
|
+
Capacitor._logger.debug("빌드 산출물 복사 시작");
|
|
805
942
|
await this._copyBuildOutput(outPath, buildType, isBundle);
|
|
943
|
+
Capacitor._logger.debug("빌드 산출물 복사 완료");
|
|
944
|
+
|
|
945
|
+
Capacitor._logger.debug("build 완료");
|
|
806
946
|
}
|
|
807
947
|
|
|
808
948
|
//#endregion
|
|
@@ -833,8 +973,9 @@ export default config;
|
|
|
833
973
|
if (content.includes("signingConfigs")) return;
|
|
834
974
|
|
|
835
975
|
const storeType = sign.keystoreType ?? "jks";
|
|
836
|
-
const
|
|
837
|
-
const
|
|
976
|
+
const escapeGroovy = (s: string) => s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
977
|
+
const escapedStorePassword = escapeGroovy(sign.storePassword);
|
|
978
|
+
const escapedKeyPassword = escapeGroovy(sign.password);
|
|
838
979
|
|
|
839
980
|
const signingBlock = ` signingConfigs {
|
|
840
981
|
release {
|
|
@@ -848,7 +989,7 @@ export default config;
|
|
|
848
989
|
`;
|
|
849
990
|
|
|
850
991
|
// signingConfigs 블록을 buildTypes 앞에 삽입
|
|
851
|
-
content = content.replace(/(\s*buildTypes\s*\{)/,
|
|
992
|
+
content = content.replace(/(\s*buildTypes\s*\{)/, (match) => `\n${signingBlock}${match}`);
|
|
852
993
|
|
|
853
994
|
// buildTypes.release에 signingConfig 추가
|
|
854
995
|
content = content.replace(
|
|
@@ -874,11 +1015,15 @@ export default config;
|
|
|
874
1015
|
|
|
875
1016
|
const androidPath = pathx.posixResolve(this._capPath, "android");
|
|
876
1017
|
const isWindows = process.platform === "win32";
|
|
877
|
-
const gradlew = isWindows
|
|
878
|
-
? pathx.posixResolve(androidPath, "gradlew.bat")
|
|
879
|
-
: pathx.posixResolve(androidPath, "gradlew");
|
|
880
1018
|
|
|
881
|
-
|
|
1019
|
+
if (isWindows) {
|
|
1020
|
+
Capacitor._logger.debug(`Gradle 실행: cmd /c gradlew.bat ${gradleTask}`);
|
|
1021
|
+
await this._exec("cmd", ["/c", "gradlew.bat", gradleTask, "--no-daemon"], androidPath);
|
|
1022
|
+
} else {
|
|
1023
|
+
const gradlew = pathx.posixResolve(androidPath, "gradlew");
|
|
1024
|
+
Capacitor._logger.debug(`Gradle 실행: ${gradlew} ${gradleTask}`);
|
|
1025
|
+
await this._exec(gradlew, [gradleTask, "--no-daemon"], androidPath);
|
|
1026
|
+
}
|
|
882
1027
|
}
|
|
883
1028
|
|
|
884
1029
|
/**
|
|
@@ -899,11 +1044,13 @@ export default config;
|
|
|
899
1044
|
);
|
|
900
1045
|
|
|
901
1046
|
// 빌드 산출물 찾기
|
|
1047
|
+
Capacitor._logger.debug(`빌드 산출물 탐색: ${androidBuildPath}`);
|
|
902
1048
|
const candidates = await fsx.glob(pathx.posixResolve(androidBuildPath, `app-*.${ext}`));
|
|
903
1049
|
if (candidates.length === 0) {
|
|
904
1050
|
throw new Error(`빌드 산출물을 찾을 수 없습니다: ${androidBuildPath}`);
|
|
905
1051
|
}
|
|
906
1052
|
const builtFile = candidates[0];
|
|
1053
|
+
Capacitor._logger.debug(`빌드 산출물: ${builtFile}`);
|
|
907
1054
|
const isUnsigned = builtFile.includes("unsigned");
|
|
908
1055
|
|
|
909
1056
|
// 출력 디렉토리 생성
|
package/src/commands/build.ts
CHANGED
|
@@ -4,17 +4,10 @@ import {
|
|
|
4
4
|
} from "../orchestrators/BuildOrchestrator";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* BuildOrchestrator를 통해 프로덕션 빌드를 실행한다.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - Clean dist folder (clean build)
|
|
12
|
-
* - `node`/`browser`/`neutral` target: esbuild JS build + dts generation (with type check)
|
|
13
|
-
* - `client` target: Vite production build + typecheck (dts not needed)
|
|
14
|
-
* - Set `process.exitCode = 1` if any step fails
|
|
15
|
-
*
|
|
16
|
-
* @param options - build execution options
|
|
17
|
-
* @returns resolves on completion
|
|
9
|
+
* @param options - 빌드 실행 옵션
|
|
10
|
+
* @returns 완료 시 resolve
|
|
18
11
|
*/
|
|
19
12
|
export async function runBuild(options: BuildOrchestratorOptions): Promise<void> {
|
|
20
13
|
const orchestrator = new BuildOrchestrator(options);
|
package/src/commands/check.ts
CHANGED
|
@@ -34,7 +34,7 @@ async function spawnVitest(targets: string[]): Promise<CheckResult> {
|
|
|
34
34
|
const args = ["vitest", ...targets, "--run"];
|
|
35
35
|
logger.debug("vitest 실행", { args });
|
|
36
36
|
logger.start("테스트 실행 중...");
|
|
37
|
-
const result = await cpx.
|
|
37
|
+
const result = await cpx.spawn("pnpm", args, { cwd: process.cwd(), reject: false });
|
|
38
38
|
const output = result.stdout + result.stderr;
|
|
39
39
|
const code = result.exitCode;
|
|
40
40
|
|
|
@@ -188,7 +188,7 @@ export async function runCheck(options: CheckOptions): Promise<void> {
|
|
|
188
188
|
const results = await Promise.allSettled(tasks);
|
|
189
189
|
logger.success("체크 실행 완료");
|
|
190
190
|
|
|
191
|
-
// 결과 수집 (
|
|
191
|
+
// 결과 수집 (executeTypecheck 배열 평탄화)
|
|
192
192
|
const checkResults: CheckResult[] = results.flatMap((r) => {
|
|
193
193
|
if (r.status === "fulfilled") {
|
|
194
194
|
const value = r.value;
|
|
@@ -211,7 +211,7 @@ export async function runCheck(options: CheckOptions): Promise<void> {
|
|
|
211
211
|
process.stdout.write(formatSection(result));
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
//
|
|
214
|
+
// 요약
|
|
215
215
|
const failed = checkResults.filter((r) => !r.success);
|
|
216
216
|
const totalErrors = checkResults.reduce((sum, r) => sum + r.errorCount, 0);
|
|
217
217
|
const totalWarnings = checkResults.reduce((sum, r) => sum + r.warningCount, 0);
|
package/src/commands/dev.ts
CHANGED
|
@@ -4,16 +4,10 @@ import {
|
|
|
4
4
|
} from "../orchestrators/DevWatchOrchestrator";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* DevWatchOrchestrator를 통해 서버 패키지를 개발 모드로 실행한다.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - `client` target: recognized but skipped (BuildEngine not yet implemented)
|
|
12
|
-
* - Library packages excluded from dev mode
|
|
13
|
-
* - Terminate with SIGINT/SIGTERM signals
|
|
14
|
-
*
|
|
15
|
-
* @param options - dev execution options (targets, options)
|
|
16
|
-
* @returns resolves on termination signal
|
|
9
|
+
* @param options - 개발 모드 실행 옵션 (targets, options)
|
|
10
|
+
* @returns 종료 시그널 수신 시 resolve
|
|
17
11
|
*/
|
|
18
12
|
export async function runDev(options: Omit<DevWatchOrchestratorOptions, "mode">): Promise<void> {
|
|
19
13
|
const orchestrator = new DevWatchOrchestrator({ mode: "dev", ...options });
|
package/src/commands/device.ts
CHANGED
|
@@ -14,10 +14,10 @@ export interface DeviceOptions {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* 네이티브 앱을 디바이스/데스크톱에서 실행한다.
|
|
18
18
|
*
|
|
19
|
-
* - Electron
|
|
20
|
-
* -
|
|
19
|
+
* - Electron 설정이 Capacitor보다 우선한다.
|
|
20
|
+
* - --url이 제공되지 않으면 sd.config.ts의 서버 포트로 자동 생성한다.
|
|
21
21
|
*/
|
|
22
22
|
export async function runDevice(options: DeviceOptions): Promise<void> {
|
|
23
23
|
const cwd = process.cwd();
|
|
@@ -34,7 +34,7 @@ export async function runDevice(options: DeviceOptions): Promise<void> {
|
|
|
34
34
|
const clientConfig = pkgConfig;
|
|
35
35
|
const pkgDir = pathx.posixResolve(cwd, "packages", options.package);
|
|
36
36
|
|
|
37
|
-
//
|
|
37
|
+
// 서버 URL 결정
|
|
38
38
|
let serverUrl = options.url;
|
|
39
39
|
if (serverUrl == null) {
|
|
40
40
|
if (typeof clientConfig.server === "number") {
|
|
@@ -46,7 +46,7 @@ export async function runDevice(options: DeviceOptions): Promise<void> {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
// Electron
|
|
49
|
+
// Electron이 Capacitor보다 우선
|
|
50
50
|
if (clientConfig.electron != null) {
|
|
51
51
|
logger.start(`${options.package} (electron) 실행 중...`);
|
|
52
52
|
const electron = await Electron.create(pkgDir, clientConfig.electron, clientConfig.exclude);
|
package/src/commands/publish.ts
CHANGED
|
@@ -144,7 +144,7 @@ async function ensureSshAuth(
|
|
|
144
144
|
const privateKeyData = fs.readFileSync(keyPath);
|
|
145
145
|
const publicKey = fs.readFileSync(pubKeyPath, "utf-8").trim();
|
|
146
146
|
|
|
147
|
-
//
|
|
147
|
+
// 개인키 파싱 시도 (암호화 또는 형식 오류 시 Error 반환)
|
|
148
148
|
const parsed = utils.parseKey(privateKeyData);
|
|
149
149
|
const isKeyEncrypted = parsed instanceof Error;
|
|
150
150
|
const sshAgent = process.env["SSH_AUTH_SOCK"];
|
|
@@ -352,7 +352,7 @@ async function publishPackage(
|
|
|
352
352
|
logger.debug(`[${pkgName}] pnpm ${args.join(" ")}`);
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
await cpx.
|
|
355
|
+
await cpx.spawn("pnpm", args, { cwd: pkgPath });
|
|
356
356
|
} else if (publishConfig.type === "local-directory") {
|
|
357
357
|
// 로컬 디렉토리에 복사
|
|
358
358
|
const targetPath = replaceEnvVariables(publishConfig.path, version, projectPath);
|
|
@@ -466,7 +466,7 @@ async function computePublishLevels(
|
|
|
466
466
|
* 2. 버전 업그레이드 (package.json + 템플릿)
|
|
467
467
|
* 3. 빌드
|
|
468
468
|
* 4. Git commit/tag/push (변경된 파일만 명시적으로 스테이징)
|
|
469
|
-
* 5.
|
|
469
|
+
* 5. 패키지 배포 (npm/로컬 디렉토리/스토리지)
|
|
470
470
|
* 6. postPublish (실패해도 계속 진행)
|
|
471
471
|
*/
|
|
472
472
|
export async function runPublish(options: PublishOptions): Promise<void> {
|
|
@@ -559,18 +559,18 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
559
559
|
if (publishPackages.some((p) => p.config.type === "npm")) {
|
|
560
560
|
logger.debug("npm 인증 검증 중...");
|
|
561
561
|
try {
|
|
562
|
-
const { stdout: whoami } = await cpx.
|
|
562
|
+
const { stdout: whoami } = await cpx.spawn("npm", ["whoami"]);
|
|
563
563
|
if (whoami.trim() === "") {
|
|
564
564
|
throw new Error("npm 로그인 정보를 찾을 수 없습니다.");
|
|
565
565
|
}
|
|
566
566
|
logger.debug(`npm 로그인 확인됨: ${whoami.trim()}`);
|
|
567
|
-
} catch
|
|
568
|
-
logger.error(
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
"
|
|
572
|
-
" npm config set //registry.npmjs.org/:_authToken <token>",
|
|
573
|
-
)
|
|
567
|
+
} catch {
|
|
568
|
+
logger.error(
|
|
569
|
+
"npm 인증 실패. 로그인 상태를 확인해주세요.\n" +
|
|
570
|
+
" npm whoami # 현재 로그인 확인\n" +
|
|
571
|
+
" npm login # 로그인\n" +
|
|
572
|
+
" npm config set //registry.npmjs.org/:_authToken <token> # 토큰 직접 설정",
|
|
573
|
+
);
|
|
574
574
|
process.exitCode = 1;
|
|
575
575
|
return;
|
|
576
576
|
}
|
|
@@ -589,19 +589,23 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
589
589
|
if (!noBuild && hasGit) {
|
|
590
590
|
logger.debug("git 커밋 상태 확인 중...");
|
|
591
591
|
try {
|
|
592
|
-
const { stdout: diff } = await cpx.
|
|
593
|
-
const { stdout: stagedDiff } = await cpx.
|
|
592
|
+
const { stdout: diff } = await cpx.spawn("git", ["diff", "--name-only"]);
|
|
593
|
+
const { stdout: stagedDiff } = await cpx.spawn("git", ["diff", "--cached", "--name-only"]);
|
|
594
594
|
|
|
595
595
|
if (diff.trim() !== "" || stagedDiff.trim() !== "") {
|
|
596
596
|
logger.info("커밋되지 않은 변경사항 감지. claude로 자동 커밋 시도 중...");
|
|
597
597
|
try {
|
|
598
|
-
await cpx.
|
|
599
|
-
"
|
|
600
|
-
"/sd-commit
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
598
|
+
await cpx.spawn(
|
|
599
|
+
"claude",
|
|
600
|
+
["-p", "/sd-commit", "--dangerously-skip-permissions", "--model", "haiku"],
|
|
601
|
+
{
|
|
602
|
+
stdio: "inherit",
|
|
603
|
+
env: {
|
|
604
|
+
...process.env,
|
|
605
|
+
MCP_CONNECTION_NONBLOCKING: "true",
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
);
|
|
605
609
|
} catch (e) {
|
|
606
610
|
throw new Error(
|
|
607
611
|
"자동 커밋에 실패했습니다. 수동으로 커밋 후 다시 시도해주세요.\n" +
|
|
@@ -683,11 +687,11 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
683
687
|
} else {
|
|
684
688
|
logger.debug("Git commit/tag/push...");
|
|
685
689
|
try {
|
|
686
|
-
await cpx.
|
|
687
|
-
await cpx.
|
|
688
|
-
await cpx.
|
|
689
|
-
await cpx.
|
|
690
|
-
await cpx.
|
|
690
|
+
await cpx.spawn("git", ["add", ..._changedFiles]);
|
|
691
|
+
await cpx.spawn("git", ["commit", "-m", `v${version}`]);
|
|
692
|
+
await cpx.spawn("git", ["tag", "-a", `v${version}`, "-m", `v${version}`]);
|
|
693
|
+
await cpx.spawn("git", ["push"]);
|
|
694
|
+
await cpx.spawn("git", ["push", "--tags"]);
|
|
691
695
|
logger.debug("Git 작업 완료");
|
|
692
696
|
} catch (err) {
|
|
693
697
|
logger.error(
|
|
@@ -806,7 +810,7 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
806
810
|
logger.info(`[DRY-RUN] 실행 예정: ${cmd} ${args.join(" ")}`);
|
|
807
811
|
} else {
|
|
808
812
|
logger.debug(`실행 중: ${cmd} ${args.join(" ")}`);
|
|
809
|
-
await cpx.
|
|
813
|
+
await cpx.spawn(cmd, args, { cwd });
|
|
810
814
|
}
|
|
811
815
|
} catch (err) {
|
|
812
816
|
// postPublish 실패 시 경고만 출력 (배포 롤백 불가)
|