@bitmagic/cli 0.1.1 → 0.1.3

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.
Files changed (46) hide show
  1. package/dist/cli.d.ts +30 -0
  2. package/dist/cli.js +23 -11
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/forge.d.ts +107 -0
  5. package/dist/commands/forge.js +393 -0
  6. package/dist/commands/forge.js.map +1 -0
  7. package/dist/commands/generate.js +58 -45
  8. package/dist/commands/generate.js.map +1 -1
  9. package/dist/commands/verify.js +16 -16
  10. package/dist/commands/verify.js.map +1 -1
  11. package/dist/forge/apply-modifications.d.ts +19 -0
  12. package/dist/forge/apply-modifications.js +184 -0
  13. package/dist/forge/apply-modifications.js.map +1 -0
  14. package/dist/forge/bake-progress.d.ts +44 -0
  15. package/dist/forge/bake-progress.js +77 -0
  16. package/dist/forge/bake-progress.js.map +1 -0
  17. package/dist/forge/browser-host.d.ts +100 -0
  18. package/dist/forge/browser-host.js +351 -0
  19. package/dist/forge/browser-host.js.map +1 -0
  20. package/dist/forge/local-store.d.ts +30 -0
  21. package/dist/forge/local-store.js +130 -0
  22. package/dist/forge/local-store.js.map +1 -0
  23. package/dist/forge/run-pipeline.d.ts +105 -0
  24. package/dist/forge/run-pipeline.js +269 -0
  25. package/dist/forge/run-pipeline.js.map +1 -0
  26. package/dist/forge/stream.d.ts +106 -0
  27. package/dist/forge/stream.js +286 -0
  28. package/dist/forge/stream.js.map +1 -0
  29. package/dist/forge/transport.d.ts +58 -0
  30. package/dist/forge/transport.js +145 -0
  31. package/dist/forge/transport.js.map +1 -0
  32. package/dist/forge/upload-proxy.d.ts +21 -0
  33. package/dist/forge/upload-proxy.js +134 -0
  34. package/dist/forge/upload-proxy.js.map +1 -0
  35. package/dist/generate/stream.d.ts +1 -10
  36. package/dist/generate/stream.js +5 -62
  37. package/dist/generate/stream.js.map +1 -1
  38. package/dist/http/sse.d.ts +40 -0
  39. package/dist/http/sse.js +98 -0
  40. package/dist/http/sse.js.map +1 -0
  41. package/dist/local-port.d.ts +30 -0
  42. package/dist/local-port.js +53 -0
  43. package/dist/local-port.js.map +1 -0
  44. package/dist/scaffold/project-files.js +89 -9
  45. package/dist/scaffold/project-files.js.map +1 -1
  46. package/package.json +3 -2
package/dist/cli.d.ts CHANGED
@@ -63,6 +63,36 @@ declare const rawCommands: {
63
63
  };
64
64
  }>;
65
65
  generate: CommandDef<ArgsDef>;
66
+ forge: CommandDef<{
67
+ readonly prompt: {
68
+ readonly type: "string";
69
+ readonly description: "Describe the level, e.g. \"a ruined desert temple with a central courtyard\".";
70
+ };
71
+ readonly name: {
72
+ readonly type: "string";
73
+ readonly description: "Name for the level. Derived from the prompt when omitted.";
74
+ };
75
+ readonly resume: {
76
+ readonly type: "string";
77
+ readonly description: "Resume a job id printed by an earlier run; completed steps are skipped.";
78
+ };
79
+ readonly city: {
80
+ readonly type: "boolean";
81
+ readonly description: "Build a city (street grid, buildings, landmarks).";
82
+ };
83
+ readonly dungeon: {
84
+ readonly type: "boolean";
85
+ readonly description: "Build an enclosed dungeon of rooms and corridors.";
86
+ };
87
+ readonly platformer: {
88
+ readonly type: "boolean";
89
+ readonly description: "Build a third-person platformer journey.";
90
+ };
91
+ readonly freeform: {
92
+ readonly type: "boolean";
93
+ readonly description: "Build a custom place (arena, fortress, camp).";
94
+ };
95
+ }>;
66
96
  };
67
97
  type CommandName = keyof typeof rawCommands;
68
98
  export declare const subCommands: Record<CommandName, CommandDef<ArgsDef>>;
package/dist/cli.js CHANGED
@@ -8,6 +8,7 @@ import { checkCommand } from './commands/check.js';
8
8
  import { devCommand } from './commands/dev.js';
9
9
  import { verifyCommand } from './commands/verify.js';
