@genex-ai/cli-demo 0.48.0 → 0.49.0-dev.92

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
@@ -6,6 +6,7 @@ This is the `cli` app of the [genex monorepo](../../README.md).
6
6
  ```bash
7
7
  genex init <name> # authorize + create the draft project
8
8
  genex link <slug> # re-link this folder to an existing game of yours (recovery)
9
+ genex list # list your games — slug, status, page link (find the slug to link)
9
10
  genex preview # build + push to the hosted draft URL (unlisted)
10
11
  genex publish # build + push, then list the game in the gallery
11
12
  genex make-remixable # make this game remixable — migrate a private source to a public repo
@@ -15,9 +16,11 @@ genex sfx "<prompt>" # generate a sound fx → prints an asset URL
15
16
  genex texture "<prompt>" # generate a texture → prints an asset URL
16
17
  genex image "<prompt>" # generate an image → prints an asset URL
17
18
  genex video "<prompt>" # generate a video → prints an asset URL
19
+ genex wait <id> # attach to a --no-wait generation and print its URL(s) when done
18
20
  genex controller <type> # character|car|drone|networked-physics → src/controllers/
19
21
  genex controller anims <sel…> # download extra character animation clips (by tag or name) → public/assets/anims/
20
22
  genex ui <tool> # local pixel toolbox for generated UI art: extract | masks | text-color | trim
23
+ genex explore ["<query>"] # search the curated community gallery (no query lists the whole catalog)
21
24
  ```
22
25
 
23
26
  > **Invoking it.** First-time setup runs via `npx @genex-ai/cli-demo@latest init`.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import fs from "fs";
8
8
  import os from "os";
9
9
  import path from "path";
10
10
  import { fileURLToPath } from "url";
11
- var RAW_CHANNEL = "latest";
11
+ var RAW_CHANNEL = "dev";
12
12
  var CLI_CHANNEL = RAW_CHANNEL === "dev" ? "dev" : "latest";
13
13
  var STANDS = {
14
14
  prod: { api: "https://api.genex.games", dashboard: "https://genex.games" },
@@ -1328,6 +1328,113 @@ async function listOwnSlugs(apiUrl, token, log) {
1328
1328
  }
1329
1329
  }
1330
1330
 
