@genex-ai/cli-demo 1.26.0-dev.620 → 1.26.2-dev.622

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-57CT5CAN.js";
10
+ } from "./chunk-I77A53C6.js";
11
11
  import {
12
12
  getCliVersion
13
13
  } from "./chunk-HYCSNWYX.js";
@@ -704,6 +704,7 @@ async function touchCliSeat() {
704
704
  }
705
705
  }
706
706
  async function blenderCall(base, route, body) {
707
+ const cwd = process.cwd();
707
708
  const seat = readSeatGrant();
708
709
  const ctl = new AbortController();
709
710
  const timer = setTimeout(() => ctl.abort(), BLENDER_TIMEOUT_MS);
@@ -734,6 +735,15 @@ async function blenderCall(base, route, body) {
734
735
  body: body === void 0 ? void 0 : JSON.stringify(body),
735
736
  signal: ctl.signal
736
737
  });
738
+ if (res.status === 401 && seat?.token) {
739
+ const current = readSeatGrant(cwd);
740
+ if (current?.url === seat.url && current.token === seat.token) deleteSeatGrant(cwd);
741
+ await res.body?.cancel().catch(() => {
742
+ });
743
+ throw new Error(
744
+ `${route} refused the seat token (401) \u2014 ${seat.kind === "cli" ? 'run "genex blender seat" to acquire a new one' : "run the command again to acquire a new one"}`
745
+ );
746
+ }
737
747
  const text = await res.text();
738
748
  let json;
739
749
  try {
@@ -748,7 +758,11 @@ async function blenderCall(base, route, body) {
748
758
  );
749
759
  }
750
760
  const detail = typeof json.detail === "string" ? ` \u2014 ${json.detail}` : "";
751
- throw new Error(`${route} failed (${res.status}): ${json.error ?? text.slice(0, 200)}${detail}`);
761
+ const stage = typeof json.stage === "string" ? ` [${json.stage}]` : "";
762
+ const mutationWarning = json.scriptStarted === true ? " (script may have changed the scene; inspect it before retrying)" : "";
763
+ const trace = typeof json.trace === "string" ? `
764
+ ${json.trace.slice(-4e3)}` : "";
765
+ throw new Error(`${route} failed (${res.status}): ${json.error ?? text.slice(0, 200)}${stage}${detail}${mutationWarning}${trace}`);
752
766
  }
753
767
  if (seat?.kind === "cli") void touchCliSeat();
754
768
  return json;
