vibeview 0.44.0 → 0.46.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.
|
@@ -796,6 +796,90 @@ function describeLocalChanges(before, after) {
|
|
|
796
796
|
|
|
797
797
|
// src/commands/build.ts
|
|
798
798
|
import { spawn as spawn2 } from "child_process";
|
|
799
|
+
|
|
800
|
+
// src/lib/build-source.ts
|
|
801
|
+
import { execFile } from "child_process";
|
|
802
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
803
|
+
import { promisify } from "util";
|
|
804
|
+
var COMMIT_RE = /^[0-9a-f]{7,64}$/;
|
|
805
|
+
function clean(source) {
|
|
806
|
+
const out = {};
|
|
807
|
+
const commit = source.commit?.trim().toLowerCase();
|
|
808
|
+
if (commit && COMMIT_RE.test(commit)) out.commit = commit;
|
|
809
|
+
const branch = source.branch?.trim().replace(/^refs\/heads\//, "");
|
|
810
|
+
if (branch && branch.length <= 255 && !/[\u0000-\u001f\u007f]/.test(branch)) {
|
|
811
|
+
out.branch = branch;
|
|
812
|
+
}
|
|
813
|
+
const url = source.ci_run_url?.trim();
|
|
814
|
+
if (url && url.length <= 2048 && url.startsWith("https://") && !/\s/.test(url)) {
|
|
815
|
+
out.ci_run_url = url;
|
|
816
|
+
}
|
|
817
|
+
return Object.keys(out).length ? out : void 0;
|
|
818
|
+
}
|
|
819
|
+
function pullRequestHeadSha(eventPath) {
|
|
820
|
+
if (!eventPath) return void 0;
|
|
821
|
+
try {
|
|
822
|
+
const event = JSON.parse(readFileSync5(eventPath, "utf8"));
|
|
823
|
+
const sha = event.pull_request?.head?.sha;
|
|
824
|
+
return typeof sha === "string" ? sha : void 0;
|
|
825
|
+
} catch {
|
|
826
|
+
return void 0;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
function ciBuildSource(env = process.env) {
|
|
830
|
+
if (env.GITHUB_ACTIONS === "true") {
|
|
831
|
+
const run = env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_RUN_ID ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}` : void 0;
|
|
832
|
+
return clean({
|
|
833
|
+
commit: env.GITHUB_HEAD_REF && pullRequestHeadSha(env.GITHUB_EVENT_PATH) || env.GITHUB_SHA,
|
|
834
|
+
branch: env.GITHUB_HEAD_REF || env.GITHUB_REF_NAME,
|
|
835
|
+
ci_run_url: run
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
if (env.GITLAB_CI === "true") {
|
|
839
|
+
return clean({
|
|
840
|
+
commit: env.CI_COMMIT_SHA,
|
|
841
|
+
branch: env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME || env.CI_COMMIT_REF_NAME,
|
|
842
|
+
ci_run_url: env.CI_JOB_URL || env.CI_PIPELINE_URL
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
if (env.BITRISE_IO === "true") {
|
|
846
|
+
return clean({
|
|
847
|
+
commit: env.BITRISE_GIT_COMMIT || env.GIT_CLONE_COMMIT_HASH,
|
|
848
|
+
branch: env.BITRISE_GIT_BRANCH,
|
|
849
|
+
ci_run_url: env.BITRISE_BUILD_URL
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
if (env.CIRCLECI === "true") {
|
|
853
|
+
return clean({
|
|
854
|
+
commit: env.CIRCLE_SHA1,
|
|
855
|
+
branch: env.CIRCLE_BRANCH,
|
|
856
|
+
ci_run_url: env.CIRCLE_BUILD_URL
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
return void 0;
|
|
860
|
+
}
|
|
861
|
+
async function git(cwd, args) {
|
|
862
|
+
try {
|
|
863
|
+
const { stdout } = await promisify(execFile)("git", args, { cwd, timeout: 5e3 });
|
|
864
|
+
return stdout.trim();
|
|
865
|
+
} catch {
|
|
866
|
+
return void 0;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
async function buildSource(cwd, env = process.env) {
|
|
870
|
+
const ci = ciBuildSource(env);
|
|
871
|
+
if (ci) return ci;
|
|
872
|
+
const commit = await git(cwd, ["rev-parse", "HEAD"]);
|
|
873
|
+
if (!commit) return void 0;
|
|
874
|
+
const branch = await git(cwd, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
875
|
+
const dirty = await git(cwd, ["status", "--porcelain"]);
|
|
876
|
+
return clean({
|
|
877
|
+
commit: dirty === "" ? commit : void 0,
|
|
878
|
+
branch: branch && branch !== "HEAD" ? branch : void 0
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// src/commands/build.ts
|
|
799
883
|
import { createInterface } from "readline";
|
|
800
884
|
import { select as select2 } from "@inquirer/prompts";
|
|
801
885
|
import chalk3 from "chalk";
|
|
@@ -805,13 +889,13 @@ import chalk2 from "chalk";
|
|
|
805
889
|
import { input, select } from "@inquirer/prompts";
|
|
806
890
|
|
|
807
891
|
// src/lib/project-detect.ts
|
|
808
|
-
import { execFile } from "child_process";
|
|
809
|
-
import { existsSync as existsSync3, readFileSync as
|
|
892
|
+
import { execFile as execFile2 } from "child_process";
|
|
893
|
+
import { existsSync as existsSync3, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
810
894
|
import { join as join5 } from "path";
|
|
811
895
|
import ignore from "ignore";
|
|
812
896
|
function readJson(cwd, name) {
|
|
813
897
|
try {
|
|
814
|
-
return JSON.parse(
|
|
898
|
+
return JSON.parse(readFileSync6(join5(cwd, name), "utf-8"));
|
|
815
899
|
} catch {
|
|
816
900
|
return null;
|
|
817
901
|
}
|
|
@@ -826,7 +910,7 @@ function isFile(path) {
|
|
|
826
910
|
function detectFlavor(cwd) {
|
|
827
911
|
let deps = {};
|
|
828
912
|
try {
|
|
829
|
-
const pkg = JSON.parse(
|
|
913
|
+
const pkg = JSON.parse(readFileSync6(join5(cwd, "package.json"), "utf-8"));
|
|
830
914
|
deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
831
915
|
} catch {
|
|
832
916
|
}
|
|
@@ -851,7 +935,7 @@ var CAPACITOR_CONFIGS = ["capacitor.config.ts", "capacitor.config.js", "capacito
|
|
|
851
935
|
function nativeDirShipped(cwd, dir) {
|
|
852
936
|
if (!existsSync3(join5(cwd, dir))) return false;
|
|
853
937
|
try {
|
|
854
|
-
const ig = ignore().add(
|
|
938
|
+
const ig = ignore().add(readFileSync6(join5(cwd, ".gitignore"), "utf-8"));
|
|
855
939
|
return !ig.ignores(`${dir}/`);
|
|
856
940
|
} catch {
|
|
857
941
|
return true;
|
|
@@ -890,7 +974,7 @@ function dirShipped(cwd, rel) {
|
|
|
890
974
|
if (slash !== -1) checks.push([rel.slice(0, slash), rel.slice(slash + 1)]);
|
|
891
975
|
return checks.every(([dir, path]) => {
|
|
892
976
|
try {
|
|
893
|
-
return !ignore().add(
|
|
977
|
+
return !ignore().add(readFileSync6(join5(cwd, dir, ".gitignore"), "utf-8")).ignores(`${path}/`);
|
|
894
978
|
} catch {
|
|
895
979
|
return true;
|
|
896
980
|
}
|
|
@@ -986,7 +1070,7 @@ var FVM_CONFIGS = [".fvmrc", ".fvm/fvm_config.json"];
|
|
|
986
1070
|
function flutterCommand(cwd) {
|
|
987
1071
|
let ig = null;
|
|
988
1072
|
try {
|
|
989
|
-
ig = ignore().add(
|
|
1073
|
+
ig = ignore().add(readFileSync6(join5(cwd, ".gitignore"), "utf-8"));
|
|
990
1074
|
} catch {
|
|
991
1075
|
}
|
|
992
1076
|
const pinned = FVM_CONFIGS.some((f) => isFile(join5(cwd, f)) && !ig?.ignores(f));
|
|
@@ -1228,7 +1312,7 @@ function uniqueMatch(text, re) {
|
|
|
1228
1312
|
}
|
|
1229
1313
|
function readText(path) {
|
|
1230
1314
|
try {
|
|
1231
|
-
return
|
|
1315
|
+
return readFileSync6(path, "utf-8");
|
|
1232
1316
|
} catch {
|
|
1233
1317
|
return null;
|
|
1234
1318
|
}
|
|
@@ -1270,7 +1354,7 @@ var readExpoConfig = (cwd, timeoutMs = EXPO_CONFIG_TIMEOUT_MS) => {
|
|
|
1270
1354
|
clearTimeout(timer);
|
|
1271
1355
|
fn();
|
|
1272
1356
|
};
|
|
1273
|
-
const child =
|
|
1357
|
+
const child = execFile2(
|
|
1274
1358
|
process.execPath,
|
|
1275
1359
|
[cli, "config", "--json", "--type", "public"],
|
|
1276
1360
|
{
|
|
@@ -1516,8 +1600,8 @@ async function promptMetroCommand(cwd, platform) {
|
|
|
1516
1600
|
}
|
|
1517
1601
|
|
|
1518
1602
|
// src/lib/source-pack.ts
|
|
1519
|
-
import { execFile as
|
|
1520
|
-
import { lstatSync, mkdtempSync, readFileSync as
|
|
1603
|
+
import { execFile as execFile3, spawn } from "child_process";
|
|
1604
|
+
import { lstatSync, mkdtempSync, readFileSync as readFileSync7, rmSync as rmSync5, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
1521
1605
|
import { tmpdir } from "os";
|
|
1522
1606
|
import { join as join6 } from "path";
|
|
1523
1607
|
import ignore2 from "ignore";
|
|
@@ -1547,7 +1631,7 @@ async function listSourceFiles(projectRoot) {
|
|
|
1547
1631
|
let filtered = rawPaths;
|
|
1548
1632
|
const vvignorePath = join6(projectRoot, ".vvignore");
|
|
1549
1633
|
if (statOrNull(vvignorePath)?.isFile()) {
|
|
1550
|
-
const ig = ignore2().add(
|
|
1634
|
+
const ig = ignore2().add(readFileSync7(vvignorePath, "utf-8"));
|
|
1551
1635
|
filtered = filtered.filter((p) => !ig.ignores(p));
|
|
1552
1636
|
}
|
|
1553
1637
|
const result = [];
|
|
@@ -1655,7 +1739,7 @@ function probeTarNullSupport() {
|
|
|
1655
1739
|
const listPath = join6(tmp, "empty.list");
|
|
1656
1740
|
writeFileSync5(listPath, "");
|
|
1657
1741
|
const out = join6(tmp, "probe.tgz");
|
|
1658
|
-
|
|
1742
|
+
execFile3("tar", ["-czf", out, "-C", tmp, "--null", "-T", listPath], (err) => {
|
|
1659
1743
|
rmSync5(tmp, { recursive: true, force: true });
|
|
1660
1744
|
resolve(!err);
|
|
1661
1745
|
});
|
|
@@ -1686,7 +1770,7 @@ function runTar(args) {
|
|
|
1686
1770
|
}
|
|
1687
1771
|
|
|
1688
1772
|
// src/lib/build-preflight.ts
|
|
1689
|
-
import { execFile as
|
|
1773
|
+
import { execFile as execFile4 } from "child_process";
|
|
1690
1774
|
import { realpathSync, statSync as statSync4 } from "fs";
|
|
1691
1775
|
import { dirname as dirname2, isAbsolute, join as join7, relative } from "path";
|
|
1692
1776
|
import { parse } from "shell-quote";
|
|
@@ -1876,7 +1960,7 @@ function isFile2(path) {
|
|
|
1876
1960
|
}
|
|
1877
1961
|
async function gitToplevel(cwd) {
|
|
1878
1962
|
return new Promise((resolve) => {
|
|
1879
|
-
|
|
1963
|
+
execFile4("git", ["rev-parse", "--show-toplevel"], { cwd }, (err, stdout) => {
|
|
1880
1964
|
resolve(err ? null : stdout.trim() || null);
|
|
1881
1965
|
});
|
|
1882
1966
|
});
|
|
@@ -2291,6 +2375,7 @@ function defaultCloudBuildDeps(client) {
|
|
|
2291
2375
|
packSource,
|
|
2292
2376
|
listApps: client.listApps.bind(client),
|
|
2293
2377
|
createCloudBuilds: client.createCloudBuilds.bind(client),
|
|
2378
|
+
buildSource,
|
|
2294
2379
|
getCloudBuildLogs: client.getCloudBuildLogs.bind(client),
|
|
2295
2380
|
getCloudBuild: client.getCloudBuild.bind(client),
|
|
2296
2381
|
downloadCloudBuildArtifact: client.downloadCloudBuildArtifact.bind(client)
|
|
@@ -2420,7 +2505,11 @@ ${offenders}`);
|
|
|
2420
2505
|
uploadSpinner?.start();
|
|
2421
2506
|
let created;
|
|
2422
2507
|
try {
|
|
2423
|
-
const
|
|
2508
|
+
const source = d.buildSource ? await d.buildSource(cwd) : void 0;
|
|
2509
|
+
const resp = await d.createCloudBuilds(
|
|
2510
|
+
source ? { builds: manifestEntries, source } : { builds: manifestEntries },
|
|
2511
|
+
tarPath
|
|
2512
|
+
);
|
|
2424
2513
|
created = resp.builds;
|
|
2425
2514
|
} catch (err) {
|
|
2426
2515
|
uploadSpinner?.stop();
|
|
@@ -2744,7 +2833,7 @@ your build command must produce a zip \u2014 use the package/zip step, not deplo
|
|
|
2744
2833
|
|
|
2745
2834
|
// src/commands/dev.ts
|
|
2746
2835
|
import { spawn as spawn4 } from "child_process";
|
|
2747
|
-
import { closeSync, createWriteStream, mkdirSync as mkdirSync5, openSync, readFileSync as
|
|
2836
|
+
import { closeSync, createWriteStream, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync9 } from "fs";
|
|
2748
2837
|
import { dirname as dirname5, join as join9 } from "path";
|
|
2749
2838
|
import { createInterface as createInterface3 } from "readline";
|
|
2750
2839
|
import { stripVTControlCharacters } from "util";
|
|
@@ -2948,7 +3037,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
2948
3037
|
import { createInterface as createInterface2 } from "readline";
|
|
2949
3038
|
|
|
2950
3039
|
// src/lib/metro-state.ts
|
|
2951
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as
|
|
3040
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync8, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
2952
3041
|
import { dirname as dirname3, join as join8 } from "path";
|
|
2953
3042
|
var STATE_DIR2 = ".vibeview";
|
|
2954
3043
|
var STATE_FILE2 = "metro-state.json";
|
|
@@ -2974,7 +3063,7 @@ function writeMetroState(cwd, state) {
|
|
|
2974
3063
|
function readMetroState(cwd) {
|
|
2975
3064
|
let parsed;
|
|
2976
3065
|
try {
|
|
2977
|
-
parsed = JSON.parse(
|
|
3066
|
+
parsed = JSON.parse(readFileSync8(statePath2(cwd), "utf-8"));
|
|
2978
3067
|
} catch {
|
|
2979
3068
|
return null;
|
|
2980
3069
|
}
|
|
@@ -4483,7 +4572,7 @@ function openDetachLog(path) {
|
|
|
4483
4572
|
function lastErrorLine(path) {
|
|
4484
4573
|
let text;
|
|
4485
4574
|
try {
|
|
4486
|
-
text =
|
|
4575
|
+
text = readFileSync9(path, "utf-8");
|
|
4487
4576
|
} catch {
|
|
4488
4577
|
return null;
|
|
4489
4578
|
}
|
|
@@ -5014,6 +5103,24 @@ var AGENT_COMMANDS = [
|
|
|
5014
5103
|
}
|
|
5015
5104
|
]
|
|
5016
5105
|
},
|
|
5106
|
+
{
|
|
5107
|
+
// set_app_language: { language: string | null } — the Device tab's App
|
|
5108
|
+
// language. The worker restarts the app in it; iOS/iPadOS/tvOS and
|
|
5109
|
+
// Android 13+, refused on Roku and embed sessions. 'default' maps to null.
|
|
5110
|
+
verb: "set-language",
|
|
5111
|
+
tool: "set_app_language",
|
|
5112
|
+
summary: "Restart the app under test in another language \u2014 a language tag such as de, fr, ja or pt-BR, or 'default' for the device's language \u2014 e.g. to check translations or take localized screenshots. Only the app changes; the device, its status bar and other apps keep their language. iPhone, iPad, Apple TV and Android 13+; not Roku or embed sessions.",
|
|
5113
|
+
mutating: true,
|
|
5114
|
+
params: [
|
|
5115
|
+
{
|
|
5116
|
+
name: "language",
|
|
5117
|
+
cli: "positional",
|
|
5118
|
+
type: "string",
|
|
5119
|
+
required: true,
|
|
5120
|
+
description: "A language tag (de, fr, ja, pt-BR, zh-Hans, \u2026) or 'default' for the device's own language."
|
|
5121
|
+
}
|
|
5122
|
+
]
|
|
5123
|
+
},
|
|
5017
5124
|
{
|
|
5018
5125
|
// set_status_bar: { preset: 'clean' | 'default' } — the dashboard's
|
|
5019
5126
|
// Device tab Clean status bar (simctl status_bar override). iOS phones and
|
|
@@ -5184,6 +5291,11 @@ function resultLines(result) {
|
|
|
5184
5291
|
if (r.action === "location_set" && typeof r.latitude === "number" && typeof r.longitude === "number") {
|
|
5185
5292
|
lines.push(`location: ${r.latitude}, ${r.longitude}`);
|
|
5186
5293
|
}
|
|
5294
|
+
if (r.action === "app_language_set") {
|
|
5295
|
+
lines.push(
|
|
5296
|
+
`app language: ${typeof r.language === "string" && r.language ? r.language : "the device language"}`
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5187
5299
|
if (r.action === "status_bar_set" && typeof r.preset === "string") {
|
|
5188
5300
|
lines.push(
|
|
5189
5301
|
`status bar: ${r.preset === "clean" ? "clean (9:41, full battery and signal)" : "the device\u2019s own"}`
|
package/dist/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
runAgentVerb,
|
|
31
31
|
runStepsNotChecked,
|
|
32
32
|
stepsNotCheckedLabel
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-NHM2FHA2.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-
|
|
4464
|
+
const { runMcpServer } = await import("./server-W66J6PY5.js");
|
|
4465
4465
|
await runMcpServer({ ...opts, version: pkg.version });
|
|
4466
4466
|
});
|
|
4467
4467
|
program.command("agent-setup").description(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeview",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.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",
|
|
@@ -173,6 +173,10 @@ appear unexplained in their `git status`.
|
|
|
173
173
|
- Use `set-location --lat 51.5074 --lon -0.1278` to place the device before
|
|
174
174
|
a location-based flow (maps, store finders, region-gated screens); the app
|
|
175
175
|
reads it like a GPS fix. Not on TV.
|
|
176
|
+
- Use `set-language <tag>` (`de`, `ja`, `pt-BR`, … or `default`) to restart the
|
|
177
|
+
app in another language — for checking translations or localized
|
|
178
|
+
screenshots. Only the app changes; old refs are stale after it. iPhone, iPad,
|
|
179
|
+
Apple TV and Android 13+; not Roku or embed sessions.
|
|
176
180
|
- Use `set-status-bar clean` before App Store screenshots: 9:41, a full
|
|
177
181
|
battery and full Wi-Fi and cellular signal, kept for the rest of the session
|
|
178
182
|
(`set-status-bar default` puts the real one back). iOS phones and tablets
|
|
@@ -294,6 +298,7 @@ human-readable text.
|
|
|
294
298
|
| `relaunch-app` | — | Close the app and start it again (cold start, data kept) — for "does it persist after a restart" checks. The app log keeps streaming. Not on embed sessions. |
|
|
295
299
|
| `set-posture` | `<closed\|partial\|open>` or `--angle <0-180>` | Fold or unfold a foldable device (form factor `foldable`: the iPhone Duo, Android foldables) to a preset or an exact hinge angle — exactly one. Reports posture, angle and lit screen. Errors on a device without a hinge. |
|
|
296
300
|
| `rotate` | `[--degrees <90\|180\|270>]` | Rotate the device and report the new orientation. Phones/tablets and Android foldables toggle portrait/landscape (90 only); the iPhone Duo turns a quarter clockwise by default. Not on TV. |
|
|
301
|
+
| `set-language` | `<tag\|default>` | Restart the app in another language (`de`, `pt-BR`, …) or the device's (`default`). Only the app changes. iPhone, iPad, Apple TV, Android 13+; not Roku or embed sessions. |
|
|
297
302
|
| `set-status-bar` | `<clean\|default>` | Show the clean screenshot status bar (9:41, full battery and signal) or the device's own. iOS phones and tablets only. |
|
|
298
303
|
| `set-location` | `--lat <n> --lon <n>` | Set the device's simulated GPS position (decimal degrees; west and south are negative) for location-based flows. Phones, tablets and foldables; not on TV. |
|
|
299
304
|
| `wait` | `[--ms <n>]` | Wait for a specified number of seconds before continuing (default: 2s). |
|