@mcesystems/adb-kit 1.0.69 → 1.0.71

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.
@@ -1,358 +1,358 @@
1
- #!/usr/bin/env tsx
2
- /**
3
- * Export ADB (Android Debug Bridge) resources to a specified path
4
- *
5
- * This script downloads ADB platform tools from Google and exports them
6
- * to a target directory. The resources can then be used by applications
7
- * that depend on adb-kit.
8
- *
9
- * Usage:
10
- * npx tsx export-resources.ts <target-path>
11
- *
12
- * Example:
13
- * npx tsx export-resources.ts /path/to/my-app/resources/adb-kit
14
- *
15
- * Platform support:
16
- * - macOS: Downloads darwin platform-tools from Google
17
- * - Windows: Downloads windows platform-tools from Google
18
- * - Linux: Downloads linux platform-tools from Google
19
- */
20
-
21
- import { exec } from "node:child_process";
22
- import {
23
- chmodSync,
24
- copyFileSync,
25
- createWriteStream,
26
- existsSync,
27
- mkdirSync,
28
- writeFileSync,
29
- } from "node:fs";
30
- import path from "node:path";
31
- import { promisify } from "node:util";
32
-
33
- import {
34
- logDataObject,
35
- logDetail,
36
- logError,
37
- logErrorObject,
38
- logInfo,
39
- logNamespace,
40
- logWarning,
41
- setLogLevel,
42
- } from "@mcesystems/tool-debug-g4";
43
-
44
- const execAsync = promisify(exec);
45
-
46
- // ============================================================================
47
- // Configuration
48
- // ============================================================================
49
-
50
- // ADB download URLs from Google
51
- const ADB_URLS: Record<string, string> = {
52
- windows: "https://dl.google.com/android/repository/platform-tools-latest-windows.zip",
53
- darwin: "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip",
54
- linux: "https://dl.google.com/android/repository/platform-tools-latest-linux.zip",
55
- };
56
-
57
- // Files to extract from platform-tools per platform
58
- const PLATFORM_FILES: Record<string, string[]> = {
59
- windows: ["adb.exe", "AdbWinApi.dll", "AdbWinUsbApi.dll"],
60
- darwin: ["adb"],
61
- linux: ["adb"],
62
- };
63
-
64
- // ============================================================================
65
- // Utility Functions
66
- // ============================================================================
67
-
68
- function printUsage(): void {
69
- logInfo(`
70
- Usage: npx tsx export-resources.ts <target-path>
71
-
72
- Arguments:
73
- target-path Directory where resources will be exported
74
-
75
- Examples:
76
- npx tsx export-resources.ts ./my-app/resources/adb-kit
77
- npx tsx export-resources.ts /absolute/path/to/resources
78
-
79
- The script will create the following structure:
80
- <target-path>/
81
- bin/
82
- darwin/ (macOS ADB binary)
83
- windows/ (Windows ADB binaries and DLLs)
84
- linux/ (Linux ADB binary)
85
- licenses/
86
- APACHE-2.0.txt
87
- `);
88
- }
89
-
90
- async function downloadFile(url: string, destPath: string): Promise<void> {
91
- logInfo(`Downloading ${url}...`);
92
-
93
- let response: Response;
94
- try {
95
- response = await fetch(url);
96
- } catch {
97
- // Fallback to https module if fetch is not available
98
- const https = await import("node:https");
99
- const http = await import("node:http");
100
- const urlObj = new URL(url);
101
- const client = urlObj.protocol === "https:" ? https : http;
102
-
103
- return new Promise((resolve, reject) => {
104
- const fileStream = createWriteStream(destPath);
105
- const request = client.get(url, (res) => {
106
- if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
107
- // Handle redirect
108
- fileStream.close();
109
- return downloadFile(res.headers.location, destPath).then(resolve).catch(reject);
110
- }
111
- if (res.statusCode && res.statusCode !== 200) {
112
- fileStream.close();
113
- reject(new Error(`Failed to download ${url}: ${res.statusCode} ${res.statusMessage}`));
114
- return;
115
- }
116
- res.pipe(fileStream);
117
- fileStream.on("finish", () => {
118
- fileStream.close();
119
- resolve();
120
- });
121
- });
122
- request.on("error", (err) => {
123
- fileStream.close();
124
- reject(err);
125
- });
126
- });
127
- }
128
-
129
- if (!response.ok) {
130
- throw new Error(`Failed to download ${url}: ${response.statusText}`);
131
- }
132
-
133
- const fileStream = createWriteStream(destPath);
134
- const reader = response.body?.getReader();
135
- if (!reader) {
136
- throw new Error(`Failed to get response body for ${url}`);
137
- }
138
-
139
- try {
140
- while (true) {
141
- const { done, value } = await reader.read();
142
- if (done) break;
143
- fileStream.write(value);
144
- }
145
- fileStream.end();
146
- await new Promise<void>((resolve, reject) => {
147
- fileStream.on("finish", resolve);
148
- fileStream.on("error", reject);
149
- });
150
- logInfo(`✓ Downloaded to ${destPath}`);
151
- } finally {
152
- reader.releaseLock();
153
- }
154
- }
155
-
156
- async function extractZip(zipPath: string, extractDir: string): Promise<void> {
157
- logInfo(`Extracting ${zipPath}...`);
158
-
159
- if (process.platform === "win32") {
160
- // On Windows, use PowerShell Expand-Archive
161
- try {
162
- const escapedZipPath = zipPath.replace(/'/g, "''");
163
- const escapedExtractDir = extractDir.replace(/'/g, "''");
164
- await execAsync(
165
- `powershell -Command "Expand-Archive -Path '${escapedZipPath}' -DestinationPath '${escapedExtractDir}' -Force"`
166
- );
167
- } catch (error) {
168
- const err = error as { message?: string };
169
- throw new Error(
170
- `Failed to extract zip file. Please ensure PowerShell is available. Error: ${err.message || error}`
171
- );
172
- }
173
- } else {
174
- // On Unix-like systems, use unzip command
175
- try {
176
- await execAsync(`unzip -o "${zipPath}" -d "${extractDir}"`);
177
- } catch (error) {
178
- const err = error as { message?: string };
179
- throw new Error(
180
- `Failed to extract zip file. Please ensure 'unzip' is installed. Error: ${err.message || error}`
181
- );
182
- }
183
- }
184
- logDetail(`✓ Extracted to ${extractDir}`);
185
- }
186
-
187
- async function copyFiles(sourceDir: string, targetDir: string, files: string[]): Promise<void> {
188
- mkdirSync(targetDir, { recursive: true });
189
-
190
- for (const file of files) {
191
- const sourcePath = path.join(sourceDir, "platform-tools", file);
192
- const targetPath = path.join(targetDir, file);
193
-
194
- if (!existsSync(sourcePath)) {
195
- logWarning(`Warning: ${file} not found in ${sourcePath}`);
196
- continue;
197
- }
198
-
199
- copyFileSync(sourcePath, targetPath);
200
- logDetail(`✓ Copied ${file}`);
201
- }
202
- }
203
-
204
- function makeExecutable(filePath: string): void {
205
- if (process.platform !== "win32") {
206
- chmodSync(filePath, 0o755);
207
- }
208
- }
209
-
210
- async function cleanupDir(dirPath: string): Promise<void> {
211
- try {
212
- const { rimraf } = await import("rimraf");
213
- await rimraf(dirPath);
214
- } catch {
215
- // Ignore cleanup errors
216
- }
217
- }
218
-
219
- // ============================================================================
220
- // Export Functions
221
- // ============================================================================
222
-
223
- type PlatformType = "windows" | "darwin" | "linux";
224
-
225
- async function exportPlatformResources(platform: PlatformType, targetDir: string): Promise<void> {
226
- logDataObject(`Exporting ${platform} Resources`, { Target: targetDir });
227
-
228
- const binDir = path.join(targetDir, "bin", platform);
229
- const files = PLATFORM_FILES[platform];
230
- const url = ADB_URLS[platform];
231
-
232
- // Create temp directory for extraction
233
- const tempDir = path.join(targetDir, ".temp", platform);
234
- mkdirSync(tempDir, { recursive: true });
235
- const zipPath = path.join(tempDir, `platform-tools-${platform}.zip`);
236
-
237
- try {
238
- // Download
239
- await downloadFile(url, zipPath);
240
-
241
- // Extract
242
- await extractZip(zipPath, tempDir);
243
-
244
- // Copy files to target
245
- await copyFiles(tempDir, binDir, files);
246
-
247
- // Make executable on Unix
248
- if (platform !== "windows") {
249
- for (const file of files) {
250
- makeExecutable(path.join(binDir, file));
251
- }
252
- }
253
-
254
- logDetail(`✓ ${platform} resources exported to: ${binDir}`);
255
- } finally {
256
- // Clean up temp directory
257
- await cleanupDir(tempDir);
258
- }
259
- }
260
-
261
- // ============================================================================
262
- // License
263
- // ============================================================================
264
-
265
- function createLicenseFile(targetDir: string): void {
266
- const licensesDir = path.join(targetDir, "licenses");
267
- mkdirSync(licensesDir, { recursive: true });
268
-
269
- const apacheLicense = `Apache License
270
- Version 2.0, January 2004
271
- http://www.apache.org/licenses/
272
-
273
- Android Debug Bridge (ADB) is licensed under the Apache License 2.0.
274
-
275
- For full license text, see:
276
- https://www.apache.org/licenses/LICENSE-2.0
277
-
278
- These binaries are downloaded from Google's official Android SDK repository:
279
- https://developer.android.com/studio/releases/platform-tools
280
-
281
- Source code is available at:
282
- https://android.googlesource.com/platform/packages/modules/adb/
283
- `;
284
-
285
- const licensePath = path.join(licensesDir, "APACHE-2.0.txt");
286
- writeFileSync(licensePath, apacheLicense);
287
- logInfo(`✓ Created license file: ${licensePath}`);
288
- }
289
-
290
- // ============================================================================
291
- // Main
292
- // ============================================================================
293
-
294
- async function main(): Promise<void> {
295
- const args = process.argv.slice(2);
296
-
297
- logNamespace("adb-resources");
298
-
299
- if (args.includes("-v") || args.includes("--verbose")) {
300
- setLogLevel("debug");
301
- } else {
302
- setLogLevel("info");
303
- }
304
-
305
- if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
306
- printUsage();
307
- process.exit(args.length === 0 ? 1 : 0);
308
- }
309
-
310
- const targetPath = path.resolve(args[0]);
311
-
312
- // Check for optional platform argument
313
- let platforms: PlatformType[];
314
- if (args.includes("--all")) {
315
- platforms = ["windows", "darwin", "linux"];
316
- } else if (args.includes("--platform")) {
317
- const platformIdx = args.indexOf("--platform");
318
- const platformArg = args[platformIdx + 1] as PlatformType;
319
- if (!["windows", "darwin", "linux"].includes(platformArg)) {
320
- logError(`Invalid platform: ${platformArg}`);
321
- logError("Valid platforms: windows, darwin, linux");
322
- process.exit(1);
323
- }
324
- platforms = [platformArg];
325
- } else {
326
- // Default to current platform
327
- const currentPlatform = process.platform === "win32" ? "windows" : process.platform;
328
- if (!["windows", "darwin", "linux"].includes(currentPlatform)) {
329
- logError(`Unsupported platform: ${currentPlatform}`);
330
- process.exit(1);
331
- }
332
- platforms = [currentPlatform as PlatformType];
333
- }
334
-
335
- logDataObject("ADB Resources Export", { Target: targetPath, Platforms: platforms.join(", ") });
336
-
337
- // Create target directory
338
- mkdirSync(targetPath, { recursive: true });
339
-
340
- // Export resources for each platform
341
- for (const platform of platforms) {
342
- await exportPlatformResources(platform, targetPath);
343
- }
344
-
345
- // Create license file
346
- logInfo("");
347
- createLicenseFile(targetPath);
348
-
349
- // Clean up temp directory
350
- await cleanupDir(path.join(targetPath, ".temp"));
351
-
352
- logDataObject("Export Complete", { ResourcesExportedTo: targetPath });
353
- }
354
-
355
- main().catch((error) => {
356
- logErrorObject(error, "Export failed");
357
- process.exit(1);
358
- });
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Export ADB (Android Debug Bridge) resources to a specified path
4
+ *
5
+ * This script downloads ADB platform tools from Google and exports them
6
+ * to a target directory. The resources can then be used by applications
7
+ * that depend on adb-kit.
8
+ *
9
+ * Usage:
10
+ * npx tsx export-resources.ts <target-path>
11
+ *
12
+ * Example:
13
+ * npx tsx export-resources.ts /path/to/my-app/resources/adb-kit
14
+ *
15
+ * Platform support:
16
+ * - macOS: Downloads darwin platform-tools from Google
17
+ * - Windows: Downloads windows platform-tools from Google
18
+ * - Linux: Downloads linux platform-tools from Google
19
+ */
20
+
21
+ import { exec } from "node:child_process";
22
+ import {
23
+ chmodSync,
24
+ copyFileSync,
25
+ createWriteStream,
26
+ existsSync,
27
+ mkdirSync,
28
+ writeFileSync,
29
+ } from "node:fs";
30
+ import path from "node:path";
31
+ import { promisify } from "node:util";
32
+
33
+ import {
34
+ logDataObject,
35
+ logDetail,
36
+ logError,
37
+ logErrorObject,
38
+ logInfo,
39
+ logNamespace,
40
+ logWarning,
41
+ setLogLevel,
42
+ } from "@mcesystems/tool-debug-g4";
43
+
44
+ const execAsync = promisify(exec);
45
+
46
+ // ============================================================================
47
+ // Configuration
48
+ // ============================================================================
49
+
50
+ // ADB download URLs from Google
51
+ const ADB_URLS: Record<string, string> = {
52
+ windows: "https://dl.google.com/android/repository/platform-tools-latest-windows.zip",
53
+ darwin: "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip",
54
+ linux: "https://dl.google.com/android/repository/platform-tools-latest-linux.zip",
55
+ };
56
+
57
+ // Files to extract from platform-tools per platform
58
+ const PLATFORM_FILES: Record<string, string[]> = {
59
+ windows: ["adb.exe", "AdbWinApi.dll", "AdbWinUsbApi.dll"],
60
+ darwin: ["adb"],
61
+ linux: ["adb"],
62
+ };
63
+
64
+ // ============================================================================
65
+ // Utility Functions
66
+ // ============================================================================
67
+
68
+ function printUsage(): void {
69
+ logInfo(`
70
+ Usage: npx tsx export-resources.ts <target-path>
71
+
72
+ Arguments:
73
+ target-path Directory where resources will be exported
74
+
75
+ Examples:
76
+ npx tsx export-resources.ts ./my-app/resources/adb-kit
77
+ npx tsx export-resources.ts /absolute/path/to/resources
78
+
79
+ The script will create the following structure:
80
+ <target-path>/
81
+ bin/
82
+ darwin/ (macOS ADB binary)
83
+ windows/ (Windows ADB binaries and DLLs)
84
+ linux/ (Linux ADB binary)
85
+ licenses/
86
+ APACHE-2.0.txt
87
+ `);
88
+ }
89
+
90
+ async function downloadFile(url: string, destPath: string): Promise<void> {
91
+ logInfo(`Downloading ${url}...`);
92
+
93
+ let response: Response;
94
+ try {
95
+ response = await fetch(url);
96
+ } catch {
97
+ // Fallback to https module if fetch is not available
98
+ const https = await import("node:https");
99
+ const http = await import("node:http");
100
+ const urlObj = new URL(url);
101
+ const client = urlObj.protocol === "https:" ? https : http;
102
+
103
+ return new Promise((resolve, reject) => {
104
+ const fileStream = createWriteStream(destPath);
105
+ const request = client.get(url, (res) => {
106
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
107
+ // Handle redirect
108
+ fileStream.close();
109
+ return downloadFile(res.headers.location, destPath).then(resolve).catch(reject);
110
+ }
111
+ if (res.statusCode && res.statusCode !== 200) {
112
+ fileStream.close();
113
+ reject(new Error(`Failed to download ${url}: ${res.statusCode} ${res.statusMessage}`));
114
+ return;
115
+ }
116
+ res.pipe(fileStream);
117
+ fileStream.on("finish", () => {
118
+ fileStream.close();
119
+ resolve();
120
+ });
121
+ });
122
+ request.on("error", (err) => {
123
+ fileStream.close();
124
+ reject(err);
125
+ });
126
+ });
127
+ }
128
+
129
+ if (!response.ok) {
130
+ throw new Error(`Failed to download ${url}: ${response.statusText}`);
131
+ }
132
+
133
+ const fileStream = createWriteStream(destPath);
134
+ const reader = response.body?.getReader();
135
+ if (!reader) {
136
+ throw new Error(`Failed to get response body for ${url}`);
137
+ }
138
+
139
+ try {
140
+ while (true) {
141
+ const { done, value } = await reader.read();
142
+ if (done) break;
143
+ fileStream.write(value);
144
+ }
145
+ fileStream.end();
146
+ await new Promise<void>((resolve, reject) => {
147
+ fileStream.on("finish", resolve);
148
+ fileStream.on("error", reject);
149
+ });
150
+ logInfo(`✓ Downloaded to ${destPath}`);
151
+ } finally {
152
+ reader.releaseLock();
153
+ }
154
+ }
155
+
156
+ async function extractZip(zipPath: string, extractDir: string): Promise<void> {
157
+ logInfo(`Extracting ${zipPath}...`);
158
+
159
+ if (process.platform === "win32") {
160
+ // On Windows, use PowerShell Expand-Archive
161
+ try {
162
+ const escapedZipPath = zipPath.replace(/'/g, "''");
163
+ const escapedExtractDir = extractDir.replace(/'/g, "''");
164
+ await execAsync(
165
+ `powershell -Command "Expand-Archive -Path '${escapedZipPath}' -DestinationPath '${escapedExtractDir}' -Force"`
166
+ );
167
+ } catch (error) {
168
+ const err = error as { message?: string };
169
+ throw new Error(
170
+ `Failed to extract zip file. Please ensure PowerShell is available. Error: ${err.message || error}`
171
+ );
172
+ }
173
+ } else {
174
+ // On Unix-like systems, use unzip command
175
+ try {
176
+ await execAsync(`unzip -o "${zipPath}" -d "${extractDir}"`);
177
+ } catch (error) {
178
+ const err = error as { message?: string };
179
+ throw new Error(
180
+ `Failed to extract zip file. Please ensure 'unzip' is installed. Error: ${err.message || error}`
181
+ );
182
+ }
183
+ }
184
+ logDetail(`✓ Extracted to ${extractDir}`);
185
+ }
186
+
187
+ async function copyFiles(sourceDir: string, targetDir: string, files: string[]): Promise<void> {
188
+ mkdirSync(targetDir, { recursive: true });
189
+
190
+ for (const file of files) {
191
+ const sourcePath = path.join(sourceDir, "platform-tools", file);
192
+ const targetPath = path.join(targetDir, file);
193
+
194
+ if (!existsSync(sourcePath)) {
195
+ logWarning(`Warning: ${file} not found in ${sourcePath}`);
196
+ continue;
197
+ }
198
+
199
+ copyFileSync(sourcePath, targetPath);
200
+ logDetail(`✓ Copied ${file}`);
201
+ }
202
+ }
203
+
204
+ function makeExecutable(filePath: string): void {
205
+ if (process.platform !== "win32") {
206
+ chmodSync(filePath, 0o755);
207
+ }
208
+ }
209
+
210
+ async function cleanupDir(dirPath: string): Promise<void> {
211
+ try {
212
+ const { rimraf } = await import("rimraf");
213
+ await rimraf(dirPath);
214
+ } catch {
215
+ // Ignore cleanup errors
216
+ }
217
+ }
218
+
219
+ // ============================================================================
220
+ // Export Functions
221
+ // ============================================================================
222
+
223
+ type PlatformType = "windows" | "darwin" | "linux";
224
+
225
+ async function exportPlatformResources(platform: PlatformType, targetDir: string): Promise<void> {
226
+ logDataObject(`Exporting ${platform} Resources`, { Target: targetDir });
227
+
228
+ const binDir = path.join(targetDir, "bin", platform);
229
+ const files = PLATFORM_FILES[platform];
230
+ const url = ADB_URLS[platform];
231
+
232
+ // Create temp directory for extraction
233
+ const tempDir = path.join(targetDir, ".temp", platform);
234
+ mkdirSync(tempDir, { recursive: true });
235
+ const zipPath = path.join(tempDir, `platform-tools-${platform}.zip`);
236
+
237
+ try {
238
+ // Download
239
+ await downloadFile(url, zipPath);
240
+
241
+ // Extract
242
+ await extractZip(zipPath, tempDir);
243
+
244
+ // Copy files to target
245
+ await copyFiles(tempDir, binDir, files);
246
+
247
+ // Make executable on Unix
248
+ if (platform !== "windows") {
249
+ for (const file of files) {
250
+ makeExecutable(path.join(binDir, file));
251
+ }
252
+ }
253
+
254
+ logDetail(`✓ ${platform} resources exported to: ${binDir}`);
255
+ } finally {
256
+ // Clean up temp directory
257
+ await cleanupDir(tempDir);
258
+ }
259
+ }
260
+
261
+ // ============================================================================
262
+ // License
263
+ // ============================================================================
264
+
265
+ function createLicenseFile(targetDir: string): void {
266
+ const licensesDir = path.join(targetDir, "licenses");
267
+ mkdirSync(licensesDir, { recursive: true });
268
+
269
+ const apacheLicense = `Apache License
270
+ Version 2.0, January 2004
271
+ http://www.apache.org/licenses/
272
+
273
+ Android Debug Bridge (ADB) is licensed under the Apache License 2.0.
274
+
275
+ For full license text, see:
276
+ https://www.apache.org/licenses/LICENSE-2.0
277
+
278
+ These binaries are downloaded from Google's official Android SDK repository:
279
+ https://developer.android.com/studio/releases/platform-tools
280
+
281
+ Source code is available at:
282
+ https://android.googlesource.com/platform/packages/modules/adb/
283
+ `;
284
+
285
+ const licensePath = path.join(licensesDir, "APACHE-2.0.txt");
286
+ writeFileSync(licensePath, apacheLicense);
287
+ logInfo(`✓ Created license file: ${licensePath}`);
288
+ }
289
+
290
+ // ============================================================================
291
+ // Main
292
+ // ============================================================================
293
+
294
+ async function main(): Promise<void> {
295
+ const args = process.argv.slice(2);
296
+
297
+ logNamespace("adb-resources");
298
+
299
+ if (args.includes("-v") || args.includes("--verbose")) {
300
+ setLogLevel("debug");
301
+ } else {
302
+ setLogLevel("info");
303
+ }
304
+
305
+ if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
306
+ printUsage();
307
+ process.exit(args.length === 0 ? 1 : 0);
308
+ }
309
+
310
+ const targetPath = path.resolve(args[0]);
311
+
312
+ // Check for optional platform argument
313
+ let platforms: PlatformType[];
314
+ if (args.includes("--all")) {
315
+ platforms = ["windows", "darwin", "linux"];
316
+ } else if (args.includes("--platform")) {
317
+ const platformIdx = args.indexOf("--platform");
318
+ const platformArg = args[platformIdx + 1] as PlatformType;
319
+ if (!["windows", "darwin", "linux"].includes(platformArg)) {
320
+ logError(`Invalid platform: ${platformArg}`);
321
+ logError("Valid platforms: windows, darwin, linux");
322
+ process.exit(1);
323
+ }
324
+ platforms = [platformArg];
325
+ } else {
326
+ // Default to current platform
327
+ const currentPlatform = process.platform === "win32" ? "windows" : process.platform;
328
+ if (!["windows", "darwin", "linux"].includes(currentPlatform)) {
329
+ logError(`Unsupported platform: ${currentPlatform}`);
330
+ process.exit(1);
331
+ }
332
+ platforms = [currentPlatform as PlatformType];
333
+ }
334
+
335
+ logDataObject("ADB Resources Export", { Target: targetPath, Platforms: platforms.join(", ") });
336
+
337
+ // Create target directory
338
+ mkdirSync(targetPath, { recursive: true });
339
+
340
+ // Export resources for each platform
341
+ for (const platform of platforms) {
342
+ await exportPlatformResources(platform, targetPath);
343
+ }
344
+
345
+ // Create license file
346
+ logInfo("");
347
+ createLicenseFile(targetPath);
348
+
349
+ // Clean up temp directory
350
+ await cleanupDir(path.join(targetPath, ".temp"));
351
+
352
+ logDataObject("Export Complete", { ResourcesExportedTo: targetPath });
353
+ }
354
+
355
+ main().catch((error) => {
356
+ logErrorObject(error, "Export failed");
357
+ process.exit(1);
358
+ });