@thelacanians/vue-native-cli 0.4.13 → 0.4.15

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/dist/cli.js CHANGED
@@ -3,29 +3,271 @@
3
3
  // src/cli.ts
4
4
  import { program } from "commander";
5
5
 
6
- // src/commands/create.ts
6
+ // src/commands/build.ts
7
7
  import { Command } from "commander";
8
+ import { spawn, execSync } from "child_process";
9
+ import { existsSync, readdirSync, mkdirSync, copyFileSync } from "fs";
10
+ import { join, basename } from "path";
11
+ import pc from "picocolors";
12
+ function findXcodeProject(iosDir) {
13
+ if (!existsSync(iosDir)) return null;
14
+ for (const ext of [".xcworkspace", ".xcodeproj"]) {
15
+ try {
16
+ const entries = readdirSync(iosDir);
17
+ const match = entries.find((e) => e.endsWith(ext));
18
+ if (match) {
19
+ return {
20
+ path: join(iosDir, match),
21
+ isWorkspace: ext === ".xcworkspace"
22
+ };
23
+ }
24
+ } catch {
25
+ }
26
+ }
27
+ return null;
28
+ }
29
+ function findReleaseApk(androidDir) {
30
+ const apkDir = join(androidDir, "app", "build", "outputs", "apk", "release");
31
+ if (existsSync(apkDir)) {
32
+ try {
33
+ const entries = readdirSync(apkDir);
34
+ const apk = entries.find((e) => e.endsWith(".apk") && !e.includes("androidTest"));
35
+ if (apk) {
36
+ return join(apkDir, apk);
37
+ }
38
+ } catch {
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ function findReleaseAab(androidDir) {
44
+ const aabDir = join(androidDir, "app", "build", "outputs", "bundle", "release");
45
+ if (existsSync(aabDir)) {
46
+ try {
47
+ const entries = readdirSync(aabDir);
48
+ const aab = entries.find((e) => e.endsWith(".aab"));
49
+ if (aab) {
50
+ return join(aabDir, aab);
51
+ }
52
+ } catch {
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+ function ensureOutputDir(outputPath) {
58
+ if (!existsSync(outputPath)) {
59
+ mkdirSync(outputPath, { recursive: true });
60
+ }
61
+ }
62
+ var buildCommand = new Command("build").description("Create a release build of the app").argument("<platform>", "platform to build for (ios, android)").option("--mode <mode>", "build mode", "release").option("--output <path>", "output directory for the build artifact", "./build").option("--scheme <scheme>", "Xcode scheme to build (iOS only)").option("--aab", "build Android App Bundle (.aab) instead of APK").action(async (platform, options) => {
63
+ if (platform !== "ios" && platform !== "android") {
64
+ console.error(pc.red('Platform must be "ios" or "android"'));
65
+ process.exit(1);
66
+ }
67
+ const cwd = process.cwd();
68
+ const outputDir = join(cwd, options.output);
69
+ console.log(pc.cyan(`
70
+ Vue Native \u2014 ${options.mode.charAt(0).toUpperCase() + options.mode.slice(1)} Build (${platform === "ios" ? "iOS" : "Android"})
71
+ `));
72
+ console.log(pc.white(" Building JS bundle for production..."));
73
+ try {
74
+ execSync("bun run vite build --mode production", { cwd, stdio: "inherit" });
75
+ console.log(pc.green(" \u2713 Bundle built\n"));
76
+ } catch {
77
+ console.error(pc.red(" \u2717 Bundle build failed"));
78
+ process.exit(1);
79
+ }
80
+ if (platform === "ios") {
81
+ buildIOS(cwd, outputDir, options);
82
+ } else {
83
+ buildAndroid(cwd, outputDir, options);
84
+ }
85
+ });
86
+ function buildIOS(cwd, outputDir, options) {
87
+ const iosDir = join(cwd, "ios");
88
+ const project = findXcodeProject(iosDir);
89
+ if (!project) {
90
+ console.log(pc.yellow(" No Xcode project found in ./ios/"));
91
+ console.log(pc.dim(" To add iOS support, create an Xcode project in the ios/ directory."));
92
+ console.log(pc.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
93
+ return;
94
+ }
95
+ const projectFlag = project.isWorkspace ? "-workspace" : "-project";
96
+ const scheme = options.scheme || project.path.split("/").pop()?.replace(/\.(xcworkspace|xcodeproj)$/, "") || "App";
97
+ const configuration = options.mode === "release" ? "Release" : "Debug";
98
+ const archivePath = join(outputDir, `${scheme}.xcarchive`);
99
+ ensureOutputDir(outputDir);
100
+ console.log(pc.white(` Archiving ${scheme} (${configuration})...`));
101
+ console.log(pc.dim(` Archive path: ${archivePath}`));
102
+ const xcodebuild = spawn(
103
+ "xcodebuild",
104
+ [
105
+ projectFlag,
106
+ project.path,
107
+ "-scheme",
108
+ scheme,
109
+ "-configuration",
110
+ configuration,
111
+ "-destination",
112
+ "generic/platform=iOS",
113
+ "-archivePath",
114
+ archivePath,
115
+ "archive"
116
+ ],
117
+ {
118
+ cwd,
119
+ stdio: "pipe",
120
+ env: { ...process.env, DEVELOPER_DIR: "/Applications/Xcode.app/Contents/Developer" }
121
+ }
122
+ );
123
+ const cleanup = () => {
124
+ if (xcodebuild && !xcodebuild.killed) {
125
+ xcodebuild.kill();
126
+ }
127
+ };
128
+ process.on("exit", cleanup);
129
+ process.on("SIGINT", cleanup);
130
+ process.on("SIGTERM", cleanup);
131
+ xcodebuild.stdout?.on("data", (data) => {
132
+ const text = data.toString().trim();
133
+ if (text.includes("Compiling") || text.includes("Linking") || text.includes("Signing")) {
134
+ console.log(pc.dim(` ${text.split("\n").pop()}`));
135
+ }
136
+ });
137
+ xcodebuild.stderr?.on("data", (data) => {
138
+ const text = data.toString().trim();
139
+ if (text.includes("error:")) {
140
+ console.log(pc.red(` ${text}`));
141
+ } else if (text.includes("warning:")) {
142
+ console.log(pc.yellow(` ${text}`));
143
+ }
144
+ });
145
+ xcodebuild.on("error", (err) => {
146
+ console.error(pc.red(` xcodebuild process error: ${err.message}`));
147
+ cleanup();
148
+ });
149
+ xcodebuild.on("close", (code) => {
150
+ if (code !== 0) {
151
+ console.error(pc.red(` \u2717 Archive failed (exit code ${code})`));
152
+ process.exit(1);
153
+ }
154
+ console.log(pc.green(" \u2713 Archive successful\n"));
155
+ if (existsSync(archivePath)) {
156
+ console.log(pc.green(` Archive: ${archivePath}`));
157
+ console.log(pc.dim(" To export an IPA, open the archive in Xcode Organizer or run:"));
158
+ console.log(pc.dim(` xcodebuild -exportArchive -archivePath "${archivePath}" -exportOptionsPlist ExportOptions.plist -exportPath "${outputDir}"
159
+ `));
160
+ } else {
161
+ console.log(pc.yellow(" Archive path not found. Check Xcode build settings.\n"));
162
+ }
163
+ });
164
+ }
165
+ function buildAndroid(cwd, outputDir, options) {
166
+ const androidDir = join(cwd, "android");
167
+ if (!existsSync(androidDir)) {
168
+ console.log(pc.yellow(" No android/ directory found."));
169
+ console.log(pc.dim(" To add Android support, create an Android project in the android/ directory."));
170
+ console.log(pc.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
171
+ return;
172
+ }
173
+ const gradlew = join(androidDir, "gradlew");
174
+ if (!existsSync(gradlew)) {
175
+ console.error(pc.red(" \u2717 gradlew not found in android/ directory"));
176
+ console.log(pc.dim(" Make sure your Android project has the Gradle wrapper.\n"));
177
+ process.exit(1);
178
+ }
179
+ const gradleTask = options.aab ? "bundleRelease" : "assembleRelease";
180
+ const artifactType = options.aab ? "AAB" : "APK";
181
+ ensureOutputDir(outputDir);
182
+ console.log(pc.white(` Building release ${artifactType} with Gradle...`));
183
+ const gradle = spawn(
184
+ "./gradlew",
185
+ [gradleTask],
186
+ {
187
+ cwd: androidDir,
188
+ stdio: "pipe",
189
+ env: { ...process.env }
190
+ }
191
+ );
192
+ const cleanupGradle = () => {
193
+ if (gradle && !gradle.killed) {
194
+ gradle.kill();
195
+ }
196
+ };
197
+ process.on("exit", cleanupGradle);
198
+ process.on("SIGINT", cleanupGradle);
199
+ process.on("SIGTERM", cleanupGradle);
200
+ gradle.stdout?.on("data", (data) => {
201
+ const text = data.toString().trim();
202
+ if (text) {
203
+ console.log(pc.dim(` ${text}`));
204
+ }
205
+ });
206
+ gradle.stderr?.on("data", (data) => {
207
+ const text = data.toString().trim();
208
+ if (text.includes("ERROR") || text.includes("FAILURE")) {
209
+ console.log(pc.red(` ${text}`));
210
+ }
211
+ });
212
+ gradle.on("error", (err) => {
213
+ console.error(pc.red(` Gradle process error: ${err.message}`));
214
+ cleanupGradle();
215
+ });
216
+ gradle.on("close", (code) => {
217
+ if (code !== 0) {
218
+ console.error(pc.red(` \u2717 Gradle build failed (exit code ${code})`));
219
+ process.exit(1);
220
+ }
221
+ console.log(pc.green(" \u2713 Build successful\n"));
222
+ if (options.aab) {
223
+ const aabPath = findReleaseAab(androidDir);
224
+ if (aabPath) {
225
+ const destPath = join(outputDir, basename(aabPath));
226
+ copyFileSync(aabPath, destPath);
227
+ console.log(pc.green(` AAB copied to: ${destPath}`));
228
+ console.log(pc.dim(" Upload this file to the Google Play Console.\n"));
229
+ } else {
230
+ console.log(pc.yellow(" Could not locate release AAB."));
231
+ console.log(pc.dim(" Expected at android/app/build/outputs/bundle/release/\n"));
232
+ }
233
+ } else {
234
+ const apkPath = findReleaseApk(androidDir);
235
+ if (apkPath) {
236
+ const destPath = join(outputDir, basename(apkPath));
237
+ copyFileSync(apkPath, destPath);
238
+ console.log(pc.green(` APK copied to: ${destPath}`));
239
+ console.log(pc.dim(' Install with: adb install -r "' + destPath + '"\n'));
240
+ } else {
241
+ console.log(pc.yellow(" Could not locate release APK."));
242
+ console.log(pc.dim(" Expected at android/app/build/outputs/apk/release/\n"));
243
+ }
244
+ }
245
+ });
246
+ }
247
+
248
+ // src/commands/create.ts
249
+ import { Command as Command2 } from "commander";
8
250
  import { cp, mkdir, writeFile } from "fs/promises";
9
- import { join, dirname } from "path";
251
+ import { join as join2, dirname } from "path";
10
252
  import { fileURLToPath } from "url";
11
- import { existsSync } from "fs";
12
- import pc from "picocolors";
13
- var VERSION = "0.4.13";
14
- var createCommand = new Command("create").description("Create a new Vue Native project").argument("<name>", "project name").option("-t, --template <template>", "project template (blank, tabs, drawer)", "blank").action(async (name, options) => {
253
+ import { existsSync as existsSync2 } from "fs";
254
+ import pc2 from "picocolors";
255
+ var VERSION = "0.4.14";
256
+ var createCommand = new Command2("create").description("Create a new Vue Native project").argument("<name>", "project name").option("-t, --template <template>", "project template (blank, tabs, drawer)", "blank").action(async (name, options) => {
15
257
  const template = options.template;
16
258
  if (!["blank", "tabs", "drawer"].includes(template)) {
17
- console.error(pc.red(`Invalid template "${template}". Choose: blank, tabs, drawer`));
259
+ console.error(pc2.red(`Invalid template "${template}". Choose: blank, tabs, drawer`));
18
260
  process.exit(1);
19
261
  }
20
- const dir = join(process.cwd(), name);
21
- console.log(pc.cyan(`
22
- Creating Vue Native project: ${pc.bold(name)} (template: ${template})
262
+ const dir = join2(process.cwd(), name);
263
+ console.log(pc2.cyan(`
264
+ Creating Vue Native project: ${pc2.bold(name)} (template: ${template})
23
265
  `));
24
266
  try {
25
267
  await mkdir(dir, { recursive: true });
26
- await mkdir(join(dir, "app"), { recursive: true });
27
- await mkdir(join(dir, "app", "pages"), { recursive: true });
28
- await writeFile(join(dir, "package.json"), JSON.stringify({
268
+ await mkdir(join2(dir, "app"), { recursive: true });
269
+ await mkdir(join2(dir, "app", "pages"), { recursive: true });
270
+ await writeFile(join2(dir, "package.json"), JSON.stringify({
29
271
  name,
30
272
  version: "0.0.1",
31
273
  private: true,
@@ -47,7 +289,7 @@ Creating Vue Native project: ${pc.bold(name)} (template: ${template})
47
289
  "typescript": "^5.7.0"
48
290
  }
49
291
  }, null, 2));
50
- await writeFile(join(dir, "vite.config.ts"), `import { defineConfig } from 'vite'
292
+ await writeFile(join2(dir, "vite.config.ts"), `import { defineConfig } from 'vite'
51
293
  import vue from '@vitejs/plugin-vue'
52
294
  import vueNative from '@thelacanians/vue-native-vite-plugin'
53
295
 
@@ -55,7 +297,7 @@ export default defineConfig({
55
297
  plugins: [vue(), vueNative()],
56
298
  })
57
299
  `);
58
- await writeFile(join(dir, "tsconfig.json"), JSON.stringify({
300
+ await writeFile(join2(dir, "tsconfig.json"), JSON.stringify({
59
301
  compilerOptions: {
60
302
  target: "ES2020",
61
303
  module: "ESNext",
@@ -71,12 +313,12 @@ export default defineConfig({
71
313
  include: ["app/**/*", "env.d.ts"]
72
314
  }, null, 2));
73
315
  await generateTemplateFiles(dir, name, template);
74
- const iosDir = join(dir, "ios");
75
- const iosSrcDir = join(iosDir, "Sources");
316
+ const iosDir = join2(dir, "ios");
317
+ const iosSrcDir = join2(iosDir, "Sources");
76
318
  await mkdir(iosSrcDir, { recursive: true });
77
319
  const xcodeProjectName = name.replace(/[^a-zA-Z0-9]/g, "");
78
320
  const bundleId = `com.vuenative.${name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()}`;
79
- await writeFile(join(iosDir, "project.yml"), `name: ${xcodeProjectName}
321
+ await writeFile(join2(iosDir, "project.yml"), `name: ${xcodeProjectName}
80
322
  options:
81
323
  bundleIdPrefix: com.vuenative
82
324
  deploymentTarget:
@@ -107,7 +349,7 @@ targets:
107
349
  - path: ../dist/vue-native-bundle.js
108
350
  optional: true
109
351
  `);
110
- await writeFile(join(iosSrcDir, "Info.plist"), `<?xml version="1.0" encoding="UTF-8"?>
352
+ await writeFile(join2(iosSrcDir, "Info.plist"), `<?xml version="1.0" encoding="UTF-8"?>
111
353
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
112
354
  <plist version="1.0">
113
355
  <dict>
@@ -156,6 +398,11 @@ targets:
156
398
  <string>UIInterfaceOrientationLandscapeLeft</string>
157
399
  <string>UIInterfaceOrientationLandscapeRight</string>
158
400
  </array>
401
+ <key>NSAppTransportSecurity</key>
402
+ <dict>
403
+ <key>NSAllowsLocalNetworking</key>
404
+ <true/>
405
+ </dict>
159
406
  <!-- Uncomment the privacy descriptions for features your app uses -->
160
407
  <!-- <key>NSCameraUsageDescription</key><string>This app needs camera access</string> -->
161
408
  <!-- <key>NSMicrophoneUsageDescription</key><string>This app needs microphone access</string> -->
@@ -168,7 +415,7 @@ targets:
168
415
  </dict>
169
416
  </plist>
170
417
  `);
171
- await writeFile(join(iosSrcDir, "AppDelegate.swift"), `import UIKit
418
+ await writeFile(join2(iosSrcDir, "AppDelegate.swift"), `import UIKit
172
419
 
173
420
  @main
174
421
  class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -192,7 +439,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
192
439
  }
193
440
  }
194
441
  `);
195
- await writeFile(join(iosSrcDir, "SceneDelegate.swift"), `import UIKit
442
+ await writeFile(join2(iosSrcDir, "SceneDelegate.swift"), `import UIKit
196
443
  import VueNativeCore
197
444
 
198
445
  class SceneDelegate: UIResponder, UIWindowSceneDelegate {
@@ -220,29 +467,29 @@ class AppViewController: VueNativeViewController {
220
467
  #endif
221
468
  }
222
469
  `);
223
- const androidDir = join(dir, "android");
224
- const androidAppDir = join(androidDir, "app");
470
+ const androidDir = join2(dir, "android");
471
+ const androidAppDir = join2(androidDir, "app");
225
472
  const androidPkg = `com.vuenative.${name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()}`;
226
473
  const androidPkgPath = androidPkg.replace(/\./g, "/");
227
- const androidSrcDir = join(androidAppDir, "src", "main");
228
- const androidKotlinDir = join(androidSrcDir, "kotlin", androidPkgPath);
229
- const androidResValuesDir = join(androidSrcDir, "res", "values");
230
- const androidResXmlDir = join(androidSrcDir, "res", "xml");
231
- const androidDebugResXmlDir = join(androidAppDir, "src", "debug", "res", "xml");
232
- const androidGradleWrapperDir = join(androidDir, "gradle", "wrapper");
474
+ const androidSrcDir = join2(androidAppDir, "src", "main");
475
+ const androidKotlinDir = join2(androidSrcDir, "kotlin", androidPkgPath);
476
+ const androidResValuesDir = join2(androidSrcDir, "res", "values");
477
+ const androidResXmlDir = join2(androidSrcDir, "res", "xml");
478
+ const androidDebugResXmlDir = join2(androidAppDir, "src", "debug", "res", "xml");
479
+ const androidGradleWrapperDir = join2(androidDir, "gradle", "wrapper");
233
480
  await mkdir(androidKotlinDir, { recursive: true });
234
481
  await mkdir(androidResValuesDir, { recursive: true });
235
482
  await mkdir(androidResXmlDir, { recursive: true });
236
483
  await mkdir(androidDebugResXmlDir, { recursive: true });
237
484
  await mkdir(androidGradleWrapperDir, { recursive: true });
238
- await writeFile(join(androidDir, "build.gradle.kts"), `// Top-level build file
485
+ await writeFile(join2(androidDir, "build.gradle.kts"), `// Top-level build file
239
486
  plugins {
240
487
  id("com.android.application") version "8.7.3" apply false
241
488
  id("com.android.library") version "8.7.3" apply false
242
489
  id("org.jetbrains.kotlin.android") version "2.0.21" apply false
243
490
  }
244
491
  `);
245
- await writeFile(join(androidDir, "settings.gradle.kts"), `pluginManagement {
492
+ await writeFile(join2(androidDir, "settings.gradle.kts"), `pluginManagement {
246
493
  repositories {
247
494
  google()
248
495
  mavenCentral()
@@ -268,7 +515,7 @@ dependencyResolutionManagement {
268
515
  rootProject.name = "${name}"
269
516
  include(":app")
270
517
  `);
271
- await writeFile(join(androidAppDir, "build.gradle.kts"), `plugins {
518
+ await writeFile(join2(androidAppDir, "build.gradle.kts"), `plugins {
272
519
  id("com.android.application")
273
520
  id("org.jetbrains.kotlin.android")
274
521
  }
@@ -316,13 +563,13 @@ dependencies {
316
563
  implementation("androidx.core:core-ktx:1.15.0")
317
564
  }
318
565
  `);
319
- await writeFile(join(androidAppDir, "proguard-rules.pro"), `# Vue Native
566
+ await writeFile(join2(androidAppDir, "proguard-rules.pro"), `# Vue Native
320
567
  -keep class com.vuenative.** { *; }
321
568
 
322
569
  # J2V8
323
570
  -keep class com.eclipsesource.v8.** { *; }
324
571
  `);
325
- await writeFile(join(androidSrcDir, "AndroidManifest.xml"), `<?xml version="1.0" encoding="utf-8"?>
572
+ await writeFile(join2(androidSrcDir, "AndroidManifest.xml"), `<?xml version="1.0" encoding="utf-8"?>
326
573
  <manifest xmlns:android="http://schemas.android.com/apk/res/android">
327
574
  <uses-permission android:name="android.permission.INTERNET" />
328
575
 
@@ -345,12 +592,12 @@ dependencies {
345
592
  </application>
346
593
  </manifest>
347
594
  `);
348
- await writeFile(join(androidResValuesDir, "strings.xml"), `<?xml version="1.0" encoding="utf-8"?>
595
+ await writeFile(join2(androidResValuesDir, "strings.xml"), `<?xml version="1.0" encoding="utf-8"?>
349
596
  <resources>
350
597
  <string name="app_name">${name}</string>
351
598
  </resources>
352
599
  `);
353
- await writeFile(join(androidResValuesDir, "themes.xml"), `<?xml version="1.0" encoding="utf-8"?>
600
+ await writeFile(join2(androidResValuesDir, "themes.xml"), `<?xml version="1.0" encoding="utf-8"?>
354
601
  <resources>
355
602
  <style name="Theme.VueNative" parent="Theme.MaterialComponents.Light.NoActionBar">
356
603
  <item name="colorPrimary">#4F46E5</item>
@@ -363,12 +610,12 @@ dependencies {
363
610
  </style>
364
611
  </resources>
365
612
  `);
366
- await writeFile(join(androidResXmlDir, "network_security_config.xml"), `<?xml version="1.0" encoding="utf-8"?>
613
+ await writeFile(join2(androidResXmlDir, "network_security_config.xml"), `<?xml version="1.0" encoding="utf-8"?>
367
614
  <network-security-config>
368
615
  <base-config cleartextTrafficPermitted="false" />
369
616
  </network-security-config>
370
617
  `);
371
- await writeFile(join(androidDebugResXmlDir, "network_security_config.xml"), `<?xml version="1.0" encoding="utf-8"?>
618
+ await writeFile(join2(androidDebugResXmlDir, "network_security_config.xml"), `<?xml version="1.0" encoding="utf-8"?>
372
619
  <network-security-config>
373
620
  <domain-config cleartextTrafficPermitted="true">
374
621
  <domain includeSubdomains="true">localhost</domain>
@@ -377,7 +624,7 @@ dependencies {
377
624
  </domain-config>
378
625
  </network-security-config>
379
626
  `);
380
- await writeFile(join(androidKotlinDir, "MainActivity.kt"), `package ${androidPkg}
627
+ await writeFile(join2(androidKotlinDir, "MainActivity.kt"), `package ${androidPkg}
381
628
 
382
629
  import com.vuenative.core.VueNativeActivity
383
630
 
@@ -391,20 +638,20 @@ class MainActivity : VueNativeActivity() {
391
638
  }
392
639
  }
393
640
  `);
394
- await writeFile(join(androidDir, "gradle.properties"), `# Project-wide Gradle settings
641
+ await writeFile(join2(androidDir, "gradle.properties"), `# Project-wide Gradle settings
395
642
  org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
396
643
  android.useAndroidX=true
397
644
  kotlin.code.style=official
398
645
  android.nonTransitiveRClass=true
399
646
  `);
400
- await writeFile(join(androidGradleWrapperDir, "gradle-wrapper.properties"), `distributionBase=GRADLE_USER_HOME
647
+ await writeFile(join2(androidGradleWrapperDir, "gradle-wrapper.properties"), `distributionBase=GRADLE_USER_HOME
401
648
  distributionPath=wrapper/dists
402
649
  distributionUrl=https\\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
403
650
  networkTimeout=10000
404
651
  zipStoreBase=GRADLE_USER_HOME
405
652
  zipStorePath=wrapper/dists
406
653
  `);
407
- await writeFile(join(dir, "vue-native.config.ts"), `import { defineConfig } from '@thelacanians/vue-native-cli'
654
+ await writeFile(join2(dir, "vue-native.config.ts"), `import { defineConfig } from '@thelacanians/vue-native-cli'
408
655
 
409
656
  export default defineConfig({
410
657
  name: '${name}',
@@ -419,7 +666,7 @@ export default defineConfig({
419
666
  },
420
667
  })
421
668
  `);
422
- await writeFile(join(dir, "env.d.ts"), `/// <reference types="vite/client" />
669
+ await writeFile(join2(dir, "env.d.ts"), `/// <reference types="vite/client" />
423
670
  declare module '*.vue' {
424
671
  import type { DefineComponent } from '@thelacanians/vue-native-runtime'
425
672
  const component: DefineComponent<{}, {}, any>
@@ -427,7 +674,7 @@ declare module '*.vue' {
427
674
  }
428
675
  declare const __DEV__: boolean
429
676
  `);
430
- await writeFile(join(dir, ".gitignore"), `node_modules/
677
+ await writeFile(join2(dir, ".gitignore"), `node_modules/
431
678
  dist/
432
679
  *.xcuserstate
433
680
  *.xcuserdatad/
@@ -450,30 +697,30 @@ local.properties
450
697
  *.jks
451
698
  `);
452
699
  const cliDir = dirname(dirname(fileURLToPath(import.meta.url)));
453
- const bundledNative = join(cliDir, "native");
454
- if (existsSync(bundledNative)) {
455
- const nativeDir = join(dir, "native");
700
+ const bundledNative = join2(cliDir, "native");
701
+ if (existsSync2(bundledNative)) {
702
+ const nativeDir = join2(dir, "native");
456
703
  await cp(bundledNative, nativeDir, { recursive: true });
457
- console.log(pc.dim(" Bundled native/ copied as fallback.\n"));
704
+ console.log(pc2.dim(" Bundled native/ copied as fallback.\n"));
458
705
  }
459
- console.log(pc.green(" Project created successfully!\n"));
460
- console.log(pc.white(" Next steps:\n"));
461
- console.log(pc.white(` cd ${name}`));
462
- console.log(pc.white(" bun install"));
463
- console.log(pc.white(" vue-native dev\n"));
464
- console.log(pc.white(" To run on iOS:"));
465
- console.log(pc.white(" vue-native run ios\n"));
466
- console.log(pc.white(" To run on Android:"));
467
- console.log(pc.dim(" Open android/ in Android Studio, or run:"));
468
- console.log(pc.dim(" cd android && gradle wrapper && cd .."));
469
- console.log(pc.white(" vue-native run android\n"));
706
+ console.log(pc2.green(" Project created successfully!\n"));
707
+ console.log(pc2.white(" Next steps:\n"));
708
+ console.log(pc2.white(` cd ${name}`));
709
+ console.log(pc2.white(" bun install"));
710
+ console.log(pc2.white(" vue-native dev\n"));
711
+ console.log(pc2.white(" To run on iOS:"));
712
+ console.log(pc2.white(" vue-native run ios\n"));
713
+ console.log(pc2.white(" To run on Android:"));
714
+ console.log(pc2.dim(" Open android/ in Android Studio, or run:"));
715
+ console.log(pc2.dim(" cd android && gradle wrapper && cd .."));
716
+ console.log(pc2.white(" vue-native run android\n"));
470
717
  } catch (err) {
471
- console.error(pc.red(`Error creating project: ${err.message}`));
718
+ console.error(pc2.red(`Error creating project: ${err.message}`));
472
719
  process.exit(1);
473
720
  }
474
721
  });
475
722
  async function generateTemplateFiles(dir, name, template) {
476
- const pagesDir = join(dir, "app", "pages");
723
+ const pagesDir = join2(dir, "app", "pages");
477
724
  if (template === "blank") {
478
725
  await generateBlankTemplate(dir, pagesDir);
479
726
  } else if (template === "tabs") {
@@ -483,7 +730,7 @@ async function generateTemplateFiles(dir, name, template) {
483
730
  }
484
731
  }
485
732
  async function generateBlankTemplate(dir, pagesDir) {
486
- await writeFile(join(dir, "app", "main.ts"), `import { createApp } from '@thelacanians/vue-native-runtime'
733
+ await writeFile(join2(dir, "app", "main.ts"), `import { createApp } from '@thelacanians/vue-native-runtime'
487
734
  import { createRouter } from '@thelacanians/vue-native-navigation'
488
735
  import App from './App.vue'
489
736
  import Home from './pages/Home.vue'
@@ -496,7 +743,7 @@ const app = createApp(App)
496
743
  app.use(router)
497
744
  app.start()
498
745
  `);
499
- await writeFile(join(dir, "app", "App.vue"), `<template>
746
+ await writeFile(join2(dir, "app", "App.vue"), `<template>
500
747
  <VSafeArea :style="{ flex: 1, backgroundColor: '#ffffff' }">
501
748
  <RouterView />
502
749
  </VSafeArea>
@@ -506,7 +753,7 @@ app.start()
506
753
  import { RouterView } from '@thelacanians/vue-native-navigation'
507
754
  </script>
508
755
  `);
509
- await writeFile(join(pagesDir, "Home.vue"), `<script setup lang="ts">
756
+ await writeFile(join2(pagesDir, "Home.vue"), `<script setup lang="ts">
510
757
  import { ref } from 'vue'
511
758
  import { createStyleSheet } from '@thelacanians/vue-native-runtime'
512
759
 
@@ -558,13 +805,13 @@ const styles = createStyleSheet({
558
805
  `);
559
806
  }
560
807
  async function generateTabsTemplate(dir, pagesDir) {
561
- await writeFile(join(dir, "app", "main.ts"), `import { createApp } from '@thelacanians/vue-native-runtime'
808
+ await writeFile(join2(dir, "app", "main.ts"), `import { createApp } from '@thelacanians/vue-native-runtime'
562
809
  import App from './App.vue'
563
810
 
564
811
  const app = createApp(App)
565
812
  app.start()
566
813
  `);
567
- await writeFile(join(dir, "app", "App.vue"), `<script setup lang="ts">
814
+ await writeFile(join2(dir, "app", "App.vue"), `<script setup lang="ts">
568
815
  import { createTabNavigator } from '@thelacanians/vue-native-navigation'
569
816
  import Home from './pages/Home.vue'
570
817
  import Settings from './pages/Settings.vue'
@@ -583,7 +830,7 @@ const { TabNavigator } = createTabNavigator()
583
830
  </VSafeArea>
584
831
  </template>
585
832
  `);
586
- await writeFile(join(pagesDir, "Home.vue"), `<script setup lang="ts">
833
+ await writeFile(join2(pagesDir, "Home.vue"), `<script setup lang="ts">
587
834
  import { ref } from 'vue'
588
835
  import { createStyleSheet } from '@thelacanians/vue-native-runtime'
589
836
 
@@ -627,7 +874,7 @@ const styles = createStyleSheet({
627
874
  </VView>
628
875
  </template>
629
876
  `);
630
- await writeFile(join(pagesDir, "Settings.vue"), `<script setup lang="ts">
877
+ await writeFile(join2(pagesDir, "Settings.vue"), `<script setup lang="ts">
631
878
  import { ref } from 'vue'
632
879
  import { createStyleSheet } from '@thelacanians/vue-native-runtime'
633
880
 
@@ -671,13 +918,13 @@ const styles = createStyleSheet({
671
918
  `);
672
919
  }
673
920
  async function generateDrawerTemplate(dir, pagesDir) {
674
- await writeFile(join(dir, "app", "main.ts"), `import { createApp } from '@thelacanians/vue-native-runtime'
921
+ await writeFile(join2(dir, "app", "main.ts"), `import { createApp } from '@thelacanians/vue-native-runtime'
675
922
  import App from './App.vue'
676
923
 
677
924
  const app = createApp(App)
678
925
  app.start()
679
926
  `);
680
- await writeFile(join(dir, "app", "App.vue"), `<script setup lang="ts">
927
+ await writeFile(join2(dir, "app", "App.vue"), `<script setup lang="ts">
681
928
  import { createDrawerNavigator } from '@thelacanians/vue-native-navigation'
682
929
  import Home from './pages/Home.vue'
683
930
  import About from './pages/About.vue'
@@ -696,7 +943,7 @@ const { DrawerNavigator } = createDrawerNavigator()
696
943
  </VSafeArea>
697
944
  </template>
698
945
  `);
699
- await writeFile(join(pagesDir, "Home.vue"), `<script setup lang="ts">
946
+ await writeFile(join2(pagesDir, "Home.vue"), `<script setup lang="ts">
700
947
  import { createStyleSheet } from '@thelacanians/vue-native-runtime'
701
948
  import { useDrawer } from '@thelacanians/vue-native-navigation'
702
949
 
@@ -749,7 +996,7 @@ const styles = createStyleSheet({
749
996
  </VView>
750
997
  </template>
751
998
  `);
752
- await writeFile(join(pagesDir, "About.vue"), `<script setup lang="ts">
999
+ await writeFile(join2(pagesDir, "About.vue"), `<script setup lang="ts">
753
1000
  import { createStyleSheet } from '@thelacanians/vue-native-runtime'
754
1001
  import { useDrawer } from '@thelacanians/vue-native-navigation'
755
1002
 
@@ -805,19 +1052,19 @@ const styles = createStyleSheet({
805
1052
  }
806
1053
 
807
1054
  // src/commands/dev.ts
808
- import { Command as Command2 } from "commander";
809
- import { spawn, execSync } from "child_process";
1055
+ import { Command as Command3 } from "commander";
1056
+ import { spawn as spawn2, execSync as execSync2 } from "child_process";
810
1057
  import { readFile } from "fs/promises";
811
- import { existsSync as existsSync2 } from "fs";
812
- import { join as join2 } from "path";
1058
+ import { existsSync as existsSync3 } from "fs";
1059
+ import { join as join3 } from "path";
813
1060
  import { watch } from "chokidar";
814
1061
  import { WebSocketServer, WebSocket } from "ws";
815
- import pc2 from "picocolors";
1062
+ import pc3 from "picocolors";
816
1063
  var DEFAULT_PORT = 8174;
817
1064
  var BUNDLE_FILE = "dist/vue-native-bundle.js";
818
1065
  function detectIOSSimulators() {
819
1066
  try {
820
- const output = execSync("xcrun simctl list devices available -j", {
1067
+ const output = execSync2("xcrun simctl list devices available -j", {
821
1068
  stdio: "pipe",
822
1069
  encoding: "utf8"
823
1070
  });
@@ -842,33 +1089,33 @@ function detectIOSSimulators() {
842
1089
  }
843
1090
  function bootSimulator(udid) {
844
1091
  try {
845
- execSync(`xcrun simctl boot "${udid}"`, { stdio: "pipe" });
1092
+ execSync2(`xcrun simctl boot "${udid}"`, { stdio: "pipe" });
846
1093
  } catch {
847
1094
  }
848
1095
  try {
849
- execSync("open -a Simulator", { stdio: "pipe" });
1096
+ execSync2("open -a Simulator", { stdio: "pipe" });
850
1097
  } catch {
851
1098
  }
852
1099
  }
853
1100
  function detectAndroidEmulators() {
854
1101
  try {
855
- const output = execSync("adb devices", { stdio: "pipe", encoding: "utf8" });
1102
+ const output = execSync2("adb devices", { stdio: "pipe", encoding: "utf8" });
856
1103
  const lines = output.split("\n").filter((l) => l.includes("device") && !l.startsWith("List"));
857
1104
  return lines.map((l) => l.split(" ")[0]).filter(Boolean);
858
1105
  } catch {
859
1106
  return [];
860
1107
  }
861
1108
  }
862
- var devCommand = new Command2("dev").description("Start the Vue Native dev server with hot reload").option("-p, --port <port>", "WebSocket port for hot reload", String(DEFAULT_PORT)).option("--ios", "auto-detect and launch iOS Simulator").option("--android", "auto-detect Android emulator").option("--simulator <name>", "specify iOS Simulator name").action(async (options) => {
1109
+ var devCommand = new Command3("dev").description("Start the Vue Native dev server with hot reload").option("-p, --port <port>", "WebSocket port for hot reload", String(DEFAULT_PORT)).option("--ios", "auto-detect and launch iOS Simulator").option("--android", "auto-detect Android emulator").option("--simulator <name>", "specify iOS Simulator name").action(async (options) => {
863
1110
  const port = parseInt(options.port, 10);
864
1111
  const cwd = process.cwd();
865
- const bundlePath = join2(cwd, BUNDLE_FILE);
866
- console.log(pc2.cyan("\n Vue Native Dev Server\n"));
1112
+ const bundlePath = join3(cwd, BUNDLE_FILE);
1113
+ console.log(pc3.cyan("\n Vue Native Dev Server\n"));
867
1114
  if (options.ios) {
868
- console.log(pc2.white(" Detecting iOS Simulators..."));
1115
+ console.log(pc3.white(" Detecting iOS Simulators..."));
869
1116
  const simulators = detectIOSSimulators();
870
1117
  if (simulators.length === 0) {
871
- console.log(pc2.yellow(" No iOS Simulators found. Install Xcode and create a simulator."));
1118
+ console.log(pc3.yellow(" No iOS Simulators found. Install Xcode and create a simulator."));
872
1119
  } else {
873
1120
  let target = simulators.find((s) => s.state === "Booted");
874
1121
  if (!target && options.simulator) {
@@ -879,46 +1126,69 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
879
1126
  }
880
1127
  if (target) {
881
1128
  if (target.state !== "Booted") {
882
- console.log(pc2.white(` Booting ${target.name}...`));
1129
+ console.log(pc3.white(` Booting ${target.name}...`));
883
1130
  bootSimulator(target.udid);
884
1131
  }
885
- console.log(pc2.green(` iOS Simulator ready: ${target.name}`));
1132
+ console.log(pc3.green(` iOS Simulator ready: ${target.name}`));
886
1133
  }
887
1134
  }
888
1135
  console.log();
889
1136
  }
890
1137
  if (options.android) {
891
- console.log(pc2.white(" Detecting Android emulators..."));
1138
+ console.log(pc3.white(" Detecting Android emulators..."));
892
1139
  const emulators = detectAndroidEmulators();
893
1140
  if (emulators.length === 0) {
894
- console.log(pc2.yellow(" No Android emulators detected. Start one via Android Studio or `emulator -avd <name>`."));
1141
+ console.log(pc3.yellow(" No Android emulators detected. Start one via Android Studio or `emulator -avd <name>`."));
895
1142
  } else {
896
- console.log(pc2.green(` Android emulator(s) connected: ${emulators.join(", ")}`));
1143
+ console.log(pc3.green(` Android emulator(s) connected: ${emulators.join(", ")}`));
897
1144
  }
898
1145
  console.log();
899
1146
  }
1147
+ let lanIP = "";
1148
+ try {
1149
+ const nets = await import("os").then((os) => os.networkInterfaces());
1150
+ for (const ifaces of Object.values(nets)) {
1151
+ for (const iface of ifaces ?? []) {
1152
+ if (iface.family === "IPv4" && !iface.internal) {
1153
+ lanIP = iface.address;
1154
+ break;
1155
+ }
1156
+ }
1157
+ if (lanIP) break;
1158
+ }
1159
+ } catch {
1160
+ }
1161
+ const isPrivateOrLocal = (addr) => {
1162
+ if (!addr) return false;
1163
+ const ip = addr.replace(/^::ffff:/, "");
1164
+ if (ip === "127.0.0.1" || ip === "::1") return true;
1165
+ if (ip === "10.0.2.2") return true;
1166
+ if (ip.startsWith("10.")) return true;
1167
+ if (ip.startsWith("192.168.")) return true;
1168
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(ip)) return true;
1169
+ return false;
1170
+ };
900
1171
  const wss = new WebSocketServer({
901
1172
  port,
902
1173
  verifyClient: (info) => {
903
- const addr = info.req.socket.remoteAddress;
904
- return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
1174
+ return isPrivateOrLocal(info.req.socket.remoteAddress);
905
1175
  }
906
1176
  });
907
1177
  const clients = /* @__PURE__ */ new Set();
908
1178
  wss.on("connection", (ws) => {
909
1179
  clients.add(ws);
910
1180
  ws.send(JSON.stringify({ type: "connected" }));
911
- console.log(pc2.green(` Client connected (${clients.size} total)`));
1181
+ console.log(pc3.green(` Client connected (${clients.size} total)`));
912
1182
  readFile(bundlePath, "utf8").then((bundle) => {
913
1183
  if (ws.readyState === WebSocket.OPEN) {
914
1184
  ws.send(JSON.stringify({ type: "bundle", bundle }));
915
- console.log(pc2.dim(` Sent bundle to new client (${Math.round(bundle.length / 1024)}KB)`));
1185
+ console.log(pc3.dim(` Sent bundle to new client (${Math.round(bundle.length / 1024)}KB)`));
916
1186
  }
917
1187
  }).catch(() => {
918
1188
  });
919
1189
  ws.on("close", () => {
920
1190
  clients.delete(ws);
921
- console.log(pc2.dim(` Client disconnected (${clients.size} remaining)`));
1191
+ console.log(pc3.dim(` Client disconnected (${clients.size} remaining)`));
922
1192
  });
923
1193
  ws.on("message", (data) => {
924
1194
  try {
@@ -929,34 +1199,43 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
929
1199
  });
930
1200
  });
931
1201
  wss.on("error", (err) => {
932
- console.error(pc2.red(`WebSocket server error: ${err.message}`));
1202
+ console.error(pc3.red(`WebSocket server error: ${err.message}`));
933
1203
  });
934
- console.log(pc2.white(` Hot reload server: ${pc2.bold(`ws://localhost:${port}`)}`));
935
- const iosDir = join2(cwd, "ios");
936
- const androidDir = join2(cwd, "android");
937
- if (existsSync2(iosDir)) {
938
- console.log(pc2.dim(` iOS app should connect to ws://localhost:${port}`));
1204
+ console.log(pc3.white(` Hot reload server: ${pc3.bold(`ws://localhost:${port}`)}`));
1205
+ if (lanIP) {
1206
+ console.log(pc3.white(` LAN address: ${pc3.bold(`ws://${lanIP}:${port}`)}`));
939
1207
  }
940
- if (existsSync2(androidDir)) {
941
- console.log(pc2.dim(` Android emulator should connect to ws://10.0.2.2:${port}`));
1208
+ const iosDir = join3(cwd, "ios");
1209
+ const androidDir = join3(cwd, "android");
1210
+ if (existsSync3(iosDir)) {
1211
+ console.log(pc3.dim(` iOS Simulator: ws://localhost:${port}`));
1212
+ if (lanIP) {
1213
+ console.log(pc3.dim(` iOS Device (WiFi): ws://${lanIP}:${port}`));
1214
+ }
942
1215
  }
943
- console.log(pc2.dim(" Waiting for app to connect...\n"));
944
- console.log(pc2.white(" Starting Vite build watcher...\n"));
945
- const vite = spawn(
1216
+ if (existsSync3(androidDir)) {
1217
+ console.log(pc3.dim(` Android emulator: ws://10.0.2.2:${port}`));
1218
+ if (lanIP) {
1219
+ console.log(pc3.dim(` Android Device: ws://${lanIP}:${port}`));
1220
+ }
1221
+ }
1222
+ console.log(pc3.dim(" Waiting for app to connect...\n"));
1223
+ console.log(pc3.white(" Starting Vite build watcher...\n"));
1224
+ const vite = spawn2(
946
1225
  "bun",
947
1226
  ["run", "vite", "build", "--watch", "--mode", "development"],
948
1227
  { cwd, stdio: "pipe" }
949
1228
  );
950
1229
  vite.stdout?.on("data", (data) => {
951
1230
  const text = data.toString().trim();
952
- if (text) console.log(pc2.dim(` [vite] ${text}`));
1231
+ if (text) console.log(pc3.dim(` [vite] ${text}`));
953
1232
  });
954
1233
  vite.stderr?.on("data", (data) => {
955
1234
  const text = data.toString().trim();
956
- if (text) console.log(pc2.yellow(` [vite] ${text}`));
1235
+ if (text) console.log(pc3.yellow(` [vite] ${text}`));
957
1236
  });
958
1237
  vite.on("error", (err) => {
959
- console.error(pc2.red(`Vite error: ${err.message}`));
1238
+ console.error(pc3.red(`Vite error: ${err.message}`));
960
1239
  });
961
1240
  const watcher = watch(bundlePath, {
962
1241
  persistent: true,
@@ -976,7 +1255,7 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
976
1255
  sent++;
977
1256
  }
978
1257
  }
979
- console.log(pc2.green(` Bundle updated (${Math.round(bundle.length / 1024)}KB) -> sent to ${sent} client(s)`));
1258
+ console.log(pc3.green(` Bundle updated (${Math.round(bundle.length / 1024)}KB) -> sent to ${sent} client(s)`));
980
1259
  } catch {
981
1260
  }
982
1261
  }
@@ -988,7 +1267,7 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
988
1267
  }
989
1268
  }, 3e4);
990
1269
  process.on("SIGINT", () => {
991
- console.log(pc2.yellow("\n Shutting down dev server..."));
1270
+ console.log(pc3.yellow("\n Shutting down dev server..."));
992
1271
  vite.kill();
993
1272
  wss.close();
994
1273
  process.exit(0);
@@ -996,30 +1275,30 @@ var devCommand = new Command2("dev").description("Start the Vue Native dev serve
996
1275
  });
997
1276
 
998
1277
  // src/commands/run.ts
999
- import { Command as Command3 } from "commander";
1000
- import { spawn as spawn2, execSync as execSync2 } from "child_process";
1001
- import { existsSync as existsSync3, readdirSync, readFileSync } from "fs";
1002
- import { join as join3 } from "path";
1003
- import pc3 from "picocolors";
1278
+ import { Command as Command4 } from "commander";
1279
+ import { spawn as spawn3, execSync as execSync3 } from "child_process";
1280
+ import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync } from "fs";
1281
+ import { join as join4 } from "path";
1282
+ import pc4 from "picocolors";
1004
1283
  function findAppPath(_buildDir) {
1005
- const derivedDataBase = join3(
1284
+ const derivedDataBase = join4(
1006
1285
  process.env.HOME || "~",
1007
1286
  "Library/Developer/Xcode/DerivedData"
1008
1287
  );
1009
- if (existsSync3(derivedDataBase)) {
1288
+ if (existsSync4(derivedDataBase)) {
1010
1289
  try {
1011
- const projects = readdirSync(derivedDataBase);
1290
+ const projects = readdirSync2(derivedDataBase);
1012
1291
  for (const project of projects.reverse()) {
1013
- const productsDir = join3(
1292
+ const productsDir = join4(
1014
1293
  derivedDataBase,
1015
1294
  project,
1016
1295
  "Build/Products/Debug-iphonesimulator"
1017
1296
  );
1018
- if (existsSync3(productsDir)) {
1019
- const entries = readdirSync(productsDir);
1297
+ if (existsSync4(productsDir)) {
1298
+ const entries = readdirSync2(productsDir);
1020
1299
  const app = entries.find((e) => e.endsWith(".app"));
1021
1300
  if (app) {
1022
- return join3(productsDir, app);
1301
+ return join4(productsDir, app);
1023
1302
  }
1024
1303
  }
1025
1304
  }
@@ -1029,8 +1308,8 @@ function findAppPath(_buildDir) {
1029
1308
  return null;
1030
1309
  }
1031
1310
  function readBundleId(iosDir) {
1032
- const plistPath = join3(iosDir, "Sources", "Info.plist");
1033
- if (existsSync3(plistPath)) {
1311
+ const plistPath = join4(iosDir, "Sources", "Info.plist");
1312
+ if (existsSync4(plistPath)) {
1034
1313
  try {
1035
1314
  const content = readFileSync(plistPath, "utf8");
1036
1315
  const match = content.match(
@@ -1045,34 +1324,34 @@ function readBundleId(iosDir) {
1045
1324
  return "com.vuenative.app";
1046
1325
  }
1047
1326
  function findApkPath(androidDir) {
1048
- const apkDir = join3(androidDir, "app", "build", "outputs", "apk", "debug");
1049
- if (existsSync3(apkDir)) {
1327
+ const apkDir = join4(androidDir, "app", "build", "outputs", "apk", "debug");
1328
+ if (existsSync4(apkDir)) {
1050
1329
  try {
1051
- const entries = readdirSync(apkDir);
1330
+ const entries = readdirSync2(apkDir);
1052
1331
  const apk = entries.find((e) => e.endsWith(".apk") && !e.includes("androidTest"));
1053
1332
  if (apk) {
1054
- return join3(apkDir, apk);
1333
+ return join4(apkDir, apk);
1055
1334
  }
1056
1335
  } catch {
1057
1336
  }
1058
1337
  }
1059
1338
  return null;
1060
1339
  }
1061
- var runCommand = new Command3("run").description("Build and run the app").argument("<platform>", "platform to run on (ios, android)").option("--device", "run on physical device instead of simulator").option("--scheme <scheme>", "Xcode scheme to build").option("--simulator <name>", "simulator name", "iPhone 16").option("--bundle-id <id>", "app bundle identifier").option("--package <name>", "Android package name", "com.vuenative.app").option("--activity <name>", "Android activity name", ".MainActivity").action(async (platform, options) => {
1340
+ var runCommand = new Command4("run").description("Build and run the app").argument("<platform>", "platform to run on (ios, android)").option("--device", "run on physical device instead of simulator").option("--scheme <scheme>", "Xcode scheme to build").option("--simulator <name>", "simulator name", "iPhone 16").option("--bundle-id <id>", "app bundle identifier").option("--package <name>", "Android package name", "com.vuenative.app").option("--activity <name>", "Android activity name", ".MainActivity").action(async (platform, options) => {
1062
1341
  if (platform !== "ios" && platform !== "android") {
1063
- console.error(pc3.red('Platform must be "ios" or "android"'));
1342
+ console.error(pc4.red('Platform must be "ios" or "android"'));
1064
1343
  process.exit(1);
1065
1344
  }
1066
1345
  const cwd = process.cwd();
1067
- console.log(pc3.cyan(`
1346
+ console.log(pc4.cyan(`
1068
1347
  \u{1F4F1} Vue Native \u2014 Run ${platform === "ios" ? "iOS" : "Android"}
1069
1348
  `));
1070
- console.log(pc3.white(" Building JS bundle..."));
1349
+ console.log(pc4.white(" Building JS bundle..."));
1071
1350
  try {
1072
- execSync2("bun run vite build", { cwd, stdio: "inherit" });
1073
- console.log(pc3.green(" \u2713 Bundle built\n"));
1351
+ execSync3("bun run vite build", { cwd, stdio: "inherit" });
1352
+ console.log(pc4.green(" \u2713 Bundle built\n"));
1074
1353
  } catch {
1075
- console.error(pc3.red(" \u2717 Bundle build failed"));
1354
+ console.error(pc4.red(" \u2717 Bundle build failed"));
1076
1355
  process.exit(1);
1077
1356
  }
1078
1357
  if (platform === "ios") {
@@ -1083,14 +1362,14 @@ var runCommand = new Command3("run").description("Build and run the app").argume
1083
1362
  });
1084
1363
  function runIOS(cwd, options) {
1085
1364
  let xcodeProject = null;
1086
- const iosDir = join3(cwd, "ios");
1087
- if (existsSync3(iosDir)) {
1365
+ const iosDir = join4(cwd, "ios");
1366
+ if (existsSync4(iosDir)) {
1088
1367
  for (const ext of [".xcworkspace", ".xcodeproj"]) {
1089
1368
  try {
1090
- const entries = readdirSync(iosDir);
1369
+ const entries = readdirSync2(iosDir);
1091
1370
  const match = entries.find((e) => e.endsWith(ext));
1092
1371
  if (match) {
1093
- xcodeProject = join3(iosDir, match);
1372
+ xcodeProject = join4(iosDir, match);
1094
1373
  break;
1095
1374
  }
1096
1375
  } catch {
@@ -1098,17 +1377,17 @@ function runIOS(cwd, options) {
1098
1377
  }
1099
1378
  }
1100
1379
  if (!xcodeProject) {
1101
- console.log(pc3.yellow(" No Xcode project found in ./ios/"));
1102
- console.log(pc3.dim(" To add iOS support, create an Xcode project in the ios/ directory."));
1103
- console.log(pc3.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
1380
+ console.log(pc4.yellow(" No Xcode project found in ./ios/"));
1381
+ console.log(pc4.dim(" To add iOS support, create an Xcode project in the ios/ directory."));
1382
+ console.log(pc4.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
1104
1383
  return;
1105
1384
  }
1106
1385
  const isWorkspace = xcodeProject.endsWith(".xcworkspace");
1107
1386
  const scheme = options.scheme || xcodeProject.split("/").pop()?.replace(/\.(xcworkspace|xcodeproj)$/, "") || "App";
1108
1387
  const destination = options.device ? "generic/platform=iOS" : `platform=iOS Simulator,name=${options.simulator}`;
1109
1388
  const projectFlag = isWorkspace ? "-workspace" : "-project";
1110
- console.log(pc3.white(` Building ${scheme} for ${options.device ? "device" : options.simulator}...`));
1111
- const xcodebuild = spawn2(
1389
+ console.log(pc4.white(` Building ${scheme} for ${options.device ? "device" : options.simulator}...`));
1390
+ const xcodebuild = spawn3(
1112
1391
  "xcodebuild",
1113
1392
  [projectFlag, xcodeProject, "-scheme", scheme, "-destination", destination, "build"],
1114
1393
  {
@@ -1120,71 +1399,71 @@ function runIOS(cwd, options) {
1120
1399
  xcodebuild.stderr?.on("data", (data) => {
1121
1400
  const text = data.toString().trim();
1122
1401
  if (text.includes("error:") || text.includes("warning:")) {
1123
- console.log(pc3.dim(` ${text}`));
1402
+ console.log(pc4.dim(` ${text}`));
1124
1403
  }
1125
1404
  });
1126
1405
  xcodebuild.on("close", (code) => {
1127
1406
  if (code !== 0) {
1128
- console.error(pc3.red(` \u2717 Build failed (exit code ${code})`));
1407
+ console.error(pc4.red(` \u2717 Build failed (exit code ${code})`));
1129
1408
  process.exit(1);
1130
1409
  }
1131
- console.log(pc3.green(" \u2713 Build successful\n"));
1410
+ console.log(pc4.green(" \u2713 Build successful\n"));
1132
1411
  if (options.device) {
1133
- console.log(pc3.green(" App built for device. Install via Xcode.\n"));
1412
+ console.log(pc4.green(" App built for device. Install via Xcode.\n"));
1134
1413
  return;
1135
1414
  }
1136
1415
  const simulatorName = options.simulator;
1137
- const bundleId = options.bundleId || readBundleId(join3(cwd, "ios"));
1138
- console.log(pc3.white(` Booting simulator "${simulatorName}"...`));
1416
+ const bundleId = options.bundleId || readBundleId(join4(cwd, "ios"));
1417
+ console.log(pc4.white(` Booting simulator "${simulatorName}"...`));
1139
1418
  try {
1140
- execSync2(`xcrun simctl boot "${simulatorName}"`, { stdio: "pipe" });
1419
+ execSync3(`xcrun simctl boot "${simulatorName}"`, { stdio: "pipe" });
1141
1420
  } catch {
1142
1421
  }
1143
1422
  try {
1144
- execSync2("open -a Simulator", { stdio: "pipe" });
1423
+ execSync3("open -a Simulator", { stdio: "pipe" });
1145
1424
  } catch {
1146
1425
  }
1147
- const appPath = findAppPath(join3(cwd, "ios"));
1426
+ const appPath = findAppPath(join4(cwd, "ios"));
1148
1427
  if (appPath) {
1149
- console.log(pc3.white(` Installing app on simulator...`));
1428
+ console.log(pc4.white(` Installing app on simulator...`));
1150
1429
  try {
1151
- execSync2(`xcrun simctl install booted "${appPath}"`, { stdio: "pipe" });
1152
- console.log(pc3.green(" \u2713 App installed"));
1430
+ execSync3(`xcrun simctl install booted "${appPath}"`, { stdio: "pipe" });
1431
+ console.log(pc4.green(" \u2713 App installed"));
1153
1432
  } catch (err) {
1154
- console.error(pc3.red(` \u2717 Failed to install app: ${err.message}`));
1433
+ console.error(pc4.red(` \u2717 Failed to install app: ${err.message}`));
1155
1434
  process.exit(1);
1156
1435
  }
1157
- console.log(pc3.white(` Launching ${bundleId}...`));
1436
+ console.log(pc4.white(` Launching ${bundleId}...`));
1158
1437
  try {
1159
- execSync2(`xcrun simctl launch booted "${bundleId}"`, { stdio: "pipe" });
1160
- console.log(pc3.green(` \u2713 App launched on ${simulatorName}
1438
+ execSync3(`xcrun simctl launch booted "${bundleId}"`, { stdio: "pipe" });
1439
+ console.log(pc4.green(` \u2713 App launched on ${simulatorName}
1161
1440
  `));
1162
1441
  } catch (err) {
1163
- console.error(pc3.red(` \u2717 Failed to launch app: ${err.message}`));
1442
+ console.error(pc4.red(` \u2717 Failed to launch app: ${err.message}`));
1164
1443
  process.exit(1);
1165
1444
  }
1166
1445
  } else {
1167
- console.log(pc3.yellow(" Could not locate .app bundle in DerivedData."));
1168
- console.log(pc3.dim(" Try running the app from Xcode directly.\n"));
1446
+ console.log(pc4.yellow(" Could not locate .app bundle in DerivedData."));
1447
+ console.log(pc4.dim(" Try running the app from Xcode directly.\n"));
1169
1448
  }
1170
1449
  });
1171
1450
  }
1172
1451
  function runAndroid(cwd, options) {
1173
- const androidDir = join3(cwd, "android");
1174
- if (!existsSync3(androidDir)) {
1175
- console.log(pc3.yellow(" No android/ directory found."));
1176
- console.log(pc3.dim(" To add Android support, create an Android project in the android/ directory."));
1177
- console.log(pc3.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
1452
+ const androidDir = join4(cwd, "android");
1453
+ if (!existsSync4(androidDir)) {
1454
+ console.log(pc4.yellow(" No android/ directory found."));
1455
+ console.log(pc4.dim(" To add Android support, create an Android project in the android/ directory."));
1456
+ console.log(pc4.dim(" Bundle has been built to dist/vue-native-bundle.js\n"));
1178
1457
  return;
1179
1458
  }
1180
- const gradlew = join3(androidDir, "gradlew");
1181
- if (!existsSync3(gradlew)) {
1182
- console.error(pc3.red(" \u2717 gradlew not found in android/ directory"));
1183
- console.log(pc3.dim(" Make sure your Android project has the Gradle wrapper.\n"));
1459
+ const gradlew = join4(androidDir, "gradlew");
1460
+ if (!existsSync4(gradlew)) {
1461
+ console.error(pc4.red(" \u2717 gradlew not found in android/ directory"));
1462
+ console.log(pc4.dim(" Make sure your Android project has the Gradle wrapper.\n"));
1184
1463
  process.exit(1);
1185
1464
  }
1186
- console.log(pc3.white(" Building Android app with Gradle..."));
1187
- const gradle = spawn2(
1465
+ console.log(pc4.white(" Building Android app with Gradle..."));
1466
+ const gradle = spawn3(
1188
1467
  "./gradlew",
1189
1468
  ["assembleDebug"],
1190
1469
  {
@@ -1204,48 +1483,48 @@ function runAndroid(cwd, options) {
1204
1483
  gradle.stdout?.on("data", (data) => {
1205
1484
  const text = data.toString().trim();
1206
1485
  if (text) {
1207
- console.log(pc3.dim(` ${text}`));
1486
+ console.log(pc4.dim(` ${text}`));
1208
1487
  }
1209
1488
  });
1210
1489
  gradle.stderr?.on("data", (data) => {
1211
1490
  const text = data.toString().trim();
1212
1491
  if (text.includes("ERROR") || text.includes("FAILURE")) {
1213
- console.log(pc3.red(` ${text}`));
1492
+ console.log(pc4.red(` ${text}`));
1214
1493
  }
1215
1494
  });
1216
1495
  gradle.on("error", (err) => {
1217
- console.error(pc3.red(` Gradle process error: ${err.message}`));
1496
+ console.error(pc4.red(` Gradle process error: ${err.message}`));
1218
1497
  cleanupGradle();
1219
1498
  });
1220
1499
  gradle.on("close", (code) => {
1221
1500
  if (code !== 0) {
1222
- console.error(pc3.red(` \u2717 Gradle build failed (exit code ${code})`));
1501
+ console.error(pc4.red(` \u2717 Gradle build failed (exit code ${code})`));
1223
1502
  process.exit(1);
1224
1503
  }
1225
- console.log(pc3.green(" \u2713 Build successful\n"));
1504
+ console.log(pc4.green(" \u2713 Build successful\n"));
1226
1505
  const apkPath = findApkPath(androidDir);
1227
1506
  if (!apkPath) {
1228
- console.log(pc3.yellow(" Could not locate debug APK."));
1229
- console.log(pc3.dim(" Expected at android/app/build/outputs/apk/debug/\n"));
1507
+ console.log(pc4.yellow(" Could not locate debug APK."));
1508
+ console.log(pc4.dim(" Expected at android/app/build/outputs/apk/debug/\n"));
1230
1509
  return;
1231
1510
  }
1232
- console.log(pc3.white(" Installing APK on device/emulator..."));
1511
+ console.log(pc4.white(" Installing APK on device/emulator..."));
1233
1512
  try {
1234
- execSync2(`adb install -r "${apkPath}"`, { stdio: "pipe" });
1235
- console.log(pc3.green(" \u2713 APK installed"));
1513
+ execSync3(`adb install -r "${apkPath}"`, { stdio: "pipe" });
1514
+ console.log(pc4.green(" \u2713 APK installed"));
1236
1515
  } catch (err) {
1237
- console.error(pc3.red(` \u2717 Failed to install APK: ${err.message}`));
1238
- console.log(pc3.dim(" Make sure an emulator is running or a device is connected (adb devices).\n"));
1516
+ console.error(pc4.red(` \u2717 Failed to install APK: ${err.message}`));
1517
+ console.log(pc4.dim(" Make sure an emulator is running or a device is connected (adb devices).\n"));
1239
1518
  process.exit(1);
1240
1519
  }
1241
1520
  const componentName = `${options.package}/${options.activity}`;
1242
- console.log(pc3.white(` Launching ${componentName}...`));
1521
+ console.log(pc4.white(` Launching ${componentName}...`));
1243
1522
  try {
1244
- execSync2(`adb shell am start -n "${componentName}"`, { stdio: "pipe" });
1245
- console.log(pc3.green(` \u2713 App launched
1523
+ execSync3(`adb shell am start -n "${componentName}"`, { stdio: "pipe" });
1524
+ console.log(pc4.green(` \u2713 App launched
1246
1525
  `));
1247
1526
  } catch (err) {
1248
- console.error(pc3.red(` \u2717 Failed to launch app: ${err.message}`));
1527
+ console.error(pc4.red(` \u2717 Failed to launch app: ${err.message}`));
1249
1528
  process.exit(1);
1250
1529
  }
1251
1530
  });
@@ -1253,6 +1532,7 @@ function runAndroid(cwd, options) {
1253
1532
 
1254
1533
  // src/cli.ts
1255
1534
  program.name("vue-native").description("Vue Native \u2014 build native iOS and Android apps with Vue.js").version("0.1.0");
1535
+ program.addCommand(buildCommand);
1256
1536
  program.addCommand(createCommand);
1257
1537
  program.addCommand(devCommand);
1258
1538
  program.addCommand(runCommand);