vibeview 0.36.1 → 0.37.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.
package/README.md CHANGED
@@ -34,7 +34,7 @@ vibeview dev
34
34
 
35
35
  [Live Development docs →](https://vibeview.io/docs/live-development)
36
36
 
37
- ## Cloud Builds (beta)
37
+ ## Cloud Builds
38
38
 
39
39
  Build your React Native app on VibeView's build fleet — no Mac, no CI
40
40
  pipeline, no local toolchain:
@@ -838,10 +838,24 @@ function iosWorkspaceName(cwd) {
838
838
  var IOS_ARTIFACT = "ios/build/Build/Products/Debug-iphonesimulator/*.app";
839
839
  var ANDROID_ARTIFACT = "android/app/build/outputs/apk/debug/*.apk";
840
840
  function installCommand(cwd) {
841
- if (existsSync3(join5(cwd, "yarn.lock"))) return "yarn install --immutable";
842
- if (existsSync3(join5(cwd, "pnpm-lock.yaml"))) return "pnpm install --frozen-lockfile";
843
- if (existsSync3(join5(cwd, "package-lock.json"))) return "npm ci";
844
- return "yarn install --immutable";
841
+ const hit = JS_LOCKFILE_INSTALLS.find(([lockfile]) => existsSync3(join5(cwd, lockfile)));
842
+ return hit ? hit[1] : "npm install";
843
+ }
844
+ var JS_LOCKFILE_INSTALLS = [
845
+ ["yarn.lock", "yarn install --immutable"],
846
+ ["pnpm-lock.yaml", "pnpm install --frozen-lockfile"],
847
+ ["package-lock.json", "npm ci"],
848
+ ["npm-shrinkwrap.json", "npm ci"],
849
+ ["bun.lock", "npm install"],
850
+ ["bun.lockb", "npm install"]
851
+ ];
852
+ function bareInstallPrefix(cwd, platform) {
853
+ const legs = [];
854
+ if (isFile(join5(cwd, "package.json"))) legs.push(installCommand(cwd));
855
+ if (platform === "ios" && isFile(join5(cwd, "ios", "Podfile"))) {
856
+ legs.push("cd ios && pod install && cd ..");
857
+ }
858
+ return legs.map((l) => `${l} && `).join("");
845
859
  }
846
860
  function managedExpoAndroidCommand(cwd) {
847
861
  return `${installCommand(cwd)} && npx expo prebuild --platform android --no-install && cd android && ./gradlew assembleDebug`;
@@ -880,7 +894,7 @@ function defaultsFor(cwd, platform) {
880
894
  if (platform === "android") {
881
895
  const managed = isManagedExpo(cwd, "android");
882
896
  return {
883
- buildCommand: managed ? managedExpoAndroidCommand(cwd) : "cd android && ./gradlew assembleDebug",
897
+ buildCommand: managed ? managedExpoAndroidCommand(cwd) : `${bareInstallPrefix(cwd, "android")}cd android && ./gradlew assembleDebug`,
884
898
  artifact: ANDROID_ARTIFACT,
885
899
  metroCommand
886
900
  };
@@ -895,14 +909,14 @@ function defaultsFor(cwd, platform) {
895
909
  }
896
910
  const ws = iosWorkspaceName(cwd);
897
911
  return {
898
- buildCommand: ws ? `xcodebuild -workspace ios/${ws}.xcworkspace -scheme ${ws} -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build` : void 0,
912
+ buildCommand: ws ? `${bareInstallPrefix(cwd, "ios")}xcodebuild -workspace ios/${ws}.xcworkspace -scheme ${ws} -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build CODE_SIGNING_ALLOWED=NO` : void 0,
899
913
  artifact: IOS_ARTIFACT,
900
914
  metroCommand
901
915
  };
902
916
  }
903
917
  var ANDROID_PRODUCTION_ARTIFACT = "android/app/build/outputs/bundle/release/*.aab";
904
918
  function androidProductionCommand(cwd) {
905
- return `${installCommand(cwd)} && cd android && ./gradlew bundleRelease`;
919
+ return `${bareInstallPrefix(cwd, "android")}cd android && ./gradlew bundleRelease`;
906
920
  }
907
921
  var IOS_PRODUCTION_ARTIFACT = "ios/build/*.ipa";
908
922
  function managedExpoAndroidProductionCommand(cwd) {
@@ -951,7 +965,7 @@ function productionDefaultsFor(cwd, platform) {
951
965
  const ws = iosWorkspaceName(cwd);
952
966
  if (!ws) return { artifact: IOS_PRODUCTION_ARTIFACT };
953
967
  return {
954
- buildCommand: `${installCommand(cwd)} && ${iosArchiveExportCommand(ws)}`,
968
+ buildCommand: `${bareInstallPrefix(cwd, "ios")}${iosArchiveExportCommand(ws)}`,
955
969
  artifact: IOS_PRODUCTION_ARTIFACT
956
970
  };
957
971
  }
@@ -1329,6 +1343,203 @@ function runTar(args) {
1329
1343
  });
1330
1344
  }
1331
1345
 
1346
+ // src/lib/build-preflight.ts
1347
+ import { execFile as execFile3 } from "child_process";
1348
+ import { realpathSync, statSync as statSync4 } from "fs";
1349
+ import { dirname as dirname2, isAbsolute, join as join7, relative } from "path";
1350
+ import { parse } from "shell-quote";
1351
+ var DIRECTORY_CHANGERS = /* @__PURE__ */ new Set(["cd", "pushd"]);
1352
+ var DIRECTORY_FLAGS = /^(--cwd|--prefix|--dir|-C)(=|$)/;
1353
+ var VALUE_FLAGS = /^(--cwd|--prefix|--dir|-C|--loglevel|--registry|--workspace|--filter)$/;
1354
+ var GLOBAL_FLAGS = /* @__PURE__ */ new Set(["-g", "--global", "--location=global"]);
1355
+ var SEPARATORS = /* @__PURE__ */ new Set(["&&", "||", ";", ";;", "|", "|&", "&", "(", ")"]);
1356
+ var REDIRECTIONS = /* @__PURE__ */ new Set([">", ">>", "<", ">&", "<&", "&>", "&>>", ">|", "<>"]);
1357
+ var WRAPPERS = /* @__PURE__ */ new Set(["time", "env", "corepack", "command", "exec", "nohup"]);
1358
+ var JS_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["npm", "npx", "yarn", "pnpm", "pnpx", "bun", "bunx"]);
1359
+ var ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
1360
+ function simpleCommands(command) {
1361
+ const out = [];
1362
+ const flush = (words) => {
1363
+ while (words.length > 0 && ASSIGNMENT.test(words[0])) words.shift();
1364
+ while (words.length > 0 && WRAPPERS.has(words[0])) {
1365
+ words.shift();
1366
+ while (words.length > 0 && (words[0].startsWith("-") || ASSIGNMENT.test(words[0]))) {
1367
+ words.shift();
1368
+ }
1369
+ }
1370
+ if (words.length === 0) return;
1371
+ const base = words[0].replace(/@[^/]*$/, "");
1372
+ const program = JS_PACKAGE_MANAGERS.has(base) ? base : words[0];
1373
+ out.push({ program, args: words.slice(1) });
1374
+ };
1375
+ for (const line of command.replace(/\\\r?\n/g, " ").split(/\r?\n/)) {
1376
+ let tokens;
1377
+ try {
1378
+ tokens = parse(line, (name) => `$${name}`);
1379
+ } catch {
1380
+ continue;
1381
+ }
1382
+ let words = [];
1383
+ let redirectTarget = false;
1384
+ for (const t of tokens) {
1385
+ if (typeof t === "string") {
1386
+ if (redirectTarget) {
1387
+ redirectTarget = false;
1388
+ continue;
1389
+ }
1390
+ if (t === "{" || t === "}") flush(words.splice(0));
1391
+ else if (t.length > 0) words.push(t);
1392
+ } else if ("comment" in t) {
1393
+ break;
1394
+ } else if ("op" in t && t.op === "glob") {
1395
+ words.push(t.pattern);
1396
+ } else if ("op" in t && SEPARATORS.has(t.op)) {
1397
+ flush(words);
1398
+ words = [];
1399
+ } else if ("op" in t && REDIRECTIONS.has(t.op)) {
1400
+ if (words.length > 1 && /^\d+$/.test(words[words.length - 1])) words.pop();
1401
+ redirectTarget = true;
1402
+ }
1403
+ }
1404
+ flush(words);
1405
+ }
1406
+ return out;
1407
+ }
1408
+ function positionals(args) {
1409
+ const out = [];
1410
+ for (let i = 0; i < args.length; i++) {
1411
+ const a = args[i];
1412
+ if (a.startsWith("-")) {
1413
+ if (VALUE_FLAGS.test(a)) i++;
1414
+ continue;
1415
+ }
1416
+ out.push(a);
1417
+ }
1418
+ return out;
1419
+ }
1420
+ var isGlobal = (args) => args.some((a) => GLOBAL_FLAGS.has(a));
1421
+ var VERSION_OR_HELP = /* @__PURE__ */ new Set(["-v", "--version", "-h", "--help"]);
1422
+ var NPM_INSTALL_VERBS = /* @__PURE__ */ new Set([
1423
+ "ci",
1424
+ "clean-install",
1425
+ "install-clean",
1426
+ "install",
1427
+ "i",
1428
+ "add",
1429
+ "install-test",
1430
+ "it"
1431
+ ]);
1432
+ var NEEDS_MANIFEST_VERBS = /* @__PURE__ */ new Set([
1433
+ "ci",
1434
+ "clean-install",
1435
+ "install-clean",
1436
+ "install-test",
1437
+ "it",
1438
+ "run",
1439
+ "run-script"
1440
+ ]);
1441
+ function installsInStep({ program, args }) {
1442
+ if (isGlobal(args)) return false;
1443
+ const [verb, ...rest] = positionals(args);
1444
+ if (program === "yarn") {
1445
+ if (verb === void 0) return !args.some((a) => VERSION_OR_HELP.has(a));
1446
+ if (verb === "install" || verb === "add") return true;
1447
+ return verb === "workspaces" && rest[0] === "focus";
1448
+ }
1449
+ if (program === "npm" || program === "pnpm" || program === "bun") {
1450
+ return verb !== void 0 && NPM_INSTALL_VERBS.has(verb);
1451
+ }
1452
+ return false;
1453
+ }
1454
+ function needsManifest({ program, args }) {
1455
+ if (isGlobal(args) || args.some((a) => DIRECTORY_FLAGS.test(a))) return false;
1456
+ const [verb, ...rest] = positionals(args);
1457
+ if (program === "yarn") {
1458
+ if (verb === void 0) return !args.some((a) => VERSION_OR_HELP.has(a));
1459
+ if (verb === "install" || verb === "run") return true;
1460
+ return verb === "workspaces" && rest[0] === "focus";
1461
+ }
1462
+ if (program === "npm" || program === "pnpm" || program === "bun") {
1463
+ if (verb === void 0) return false;
1464
+ if (NEEDS_MANIFEST_VERBS.has(verb)) return true;
1465
+ return (verb === "install" || verb === "i") && rest.length === 0;
1466
+ }
1467
+ return false;
1468
+ }
1469
+ function packageManagerAtRoot(command) {
1470
+ for (const step of simpleCommands(command)) {
1471
+ if (DIRECTORY_CHANGERS.has(step.program)) return null;
1472
+ if (JS_PACKAGE_MANAGERS.has(step.program) && positionals(step.args)[0] === "init") return null;
1473
+ if (needsManifest(step)) return step.program;
1474
+ }
1475
+ return null;
1476
+ }
1477
+ function installsDependencies(command) {
1478
+ return simpleCommands(command).some(installsInStep);
1479
+ }
1480
+ function missingPackageJsonError(command, files, dir) {
1481
+ const pm = packageManagerAtRoot(command);
1482
+ if (!pm || files.has("package.json")) return null;
1483
+ return `No package.json in ${dir}. Run vibeview build from your project root. (Your build command runs \`${pm}\` there; nothing was uploaded or charged.)`;
1484
+ }
1485
+ function missingInstallWarning(command, files) {
1486
+ const hit = JS_LOCKFILE_INSTALLS.find(([lockfile]) => files.has(lockfile));
1487
+ if (!hit || files.has(".pnp.cjs") || installsDependencies(command)) return null;
1488
+ return `Your build command doesn't install dependencies; node_modules is never uploaded, so the build will likely fail. Add \`${hit[1]} &&\` at the start.`;
1489
+ }
1490
+ function missingLockfileWarning(command, files) {
1491
+ if (!files.has("package.json")) return null;
1492
+ if (JS_LOCKFILE_INSTALLS.some(([lockfile]) => files.has(lockfile))) return null;
1493
+ if (!installsDependencies(command)) return null;
1494
+ return "No lockfile in the upload (yarn.lock, package-lock.json, pnpm-lock.yaml): a frozen install (`npm ci`, `--immutable`, `--frozen-lockfile`) will fail, and any other install resolves fresh versions. Commit your lockfile, or run vibeview build from the directory that has it.";
1495
+ }
1496
+ function bunWarning(command) {
1497
+ const step = simpleCommands(command).find((s) => s.program === "bun" || s.program === "bunx");
1498
+ if (!step) return null;
1499
+ return `Your build command runs \`${step.program}\`, but cloud builders don't have Bun, so that step will fail unless your command installs Bun first. Use npm, yarn or pnpm instead.`;
1500
+ }
1501
+ function buildCommandWarnings(command, files) {
1502
+ return [
1503
+ bunWarning(command),
1504
+ missingInstallWarning(command, files),
1505
+ missingLockfileWarning(command, files)
1506
+ ].filter((w) => w !== null);
1507
+ }
1508
+ function projectRootHint(cwd, gitRoot, files, hasPackageJson = (dir) => isFile2(join7(dir, "package.json"))) {
1509
+ if (!gitRoot || files.has("package.json")) return null;
1510
+ cwd = realPathOr(cwd);
1511
+ gitRoot = realPathOr(gitRoot);
1512
+ const rel = relative(gitRoot, cwd);
1513
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) return null;
1514
+ for (let dir = dirname2(cwd); ; dir = dirname2(dir)) {
1515
+ if (hasPackageJson(dir)) {
1516
+ return `You're running from ${cwd}; the project root looks like ${dir}. Only ${cwd} will be uploaded.`;
1517
+ }
1518
+ if (dir === gitRoot || dir === dirname2(dir)) return null;
1519
+ }
1520
+ }
1521
+ function realPathOr(path) {
1522
+ try {
1523
+ return realpathSync(path);
1524
+ } catch {
1525
+ return path;
1526
+ }
1527
+ }
1528
+ function isFile2(path) {
1529
+ try {
1530
+ return statSync4(path).isFile();
1531
+ } catch {
1532
+ return false;
1533
+ }
1534
+ }
1535
+ async function gitToplevel(cwd) {
1536
+ return new Promise((resolve) => {
1537
+ execFile3("git", ["rev-parse", "--show-toplevel"], { cwd }, (err, stdout) => {
1538
+ resolve(err ? null : stdout.trim() || null);
1539
+ });
1540
+ });
1541
+ }
1542
+
1332
1543
  // src/commands/build.ts
1333
1544
  var CLOUD_PLATFORMS = ["ios", "android", "tvos", "androidtv"];
1334
1545
  var PRODUCTION_SIGNING_PLATFORMS = ["ios", "android", "androidtv", "tvos"];
@@ -1795,6 +2006,25 @@ async function runCloudBuildCommand(cwd, cfgRef, opts, deps) {
1795
2006
  }
1796
2007
  throw err;
1797
2008
  }