1331
+ // src/commands/list.ts
1332
+ async function runList(opts) {
1333
+ const log = createLogger({ quiet: opts.quiet });
1334
+ const extra = opts.name?.trim();
1335
+ if (extra) {
1336
+ log.error(
1337
+ `\`genex list\` lists your games \u2014 \`genex list ${extra}\` isn't available yet.`
1338
+ );
1339
+ process.exitCode = 1;
1340
+ return;
1341
+ }
1342
+ let token = opts.token ?? await readUserToken(opts.envPath);
1343
+ if (!token) {
1344
+ if (opts.noAuth) {
1345
+ log.error("Not signed in. Re-run without --no-auth to connect in the browser.");
1346
+ process.exitCode = 1;
1347
+ return;
1348
+ }
1349
+ log.plain("Not signed in \u2014 opening the browser to connect\u2026");
1350
+ try {
1351
+ token = await authorize(getAuthUrl(opts.authUrl), {
1352
+ log,
1353
+ timeoutMs: opts.timeoutSec ? opts.timeoutSec * 1e3 : void 0
1354
+ });
1355
+ } catch (err) {
1356
+ log.error(`Sign-in didn't complete: ${String(err)}`);
1357
+ process.exitCode = 1;
1358
+ return;
1359
+ }
1360
+ const { path: tokenPath } = await writeUserToken(token, opts.envPath);
1361
+ log.success(`Authorized. Saved your token to ${c.cyan(tokenPath)}.`);
1362
+ log.plain("");
1363
+ }
1364
+ const meta = await readProject();
1365
+ const apiUrl = getApiUrl(opts.apiUrl ?? meta?.apiUrl);
1366
+ const dashOrigin = (meta?.dashboardOrigins?.[0] ?? getAuthUrl(opts.authUrl)).replace(/\/+$/, "");
1367
+ const projectsUrl = `${apiUrl}/api/projects`;
1368
+ const fetchProjects = (t) => apiFetch(projectsUrl, { headers: { Authorization: `Bearer ${t}` } });
1369
+ let res;
1370
+ try {
1371
+ res = await fetchProjects(token);
1372
+ if (res.status === 401 && !opts.token && !opts.noAuth) {
1373
+ log.plain("Your saved sign-in was rejected \u2014 reconnecting in the browser\u2026");
1374
+ token = await authorize(getAuthUrl(opts.authUrl), {
1375
+ log,
1376
+ timeoutMs: opts.timeoutSec ? opts.timeoutSec * 1e3 : void 0
1377
+ });
1378
+ await writeUserToken(token, opts.envPath);
1379
+ res = await fetchProjects(token);
1380
+ }
1381
+ } catch (err) {
1382
+ log.error(`Couldn't reach the API at ${apiUrl}.`);
1383
+ log.dim(` ${String(err)}`);
1384
+ process.exitCode = 1;
1385
+ return;
1386
+ }
1387
+ if (!res.ok) {
1388
+ if (!printedStructuredError(res)) {
1389
+ if (res.status === 401) {
1390
+ log.error("Not authorized \u2014 your sign-in was rejected. Re-run `genex list` to reconnect.");
1391
+ } else {
1392
+ log.error(`Couldn't list your games (HTTP ${res.status}).`);
1393
+ }
1394
+ }
1395
+ process.exitCode = 1;
1396
+ return;
1397
+ }
1398
+ const body = await res.json().catch(() => null);
1399
+ const projects = body?.projects ?? [];
1400
+ if (opts.json) {
1401
+ console.log(JSON.stringify(projects, null, 2));
1402
+ return;
1403
+ }
1404
+ const email = await fetchSignedInEmail(apiUrl, token);
1405
+ if (email) log.plain(` signed in as ${c.cyan(email)}`);
1406
+ if (projects.length === 0) {
1407
+ log.plain("You have no games yet \u2014 `npx genex init <name>` in a new folder creates one.");
1408
+ return;
1409
+ }
1410
+ log.plain("");
1411
+ for (const p of projects) {
1412
+ const published = p.status === "published";
1413
+ const pageUrl = `${dashOrigin}/${published ? "world" : "draft"}/${p.slug}`;
1414
+ const isHere = Boolean(meta && (meta.id === p.id || meta.slug === p.slug));
1415
+ const bits = [
1416
+ published ? c.green("published") : c.dim("draft"),
1417
+ published && p.playsCount ? `${p.playsCount} play${p.playsCount === 1 ? "" : "s"}` : "",
1418
+ p.private ? "remixing off" : "",
1419
+ p.purchaseUrl ? "paid" : "",
1420
+ p.updatedAt ? `updated ${relTime(p.updatedAt)}` : ""
1421
+ ].filter(Boolean).join(" \xB7 ");
1422
+ log.plain(` ${c.bold(p.slug)} ${bits}${isHere ? c.green(" \u2190 this folder") : ""}`);
1423
+ log.dim(` ${pageUrl}`);
1424
+ }
1425
+ if (projects.length === 100) {
1426
+ log.dim(" (showing your 100 most recent games)");
1427
+ }
1428
+ }
1429
+ function relTime(iso) {
1430
+ const ms = Date.parse(iso);
1431
+ if (Number.isNaN(ms)) return "recently";
1432
+ const s = Math.max(0, (Date.now() - ms) / 1e3);
1433
+ if (s < 3600) return `${Math.max(1, Math.floor(s / 60))}m ago`;
1434
+ if (s < 86400) return `${Math.floor(s / 3600)}h ago`;
1435
+ return `${Math.floor(s / 86400)}d ago`;
1436
+ }
1437
+
1331
1438
  // src/lib/deploy.ts
1332
1439
  import { spawn as spawn3 } from "child_process";
1333
1440
  import crypto3 from "crypto";
