vibeview 0.12.1 → 0.12.3
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.
|
@@ -128,8 +128,11 @@ function loadDevConfig(cwd) {
|
|
|
128
128
|
`vibeview.json: unknown platform "${key}" (expected one of ${DEV_PLATFORMS.join(", ")})`
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
|
-
if (!entry || typeof entry
|
|
132
|
-
throw new Error(`vibeview.json: platforms.${key}
|
|
131
|
+
if (!entry || typeof entry !== "object") {
|
|
132
|
+
throw new Error(`vibeview.json: platforms.${key} must be an object`);
|
|
133
|
+
}
|
|
134
|
+
if (entry.appId !== void 0 && (typeof entry.appId !== "string" || !entry.appId)) {
|
|
135
|
+
throw new Error(`vibeview.json: platforms.${key}.appId must be a non-empty string`);
|
|
133
136
|
}
|
|
134
137
|
if (entry.build !== void 0) {
|
|
135
138
|
if (typeof entry.build !== "object" || entry.build === null) {
|
|
@@ -411,6 +414,15 @@ function platformChoices(cwd) {
|
|
|
411
414
|
if (detectFlavor(cwd) === "roku") choices.unshift({ value: "roku", name: "Roku (beta)" });
|
|
412
415
|
return choices;
|
|
413
416
|
}
|
|
417
|
+
function appsForPlatform(apps, platform) {
|
|
418
|
+
return apps.filter((a) => a.platform === platform);
|
|
419
|
+
}
|
|
420
|
+
function noAppsMessage(platform, hasBuildConfig) {
|
|
421
|
+
if (hasBuildConfig) {
|
|
422
|
+
return `No ${platform} apps found \u2014 run \`vibeview dev --build\` (or \`vibeview build\`) to build and upload one.`;
|
|
423
|
+
}
|
|
424
|
+
return `No ${platform} apps found. Run \`vibeview build --platform ${platform}\` to build and upload one (it will ask for your build command), or upload a build with \`vibeview upload-app\`.`;
|
|
425
|
+
}
|
|
414
426
|
function firstRunAppStrategy(apps, buildConfigured) {
|
|
415
427
|
if (!buildConfigured) return "picker";
|
|
416
428
|
return apps.length === 0 ? "build_now" : "ask";
|
|
@@ -699,34 +711,59 @@ async function resolveBarePlatform(cwd, cfg, opts) {
|
|
|
699
711
|
}
|
|
700
712
|
return platform;
|
|
701
713
|
}
|
|
714
|
+
function persistPromptedBuild(cwd, cfg, platform, build) {
|
|
715
|
+
const next = cfg ?? { defaultPlatform: platform, platforms: {} };
|
|
716
|
+
const entry = next.platforms[platform];
|
|
717
|
+
if (entry) {
|
|
718
|
+
entry.build = build;
|
|
719
|
+
} else {
|
|
720
|
+
next.platforms[platform] = { build };
|
|
721
|
+
}
|
|
722
|
+
saveDevConfig(cwd, next);
|
|
723
|
+
return next;
|
|
724
|
+
}
|
|
725
|
+
function persistUploadedAppId(cwd, cfg, platform, build, appId) {
|
|
726
|
+
const next = cfg ?? { defaultPlatform: platform, platforms: {} };
|
|
727
|
+
const entry = next.platforms[platform];
|
|
728
|
+
if (!entry) {
|
|
729
|
+
next.platforms[platform] = { appId, build };
|
|
730
|
+
saveDevConfig(cwd, next);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
if (entry.appId !== appId || !entry.build) {
|
|
734
|
+
entry.appId = appId;
|
|
735
|
+
entry.build = build;
|
|
736
|
+
saveDevConfig(cwd, next);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
async function resolveBuildConfig(cwd, cfgRef, platform, opts) {
|
|
740
|
+
const existing = cfgRef.current?.platforms?.[platform]?.build;
|
|
741
|
+
if (existing) return existing;
|
|
742
|
+
if (opts.json || !process.stdin.isTTY) {
|
|
743
|
+
fail(
|
|
744
|
+
opts,
|
|
745
|
+
`no build config for ${platform}: add platforms.${platform}.build {command, artifact} to vibeview.json`,
|
|
746
|
+
"config_required"
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
const answered = await promptBuildConfig(cwd, platform);
|
|
750
|
+
if (!answered) {
|
|
751
|
+
fail(opts, "build config is required to run vibeview build", "config_required");
|
|
752
|
+
}
|
|
753
|
+
cfgRef.current = persistPromptedBuild(cwd, cfgRef.current, platform, answered);
|
|
754
|
+
return answered;
|
|
755
|
+
}
|
|
702
756
|
async function buildCommand(opts, cloudDeps) {
|
|
703
757
|
const cwd = process.cwd();
|
|
704
|
-
const
|
|
758
|
+
const cfgRef = { current: loadDevConfig(cwd) };
|
|
705
759
|
try {
|
|
706
760
|
if (opts.cloud) {
|
|
707
|
-
await runCloudBuildCommand(cwd,
|
|
761
|
+
await runCloudBuildCommand(cwd, cfgRef, opts, cloudDeps);
|
|
708
762
|
return;
|
|
709
763
|
}
|
|
710
|
-
const platform = await resolveBarePlatform(cwd,
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
if (opts.json || !process.stdin.isTTY) {
|
|
714
|
-
fail(
|
|
715
|
-
opts,
|
|
716
|
-
`no build config for ${platform}: add platforms.${platform}.build {command, artifact} to vibeview.json`,
|
|
717
|
-
"config_required"
|
|
718
|
-
);
|
|
719
|
-
}
|
|
720
|
-
const answered = await promptBuildConfig(cwd, platform);
|
|
721
|
-
if (!answered) {
|
|
722
|
-
fail(opts, "build config is required to run vibeview build", "config_required");
|
|
723
|
-
}
|
|
724
|
-
build = answered;
|
|
725
|
-
if (cfg?.platforms?.[platform]) {
|
|
726
|
-
cfg.platforms[platform].build = build;
|
|
727
|
-
saveDevConfig(cwd, cfg);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
764
|
+
const platform = await resolveBarePlatform(cwd, cfgRef.current, opts);
|
|
765
|
+
const build = await resolveBuildConfig(cwd, cfgRef, platform, opts);
|
|
766
|
+
const cfg = cfgRef.current;
|
|
730
767
|
const result = await runBuildForPlatform(
|
|
731
768
|
cwd,
|
|
732
769
|
platform,
|
|
@@ -735,16 +772,7 @@ async function buildCommand(opts, cloudDeps) {
|
|
|
735
772
|
(l) => console.error(chalk.dim(l))
|
|
736
773
|
);
|
|
737
774
|
for (const w of result.warnings ?? []) console.error(chalk.yellow(`\u26A0 ${w}`));
|
|
738
|
-
|
|
739
|
-
const entry = nextCfg.platforms[platform];
|
|
740
|
-
if (!entry) {
|
|
741
|
-
nextCfg.platforms[platform] = { appId: result.public_id, build };
|
|
742
|
-
saveDevConfig(cwd, nextCfg);
|
|
743
|
-
} else if (entry.appId !== result.public_id || !entry.build) {
|
|
744
|
-
entry.appId = result.public_id;
|
|
745
|
-
entry.build = build;
|
|
746
|
-
saveDevConfig(cwd, nextCfg);
|
|
747
|
-
}
|
|
775
|
+
persistUploadedAppId(cwd, cfg, platform, build, result.public_id);
|
|
748
776
|
if (opts.json) {
|
|
749
777
|
console.log(
|
|
750
778
|
JSON.stringify({ app_id: result.public_id, name: result.name, platform: result.platform })
|
|
@@ -773,22 +801,29 @@ function fail(opts, message, code) {
|
|
|
773
801
|
function emitCloud(json, evt) {
|
|
774
802
|
if (json) console.log(JSON.stringify(evt));
|
|
775
803
|
}
|
|
776
|
-
async function resolveCloudPlatforms(cwd,
|
|
804
|
+
async function resolveCloudPlatforms(cwd, cfgRef, opts) {
|
|
777
805
|
if (opts.platform === "all") {
|
|
778
|
-
const configured = Object.entries(
|
|
806
|
+
const configured = Object.entries(cfgRef.current?.platforms ?? {});
|
|
779
807
|
const withBuild = configured.filter(([p, entry]) => isCloudPlatform(p) && entry?.build);
|
|
780
|
-
if (withBuild.length
|
|
808
|
+
if (withBuild.length > 0) return withBuild.map(([p]) => p);
|
|
809
|
+
if (opts.json || !process.stdin.isTTY) {
|
|
781
810
|
fail(
|
|
782
811
|
opts,
|
|
783
812
|
`--platform all: ${describeAllExclusions(configured)} \u2014 add platforms.<platform>.build {command, artifact} to vibeview.json`,
|
|
784
813
|
"config_required"
|
|
785
814
|
);
|
|
786
815
|
}
|
|
787
|
-
|
|
816
|
+
const chosen = await resolveBarePlatform(cwd, cfgRef.current, {
|
|
817
|
+
...opts,
|
|
818
|
+
platform: void 0
|
|
819
|
+
});
|
|
820
|
+
requireCloudCapable(opts, chosen);
|
|
821
|
+
await resolveBuildConfig(cwd, cfgRef, chosen, opts);
|
|
822
|
+
return [chosen];
|
|
788
823
|
}
|
|
789
|
-
const platform = opts.platform ? validateExplicitPlatform(opts.platform) : await resolveBarePlatform(cwd,
|
|
824
|
+
const platform = opts.platform ? validateExplicitPlatform(opts.platform) : await resolveBarePlatform(cwd, cfgRef.current, opts);
|
|
790
825
|
requireCloudCapable(opts, platform);
|
|
791
|
-
|
|
826
|
+
await resolveBuildConfig(cwd, cfgRef, platform, opts);
|
|
792
827
|
return [platform];
|
|
793
828
|
}
|
|
794
829
|
function validateExplicitPlatform(raw) {
|
|
@@ -808,14 +843,72 @@ function requireCloudCapable(opts, platform) {
|
|
|
808
843
|
);
|
|
809
844
|
}
|
|
810
845
|
}
|
|
811
|
-
function
|
|
812
|
-
|
|
846
|
+
function persistPickedAppId(cwd, cfg, platform, appId) {
|
|
847
|
+
const next = cfg ?? { defaultPlatform: platform, platforms: {} };
|
|
848
|
+
const entry = next.platforms[platform];
|
|
849
|
+
if (entry) {
|
|
850
|
+
entry.appId = appId;
|
|
851
|
+
} else {
|
|
852
|
+
next.platforms[platform] = { appId };
|
|
853
|
+
}
|
|
854
|
+
saveDevConfig(cwd, next);
|
|
855
|
+
return next;
|
|
856
|
+
}
|
|
857
|
+
var CREATE_NEW_APP = "__vibeview_create_new_app__";
|
|
858
|
+
async function resolveCloudAppIds(cwd, cfgRef, platforms, opts, listApps) {
|
|
859
|
+
const createFromArtifact = /* @__PURE__ */ new Set();
|
|
860
|
+
const missing = platforms.filter((p) => !cfgRef.current?.platforms?.[p]?.appId);
|
|
861
|
+
if (missing.length === 0) return createFromArtifact;
|
|
862
|
+
if (opts.json || !process.stdin.isTTY) {
|
|
863
|
+
for (const platform of missing) createFromArtifact.add(platform);
|
|
864
|
+
return createFromArtifact;
|
|
865
|
+
}
|
|
866
|
+
let allApps;
|
|
867
|
+
try {
|
|
868
|
+
allApps = await listApps();
|
|
869
|
+
} catch (err) {
|
|
813
870
|
fail(
|
|
814
871
|
opts,
|
|
815
|
-
`
|
|
816
|
-
"config_required"
|
|
872
|
+
`could not fetch your app list \u2014 ${err instanceof Error ? err.message : String(err)}`
|
|
817
873
|
);
|
|
818
874
|
}
|
|
875
|
+
for (const platform of missing) {
|
|
876
|
+
const apps = appsForPlatform(allApps, platform);
|
|
877
|
+
if (apps.length === 0) {
|
|
878
|
+
createFromArtifact.add(platform);
|
|
879
|
+
if (!opts.json) {
|
|
880
|
+
console.error(
|
|
881
|
+
chalk.dim(`no ${platform} apps yet \u2014 this build will create one from the artifact`)
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
continue;
|
|
885
|
+
}
|
|
886
|
+
const appId = await select2({
|
|
887
|
+
message: platforms.length > 1 ? `Which app should these ${platform} builds attach to?` : "Which app should these builds attach to?",
|
|
888
|
+
// No platform suffix on the rows: the list is already filtered to this
|
|
889
|
+
// one platform, so `(ios)` on every row would be pure noise (same
|
|
890
|
+
// reasoning as dev.ts's picker).
|
|
891
|
+
choices: [
|
|
892
|
+
...apps.map((a) => ({ value: a.public_id, name: a.name })),
|
|
893
|
+
{ value: CREATE_NEW_APP, name: "Create a new app from this build" }
|
|
894
|
+
]
|
|
895
|
+
});
|
|
896
|
+
if (appId === CREATE_NEW_APP) {
|
|
897
|
+
createFromArtifact.add(platform);
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
cfgRef.current = persistPickedAppId(cwd, cfgRef.current, platform, appId);
|
|
901
|
+
}
|
|
902
|
+
return createFromArtifact;
|
|
903
|
+
}
|
|
904
|
+
function persistResolvedAppIds(cwd, cfgRef, createFromArtifact, finished) {
|
|
905
|
+
for (const b of finished) {
|
|
906
|
+
if (!b.app_public_id) continue;
|
|
907
|
+
const platform = b.platform;
|
|
908
|
+
if (!createFromArtifact.has(platform)) continue;
|
|
909
|
+
if (cfgRef.current?.platforms?.[platform]?.appId) continue;
|
|
910
|
+
cfgRef.current = persistPickedAppId(cwd, cfgRef.current, platform, b.app_public_id);
|
|
911
|
+
}
|
|
819
912
|
}
|
|
820
913
|
function describeAllExclusions(configured) {
|
|
821
914
|
if (configured.length === 0) return "no platforms are configured";
|
|
@@ -857,6 +950,7 @@ function defaultCloudBuildDeps(client) {
|
|
|
857
950
|
return {
|
|
858
951
|
listSourceFiles,
|
|
859
952
|
packSource,
|
|
953
|
+
listApps: client.listApps.bind(client),
|
|
860
954
|
createCloudBuilds: client.createCloudBuilds.bind(client),
|
|
861
955
|
getCloudBuildLogs: client.getCloudBuildLogs.bind(client),
|
|
862
956
|
getCloudBuild: client.getCloudBuild.bind(client),
|
|
@@ -876,8 +970,13 @@ function formatDuration(startedAt, finishedAt) {
|
|
|
876
970
|
function formatCost(costMicro) {
|
|
877
971
|
return `$${(costMicro / 1e6).toFixed(2)}`;
|
|
878
972
|
}
|
|
879
|
-
async function runCloudBuildCommand(cwd,
|
|
880
|
-
const platforms = await resolveCloudPlatforms(cwd,
|
|
973
|
+
async function runCloudBuildCommand(cwd, cfgRef, opts, deps) {
|
|
974
|
+
const platforms = await resolveCloudPlatforms(cwd, cfgRef, opts);
|
|
975
|
+
const { token, baseUrl } = resolveAuth(opts);
|
|
976
|
+
const client = new ApiClient(baseUrl, token);
|
|
977
|
+
const d = deps ?? defaultCloudBuildDeps(client);
|
|
978
|
+
const createFromArtifact = await resolveCloudAppIds(cwd, cfgRef, platforms, opts, d.listApps);
|
|
979
|
+
const cfg = cfgRef.current;
|
|
881
980
|
for (const p of platforms) {
|
|
882
981
|
try {
|
|
883
982
|
validateBuildEnv(cfg?.platforms?.[p]?.build?.env, p);
|
|
@@ -885,9 +984,6 @@ async function runCloudBuildCommand(cwd, cfg, opts, deps) {
|
|
|
885
984
|
fail(opts, err instanceof Error ? err.message : String(err));
|
|
886
985
|
}
|
|
887
986
|
}
|
|
888
|
-
const { token, baseUrl } = resolveAuth(opts);
|
|
889
|
-
const client = new ApiClient(baseUrl, token);
|
|
890
|
-
const d = deps ?? defaultCloudBuildDeps(client);
|
|
891
987
|
let cleanupTar;
|
|
892
988
|
try {
|
|
893
989
|
let files;
|
|
@@ -927,7 +1023,12 @@ ${offenders}`);
|
|
|
927
1023
|
const build = entry.build;
|
|
928
1024
|
return {
|
|
929
1025
|
platform: p,
|
|
930
|
-
|
|
1026
|
+
// OMITTED, never invented, for a platform whose app the artifact will
|
|
1027
|
+
// create (resolveCloudAppIds). Otherwise the non-null assertion is
|
|
1028
|
+
// safe: resolveCloudAppIds ran for every entry in `platforms` above —
|
|
1029
|
+
// it either persisted a picked appId onto the entry, marked the
|
|
1030
|
+
// platform create-from-artifact, or failed the whole command.
|
|
1031
|
+
...createFromArtifact.has(p) ? {} : { app_public_id: entry.appId },
|
|
931
1032
|
command: build.command,
|
|
932
1033
|
artifact_path: build.artifact,
|
|
933
1034
|
...build.env ? { env: build.env } : {}
|
|
@@ -959,6 +1060,7 @@ ${offenders}`);
|
|
|
959
1060
|
return;
|
|
960
1061
|
}
|
|
961
1062
|
const finished = await waitForCloudBuilds(created, opts, d);
|
|
1063
|
+
persistResolvedAppIds(cwd, cfgRef, createFromArtifact, finished.values());
|
|
962
1064
|
let downloadFailed = false;
|
|
963
1065
|
if (opts.download) {
|
|
964
1066
|
for (const b of finished.values()) {
|
|
@@ -1845,20 +1947,11 @@ var PLATFORM_DEVICE = {
|
|
|
1845
1947
|
// handheld type plus category tv) — the worker registers it as such.
|
|
1846
1948
|
roku: { deviceType: "roku", tv: true }
|
|
1847
1949
|
};
|
|
1848
|
-
function appsForPlatform(apps, platform) {
|
|
1849
|
-
return apps.filter((a) => a.platform === platform);
|
|
1850
|
-
}
|
|
1851
1950
|
function validateAppChoice(requested, fromFlag, apps) {
|
|
1852
1951
|
if (!requested) return {};
|
|
1853
1952
|
if (apps.some((a) => a.public_id === requested)) return { appId: requested };
|
|
1854
1953
|
return fromFlag ? { staleFlag: requested } : { staleCached: requested };
|
|
1855
1954
|
}
|
|
1856
|
-
function noAppsMessage(platform, hasBuildConfig) {
|
|
1857
|
-
if (hasBuildConfig) {
|
|
1858
|
-
return `No ${platform} apps found \u2014 run \`vibeview dev --build\` (or \`vibeview build\`) to build and upload one.`;
|
|
1859
|
-
}
|
|
1860
|
-
return `No ${platform} apps found. Run \`vibeview build --platform ${platform}\` to build and upload one (it will ask for your build command), or upload a build with \`vibeview upload-app\`.`;
|
|
1861
|
-
}
|
|
1862
1955
|
function requireNonInteractive(json) {
|
|
1863
1956
|
if (!json) return;
|
|
1864
1957
|
emit(json, {
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
readDevState,
|
|
14
14
|
readMetroState,
|
|
15
15
|
runAgentVerb
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-2OI7HL6X.js";
|
|
17
17
|
import {
|
|
18
18
|
ApiClient,
|
|
19
19
|
EXIT_INFRA_ERROR,
|
|
@@ -1717,7 +1717,7 @@ program.command("dev-stop").description("Stop a `vibeview dev --detach` session
|
|
|
1717
1717
|
program.command("mcp").description(
|
|
1718
1718
|
"Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop as tools"
|
|
1719
1719
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
|
|
1720
|
-
const { runMcpServer } = await import("./server-
|
|
1720
|
+
const { runMcpServer } = await import("./server-25CXVTUV.js");
|
|
1721
1721
|
await runMcpServer(opts);
|
|
1722
1722
|
});
|
|
1723
1723
|
program.command("agent-setup").description(
|