2009
+ const uploaded = new Set(files);
2010
+ const warnings = /* @__PURE__ */ new Map();
2011
+ for (const p of platforms) {
2012
+ const command = productionBuilds.get(p)?.command ?? cfg.platforms[p].build.command;
2013
+ const missingPkg = missingPackageJsonError(command, uploaded, cwd);
2014
+ if (missingPkg) fail(opts, missingPkg, "no_package_json");
2015
+ for (const w of buildCommandWarnings(command, uploaded)) {
2016
+ warnings.set(w, [...warnings.get(w) ?? [], p]);
2017
+ }
2018
+ }
2019
+ const rootHint = projectRootHint(cwd, await (d.gitToplevel ?? gitToplevel)(cwd), uploaded);
2020
+ if (rootHint) warnings.set(rootHint, [...platforms]);
2021
+ for (const [message, ps] of warnings) {
2022
+ for (const p of ps) emitCloud(opts.json, { event: "warning", platform: p, message });
2023
+ if (!opts.json) {
2024
+ const prefix = platforms.length > 1 && ps.length < platforms.length ? `${ps.join(", ")}: ` : "";
2025
+ console.error(chalk3.yellow(`\u26A0 ${prefix}${message}`));
2026
+ }
2027
+ }
1798
2028
  const packSpinner = !opts.json ? createSpinner(`packing source (${files.length} files)`) : null;
