vibeview 0.40.0 → 0.41.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/dist/cli.js CHANGED
@@ -657,11 +657,13 @@ function formatToolCall(tc) {
657
657
  function runStartedLine(evt) {
658
658
  const steps = `${evt.total_steps} step(s)`;
659
659
  const model = chalk2.bold(evt.model || "default");
660
- if (evt.mode === "replay") return `${chalk2.cyan("\u25B6")} Replay started \u2014 ${steps} (no AI)`;
660
+ if (evt.mode === "replay") {
661
+ return `${chalk2.cyan("\u25B6")} No AI run started \u2014 ${steps}, replays only (no AI)`;
662
+ }
661
663
  if (evt.mode === "hybrid") {
662
- return `${chalk2.cyan("\u25B6")} Hybrid test started \u2014 ${steps}, replaying the recording, AI fallback model: ${model}`;
664
+ return `${chalk2.cyan("\u25B6")} Smart run started \u2014 ${steps}, replays recorded and learned paths, AI where needed (model: ${model})`;
663
665
  }
664
- return `${chalk2.cyan("\u25B6")} AI test started \u2014 ${steps}, model: ${model}`;
666
+ return `${chalk2.cyan("\u25B6")} AI only run started \u2014 ${steps}, model: ${model}`;
665
667
  }
666
668
  function displayProgressEvent(evt, ctx) {
667
669
  const { spinner } = ctx;
@@ -775,6 +777,37 @@ function parseRunPlatform(value) {
775
777
  }
776
778
  return value;
777
779
  }
780
+ var RUN_MODES = ["hybrid", "ai", "replay"];
781
+ function parseRunMode(value) {
782
+ if (value === void 0) return void 0;
783
+ if (!RUN_MODES.includes(value)) {
784
+ throw new Error(
785
+ `--mode must be one of ${RUN_MODES.join(", ")} (Smart, AI only, No AI), got "${value}"`
786
+ );
787
+ }
788
+ return value;
789
+ }
790
+ var MAX_TIMEOUT_S = 7200;
791
+ var POSITIVE_INT = /^[1-9][0-9]*$/;
792
+ function parseTimeoutSeconds(value) {
793
+ const n = POSITIVE_INT.test(value.trim()) ? Number(value.trim()) : NaN;
794
+ if (!Number.isSafeInteger(n) || n < 1 || n > MAX_TIMEOUT_S) {
795
+ throw new Error(
796
+ `--timeout must be a whole number of seconds from 1 to ${MAX_TIMEOUT_S}, got "${value}"`
797
+ );
798
+ }
799
+ return n;
800
+ }
801
+ function parseBuildId(value) {
802
+ if (value === void 0) return void 0;
803
+ const n = POSITIVE_INT.test(value.trim()) ? Number(value.trim()) : NaN;
804
+ if (!Number.isSafeInteger(n)) {
805
+ throw new Error(
806
+ `--build must be a build id (a positive whole number, see \`vibeview list-builds\`), got "${value}"`
807
+ );
808
+ }
809
+ return n;
810
+ }
778
811
  function refusePlatformWithApp(options) {
779
812
  if (options.platform && options.app) {
780
813
  throw new Error(
@@ -4079,11 +4112,27 @@ function resolveMetadata(opts) {
4079
4112
  process.exit(2);
4080
4113
  }
4081
4114
  }
4115
+ function parseRunFlags(opts) {
4116
+ try {
4117
+ return {
4118
+ mode: parseRunMode(opts.mode),
4119
+ timeout: parseTimeoutSeconds(opts.timeout),
4120
+ build: parseBuildId(opts.build)
4121
+ };
4122
+ } catch (err) {
4123
+ process.stderr.write(`error: ${err.message}
4124
+ `);
4125
+ process.exit(2);
4126
+ }
4127
+ }
4082
4128
  var program = new Command();
4083
4129
  program.name("vibeview").description(
4084
4130
  "VibeView CLI -- run your app on cloud iOS simulators, Android emulators, Apple TV, Android TV and Roku devices: a React Native dev loop (dev), device control for you or your coding agent (ui-tree, tap, mcp), and tests from CI (run-test, run-suites)"
4085
4131
  ).version(pkg.version);
4086
- program.command("run-suite <suite-id>").description("Run all test cases in a suite").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-case breakdown", false).option("--timeout <seconds>", "Max wait time in seconds (queue wait plus execution)", "1800").option("--commit-sha <sha>", "Git commit SHA for GitHub status checks").option("--model <model>", "AI model to use").option("--provider <provider>", "AI provider").option("--mode <mode>", "Execution mode: hybrid, ai, replay").option(
4132
+ program.command("run-suite <suite-id>").description("Run all test cases in a suite").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-case breakdown", false).option("--timeout <seconds>", "Max wait time in seconds (queue wait plus execution)", "1800").option("--commit-sha <sha>", "Git commit SHA for GitHub status checks").option("--model <model>", "AI model to use").option("--provider <provider>", "AI provider").option(
4133
+ "--mode <mode>",
4134
+ "Execution mode: hybrid (Smart, the default), ai (AI only), replay (No AI)"
4135
+ ).option(
4087
4136
  "--device-category <category>",
4088
4137
  "Device category: phone, tablet, tv (default: tv for a TV platform, else phone)",
4089
4138
  parseDeviceCategory
@@ -4112,12 +4161,12 @@ program.command("run-suite <suite-id>").description("Run all test cases in a sui
4112
4161
  `);
4113
4162
  process.exit(2);
4114
4163
  }
4164
+ const runFlags = parseRunFlags(opts);
4115
4165
  const metadata = resolveMetadata(opts);
4116
4166
  return runSuite(suiteId, {
4117
4167
  ...opts,
4118
4168
  metadata,
4119
- timeout: parseInt(opts.timeout, 10),
4120
- build: opts.build ? parseInt(opts.build, 10) : void 0
4169
+ ...runFlags
4121
4170
  });
4122
4171
  });
4123
4172
  program.command("run-suites").description("Run all suites matching a tag filter").requiredOption(
@@ -4128,7 +4177,10 @@ program.command("run-suites").description("Run all suites matching a tag filter"
4128
4177
  ).option("--match <mode>", "any (default) or all", "any").option(
4129
4178
  "--platform <platform>",
4130
4179
  "Filter matched suites to one platform: ios, android, tvos, androidtv, roku (default: no filter)"
4131
- ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-suite progress", false).option("--timeout <seconds>", "Per-suite timeout, capped at 2 hours total", "1800").option("--commit-sha <sha>", "Git commit SHA propagated to every SuiteRun").option("--model <model>", "AI model").option("--provider <provider>", "AI provider").option("--mode <mode>", "Execution mode: hybrid, ai, replay").option(
4180
+ ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-suite progress", false).option("--timeout <seconds>", "Per-suite timeout, capped at 2 hours total", "1800").option("--commit-sha <sha>", "Git commit SHA propagated to every SuiteRun").option("--model <model>", "AI model").option("--provider <provider>", "AI provider").option(
4181
+ "--mode <mode>",
4182
+ "Execution mode: hybrid (Smart, the default), ai (AI only), replay (No AI)"
4183
+ ).option(
4132
4184
  "--device-category <category>",
4133
4185
  "Device category: phone, tablet, tv (default: tv for a TV platform, else phone)",
4134
4186
  parseDeviceCategory
@@ -4150,15 +4202,18 @@ program.command("run-suites").description("Run all suites matching a tag filter"
4150
4202
  `);
4151
4203
  process.exit(2);
4152
4204
  }
4205
+ const runFlags = parseRunFlags(opts);
4153
4206
  const metadata = resolveMetadata(opts);
4154
4207
  return runSuites({
4155
4208
  ...opts,
4156
4209
  metadata,
4157
- timeout: parseInt(opts.timeout, 10),
4158
- build: opts.build ? parseInt(opts.build, 10) : void 0
4210
+ ...runFlags
4159
4211
  });
4160
4212
  });
