vibeview 0.28.1 → 0.29.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.
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./chunk-PBMB6TG4.js";
|
|
17
17
|
|
|
18
18
|
// src/lib/dev-config.ts
|
|
19
|
-
import { readFileSync, writeFileSync } from "fs";
|
|
19
|
+
import { readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
20
20
|
import { join } from "path";
|
|
21
21
|
var DEV_PLATFORMS = ["ios", "android", "tvos", "androidtv", "roku"];
|
|
22
22
|
var ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -166,7 +166,58 @@ function validateBuildEnv(env, platformKey) {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
function saveDevConfig(cwd, cfg) {
|
|
169
|
-
|
|
169
|
+
const target = join(cwd, FILE);
|
|
170
|
+
const tmp = join(cwd, `.${FILE}.${process.pid}.${Date.now()}.tmp`);
|
|
171
|
+
try {
|
|
172
|
+
writeFileSync(tmp, JSON.stringify(cfg, null, 2) + "\n");
|
|
173
|
+
renameSync(tmp, target);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
rmSync(tmp, { force: true });
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function updateDevConfig(cwd, platform, apply) {
|
|
180
|
+
const fresh = loadDevConfig(cwd) ?? { defaultPlatform: platform, platforms: {} };
|
|
181
|
+
if (apply(fresh) === false) return fresh;
|
|
182
|
+
saveDevConfig(cwd, fresh);
|
|
183
|
+
return fresh;
|
|
184
|
+
}
|
|
185
|
+
function configLeaves(value, path = [], out = []) {
|
|
186
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
187
|
+
for (const [k, v] of Object.entries(value)) {
|
|
188
|
+
configLeaves(v, [...path, k], out);
|
|
189
|
+
}
|
|
190
|
+
} else if (value !== void 0) {
|
|
191
|
+
out.push({ path, value });
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
function applyConfigChanges(target, before, after) {
|
|
196
|
+
const key = (path) => JSON.stringify(path);
|
|
197
|
+
const prev = new Map(configLeaves(before ?? {}).map((l) => [key(l.path), l.value]));
|
|
198
|
+
const root = target;
|
|
199
|
+
for (const { path, value } of configLeaves(after)) {
|
|
200
|
+
const old = prev.get(key(path));
|
|
201
|
+
prev.delete(key(path));
|
|
202
|
+
if (old !== void 0 && JSON.stringify(old) === JSON.stringify(value)) continue;
|
|
203
|
+
let node = root;
|
|
204
|
+
for (const segment of path.slice(0, -1)) {
|
|
205
|
+
const child = node[segment];
|
|
206
|
+
if (!child || typeof child !== "object" || Array.isArray(child)) node[segment] = {};
|
|
207
|
+
node = node[segment];
|
|
208
|
+
}
|
|
209
|
+
node[path[path.length - 1]] = value;
|
|
210
|
+
}
|
|
211
|
+
for (const k of prev.keys()) {
|
|
212
|
+
const path = JSON.parse(k);
|
|
213
|
+
let node = root;
|
|
214
|
+
for (const segment of path.slice(0, -1)) {
|
|
215
|
+
node = node && typeof node === "object" ? node[segment] : void 0;
|
|
216
|
+
}
|
|
217
|
+
if (node && typeof node === "object") {
|
|
218
|
+
delete node[path[path.length - 1]];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
170
221
|
}
|
|
171
222
|
function describeConfigChanges(before, after) {
|
|
172
223
|
const flat = (value, prefix, out) => {
|
|
@@ -220,6 +271,10 @@ function buildSavedConfig(input2) {
|
|
|
220
271
|
platforms: {
|
|
221
272
|
...existing?.platforms,
|
|
222
273
|
[platform]: {
|
|
274
|
+
// Everything else on the entry (`submit` defaults, keys a newer CLI
|
|
275
|
+
// wrote) is carried forward untouched; the fields below are the ones
|
|
276
|
+
// `vibeview dev` owns.
|
|
277
|
+
...existing?.platforms?.[platform],
|
|
223
278
|
appId,
|
|
224
279
|
deviceCategory: isTv ? void 0 : deviceCategory,
|
|
225
280
|
...existing?.platforms?.[platform]?.build ? { build: { ...existing.platforms[platform].build } } : {},
|
|
@@ -235,6 +290,11 @@ function buildSavedConfig(input2) {
|
|
|
235
290
|
}
|
|
236
291
|
|
|
237
292
|
// src/lib/dev-build.ts
|
|
293
|
+
function canUseMetro(build) {
|
|
294
|
+
if (build.can_use_metro === true || build.can_use_metro === false) return build.can_use_metro;
|
|
295
|
+
if (build.is_debug === true) return true;
|
|
296
|
+
return build.is_debug === false ? false : null;
|
|
297
|
+
}
|
|
238
298
|
function parseBuildId(raw) {
|
|
239
299
|
const text = typeof raw === "number" ? String(raw) : typeof raw === "string" ? raw.trim() : "";
|
|
240
300
|
if (!/^\d+$/.test(text) || Number(text) < 1) {
|
|
@@ -244,9 +304,10 @@ function parseBuildId(raw) {
|
|
|
244
304
|
}
|
|
245
305
|
return Number(text);
|
|
246
306
|
}
|
|
247
|
-
function buildKind(
|
|
248
|
-
|
|
249
|
-
if (
|
|
307
|
+
function buildKind(build) {
|
|
308
|
+
const usable = build !== null && typeof build === "object" ? canUseMetro(build) : canUseMetro({ is_debug: build });
|
|
309
|
+
if (usable === true) return "debug";
|
|
310
|
+
if (usable === false) return "release";
|
|
250
311
|
return "unknown";
|
|
251
312
|
}
|
|
252
313
|
function checkDevBuild(app, buildId, platform, opts = {}) {
|
|
@@ -266,10 +327,11 @@ function checkDevBuild(app, buildId, platform, opts = {}) {
|
|
|
266
327
|
`build ${buildId} is not a build of app ${app.public_id} \u2014 see \`vibeview list-builds ${app.public_id}\``
|
|
267
328
|
);
|
|
268
329
|
}
|
|
269
|
-
|
|
270
|
-
|
|
330
|
+
const usable = canUseMetro(build);
|
|
331
|
+
if (!opts.standalone && usable !== true) {
|
|
332
|
+
const why = usable === false ? "it is a release build (or not a React Native build), so it cannot load JavaScript from Metro" : "it could not be identified as a React Native debug build";
|
|
271
333
|
throw new Error(
|
|
272
|
-
`build ${buildId} is not a debug build \u2014 ${why}. \`vibeview dev\` needs ${platformWithArticle(platform)} debug simulator/emulator build
|
|
334
|
+
`build ${buildId} is not a debug build \u2014 ${why}. \`vibeview dev\` needs ${platformWithArticle(platform)} React Native debug simulator/emulator build (see \`vibeview list-builds ${app.public_id}\`); to run this build as it is, with no Metro, use \`vibeview dev --standalone --build ${buildId}\``
|
|
273
335
|
);
|
|
274
336
|
}
|
|
275
337
|
return build;
|
|
@@ -283,8 +345,9 @@ function buildRows(app) {
|
|
|
283
345
|
version: b.version ?? null,
|
|
284
346
|
build_number: b.build_number ?? null,
|
|
285
347
|
platform: app.platform,
|
|
286
|
-
kind: buildKind(b
|
|
348
|
+
kind: buildKind(b),
|
|
287
349
|
is_debug: b.is_debug ?? null,
|
|
350
|
+
can_use_metro: canUseMetro(b),
|
|
288
351
|
uploaded_at: b.uploaded_at ?? null,
|
|
289
352
|
note: b.note ?? null
|
|
290
353
|
}));
|
|
@@ -329,7 +392,7 @@ async function listBuilds(appId, opts, deps) {
|
|
|
329
392
|
}
|
|
330
393
|
|
|
331
394
|
// src/lib/dev-state.ts
|
|
332
|
-
import { existsSync, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
395
|
+
import { existsSync, mkdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
333
396
|
import { dirname, join as join2 } from "path";
|
|
334
397
|
var STATE_DIR = ".vibeview";
|
|
335
398
|
var STATE_FILE = "dev-state.json";
|
|
@@ -399,7 +462,7 @@ function readDevState(cwd) {
|
|
|
399
462
|
function clearDevState(cwd) {
|
|
400
463
|
const path = statePath(cwd);
|
|
401
464
|
if (existsSync(path)) {
|
|
402
|
-
|
|
465
|
+
rmSync2(path, { force: true });
|
|
403
466
|
}
|
|
404
467
|
}
|
|
405
468
|
|
|
@@ -703,7 +766,7 @@ async function promptMetroCommand(cwd, platform) {
|
|
|
703
766
|
|
|
704
767
|
// src/lib/source-pack.ts
|
|
705
768
|
import { execFile, spawn } from "child_process";
|
|
706
|
-
import { lstatSync, mkdtempSync, readFileSync as readFileSync4, rmSync as
|
|
769
|
+
import { lstatSync, mkdtempSync, readFileSync as readFileSync4, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
707
770
|
import { tmpdir } from "os";
|
|
708
771
|
import { join as join4 } from "path";
|
|
709
772
|
import ignore2 from "ignore";
|
|
@@ -801,7 +864,7 @@ async function packSource(projectRoot, files, opts = {}) {
|
|
|
801
864
|
);
|
|
802
865
|
}
|
|
803
866
|
const tmpDir = mkdtempSync(join4(tmpdir(), "vibeview-source-pack-"));
|
|
804
|
-
const cleanup = () =>
|
|
867
|
+
const cleanup = () => rmSync3(tmpDir, { recursive: true, force: true });
|
|
805
868
|
try {
|
|
806
869
|
const supportsNull = await probeTarNullSupport();
|
|
807
870
|
const tarPath = join4(tmpDir, "source.tgz");
|
|
@@ -842,7 +905,7 @@ function probeTarNullSupport() {
|
|
|
842
905
|
writeFileSync3(listPath, "");
|
|
843
906
|
const out = join4(tmp, "probe.tgz");
|
|
844
907
|
execFile("tar", ["-czf", out, "-C", tmp, "--null", "-T", listPath], (err) => {
|
|
845
|
-
|
|
908
|
+
rmSync3(tmp, { recursive: true, force: true });
|
|
846
909
|
resolve(!err);
|
|
847
910
|
});
|
|
848
911
|
});
|
|
@@ -946,30 +1009,28 @@ async function resolveBarePlatform(cwd, cfg, opts) {
|
|
|
946
1009
|
}
|
|
947
1010
|
return platform;
|
|
948
1011
|
}
|
|
949
|
-
function persistPromptedBuild(cwd,
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
return next;
|
|
1012
|
+
function persistPromptedBuild(cwd, platform, build) {
|
|
1013
|
+
return updateDevConfig(cwd, platform, (next) => {
|
|
1014
|
+
const entry = next.platforms[platform];
|
|
1015
|
+
if (entry) {
|
|
1016
|
+
entry.build = build;
|
|
1017
|
+
} else {
|
|
1018
|
+
next.platforms[platform] = { build };
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
959
1021
|
}
|
|
960
|
-
function persistUploadedAppId(cwd,
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
if (entry.appId !== appId || !entry.build) {
|
|
1022
|
+
function persistUploadedAppId(cwd, platform, build, appId) {
|
|
1023
|
+
updateDevConfig(cwd, platform, (next) => {
|
|
1024
|
+
const entry = next.platforms[platform];
|
|
1025
|
+
if (!entry) {
|
|
1026
|
+
next.platforms[platform] = { appId, build };
|
|
1027
|
+
return true;
|
|
1028
|
+
}
|
|
1029
|
+
if (entry.appId === appId && entry.build) return false;
|
|
969
1030
|
entry.appId = appId;
|
|
970
|
-
entry.build = build;
|
|
971
|
-
|
|
972
|
-
}
|
|
1031
|
+
if (!entry.build) entry.build = build;
|
|
1032
|
+
return true;
|
|
1033
|
+
});
|
|
973
1034
|
}
|
|
974
1035
|
async function resolveBuildConfig(cwd, cfgRef, platform, opts) {
|
|
975
1036
|
const existing = cfgRef.current?.platforms?.[platform]?.build;
|
|
@@ -985,11 +1046,15 @@ async function resolveBuildConfig(cwd, cfgRef, platform, opts) {
|
|
|
985
1046
|
if (!answered) {
|
|
986
1047
|
fail(opts, "build config is required to run vibeview build", "config_required");
|
|
987
1048
|
}
|
|
988
|
-
cfgRef.current = persistPromptedBuild(cwd,
|
|
1049
|
+
cfgRef.current = persistPromptedBuild(cwd, platform, answered);
|
|
989
1050
|
return answered;
|
|
990
1051
|
}
|
|
991
|
-
function persistPromptedProductionBuild(cwd,
|
|
992
|
-
|
|
1052
|
+
function persistPromptedProductionBuild(cwd, platform, production) {
|
|
1053
|
+
return updateDevConfig(cwd, platform, (next) => {
|
|
1054
|
+
mergeProductionPair(next, platform, production);
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
function mergeProductionPair(next, platform, production) {
|
|
993
1058
|
const existingBuild = next.platforms[platform]?.build;
|
|
994
1059
|
if (!existingBuild?.command || !existingBuild?.artifact) {
|
|
995
1060
|
throw new Error(
|
|
@@ -997,8 +1062,6 @@ function persistPromptedProductionBuild(cwd, cfg, platform, production) {
|
|
|
997
1062
|
);
|
|
998
1063
|
}
|
|
999
1064
|
next.platforms[platform].build = { ...existingBuild, ...production };
|
|
1000
|
-
saveDevConfig(cwd, next);
|
|
1001
|
-
return next;
|
|
1002
1065
|
}
|
|
1003
1066
|
async function resolveProductionBuildConfig(cwd, cfgRef, platform, opts) {
|
|
1004
1067
|
const entry = cfgRef.current?.platforms?.[platform]?.build;
|
|
@@ -1016,7 +1079,7 @@ async function resolveProductionBuildConfig(cwd, cfgRef, platform, opts) {
|
|
|
1016
1079
|
if (!answered) {
|
|
1017
1080
|
fail(opts, "a production build config is required for --production", "config_required");
|
|
1018
1081
|
}
|
|
1019
|
-
cfgRef.current = persistPromptedProductionBuild(cwd,
|
|
1082
|
+
cfgRef.current = persistPromptedProductionBuild(cwd, platform, answered);
|
|
1020
1083
|
return { command: answered.productionCommand, artifact: answered.productionArtifact };
|
|
1021
1084
|
}
|
|
1022
1085
|
async function buildCommand(opts, cloudDeps) {
|
|
@@ -1036,7 +1099,6 @@ async function buildCommand(opts, cloudDeps) {
|
|
|
1036
1099
|
}
|
|
1037
1100
|
const platform = await resolveBarePlatform(cwd, cfgRef.current, opts);
|
|
1038
1101
|
const build = await resolveBuildConfig(cwd, cfgRef, platform, opts);
|
|
1039
|
-
const cfg = cfgRef.current;
|
|
1040
1102
|
const result = await runBuildForPlatform(
|
|
1041
1103
|
cwd,
|
|
1042
1104
|
platform,
|
|
@@ -1045,7 +1107,7 @@ async function buildCommand(opts, cloudDeps) {
|
|
|
1045
1107
|
(l) => console.error(chalk3.dim(l))
|
|
1046
1108
|
);
|
|
1047
1109
|
for (const w of result.warnings ?? []) console.error(chalk3.yellow(`\u26A0 ${w}`));
|
|
1048
|
-
persistUploadedAppId(cwd,
|
|
1110
|
+
persistUploadedAppId(cwd, platform, build, result.public_id);
|
|
1049
1111
|
if (opts.json) {
|
|
1050
1112
|
console.log(
|
|
1051
1113
|
JSON.stringify({ app_id: result.public_id, name: result.name, platform: result.platform })
|
|
@@ -1148,16 +1210,17 @@ function requireProductionCapable(opts, platform) {
|
|
|
1148
1210
|
fail(opts, productionUnsupportedReason(platform));
|
|
1149
1211
|
}
|
|
1150
1212
|
}
|
|
1151
|
-
function persistPickedAppId(cwd,
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
entry
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1213
|
+
function persistPickedAppId(cwd, platform, appId, opts = {}) {
|
|
1214
|
+
return updateDevConfig(cwd, platform, (next) => {
|
|
1215
|
+
const entry = next.platforms[platform];
|
|
1216
|
+
if (opts.onlyIfUnset && entry?.appId) return false;
|
|
1217
|
+
if (entry) {
|
|
1218
|
+
entry.appId = appId;
|
|
1219
|
+
} else {
|
|
1220
|
+
next.platforms[platform] = { appId };
|
|
1221
|
+
}
|
|
1222
|
+
return true;
|
|
1223
|
+
});
|
|
1161
1224
|
}
|
|
1162
1225
|
var APP_PICKER_SENTINEL = {
|
|
1163
1226
|
CREATE_NEW_APP: "__vibeview_create_new_app__",
|
|
@@ -1225,7 +1288,7 @@ async function resolveCloudAppIds(cwd, cfgRef, platforms, opts, listApps) {
|
|
|
1225
1288
|
createFromArtifact.add(platform);
|
|
1226
1289
|
continue;
|
|
1227
1290
|
}
|
|
1228
|
-
cfgRef.current = persistPickedAppId(cwd,
|
|
1291
|
+
cfgRef.current = persistPickedAppId(cwd, platform, appId);
|
|
1229
1292
|
}
|
|
1230
1293
|
return createFromArtifact;
|
|
1231
1294
|
}
|
|
@@ -1235,7 +1298,7 @@ function persistResolvedAppIds(cwd, cfgRef, createFromArtifact, finished) {
|
|
|
1235
1298
|
const platform = b.platform;
|
|
1236
1299
|
if (!createFromArtifact.has(platform)) continue;
|
|
1237
1300
|
if (cfgRef.current?.platforms?.[platform]?.appId) continue;
|
|
1238
|
-
cfgRef.current = persistPickedAppId(cwd,
|
|
1301
|
+
cfgRef.current = persistPickedAppId(cwd, platform, b.app_public_id, { onlyIfUnset: true });
|
|
1239
1302
|
}
|
|
1240
1303
|
}
|
|
1241
1304
|
function describeAllExclusions(configured) {
|
|
@@ -1910,7 +1973,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
1910
1973
|
import { createInterface as createInterface2 } from "readline";
|
|
1911
1974
|
|
|
1912
1975
|
// src/lib/metro-state.ts
|
|
1913
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, rmSync as
|
|
1976
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1914
1977
|
import { dirname as dirname2, join as join5 } from "path";
|
|
1915
1978
|
var STATE_DIR2 = ".vibeview";
|
|
1916
1979
|
var STATE_FILE2 = "metro-state.json";
|
|
@@ -1948,7 +2011,7 @@ function readMetroState(cwd) {
|
|
|
1948
2011
|
}
|
|
1949
2012
|
function clearMetroState(cwd) {
|
|
1950
2013
|
const path = statePath2(cwd);
|
|
1951
|
-
if (existsSync3(path))
|
|
2014
|
+
if (existsSync3(path)) rmSync4(path, { force: true });
|
|
1952
2015
|
}
|
|
1953
2016
|
function killOwnedMetro(cwd) {
|
|
1954
2017
|
const state = readMetroState(cwd);
|
|
@@ -2617,7 +2680,9 @@ ${hint}`);
|
|
|
2617
2680
|
firstRunBuild
|
|
2618
2681
|
});
|
|
2619
2682
|
const commitConfig = () => {
|
|
2620
|
-
|
|
2683
|
+
updateDevConfig(process.cwd(), platform, (fresh) => {
|
|
2684
|
+
applyConfigChanges(fresh, existing, cfg);
|
|
2685
|
+
});
|
|
2621
2686
|
if (existing) {
|
|
2622
2687
|
const changes = describeConfigChanges(existing, cfg);
|
|
2623
2688
|
if (changes.length) {
|
|
@@ -2657,6 +2722,13 @@ async function runDevInProcess(opts) {
|
|
|
2657
2722
|
emit(opts.json, { event: "error", code: "invalid_flag", message });
|
|
2658
2723
|
process.exit(2);
|
|
2659
2724
|
}
|
|
2725
|
+
const standalone = opts.standalone === true;
|
|
2726
|
+
if (standalone && opts.platform === "roku") {
|
|
2727
|
+
const message = "--standalone is not for roku \u2014 a Roku dev session has no Metro; it re-packages the channel";
|
|
2728
|
+
console.error(chalk4.red(`error: ${message}`));
|
|
2729
|
+
emit(opts.json, { event: "error", code: "invalid_flag", message });
|
|
2730
|
+
process.exit(2);
|
|
2731
|
+
}
|
|
2660
2732
|
let pinnedBuildId;
|
|
2661
2733
|
if (typeof opts.build === "string") {
|
|
2662
2734
|
try {
|
|
@@ -2685,7 +2757,7 @@ async function runDevInProcess(opts) {
|
|
|
2685
2757
|
const cfg = await ensureConfig(api, opts);
|
|
2686
2758
|
if (pinnedBuildId !== void 0) {
|
|
2687
2759
|
try {
|
|
2688
|
-
checkDevBuild(await api.getApp(cfg.appId), pinnedBuildId, cfg.platform);
|
|
2760
|
+
checkDevBuild(await api.getApp(cfg.appId), pinnedBuildId, cfg.platform, { standalone });
|
|
2689
2761
|
} catch (err) {
|
|
2690
2762
|
const message = err.message;
|
|
2691
2763
|
console.error(chalk4.red(`error: ${message}`));
|
|
@@ -2721,10 +2793,12 @@ async function runDevInProcess(opts) {
|
|
|
2721
2793
|
(l) => console.error(chalk4.dim(l))
|
|
2722
2794
|
);
|
|
2723
2795
|
cfg.appId = result.public_id;
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2796
|
+
updateDevConfig(process.cwd(), cfg.platform, (fresh) => {
|
|
2797
|
+
const entry = fresh.platforms[cfg.platform];
|
|
2798
|
+
if (!entry || entry.appId === result.public_id) return false;
|
|
2799
|
+
entry.appId = result.public_id;
|
|
2800
|
+
return true;
|
|
2801
|
+
});
|
|
2728
2802
|
} catch (err) {
|
|
2729
2803
|
const message = err.message;
|
|
2730
2804
|
console.error(chalk4.red(`error: ${message}`));
|
|
@@ -2735,7 +2809,14 @@ async function runDevInProcess(opts) {
|
|
|
2735
2809
|
let metroOwnedThisRun = false;
|
|
2736
2810
|
let rokuBuild;
|
|
2737
2811
|
let watchIgnore = [];
|
|
2738
|
-
if (
|
|
2812
|
+
if (standalone && cfg.platform === "roku") {
|
|
2813
|
+
const message = "--standalone is not for roku \u2014 a Roku dev session has no Metro";
|
|
2814
|
+
console.error(chalk4.red(`error: ${message}`));
|
|
2815
|
+
emit(opts.json, { event: "error", code: "invalid_flag", message });
|
|
2816
|
+
process.exit(2);
|
|
2817
|
+
}
|
|
2818
|
+
if (standalone) {
|
|
2819
|
+
} else if (PLATFORM_NEEDS_METRO[cfg.platform]) {
|
|
2739
2820
|
const metroPort = cfg.metroPort ?? 8081;
|
|
2740
2821
|
let metroResult;
|
|
2741
2822
|
try {
|
|
@@ -2787,7 +2868,7 @@ async function runDevInProcess(opts) {
|
|
|
2787
2868
|
}
|
|
2788
2869
|
console.error(
|
|
2789
2870
|
chalk4.dim(
|
|
2790
|
-
`Starting ${platformWithArticle(cfg.platform)} dev session for ${cfg.appId}${pinnedBuildId !== void 0 ? ` (build ${pinnedBuildId})` : ""}...`
|
|
2871
|
+
`Starting ${platformWithArticle(cfg.platform)} ${standalone ? "standalone session (no Metro)" : "dev session"} for ${cfg.appId}${pinnedBuildId !== void 0 ? ` (build ${pinnedBuildId})` : ""}...`
|
|
2791
2872
|
)
|
|
2792
2873
|
);
|
|
2793
2874
|
let stopping = false;
|
|
@@ -2820,6 +2901,7 @@ async function runDevInProcess(opts) {
|
|
|
2820
2901
|
deviceCategory: cfg.deviceCategory,
|
|
2821
2902
|
model: cfg.model,
|
|
2822
2903
|
buildId: pinnedBuildId,
|
|
2904
|
+
...standalone ? { standalone } : {},
|
|
2823
2905
|
metroPort: cfg.metroPort ?? 8081,
|
|
2824
2906
|
// startDevSession's own browser-open happens before we've written the
|
|
2825
2907
|
// state file / emitted session_ready — open it ourselves afterward
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
readDevState,
|
|
23
23
|
readMetroState,
|
|
24
24
|
runAgentVerb
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-T6EQQV6E.js";
|
|
26
26
|
import {
|
|
27
27
|
ApiClient,
|
|
28
28
|
ApiStatusError,
|
|
@@ -1785,7 +1785,8 @@ function defaultDeps2(client) {
|
|
|
1785
1785
|
getSubmission: client.getSubmission.bind(client),
|
|
1786
1786
|
getSubmissionLog: client.getSubmissionLog.bind(client),
|
|
1787
1787
|
listCloudBuilds: client.listCloudBuilds.bind(client),
|
|
1788
|
-
checkStorePreflight: client.checkStorePreflight.bind(client)
|
|
1788
|
+
checkStorePreflight: client.checkStorePreflight.bind(client),
|
|
1789
|
+
getApp: client.getApp.bind(client)
|
|
1789
1790
|
};
|
|
1790
1791
|
}
|
|
1791
1792
|
var POLL_INTERVAL_MS2 = 2e3;
|
|
@@ -1910,7 +1911,7 @@ async function submitCommand(opts, deps) {
|
|
|
1910
1911
|
}
|
|
1911
1912
|
if (rollout !== void 0 && releaseStatus !== "inProgress") {
|
|
1912
1913
|
throw new UsageError(
|
|
1913
|
-
`a rollout fraction requires release status "inProgress" (a staged rollout) \u2014 got "${releaseStatus ?? "completed"}"`
|
|
1914
|
+
`a rollout fraction requires release status "inProgress" (a staged rollout) \u2014 got "${releaseStatus ?? (track === "production" ? "draft" : "completed")}"`
|
|
1914
1915
|
);
|
|
1915
1916
|
}
|
|
1916
1917
|
if (releaseStatus === "inProgress" && rollout === void 0) {
|
|
@@ -1964,12 +1965,19 @@ async function submitCommand(opts, deps) {
|
|
|
1964
1965
|
}
|
|
1965
1966
|
}
|
|
1966
1967
|
async function checkStore(platform, androidFamily, ascKey2, opts, deps) {
|
|
1967
|
-
const
|
|
1968
|
+
const flagged = androidFamily ? opts.package : opts.bundleId;
|
|
1969
|
+
const usage = androidFamily ? `--check needs the package name to look up: --package <name> (e.g. --package io.example.app)` : `--check needs the bundle identifier to look up: --bundle-id <id> (e.g. --bundle-id io.example.app)`;
|
|
1970
|
+
let identifier = flagged;
|
|
1968
1971
|
if (!identifier) {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
)
|
|
1972
|
+
try {
|
|
1973
|
+
identifier = await linkedIdentifier(platform, opts, deps);
|
|
1974
|
+
} catch (err) {
|
|
1975
|
+
printError2(opts, err);
|
|
1976
|
+
process.exitCode = errorExitCode(err);
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1972
1979
|
}
|
|
1980
|
+
if (!identifier) throw new UsageError(usage);
|
|
1973
1981
|
try {
|
|
1974
1982
|
const result = await deps.checkStorePreflight({
|
|
1975
1983
|
platform,
|
|
@@ -1994,6 +2002,32 @@ async function checkStore(platform, androidFamily, ascKey2, opts, deps) {
|
|
|
1994
2002
|
process.exitCode = errorExitCode(err);
|
|
1995
2003
|
}
|
|
1996
2004
|
}
|
|
2005
|
+
async function linkedIdentifier(platform, opts, deps) {
|
|
2006
|
+
if (!deps.getApp) return void 0;
|
|
2007
|
+
let appId;
|
|
2008
|
+
try {
|
|
2009
|
+
appId = loadDevConfig(process.cwd())?.platforms?.[platform]?.appId;
|
|
2010
|
+
} catch {
|
|
2011
|
+
return void 0;
|
|
2012
|
+
}
|
|
2013
|
+
if (!appId) return void 0;
|
|
2014
|
+
let app;
|
|
2015
|
+
try {
|
|
2016
|
+
app = await deps.getApp(appId);
|
|
2017
|
+
} catch (err) {
|
|
2018
|
+
if (err instanceof NotFoundError) {
|
|
2019
|
+
throw new Error(
|
|
2020
|
+
`the app linked in vibeview.json for ${platform} (${appId}) no longer exists \u2014 ` + (platform === "android" || platform === "androidtv" ? "pass --package <name>" : "pass --bundle-id <id>")
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
throw err;
|
|
2024
|
+
}
|
|
2025
|
+
if (!app.package_name) return void 0;
|
|
2026
|
+
if (!opts.json) {
|
|
2027
|
+
console.error(chalk14.dim(`Checking ${app.package_name} (${app.name}, linked in vibeview.json)`));
|
|
2028
|
+
}
|
|
2029
|
+
return app.package_name;
|
|
2030
|
+
}
|
|
1997
2031
|
async function resolveLatestBuild(platform, deps) {
|
|
1998
2032
|
const { builds: builds2 } = await deps.listCloudBuilds({
|
|
1999
2033
|
platform,
|
|
@@ -3648,11 +3682,15 @@ program.command("dev").description(
|
|
|
3648
3682
|
false
|
|
3649
3683
|
).option(
|
|
3650
3684
|
"--build [id]",
|
|
3651
|
-
"Bare: build and upload first (uses platforms.<platform>.build from vibeview.json). With an id: run that uploaded debug build instead of the newest one (see `vibeview list-builds <app>`)",
|
|
3685
|
+
"Bare: build and upload first (uses platforms.<platform>.build from vibeview.json). With an id: run that uploaded debug build instead of the newest one (any build with --standalone) (see `vibeview list-builds <app>`)",
|
|
3652
3686
|
false
|
|
3653
3687
|
).option(
|
|
3654
3688
|
"--watch [seconds]",
|
|
3655
3689
|
"Roku only: auto-reload after file changes settle (default: 2 seconds of quiet)"
|
|
3690
|
+
).option(
|
|
3691
|
+
"--standalone",
|
|
3692
|
+
"Run the build as it is, with no Metro and no tunnel (a release, CI or cloud build); without --build <id>, the newest release build. Code changes do not hot-reload",
|
|
3693
|
+
false
|
|
3656
3694
|
).action((opts) => dev(opts));
|
|
3657
3695
|
program.command("build").description("Run your configured build command and upload the result (see vibeview.json)").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option(
|
|
3658
3696
|
"--platform <platform>",
|
|
@@ -3687,13 +3725,13 @@ program.command("submit").description(
|
|
|
3687
3725
|
"ios/tvos only: which stored App Store Connect key to use (default when exactly one \u2014 see `vibeview credentials asc-key add`)"
|
|
3688
3726
|
).option(
|
|
3689
3727
|
"--release-status <status>",
|
|
3690
|
-
"android/androidtv only: Play release status \u2014 completed (default
|
|
3728
|
+
"android/androidtv only: Play release status \u2014 completed, draft, or inProgress (default: draft on the production track, completed on the others)"
|
|
3691
3729
|
).option(
|
|
3692
3730
|
"--rollout <fraction>",
|
|
3693
3731
|
"android/androidtv only: staged-rollout fraction, 0 < f < 1 (requires --release-status inProgress)"
|
|
3694
3732
|
).option(
|
|
3695
3733
|
"--check",
|
|
3696
|
-
"Only check store readiness: does the store know this app with your stored key? Takes --platform plus --bundle-id (ios/tvos) or --package (android/androidtv); no build needed. Exit 0 when ready",
|
|
3734
|
+
"Only check store readiness: does the store know this app with your stored key? Takes --platform plus --bundle-id (ios/tvos) or --package (android/androidtv), defaulting to the app linked in vibeview.json; no build needed. Exit 0 when ready",
|
|
3697
3735
|
false
|
|
3698
3736
|
).option("--bundle-id <id>", "ios/tvos, with --check: the bundle identifier to look up").option("--no-wait", "Print the submission id and exit without waiting for completion").option("--json", "Emit line-delimited JSON events on stdout instead of human output", false).action((opts) => submitCommand(opts));
|
|
3699
3737
|
var builds = program.command("builds").description("Manage cloud builds (see `vibeview build --cloud`)");
|
|
@@ -3793,7 +3831,7 @@ program.command("dev-reload").description(
|
|
|
3793
3831
|
program.command("mcp").description(
|
|
3794
3832
|
"Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
|
|
3795
3833
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
|
|
3796
|
-
const { runMcpServer } = await import("./server-
|
|
3834
|
+
const { runMcpServer } = await import("./server-IGY2VPYT.js");
|
|
3797
3835
|
await runMcpServer({ ...opts, version: pkg.version });
|
|
3798
3836
|
});
|
|
3799
3837
|
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.29.0",
|
|
4
4
|
"description": "VibeView CLI -- run your app on cloud iOS simulators, Android emulators, Apple TV, Android TV and Roku (beta) 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",
|