vibeview 0.52.2 → 0.53.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
@@ -91,6 +91,7 @@ Build-time secrets work the same way:
91
91
 
92
92
  ```bash
93
93
  vibeview env set NPM_TOKEN "..." # secret by default, injected into builds
94
+ vibeview env set API_URL "https://staging.example.com" --plain --profile preview # only preview builds
94
95
  vibeview webhooks add --url https://ci.example.com/hooks/vibeview
95
96
  ```
96
97
 
@@ -13,7 +13,7 @@ import {
13
13
  resolveArtifact,
14
14
  resolveAuth,
15
15
  uploadAppBuild
16
- } from "./chunk-LRPZFDKL.js";
16
+ } from "./chunk-YCFQKMG7.js";
17
17
 
18
18
  // src/lib/formatters/not-checked.ts
19
19
  function notCheckedSteps(steps) {
@@ -6074,6 +6074,7 @@ export {
6074
6074
  stepsNotCheckedLabel,
6075
6075
  notCheckedSuffix,
6076
6076
  outcomeOf,
6077
+ PROFILE_NAME_RE,
6077
6078
  developmentProfile,
6078
6079
  DEV_PLATFORMS,
6079
6080
  PLATFORM_NEEDS_METRO,
@@ -560,7 +560,8 @@ var ApiClient = class {
560
560
  return this.requestRaw("GET", `/build-env/${qs}`);
561
561
  }
562
562
  /** POST /api/v1/build-env/ (JSON body) for a plain/sensitive/secret value.
563
- * Requires ADMIN role. Upserts by (org, app, name). */
563
+ * Requires ADMIN role. Upserts by (org, app, profile, name); `profile`
564
+ * omitted = every build profile. */
564
565
  async setBuildEnvVar(body) {
565
566
  return this.requestRaw("POST", "/build-env/", body);
566
567
  }
@@ -573,6 +574,7 @@ var ApiClient = class {
573
574
  formData.append("name", body.name);
574
575
  formData.append("visibility", body.visibility);
575
576
  if (body.app) formData.append("app", body.app);
577
+ if (body.profile) formData.append("profile", body.profile);
576
578
  const blob = new Blob([new Uint8Array(body.content)]);
577
579
  formData.append("file", blob, body.filename);
578
580
  return this.requestFormData("POST", "/build-env/", formData);
@@ -585,11 +587,15 @@ var ApiClient = class {
585
587
  async deleteBuildEnvVar(id) {
586
588
  await this.requestRaw("DELETE", `/build-env/${id}`);
587
589
  }
588
- /** GET /api/v1/build-env/pull[?app=]. Requires DEVELOPER role. The only
589
- * endpoint that returns values — already excludes secret/file variables
590
- * server-side. */
591
- async pullBuildEnvVars(app) {
592
- const qs = app ? `?app=${encodeURIComponent(app)}` : "";
590
+ /** GET /api/v1/build-env/pull[?app=][&profile=]. Requires DEVELOPER role.
591
+ * The only endpoint that returns values — already excludes secret/file
592
+ * variables server-side. With `profile`, the values a build of that
593
+ * profile gets (precedence resolved server-side). */
594
+ async pullBuildEnvVars(app, profile) {
595
+ const params = new URLSearchParams();
596
+ if (app) params.set("app", app);
597
+ if (profile) params.set("profile", profile);
598
+ const qs = params.toString() ? `?${params.toString()}` : "";
593
599
  return this.requestRaw("GET", `/build-env/pull${qs}`);
594
600
  }
595
601
  /** GET /api/v1/signing-credentials/[?app=]. Requires VIEWER role. Never
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  BUILD_TERMINAL_STATUSES,
5
5
  FEEDBACK_KINDS,
6
6
  FEEDBACK_RULES,
7
+ PROFILE_NAME_RE,
7
8
  buildCommand,
8
9
  clearDevState,
9
10
  createRokuPush,
@@ -35,7 +36,7 @@ import {
35
36
  runAgentVerb,
36
37
  runStepsNotChecked,
37
38
  stepsNotCheckedLabel
38
- } from "./chunk-S4VPSFPP.js";
39
+ } from "./chunk-O6MXCYWR.js";
39
40
  import {
40
41
  ApiClient,
41
42
  ApiStatusError,
@@ -58,7 +59,7 @@ import {
58
59
  runCommandParseExitCode,
59
60
  saveConfig,
60
61
  uploadApp
61
- } from "./chunk-LRPZFDKL.js";
62
+ } from "./chunk-YCFQKMG7.js";
62
63
 
63
64
  // src/cli.ts
64
65
  import { createRequire } from "module";
@@ -2882,6 +2883,17 @@ function isGitIgnored(path, cwd = process.cwd()) {
2882
2883
  }
2883
2884
 
2884
2885
  // src/commands/env.ts
2886
+ function checkProfileOption(profile) {
2887
+ if (profile === void 0) return;
2888
+ if (!PROFILE_NAME_RE.test(profile)) {
2889
+ throw new Error(
2890
+ `--profile must be a build profile name (lowercase letters, digits and dashes, starting with a letter), got "${profile}"`
2891
+ );
2892
+ }
2893
+ }
2894
+ function profileLabel(profile) {
2895
+ return profile ? `profile "${profile}"` : "every profile";
2896
+ }
2885
2897
  function clientFor(opts) {
2886
2898
  const { token, baseUrl } = resolveAuth(opts);
2887
2899
  return new ApiClient(baseUrl, token);
@@ -2900,10 +2912,20 @@ function defaultDeps5(client) {
2900
2912
  listVars: (app) => client.listBuildEnvVars(app),
2901
2913
  setVar: (body) => client.setBuildEnvVar(body),
2902
2914
  setFileVar: (body) => client.setBuildEnvFileVar(body),
2903
- rmVar: async ({ name, app }) => {
2915
+ rmVar: async ({ name, app, profile }) => {
2904
2916
  const { variables } = await client.listBuildEnvVars(app);
2905
2917
  const wantApp = app ?? null;
2906
- const match = variables.find((v) => v.name === name && (v.app_public_id ?? null) === wantApp);
2918
+ const wantProfile = profile ?? null;
2919
+ const inScope = variables.filter(
2920
+ (v) => v.name === name && (v.app_public_id ?? null) === wantApp
2921
+ );
2922
+ const match = inScope.find((v) => (v.profile ?? null) === wantProfile);
2923
+ if (!match && inScope.length > 0) {
2924
+ const others = inScope.map((v) => v.profile ? `--profile ${v.profile}` : "no --profile (every profile)").join(", ");
2925
+ throw new Error(
2926
+ `No variable named "${name}" for ${profileLabel(wantProfile)}${app ? ` in app "${app}"` : ""}. It exists for: ${others}. Re-run with the matching --profile to remove one.`
2927
+ );
2928
+ }
2907
2929
  if (!match) {
2908
2930
  const otherScope = variables.find((v) => v.name === name);
2909
2931
  if (otherScope) {
@@ -2915,7 +2937,7 @@ function defaultDeps5(client) {
2915
2937
  }
2916
2938
  await client.deleteBuildEnvVar(match.id);
2917
2939
  },
2918
- pullVars: (app) => client.pullBuildEnvVars(app),
2940
+ pullVars: (app, profile) => client.pullBuildEnvVars(app, profile),
2919
2941
  // `hidden` is always true in practice (env set only prompts for secret
2920
2942
  // values), but the parameter exists so a future caller/test can't
2921
2943
  // accidentally get echoed input by omitting it.
@@ -2928,9 +2950,11 @@ function defaultDeps5(client) {
2928
2950
  };
2929
2951
  }
2930
2952
  async function envList(opts, deps) {
2953
+ checkProfileOption(opts.profile);
2931
2954
  const d = deps ?? defaultDeps5(clientFor(opts));
2932
2955
  try {
2933
- const { variables } = await d.listVars(opts.app);
2956
+ const listed = (await d.listVars(opts.app)).variables;
2957
+ const variables = opts.profile ? listed.filter((v) => (v.profile ?? null) === null || v.profile === opts.profile) : listed;
2934
2958
  if (opts.json) {
2935
2959
  console.log(JSON.stringify(variables, null, 2));
2936
2960
  } else {
@@ -2946,11 +2970,12 @@ function formatEnvVarsHuman(variables) {
2946
2970
  if (variables.length === 0) {
2947
2971
  return "No build variables found.\n";
2948
2972
  }
2949
- const HEADERS3 = ["NAME", "VISIBILITY", "SCOPE", "HINT"];
2973
+ const HEADERS3 = ["NAME", "VISIBILITY", "SCOPE", "PROFILE", "HINT"];
2950
2974
  const rows = variables.map((v) => [
2951
2975
  v.name,
2952
2976
  v.is_file ? `${v.visibility} (file)` : v.visibility,
2953
2977
  v.app_public_id ?? "org-wide",
2978
+ v.profile ?? "all",
2954
2979
  v.value_hint ?? ""
2955
2980
  ]);
2956
2981
  const widths = HEADERS3.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
@@ -2961,6 +2986,7 @@ function formatEnvVarsHuman(variables) {
2961
2986
  return lines.join("\n") + "\n";
2962
2987
  }
2963
2988
  async function envSet(name, value, opts, deps) {
2989
+ checkProfileOption(opts.profile);
2964
2990
  const d = deps ?? defaultDeps5(clientFor(opts));
2965
2991
  let resolvedValue = value;
2966
2992
  if (resolvedValue === void 0 && !opts.file) {
@@ -2975,7 +3001,14 @@ async function envSet(name, value, opts, deps) {
2975
3001
  if (opts.file) {
2976
3002
  const content = await d.readFile(opts.file);
2977
3003
  const filename = basename2(opts.file);
2978
- const result2 = await d.setFileVar({ name, content, filename, visibility, app: opts.app });
3004
+ const result2 = await d.setFileVar({
3005
+ name,
3006
+ content,
3007
+ filename,
3008
+ visibility,
3009
+ app: opts.app,
3010
+ profile: opts.profile
3011
+ });
2979
3012
  printSetResult(opts, result2);
2980
3013
  process.exitCode = 0;
2981
3014
  return;
@@ -2983,7 +3016,13 @@ async function envSet(name, value, opts, deps) {
2983
3016
  if (resolvedValue === void 0) {
2984
3017
  resolvedValue = await d.prompt({ message: `Value for ${name}`, hidden: true });
2985
3018
  }
2986
- const result = await d.setVar({ name, value: resolvedValue, visibility, app: opts.app });
3019
+ const result = await d.setVar({
3020
+ name,
3021
+ value: resolvedValue,
3022
+ visibility,
3023
+ app: opts.app,
3024
+ profile: opts.profile
3025
+ });
2987
3026
  printSetResult(opts, result);
2988
3027
  process.exitCode = 0;
2989
3028
  } catch (err) {
@@ -3006,17 +3045,20 @@ function printSetResult(opts, result) {
3006
3045
  if (opts.json) {
3007
3046
  console.log(JSON.stringify(result));
3008
3047
  } else {
3009
- console.log(chalk20.green(`\u2713 set ${result.name} (${result.visibility})`));
3048
+ const forProfile = opts.profile ? `, profile ${opts.profile}` : "";
3049
+ console.log(chalk20.green(`\u2713 set ${result.name} (${result.visibility}${forProfile})`));
3010
3050
  }
3011
3051
  }
3012
3052
  async function envRm(name, opts, deps) {
3053
+ checkProfileOption(opts.profile);
3013
3054
  const d = deps ?? defaultDeps5(clientFor(opts));
3014
3055
  try {
3015
- await d.rmVar({ name, app: opts.app });
3056
+ await d.rmVar({ name, app: opts.app, profile: opts.profile });
3016
3057
  if (opts.json) {
3017
- console.log(JSON.stringify({ event: "deleted", name }));
3058
+ console.log(JSON.stringify({ event: "deleted", name, profile: opts.profile ?? null }));
3018
3059
  } else {
3019
- console.log(chalk20.green(`\u2713 removed ${name}`));
3060
+ const forProfile = opts.profile ? ` (profile ${opts.profile})` : "";
3061
+ console.log(chalk20.green(`\u2713 removed ${name}${forProfile}`));
3020
3062
  }
3021
3063
  process.exitCode = 0;
3022
3064
  } catch (err) {
@@ -3025,10 +3067,11 @@ async function envRm(name, opts, deps) {
3025
3067
  }
3026
3068
  }
3027
3069
  async function envPull(opts, deps) {
3070
+ checkProfileOption(opts.profile);
3028
3071
  const d = deps ?? defaultDeps5(clientFor(opts));
3029
3072
  const outPath = opts.out ?? ".env";
3030
3073
  try {
3031
- const { variables } = await d.pullVars(opts.app);
3074
+ const { variables } = await d.pullVars(opts.app, opts.profile);
3032
3075
  const ignored = await d.isIgnored(outPath);
3033
3076
  if (!ignored) {
3034
3077
  d.warn(
@@ -4432,17 +4475,29 @@ versions.command("set <number>").description(
4432
4475
  ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "App public id (see `vibeview list-apps`)").option("--platform <platform>", "ios, android, tvos, or androidtv").option("--json", "Print the updated version object as one JSON line", false).action((number, opts) => versionsSet(number, opts));
4433
4476
  program.command("whoami").description("Show which account and role this CLI is authenticated as").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--json", "Print the identity as one JSON line", false).action((opts) => whoAmI(opts));
4434
4477
  var env = program.command("env").description("Manage cloud build environment variables and secrets");
4435
- env.command("list").description("List build variables and secrets (never prints a value)").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide variables only)").option("--json", "Print the raw variable list as a JSON array", false).action((opts) => envList(opts));
4478
+ env.command("list").description("List build variables and secrets (never prints a value)").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide variables only)").option(
4479
+ "--profile <name>",
4480
+ "Only variables a build of this vibeview.json build profile can use (its own + every-profile ones)"
4481
+ ).option("--json", "Print the raw variable list as a JSON array", false).action((opts) => envList(opts));
4436
4482
  env.command("set <name> [value]").description(
4437
4483
  "Set a build variable or secret. Defaults to --secret (never retrievable via the API) unless --plain or --sensitive is passed explicitly."
4438
- ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide)").option("--secret", "Store as secret (default): never returned by the API, including `env pull`").option(
4484
+ ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide)").option(
4485
+ "--profile <name>",
4486
+ "Limit to one vibeview.json build profile (default: every profile); its value beats the every-profile one"
4487
+ ).option("--secret", "Store as secret (default): never returned by the API, including `env pull`").option(
4439
4488
  "--sensitive",
4440
4489
  "Store as sensitive: value_hint only in `env list`, full value via `env pull`"
4441
4490
  ).option("--plain", "Store as plain: value returned by `env pull`, unmasked").option("--file <path>", "Upload a file as the value (e.g. a keystore) instead of a text value").option("--json", "Print the resulting variable as one JSON line", false).action((name, value, opts) => envSet(name, value, opts));
4442
- env.command("rm <name>").description("Remove a build variable or secret").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide)").option("--json", "Print the result as one JSON line", false).action((name, opts) => envRm(name, opts));
4491
+ env.command("rm <name>").description("Remove a build variable or secret").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide)").option(
4492
+ "--profile <name>",
4493
+ "Remove the one limited to this build profile (default: the every-profile one)"
4494
+ ).option("--json", "Print the result as one JSON line", false).action((name, opts) => envRm(name, opts));
4443
4495
  env.command("pull").description(
4444
4496
  "Write plain/sensitive variable values to a .env file (secrets and files are never included)"
4445
- ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide variables only)").option("--out <path>", "Output file path (default: .env)").option("--json", "Print the result as one JSON line", false).action((opts) => envPull(opts));
4497
+ ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--app <id>", "Scope to a single app (default: org-wide variables only)").option(
4498
+ "--profile <name>",
4499
+ "Write the values a build of this vibeview.json build profile gets (default: every-profile values only)"
4500
+ ).option("--out <path>", "Output file path (default: .env)").option("--json", "Print the result as one JSON line", false).action((opts) => envPull(opts));
4446
4501
  var credentials = program.command("credentials").description("Manage app-signing credentials for production cloud builds");
4447
4502
  credentials.command("add").description(
4448
4503
  "Add a signing credential. Prompts for passwords with hidden input \u2014 they are never accepted as flags (a flag lands in shell history and in `ps`)."
@@ -4520,7 +4575,7 @@ program.command("dev-reload").description(
4520
4575
  program.command("mcp").description(
4521
4576
  "Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop/dev_reload as tools"
4522
4577
  ).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
4523
- const { runMcpServer } = await import("./server-5VWZMZRE.js");
4578
+ const { runMcpServer } = await import("./server-JLT3PQTH.js");
4524
4579
  await runMcpServer({ ...opts, version: pkg.version });
4525
4580
  });
4526
4581
  program.command("agent-setup").description(
@@ -35,12 +35,12 @@ import {
35
35
  renderEnvelope,
36
36
  resolveMetro,
37
37
  startDevSession
38
- } from "./chunk-S4VPSFPP.js";
38
+ } from "./chunk-O6MXCYWR.js";
39
39
  import {
40
40
  ApiClient,
41
41
  NotFoundError,
42
42
  resolveAuth
43
- } from "./chunk-LRPZFDKL.js";
43
+ } from "./chunk-YCFQKMG7.js";
44
44
 
45
45
  // src/mcp/server.ts
46
46
  import { writeFileSync } from "fs";
@@ -999,7 +999,7 @@ async function handleUploadApp(args, deps) {
999
999
  }
1000
1000
  const name = typeof args.name === "string" && args.name ? args.name : void 0;
1001
1001
  const upload = deps.uploadApp ?? (async (f, n) => {
1002
- const { uploadAppBuild } = await import("./upload-app-OV3QKL7O.js");
1002
+ const { uploadAppBuild } = await import("./upload-app-KQCXAZST.js");
1003
1003
  const { result: result2 } = await uploadAppBuild(f, { ...deps.auth, name: n });
1004
1004
  return result2;
1005
1005
  });
@@ -3,7 +3,7 @@ import {
3
3
  describeBuild,
4
4
  uploadApp,
5
5
  uploadAppBuild
6
- } from "./chunk-LRPZFDKL.js";
6
+ } from "./chunk-YCFQKMG7.js";
7
7
  export {
8
8
  describeBuild,
9
9
  uploadApp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeview",
3
- "version": "0.52.2",
3
+ "version": "0.53.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",