4161
- program.command("run-test <test-id>").description("Run a single test case").option("--token <token>", "API token").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show step details", false).option("--timeout <seconds>", "Max wait time in seconds (queue wait plus execution)", "1800").option("--commit-sha <sha>", "Git commit SHA for GitHub status checks").option("--model <model>", "AI model to use").option("--provider <provider>", "AI provider").option("--mode <mode>", "Execution mode: hybrid, ai, replay").option(
4213
+ program.command("run-test <test-id>").description("Run a single test case").option("--token <token>", "API token").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show step details", false).option("--timeout <seconds>", "Max wait time in seconds (queue wait plus execution)", "1800").option("--commit-sha <sha>", "Git commit SHA for GitHub status checks").option("--model <model>", "AI model to use").option("--provider <provider>", "AI provider").option(
4214
+ "--mode <mode>",
4215
+ "Execution mode: hybrid (Smart, the default), ai (AI only), replay (No AI)"
4216
+ ).option(
4162
4217
  "--device-category <category>",
4163
4218
  "Device category: phone, tablet, tv (default: tv for a TV platform, else phone)",
4164
4219
  parseDeviceCategory
@@ -4187,12 +4242,12 @@ program.command("run-test <test-id>").description("Run a single test case").opti
4187
4242
  `);
4188
4243
  process.exit(2);
4189
4244
  }
4245
+ const runFlags = parseRunFlags(opts);
4190
4246
  const metadata = resolveMetadata(opts);
4191
4247
  return runTest(testId, {
4192
4248
  ...opts,
4193
4249
  metadata,
4194
- timeout: parseInt(opts.timeout, 10),
4195
- build: opts.build ? parseInt(opts.build, 10) : void 0
4250
+ ...runFlags
4196
4251
  });
4197
4252
  });
4198
4253
  program.command("list-suites").description("List available test suites").option("--token <token>", "API token").option("--output <format>", "Output format: human, json", "human").option(
@@ -4406,7 +4461,7 @@ program.command("dev-reload").description(
4406
4461
  program.command("mcp").description(
4407
4462
  "Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
4408
4463
  ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
4409
- const { runMcpServer } = await import("./server-56MR4KJW.js");
4464
+ const { runMcpServer } = await import("./server-435X37GD.js");
4410
4465
  await runMcpServer({ ...opts, version: pkg.version });
4411
4466
  });
4412
4467
  program.command("agent-setup").description(
@@ -48,7 +48,7 @@ var SESSION_ID_PROPERTY = {
48
48
  };
49
49
  var AI_USE_PROPERTY = {
50
50
  type: "string",
51
- description: "smart (default): replays saved paths and uses AI only where the screen changed; no_ai: replays only, no usage credit; ai_only: the AI does every step.",
51
+ description: "smart (default): replays recorded and learned paths, and uses AI only where the screen changed or a step has no path yet; no_ai: replays only, no AI and no usage credit (a step with no path is not checked); ai_only: the AI does every step.",
52
52
  enum: ["smart", "no_ai", "ai_only"]
53
53
  };
54
54
  var AI_USE_MODE = { smart: "hybrid", no_ai: "replay", ai_only: "ai" };
@@ -461,12 +461,25 @@ function formatRunForAgent(run) {
461
461
  lines.push(head);
462
462
  for (const r of lane.runs ?? []) {
463
463
  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
- const q = r.kind === "test" && quarantinedFailure(r.tests?.[0] ?? {}) ? " (quarantined)" : "";
464
+ const cell = r.kind === "test" ? r.tests?.[0] ?? {} : {};
465
+ const q = r.kind === "test" && quarantinedFailure(cell) ? " (quarantined)" : "";
466
+ const why = r.error_message || cell.not_run_reason;
467
+ const unchecked = r.kind === "test" ? notCheckedNote(outcomeOf(cell), cell.steps_not_checked) : "";
465
468
  lines.push(
466
- ` ${r.name}: ${agentStatus(r)}${q}${count}${r.error_message ? ` \u2014 ${r.error_message}` : ""}`
469
+ ` ${r.name}: ${agentStatus(r)}${q}${count}${why ? ` \u2014 ${why}` : ""}${unchecked}`
467
470
  );
468
471
  if (r.kind !== "group") continue;
469
472
  for (const t of r.tests ?? []) {
473
+ if (t.status === "not_run") {
474
+ const reason = t.not_run_reason || t.error_message;
475
+ lines.push(` ${t.name}: not run${reason ? ` \u2014 ${reason}` : ""}`);
476
+ continue;
477
+ }
478
+ const note = notCheckedNote(outcomeOf(t), t.steps_not_checked);
479
+ if (note) {
480
+ lines.push(` ${t.name}: ${agentStatus(t)}${note}`);
481
+ continue;
482
+ }
470
483
  if (t.status !== "failed" && t.status !== "error") continue;
471
484
  const tq = quarantinedFailure(t) ? " (quarantined)" : "";
472
485
  lines.push(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeview",
3
- "version": "0.40.0",
3
+ "version": "0.41.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",