vibeview 0.52.0 → 0.52.2

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.
@@ -869,9 +869,10 @@ function prepareUploadArtifact(path) {
869
869
  import ora from "ora";
870
870
  function createSpinner(text, opts = {}) {
871
871
  const isCI = process.env.CI === "true" || process.env.CI === "1" || !process.stdout.isTTY;
872
+ const drawable = process.stderr.isTTY === true && (process.stderr.columns ?? 0) > 0;
872
873
  return ora({
873
874
  text,
874
- isEnabled: !isCI,
875
+ isEnabled: !isCI && drawable,
875
876
  stream: process.stderr,
876
877
  discardStdin: false,
877
878
  isSilent: opts.silent === true
@@ -13,7 +13,7 @@ import {
13
13
  resolveArtifact,
14
14
  resolveAuth,
15
15
  uploadAppBuild
16
- } from "./chunk-42GZ4UEJ.js";
16
+ } from "./chunk-LRPZFDKL.js";
17
17
 
18
18
  // src/lib/formatters/not-checked.ts
19
19
  function notCheckedSteps(steps) {
@@ -1057,6 +1057,8 @@ import { select as select2 } from "@inquirer/prompts";
1057
1057
  import chalk3 from "chalk";
1058
1058
 
1059
1059
  // src/lib/dev-setup.ts
1060
+ import { readFileSync as readFileSync7 } from "fs";
1061
+ import { basename, join as join6 } from "path";
1060
1062
  import chalk2 from "chalk";
1061
1063
  import { input, select } from "@inquirer/prompts";
1062
1064
 
@@ -1123,8 +1125,14 @@ function isManagedExpo(cwd, platform) {
1123
1125
  }
1124
1126
  function iosWorkspaceName(cwd) {
1125
1127
  try {
1126
- const found = readdirSync2(join5(cwd, "ios")).find((f) => f.endsWith(".xcworkspace"));
1127
- return found ? found.replace(/\.xcworkspace$/, "") : null;
1128
+ const entries = readdirSync2(join5(cwd, "ios"));
1129
+ const found = entries.find((f) => f.endsWith(".xcworkspace"));
1130
+ if (found) return found.replace(/\.xcworkspace$/, "");
1131
+ const projects = entries.filter((f) => f.endsWith(".xcodeproj"));
1132
+ if (projects.length === 1 && entries.includes("Podfile")) {
1133
+ return projects[0].replace(/\.xcodeproj$/, "");
1134
+ }
1135
+ return null;
1128
1136
  } catch {
1129
1137
  return null;
1130
1138
  }
@@ -1302,6 +1310,12 @@ function installCommand(cwd) {
1302
1310
  const hit = JS_LOCKFILE_INSTALLS.find(([lockfile]) => existsSync3(join5(cwd, lockfile)));
1303
1311
  return hit ? hit[1] : "npm install";
1304
1312
  }
1313
+ function localInstallCommand(cwd) {
1314
+ if (existsSync3(join5(cwd, "yarn.lock"))) return "yarn install";
1315
+ if (existsSync3(join5(cwd, "pnpm-lock.yaml"))) return "pnpm install";
1316
+ if (existsSync3(join5(cwd, "bun.lock")) || existsSync3(join5(cwd, "bun.lockb"))) return "bun install";
1317
+ return "npm install";
1318
+ }
1305
1319
  var JS_LOCKFILE_INSTALLS = [
1306
1320
  ["yarn.lock", "yarn install --immutable"],
1307
1321
  ["pnpm-lock.yaml", "pnpm install --frozen-lockfile"],
@@ -1566,7 +1580,9 @@ var readExpoConfig = (cwd, timeoutMs = EXPO_CONFIG_TIMEOUT_MS) => {
1566
1580
  const cli = join5(cwd, "node_modules", "expo", "bin", "cli");
1567
1581
  if (!existsSync3(cli)) {
1568
1582
  return Promise.reject(
1569
- new Error("Expo isn't installed in this project yet (run your install command first)")
1583
+ new Error(
1584
+ `Expo isn't installed in this project yet. Run \`${localInstallCommand(cwd)}\`, then run this again for a suggested command`
1585
+ )
1570
1586
  );
1571
1587
  }
1572
1588
  return new Promise((resolve, reject) => {
@@ -1770,6 +1786,7 @@ function usesMetroBuild(cwd, platform) {
1770
1786
  const flavor = detectFlavor(cwd);
1771
1787
  return (flavor === "expo" || flavor === "bare-rn") && (platform === "ios" || platform === "android");
1772
1788
  }
1789
+ var SAVED_LINE = " The answer is saved to vibeview.json. Commit it so your team and CI build the same way.";
1773
1790
  function profileIntro(cwd, platform, profile, defaults) {
1774
1791
  const label = platformLabel(platform);
1775
1792
  const metro = usesMetroBuild(cwd, platform);
@@ -1777,7 +1794,7 @@ function profileIntro(cwd, platform, profile, defaults) {
1777
1794
  return [
1778
1795
  `No development build profile for ${label} in vibeview.json yet.`,
1779
1796
  metro ? " development is the debug build VibeView devices run while you code: it loads your JavaScript from Metro (vibeview dev)." : " development is the build VibeView devices run while you work: vibeview build and vibeview dev use it.",
1780
- " The answer is saved to vibeview.json. Commit it so your team and CI build the same way.",
1797
+ SAVED_LINE,
1781
1798
  ` Build profiles: ${PROFILES_DOCS_URL}`
1782
1799
  ];
1783
1800
  }
@@ -1796,20 +1813,22 @@ function profileIntro(cwd, platform, profile, defaults) {
1796
1813
  " Your development build already runs by itself, so the suggestion is the same command."
1797
1814
  );
1798
1815
  }
1799
- lines.push(` Build profiles: ${PROFILES_DOCS_URL}`);
1816
+ lines.push(SAVED_LINE, ` Build profiles: ${PROFILES_DOCS_URL}`);
1800
1817
  return lines;
1801
1818
  }
1802
1819
  if (profile === PRODUCTION) {
1803
1820
  return [
1804
1821
  `No production build profile for ${label} in vibeview.json yet.`,
1805
1822
  " production is the signed build for the stores (.ipa for TestFlight, .aab for Google Play).",
1806
- ` It builds in the cloud with the signing you set up in VibeView: ${SIGNING_DOCS_URL}`
1823
+ ` It builds in the cloud with the signing you set up in VibeView: ${SIGNING_DOCS_URL}`,
1824
+ SAVED_LINE
1807
1825
  ];
1808
1826
  }
1809
1827
  return [
1810
1828
  `No "${profile}" build profile for ${label} in vibeview.json yet.`,
1811
1829
  " A profile of your own makes a build that runs on VibeView devices, like development.",
1812
- ` To make it a signed store build, add "distribution": "production" to it in vibeview.json: ${PROFILES_DOCS_URL}`
1830
+ ` To make it a signed store build, add "distribution": "production" to it in vibeview.json: ${PROFILES_DOCS_URL}`,
1831
+ SAVED_LINE
1813
1832
  ];
1814
1833
  }
1815
1834
  function previewSkippedNote(cwd, platform) {
@@ -1826,6 +1845,13 @@ function previewSavedNote() {
1826
1845
  " GitHub pull requests. Build it with `vibeview build --cloud --profile preview`."
1827
1846
  ];
1828
1847
  }
1848
+ function installTipExample(platform, production) {
1849
+ if (platform === "roku") return "npm ci && npm run package";
1850
+ if (platform === "ios" || platform === "tvos") {
1851
+ return production ? "yarn install --immutable && cd ios && pod install && cd .. && xcodebuild archive \u2026" : "yarn install --immutable && cd ios && pod install && cd .. && xcodebuild \u2026";
1852
+ }
1853
+ return production ? "yarn install --immutable && cd android && ./gradlew bundleRelease" : "yarn install --immutable && cd android && ./gradlew assembleDebug";
1854
+ }
1829
1855
  function commandLabel(profile, platform) {
1830
1856
  return `Build command for ${platformLabel(platform)} (${profile} profile)`;
1831
1857
  }
@@ -1842,7 +1868,8 @@ async function promptProfileConfig(cwd, platform, profile) {
1842
1868
  }
1843
1869
  console.log(
1844
1870
  chalk2.dim(
1845
- " Tip: include your install step \u2014 dependencies are not uploaded.\n" + (production ? " e.g. `yarn install --immutable && cd android && ./gradlew bundleRelease`" : " e.g. `yarn install --immutable && yarn build:android`")
1871
+ ` Tip: include your install step \u2014 dependencies are not uploaded.
1872
+ e.g. \`${installTipExample(platform, production)}\``
1846
1873
  )
1847
1874
  );
1848
1875
  const command = await input({ message: label, required: true });
@@ -1865,6 +1892,20 @@ async function companionPreview(cwd, platform, development) {
1865
1892
  if (!preview.buildCommand || !preview.artifact) return null;
1866
1893
  return { command: preview.buildCommand, artifact: preview.artifact };
1867
1894
  }
1895
+ async function companionDevelopment(cwd, platform, preview) {
1896
+ const suggested = await promptDefaults(cwd, platform, { profile: PREVIEW });
1897
+ if (suggested.buildCommand !== preview.command || suggested.artifact !== preview.artifact)
1898
+ return null;
1899
+ const dev2 = await promptDefaults(cwd, platform);
1900
+ if (!dev2.buildCommand || !dev2.artifact) return null;
1901
+ return { command: dev2.buildCommand, artifact: dev2.artifact };
1902
+ }
1903
+ function developmentSavedNote(cwd, platform) {
1904
+ return usesMetroBuild(cwd, platform) ? [
1905
+ " development is the debug build that loads your JavaScript from Metro while you code",
1906
+ " (vibeview dev). vibeview build uses it when you pass no --profile."
1907
+ ] : [" development is what vibeview build and vibeview dev use when you pass no --profile."];
1908
+ }
1868
1909
  async function promptMetroCommand(cwd, platform) {
1869
1910
  const defaults = defaultsFor(cwd, platform);
1870
1911
  const choice = await commandSelect("Command that starts Metro", defaults.metroCommand);
@@ -1872,12 +1913,42 @@ async function promptMetroCommand(cwd, platform) {
1872
1913
  if (choice === "default") return defaults.metroCommand;
1873
1914
  return input({ message: "Metro command", required: true });
1874
1915
  }
1916
+ var normalizeName = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
1917
+ function projectNames(cwd) {
1918
+ const names = [basename(cwd)];
1919
+ const readJson2 = (file) => {
1920
+ try {
1921
+ return JSON.parse(readFileSync7(join6(cwd, file), "utf-8"));
1922
+ } catch {
1923
+ return null;
1924
+ }
1925
+ };
1926
+ const pkg = readJson2("package.json");
1927
+ if (typeof pkg?.name === "string") names.push(pkg.name.replace(/^@[^/]+\//, ""));
1928
+ const appJson = readJson2("app.json");
1929
+ const expo = appJson?.expo;
1930
+ if (typeof expo?.name === "string") names.push(expo.name);
1931
+ if (typeof appJson?.name === "string") names.push(appJson.name);
1932
+ try {
1933
+ const m = /^name:\s*([\w-]+)/m.exec(readFileSync7(join6(cwd, "pubspec.yaml"), "utf-8"));
1934
+ if (m) names.push(m[1]);
1935
+ } catch {
1936
+ }
1937
+ return new Set(names.map(normalizeName).filter(Boolean));
1938
+ }
1939
+ function rankAppsForProject(apps, cwd) {
1940
+ const names = projectNames(cwd);
1941
+ const nameMatches = (n) => names.has(n) || [...names].some((p) => p.length >= 4 && n.startsWith(p));
1942
+ const matches = (a) => nameMatches(normalizeName(a.name)) || !!a.package_name && names.has(normalizeName(a.package_name.split(".").pop() ?? ""));
1943
+ const first = apps.filter(matches);
1944
+ return { apps: [...first, ...apps.filter((a) => !matches(a))], matched: first.length > 0 };
1945
+ }
1875
1946
 
1876
1947
  // src/lib/source-pack.ts
1877
1948
  import { execFile as execFile3, spawn } from "child_process";
1878
- import { lstatSync, mkdtempSync, readFileSync as readFileSync7, rmSync as rmSync5, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
1949
+ import { lstatSync, mkdtempSync, readFileSync as readFileSync8, rmSync as rmSync5, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
1879
1950
  import { tmpdir } from "os";
1880
- import { join as join6 } from "path";
1951
+ import { join as join7 } from "path";
1881
1952
  import ignore2 from "ignore";
1882
1953
  var NotAGitRepoError = class extends Error {
1883
1954
  constructor(message) {
@@ -1903,15 +1974,15 @@ async function listSourceFiles(projectRoot) {
1903
1974
  const stdout = await runGitLsFiles(projectRoot);
1904
1975
  const rawPaths = stdout.length ? stdout.split("\0").filter((p) => p.length > 0) : [];
1905
1976
  let filtered = rawPaths;
1906
- const vvignorePath = join6(projectRoot, ".vvignore");
1977
+ const vvignorePath = join7(projectRoot, ".vvignore");
1907
1978
  if (statOrNull(vvignorePath)?.isFile()) {
1908
- const ig = ignore2().add(readFileSync7(vvignorePath, "utf-8"));
1979
+ const ig = ignore2().add(readFileSync8(vvignorePath, "utf-8"));
1909
1980
  filtered = filtered.filter((p) => !ig.ignores(p));
1910
1981
  }
1911
1982
  const result = [];
1912
1983
  for (const relPath of filtered) {
1913
1984
  if (isForceExcluded(relPath)) continue;
1914
- const st = statOrNull(join6(projectRoot, relPath));
1985
+ const st = statOrNull(join7(projectRoot, relPath));
1915
1986
  if (!st) continue;
1916
1987
  result.push(relPath);
1917
1988
  }
@@ -1961,7 +2032,7 @@ async function packSource(projectRoot, files, opts = {}) {
1961
2032
  let totalBytes = 0;
1962
2033
  const sized = [];
1963
2034
  for (const relPath of files) {
1964
- const bytes = lstatSync(join6(projectRoot, relPath)).size;
2035
+ const bytes = lstatSync(join7(projectRoot, relPath)).size;
1965
2036
  totalBytes += bytes;
1966
2037
  sized.push({ path: relPath, bytes });
1967
2038
  }
@@ -1972,13 +2043,13 @@ async function packSource(projectRoot, files, opts = {}) {
1972
2043
  largest
1973
2044
  );
1974
2045
  }
1975
- const tmpDir = mkdtempSync(join6(tmpdir(), "vibeview-source-pack-"));
2046
+ const tmpDir = mkdtempSync(join7(tmpdir(), "vibeview-source-pack-"));
1976
2047
  const cleanup = () => rmSync5(tmpDir, { recursive: true, force: true });
1977
2048
  try {
1978
2049
  const supportsNull = await probeTarNullSupport();
1979
- const tarPath = join6(tmpDir, "source.tgz");
2050
+ const tarPath = join7(tmpDir, "source.tgz");
1980
2051
  if (supportsNull) {
1981
- const listPath = join6(tmpDir, "files.list");
2052
+ const listPath = join7(tmpDir, "files.list");
1982
2053
  writeFileSync5(listPath, files.map((f) => `${f}\0`).join(""));
1983
2054
  await runTar(["-czf", tarPath, "-C", projectRoot, "--null", "-T", listPath]);
1984
2055
  } else {
@@ -1988,7 +2059,7 @@ async function packSource(projectRoot, files, opts = {}) {
1988
2059
  `cannot pack source: filename contains a newline (${JSON.stringify(badName)}) and the installed tar doesn't support --null -T; rename the file or install a tar that supports --null`
1989
2060
  );
1990
2061
  }
1991
- const listPath = join6(tmpDir, "files.list");
2062
+ const listPath = join7(tmpDir, "files.list");
1992
2063
  writeFileSync5(listPath, files.map((f) => `${f}
1993
2064
  `).join(""));
1994
2065
  await runTar(["-czf", tarPath, "-C", projectRoot, "-T", listPath]);
@@ -2009,10 +2080,10 @@ var nullSupportCache = null;
2009
2080
  function probeTarNullSupport() {
2010
2081
  if (!nullSupportCache) {
2011
2082
  nullSupportCache = new Promise((resolve) => {
2012
- const tmp = mkdtempSync(join6(tmpdir(), "vibeview-tar-probe-"));
2013
- const listPath = join6(tmp, "empty.list");
2083
+ const tmp = mkdtempSync(join7(tmpdir(), "vibeview-tar-probe-"));
2084
+ const listPath = join7(tmp, "empty.list");
2014
2085
  writeFileSync5(listPath, "");
2015
- const out = join6(tmp, "probe.tgz");
2086
+ const out = join7(tmp, "probe.tgz");
2016
2087
  execFile3("tar", ["-czf", out, "-C", tmp, "--null", "-T", listPath], (err) => {
2017
2088
  rmSync5(tmp, { recursive: true, force: true });
2018
2089
  resolve(!err);
@@ -2079,7 +2150,7 @@ function cloudManifestEntry(platform, profile, opts = {}) {
2079
2150
  // src/lib/build-preflight.ts
2080
2151
  import { execFile as execFile4 } from "child_process";
2081
2152
  import { realpathSync, statSync as statSync4 } from "fs";
2082
- import { dirname as dirname2, isAbsolute, join as join7, relative } from "path";
2153
+ import { dirname as dirname2, isAbsolute, join as join8, relative } from "path";
2083
2154
  import { parse } from "shell-quote";
2084
2155
  var DIRECTORY_CHANGERS = /* @__PURE__ */ new Set(["cd", "pushd"]);
2085
2156
  var DIRECTORY_FLAGS = /^(--cwd|--prefix|--dir|-C)(=|$)/;
@@ -2238,7 +2309,7 @@ function buildCommandWarnings(command, files) {
2238
2309
  missingLockfileWarning(command, files)
2239
2310
  ].filter((w) => w !== null);
2240
2311
  }
2241
- function projectRootHint(cwd, gitRoot, files, hasPackageJson = (dir) => isFile2(join7(dir, "package.json"))) {
2312
+ function projectRootHint(cwd, gitRoot, files, hasPackageJson = (dir) => isFile2(join8(dir, "package.json"))) {
2242
2313
  if (!gitRoot || files.has("package.json")) return null;
2243
2314
  cwd = realPathOr(cwd);
2244
2315
  gitRoot = realPathOr(gitRoot);
@@ -2395,6 +2466,12 @@ async function resolveBuildProfile(cwd, cfgRef, platform, opts) {
2395
2466
  const preview = await companionPreview(cwd, platform, answered);
2396
2467
  if (preview) save[PREVIEW] = preview;
2397
2468
  note = preview ? previewSavedNote() : previewSkippedNote(cwd, platform);
2469
+ } else if (name === PREVIEW && !hasProfile(build, DEVELOPMENT)) {
2470
+ const development = await companionDevelopment(cwd, platform, answered);
2471
+ if (development) {
2472
+ save[DEVELOPMENT] = development;
2473
+ note = developmentSavedNote(cwd, platform);
2474
+ }
2398
2475
  }
2399
2476
  cfgRef.current = persistPromptedProfiles(cwd, platform, save);
2400
2477
  console.error(
@@ -2639,7 +2716,8 @@ async function resolveCloudAppIds(cwd, cfgRef, platforms, opts, listApps) {
2639
2716
  );
2640
2717
  }
2641
2718
  for (const platform of missing) {
2642
- const apps = appsForPlatform(allApps, platform);
2719
+ const ranked = rankAppsForProject(appsForPlatform(allApps, platform), cwd);
2720
+ const apps = ranked.apps;
2643
2721
  if (apps.length === 0) {
2644
2722
  createFromArtifact.add(platform);
2645
2723
  if (!opts.json) {
@@ -2662,13 +2740,19 @@ async function resolveCloudAppIds(cwd, cfgRef, platforms, opts, listApps) {
2662
2740
  // is suppressed there): production builds aren't linked to an app
2663
2741
  // unless the user explicitly wants the link — see APP_PICKER_SENTINEL.
2664
2742
  ...opts.production ? [{ value: APP_PICKER_SENTINEL.DONT_LINK_APP, name: "Don't link an app" }] : [],
2743
+ ...!opts.production && !ranked.matched ? [
2744
+ {
2745
+ value: APP_PICKER_SENTINEL.CREATE_NEW_APP,
2746
+ name: "Create a new app from this build"
2747
+ }
2748
+ ] : [],
2665
2749
  ...apps.map((a) => ({ value: a.public_id, name: a.name })),
2666
2750
  // No create-from-artifact row under --production: a production build
2667
2751
  // never creates an app (internal_builds returns before app creation),
2668
2752
  // so offering it would promise something that can't happen. Picking
2669
2753
  // an EXISTING app is still meaningful — app-scoped signing
2670
2754
  // credentials resolve by app.
2671
- ...opts.production ? [] : [
2755
+ ...opts.production || !ranked.matched ? [] : [
2672
2756
  {
2673
2757
  value: APP_PICKER_SENTINEL.CREATE_NEW_APP,
2674
2758
  name: "Create a new app from this build"
@@ -2762,6 +2846,13 @@ async function runCloudBuildCommand(cwd, cfgRef, opts, deps) {
2762
2846
  if (nodeFlag === null) {
2763
2847
  fail(opts, `--node must be a Node.js major version like 24, got "${opts.node}"`, "usage");
2764
2848
  }
2849
+ if (!deps && !await gitToplevel(cwd)) {
2850
+ fail(
2851
+ opts,
2852
+ `${cwd} is not a git repository \u2014 cloud builds pack your project source via git; run \`git init\` and commit, then try again`,
2853
+ "config_required"
2854
+ );
2855
+ }
2765
2856
  const platforms = await resolveCloudPlatforms(cwd, cfgRef, opts);
2766
2857
  if (opts.xcode !== void 0 && !platforms.some(platformUsesXcode)) {
2767
2858
  fail(
@@ -3219,8 +3310,8 @@ your build command must produce a zip \u2014 use the package/zip step, not deplo
3219
3310
 
3220
3311
  // src/commands/dev.ts
3221
3312
  import { spawn as spawn4 } from "child_process";
3222
- import { closeSync, createWriteStream, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync9 } from "fs";
3223
- import { dirname as dirname5, join as join9 } from "path";
3313
+ import { closeSync, createWriteStream, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync10 } from "fs";
3314
+ import { dirname as dirname5, join as join10 } from "path";
3224
3315
  import { createInterface as createInterface3 } from "readline";
3225
3316
  import { stripVTControlCharacters } from "util";
3226
3317
  import { select as select3 } from "@inquirer/prompts";
@@ -3423,15 +3514,15 @@ import { spawn as spawn3 } from "child_process";
3423
3514
  import { createInterface as createInterface2 } from "readline";
3424
3515
 
3425
3516
  // src/lib/metro-state.ts
3426
- import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync8, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "fs";
3427
- import { dirname as dirname3, join as join8 } from "path";
3517
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync9, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "fs";
3518
+ import { dirname as dirname3, join as join9 } from "path";
3428
3519
  var STATE_DIR2 = ".vibeview";
3429
3520
  var STATE_FILE2 = "metro-state.json";
3430
3521
  function statePath2(cwd) {
3431
- return join8(cwd, STATE_DIR2, STATE_FILE2);
3522
+ return join9(cwd, STATE_DIR2, STATE_FILE2);
3432
3523
  }
3433
3524
  function metroLogPath(cwd) {
3434
- return join8(cwd, STATE_DIR2, "metro.log");
3525
+ return join9(cwd, STATE_DIR2, "metro.log");
3435
3526
  }
3436
3527
  function isPidAlive2(pid) {
3437
3528
  try {
@@ -3449,7 +3540,7 @@ function writeMetroState(cwd, state) {
3449
3540
  function readMetroState(cwd) {
3450
3541
  let parsed;
3451
3542
  try {
3452
- parsed = JSON.parse(readFileSync8(statePath2(cwd), "utf-8"));
3543
+ parsed = JSON.parse(readFileSync9(statePath2(cwd), "utf-8"));
3453
3544
  } catch {
3454
3545
  return null;
3455
3546
  }
@@ -3582,7 +3673,7 @@ async function waitFor(cond, timeoutMs, everyMs) {
3582
3673
 
3583
3674
  // src/lib/reload-loop.ts
3584
3675
  import { watch } from "fs";
3585
- import { basename, dirname as dirname4 } from "path";
3676
+ import { basename as basename2, dirname as dirname4 } from "path";
3586
3677
  function createReloadLoop(deps) {
3587
3678
  let inFlight = null;
3588
3679
  let pendingFollowUp = false;
@@ -3668,9 +3759,9 @@ function isIgnoredWatchPath(relPath, artifact, userIgnore = []) {
3668
3759
  return true;
3669
3760
  }
3670
3761
  if (dirname4(rel) !== artifactDir) return false;
3671
- const name = basename(artifactPattern);
3762
+ const name = basename2(artifactPattern);
3672
3763
  const re = new RegExp(`^${name.split("*").map(escapeRegExp).join(".*")}$`);
3673
- return re.test(basename(rel));
3764
+ return re.test(basename2(rel));
3674
3765
  }
3675
3766
  function escapeRegExp(s) {
3676
3767
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -4957,7 +5048,7 @@ async function dev(opts) {
4957
5048
  if (process.exitCode === 1) return;
4958
5049
  }
4959
5050
  function detachLogPath(cwd) {
4960
- return join9(cwd, ".vibeview", "dev-detach.log");
5051
+ return join10(cwd, ".vibeview", "dev-detach.log");
4961
5052
  }
4962
5053
  function openDetachLog(path) {
4963
5054
  try {
@@ -4971,7 +5062,7 @@ function openDetachLog(path) {
4971
5062
  function lastErrorLine(path) {
4972
5063
  let text;
4973
5064
  try {
4974
- text = readFileSync9(path, "utf-8");
5065
+ text = readFileSync10(path, "utf-8");
4975
5066
  } catch {
4976
5067
  return null;
4977
5068
  }
package/dist/cli.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  runAgentVerb,
36
36
  runStepsNotChecked,
37
37
  stepsNotCheckedLabel
38
- } from "./chunk-AQCZ3UOE.js";
38
+ } from "./chunk-S4VPSFPP.js";
39
39
  import {
40
40
  ApiClient,
41
41
  ApiStatusError,
@@ -58,7 +58,7 @@ import {
58
58
  runCommandParseExitCode,
59
59
  saveConfig,
60
60
  uploadApp
61
- } from "./chunk-42GZ4UEJ.js";
61
+ } from "./chunk-LRPZFDKL.js";
62
62
 
63
63
  // src/cli.ts
64
64
  import { createRequire } from "module";
@@ -4520,7 +4520,7 @@ program.command("dev-reload").description(
4520
4520
  program.command("mcp").description(
4521
4521
  "Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
4522
4522
  ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
4523
- const { runMcpServer } = await import("./server-3D436M2S.js");
4523
+ const { runMcpServer } = await import("./server-5VWZMZRE.js");
4524
4524
  await runMcpServer({ ...opts, version: pkg.version });
4525
4525
  });
4526
4526
  program.command("agent-setup").description(
@@ -35,12 +35,12 @@ import {
35
35
  renderEnvelope,
36
36
  resolveMetro,
37
37
  startDevSession
38
- } from "./chunk-AQCZ3UOE.js";
38
+ } from "./chunk-S4VPSFPP.js";
39
39
  import {
40
40
  ApiClient,
41
41
  NotFoundError,
42
42
  resolveAuth
43
- } from "./chunk-42GZ4UEJ.js";
43
+ } from "./chunk-LRPZFDKL.js";
44
44
 
45
45
  // src/mcp/server.ts
46
46
  import { writeFileSync } from "fs";
@@ -999,7 +999,7 @@ async function handleUploadApp(args, deps) {
999
999
  }
1000
1000
  const name = typeof args.name === "string" && args.name ? args.name : void 0;
1001
1001
  const upload = deps.uploadApp ?? (async (f, n) => {
1002
- const { uploadAppBuild } = await import("./upload-app-DLBU3ZZY.js");
1002
+ const { uploadAppBuild } = await import("./upload-app-OV3QKL7O.js");
1003
1003
  const { result: result2 } = await uploadAppBuild(f, { ...deps.auth, name: n });
1004
1004
  return result2;
1005
1005
  });
@@ -3,7 +3,7 @@ import {
3
3
  describeBuild,
4
4
  uploadApp,
5
5
  uploadAppBuild
6
- } from "./chunk-42GZ4UEJ.js";
6
+ } from "./chunk-LRPZFDKL.js";
7
7
  export {
8
8
  describeBuild,
9
9
  uploadApp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeview",
3
- "version": "0.52.0",
3
+ "version": "0.52.2",
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",