@@ -3810,6 +3917,9 @@ ${c.bold("Usage")}
3810
3917
  genex link <slug> [options] Re-link THIS folder to an existing game of yours
3811
3918
  (lost folder / new machine); preview/publish then
3812
3919
  update the same live game. Never creates a project.
3920
+ genex list [options] List your games \u2014 slug, status, and page link for
3921
+ each. Signs you in if needed; --json for raw data.
3922
+ Find the slug to reconnect with 'genex link' here.
3813
3923
  genex preview [options] Build + push to the hosted draft URL (unlisted).
3814
3924
  genex publish [options] Build + push, then list the game in the gallery.
3815
3925
  genex make-remixable [options] Make THIS game remixable by everyone \u2014 migrates a
@@ -3908,6 +4018,12 @@ ${c.bold("Options for `explore`")}
3908
4018
  --api-url <url> Override the API base URL.
3909
4019
  (No query at all lists the entire curated catalog.)
3910
4020
 
4021
+ ${c.bold("Options for `list`")}
4022
+ --json Print your games as JSON (all fields, incl. play/clone URLs).
4023
+ --api-url <url> Override the API base URL.
4024
+ --env <path> Token env file (default: ~/.genex/env).
4025
+ --auth-url <url> Override the auth site (used only if sign-in is needed).
4026
+
3911
4027
  ${UI_USAGE}
3912
4028
 
3913
4029
  ${c.bold("Global")}
@@ -3925,6 +4041,7 @@ ${c.bold("Environment")}
3925
4041
  ${c.bold("Examples")}
3926
4042
  genex init my-game
3927
4043
  genex init my-game --api-url http://localhost:3000 --auth-url http://localhost:5173
4044
+ genex list
3928
4045
  genex link my-game
3929
4046
  genex preview
3930
4047
  genex publish
@@ -4280,6 +4397,9 @@ async function main() {
4280
4397
  case "link":
4281
4398
  await runLink(parsed.options);
4282
4399
  break;
4400
+ case "list":
4401
+ await runList(parsed.options);
4402
+ break;
4283
4403
  case "make-remixable":
4284
4404
  await runMakeRemixable(parsed.options);
4285
4405
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "0.48.0",
3
+ "version": "0.49.0-dev.92",
4
4
  "description": "Set up your ~/.claude workspace, authorize, create a game project, generate AI assets, and publish (genex CLI).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -391,7 +391,7 @@ after a bad single costs the whole chain).
391
391
 
392
392
  ## Troubleshooting
393
393
 
394
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it
394
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it
395
395
  writes your `GENEX_TOKEN`).
396
396
  - **"Prompt rejected"** — the provider's content-safety filter blocked the
397
397
  prompt. Non-retryable; rewrite the wording.
@@ -182,7 +182,7 @@ set belongs to `$genex-ai-hud` — both build on this command.
182
182
 
183
183
  ## Troubleshooting
184
184
 
185
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
185
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
186
186
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
187
187
  This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
188
188
  - **Decal is an opaque rectangle** — the image has no alpha. Regenerate with
@@ -321,7 +321,7 @@ upgrades, in order of effort:
321
321
 
322
322
  ## Troubleshooting
323
323
 
324
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it
324
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it
325
325
  writes your `GENEX_TOKEN`).
326
326
  - **"Prompt rejected"** — the provider's content-safety filter blocked the
327
327
  prompt. Non-retryable; rewrite the wording.
@@ -107,7 +107,7 @@ scene is a ghost: players and objects pass straight through it.
107
107
 
108
108
  ## Troubleshooting
109
109
 
110
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
110
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
111
111
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
112
112
  this model generation. Tell the user the facts the CLI printed: their balance, this
