import { type CatalogEntry, type ForgeJobInput } from '@bitmagic/world-forger/pipeline/index.js'; import { type CommandRunDeps } from './run-deps.js'; /** The five scene approaches the forger supports. Exactly one may be chosen; none = terrain. */ declare const MODE_FLAGS: readonly ["city", "dungeon", "platformer", "freeform", "vessel"]; type ModeFlag = (typeof MODE_FLAGS)[number]; /** * The level's name. Always sent EXPLICITLY to the server, even when derived: api-server's * `resolveLevelName` falls back to its own derivation from the prompt when `name` is absent, and * this lane also freezes an `input` artifact locally (see `seedForgeStore`). Two independent * derivations of the same name would be a drift waiting to happen, so the CLI decides once and * the server receives the answer rather than recomputing it. */ export declare function deriveLevelName(explicit: string | undefined, prompt: string): string; /** * `--edit` changes a level as it was designed, so it takes none of a fresh forge's steering: no * prompt, no scene type, no reference image, no revision rounds, no start-level switch, and no * resume (a resumed edit replays its frozen request, which `--edit` would contradict). Refused * before any request, where it is still free. */ export declare function assertEditFlags(args: Record): void; /** The single selected mode, or undefined for plain terrain. */ export declare function selectMode(args: Record): ModeFlag | undefined; /** * Resolve the frozen request for this run. * * On a fresh run it comes from the flags. On a resume it comes from the job's LOCAL frozen * `input` artifact where one exists, so the resumed request re-sends exactly what the original * sent — which also lets `--resume` stand alone, without repeating the prompt. api-server freezes * its own copy and never overwrites it, so a resume that did send different flags would produce a * level whose geometry came from the original design but whose name and prompt came from the new * invocation. Reading the frozen copy back removes that divergence rather than documenting it. */ export declare function resolveJobInput(options: { frozen: ForgeJobInput | null; prompt: string | undefined; name: string | undefined; mode: ModeFlag | undefined; gameId: string; resumeJobId: string | null; makeStartLevel: boolean; /** The already-resolved reference image (flag > --no-reference > accepted), if any. */ referenceImageUrl?: string; /** `--match-rounds`, already parsed; omitted = the server's default (2 with a reference). */ referenceMatchRounds?: number; /** The project collides on the engine's ground plane (top-down 2D physics) — forge FLAT terrain. */ groundPlane?: boolean; }): ForgeJobInput; /** * The request body for `POST /api/cli/v1/forge/stream`. * * `assetCatalog` is what lets the designer REUSE what the game already owns — HQ-regenerated * landmarks, the creator's imports — instead of minting a fresh placeholder for it. The web lane * builds it from its work copy of world.json; api-server has no world.json, so this lane sent * nothing and every forge started from scratch. The CLI has the project's file and the same * `buildAssetCatalog` the web lane uses, so it builds the compact catalog and sends that rather * than the raw assets[]. * * An empty catalog is OMITTED rather than sent: the seam's contract is that an absent catalog * means "no reuse", and an empty array would instead assert the game owns nothing placeable. */ export declare function buildForgeRequestBody(input: ForgeJobInput, resumeJobId: string | null, assetCatalog?: CatalogEntry[]): Record; export interface ForgeRunDeps extends CommandRunDeps { } /** * The whole command. Failure wording is the contract here — see the file header. * * - Anything before step 5's apply leaves world.json untouched, and says so. * - A server-side failure additionally says whether resuming can help; see * `classifyForgeFailure`, which is the difference between "try again" and "change your prompt". * - A failure AFTER the design and geometry landed but before (or during) the local write is the * expensive case: the forge has been billed, and the message says the work is saved under a job * id rather than lost. */ export declare function runForge(args: { prompt?: string; name?: string; resume?: string; } & Record, deps?: ForgeRunDeps): Promise; /** * Decorate a steps 3-5 failure with the job id, REGARDLESS of its class. * * The class check `generate.ts` uses would be wrong here, and the difference is not stylistic: * steps 3-5 come from `@bitmagic/world-forger` and throw plain `Error`/`ForgeStepError`, not * `CliError` — the bake timeout (`voxelize-level.ts`), the placement timeout * (`place-and-persist-level.ts`), a missing artifact (`artifact-store.ts`) and the abort when * every archetype bake failed (`create-level-archetypes.ts`) are all third-party classes. Passing * those through untouched sends them past `withCleanErrors` into citty's raw stack dump, with no * job id and no world.json statement — in the exact window where the design and geometry are * already paid for. * A creator seeing `Error: Level voxelization timed out` and a stack has no way to know that * resuming is free, and will re-run with `--prompt` and pay for a second design. * * `generate.ts` gets away with the class check only because nothing in its span throws a * third-party error class. */ export declare function decorateBrowserStepError(error: unknown, jobId: string): unknown; export declare const forgeCommand: import("citty").CommandDef<{ readonly prompt: { readonly type: "string"; readonly description: "Describe the level, e.g. \"a ruined desert temple with a central courtyard\"."; }; readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly name: { readonly type: "string"; readonly description: "Name for the level. Derived from the prompt when omitted."; }; readonly resume: { readonly type: "string"; readonly description: "Resume a job id printed by an earlier run; completed steps are skipped."; }; readonly 'reference-image-url': { readonly type: "string"; readonly description: "Style/composition reference image URL forwarded to the image model. Overrides the accepted project reference for this call."; }; readonly 'reference-image': { readonly type: "string"; readonly description: "A local image file (PNG/JPEG/WebP) to use as the reference for this call — uploaded to the game's storage first. Overrides the accepted project reference."; }; readonly reference: { readonly type: "boolean"; readonly negativeDescription: "Do not apply the accepted project reference image (`bitmagic reference`) to this call."; }; readonly 'match-rounds': { readonly type: "string"; readonly description: "With a reference image: revision rounds the designer spends iterating the level toward it (0-3, default 2). Each round renders the design, has a vision critic compare it with the picture and revises; 0 designs once and skips the comparison."; }; readonly city: { readonly type: "boolean"; readonly description: "Build a city (street grid, buildings, landmarks)."; }; readonly dungeon: { readonly type: "boolean"; readonly description: "Build an enclosed dungeon of rooms and corridors."; }; readonly platformer: { readonly type: "boolean"; readonly description: "Build a third-person platformer journey."; }; readonly freeform: { readonly type: "boolean"; readonly description: "Build a custom place (arena, fortress, camp)."; }; readonly vessel: { readonly type: "boolean"; readonly description: "Build a ship as the level (longship, galleon, space barge deck, or the rooms inside a spaceship)."; }; readonly 'make-start': { readonly type: "boolean"; readonly description: "Boot the game into this level. Without it, only a game's FIRST forge becomes the start level, so a later forge lands in the level list unseen."; }; readonly edit: { readonly type: "string"; readonly description: "Change a detail of a level this project forged (\"make the doors sliding bulkheads\", \"warm amber lanterns instead of the lamps\") without re-forging it: the stored design is patched and only what the change touches is re-made. Replaces the level in place. Takes --level; no other forge flag."; }; readonly level: { readonly type: "string"; readonly description: "With --edit: the level to change, by id or name (`bitmagic levels list`). Omit when the project has one forged level."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; export {};