unoverse 0.1.212 → 0.1.213

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/lib/login.mjs CHANGED
@@ -174,7 +174,7 @@ export async function login(universeInput, { log = console.log } = {}) {
174
174
  if (!config.authEnabled) {
175
175
  throw new Error(
176
176
  `${origin} has authentication switched off, so there is no account to sign in with.\n` +
177
- ` To deploy there, set UNOVERSE_TOKEN to a deploy key minted on the universe itself.`,
177
+ ` To deploy there, set UNOVERSE_TOKEN to a publish key minted on the universe itself.`,
178
178
  );
179
179
  }
180
180
  if (!config.issuer) throw new Error(`${origin} has no identity provider configured.`);
@@ -257,13 +257,13 @@ export async function tokenFor(origin, { interactive = true, log = console.log }
257
257
  } else if (!config.authEnabled) {
258
258
  throw new Error(
259
259
  `${origin} has authentication switched off.\n` +
260
- ` To deploy there, set UNOVERSE_TOKEN to a deploy key minted on the universe itself.`,
260
+ ` To deploy there, set UNOVERSE_TOKEN to a publish key minted on the universe itself.`,
261
261
  );
262
262
  }
263
263
 
264
264
  if (!interactive || !process.stdin.isTTY) {
265
265
  throw new Error(
266
- `No credential for ${origin}. In CI, set UNOVERSE_TOKEN to a deploy key.\n` +
266
+ `No credential for ${origin}. In CI, set UNOVERSE_TOKEN to a publish key.\n` +
267
267
  ` At a terminal, run: unoverse login ${origin}`,
268
268
  );
269
269
  }
package/lib/publish.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * unoverse publish — ship an asset workspace's items to its universe.
2
+ * unoverse deploy studio: ship an asset workspace's items to its universe.
3
3
  *
4
4
  * The terminal face of @unoverse-platform/base items/publish. The order is the safety:
5
5
  * LINT, then COMPARE (a dry-run per item against the universe), then a plan and a
@@ -49,7 +49,7 @@ const ask = async (question) => {
49
49
  };
50
50
 
51
51
  /**
52
- * `unoverse publish [project] [--to <universe>] [--dry-run] [--yes]`
52
+ * `unoverse deploy studio [project] [--to <universe> | --env <name>] [--dry-run] [--yes]`
53
53
  * Run from anywhere inside an asset workspace. bin/unoverse.mjs routes here only when
54
54
  * the nearest marker up from cwd is a design home.
55
55
  */
@@ -59,7 +59,9 @@ export async function publish(args) {
59
59
  const i = args.indexOf(`--${name}`);
60
60
  return i >= 0 ? args[i + 1] : undefined;
61
61
  };
62
- const positional = args.find((a) => !a.startsWith("--") && a !== opt("to"));
62
+ // An option's value is never the project: `--env uat` must not read "uat" as one.
63
+ const optionValues = new Set(["to", "env"].map(opt).filter(Boolean));
64
+ const positional = args.find((a) => !a.startsWith("--") && !optionValues.has(a));
63
65
 
64
66
  const ws = findWorkspace();
65
67
  if (ws?.kind !== "assets") die("no design/ folder here or above. Run this inside your workspace.");
@@ -81,10 +83,20 @@ export async function publish(args) {
81
83
  die(`no project "${project}" in ${designRoot}. Found: ${projects.join(", ") || "none"}`);
82
84
  }
83
85
 
84
- // ── which universe: --to overrides, unoverse.yaml remembers, the login answers,
85
- // and only a machine that knows nothing asks ─────────────────────────────
86
+ // ── which universe: --to overrides, --env names one from unoverse.yaml's
87
+ // `environments:`, `universe:` is the default, the login answers, and only a
88
+ // machine that knows nothing asks ─────────────────────────────────────────
86
89
  const config = await readConfig(ws.root);
87
- let universe = opt("to") ?? config.universe;
90
+ const envName = opt("env");
91
+ let envUniverse;
92
+ if (envName && !opt("to")) {
93
+ envUniverse = config.environments?.[envName];
94
+ if (!envUniverse) {
95
+ const known = Object.keys(config.environments ?? {});
96
+ die(`no environment "${envName}" in unoverse.yaml. ${known.length ? `Found: ${known.join(", ")}` : "Add one:\n\n environments:\n " + envName + ": https://your-universe.example"}`);
97
+ }
98
+ }
99
+ let universe = opt("to") ?? envUniverse ?? config.universe;
88
100
  if (!universe) {
89
101
  // THE LOGIN ALREADY NAMED THE UNIVERSE. `unoverse login` takes an address and
90
102
  // keeps a session for it, so a machine signed in to exactly one universe has
package/lib/ui.mjs CHANGED
@@ -22,7 +22,7 @@ export async function ask(rl, q) {
22
22
  }
23
23
 
24
24
  export const OPTIONS = [
25
- ["Studio", "Components, agents and workflows", "Most people start here"],
25
+ ["Studio", "Components, apps, agents and nodes", "Most people start here"],
26
26
  ["Universe", "Run the platform yourself, on your own infrastructure"],
27
27
  ["Client", "A client accelerator that talks to unoverse"],
28
28
  ];
package/lib/workspace.mjs CHANGED
@@ -6,10 +6,11 @@
6
6
  * reason studio keeps one: this package is plain node and cannot import base's TypeScript.
7
7
  * Keep the three in step.
8
8
  *
9
- * `unoverse.yaml` at the workspace root is the COMMITTED project config — today one key,
10
- * `universe:`, the publish target. It is config, not a secret: the whole team and CI
11
- * publish to the same place, which is exactly why it belongs in the repo. Credentials
12
- * never live here (they are per machine, in ~/.unoverse — see session.mjs).
9
+ * `unoverse.yaml` at the workspace root is the COMMITTED project config: `universe:`, the
10
+ * default deploy target, and `environments:`, named targets (`uat`, `production`) that CI
11
+ * picks with `--env`. It is config, not a secret: the whole team and CI deploy to the same
12
+ * places, which is exactly why it belongs in the repo. Credentials never live here (they
13
+ * are per machine in ~/.unoverse, see session.mjs, or a CI secret in UNOVERSE_TOKEN).
13
14
  */
14
15
  import { existsSync, renameSync, readFileSync, writeFileSync } from "node:fs";
15
16
  import { join, resolve } from "node:path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unoverse",
3
- "version": "0.1.212",
3
+ "version": "0.1.213",
4
4
  "description": "The Unoverse front door — create a Studio project, a universe, or a client app, and launch Studio.",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",
@@ -924,6 +924,15 @@ function componentNamesForFile(file) {
924
924
  const org = projectSegs.join("/");
925
925
  const cached = componentNamesCache.get(org);
926
926
  if (cached !== undefined) return cached;
927
+ // A PARTIAL SET IS WORSE THAN NO SET (the app-sizes trap below, same cause). A developer's
928
+ // project has no design system on disk, so DS falls back to DESIGN_ROOT and only the org's
929
+ // own names would be left: every marketplace name a preview uses (`card`) then reads as
930
+ // unknown, and a fresh Studio workspace failed lint on its own sample. Unverifiable here,
931
+ // so not asserted.
932
+ if (DS === DESIGN_ROOT) {
933
+ componentNamesCache.set(org, null);
934
+ return null;
935
+ }
927
936
  const dirs = [
928
937
  join(DS, "components"),
929
938
  join(DESIGN_ROOT, ...projectSegs, "components"),