113
113
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -72,7 +72,7 @@ Reuse one loaded `buffer` across many plays; create a fresh `Audio`/`PositionalA
72
72
 
73
73
  ## Troubleshooting
74
74
 
75
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
75
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
76
76
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
77
77
  this sound generation. Tell the user the facts the CLI printed: their balance, this
78
78
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -76,7 +76,7 @@ scene.background = texture; // keep the raw texture for the visible sky
76
76
 
77
77
  ## Troubleshooting
78
78
 
79
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
79
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
80
80
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
81
81
  this skybox generation. Tell the user the facts the CLI printed: their balance, this
82
82
  generation's cost, and when their credits refill. Then offer to continue the build
@@ -81,7 +81,7 @@ scene.add(ground);
81
81
 
82
82
  ## Troubleshooting
83
83
 
84
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
84
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
85
85
  - **"Out of credits" (`insufficient_credits`)** — the account has no credits left for
86
86
  this texture generation. Tell the user the facts the CLI printed: their balance,
87
87
  this generation's cost, and when their credits refill. Then offer to continue the
@@ -145,7 +145,7 @@ set belongs to `$genex-ai-hud` — both build on `npx genex image`/`video`.
145
145
 
146
146
  ## Troubleshooting
147
147
 
148
- - **"Not authorized"** — run `npx @genex-ai/cli-demo@latest init` first (it writes your `GENEX_TOKEN`).
148
+ - **"Not authorized"** — run `npx @genex-ai/cli-demo@dev init` first (it writes your `GENEX_TOKEN`).
149
149
  - **"Prompt rejected"** — the provider's content-safety filter blocked the prompt.
150
150
  This is non-retryable; retrying the same wording fails again. Rewrite the prompt.
151
151
  - **Nothing plays / black surface** — the first `video.play()` must run inside a user
@@ -43,7 +43,7 @@ Add `--json` for machine-readable output.
43
43
  **As a NEW game (start from the whole project):**
44
44
 
45
45
  1. `git clone <clone URL from the output> <name>` — pick a short one-word name.
46
- 2. `cd <name>`, then `npx @genex-ai/cli-demo@latest init <name>` — never use
46
+ 2. `cd <name>`, then `npx @genex-ai/cli-demo@dev init <name>` — never use
47
47
  `--force`. This creates your own project; the original is untouched.
48
48
  3. `npm install`, keep `base: './'` in `vite.config`, then build your changes
49
49
  and ship with `npx genex preview`.
@@ -125,9 +125,13 @@ and re-link the clone to the same live game:
125
125
  ```bash
126
126
  git clone <the game's repo url> my-game && cd my-game
127
127
  npm install
128
- npx @genex-ai/cli-demo@latest link <slug> # slug = the name in the play URL
128
+ npx @genex-ai/cli-demo@dev link <slug> # slug = the name in the play URL
129
129
  ```
130
130
 
131
+ Don't know the slug? **`npx genex list`** prints every game on your account —
132
+ slug, status, and page link for each — signing you in first if needed. Find the
133
+ game there, then `link` its slug.
134
+
131
135
  `link` never creates a project: it signs in if needed (the browser opens once)
132
136
  and rewrites the local link (source pushes authorize over HTTPS, so there's no
133
137
  key to set up — it works from any machine).
@@ -148,7 +152,7 @@ Safe to run any time — genex-owned skills are refreshed to the latest version,
148
152
  and your own files are never touched:
149
153
 
150
154
  ```bash
151
- npx @genex-ai/cli-demo@latest init
155
+ npx @genex-ai/cli-demo@dev init
152
156
  ```
153
157
 
154
158
  Use `--force` only if you intentionally want your own existing files overwritten
@@ -38,7 +38,7 @@ update, so update immediately.)
38
38
  Run exactly the command the nudge printed, from the game project root:
39
39
 
40
40
  ```bash
41
- npm i -D @genex-ai/cli-demo@latest # the genex CLI (a dev dependency)
41
+ npm i -D @genex-ai/cli-demo@dev # the genex CLI (a dev dependency)
42
42
  npm i @genex-ai/embed-sdk@latest # identity/saves SDK (ships inside the game)
43
43
  npm i @genex-ai/multiplayer@latest # multiplayer SDK (only if the game uses it)
44
44
  ```