10
10
  import { generateCommand } from './commands/generate.js';
11
+ import { forgeCommand } from './commands/forge.js';
11
12
  // citty's runMain() catches every error thrown from a command's `run()` internally and calls
12
13
  // process.exit() itself — it never rejects the promise it returns, so the `.catch()` below
13
14
  // never runs for those. For anything that isn't citty's own internal CLIError class, its catch
@@ -18,6 +19,18 @@ import { generateCommand } from './commands/generate.js';
18
19
  // "every entry of subCommands is wrapped" structurally, by reference, instead of maintaining a
19
20
  // separate list of command names that could drift out of sync with the real map.
20
21
  const wrappedRuns = new WeakSet();
22
+ /**
23
+ * The command's subcommand map, or `undefined` if it has none. Every `subCommands` value in this
24
+ * CLI is a plain synchronous object literal (never a citty Promise/function Resolvable), so
25
+ * narrowing it this way is safe for this codebase's actual usage even though citty's own type
26
+ * allows more.
27
+ */
28
+ function subCommandsOf(command) {
29
+ const subs = command.subCommands;
30
+ if (!subs || typeof subs !== 'object')
31
+ return undefined;
32
+ return subs;
33
+ }
21
34
  export function withCleanErrors(command) {
22
35
  const originalRun = command.run;
23
36
  const wrapped = { ...command };
@@ -43,12 +56,10 @@ export function withCleanErrors(command) {
43
56
  // unrecursed, a CliError thrown from one of those would clear this command's own (nonexistent)
44
57
  // run untouched and hit citty's default handling instead — a raw stack trace, the exact thing
45
58
  // this wrapper exists to prevent. Recurse so every depth gets the same clean single-line
46
- // treatment. Every subCommands value in this CLI is a plain synchronous object literal (never a
47
- // citty Promise/function Resolvable), so narrowing it that way here is safe for this codebase's
48
- // actual usage even though citty's own type allows more.
49
- if (command.subCommands && typeof command.subCommands === 'object') {
50
- const rawSubCommands = command.subCommands;
51
- wrapped.subCommands = Object.fromEntries(Object.entries(rawSubCommands).map(([name, sub]) => [name, withCleanErrors(sub)]));
59
+ // treatment.
60
+ const subs = subCommandsOf(command);
61
+ if (subs) {
62
+ wrapped.subCommands = Object.fromEntries(Object.entries(subs).map(([name, sub]) => [name, withCleanErrors(sub)]));
52
63
  }
53
64
  return wrapped;
54
65
  }
@@ -62,11 +73,11 @@ export function isWrappedWithCleanErrors(command) {
62
73
  if (command.run !== undefined) {
63
74
  return wrappedRuns.has(command.run);
64
75
  }
65
- if (command.subCommands && typeof command.subCommands === 'object') {
66
- const entries = Object.values(command.subCommands);
67
- return entries.length > 0 && entries.every((sub) => isWrappedWithCleanErrors(sub));
68
- }
69
- return false;
76
+ const subs = subCommandsOf(command);
77
+ if (!subs)
78
+ return false;
79
+ const entries = Object.values(subs);
80
+ return entries.length > 0 && entries.every((sub) => isWrappedWithCleanErrors(sub));
70
81
  }
71
82
  // Wrapping happens once here, over the whole map, rather than per-entry at each call site —
72
83
  // a future command added to `rawCommands` is wrapped automatically, so there is no per-command
@@ -80,6 +91,7 @@ const rawCommands = {
80
91
  dev: devCommand,
81
92
  verify: verifyCommand,
82
93
  generate: generateCommand,
94
+ forge: forgeCommand,
83
95
  };
84
96
  export const subCommands = Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => [name, withCleanErrors(command)]));
