vibeview 0.41.0 → 0.42.0

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.
@@ -831,10 +831,23 @@ function detectFlavor(cwd) {
831
831
  } catch {
832
832
  }
833
833
  if ("expo" in deps) return "expo";
834
- if (existsSync3(join5(cwd, "android", "gradlew")) || iosWorkspaceName(cwd)) return "bare-rn";
834
+ if (isFlutterProject(cwd)) return "flutter";
835
+ const nativeDirs = existsSync3(join5(cwd, "android", "gradlew")) || iosWorkspaceName(cwd);
836
+ const rnDirs = existsSync3(join5(cwd, "ios")) || existsSync3(join5(cwd, "android"));
837
+ if ("react-native" in deps && rnDirs) return "bare-rn";
838
+ if ("@capacitor/core" in deps || CAPACITOR_CONFIGS.some((f) => isFile(join5(cwd, f)))) {
839
+ return "capacitor";
840
+ }
841
+ if (nativeDirs) return isFile(join5(cwd, "package.json")) ? "bare-rn" : "native";
835
842
  if (isFile(join5(cwd, "manifest"))) return "roku";
843
+ if (isFile(join5(cwd, "gradlew")) || xcodeProjects(cwd).length > 0) return "native";
836
844
  return "unknown";
837
845
  }
