@genex-ai/cli-demo 0.51.0-dev.101 → 0.51.0-dev.110
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
|
@@ -1652,7 +1652,13 @@ async function callPublish(ctx, commit, opts, log) {
|
|
|
1652
1652
|
async function pushSource(cwd, ctx, log) {
|
|
1653
1653
|
const target = await fetchPushUrl(ctx, log);
|
|
1654
1654
|
if (!target) return false;
|
|
1655
|
-
|
|
1655
|
+
if (await pushWorktree(cwd, target.pushUrl, target.managed, log)) return true;
|
|
1656
|
+
if (!target.managed) return false;
|
|
1657
|
+
log.info("Retrying the source push\u2026");
|
|
1658
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
1659
|
+
const fresh = await fetchPushUrl(ctx, log);
|
|
1660
|
+
if (!fresh) return false;
|
|
1661
|
+
return pushWorktree(cwd, fresh.pushUrl, fresh.managed, log);
|
|
1656
1662
|
}
|
|
1657
1663
|
async function pushWorktree(cwd, pushUrl, managed, log) {
|
|
1658
1664
|
const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
@@ -2119,6 +2125,44 @@ async function runPreview(opts) {
|
|
|
2119
2125
|
}
|
|
2120
2126
|
}
|
|
2121
2127
|
|
|
2128
|
+
// src/lib/open.ts
|
|
2129
|
+
import { spawn as spawn4 } from "child_process";
|
|
2130
|
+
function tokenize(cmd) {
|
|
2131
|
+
return cmd.trim().split(/\s+/).filter(Boolean);
|
|
2132
|
+
}
|
|
2133
|
+
function openUrl(url) {
|
|
2134
|
+
let command;
|
|
2135
|
+
let args;
|
|
2136
|
+
const custom = (process.env.GENEX_BROWSER || process.env.BROWSER)?.trim();
|
|
2137
|
+
const customParts = custom ? tokenize(custom) : [];
|
|
2138
|
+
if (customParts.length > 0) {
|
|
2139
|
+
command = customParts[0];
|
|
2140
|
+
args = [...customParts.slice(1), url];
|
|
2141
|
+
} else {
|
|
2142
|
+
switch (process.platform) {
|
|
2143
|
+
case "darwin":
|
|
2144
|
+
command = "open";
|
|
2145
|
+
args = [url];
|
|
2146
|
+
break;
|
|
2147
|
+
case "win32":
|
|
2148
|
+
command = "cmd";
|
|
2149
|
+
args = ["/c", "start", "", url];
|
|
2150
|
+
break;
|
|
2151
|
+
default:
|
|
2152
|
+
command = "xdg-open";
|
|
2153
|
+
args = [url];
|
|
2154
|
+
break;
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
try {
|
|
2158
|
+
const child = spawn4(command, args, { stdio: "ignore", detached: true });
|
|
2159
|
+
child.on("error", () => {
|
|
2160
|
+
});
|
|
2161
|
+
child.unref();
|
|
2162
|
+
} catch {
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2122
2166
|
// src/lib/sse.ts
|
|
2123
2167
|
async function* readSSE(body) {
|
|
2124
2168
|
const decoder = new TextDecoder();
|
|
@@ -2255,9 +2299,9 @@ async function runGenerate(kind, opts) {
|
|
|
2255
2299
|
log.dim(" (Re-running the generate command would start \u2014 and bill \u2014 a NEW generation.)");
|
|
2256
2300
|
return;
|
|
2257
2301
|
}
|
|
2258
|
-
await awaitAndReport(apiUrl, token, id, kind, log);
|
|
2302
|
+
await awaitAndReport(apiUrl, token, id, kind, log, opts.open);
|
|
2259
2303
|
}
|
|
2260
|
-
async function awaitAndReport(apiUrl, token, id, kind, log) {
|
|
2304
|
+
async function awaitAndReport(apiUrl, token, id, kind, log, open = false) {
|
|
2261
2305
|
log.step("Generating\u2026 (this can take up to a minute)");
|
|
2262
2306
|
const onProgress = (p) => log.dim(` ${p}%`);
|
|
2263
2307
|
const timeoutMs = waitTimeoutFor(kind);
|
|
@@ -2269,9 +2313,9 @@ async function awaitAndReport(apiUrl, token, id, kind, log) {
|
|
|
2269
2313
|
process.exitCode = 1;
|
|
2270
2314
|
return;
|
|
2271
2315
|
}
|
|
2272
|
-
await reportTerminal(kind, view, log);
|
|
2316
|
+
await reportTerminal(kind, view, log, open);
|
|
2273
2317
|
}
|
|
2274
|
-
async function reportTerminal(kind, view, log) {
|
|
2318
|
+
async function reportTerminal(kind, view, log, open = false) {
|
|
2275
2319
|
if (view.status !== "completed") {
|
|
2276
2320
|
log.error(`Generation ${view.status}${view.error ? `: ${view.error}` : ""}.`);
|
|
2277
2321
|
process.exitCode = 1;
|
|
@@ -2290,6 +2334,14 @@ async function reportTerminal(kind, view, log) {
|
|
|
2290
2334
|
log.plain(` ${label}${f.url}`);
|
|
2291
2335
|
}
|
|
2292
2336
|
log.plain("");
|
|
2337
|
+
if (open && files[0]) {
|
|
2338
|
+
openUrl(files[0].url);
|
|
2339
|
+
log.plain(
|
|
2340
|
+
` ${c.bold("\u{1F441} Show this to the user")} \u2014 it just opened in their browser; paste this link in chat too so they can open it themselves:`
|
|
2341
|
+
);
|
|
2342
|
+
log.plain(` ${files[0].url}`);
|
|
2343
|
+
log.plain("");
|
|
2344
|
+
}
|
|
2293
2345
|
printHint(kind, files, log);
|
|
2294
2346
|
await firstPreviewNudge(log);
|
|
2295
2347
|
}
|
|
@@ -2440,10 +2492,10 @@ async function runWait(opts) {
|
|
|
2440
2492
|
log.dim(` ${kind} ${id}`);
|
|
2441
2493
|
log.plain("");
|
|
2442
2494
|
if (TERMINAL2.has(view.status)) {
|
|
2443
|
-
await reportTerminal(kind, view, log);
|
|
2495
|
+
await reportTerminal(kind, view, log, opts.open);
|
|
2444
2496
|
return;
|
|
2445
2497
|
}
|
|
2446
|
-
await awaitAndReport(apiUrl, token, id, kind, log);
|
|
2498
|
+
await awaitAndReport(apiUrl, token, id, kind, log, opts.open);
|
|
2447
2499
|
}
|
|
2448
2500
|
|
|
2449
2501
|
// src/commands/controller.ts
|
|
@@ -4048,6 +4100,8 @@ ${c.bold("Options for the generators (`model` `skybox` `sfx` `texture` `image` `
|
|
|
4048
4100
|
--terrain (texture) seamless tiling surface for terrain/ground.
|
|
4049
4101
|
--duration <sec> (sfx, video) target clip length in seconds.
|
|
4050
4102
|
--transparent (image) transparent background (alpha) \u2014 for decals/stickers.
|
|
4103
|
+
--open (image/video) open the finished asset in the user's browser +
|
|
4104
|
+
print a link \u2014 show them the concept frame / anything they approve.
|
|
4051
4105
|
--aspect <ratio> (image) aspect preset (e.g. square, landscape, portrait).
|
|
4052
4106
|
--quality <q> (image) quality preset: low | medium | high.
|
|
4053
4107
|
--candidates <n> (image) generate 2-4 variants in ONE call and print every
|
|
@@ -4232,6 +4286,9 @@ function parseArgs(argv) {
|
|
|
4232
4286
|
case "--no-wait":
|
|
4233
4287
|
parsed.options.noWait = true;
|
|
4234
4288
|
break;
|
|
4289
|
+
case "--open":
|
|
4290
|
+
parsed.options.open = true;
|
|
4291
|
+
break;
|
|
4235
4292
|
case "--terrain":
|
|
4236
4293
|
parsed.options.terrain = true;
|
|
4237
4294
|
break;
|
package/package.json
CHANGED
|
@@ -79,13 +79,25 @@ lap counter in a game without laps). `--aspect 16:9 --quality high
|
|
|
79
79
|
--no-wait`, enqueued FIRST of all art; the URL goes into the style-brief
|
|
80
80
|
comment.
|
|
81
81
|
|
|
82
|
-
**Share it before building on it
|
|
83
|
-
the
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
**Share it before building on it — actually SHOW the image, don't just ask.**
|
|
83
|
+
When the concept lands, pick it up with `genex wait <id> --open` (or generate it
|
|
84
|
+
with `--open`): it opens in the user's browser AND prints the link. Paste that
|
|
85
|
+
URL as a clickable link in your approval message — a URL is invisible in a
|
|
86
|
+
terminal, and "do you like it?" with no picture in front of the user is the #1
|
|
87
|
+
way this checkpoint fails (they end up digging logs for the file path). Then ask
|
|
88
|
+
ONE structured question — "this is roughly how the game will look: keep it, or
|
|
89
|
+
change something?" — with 2–3 concrete adjustment options. Keep building
|
|
90
|
+
gameplay-neutral work (scaffold, physics, netcode) while waiting, but do NOT
|
|
91
|
+
anchor further art to an unapproved frame. **Approval is a LOOP, not a
|
|
92
|
+
one-shot:** if the user dislikes ANYTHING, regenerate with their exact notes
|
|
93
|
+
(`--candidates 2–3` gives them options to choose from), open + link the new
|
|
94
|
+
frame, and ask again — repeat until they actually approve. Carry every note
|
|
95
|
+
forward so each round compounds; if two rounds don't converge, offer 2–3
|
|
96
|
+
distinct directions as a structured question instead of re-rolling blind. The
|
|
97
|
+
HUD mockup, the menu, and every downstream asset wait for a frame the user has
|
|
98
|
+
signed off — a single "meh" is never permission to move on. The same "open it +
|
|
99
|
+
paste the link" rule covers every image the user weighs in on — the menu still,
|
|
100
|
+
the HUD mockup candidates.
|
|
89
101
|
|
|
90
102
|
**The concept anchors STYLE, not truth.** Palette, materials, light, and
|
|
91
103
|
register come from the frame; CONTENT comes from the game contract. When
|