85
97
  // This module only builds `main` and exports it (along with `subCommands` and `withCleanErrors`)
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import { type ForgeJobInput } from '@bitmagic/world-forger/pipeline/index.js';
2
+ /** The four scene approaches the forger supports. Exactly one may be chosen; none = terrain. */
3
+ declare const MODE_FLAGS: readonly ["city", "dungeon", "platformer", "freeform"];
4
+ type ModeFlag = (typeof MODE_FLAGS)[number];
5
+ /**
6
+ * The level's name. Always sent EXPLICITLY to the server, even when derived: api-server's
7
+ * `resolveLevelName` falls back to its own derivation from the prompt when `name` is absent, and
8
+ * this lane also freezes an `input` artifact locally (see `seedForgeStore`). Two independent
9
+ * derivations of the same name would be a drift waiting to happen, so the CLI decides once and
10
+ * the server receives the answer rather than recomputing it.
11
+ */
12
+ export declare function deriveLevelName(explicit: string | undefined, prompt: string): string;
13
+ /** The single selected mode, or undefined for plain terrain. */
14
+ export declare function selectMode(args: Record<string, unknown>): ModeFlag | undefined;
15
+ /**
16
+ * Resolve the frozen request for this run.
17
+ *
18
+ * On a fresh run it comes from the flags. On a resume it comes from the job's LOCAL frozen
19
+ * `input` artifact where one exists, so the resumed request re-sends exactly what the original
20
+ * sent — which also lets `--resume` stand alone, without repeating the prompt. api-server freezes
21
+ * its own copy and never overwrites it, so a resume that did send different flags would produce a
22
+ * level whose geometry came from the original design but whose name and prompt came from the new
23
+ * invocation. Reading the frozen copy back removes that divergence rather than documenting it.
24
+ */
25
+ export declare function resolveJobInput(options: {
26
+ frozen: ForgeJobInput | null;
27
+ prompt: string | undefined;
28
+ name: string | undefined;
29
+ mode: ModeFlag | undefined;
30
+ gameId: string;
31
+ resumeJobId: string | null;
32
+ }): ForgeJobInput;
33
+ /** The request body for `POST /api/cli/v1/forge/stream`. */
34
+ export declare function buildForgeRequestBody(input: ForgeJobInput, resumeJobId: string | null): Record<string, unknown>;
35
+ export interface ForgeRunDeps {
36
+ fetch: typeof globalThis.fetch;
37
+ sleep: (ms: number) => Promise<void>;
38
+ now?: () => number;
39
+ /** Test-only override; production omits it and loadProjectContext walks up from process.cwd(). */
40
+ startDir?: string;
41
+ /** Test-only override; production omits it and the credential helpers read ~/.bitmagic. */
42
+ baseDir?: string;
43
+ log: (message: string) => void;
44
+ }
45
+ /**
46
+ * The whole command. Failure wording is the contract here — see the file header.
47
+ *
48
+ * - Anything before step 5's apply leaves world.json untouched, and says so.
49
+ * - A server-side failure additionally says whether resuming can help; see
50
+ * `classifyForgeFailure`, which is the difference between "try again" and "change your prompt".
51
+ * - A failure AFTER the design and geometry landed but before (or during) the local write is the
52
+ * expensive case: the forge has been billed, and the message says the work is saved under a job
53
+ * id rather than lost.
54
+ */
55
+ export declare function runForge(args: {
56
+ prompt?: string;
57
+ name?: string;
58
+ resume?: string;
59
+ } & Record<string, unknown>, deps?: ForgeRunDeps): Promise<void>;
60
+ /**
61
+ * Decorate a steps 3-5 failure with the job id, REGARDLESS of its class.
62
+ *
63
+ * The class check `generate.ts` uses would be wrong here, and the difference is not stylistic:
64
+ * steps 3-5 come from `@bitmagic/world-forger` and throw plain `Error`/`ForgeStepError`, not
65
+ * `CliError` — the bake timeout (`voxelize-level.ts`), the placement timeout
66
+ * (`place-and-persist-level.ts`), a missing artifact (`artifact-store.ts`) and the archetype
67
+ * timeout (`create-level-archetypes.ts`) are all third-party classes. Passing those through
68
+ * untouched sends them past `withCleanErrors` into citty's raw stack dump, with no job id and no
69
+ * world.json statement — in the exact window where the design and geometry are already paid for.
70
+ * A creator seeing `Error: Level voxelization timed out` and a stack has no way to know that
71
+ * resuming is free, and will re-run with `--prompt` and pay for a second design.
72
+ *
73
+ * `generate.ts` gets away with the class check only because nothing in its span throws a
74
+ * third-party error class.
75
+ */
76
+ export declare function decorateBrowserStepError(error: unknown, jobId: string): unknown;
77
+ export declare const forgeCommand: import("citty").CommandDef<{
78
+ readonly prompt: {
79
+ readonly type: "string";
80
+ readonly description: "Describe the level, e.g. \"a ruined desert temple with a central courtyard\".";
81
+ };
82
+ readonly name: {
83
+ readonly type: "string";
84
+ readonly description: "Name for the level. Derived from the prompt when omitted.";
85
+ };
86
+ readonly resume: {
87
+ readonly type: "string";
88
+ readonly description: "Resume a job id printed by an earlier run; completed steps are skipped.";
89
+ };
90
+ readonly city: {
91
+ readonly type: "boolean";
92
+ readonly description: "Build a city (street grid, buildings, landmarks).";
93
+ };
94
+ readonly dungeon: {
95
+ readonly type: "boolean";
96
+ readonly description: "Build an enclosed dungeon of rooms and corridors.";
97
+ };
98
+ readonly platformer: {
99
+ readonly type: "boolean";
100
+ readonly description: "Build a third-person platformer journey.";
101
+ };
102
+ readonly freeform: {
103
+ readonly type: "boolean";
104
+ readonly description: "Build a custom place (arena, fortress, camp).";
105
+ };
106
+ }>;
107
+ export {};
@@ -0,0 +1,393 @@
1
+ /**
2
+ * `bitmagic forge` — design, build and install a playable level, in one command.
3
+ *
4
+ * Five steps, split across two hosts:
5
+ *
6
+ * 1. design the scene with an LLM ┐ api-server, over `POST /api/cli/v1/forge/stream`
7
+ * 2. forge geometry + upload GLBs ┘ (paid, and the private half of the forger)
8
+ * 3. create the archetype assets ┐
9
+ * 4. bake the level to voxels ├ HERE, driving a headless Chrome that runs the real engine
10
+ * 5. place instances + persist ┘
11
+ *
12
+ * Steps 3-5 are not pure compute: they drive the game engine over `postMessage`, and the round
13
+ * trip through the engine is the only source of the instance ids step 5 persists. So this command
14
+ * builds the project, serves it, opens it in Chrome, and runs the shared pipeline against that
15
+ * page — then applies what step 5 returns to the project's own world.json.
16
+ *
17
+ * Every failure path states explicitly whether world.json changed. A creator (or the agent driving
18
+ * this CLI) who does not know has to go and look, and a forge costs enough that "did I pay for
19
+ * nothing, and is my project still intact?" is the first question.
20
+ */
21
+ import { defineCommand } from 'citty';
22
+ import { spawn, spawnSync } from 'child_process';
23
+ import { createForgedWorkStore, } from '@bitmagic/world-forger/pipeline/index.js';
24
+ import { CliError } from '../errors.js';
25
+ import { loadProjectContext, projectBin } from '../project/context.js';
26
+ import { resolveEnvironment, resolveAuth0ClientId } from '../config/environments.js';
27
+ import { readDefaultEnvironment } from '../config/credentials.js';
28
+ import { getAccessToken } from '../auth/session.js';
29
+ import { waitForServer } from '../verify/wait-for-server.js';
30
+ import { ForgeBrowserHost, readProjectGameData } from '../forge/browser-host.js';
31
+ import { startUploadProxy } from '../forge/upload-proxy.js';
32
+ import { reserveCorsAllowedPort, CORS_ALLOWED_PORT_MIN, CORS_ALLOWED_PORT_MAX } from '../local-port.js';
33
+ import { createBakeProgressPrinter } from '../forge/bake-progress.js';
34
+ import { createLocalForgeStorage } from '../forge/local-store.js';
35
+ import { describeForgeFailure, requestForge } from '../forge/stream.js';
36
+ import { buildCliForgeDeps, createConsoleForgeLogger, readFrozenInput, runForgePipeline, seedForgeStore, } from '../forge/run-pipeline.js';
37
+ /** Mirrors api-server's `FORGE_JOB_ID_PATTERN` so a typo is rejected here, before a round trip. */
38
+ const JOB_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
39
+ /**
40
+ * The command that resumes a job. One definition because `decorateBrowserStepError` decides
41
+ * whether to append its advice by looking for this exact string — two spellings would make that
42
+ * check silently miss.
43
+ */
44
+ function resumeCommand(jobId) {
45
+ return `bitmagic forge --resume ${jobId}`;
46
+ }
47
+ /** The four scene approaches the forger supports. Exactly one may be chosen; none = terrain. */
48
+ const MODE_FLAGS = ['city', 'dungeon', 'platformer', 'freeform'];
49
+ /** `cityMode`, `dungeonMode`, … — the body fields `ForgeJobInput` declares. */
50
+ function modeField(mode) {
51
+ return `${mode}Mode`;
52
+ }
53
+ /**
54
+ * The level's name. Always sent EXPLICITLY to the server, even when derived: api-server's
55
+ * `resolveLevelName` falls back to its own derivation from the prompt when `name` is absent, and
56
+ * this lane also freezes an `input` artifact locally (see `seedForgeStore`). Two independent
57
+ * derivations of the same name would be a drift waiting to happen, so the CLI decides once and
58
+ * the server receives the answer rather than recomputing it.
59
+ */
60
+ export function deriveLevelName(explicit, prompt) {
61
+ if (explicit !== undefined && explicit.trim().length > 0)
62
+ return explicit.trim();
63
+ const derived = prompt.trim().split(/\s+/).slice(0, 6).join(' ').slice(0, 48).trim();
64
+ return derived.length > 0 ? derived : 'level';
65
+ }
66
+ /** The single selected mode, or undefined for plain terrain. */
67
+ export function selectMode(args) {
68
+ const chosen = MODE_FLAGS.filter((mode) => args[mode] === true);
69
+ if (chosen.length > 1) {
70
+ // No "world.json is unchanged." here: `prepareForgeRequest` appends it to every CliError
71
+ // raised in the pre-request span, so stating it again would print it twice.
72
+ throw new CliError(`Choose at most one scene type — got ${chosen.map((m) => `--${m}`).join(' and ')}. `
73
+ + 'Omit them all for natural terrain.');
74
+ }
75
+ return chosen[0];
76
+ }
77
+ /**
78
+ * A free port INSIDE the CORS-allowed window, never an OS-assigned ephemeral one.
79
+ *
80
+ * The bake browser itself would not care — it runs with `--disable-web-security`. The project
81
+ * served here outlives the bake though: this is the same build a creator then loads with
82
+ * `bitmagic dev` or `bitmagic verify` in an ordinary browser, and from an out-of-window origin the
83
+ * CDN refuses the forged `.vwld`, the engine initialises an empty voxel world, and the level has
84
+ * no terrain to stand on. See local-port.ts.
85
+ */
86
+ async function freePort() {
87
+ const port = await reserveCorsAllowedPort();
88
+ if (port === null) {
89
+ throw new CliError(`No free port between ${CORS_ALLOWED_PORT_MIN} and ${CORS_ALLOWED_PORT_MAX}, which is the `
90
+ + 'range the asset CDN allows as an origin. Stop whatever is holding them and forge again.');
91
+ }
92
+ return port;
93
+ }
94
+ /**
95
+ * Resolve the frozen request for this run.
96
+ *
97
+ * On a fresh run it comes from the flags. On a resume it comes from the job's LOCAL frozen
98
+ * `input` artifact where one exists, so the resumed request re-sends exactly what the original
99
+ * sent — which also lets `--resume` stand alone, without repeating the prompt. api-server freezes
100
+ * its own copy and never overwrites it, so a resume that did send different flags would produce a
101
+ * level whose geometry came from the original design but whose name and prompt came from the new
102
+ * invocation. Reading the frozen copy back removes that divergence rather than documenting it.
103
+ */
104
+ export function resolveJobInput(options) {
105
+ const { frozen, prompt, name, mode, gameId, resumeJobId } = options;
106
+ if (frozen !== null && prompt === undefined)
107
+ return frozen;
108
+ if (prompt === undefined || prompt.trim().length === 0) {
109
+ throw new CliError(resumeJobId === null
110
+ ? '--prompt is required. Describe the level you want, e.g. `bitmagic forge --prompt "a ruined desert temple with a central courtyard"`.'
111
+ : `This machine has no saved record of job "${resumeJobId}" (it was started elsewhere, or `
112
+ + '`.bitmagic/` was cleared), so --prompt is required to resume it. Pass the SAME prompt '
113
+ + 'the original run used — the server forges what it froze, but the level name and '
114
+ + 'description saved into world.json come from this invocation.');
115
+ }
116
+ const trimmed = prompt.trim();
117
+ return {
118
+ name: deriveLevelName(name, trimmed),
119
+ prompt: trimmed,
120
+ gameId,
121
+ ...(mode ? { [modeField(mode)]: true } : {}),
122
+ };
123
+ }
124
+ /** The request body for `POST /api/cli/v1/forge/stream`. */
125
+ export function buildForgeRequestBody(input, resumeJobId) {
126
+ return {
127
+ ...input,
128
+ ...(resumeJobId !== null ? { jobId: resumeJobId } : {}),
129
+ };
130
+ }
131
+ /** Print the level the forge produced, and what to do next. */
132
+ function reportSummary(summary, changes, log) {
133
+ log('');
134
+ log(`Level "${summary.asset_name}" is in your project.`);
135
+ for (const line of changes)
136
+ log(` - ${line}`);
137
+ const { x, y, z } = summary.player_start;
138
+ log(`Player start: (${x.toFixed(1)}, ${y.toFixed(1)}, ${z.toFixed(1)})`);
139
+ if (summary.library_assets.length > 0) {
140
+ log(`Library assets: ${summary.library_assets.map((a) => `${a.name} x${a.instances}`).join(', ')}`);
141
+ }
142
+ if (summary.markers.length > 0) {
143
+ log(`Markers: ${summary.markers.map((m) => m.name).join(', ')}`);
144
+ }
145
+ log('');
146
+ log('Run `bitmagic dev` and walk the level to check it.');
147
+ }
148
+ function defaultDeps() {
149
+ return {
150
+ fetch: globalThis.fetch,
151
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
152
+ log: (message) => console.log(message),
153
+ };
154
+ }
155
+ /** Build the project to completion. Every alias resolves into dist/, so serving before the first
156
+ * emit 404s every module — a failure that reads as "the engine is broken", not "not built". */
157
+ function buildProject(context, log) {
158
+ const tsc = projectBin(context.root, 'tsc');
159
+ log('Building the project…');
160
+ const build = spawnSync(tsc, [], { cwd: context.root, stdio: 'inherit' });
161
+ if (build.error) {
162
+ throw new CliError(`Could not run the TypeScript compiler: ${build.error.message} world.json is unchanged.`);
163
+ }
164
+ if (build.status !== 0) {
165
+ throw new CliError('Build failed, so the game cannot be loaded to bake the level. Fix the errors above and '
166
+ + 'resume this forge — world.json is unchanged.', build.status ?? 1);
167
+ }
168
+ }
169
+ /**
170
+ * Steps 3-5: serve the project, drive a headless Chrome through it, and apply the result.
171
+ *
172
+ * Split out so the browser + server lifecycle has exactly one `finally` that owns tearing both
173
+ * down, however this exits — an orphaned vite on a random port and a headless Chrome holding a
174
+ * temp profile are both silent, and both outlive the terminal.
175
+ */
176
+ async function runBrowserSteps(options) {
177
+ const { context, environment, jobId, token, deps } = options;
178
+ const { log } = deps;
179
+ buildProject(context, log);
180
+ const port = await freePort();
181
+ const vite = projectBin(context.root, 'vite');
182
+ let server;
183
+ let host;
184
+ let uploadProxy;
185
+ try {
186
+ server = spawn(vite, ['--port', String(port), '--strictPort'], {
187
+ cwd: context.root,
188
+ stdio: ['ignore', 'ignore', 'pipe'],
189
+ });
190
+ let viteStderr = '';
191
+ server.stderr?.on('data', (chunk) => {
192
+ viteStderr += String(chunk);
193
+ });
194
+ try {
195
+ await waitForServer(port, 30_000);
196
+ }
197
+ catch {
198
+ throw new CliError(`The project's dev server did not come up on port ${port}, so the level cannot be baked.`
199
+ + (viteStderr.trim() ? `\n${viteStderr.trim()}` : '')
200
+ + `\nFix that, then resume with \`${resumeCommand(jobId)}\`. world.json is unchanged.`);
201
+ }
202
+ log(`Serving the project on http://localhost:${port}/ for the bake.`);
203
+ uploadProxy = await startUploadProxy({
204
+ apiUrl: environment.apiUrl,
205
+ token,
206
+ gameId: context.metadata.gameId,
207
+ log,
208
+ });
209
+ host = new ForgeBrowserHost({
210
+ gamePort: port,
211
+ gameId: context.metadata.gameId,
212
+ gameData: readProjectGameData(context.root, context.metadata),
213
+ // api-server, NOT game-play-agent: the engine reads this back as `window.AI_AGENT_URL` and
214
+ // uses it to reach `POST /api/cli/v1/uploads/signed-url` for every GLB and .vwld it writes.
215
+ // The LOCAL proxy, not api-server directly. The engine calls a hardcoded
216
+ // `${agentUrl}/api/generate-upload-url` with no Authorization header, which api-server
217
+ // neither serves nor would accept unauthenticated — see forge/upload-proxy.ts.
218
+ agentUrl: uploadProxy.url,
219
+ log,
220
+ });
221
+ await host.launch();
222
+ await host.loadGame();
223
+ // The bake's own chunk counts, throttled. Subscribed before the pipeline starts so no
224
+ // progress is missed, and left subscribed for the whole run — steps 3 and 5 post no
225
+ // progress of this type, so there is nothing for it to pick up outside the bake.
226
+ const stopBakeProgress = host.onPageMessage(createBakeProgressPrinter(log));
227
+ const storage = createLocalForgeStorage(context.root);
228
+ const store = createForgedWorkStore(jobId, storage);
229
+ const forgeDeps = buildCliForgeDeps({
230
+ projectRoot: context.root,
231
+ storage,
232
+ transport: host.transport,
233
+ logger: createConsoleForgeLogger(log),
234
+ });
235
+ try {
236
+ const result = await runForgePipeline({
237
+ projectRoot: context.root,
238
+ store,
239
+ deps: forgeDeps,
240
+ log,
241
+ });
242
+ if (result.applied) {
243
+ reportSummary(result.summary, result.changes, log);
244
+ }
245
+ else {
246
+ log(`Level "${result.summary.asset_name}" was already applied to world.json by an earlier run.`);
247
+ }
248
+ }
249
+ finally {
250
+ stopBakeProgress();
251
+ }
252
+ }
253
+ finally {
254
+ await host?.close().catch(() => {
255
+ // Closing a browser that already died is not a forge failure, and letting it mask the real
256
+ // error would be. The temp profile directory is under the OS temp dir either way.
257
+ });
258
+ server?.kill('SIGTERM');
259
+ await uploadProxy?.close().catch(() => {
260
+ // Same reasoning as the browser above: a proxy that is already down must not mask the real
261
+ // failure. It is a loopback listener in this process either way.
262
+ });
263
+ }
264
+ }
265
+ /**
266
+ * The whole command. Failure wording is the contract here — see the file header.
267
+ *
268
+ * - Anything before step 5's apply leaves world.json untouched, and says so.
269
+ * - A server-side failure additionally says whether resuming can help; see
270
+ * `classifyForgeFailure`, which is the difference between "try again" and "change your prompt".
271
+ * - A failure AFTER the design and geometry landed but before (or during) the local write is the
272
+ * expensive case: the forge has been billed, and the message says the work is saved under a job
273
+ * id rather than lost.
274
+ */
275
+ export async function runForge(args, deps = defaultDeps()) {
276
+ const prepared = await prepareForgeRequest(args, deps);
277
+ const { context, environment, storage, input, resumeJobId, token } = prepared;
278
+ deps.log(resumeJobId !== null
279
+ ? `Resuming forge job ${resumeJobId} for game ${context.metadata.gameId}.`
280
+ : `Forging a level for game ${context.metadata.gameId}: "${input.prompt}"`);
281
+ deps.log('[1-2/5] Designing the scene and forging its geometry (this runs on the server)…');
282
+ const outcome = await requestForge(environment, token, buildForgeRequestBody(input, resumeJobId), { fetch: deps.fetch, onProgress: (message) => deps.log(` ${message}`) });
283
+ if (!outcome.success) {
284
+ throw new CliError(describeForgeFailure(outcome));
285
+ }
286
+ const { jobId, artifact, platformerMovement } = outcome;
287
+ deps.log(`[1-2/5] Geometry forged (job ${jobId}).`);
288
+ // From here on the design and the geometry are PAID FOR and saved server-side. Every failure
289
+ // below must therefore point at the resume rather than at re-running from scratch.
290
+ await seedForgeStore(createForgedWorkStore(jobId, storage), artifact, input, platformerMovement);
291
+ try {
292
+ await runBrowserSteps({ context, environment, jobId, token, deps });
293
+ }
294
+ catch (error) {
295
+ throw decorateBrowserStepError(error, jobId);
296
+ }
297
+ }
298
+ async function prepareForgeRequest(args, deps) {
299
+ try {
300
+ const context = loadProjectContext(deps.startDir);
301
+ const mode = selectMode(args);
302
+ const resumeJobId = typeof args.resume === 'string' && args.resume.length > 0 ? args.resume : null;
303
+ if (resumeJobId !== null && !JOB_ID_PATTERN.test(resumeJobId)) {
304
+ throw new CliError('--resume takes a job id of 1-64 characters (letters, digits, "_" or "-") — the one printed '
305
+ + 'by the run you are resuming.');
306
+ }
307
+ const storage = createLocalForgeStorage(context.root);
308
+ const frozen = resumeJobId !== null ? await readFrozenInput(storage, resumeJobId) : null;
309
+ const input = resolveJobInput({
310
+ frozen,
311
+ prompt: args.prompt,
312
+ name: args.name,
313
+ mode,
314
+ gameId: context.metadata.gameId,
315
+ resumeJobId,
316
+ });
317
+ const environment = resolveEnvironment({ storedDefault: readDefaultEnvironment(deps.baseDir) });
318
+ const clientId = resolveAuth0ClientId(environment);
319
+ const token = await getAccessToken(environment, clientId, { fetch: deps.fetch, sleep: deps.sleep, now: deps.now }, deps.baseDir);
320
+ return { context, environment, storage, input, resumeJobId, token };
321
+ }
322
+ catch (error) {
323
+ // Only a CliError is decorated, exactly as `generate.ts` does: anything else is a genuine bug
324
+ // rather than a condition we designed a message for, and citty's stack trace is the right
325
+ // output for it. (The one plain-Error condition worth naming in this span — a `.bitmagic/`
326
+ // that cannot be created — raises a CliError of its own in `createLocalForgeStorage`.)
327
+ //
328
+ // Deliberately UNLIKE the steps 3-5 boundary below, which decorates every error class. The
329
+ // difference is what is at stake: nothing has been spent yet here, so a stack trace costs a
330
+ // creator only clarity, whereas after the forge is billed it costs them a second design.
331
+ throw error instanceof CliError
332
+ ? new CliError(`${error.message} world.json is unchanged.`, error.exitCode)
333
+ : error;
334
+ }
335
+ }
336
+ /**
337
+ * Decorate a steps 3-5 failure with the job id, REGARDLESS of its class.
338
+ *
339
+ * The class check `generate.ts` uses would be wrong here, and the difference is not stylistic:
340
+ * steps 3-5 come from `@bitmagic/world-forger` and throw plain `Error`/`ForgeStepError`, not
341
+ * `CliError` — the bake timeout (`voxelize-level.ts`), the placement timeout
342
+ * (`place-and-persist-level.ts`), a missing artifact (`artifact-store.ts`) and the archetype
343
+ * timeout (`create-level-archetypes.ts`) are all third-party classes. Passing those through
344
+ * untouched sends them past `withCleanErrors` into citty's raw stack dump, with no job id and no
345
+ * world.json statement — in the exact window where the design and geometry are already paid for.
346
+ * A creator seeing `Error: Level voxelization timed out` and a stack has no way to know that
347
+ * resuming is free, and will re-run with `--prompt` and pay for a second design.
348
+ *
349
+ * `generate.ts` gets away with the class check only because nothing in its span throws a
350
+ * third-party error class.
351
+ */
352
+ export function decorateBrowserStepError(error, jobId) {
353
+ const message = error instanceof Error ? error.message : String(error);
354
+ // Skip only when the message already carries the RESUME COMMAND (the dev-server failure prints
355
+ // its own), never merely the job id. The shared package puts the jobId in its own text —
356
+ // `artifact-store.ts` says `… missing for job <jobId> — cannot continue` — so a bare
357
+ // `includes(jobId)` check would silently drop the advice from exactly the third-party errors
358
+ // this function exists to decorate.
359
+ if (message.includes(resumeCommand(jobId)))
360
+ return error;
361
+ const exitCode = error instanceof CliError ? error.exitCode : 1;
362
+ return new CliError(`${message}\nThe scene design and geometry for this level are saved and already billed — `
363
+ + `resume from them with \`${resumeCommand(jobId)}\` rather than starting a new `
364
+ + 'forge. Nothing already completed will be re-run or re-billed.', exitCode);
365
+ }
366
+ export const forgeCommand = defineCommand({
367
+ meta: {
368
+ name: 'forge',
369
+ description: 'Design, build and install a whole playable level from a prompt.',
370
+ },
371
+ args: {
372
+ prompt: {
373
+ type: 'string',
374
+ description: 'Describe the level, e.g. "a ruined desert temple with a central courtyard".',
375
+ },
376
+ name: {
377
+ type: 'string',
378
+ description: 'Name for the level. Derived from the prompt when omitted.',
379
+ },
380
+ resume: {
381
+ type: 'string',
382
+ description: 'Resume a job id printed by an earlier run; completed steps are skipped.',
383
+ },
384
+ city: { type: 'boolean', description: 'Build a city (street grid, buildings, landmarks).' },
385
+ dungeon: { type: 'boolean', description: 'Build an enclosed dungeon of rooms and corridors.' },
386
+ platformer: { type: 'boolean', description: 'Build a third-person platformer journey.' },
387
+ freeform: { type: 'boolean', description: 'Build a custom place (arena, fortress, camp).' },
388
+ },
389
+ async run({ args }) {
390
+ await runForge(args);
391
+ },
392
+ });
393
+ //# sourceMappingURL=forge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forge.js","sourceRoot":"","sources":["../../src/commands/forge.ts"],"names":[],"mappings":"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"}