846
+ function isFlutterProject(cwd) {
847
+ const pubspec = readText(join5(cwd, "pubspec.yaml"));
848
+ return pubspec !== null && /^\s*sdk:\s*flutter\s*(#.*)?$/m.test(pubspec) && !/^\s+plugin:\s*(#.*)?$/m.test(pubspec);
849
+ }
850
+ var CAPACITOR_CONFIGS = ["capacitor.config.ts", "capacitor.config.js", "capacitor.config.json"];
838
851
  function nativeDirShipped(cwd, dir) {
839
852
  if (!existsSync3(join5(cwd, dir))) return false;
840
853
  try {
@@ -862,6 +875,163 @@ function iosWorkspaceName(cwd) {
862
875
  }
863
876
  var IOS_ARTIFACT = "ios/build/Build/Products/Debug-iphonesimulator/*.app";
864
877
  var ANDROID_ARTIFACT = "android/app/build/outputs/apk/debug/*.apk";
878
+ var NATIVE_SEARCH_SKIP = /* @__PURE__ */ new Set(["node_modules", "build", "Pods", "DerivedData"]);
879
+ function topLevelDirs(cwd) {
880
+ try {
881
+ return readdirSync2(cwd, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".") && !NATIVE_SEARCH_SKIP.has(e.name)).map((e) => e.name).sort();
882
+ } catch {
883
+ return [];
884
+ }
885
+ }
886
+ var SAFE_SEGMENT = /^[A-Za-z0-9._-]+$/;
887
+ function dirShipped(cwd, rel) {
888
+ const slash = rel.indexOf("/");
889
+ const checks = [["", rel]];
890
+ if (slash !== -1) checks.push([rel.slice(0, slash), rel.slice(slash + 1)]);
891
+ return checks.every(([dir, path]) => {
892
+ try {
893
+ return !ignore().add(readFileSync5(join5(cwd, dir, ".gitignore"), "utf-8")).ignores(`${path}/`);
894
+ } catch {
895
+ return true;
896
+ }
897
+ });
898
+ }
899
+ function xcodeProjects(cwd) {
900
+ const found = [];
901
+ for (const dir of ["", ...topLevelDirs(cwd)]) {
902
+ try {
903
+ for (const f of readdirSync2(join5(cwd, dir)).sort()) {
904
+ const rel = dir ? `${dir}/${f}` : f;
905
+ if (f.endsWith(".xcodeproj") && dirShipped(cwd, rel)) found.push(rel);
906
+ }
907
+ } catch {
908
+ }
909
+ }
910
+ return found;
911
+ }
912
+ function xcodeScheme(cwd, project) {
913
+ const shared = (() => {
914
+ try {
915
+ return readdirSync2(join5(cwd, project, "xcshareddata", "xcschemes")).filter((f) => f.endsWith(".xcscheme")).map((f) => f.replace(/\.xcscheme$/, ""));
916
+ } catch {
917
+ return [];
918
+ }
919
+ })();
920
+ if (shared.length === 1) return shared[0];
921
+ if (shared.length > 1) return null;
922
+ const pbx = readText(join5(cwd, project, "project.pbxproj"));
923
+ if (!pbx) return null;
924
+ const apps = pbx.split("isa = PBXNativeTarget;").slice(1).map((block) => block.slice(0, block.indexOf("};"))).filter((block) => block.includes('productType = "com.apple.product-type.application";')).map((block) => /\bname = ("?)([^";]+)\1;/.exec(block)?.[2]?.trim()).filter((name) => Boolean(name));
925
+ return apps.length === 1 ? apps[0] : null;
926
+ }
927
+ function shellWord(word) {
928
+ return /^[A-Za-z0-9._/-]+$/.test(word) ? word : `'${word.replace(/'/g, `'\\''`)}'`;
929
+ }
930
+ function nativeIosDefaults(cwd) {
931
+ const projects = xcodeProjects(cwd);
932
+ if (projects.length !== 1) return {};
933
+ const project = projects[0];
934
+ const slash = project.lastIndexOf("/");
935
+ const dir = slash === -1 ? "" : project.slice(0, slash);
936
+ const base = project.slice(slash + 1).replace(/\.xcodeproj$/, "");
937
+ const derived = dir && SAFE_SEGMENT.test(dir) ? `${dir}/build` : "build";
938
+ const artifact = `${derived}/Build/Products/Debug-iphonesimulator/*.app`;
939
+ const scheme = xcodeScheme(cwd, project);
940
+ if (!scheme) return { artifact };
941
+ const pods = isFile(join5(cwd, dir, "Podfile"));
942
+ if (pods && isFile(join5(cwd, "gradlew"))) return { artifact };
943
+ const podLeg = pods ? dir ? `cd ${shellWord(dir)} && pod install && cd .. && ` : "pod install && " : "";
944
+ const target = pods ? `-workspace ${shellWord(dir ? `${dir}/${base}.xcworkspace` : `${base}.xcworkspace`)}` : `-project ${shellWord(project)}`;
945
+ return {
946
+ buildCommand: `${podLeg}xcodebuild ${target} -scheme ${shellWord(scheme)} -configuration Debug -sdk iphonesimulator -derivedDataPath ${shellWord(derived)} CODE_SIGNING_ALLOWED=NO`,
947
+ artifact
948
+ };
949
+ }
950
+ var GRADLE_LOGIC_DIRS = /* @__PURE__ */ new Set(["buildSrc", "build-logic", "gradle"]);
951
+ var APPLIES_ANDROID_APP = /(?:com\.android\.application|libs\.plugins\.android\.?application)\b(?![^\n]*\bapply\s*\(?\s*false)/i;
952
+ function androidAppModules(root) {
953
+ return topLevelDirs(root).filter((dir) => {
954
+ if (!SAFE_SEGMENT.test(dir) || GRADLE_LOGIC_DIRS.has(dir)) return false;
955
+ const script = readText(join5(root, dir, "build.gradle.kts")) ?? readText(join5(root, dir, "build.gradle"));
956
+ return script !== null && APPLIES_ANDROID_APP.test(script);
957
+ });
958
+ }
959
+ function nativeAndroidDefaults(cwd, production) {
960
+ if (!isFile(join5(cwd, "gradlew"))) {
961
+ if (!isFile(join5(cwd, "android", "gradlew"))) return {};
962
+ const inAndroid = androidAppModules(join5(cwd, "android"));
963
+ const m2 = inAndroid.length === 1 ? inAndroid[0] : "app";
964
+ return production ? {
965
+ buildCommand: "cd android && ./gradlew bundleRelease",
966
+ artifact: `android/${m2}/build/outputs/bundle/release/*.aab`
967
+ } : {
968
+ buildCommand: "cd android && ./gradlew assembleDebug",
969
+ artifact: `android/${m2}/build/outputs/apk/debug/*.apk`
970
+ };
971
+ }
972
+ const modules = androidAppModules(cwd);
973
+ if (modules.length !== 1) {
974
+ return {};
975
+ }
976
+ const m = modules[0];
977
+ return production ? {
978
+ buildCommand: `./gradlew :${m}:bundleRelease`,
979
+ artifact: `${m}/build/outputs/bundle/release/*.aab`
980
+ } : {
981
+ buildCommand: `./gradlew :${m}:assembleDebug`,
982
+ artifact: `${m}/build/outputs/apk/debug/*.apk`
983
+ };
984
+ }
985
+ var FLUTTER_ANDROID_ARTIFACT = "build/app/outputs/flutter-apk/app-debug.apk";
986
+ var FLUTTER_IOS_ARTIFACT = "build/ios/iphonesimulator/Runner.app";
987
+ var FLUTTER_ANDROID_PRODUCTION_ARTIFACT = "build/app/outputs/bundle/release/app-release.aab";
988
+ function webBuildCommand(cwd) {
989
+ const scripts = readJson(cwd, "package.json")?.scripts ?? {};
990
+ if (typeof scripts.build !== "string") return null;
991
+ const install = installCommand(cwd);
992
+ if (install.startsWith("yarn ")) return "yarn build";
993
+ if (install.startsWith("pnpm ")) return "pnpm build";
994
+ return "npm run build";
995
+ }
996
+ function gradleWrapperVersion(root) {
997
+ const props = readText(join5(root, "gradle", "wrapper", "gradle-wrapper.properties"));
998
+ const m = props && /distributionUrl=.*gradle-(\d+)\.(\d+)/.exec(props);
999
+ return m ? [Number(m[1]), Number(m[2])] : null;
1000
+ }
1001
+ function dependencyMajor(cwd, name) {
1002
+ const pkg = readJson(cwd, "package.json");
1003
+ const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
1004
+ const range = deps[name];
1005
+ const m = typeof range === "string" ? /(\d+)/.exec(range) : null;
1006
+ return m ? Number(m[1]) : null;
1007
+ }
1008
+ function capacitorDefaults(cwd, platform, production) {
1009
+ const web = webBuildCommand(cwd);
1010
+ const prefix = `${installCommand(cwd)} && ${web ? `${web} && ` : ""}npx cap sync ${platform} && `;
1011
+ if (platform === "android") {
1012
+ const artifact = production ? ANDROID_PRODUCTION_ARTIFACT : ANDROID_ARTIFACT;
1013
+ if (!nativeDirShipped(cwd, "android") || !isFile(join5(cwd, "android", "gradlew"))) {
1014
+ return { artifact };
1015
+ }
1016
+ const major = dependencyMajor(cwd, "@capacitor/android") ?? dependencyMajor(cwd, "@capacitor/core");
1017
+ const wrapper = gradleWrapperVersion(join5(cwd, "android"));
1018
+ const on21 = wrapper ? wrapper[0] > 8 || wrapper[0] === 8 && wrapper[1] >= 5 : major !== null && major >= 7;
1019
+ const java = on21 ? "JAVA_HOME=${JAVA_HOME_21:-$JAVA_HOME} " : "";
1020
+ return {
1021
+ buildCommand: `${prefix}cd android && ${java}./gradlew ${production ? "bundleRelease" : "assembleDebug"}`,
1022
+ artifact
1023
+ };
1024
+ }
1025
+ if (production) return { artifact: IOS_PRODUCTION_ARTIFACT };
1026
+ const project = "ios/App/App.xcodeproj";
1027
+ const scheme = nativeDirShipped(cwd, "ios") ? xcodeScheme(cwd, project) : null;
1028
+ if (!scheme) return { artifact: IOS_ARTIFACT };
1029
+ const target = isFile(join5(cwd, "ios", "App", "Podfile")) ? "-workspace ios/App/App.xcworkspace" : `-project ${project}`;
1030
+ return {
1031
+ buildCommand: `${prefix}xcodebuild ${target} -scheme ${shellWord(scheme)} -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build CODE_SIGNING_ALLOWED=NO`,
1032
+ artifact: IOS_ARTIFACT
1033
+ };
1034
+ }
865
1035
  function installCommand(cwd) {
866
1036
  const hit = JS_LOCKFILE_INSTALLS.find(([lockfile]) => existsSync3(join5(cwd, lockfile)));
867
1037
  return hit ? hit[1] : "npm install";
@@ -914,12 +1084,17 @@ function defaultsFor(cwd, platform, evaluatedIosName) {
914
1084
  const flavor = detectFlavor(cwd);
915
1085
  if (platform === "roku") return flavor === "roku" ? rokuDefaults(cwd) : {};
916
1086
  if (flavor === "unknown" || flavor === "roku") return {};
1087
+ if (flavor === "flutter" || flavor === "capacitor" || flavor === "native") {
1088
+ if (platform === "tvos" || platform === "androidtv") return {};
1089
+ return otherFrameworkDefaults(cwd, flavor, platform, false);
1090
+ }
917
1091
  const metroCommand = flavor === "expo" ? "npx expo start" : "yarn start";
918
1092
  if (platform === "tvos" || platform === "androidtv") return { metroCommand };
919
1093
  if (platform === "android") {
920
1094
  const managed = isManagedExpo(cwd, "android");
1095
+ const wrapper = isFile(join5(cwd, "android", "gradlew"));
921
1096
  return {
922
- buildCommand: managed ? managedExpoAndroidCommand(cwd) : `${bareInstallPrefix(cwd, "android")}cd android && ./gradlew assembleDebug`,
1097
+ buildCommand: managed ? managedExpoAndroidCommand(cwd) : wrapper ? `${bareInstallPrefix(cwd, "android")}cd android && ./gradlew assembleDebug` : void 0,
923
1098
  artifact: ANDROID_ARTIFACT,
924
1099
  metroCommand
925
1100
  };
@@ -939,6 +1114,29 @@ function defaultsFor(cwd, platform, evaluatedIosName) {
939
1114
  metroCommand
940
1115
  };
941
1116
  }
1117
+ function otherFrameworkDefaults(cwd, flavor, platform, production) {
1118
+ if (flavor === "flutter") {
1119
+ if (!existsSync3(join5(cwd, platform))) return {};
1120
+ if (platform === "android") {
1121
+ return production ? {
1122
+ buildCommand: "flutter build appbundle --release",
1123
+ artifact: FLUTTER_ANDROID_PRODUCTION_ARTIFACT
1124
+ } : { buildCommand: "flutter build apk --debug", artifact: FLUTTER_ANDROID_ARTIFACT };
1125
+ }
1126
+ return production ? {} : { buildCommand: "flutter build ios --simulator --debug", artifact: FLUTTER_IOS_ARTIFACT };
1127
+ }
1128
+ if (flavor === "capacitor") return capacitorDefaults(cwd, platform, production);
1129
+ if (platform === "android") return nativeAndroidDefaults(cwd, production);
1130
+ if (!production) return nativeIosDefaults(cwd);
1131
+ const ws = iosWorkspaceName(cwd);
1132
+ const scheme = ws ? xcodeScheme(cwd, `ios/${ws}.xcodeproj`) : null;
1133
+ if (!ws) return {};
1134
+ if (!scheme) return { artifact: IOS_PRODUCTION_ARTIFACT };
1135
+ return {
1136
+ buildCommand: `${bareInstallPrefix(cwd, "ios")}${iosArchiveExportCommand(ws, scheme)}`,
1137
+ artifact: IOS_PRODUCTION_ARTIFACT
1138
+ };
1139
+ }
942
1140
  var ANDROID_PRODUCTION_ARTIFACT = "android/app/build/outputs/bundle/release/*.aab";
943
1141
  function androidProductionCommand(cwd) {
944
1142
  return `${bareInstallPrefix(cwd, "android")}cd android && ./gradlew bundleRelease`;
@@ -965,9 +1163,9 @@ function managedExpoIosName(cwd, evaluatedName) {
965
1163
  if (typeof name !== "string") return null;
966
1164
  return expoSanitizedName(name) || null;
967
1165
  }
968
- function iosArchiveExportCommand(ws) {
1166
+ function iosArchiveExportCommand(ws, scheme = ws) {
969
1167
  const archivePath = `ios/build/${ws}.xcarchive`;
970
- const archiveCmd = `xcodebuild archive -workspace ios/${ws}.xcworkspace -scheme ${ws} -configuration Release -archivePath ${archivePath} CODE_SIGN_STYLE=Manual \${VIBEVIEW_DEVELOPMENT_TEAM:+"DEVELOPMENT_TEAM=$VIBEVIEW_DEVELOPMENT_TEAM"} \${VIBEVIEW_PROVISIONING_PROFILE:+"PROVISIONING_PROFILE_SPECIFIER=$VIBEVIEW_PROVISIONING_PROFILE"} \${VIBEVIEW_CODE_SIGN_IDENTITY:+"CODE_SIGN_IDENTITY=$VIBEVIEW_CODE_SIGN_IDENTITY"}`;
1168
+ const archiveCmd = `xcodebuild archive -workspace ios/${ws}.xcworkspace -scheme ${shellWord(scheme)} -configuration Release -archivePath ${archivePath} CODE_SIGN_STYLE=Manual \${VIBEVIEW_DEVELOPMENT_TEAM:+"DEVELOPMENT_TEAM=$VIBEVIEW_DEVELOPMENT_TEAM"} \${VIBEVIEW_PROVISIONING_PROFILE:+"PROVISIONING_PROFILE_SPECIFIER=$VIBEVIEW_PROVISIONING_PROFILE"} \${VIBEVIEW_CODE_SIGN_IDENTITY:+"CODE_SIGN_IDENTITY=$VIBEVIEW_CODE_SIGN_IDENTITY"}`;
971
1169
  const exportCmd = `xcodebuild -exportArchive -archivePath ${archivePath} -exportPath ios/build -exportOptionsPlist "$VIBEVIEW_EXPORT_OPTIONS_PLIST"`;
972
1170
  return `${archiveCmd} && ${exportCmd}`;
973
1171
  }
@@ -975,9 +1173,13 @@ function managedExpoIosProductionCommand(cwd, name) {
975
1173
  return `${installCommand(cwd)} && npx expo prebuild --platform ios && ` + iosArchiveExportCommand(name);
976
1174
  }
977
1175
  function productionDefaultsFor(cwd, platform, evaluatedIosName) {
1176
+ const flavor = detectFlavor(cwd);
1177
+ if ((flavor === "flutter" || flavor === "capacitor" || flavor === "native") && platform !== "tvos" && platform !== "roku") {
1178
+ return otherFrameworkDefaults(cwd, flavor, platform === "ios" ? "ios" : "android", true);
1179
+ }
978
1180
  if (platform === "android" || platform === "androidtv") {
979
1181
  return {
980
- buildCommand: isManagedExpo(cwd, "android") ? managedExpoAndroidProductionCommand(cwd) : androidProductionCommand(cwd),
1182
+ buildCommand: isManagedExpo(cwd, "android") ? managedExpoAndroidProductionCommand(cwd) : flavor !== "bare-rn" || isFile(join5(cwd, "android", "gradlew")) ? androidProductionCommand(cwd) : void 0,
981
1183
  artifact: ANDROID_PRODUCTION_ARTIFACT
982
1184
  };
983
1185
  }
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  runAgentVerb,
31
31
  runStepsNotChecked,
32
32
  stepsNotCheckedLabel
33
- } from "./chunk-MK3WDPVZ.js";
33
+ } from "./chunk-4WIEZBTP.js";
34
34
  import {
35
35
  ApiClient,
36
36
  ApiStatusError,
@@ -4461,7 +4461,7 @@ program.command("dev-reload").description(
4461
4461
  program.command("mcp").description(
4462
4462
  "Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
4463
4463
  ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
4464
- const { runMcpServer } = await import("./server-435X37GD.js");
4464
+ const { runMcpServer } = await import("./server-VPNWTXOY.js");
4465
4465
  await runMcpServer({ ...opts, version: pkg.version });
4466
4466
  });
4467
4467
  program.command("agent-setup").description(
@@ -30,7 +30,7 @@ import {
30
30
  renderEnvelope,
31
31
  resolveMetro,
32
32
  startDevSession
33
- } from "./chunk-MK3WDPVZ.js";
33
+ } from "./chunk-4WIEZBTP.js";
34
34
  import {
35
35
  ApiClient,
36
36
  NotFoundError,
@@ -419,6 +419,9 @@ async function handleRun(kind, args, deps) {
419
419
  return errorResult(`error: ${testToolErrorMessage(err)}`);
420
420
  }
421
421
  }
422
+ function withoutNotRunPrefix(reason) {
423
+ return reason ? reason.replace(/^Not run:\s*/, "") : reason;
424
+ }
422
425
  function notCheckedNote(status, n) {
423
426
  if (status !== "passed" || typeof n !== "number" || n <= 0) return "";
424
427
  return ` \u2014 ${n} step${n === 1 ? "" : "s"} not checked (no recorded actions; not verified)`;
@@ -463,7 +466,7 @@ function formatRunForAgent(run) {
463
466
  const count = r.kind === "group" && typeof r.tests_total === "number" ? ` (${r.tests_passed ?? 0}/${r.tests_total} tests passed${testsNotChecked(r.tests_not_checked)}${quarantinedCount(rowQuarantined(r))})` : "";
464
467
  const cell = r.kind === "test" ? r.tests?.[0] ?? {} : {};
465
468
  const q = r.kind === "test" && quarantinedFailure(cell) ? " (quarantined)" : "";
466
- const why = r.error_message || cell.not_run_reason;
469
+ const why = withoutNotRunPrefix(r.error_message || cell.not_run_reason);
467
470
  const unchecked = r.kind === "test" ? notCheckedNote(outcomeOf(cell), cell.steps_not_checked) : "";
468
471
  lines.push(
469
472
  ` ${r.name}: ${agentStatus(r)}${q}${count}${why ? ` \u2014 ${why}` : ""}${unchecked}`
@@ -471,7 +474,7 @@ function formatRunForAgent(run) {
471
474
  if (r.kind !== "group") continue;
472
475
  for (const t of r.tests ?? []) {
473
476
  if (t.status === "not_run") {
474
- const reason = t.not_run_reason || t.error_message;
477
+ const reason = withoutNotRunPrefix(t.not_run_reason || t.error_message);
475
478
  lines.push(` ${t.name}: not run${reason ? ` \u2014 ${reason}` : ""}`);
476
479
  continue;
477
480
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeview",
3
- "version": "0.41.0",
3
+ "version": "0.42.0",
4
4
  "description": "VibeView CLI -- run your app on cloud iOS simulators, Android emulators, Apple TV, Android TV and Roku devices: a React Native dev loop, device control for you or your coding agent (CLI or MCP), and tests from CI",
5
5
  "mcpName": "io.github.vibeview/vibeview",
6
6
  "type": "module",