1799
2029
  packSpinner?.start();
1800
2030
  let tarPath;
@@ -2173,7 +2403,7 @@ your build command must produce a zip \u2014 use the package/zip step, not deplo
2173
2403
  // src/commands/dev.ts
2174
2404
  import { spawn as spawn4 } from "child_process";
2175
2405
  import { createWriteStream, mkdirSync as mkdirSync5 } from "fs";
2176
- import { dirname as dirname4 } from "path";
2406
+ import { dirname as dirname5 } from "path";
2177
2407
  import { createInterface as createInterface3 } from "readline";
2178
2408
  import { select as select3 } from "@inquirer/prompts";
2179
2409
  import chalk4 from "chalk";
@@ -2376,14 +2606,14 @@ import { createInterface as createInterface2 } from "readline";
2376
2606
 
2377
2607
  // src/lib/metro-state.ts
2378
2608
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync7, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "fs";
2379
- import { dirname as dirname2, join as join7 } from "path";
2609
+ import { dirname as dirname3, join as join8 } from "path";
2380
2610
  var STATE_DIR2 = ".vibeview";
2381
2611
  var STATE_FILE2 = "metro-state.json";
2382
2612
  function statePath2(cwd) {
2383
- return join7(cwd, STATE_DIR2, STATE_FILE2);
2613
+ return join8(cwd, STATE_DIR2, STATE_FILE2);
2384
2614
  }
