@genex-ai/cli-demo 1.17.0-dev.590 → 1.18.0-dev.592

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.
@@ -7,7 +7,7 @@ import {
7
7
  isRenderMode,
8
8
  sceneSummary,
9
9
  sheetOf
10
- } from "./chunk-GRBSHEXG.js";
10
+ } from "./chunk-YSMZVFJM.js";
11
11
  import {
12
12
  getCliVersion
13
13
  } from "./chunk-HYCSNWYX.js";
@@ -314,6 +314,22 @@ var workspaceLabel = null;
314
314
  function setWorkspaceHeader(label) {
315
315
  workspaceLabel = workspaceHeaderValue(label);
316
316
  }
317
+ var ASSETS_MODE_HEADER = "x-genex-assets-mode";
318
+ var ASSETS_MODE_ENV = "GENEX_ASSETS_MODE";
319
+ function assetsModeFromEnv() {
320
+ const raw = process.env[ASSETS_MODE_ENV];
321
+ if (typeof raw !== "string") return null;
322
+ const value = raw.trim();
323
+ return value ? value : null;
324
+ }
325
+ function formatInvalidAssetsMode(body) {
326
+ const message = body.message ?? `the ${ASSETS_MODE_HEADER} header is malformed \u2014 send \`none\` or a comma-separated list of lanes.`;
327
+ const current = assetsModeFromEnv();
328
+ return [
329
+ `${c.red("\u2717")} Assets mode refused \u2014 ${lowerFirst(message)}`,
330
+ ` It comes from ${ASSETS_MODE_ENV}${current ? `="${current}"` : ""} in this shell \u2014 fix or unset it, then re-run. Nothing was generated or charged.`
331
+ ];
332
+ }
317
333
  function formatUpdateRequired(body) {
318
334
  const action = body.action ?? `npm i -D @genex-ai/cli-demo@${CLI_CHANNEL}`;
319
335
  const message = body.message ?? `Genex CLI ${body.clientVersion ?? getCliVersion()} is below the minimum supported version${body.minVersion ? ` ${body.minVersion}` : ""}.`;
@@ -363,6 +379,10 @@ async function apiFetch(url, init = {}, opts = {}) {
363
379
  if (workspaceLabel && !headers.has(WORKSPACE_HEADER)) {
364
380
  headers.set(WORKSPACE_HEADER, workspaceLabel);
365
381
  }
382
+ const assetsMode = assetsModeFromEnv();
383
+ if (assetsMode && !headers.has(ASSETS_MODE_HEADER)) {
384
+ headers.set(ASSETS_MODE_HEADER, assetsMode);
385
+ }
366
386
  const res = await fetch(url, { ...init, headers });
367
387
  if (res.status === 403 && !opts.noTermsWait && await isTermsRefusal(res)) {
368
388
  const log = stderrLogger;
@@ -411,6 +431,16 @@ async function apiFetch(url, init = {}, opts = {}) {
411
431
  } catch {
412
432
  }
413
433
  }
434
+ if (res.status === 400) {
435
+ try {
436
+ const body = await res.clone().json();
437
+ if (body?.error === "invalid_assets_mode") {
438
+ for (const line of formatInvalidAssetsMode(body)) process.stderr.write(line + "\n");
439
+ structuredPrinted.add(res);
440
+ }
441
+ } catch {
442
+ }
443
+ }
414
444
  if (res.status === 503) {
415
445
  try {
416
446
  const body = await res.clone().json();
@@ -860,6 +890,8 @@ export {
860
890
  reportTermsRefusal,
861
891
  runAccept,
862
892
  setWorkspaceHeader,
893
+ ASSETS_MODE_ENV,
894
+ assetsModeFromEnv,
863
895
  printedStructuredError,
864
896
  apiFetch,
865
897
  fetchSignedInEmail,
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ ASSETS_MODE_ENV,
3
4
  RENDER_MODES,
4
5
  SHEET_FORMATS,
5
6
  acceptUrl,
6
7
  acquireCliSeat,
7
8
  acquireSeat,
8
9
  apiFetch,
10
+ assetsModeFromEnv,
9
11
  blenderCall,
10
12
  blenderEndpoint,
11
13
  blenderSetupHint,
@@ -40,7 +42,7 @@ import {
40
42
  writeProject,
41
43
  writeUserToken,
42
44
  writeWorkspace
43
- } from "./chunk-GRBSHEXG.js";
45
+ } from "./chunk-YSMZVFJM.js";
44
46
  import {
45
47
  CLI_CHANNEL,
46
48
  DEFAULT_API_URL,
@@ -7011,6 +7013,10 @@ async function* readSSE(body) {
7011
7013
  }
7012
7014
 
7013
7015
  // src/commands/generate.ts
7016
+ var MOCKED_LINE = "placeholder \u2014 this lane is mocked for this run";
7017
+ function reportMocked(view, log) {
7018
+ if (view.mocked === true) log.dim(` ${MOCKED_LINE}`);
7019
+ }
7014
7020
  var sleep3 = (ms) => new Promise((r) => setTimeout(r, ms));
7015
7021
  var INLINE_IMAGE_LIMIT_BYTES = 4 * 1024 * 1024;
7016
7022
  var IMAGE_MIME_BY_EXT = {
@@ -7550,11 +7556,13 @@ async function reportTerminal(kind, view, log, open = false, json = false, local
7550
7556
  if (kind === "character_concept") {
7551
7557
  reportCharacterConceptTerminal(view, log, { json, open });
7552
7558
  if (delivered) reportLocalFiles(delivered, log, json);
7559
+ if (!json) reportMocked(view, log);
7553
7560
  return;
7554
7561
  }
7555
7562
  if (kind === "character_preview") {
7556
7563
  reportCharacterPreviewTerminal(view, log, { json, open });
7557
7564
  if (delivered) reportLocalFiles(delivered, log, json);
7565
+ if (!json) reportMocked(view, log);
7558
7566
  return;
7559
7567
  }
7560
7568
  if (json) {
@@ -7563,6 +7571,8 @@ async function reportTerminal(kind, view, log, open = false, json = false, local
7563
7571
  id: view.id,
7564
7572
  status: view.status,
7565
7573
  files,
7574
+ // Only when the server said so — absent stays absent (unknown).
7575
+ ...view.mocked === true ? { mocked: true } : {},
7566
7576
  ...delivered ? { saved: delivered.saved, downloadFailures: delivered.failures } : {},
7567
7577
  ...kind === "character" ? {
7568
7578
  characterId: view.id,
@@ -7581,6 +7591,7 @@ async function reportTerminal(kind, view, log, open = false, json = false, local
7581
7591
  log.plain(` ${label}${f.url}`);
7582
7592
  }
7583
7593
  }
7594
+ reportMocked(view, log);
7584
7595
  log.plain("");
7585
7596
  if (kind === "texture" && files[0]) await reportTextureSeam(files[0].url, log);
7586
7597
  if (kind === "model_segment") {
@@ -7857,6 +7868,10 @@ function reportCharacterConceptTerminal(view, log, opts = {}) {
7857
7868
  candidates,
7858
7869
  ...contactSheet ? { contactSheetUrl: contactSheet.url } : {},
7859
7870
  ...opts.quote ? { quote: opts.quote } : {},
7871
+ // Only when the server said so — absent stays absent (unknown). The
7872
+ // character lane is the one the 2026-09-01 wave ran on every village
7873
+ // run, so a harness reading this object must see the placeholder too.
7874
+ ...view.mocked === true ? { mocked: true } : {},
7860
7875
  requiresUserApproval: true,
7861
7876
  nextCommand
7862
7877
  });
@@ -7927,6 +7942,8 @@ function reportCharacterPreviewTerminal(view, log, opts = {}) {
7927
7942
  ...sourceUrl ? { sourceUrl } : {},
7928
7943
  requestedBuild: intent,
7929
7944
  ...opts.quote ? { quote: opts.quote } : {},
7945
+ // Same rule as the concept object above.
7946
+ ...view.mocked === true ? { mocked: true } : {},
7930
7947
  requiresUserApproval: true,
7931
7948
  nextCommand
7932
7949
  });
@@ -8073,6 +8090,10 @@ async function runWait(opts) {
8073
8090
  process.exitCode = 1;
8074
8091
  return;
8075
8092
  }
8093
+ if (printedStructuredError(res)) {
8094
+ process.exitCode = 1;
8095
+ return;
8096
+ }
8076
8097
  if (!res.ok) {
8077
8098
  log.error(`Couldn't look up the generation (HTTP ${res.status}).`);
8078
8099
  process.exitCode = 1;
@@ -8169,6 +8190,7 @@ async function runWaitAll(opts) {
8169
8190
  if (r.status === "failed" && r.error) {
8170
8191
  for (const line of describeGenerationFailure(r.kind, r.error).lines) log.plain(` ${line}`);
8171
8192
  }
8193
+ if (r.status === "done" && r.mocked) log.dim(` ${MOCKED_LINE}`);
8172
8194
  }
8173
8195
  const count = (s) => rows.filter((r) => r.status === s).length;
8174
8196
  const billingFailed = rows.filter(
@@ -8218,7 +8240,7 @@ async function toRow(e, v, cwd) {
8218
8240
  }
8219
8241
  switch (v.status) {
8220
8242
  case "completed":
8221
- return { ...base, status: "done" };
8243
+ return { ...base, status: "done", ...v.mocked === true ? { mocked: true } : {} };
8222
8244
  case "failed":
8223
8245
  return { ...base, status: "failed", error: v.error };
8224
8246
  case "processing":
@@ -20623,7 +20645,7 @@ async function runBlender(opts) {
20623
20645
  return serveLocalBlender({ port, log });
20624
20646
  }
20625
20647
  if (sub === "mcp") {
20626
- const { runBlenderMcp } = await import("./blender-mcp-GMZATIZS.js");
20648
+ const { runBlenderMcp } = await import("./blender-mcp-FQJFZETR.js");
20627
20649
  return runBlenderMcp();
20628
20650
  }
20629
20651
  if (sub === "seat") {
@@ -21312,6 +21334,14 @@ async function runDoctor(opts = {}) {
21312
21334
  fix: "`npx genex tools` for the asset toolkit, or `npx genex init` to build a hosted game here."
21313
21335
  }
21314
21336
  );
21337
+ const assetsMode = assetsModeFromEnv();
21338
+ if (assetsMode) {
21339
+ rows.push({
21340
+ label: "Assets",
21341
+ value: `mocked (${ASSETS_MODE_ENV}=${assetsMode})`,
21342
+ fix: "every generation on a switched-off lane returns a valid placeholder and costs nothing"
21343
+ });
21344
+ }
21315
21345
  const nodeMajor = Number(process.versions.node.split(".")[0]);
21316
21346
  const nodeOk = Number.isFinite(nodeMajor) && nodeMajor >= NODE_FLOOR;
21317
21347
  rows.push({
@@ -21357,6 +21387,13 @@ async function runDoctor(opts = {}) {
21357
21387
  JSON.stringify(
21358
21388
  {
21359
21389
  workspace: mode,
21390
+ // Same rule as the row: unset adds nothing, to either form.
21391
+ // ALWAYS present in --json, `null` when the variable is unset: the eval
21392
+ // harness reads this key to tell a CLI that KNOWS the variable (key
21393
+ // present, value or null) from one that predates it (no key) — with the
21394
+ // key omitted when unset, a run under `--assets all` (variable absent
21395
+ // by design) recorded a current CLI as "predates the header".
21396
+ assetsMode: assetsMode ?? null,
21360
21397
  node: process.versions.node,
21361
21398
  cli: { installed, latest },
21362
21399
  auth: { state: authState, email, apiUrl },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "1.17.0-dev.590",
3
+ "version": "1.18.0-dev.592",
4
4
  "description": "Set up your project's agent workspace (.claude/.codex/.cursor in the game folder), authorize, create a game project, generate AI assets, and publish (genex CLI).",
5
5
  "type": "module",
6
6
  "bin": {