@genex-ai/cli-demo 1.21.0-dev.603 → 1.22.0-dev.605
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/index.js
CHANGED
|
@@ -2394,6 +2394,26 @@ async function recordTerminal(id, status, urls, cwd = process.cwd()) {
|
|
|
2394
2394
|
if (existing && existing.status === status) return;
|
|
2395
2395
|
await append(cwd, { t: "done", id, status, ...urls?.length ? { urls } : {} });
|
|
2396
2396
|
}
|
|
2397
|
+
async function recordShipped(commit, cwd = process.cwd()) {
|
|
2398
|
+
await append(cwd, { t: "ship", at: (/* @__PURE__ */ new Date()).toISOString(), ...commit ? { commit } : {} });
|
|
2399
|
+
}
|
|
2400
|
+
async function readLedgerRows(cwd = process.cwd()) {
|
|
2401
|
+
let raw;
|
|
2402
|
+
try {
|
|
2403
|
+
raw = await fs11.readFile(ledgerPath(cwd), "utf8");
|
|
2404
|
+
} catch {
|
|
2405
|
+
return [];
|
|
2406
|
+
}
|
|
2407
|
+
const rows = [];
|
|
2408
|
+
for (const line of raw.split("\n")) {
|
|
2409
|
+
if (!line.trim()) continue;
|
|
2410
|
+
try {
|
|
2411
|
+
rows.push(JSON.parse(line));
|
|
2412
|
+
} catch {
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
return rows;
|
|
2416
|
+
}
|
|
2397
2417
|
async function countFailed(kind, cwd = process.cwd()) {
|
|
2398
2418
|
return (await readLedger(cwd)).filter((e) => e.kind === kind && e.status === "failed").length;
|
|
2399
2419
|
}
|
|
@@ -4870,6 +4890,8 @@ async function deployGame(ctx, opts, log) {
|
|
|
4870
4890
|
});
|
|
4871
4891
|
}
|
|
4872
4892
|
}
|
|
4893
|
+
await recordShipped(commit, cwd).catch(() => {
|
|
4894
|
+
});
|
|
4873
4895
|
const index = files.find((f) => f.relPath === "index.html");
|
|
4874
4896
|
const liveUrl = published.url || grant.playUrl;
|
|
4875
4897
|
await waitUntilLive(liveUrl, fingerprintOf(index.bytes.toString("utf8")), opts.liveTimeoutMs ?? 2e4, log);
|
|
@@ -6885,6 +6907,63 @@ function describeGenerationFailure(kind, error) {
|
|
|
6885
6907
|
};
|
|
6886
6908
|
}
|
|
6887
6909
|
|
|
6910
|
+
// src/lib/generation-ceiling.ts
|
|
6911
|
+
var CHARACTER_KINDS = /* @__PURE__ */ new Set([
|
|
6912
|
+
"character",
|
|
6913
|
+
"character_concept",
|
|
6914
|
+
"character_preview",
|
|
6915
|
+
"character_animation",
|
|
6916
|
+
"character_motion"
|
|
6917
|
+
]);
|
|
6918
|
+
var DEFAULT_CEILING = 12;
|
|
6919
|
+
var DEFAULT_CHARACTER_CEILING = 3;
|
|
6920
|
+
function envNumber(raw, fallback) {
|
|
6921
|
+
if (raw === void 0 || raw.trim() === "") return fallback;
|
|
6922
|
+
const n = Number(raw);
|
|
6923
|
+
return Number.isFinite(n) && n >= 0 ? Math.floor(n) : fallback;
|
|
6924
|
+
}
|
|
6925
|
+
function ceilingConfig(env = process.env) {
|
|
6926
|
+
return {
|
|
6927
|
+
ceiling: envNumber(env.GENEX_GENERATION_CEILING, DEFAULT_CEILING),
|
|
6928
|
+
characterCeiling: envNumber(env.GENEX_CHARACTER_CEILING, DEFAULT_CHARACTER_CEILING)
|
|
6929
|
+
};
|
|
6930
|
+
}
|
|
6931
|
+
function unshippedCounts(rows) {
|
|
6932
|
+
let lastShip = -1;
|
|
6933
|
+
for (let i = rows.length - 1; i >= 0; i -= 1) {
|
|
6934
|
+
if (rows[i]?.t === "ship") {
|
|
6935
|
+
lastShip = i;
|
|
6936
|
+
break;
|
|
6937
|
+
}
|
|
6938
|
+
}
|
|
6939
|
+
let total = 0;
|
|
6940
|
+
let character = 0;
|
|
6941
|
+
for (let i = lastShip + 1; i < rows.length; i += 1) {
|
|
6942
|
+
const r = rows[i];
|
|
6943
|
+
if (r?.t !== "q") continue;
|
|
6944
|
+
total += 1;
|
|
6945
|
+
if (typeof r.kind === "string" && CHARACTER_KINDS.has(r.kind)) character += 1;
|
|
6946
|
+
}
|
|
6947
|
+
return { total, character };
|
|
6948
|
+
}
|
|
6949
|
+
function ceilingVerdict(input) {
|
|
6950
|
+
const { kind, counts, config } = input;
|
|
6951
|
+
const isCharacter = CHARACTER_KINDS.has(kind);
|
|
6952
|
+
if (isCharacter && config.characterCeiling > 0 && counts.character >= config.characterCeiling) {
|
|
6953
|
+
return {
|
|
6954
|
+
allow: false,
|
|
6955
|
+
reason: `${counts.character} character generations are already waiting and none has been seen in the game yet. Run \`npx genex preview\` \u2014 put the bodies you have in front of the player, look at them, then generate the rest. (A cast fanned out before one body is on screen is how a build ends up with an asset library and an empty world. Raise or remove this with GENEX_CHARACTER_CEILING; 0 turns it off.)`
|
|
6956
|
+
};
|
|
6957
|
+
}
|
|
6958
|
+
if (config.ceiling > 0 && counts.total >= config.ceiling) {
|
|
6959
|
+
return {
|
|
6960
|
+
allow: false,
|
|
6961
|
+
reason: `${counts.total} generations are already waiting and none of them has been shipped yet. Run \`npx genex preview\` \u2014 it takes seconds, it is free, and it resets this immediately. (There is no total here: preview between batches and generate as much as the game needs. Raise or remove it with GENEX_GENERATION_CEILING; 0 turns it off.)`
|
|
6962
|
+
};
|
|
6963
|
+
}
|
|
6964
|
+
return { allow: true };
|
|
6965
|
+
}
|
|
6966
|
+
|
|
6888
6967
|
// src/lib/download-assets.ts
|
|
6889
6968
|
import fs16 from "fs/promises";
|
|
6890
6969
|
import path15 from "path";
|
|
@@ -7400,6 +7479,15 @@ async function runGenerate(kind, opts) {
|
|
|
7400
7479
|
log.dim(` ${prompt}`);
|
|
7401
7480
|
if (skyboxGuard?.guarded) log.dim(" \u21B3 environment-only guard applied (--raw to disable)");
|
|
7402
7481
|
log.plain("");
|
|
7482
|
+
{
|
|
7483
|
+
const counts = unshippedCounts(await readLedgerRows());
|
|
7484
|
+
const verdict = ceilingVerdict({ kind, counts, config: ceilingConfig() });
|
|
7485
|
+
if (!verdict.allow) {
|
|
7486
|
+
log.error(verdict.reason);
|
|
7487
|
+
process.exitCode = 1;
|
|
7488
|
+
return;
|
|
7489
|
+
}
|
|
7490
|
+
}
|
|
7403
7491
|
let id;
|
|
7404
7492
|
try {
|
|
7405
7493
|
const res = await apiFetch(`${apiUrl}/api/generations`, {
|
|
@@ -18618,6 +18706,15 @@ async function postWorkflow(url, token, body) {
|
|
|
18618
18706
|
}
|
|
18619
18707
|
async function runWorkflow(args) {
|
|
18620
18708
|
const log = createLogger({ quiet: args.opts.quiet || args.opts.json });
|
|
18709
|
+
{
|
|
18710
|
+
const counts = unshippedCounts(await readLedgerRows());
|
|
18711
|
+
const verdict = ceilingVerdict({ kind: args.kind, counts, config: ceilingConfig() });
|
|
18712
|
+
if (!verdict.allow) {
|
|
18713
|
+
log.error(verdict.reason);
|
|
18714
|
+
process.exitCode = 1;
|
|
18715
|
+
return;
|
|
18716
|
+
}
|
|
18717
|
+
}
|
|
18621
18718
|
const created = await postWorkflow(`${args.ctx.apiUrl}${args.createPath}`, args.ctx.token, args.body);
|
|
18622
18719
|
if (!created) {
|
|
18623
18720
|
process.exitCode = 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0-dev.605",
|
|
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": {
|
|
@@ -204,7 +204,11 @@ together with `--no-wait` while you scaffold. Before a second batch starts,
|
|
|
204
204
|
every id in the first is collected with `npx genex wait --all`, loaded from a
|
|
205
205
|
file in `src/`, and seen in a capture. A batch begun while the previous one is
|
|
206
206
|
still uncollected is how a game ends up with an asset library and an empty
|
|
207
|
-
world.
|
|
207
|
+
world. This is enforced, not merely advised: unshipped generations are counted
|
|
208
|
+
and the generate commands refuse past a ceiling, which `npx genex preview`
|
|
209
|
+
resets to zero. There is no total — preview between batches and generate as
|
|
210
|
+
much as the game needs. Preserve every id, URL and wiring state across a
|
|
211
|
+
compaction.
|
|
208
212
|
|
|
209
213
|
## 5. Execute by working mode
|
|
210
214
|
|
|
@@ -45,6 +45,24 @@ Skip this and the mesh is a speck or a wall — it is the single most common way
|
|
|
45
45
|
generated asset ships broken. Rigged bodies mismeasure here; those go through
|
|
46
46
|
the controller's own boot path, not this snippet.
|
|
47
47
|
|
|
48
|
+
## Generate in batches you can finish
|
|
49
|
+
|
|
50
|
+
The belt has a **shipping ratchet**: generations that have not been shown to the
|
|
51
|
+
player are counted, and the count resets to zero every time you `npx genex
|
|
52
|
+
preview`. Hit it and the command refuses with the number and the fix.
|
|
53
|
+
|
|
54
|
+
It is not a spend limit and there is no total — preview between batches and
|
|
55
|
+
generate as much as the game needs. What it stops is one thing: fanning out a
|
|
56
|
+
whole cast or a shelf of props before the player has seen any of it. If you are
|
|
57
|
+
refused, you are not out of anything. You have work that nobody has looked at.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx genex model "..." --no-wait # a batch you can finish
|
|
61
|
+
npx genex wait --all # collect it
|
|
62
|
+
# wire it, then:
|
|
63
|
+
npx genex preview # free, seconds — and the count is zero again
|
|
64
|
+
```
|
|
65
|
+
|
|
48
66
|
## The one rule
|
|
49
67
|
|
|
50
68
|
An asset is not done when the command exits. It is done when something in
|