package/dist/index.js CHANGED
@@ -41,7 +41,7 @@ import {
41
41
  writeProject,
42
42
  writeUserToken,
43
43
  writeWorkspace
44
- } from "./chunk-57CT5CAN.js";
44
+ } from "./chunk-I77A53C6.js";
45
45
  import {
46
46
  CLI_CHANNEL,
47
47
  DEFAULT_API_URL,
@@ -21104,7 +21104,7 @@ async function runBlender(opts) {
21104
21104
  return serveLocalBlender({ port, log });
21105
21105
  }
21106
21106
  if (sub === "mcp") {
21107
- const { runBlenderMcp } = await import("./blender-mcp-TTLZ24PD.js");
21107
+ const { runBlenderMcp } = await import("./blender-mcp-DPH5PIVX.js");
21108
21108
  return runBlenderMcp();
21109
21109
  }
21110
21110
  if (sub === "seat") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/cli-demo",
3
- "version": "1.26.0-dev.620",
3
+ "version": "1.26.2-dev.622",
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": {
@@ -214,12 +214,12 @@ def scene_digest():
214
214
  if m.use_nodes and m.node_tree:
215
215
  for node in m.node_tree.nodes:
216
216
  if node.type == "BSDF_PRINCIPLED":
217
- h.update(("bsdf:%s\n" % tuple(node.inputs["Base Color"].default_value)).encode())
217
+ h.update(("bsdf:%s\n" % (tuple(node.inputs["Base Color"].default_value),)).encode())
218
218
  elif obj.type == "LIGHT" and data is not None:
219
219
  h.update(("light:%s:%s:%s\n" % (data.type, data.energy, tuple(data.color))).encode())
220
220
  elif obj.type == "CAMERA" and data is not None:
221
221
  h.update(("cam:%s:%s\n" % (data.lens, data.type)).encode())
222
222
  w = scene.world
223
223
  if w is not None:
224
- h.update(("world:%s\n" % tuple(getattr(w, "color", (0, 0, 0)))).encode())
224
+ h.update(("world:%s\n" % (tuple(getattr(w, "color", (0, 0, 0))),)).encode())
225
225
  return h.hexdigest()
@@ -406,15 +406,21 @@ class Handler(BaseHTTPRequestHandler):
406
406
  started = time.time()
407
407
  route = self.path.split("?")[0]
408
408
  _set_deadline(route, _budget_for(route, body))
409
+ stage = route.lstrip("/")
410
+ script_started = False
409
411
  try:
410
412
  if route == "/exec":
413
+ stage = "script"
414
+ script_started = True
411
415
  result = ops.run_script(body.get("script", ""))
416
+ stage = "scene_info"
412
417
  result["scene"] = ops.scene_info()
413
418
  result["gpu"] = GPU_WITNESS
414
419
  # The sheet rides EVERY exec by default. verify:false is for
415
420
  # bulk sub-steps only -- an agent that has to ask for the
416
421
  # picture is an agent that will forget to.
417
422
  if body.get("verify", True):
423
+ stage = "verification"
418
424
  _attach_sheet(result, body, body.get("mode") or DEFAULT_MODE)
419
425
  result["ms"] = int((time.time() - started) * 1000)
420
426
  _checkpoint()
@@ -492,7 +498,8 @@ class Handler(BaseHTTPRequestHandler):
492
498
  except Exception as e:
493
499
  import traceback
494
500
 
495
- self._send(500, {"error": "exec_failed", "detail": str(e), "trace": traceback.format_exc(limit=6)})
501
+ self._send(500, {"error": "exec_failed", "detail": str(e), "trace": traceback.format_exc(limit=6),
502
+ "stage": stage, "scriptStarted": script_started})
496
503
  finally:
497
504
  # MUST run: a stale deadline file makes the supervisor kill a
498
505
  # perfectly healthy Blender on its next poll.
@@ -600,4 +607,5 @@ def main():
600
607
  srv.server_close()
601
608
 
602
609
 
603
- main()
610
+ if __name__ == "__main__":
611
+ main()
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: genex-blender-scene
3
- description: Compose a level, arena, interior, building or map — a SPACE of rooms, lanes, walls and sites that must relate — in a live Blender with `npx genex blender`, then export one GLB the game walks through. Use when the request is a place to move through (from a description or a floor plan), not a single prop; probe the lane first and build the same space in code if it is off.
3
+ description: Compose a level, arena, interior, building or map — a SPACE of rooms, lanes, walls and sites that must relate — in a live Blender with `npx genex blender`, then export one GLB the game walks through. Use for places to move through, floor plans, or explicit Blender authoring including standalone assets. Probe the lane first; code is the fallback only when Blender was not explicitly required.
4
4
  ---
5
5
 
6
6
  # Genex Blender · Scene
@@ -12,13 +12,22 @@ level grows the way a level is actually built: shell, then zones, then dressing.
12
12
 
13
13
  ## When this lane owns the work
14
14
 
15
+ - An explicit request to author or edit **in Blender**, even one standalone
16
+ asset. This overrides the default single-object route below. Keep Python
17
+ source under `blender/`, export the requested GLB and show it in a simple
18
+ browser preview; add gameplay only when requested. In hosted creation use
19
+ the CLI through Bash and open contact sheets with Read: the Blender MCP
20
+ server is not registered in the hosted harness.
21
+ If Blender is unavailable, report that limitation and keep the authored
22
+ scripts; the code fallback below is for requests that did not require Blender.
23
+
15
24
  - A **space**: a level, arena, interior, building, map, dungeon, station — several
16
25
  rooms, lanes, walls or sites that must relate to each other, and a player who
17
26
  moves through them.
18
27
  - A **floor plan or reference** to trace (a sketch, an ASCII plan, a photo of a room).
19
28
  - A **blockout**: the playable shape first, dressing later.
20
29
 
21
- Not this lane:
30
+ Default routes when the player did not explicitly request Blender:
22
31
 
23
32
  - One recognisable object (a barrel, a cart, a statue) → `$genex-ai-model`.
24
33
  - One parameterized object placed many times with variation, or a stylized shader
@@ -224,9 +233,11 @@ when one is available — the measurements favour it, and it costs nothing.
224
233
  - `payload_too_large` on export → fewer cylinder segments, delete faces the player
225
234
  never sees, or export two GLBs (`--out public/assets/level-a.glb`).
226
235
  - The sheet is grey → `material.diffuse_color` was not set (see above).
227
- - `refused the seat token (401)` → the seat was closed (the session rested, or the
228
- pod was replaced); run the same command again it re-acquires, and a replaced
229
- pod restores your scene from its checkpoint.
236
+ - `refused the seat token (401)` → the rejected cached grant has been removed.
237
+ In hosted creation, run `npx genex blender scene` to acquire a new seat and
238
+ inspect the restored scene before deciding whether to rerun the failed script.
239
+ At a terminal, run `npx genex blender seat` first. Recovery never automatically
240
+ replays scene changes; a replaced pod restores the latest saved checkpoint.
230
241
  - `seat_not_ready` → the pod is still booting; run again shortly.
231
242
  - The numbers are right but the top view is wrong → coordinates: `y` in Blender is
232
243
  depth, and `scale` on a 2-unit cube is the half-size.
@@ -41,6 +41,13 @@ paths. Building, previewing, promoting and publishing use `genex preview` /
41
41
 
42
42
  Use the request in front of you, not the oldest description of the project.
43
43
 
44
+ - **Explicit Blender authoring**, including a standalone prop, owns the
45
+ `$genex-blender-scene` lane. Keep the requested scope: Python scripts, an
46
+ exported GLB and a browser preview for an asset request. Do not invent
47
+ gameplay, a character controller or a game concept to justify the hosted
48
+ workspace. Blender in this sentence names the authoring tool; a kitchen
49
+ blender requested as a prop follows the ordinary asset rows.
50
+
44
51
  - **Clear focused request**—“work on the UI,” “fix movement,” “add one enemy,”
45
52
  “make this prop,” “publish this”—read the touched implementation and
46
53
  `DESIGN.md`, load only the owning skills, update `Now:`, and start. Do not