import type { ArgsDef, CommandDef } from 'citty'; import { type BeginCommandInput } from './telemetry/command-context.js'; import { type CommandReport } from './telemetry/report.js'; /** * What the wrapper needs from the outside world to report a command's outcome. The real ones * (below) mark the command as begun and send the beacon to api-server; tests pass stubs so a * wrapped command under test never touches `~/.bitmagic` or the network. */ export interface CommandRunDeps { begin: (input: BeginCommandInput) => void; report: (report: CommandReport) => Promise; /** Refresh the cached unread-messages count for the NEXT run (see messages/refresh.ts). */ refreshMessages: () => Promise; now: () => number; } /** * Wraps a command's `run` so that (a) a CliError becomes a clean single-line message and exit * code, and (b) EVERY run — success, refusal or crash — reports how it went to api-server, once, * with the command's name and duration (see telemetry/report.ts). Doing both here, over the * whole map, is what makes the reporting complete: there is no per-command call anyone can * forget, and the offline commands (`dev`, `build`, `check`, ...) are covered exactly like the * ones that talk to the server anyway. * * `name` is what the report calls the command — `publish`, `generate skybox` — as the creator * typed it. */ export declare function withCleanErrors(command: CommandDef, name?: string, deps?: CommandRunDeps): CommandDef; /** * Structural check for tests: has this command actually passed through `withCleanErrors`? A leaf * command (one with its own `run`) is wrapped when that `run` is in `wrappedRuns`. A grouping * command with no `run` of its own (see the doc comment above) is wrapped when it has at least * one subcommand and every one of them is — recursively, so nesting can go arbitrarily deep. */ export declare function isWrappedWithCleanErrors(command: CommandDef): boolean; declare const rawCommands: { login: CommandDef<{ readonly env: { readonly type: "string"; readonly description: "Environment to log in to (dev, prod, local)."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; logout: CommandDef<{ readonly env: { readonly type: "string"; readonly description: "Environment to log out of (dev, prod, local)."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; 'reset-account': CommandDef<{ readonly env: { readonly type: "string"; readonly description: "Environment to reset in (dev, local). Never prod."; }; readonly yes: { readonly type: "boolean"; readonly description: "Skip the confirmation. Required in a non-interactive shell."; }; readonly 'keep-cli': { readonly type: "boolean"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; whoami: CommandDef<{ readonly env: { readonly type: "string"; readonly description: "Environment to query (dev, prod, local)."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; subscribe: CommandDef<{ readonly env: { readonly type: "string"; readonly description: "Environment to subscribe in (dev, prod, local)."; }; readonly 'no-wait': { readonly type: "boolean"; readonly description: "Open the Bitmagic Pro page and exit instead of waiting for it to complete."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; usage: CommandDef<{ readonly days: { readonly type: "string"; readonly description: "How many days to report on (default 30, max 90)."; }; readonly env: { readonly type: "string"; readonly description: "Environment to query (dev, prod, local)."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; allowance: CommandDef<{ readonly 'allow-sparks': { readonly type: "boolean"; readonly description: "Let your purchased sparks fund work once the allowance runs out. Ask a human to run this."; }; readonly 'block-sparks': { readonly type: "boolean"; readonly description: "Stop purchased sparks funding work; the allowance alone pays."; }; readonly env: { readonly type: "string"; readonly description: "Environment to query (dev, prod, local)."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; init: CommandDef<{ readonly dir: { readonly type: "positional"; readonly required: false; readonly description: "Directory to create the project in."; }; readonly template: { readonly type: "string"; readonly description: "Template id (see templates in the engine bundle). Defaults to empty-3d, or to whatever --idea suggests."; }; readonly name: { readonly type: "string"; readonly description: "Game name."; }; readonly 'art-style': { readonly type: "string"; readonly description: string; }; readonly idea: { readonly type: "string"; readonly description: "One-line pitch. Seeds GAME-DESIGN.md and picks the template whose camera and controls fit it. Optional — you can write it yourself."; }; readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly env: { readonly type: "string"; readonly description: "Environment (dev, prod, local)."; }; readonly agent: { readonly type: "string"; readonly description: string; }; readonly force: { readonly type: "boolean"; readonly description: "Scaffold into a non-empty directory."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; import: CommandDef<{ readonly zip: { readonly type: "positional"; readonly required: true; readonly description: "The .zip downloaded from the Creator's \"Export game\" button."; }; readonly dir: { readonly type: "positional"; readonly required: false; readonly description: "Directory to create the project in. Defaults to ./."; }; readonly name: { readonly type: "string"; readonly description: "Project name for package.json. Defaults to the directory name."; }; readonly agent: { readonly type: "string"; readonly description: string; }; readonly 'new-game': { readonly type: "boolean"; readonly description: string; }; readonly 'no-rehost': { readonly type: "boolean"; readonly description: string; }; readonly env: { readonly type: "string"; readonly description: "Environment (dev, prod, local)."; }; readonly force: { readonly type: "boolean"; readonly description: "Import into a non-empty directory."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; promote: CommandDef<{ readonly project: { readonly type: "positional"; readonly required: true; readonly description: "The project to promote, e.g. ../dev-games/icy-boat-driver."; }; readonly dir: { readonly type: "positional"; readonly required: false; readonly description: "Where to create the promoted project. Defaults to ./."; }; readonly to: { readonly type: "string"; readonly description: "Environment to promote onto. Defaults to prod."; }; readonly from: { readonly type: "string"; readonly description: "Environment the project is really on, when its bitmagic.json does not pin one."; }; readonly name: { readonly type: "string"; readonly description: "Project name for package.json. Defaults to the directory name."; }; readonly 'no-rehost': { readonly type: "boolean"; readonly description: string; }; readonly force: { readonly type: "boolean"; readonly description: "Promote into a non-empty directory, or one marked for another environment."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; upgrade: CommandDef<{ readonly engine: { readonly type: "string"; readonly description: "Engine version to upgrade to (must be the currently published one)."; }; readonly force: { readonly type: "boolean"; readonly description: "Upgrade even with uncommitted changes in the working tree."; }; readonly agent: { readonly type: "string"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; 'self-update': CommandDef<{ readonly tag: { readonly type: "string"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; check: CommandDef<{ readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; dev: CommandDef<{ readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly port: { readonly type: "string"; readonly description: `Port to serve the game on (default ${number}, or ${number} on the dev line).`; }; readonly 'editor-port': { readonly type: "string"; readonly description: `Port to serve the Game/Editor view on (default ${number}, or ${number} on the dev line).`; }; readonly 'no-open': { readonly type: "boolean"; readonly description: "Do not open a browser. Same as setting BITMAGIC_NO_OPEN."; }; readonly mobile: { readonly type: "boolean"; readonly description: "Also serve the game to phones on this network, and print a QR code for it."; }; readonly 'mobile-http': { readonly type: "boolean"; readonly description: "Serve --mobile over http instead of a self-signed certificate (no WebGPU on the device)."; }; }>; reload: CommandDef<{ readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly port: { readonly type: "string"; readonly description: `Port the dev view is on. Defaults to the running server, then this project's own slot (${number} and up, ${number} and up on the dev line).`; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; verify: CommandDef<{ readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly timeout: { readonly type: "string"; readonly description: string; }; readonly renderer: { readonly type: "string"; readonly description: "Renderer to boot the game with: webgpu (default, what players run) or webgl."; }; readonly platform: { readonly type: "string"; readonly description: string; }; readonly fast: { readonly type: "boolean"; readonly description: string; }; readonly watch: { readonly type: "boolean"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; build: CommandDef<{ readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; readonly 'single-file': { readonly type: "boolean"; readonly description: string; }; }>; generate: CommandDef; character: CommandDef; assets: CommandDef; levels: CommandDef; theme: CommandDef; cover: CommandDef<{ readonly prompt: { readonly type: "string"; readonly description: "Describe the game for this call only, instead of reading GAME-DESIGN.md. Never written to the file."; }; readonly force: { readonly type: "boolean"; readonly description: "Generate a new cover even when the design has not changed since the last one."; }; readonly 'start-screen': { readonly type: "boolean"; readonly negativeDescription: "Leave hud.startScreen.imageUrl alone — still saves the cover and uses it as the publish thumbnail."; }; 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 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; trailer: CommandDef; reference: CommandDef; judge: CommandDef<{ readonly genre: { readonly type: "string"; readonly description: "Genre hint for the rubric: platformer, racing, shooter, combat, driving, tower-defense."; }; readonly platform: { readonly type: "string"; readonly description: string; }; readonly 'min-score': { readonly type: "string"; readonly description: "Fail (exit 4) when the overall score is below this 1-10 bar. Without it the judge informs and exits 0."; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; forge: 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."; }; }>; publish: CommandDef<{ readonly 'original-prompt': { readonly type: "string"; readonly description: string; }; readonly visibility: { readonly type: "string"; readonly description: string; }; readonly name: { readonly type: "string"; readonly description: "Override the published name for this publish only — never written to game.json."; }; readonly description: { readonly type: "string"; readonly description: "Override the published description for this publish only — never written to game.json."; }; readonly force: { readonly type: "boolean"; readonly description: "Publish despite a stale or failed verify. Does NOT bypass a missing verify record."; }; readonly 'skip-smoke': { readonly type: "boolean"; readonly description: "Skip the post-publish render check. The game still publishes; it is simply not confirmed to render."; }; readonly 'version-url': { readonly type: "boolean"; readonly description: string; }; readonly 'no-qr': { readonly type: "boolean"; readonly description: "Do not draw the published URL as a QR code. `BITMAGIC_NO_QR` does the same for every run."; }; readonly 'single-file': { readonly type: "boolean"; readonly description: string; }; readonly json: { readonly type: "boolean"; readonly description: "Print the result as JSON on stdout; all progress goes to stderr."; }; }>; ios: CommandDef; tools: CommandDef; }; type CommandName = keyof typeof rawCommands; export declare const subCommands: Record>; export declare const main: CommandDef; /** * The message for a command name this CLI does not have, or null when `rawArgs` names only * commands that exist (including when it names none at all — citty's own "No command specified" * still owns that). * * Walks the whole path rather than checking the first token, so `bitmagic generate nonsense --help` * is refused for the same reason `bitmagic nonsense --help` is. Stops as soon as it reaches a * command with no subcommands of its own: everything after that is positional arguments, and * `bitmagic promote ../dev-games/icy-boat-driver` must not be read as a subcommand named * `../dev-games/icy-boat-driver`. */ export declare function unknownCommandMessage(rawArgs: string[], root?: CommandDef): string | null; export {};