@genex-ai/cli-demo 1.35.0 → 1.35.2-dev.749
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/dist/{blender-mcp-6TEAE65U.js → blender-mcp-HKT7N5BQ.js} +2 -2
- package/dist/{blender-serve-66OHC4ML.js → blender-serve-EH2MOW3U.js} +1 -1
- package/dist/{chunk-5WBSWMH5.js → chunk-FYHYZYBC.js} +1 -1
- package/dist/{chunk-QI7FIYBY.js → chunk-K4EHXOZK.js} +1 -1
- package/dist/index.js +6 -5
- package/package.json +1 -1
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-llm-in-games/SKILL.md +78 -1
- package/templates/skills/genex-updates/SKILL.md +1 -1
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
isRenderMode,
|
|
8
8
|
sceneSummary,
|
|
9
9
|
sheetOf
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-FYHYZYBC.js";
|
|
11
11
|
import {
|
|
12
12
|
getCliVersion
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-K4EHXOZK.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/blender-mcp.ts
|
|
16
16
|
import fs from "fs/promises";
|
|
@@ -38,7 +38,7 @@ import fs from "fs";
|
|
|
38
38
|
import os from "os";
|
|
39
39
|
import path from "path";
|
|
40
40
|
import { fileURLToPath } from "url";
|
|
41
|
-
var RAW_CHANNEL = "
|
|
41
|
+
var RAW_CHANNEL = "dev";
|
|
42
42
|
var CLI_CHANNEL = RAW_CHANNEL === "dev" ? "dev" : "latest";
|
|
43
43
|
var STANDS = {
|
|
44
44
|
prod: { api: "https://api.genex.games", dashboard: "https://genex.games" },
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
writeSecretFile,
|
|
43
43
|
writeUserToken,
|
|
44
44
|
writeWorkspace
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-FYHYZYBC.js";
|
|
46
46
|
import {
|
|
47
47
|
CLI_CHANNEL,
|
|
48
48
|
DEFAULT_API_URL,
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
normalizeApiOrigin,
|
|
64
64
|
originKey,
|
|
65
65
|
resolveAgentTargets
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-K4EHXOZK.js";
|
|
67
67
|
|
|
68
68
|
// src/instrument.ts
|
|
69
69
|
import * as Sentry from "@sentry/node";
|
|
@@ -22772,7 +22772,7 @@ async function runBlender(opts) {
|
|
|
22772
22772
|
return 1;
|
|
22773
22773
|
}
|
|
22774
22774
|
if (sub === "serve") {
|
|
22775
|
-
const { serveLocalBlender } = await import("./blender-serve-
|
|
22775
|
+
const { serveLocalBlender } = await import("./blender-serve-EH2MOW3U.js");
|
|
22776
22776
|
const port = Number(process.env.GENEX_BLENDER_PORT ?? 8088);
|
|
22777
22777
|
log.step(`Starting a local Blender service on port ${port}`);
|
|
22778
22778
|
log.plain(
|
|
@@ -22781,7 +22781,7 @@ async function runBlender(opts) {
|
|
|
22781
22781
|
return serveLocalBlender({ port, log });
|
|
22782
22782
|
}
|
|
22783
22783
|
if (sub === "mcp") {
|
|
22784
|
-
const { runBlenderMcp } = await import("./blender-mcp-
|
|
22784
|
+
const { runBlenderMcp } = await import("./blender-mcp-HKT7N5BQ.js");
|
|
22785
22785
|
return runBlenderMcp();
|
|
22786
22786
|
}
|
|
22787
22787
|
if (sub === "seat") {
|
|
@@ -23564,8 +23564,9 @@ async function reportModels(apiUrl, token, opts, log, toolsOnly = false) {
|
|
|
23564
23564
|
);
|
|
23565
23565
|
for (const m of shown) {
|
|
23566
23566
|
const plan = m.personalPlan ? ` \xB7 personal plan: ${m.personalPlan}` : "";
|
|
23567
|
+
const kind = m.kind === "typesafe" ? " \xB7 judge (classifier): judge() under a budget, not generate() or bench" : "";
|
|
23567
23568
|
log.plain(
|
|
23568
|
-
` ${c.cyan(m.id)} ${m.label} \u2014 ${usdPerMillion(m.inputUsdPerMillion)} in / ${usdPerMillion(m.outputUsdPerMillion)} out per million tokens${plan}`
|
|
23569
|
+
` ${c.cyan(m.id)} ${m.label} \u2014 ${usdPerMillion(m.inputUsdPerMillion)} in / ${usdPerMillion(m.outputUsdPerMillion)} out per million tokens${plan}${kind}`
|
|
23569
23570
|
);
|
|
23570
23571
|
}
|
|
23571
23572
|
if (hiddenCount > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "1.35.
|
|
3
|
+
"version": "1.35.2-dev.749",
|
|
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": {
|
|
@@ -161,7 +161,7 @@ downloads the game too, binary assets and all:
|
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
163
|
mkdir my-game && cd my-game
|
|
164
|
-
npx @genex-ai/cli-demo@
|
|
164
|
+
npx @genex-ai/cli-demo@dev link <slug> # slug = the name in the play URL
|
|
165
165
|
npm install
|
|
166
166
|
```
|
|
167
167
|
|
|
@@ -225,7 +225,7 @@ Safe to run any time — genex-owned skills are refreshed to the latest version,
|
|
|
225
225
|
and your own files are never touched:
|
|
226
226
|
|
|
227
227
|
```bash
|
|
228
|
-
npx @genex-ai/cli-demo@
|
|
228
|
+
npx @genex-ai/cli-demo@dev init
|
|
229
229
|
```
|
|
230
230
|
|
|
231
231
|
Use `--force` only if you intentionally want your own existing files overwritten
|
|
@@ -25,6 +25,23 @@ Two modes. Picking the wrong one is the most expensive mistake on this lane:
|
|
|
25
25
|
A popup per NPC turn is not a feature, it is an interruption. More than a call
|
|
26
26
|
or two per session means a grant.
|
|
27
27
|
|
|
28
|
+
**Deciding, not writing? Use the judge.** When the game needs to KNOW something
|
|
29
|
+
— is this NPC lying, which of five moods is the player in, how threatening is
|
|
30
|
+
the scene on a scale — and not to produce words, ask the grant's classifier with
|
|
31
|
+
`judge()` instead of asking `generate()` for a label. It answers typed questions
|
|
32
|
+
(`choice`, `score`, `noul`) with calibrated probabilities in about a third of a
|
|
33
|
+
second, writes no prose and cannot drift out of your options. It is grant-only
|
|
34
|
+
and billed as used: each call is a small fraction of a coin and accrues on the
|
|
35
|
+
budget, so a check every turn is affordable where a generate every turn is not.
|
|
36
|
+
`generate()` for words, `judge()` for decisions; a feature often wants both —
|
|
37
|
+
the judge picks the branch, generate writes the line.
|
|
38
|
+
|
|
39
|
+
**Words the player watches appear? Stream them.** Dialogue, narration, an NPC's
|
|
40
|
+
reply in a speech bubble: under a grant, `generateStream()` is the same call as
|
|
41
|
+
`generate({ grantId })`, but the text arrives while the model writes it instead
|
|
42
|
+
of all at once after it. Keep `generate()` for answers the game only uses whole
|
|
43
|
+
(a quest object, a list of decisions) — nobody watches those being written.
|
|
44
|
+
|
|
28
45
|
## Step 0 — is the lane live on this stand?
|
|
29
46
|
|
|
30
47
|
```bash
|
|
@@ -67,9 +84,24 @@ identity must be resolved first — `$genex-threejs-embed-auth`.
|
|
|
67
84
|
(`billingStatus`, `reservedCoins`, `chargedCoins`, their display-USD twins).
|
|
68
85
|
- `requestSpendGrant({ models, perCallMaxCoins, perCallEstimateCoins,
|
|
69
86
|
disclosure: { periodLabel, estimatedCallsPerPeriod, estimatedCoinsPerPeriod },
|
|
70
|
-
maxConcurrent?, maxCallsPerMinute?, allowExternal?,
|
|
87
|
+
maxConcurrent?, maxCallsPerMinute?, allowExternal?, judge?: { enabled,
|
|
88
|
+
estimatedCallsPerPeriod }, idempotencyKey? })` →
|
|
71
89
|
`{ status, grantId, … the limits the player approved }`; status is `active` |
|
|
72
90
|
`canceled` | `expired` | `failed` | `pending`.
|
|
91
|
+
- `judge({ grantId, state, questions, idempotencyKey?, timeoutMs? })` →
|
|
92
|
+
`{ status, generationId, answers, error, billing }` — the grant's classifier,
|
|
93
|
+
answered in the same response. `questions` is 1–64 named `choice`
|
|
94
|
+
(`{ instructions, criteria: { option: description } }`), `score`
|
|
95
|
+
(`{ instructions, criteria: [levels, lowest first] }`) or `noul`
|
|
96
|
+
(`{ instructions }`); each answer has its question's type, and `noul` is a
|
|
97
|
+
probability — pick your own threshold. Needs a budget requested with `judge`.
|
|
98
|
+
- `generateStream({ …the generate() options, grantId, onDelta?(text, soFar),
|
|
99
|
+
onPartialField?(name, partialText), signal? })` → the same result as
|
|
100
|
+
`generate()`. Grant-only. `onDelta` hands over each piece and all the text so
|
|
101
|
+
far; for `outputFormat: 'json'`, `onPartialField` reports the schema's FIRST
|
|
102
|
+
top-level string property as far as it is written — put the spoken line first
|
|
103
|
+
in the schema. `signal` stops the reading, never the call (it still finishes
|
|
104
|
+
and is charged).
|
|
73
105
|
- `getSpendGrant(grantId)` — live state and counters; the ONE source for an
|
|
74
106
|
in-game budget readout.
|
|
75
107
|
- `stopSpendGrant(grantId)` — the game's own stop door. Prospective: no further
|
|
@@ -188,6 +220,36 @@ arithmetic into `DESIGN.md` beside the feature. The player sees your estimate
|
|
|
188
220
|
attributed to the game, beside the platform's own worst case; an estimate that
|
|
189
221
|
is transparently low is a grant that dies mid-session.
|
|
190
222
|
|
|
223
|
+
**Using the judge too?** Add `judge: { enabled: true, estimatedCallsPerPeriod }`
|
|
224
|
+
to the same request — the checks you really expect per `periodLabel`, from the
|
|
225
|
+
same loop arithmetic. The sheet tells the player the game also uses a fast
|
|
226
|
+
classifier billed as used, with the platform's own worst case beside your count.
|
|
227
|
+
A judge-only feature passes `models: []`. A budget with the judge is coin-funded
|
|
228
|
+
only, and judge calls share the budget's `maxConcurrent` and
|
|
229
|
+
`maxCallsPerMinute`: batch questions into one call (up to 64) rather than one
|
|
230
|
+
call per question.
|
|
231
|
+
|
|
232
|
+
**Streaming a reply under the budget:**
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
const res = await generateStream({
|
|
236
|
+
grantId, modelId, outputFormat: 'json', schema: LINE_SCHEMA, // `line` is its first property
|
|
237
|
+
prompt: npcPrompt(npc, playerLine), estimateCoins: NPC_CALL_PRICE,
|
|
238
|
+
idempotencyKey: `npc:${npc.id}:${turnId}`,
|
|
239
|
+
onPartialField: (_name, soFar) => npc.bubble.show(soFar), // provisional
|
|
240
|
+
});
|
|
241
|
+
applyGeneration(res); // the answer is THIS
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
The pieces are provisional: a call can still fail after text has shown (the
|
|
245
|
+
model broke off, the JSON missed the schema), so the bubble shows them and
|
|
246
|
+
`applyGeneration` decides what the game keeps — the same one writer as always.
|
|
247
|
+
Price, benchmark and receipt are `generate()`'s: a started stream is charged its
|
|
248
|
+
declared price even when the player walks away mid-sentence. A stream holds one
|
|
249
|
+
of the budget's `maxConcurrent` slots until it has settled. Sometimes the reply
|
|
250
|
+
arrives whole — a busy stand, a retried call, a budget on the player's own plan —
|
|
251
|
+
and `onDelta` then gets the whole text once; the game needs no second path.
|
|
252
|
+
|
|
191
253
|
**Then keep the burn low, because you wrote the loop:** batch those five NPCs
|
|
192
254
|
into ONE call returning five decisions, cache a decision until the situation
|
|
193
255
|
that caused it changes, pick the cheapest model that passes your own check, and
|
|
@@ -285,6 +347,8 @@ These are source contracts, not a claim that every stand runs this lane —
|
|
|
285
347
|
- [ ] A bench refused as `generation_limit` was answered with `npx genex llm status`, never a retry
|
|
286
348
|
- [ ] `generate()` / `requestSpendGrant()` is the first statement of a click handler
|
|
287
349
|
- [ ] A repeated-call feature uses a grant; a one-off uses `generate()`
|
|
350
|
+
- [ ] A decision (a label, a yes/no, a level) is a `judge()` question under the grant, not a `generate()` asked for a word
|
|
351
|
+
- [ ] Dialogue the player watches appear uses `generateStream()` under the grant; the resolved result, not the pieces, goes to `applyGeneration()`
|
|
288
352
|
- [ ] Disclosure numbers derive from the real loop and are written in `DESIGN.md`
|
|
289
353
|
- [ ] Calls are batched and cached; nothing fires on an invisible timer
|
|
290
354
|
- [ ] Every grant-ending code has in-fiction copy and a playable fallback
|
|
@@ -316,6 +380,19 @@ cause rather than showing it for both.
|
|
|
316
380
|
**`grant_price_unreasonable`** — the declared per-call price is far above what
|
|
317
381
|
that prompt can cost on that model. Re-benchmark and declare what it prints.
|
|
318
382
|
|
|
383
|
+
**`judge_not_enabled`** — the budget was approved without the judge. Request a
|
|
384
|
+
new one with `judge` from the next deliberate click; never auto-renew.
|
|
385
|
+
**`judge_requires_grant`** — the judge's model was sent to `generate()` with no
|
|
386
|
+
budget; the judge is grant-only and is called with `judge()`.
|
|
387
|
+
**`judge_period_limit`** — the checks reached the ceiling the player approved for
|
|
388
|
+
the period (your own `estimatedCallsPerPeriod` at the largest size): wait, and
|
|
389
|
+
if it keeps happening your declared rate is too low — fix the loop or the
|
|
390
|
+
estimate, never retry in a tight loop.
|
|
391
|
+
|
|
392
|
+
**`stream_requires_grant`** — `generateStream()` was called without a
|
|
393
|
+
`grantId`. Streaming is grant-only: a one-time call waits on the player's
|
|
394
|
+
approval popup, so use `generate()` for it.
|
|
395
|
+
|
|
319
396
|
**`generation_limit`** — three ad-hoc calls are already in flight for this
|
|
320
397
|
account, or recently stopped with their bill still pending; a pending call
|
|
321
398
|
stops counting ten minutes after it was dispatched. From the bench: run
|
|
@@ -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@
|
|
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
|
```
|