2385
2615
  function metroLogPath(cwd) {
2386
- return join7(cwd, STATE_DIR2, "metro.log");
2616
+ return join8(cwd, STATE_DIR2, "metro.log");
2387
2617
  }
2388
2618
  function isPidAlive2(pid) {
2389
2619
  try {
@@ -2395,7 +2625,7 @@ function isPidAlive2(pid) {
2395
2625
  }
2396
2626
  function writeMetroState(cwd, state) {
2397
2627
  const path = statePath2(cwd);
2398
- mkdirSync4(dirname2(path), { recursive: true });
2628
+ mkdirSync4(dirname3(path), { recursive: true });
2399
2629
  writeFileSync6(path, JSON.stringify(state, null, 2) + "\n");
2400
2630
  }
2401
2631
  function readMetroState(cwd) {
@@ -2534,7 +2764,7 @@ async function waitFor(cond, timeoutMs, everyMs) {
2534
2764
 
2535
2765
  // src/lib/reload-loop.ts
2536
2766
  import { watch } from "fs";
2537
- import { basename, dirname as dirname3 } from "path";
2767
+ import { basename, dirname as dirname4 } from "path";
2538
2768
  function createReloadLoop(deps) {
2539
2769
  let inFlight = null;
2540
2770
  let pendingFollowUp = false;
@@ -2615,11 +2845,11 @@ function isIgnoredWatchPath(relPath, artifact, userIgnore = []) {
2615
2845
  if (IGNORED_FILES.includes(rel)) return true;
2616
2846
  if (userIgnore.some((entry) => isUnderPath(rel, entry))) return true;
2617
2847
  const artifactPattern = artifact.replace(/\\/g, "/").replace(/^\.\//, "");
2618
- const artifactDir = dirname3(artifactPattern);
2848
+ const artifactDir = dirname4(artifactPattern);
2619
2849
  if (artifactDir !== "." && (rel === artifactDir || rel.startsWith(`${artifactDir}/`))) {
2620
2850
  return true;
2621
2851
  }
2622
- if (dirname3(rel) !== artifactDir) return false;
2852
+ if (dirname4(rel) !== artifactDir) return false;
2623
2853
  const name = basename(artifactPattern);
2624
2854
  const re = new RegExp(`^${name.split("*").map(escapeRegExp).join(".*")}$`);
2625
2855
  return re.test(basename(rel));
@@ -3497,7 +3727,7 @@ async function runDevInProcess(opts) {
3497
3727
  const captureMetroLine = (line) => {
3498
3728
  try {
3499
3729
  if (!metroLogStream) {
3500
- mkdirSync5(dirname4(metroLogPath(process.cwd())), { recursive: true });
3730
+ mkdirSync5(dirname5(metroLogPath(process.cwd())), { recursive: true });
3501
3731
  metroLogStream = createWriteStream(metroLogPath(process.cwd()), { flags: "w" });
3502
3732
  }
3503
3733
  metroLogStream.write(line.replace(/^\[metro\] /, "") + "\n");
@@ -4618,9 +4848,9 @@ function flagKey(cli) {
4618
4848
  const name = cli.replace(/^--/, "");
4619
4849
  return name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
4620
4850
  }
4621
- function buildToolCall(cmd, positionals, opts) {
4851
+ function buildToolCall(cmd, positionals2, opts) {
4622
4852
  if (cmd.verb === "tap") {
4623
- const target = positionals[0];
4853
+ const target = positionals2[0];
4624
4854
  if (!target) throw new Error('tap requires a target: an element ref (@e5) or "x,y"');
4625
4855
  const coords = parseCoords(target);
4626
4856
  if (coords) {
@@ -4635,7 +4865,7 @@ function buildToolCall(cmd, positionals, opts) {
4635
4865
  return { tool: "tap", args: { ref: stripRef(target) } };
4636
4866
  }
4637
4867
  if (cmd.verb === "long-press") {
4638
- const target = positionals[0];
4868
+ const target = positionals2[0];
4639
4869
  if (!target) throw new Error("long-press requires a ref, e.g. @e5");
4640
4870
  if (parseCoords(target) || target.includes(",") && !REF_RE.test(target)) {
4641
4871
  throw new Error(
@@ -4649,8 +4879,8 @@ function buildToolCall(cmd, positionals, opts) {
4649
4879
  return { tool: cmd.tool, args: args2 };
4650
4880
  }
4651
4881
  if (cmd.verb === "drag") {
4652
- const from = positionals[0];
4653
- const to = positionals[1];
4882
+ const from = positionals2[0];
4883
+ const to = positionals2[1];
4654
4884
  if (!from || !to) {
4655
4885
  throw new Error('drag requires two targets: <from> <to>, each an element ref (@e5) or "x,y"');
4656
4886
  }
@@ -4691,7 +4921,7 @@ function buildToolCall(cmd, positionals, opts) {
4691
4921
  return { tool: cmd.tool, args: args2 };
4692
4922
  }
4693
4923
  if (cmd.verb === "scroll") {
4694
- const direction = positionals[0];
4924
+ const direction = positionals2[0];
4695
4925
  const valid = ["up", "down", "left", "right"];
4696
4926
  if (!direction || !valid.includes(direction)) {
4697
4927
  throw new Error(`scroll: direction must be one of ${valid.join(", ")}, got "${direction}"`);
@@ -4699,7 +4929,7 @@ function buildToolCall(cmd, positionals, opts) {
4699
4929
  return { tool: cmd.tool, args: { name: `scroll_${direction}` } };
4700
4930
  }
4701
4931
  if (cmd.verb === "swipe") {
4702
- const direction = positionals[0];
4932
+ const direction = positionals2[0];
4703
4933
  const valid = ["up", "down", "left", "right"];
4704
4934
  if (!direction || !valid.includes(direction)) {
4705
4935
  throw new Error(`swipe: direction must be one of ${valid.join(", ")}, got "${direction}"`);
@@ -4711,7 +4941,7 @@ function buildToolCall(cmd, positionals, opts) {
4711
4941
  return { tool: cmd.tool, args: args2 };
4712
4942
  }
4713
4943
  if (cmd.verb === "set-posture") {
4714
- const hasPosture = positionals[0] !== void 0 && positionals[0] !== "";
4944
+ const hasPosture = positionals2[0] !== void 0 && positionals2[0] !== "";
4715
4945
  const hasAngle = opts.angle !== void 0 && opts.angle !== "";
4716
4946
  if (hasPosture === hasAngle) {
4717
4947
  throw new FlagError(
@@ -4724,7 +4954,7 @@ function buildToolCall(cmd, positionals, opts) {
4724
4954
  for (const param of cmd.params) {
4725
4955
  let raw;
4726
4956
  if (param.cli === "positional") {
4727
- raw = positionals[positionalIndex];
4957
+ raw = positionals2[positionalIndex];
4728
4958
  positionalIndex += 1;
4729
4959
  } else {
4730
4960
  const key = flagKey(param.cli);
@@ -4774,7 +5004,7 @@ var NON_USE_TOOLS = /* @__PURE__ */ new Set([
4774
5004
  function countsAsUse(tool) {
4775
5005
  return !NON_USE_TOOLS.has(tool);
4776
5006
  }
4777
- async function runAgentVerb(cmd, positionals, opts) {
5007
+ async function runAgentVerb(cmd, positionals2, opts) {
4778
5008
  const { token, baseUrl } = resolveAuth(opts);
4779
5009
  const sessionId = opts.session || readDevState(process.cwd())?.session_id;
4780
5010
  if (!sessionId) {
@@ -4783,7 +5013,7 @@ async function runAgentVerb(cmd, positionals, opts) {
4783
5013
  }
4784
5014
  let call;
4785
5015
  try {
4786
- call = buildToolCall(cmd, positionals, opts);
5016
+ call = buildToolCall(cmd, positionals2, opts);
4787
5017
  } catch (err) {
4788
5018
  process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}
4789
5019
  `);
package/dist/cli.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  readMetroState,
26
26
  recordDevUse,
27
27
  runAgentVerb
28
- } from "./chunk-VFCG4U7V.js";
28
+ } from "./chunk-6LNOXEPC.js";
29
29
  import {
30
30
  ApiClient,
31
31
  ApiStatusError,
@@ -4147,7 +4147,7 @@ program.command("dev-reload").description(
4147
4147
  program.command("mcp").description(
4148
4148
  "Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
4149
4149
  ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
4150
- const { runMcpServer } = await import("./server-2CDIRTBV.js");
4150
+ const { runMcpServer } = await import("./server-QRIH34XN.js");
4151
4151
  await runMcpServer({ ...opts, version: pkg.version });
4152
4152
  });
4153
4153
  program.command("agent-setup").description(
@@ -28,7 +28,7 @@ import {
28
28
  renderEnvelope,
29
29
  resolveMetro,
30
30
  startDevSession
31
- } from "./chunk-VFCG4U7V.js";
31
+ } from "./chunk-6LNOXEPC.js";
32
32
  import {
33
33
  ApiClient,
34
34
  NotFoundError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeview",
3
- "version": "0.36.1",
3
+ "version": "0.37.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",
@@ -33,11 +33,13 @@
33
33
  "ignore": "^7.0.0",
34
34
  "open": "^11.0.0",
35
35
  "ora": "^9.0.0",
36
+ "shell-quote": "^1.8.3",
36
37
  "ws": "^8.18.0",
37
38
  "zod": "^4.0.0"
38
39
  },
39
40
  "devDependencies": {
40
41
  "@types/node": "^20.0.0",
42
+ "@types/shell-quote": "^1.7.5",
41
43
  "@types/ws": "^8.5.0",
42
44
  "dotenv": "^16.4.5",
43
45
  "tsup": "^8.0.0",