@bitmagic/cli 0.1.21 → 0.1.24

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 (56) hide show
  1. package/README.md +83 -20
  2. package/dist/cli.d.ts +10 -6
  3. package/dist/cli.js +2 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/dev.d.ts +5 -1
  6. package/dist/commands/dev.js +82 -13
  7. package/dist/commands/dev.js.map +1 -1
  8. package/dist/commands/generate.d.ts +20 -0
  9. package/dist/commands/generate.js +100 -2
  10. package/dist/commands/generate.js.map +1 -1
  11. package/dist/commands/reload.d.ts +10 -0
  12. package/dist/commands/reload.js +82 -0
  13. package/dist/commands/reload.js.map +1 -0
  14. package/dist/commands/upgrade.js +6 -0
  15. package/dist/commands/upgrade.js.map +1 -1
  16. package/dist/editor/journal.js +2 -2
  17. package/dist/editor/reload-bus.d.ts +38 -0
  18. package/dist/editor/reload-bus.js +66 -0
  19. package/dist/editor/reload-bus.js.map +1 -0
  20. package/dist/editor/server.d.ts +7 -0
  21. package/dist/editor/server.js +51 -9
  22. package/dist/editor/server.js.map +1 -1
  23. package/dist/editor/shell-page.d.ts +24 -5
  24. package/dist/editor/shell-page.js +295 -36
  25. package/dist/editor/shell-page.js.map +1 -1
  26. package/dist/editor/watch.d.ts +101 -0
  27. package/dist/editor/watch.js +228 -0
  28. package/dist/editor/watch.js.map +1 -0
  29. package/dist/generate/stream.d.ts +16 -3
  30. package/dist/generate/stream.js +22 -1
  31. package/dist/generate/stream.js.map +1 -1
  32. package/dist/generate/vehicle.d.ts +53 -0
  33. package/dist/generate/vehicle.js +227 -0
  34. package/dist/generate/vehicle.js.map +1 -0
  35. package/dist/local-port.d.ts +10 -0
  36. package/dist/local-port.js +23 -0
  37. package/dist/local-port.js.map +1 -1
  38. package/dist/project/dev-handle.d.ts +14 -0
  39. package/dist/project/dev-handle.js +53 -0
  40. package/dist/project/dev-handle.js.map +1 -0
  41. package/dist/scaffold/claude-settings.d.ts +41 -0
  42. package/dist/scaffold/claude-settings.js +98 -0
  43. package/dist/scaffold/claude-settings.js.map +1 -0
  44. package/dist/scaffold/project-files.js +36 -10
  45. package/dist/scaffold/project-files.js.map +1 -1
  46. package/dist/scaffold/project.js +5 -0
  47. package/dist/scaffold/project.js.map +1 -1
  48. package/dist/scaffold/upgrade-project.d.ts +6 -0
  49. package/dist/scaffold/upgrade-project.js +19 -1
  50. package/dist/scaffold/upgrade-project.js.map +1 -1
  51. package/dist/verify/browser.js +3 -1
  52. package/dist/verify/browser.js.map +1 -1
  53. package/package.json +1 -1
  54. package/dist/commands/edit.d.ts +0 -10
  55. package/dist/commands/edit.js +0 -148
  56. package/dist/commands/edit.js.map +0 -1
package/README.md CHANGED
@@ -20,7 +20,7 @@ bitmagic init my-game # scaffold a new project into ./my-game
20
20
  cd my-game
21
21
  bitmagic cover # generate cover art from GAME-DESIGN.md
22
22
  bitmagic check # typecheck against the vendored engine
23
- bitmagic dev # build, then serve with live rebuilds
23
+ bitmagic dev # build, then serve the game + editor, and leave it running
24
24
  bitmagic verify # boot the game in a real browser and report what broke
25
25
  bitmagic publish # verify-gate, build, and ship — private by default
26
26
  ```
@@ -34,13 +34,13 @@ bitmagic publish # verify-gate, build, and ship — private by defa
34
34
  | `bitmagic whoami [--env <env>]` | Show the identity the CLI is authenticated as. |
35
35
  | `bitmagic init [dir] [--template <id>] [--name <name>] [--idea "<pitch>"] [--env <env>] [--force]` | Scaffold a new project: mints a game, downloads the vendored engine, writes `AGENTS.md`, `GAME-DESIGN.md` and templates. `--idea` seeds the design doc's pitch. |
36
36
  | `bitmagic check` | Typecheck (`tsc --noEmit`) against the vendored engine. Fast; does not prove the game runs. |
37
- | `bitmagic dev [--port <port>]` | Build, then serve with `tsc --watch` + `vite`, default port 3010. |
38
- | `bitmagic edit [--port <port>] [--editor-port <port>]` | Everything `dev` does, plus a visual scene editor at `http://localhost:3011/`: click an object, drag the gizmo, and the new transform is written to `src/work/world.json`. See **Editing the scene visually** below. |
37
+ | `bitmagic dev [--port <port>] [--editor-port <port>]` | Build, then serve everything and keep it running: `tsc --watch`, `vite` on 3010, and a **Game / Editor** view on 3011 that reloads itself when the project changes. The one command to leave open. See **The dev view** below. |
38
+ | `bitmagic reload [--port <port>]` | Tell a running `bitmagic dev` to reload the browser now. For agents: run it when you finish a round of edits. Exits 0 and does nothing when no dev server is running. |
39
39
  | `bitmagic verify [--timeout <ms>]` | Build, boot the game in a headless browser, click the engine's Play button like a player would, and report what broke. A game without the button passes as long as gameplay starts by itself (auto-starting genres, custom start UIs); a run where gameplay never starts fails. `--timeout` is settle time in ms measured after gameplay starts, so the screenshot captures gameplay. Writes the artifacts the publish gate reads (see below). |
40
40
  | `bitmagic build` | Bundle the game into one self-contained `.bitmagic/build/index.html`. Rarely needs to be run by hand — `publish` builds automatically when the project changed. |
41
41
  | `bitmagic publish [--visibility public\|private] [--name <name>] [--description <desc>] [--force]` | Verify-gate, build if needed, and upload straight to GCS. **Private unless `--visibility public` is passed.** |
42
42
  | `bitmagic upgrade [--engine <version>] [--force]` | Refresh vendored platform files and the CLI's own skills to the currently published engine. Refuses a dirty git tree unless `--force`. |
43
- | `bitmagic generate <skybox\|sound\|image\|character\|animation\|prop> ...` | Generate one asset directly into `src/work/world.json`. Costs sparks. `prop` upgrades an existing placeholder asset in place — see below. |
43
+ | `bitmagic generate <skybox\|sound\|image\|character\|animation\|prop\|vehicle> ...` | Generate one asset directly into `src/work/world.json`. Costs sparks. `prop` upgrades an existing placeholder asset in place, `vehicle` adds a new drivable one — see below. |
44
44
  | `bitmagic cover [--prompt "..."] [--force] [--no-start-screen]` | Generate the game's cover art from `GAME-DESIGN.md`: sets the start screen, saves `.bitmagic/cover.webp`, becomes the publish thumbnail. Costs sparks. |
45
45
  | `bitmagic forge --prompt "..." [--city\|--dungeon\|--platformer\|--freeform] [--name <name>] [--resume <jobId>]` | Design and bake a whole playable level into `world.json`. Slow and expensive; supports `--resume`. |
46
46
 
@@ -60,10 +60,14 @@ my-game/
60
60
  engine/ # vendored engine, read-only, replaced wholesale by `bitmagic upgrade`
61
61
  AGENTS.md # guidance for the agent editing this project
62
62
  GAME-DESIGN.md # what the game is — yours to write; bitmagic cover reads it
63
+ .claude/
64
+ settings.json # yours; seeded with a Stop hook that runs `bitmagic reload`
65
+ skills/ # generating-assets is shipped by the CLI; your own are untouched
63
66
  .bitmagic/
64
67
  cover.webp # bitmagic cover's artwork — the publish thumbnail when present
65
68
  cover.json # its URL and the design hash it was generated from
66
69
  AGENTS.md.latest # the current AGENTS.md template, when upgrade kept your edited one
70
+ dev.json # the running `bitmagic dev`'s ports, so `bitmagic reload` finds it
67
71
  build/
68
72
  index.html # bitmagic build's output bundle
69
73
  manifest.json # engineVersion, fingerprint, bytes, sha256, builtAt
@@ -89,33 +93,59 @@ Re-running on an unchanged design generates nothing and costs nothing — it rep
89
93
  cover. Edit the design and run again, or pass `--force`, to replace it. Because it writes
90
94
  `world.json`, it invalidates a passing verify: run it before `bitmagic verify`, not after.
91
95
 
92
- ## Editing the scene visually
96
+ ## The dev view
93
97
 
94
- Some things are faster with a mouse. `bitmagic edit` runs everything `bitmagic dev` runs and adds a
95
- local editor on a second port:
98
+ `bitmagic dev` is meant to be started once and left running, beside your agent:
96
99
 
97
100
  ```bash
98
- bitmagic edit
99
- # Serving the game at http://localhost:3010/
100
- # Editor ready at http://localhost:3011/
101
+ bitmagic dev
102
+ # Open http://localhost:3011/ ← game + editor
103
+ #
104
+ # Game only http://localhost:3010/
105
+ # Editor actions .bitmagic/edit/events.jsonl
101
106
  ```
102
107
 
103
- Open the editor URL in your normal browser. The game loads paused, with a free-flying camera, the
104
- scene hierarchy and the transform gizmo the same editor the web Creator uses, which already ships
105
- inside `engine/`. Click an object to select it, then move, rotate, scale, snap it to the ground,
106
- edit its numbers in the inspector, delete it, or right-click to add one from the project's assets.
108
+ Open the 3011 URL in your normal browser and put it beside your agent's window. It is one page with
109
+ two tabs over the same running game, so switching costs nothing and does not restart anything:
107
110
 
108
- **Every change is saved to `src/work/world.json` as you make it.** There is no Save button and no
109
- unsaved state: your agent reads the same file, and `git diff` is the record of what you moved.
110
- Saves are surgical one entry per object touched, nothing else in the file is rewritten.
111
+ - **Game** your game, playing. Click into it to capture the mouse, exactly as a player would.
112
+ - **Editor** the same world, paused, with a free-flying camera, the scene hierarchy and the
113
+ transform gizmo. This is the editor the web Creator uses, which already ships inside `engine/`.
114
+ Click an object to select it, then move, rotate, scale, snap it to the ground, edit its numbers in
115
+ the inspector, delete it, or right-click to add one from the project's assets.
111
116
 
112
- If your agent edits `world.json` while the editor is open, the editor says so and offers a reload
113
- rather than silently reloading over work in progress.
117
+ 3010 still serves the game on its own, for a second window or a bookmark. Both ports must stay
118
+ inside 3000–3199: the asset CDN allowlists only those origins, and outside that window the world
119
+ loads with no terrain.
120
+
121
+ **Every change in the Editor tab is saved to `src/work/world.json` as you make it.** There is no
122
+ Save button and no unsaved state: your agent reads the same file, and `git diff` is the record of
123
+ what you moved. Saves are surgical — one entry per object touched, nothing else in the file is
124
+ rewritten.
125
+
126
+ ### Auto-reload
127
+
128
+ The browser reloads itself when the project changes, so you watch your agent's work appear instead
129
+ of reaching for F5. Three things drive it:
130
+
131
+ - **The file watcher.** `src/` and `dist/` are watched, and a reload fires once the writes go quiet.
132
+ - **The build gate.** A reload waits for `tsc --watch` to finish and land clean. If the build fails
133
+ the reload is dropped and the page says so — reloading would show you the previous build's code
134
+ running against your new source, which is the most confusing outcome available.
135
+ - **`bitmagic reload`.** The watcher has to guess when an agent is finished, because an agent pauses
136
+ to think. This command replaces the guess. `bitmagic init` wires it to Claude Code's `Stop` hook in
137
+ `.claude/settings.json`, so Claude fires it at the end of every turn; any other agent can run it
138
+ directly. `bitmagic upgrade` adds the hook to an existing project without touching anything else in
139
+ that file.
140
+
141
+ Turn it off with the **Auto-reload** checkbox in the top bar — the setting sticks, and you get the
142
+ old "changed on disk, click to reload" banner instead. It also falls back to the banner on its own
143
+ while you are mid-edit in the Editor tab, rather than reloading a drag away.
114
144
 
115
145
  ### What your agent sees
116
146
 
117
147
  Every editor action is appended to `.bitmagic/edit/events.jsonl`, one JSON object per line, and
118
- printed to the command's own output — so the agent that launched `bitmagic edit` can tell what you
148
+ printed to the command's own output — so the agent that launched `bitmagic dev` can tell what you
119
149
  did without inferring it from a diff:
120
150
 
121
151
  ```
@@ -151,6 +181,35 @@ engine's terrain tools, but saving them needs an asset upload this command does
151
181
  editor warns you as soon as you change a voxel and offers to discard it. Use the web Creator for
152
182
  terrain work.
153
183
 
184
+ ## Drivable vehicles
185
+
186
+ `bitmagic generate vehicle` designs a vehicle and registers it as a **new** asset — unlike
187
+ `generate prop`, which upgrades an existing placeholder in place. An AI designer authors the shape,
188
+ paint and wrap art (including generated side art like "a poodle mural on a grooming van"); a
189
+ parametric builder produces the model; the engine voxelizes it and derives its physics fitment.
190
+
191
+ ```bash
192
+ bitmagic generate vehicle --prompt "a rusty orange pickup with flame decals"
193
+ bitmagic generate vehicle --preset VAN # a standard vehicle: skips the designer, free
194
+ ```
195
+
196
+ Then spawn it from game code by name:
197
+
198
+ ```js
199
+ engine.getVehicleSpawner().spawnAndEnterFromAsset({ x: 0, z: 0 }, '<assetName>', playerController);
200
+ ```
201
+
202
+ Like `prop` it needs Chrome and a free port between 3000 and 3199 — only the engine can voxelize,
203
+ so the CLI drives its own headless browser. Headlights, taillights and emergency beacons are built
204
+ and lit automatically; there is no need to ask for them.
205
+
206
+ Costs sparks based on what the designer actually spends, so a retrying design costs more than a
207
+ clean one and `--preset` costs nothing. If it fails after the model exists, the error prints the
208
+ exact `--glb-url … --voxel-size …` command to retry the browser step without paying again.
209
+
210
+ If the finished asset reports that it will not drive, the project's vendored engine predates
211
+ vehicle-fitment derivation: run `bitmagic upgrade`, then regenerate.
212
+
154
213
  ## Publishing
155
214
 
156
215
  `bitmagic publish` is two gated steps in one command:
@@ -209,6 +268,10 @@ its own reviewable diff.
209
268
  What is yours and never touched: `src/`, `world.json`, `game.json`, `package.json`, `CLAUDE.md`,
210
269
  `GAME-DESIGN.md`, `.gitignore`, and any skill you wrote yourself.
211
270
 
271
+ `.claude/settings.json` is merged rather than rewritten — it is where your permissions and your own
272
+ hooks live. An upgrade adds the `bitmagic reload` Stop hook if it is missing and changes nothing
273
+ else; if it cannot parse the file it leaves it entirely alone and says so.
274
+
212
275
  `AGENTS.md` is the one conditional case, and it can never lose your work. The CLI records a hash of
213
276
  the `AGENTS.md` it writes. On a later upgrade:
214
277
 
package/dist/cli.d.ts CHANGED
@@ -92,17 +92,21 @@ declare const rawCommands: {
92
92
  dev: CommandDef<{
93
93
  readonly port: {
94
94
  readonly type: "string";
95
- readonly description: "Port to serve on (default 3010).";
95
+ readonly description: "Port to serve the game on (default 3010).";
96
+ };
97
+ readonly 'editor-port': {
98
+ readonly type: "string";
99
+ readonly description: "Port to serve the Game/Editor view on (default 3011).";
96
100
  };
97
101
  }>;
98
- edit: CommandDef<{
102
+ reload: CommandDef<{
99
103
  readonly port: {
100
104
  readonly type: "string";
101
- readonly description: "Port to serve the game on (default 3010).";
105
+ readonly description: "Port the dev view is on. Defaults to the running server, then 3011.";
102
106
  };
103
- readonly 'editor-port': {
104
- readonly type: "string";
105
- readonly description: "Port to serve the editor on (default 3011).";
107
+ readonly json: {
108
+ readonly type: "boolean";
109
+ readonly description: "Print the result as JSON on stdout; all progress goes to stderr.";
106
110
  };
107
111
  }>;
108
112
  verify: CommandDef<{
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import { initCommand } from './commands/init.js';
8
8
  import { upgradeCommand } from './commands/upgrade.js';
9
9
  import { checkCommand } from './commands/check.js';
10
10
  import { devCommand } from './commands/dev.js';
11
- import { editCommand } from './commands/edit.js';
11
+ import { reloadCommand } from './commands/reload.js';
12
12
  import { verifyCommand } from './commands/verify.js';
13
13
  import { buildCommand } from './commands/build.js';
14
14
  import { generateCommand } from './commands/generate.js';
@@ -103,7 +103,7 @@ const rawCommands = {
103
103
  upgrade: upgradeCommand,
104
104
  check: checkCommand,
105
105
  dev: devCommand,
106
- edit: editCommand,
106
+ reload: reloadCommand,
107
107
  verify: verifyCommand,
108
108
  build: buildCommand,
109
109
  generate: generateCommand,
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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"}
@@ -1,6 +1,10 @@
1
1
  export declare const devCommand: import("citty").CommandDef<{
2
2
  readonly port: {
3
3
  readonly type: "string";
4
- readonly description: "Port to serve on (default 3010).";
4
+ readonly description: "Port to serve the game on (default 3010).";
5
+ };
6
+ readonly 'editor-port': {
7
+ readonly type: "string";
8
+ readonly description: "Port to serve the Game/Editor view on (default 3011).";
5
9
  };
6
10
  }>;
@@ -1,7 +1,29 @@
1
+ /**
2
+ * `bitmagic dev` — the whole local loop, in one command that stays running.
3
+ *
4
+ * It builds, watches, serves the game, serves a shell page with a **Game** tab and an **Editor**
5
+ * tab, and reloads the browser when the project changes. There is deliberately no second command:
6
+ * the workflow this exists for is an agent window beside a browser window, and a creator should
7
+ * never have to stop one server and start another to go from playing their game to nudging an
8
+ * object in it. (`bitmagic edit` was that second command, and folding it in is why it is gone.)
9
+ *
10
+ * Four processes make that up, all owned here:
11
+ * tsc --watch piped, not inherited — its `Found N errors` line is the only signal that tells
12
+ * auto-reload whether the emit in dist/ is worth showing (see editor/watch.ts)
13
+ * vite serves the project at --port
14
+ * the sidecar serves the shell and the scene-save API at --editor-port (see editor/server.ts)
15
+ * the watcher src/ and dist/, debounced, feeding the same coordinator as tsc
16
+ */
1
17
  import { defineCommand } from 'citty';
2
18
  import { spawn, spawnSync } from 'child_process';
19
+ import * as path from 'path';
3
20
  import { CliError } from '../errors.js';
4
21
  import { loadProjectContext, projectBin } from '../project/context.js';
22
+ import { removeDevHandle, writeDevHandle } from '../project/dev-handle.js';
23
+ import { startEditorServer } from '../editor/server.js';
24
+ import { ReloadBus } from '../editor/reload-bus.js';
25
+ import { ReloadCoordinator, pipeTscWatch, watchProject } from '../editor/watch.js';
26
+ import { parseLocalPort } from '../local-port.js';
5
27
  import { waitForServer } from '../verify/wait-for-server.js';
6
28
  import { engineUpdateNotice } from '../project/engine-update.js';
7
29
  /**
@@ -34,17 +56,29 @@ async function notifyIfEngineOutdated(projectEngineVersion, log) {
34
56
  // See above: no login, no network, or no manifest all mean "no hint", never "dev failed".
35
57
  }
36
58
  }
37
- const DEFAULT_PORT = 3010;
59
+ const DEFAULT_GAME_PORT = 3010;
60
+ const DEFAULT_EDITOR_PORT = 3011;
38
61
  export const devCommand = defineCommand({
39
- meta: { name: 'dev', description: 'Build the game, then serve it with live rebuilds.' },
62
+ meta: {
63
+ name: 'dev',
64
+ description: 'Build the game, then serve it with live rebuilds, a scene editor and auto-reload.',
65
+ },
40
66
  args: {
41
- port: { type: 'string', description: `Port to serve on (default ${DEFAULT_PORT}).` },
67
+ port: { type: 'string', description: `Port to serve the game on (default ${DEFAULT_GAME_PORT}).` },
68
+ 'editor-port': {
69
+ type: 'string',
70
+ description: `Port to serve the Game/Editor view on (default ${DEFAULT_EDITOR_PORT}).`,
71
+ },
42
72
  },
43
73
  async run({ args }) {
44
74
  const context = loadProjectContext();
45
75
  const tsc = projectBin(context.root, 'tsc');
46
76
  const vite = projectBin(context.root, 'vite');
47
- const port = args.port ?? String(DEFAULT_PORT);
77
+ const gamePort = parseLocalPort(args.port, DEFAULT_GAME_PORT, '--port');
78
+ const editorPort = parseLocalPort(args['editor-port'], DEFAULT_EDITOR_PORT, '--editor-port');
79
+ if (gamePort === editorPort) {
80
+ throw new CliError('`--port` and `--editor-port` must differ — the game and the shell are two servers.');
81
+ }
48
82
  // Build to completion first. Every alias resolves into dist/, so serving before the first
49
83
  // emit 404s every module — a failure that reads as "the engine is broken", not "not built".
50
84
  console.log('Building…');
@@ -57,16 +91,33 @@ export const devCommand = defineCommand({
57
91
  }
58
92
  // Fire and forget: the nudge must never gate or delay the server coming up.
59
93
  void notifyIfEngineOutdated(context.metadata.engineVersion, (m) => console.log(m));
94
+ // Bus first, then the coordinator that feeds it, then the servers that feed the coordinator.
95
+ const bus = new ReloadBus();
96
+ const coordinator = new ReloadCoordinator({
97
+ onReload: (reason) => bus.reload(reason),
98
+ onBuild: (status, message) => bus.build(status, message),
99
+ });
100
+ // Before the children, so a port clash fails fast rather than after vite has claimed its port.
101
+ const editor = await startEditorServer({
102
+ root: context.root,
103
+ metadata: context.metadata,
104
+ gameId: context.metadata.gameId,
105
+ gamePort,
106
+ port: editorPort,
107
+ bus,
108
+ coordinator,
109
+ log: (message) => console.log(message),
110
+ });
60
111
  const children = [
61
- {
62
- name: 'tsc --watch',
63
- process: spawn(tsc, ['--watch', '--preserveWatchOutput'], { cwd: context.root, stdio: 'inherit' }),
64
- },
112
+ // Piped rather than inherited — see the file header and editor/watch.ts.
113
+ { name: 'tsc --watch', process: pipeTscWatch(tsc, context.root, coordinator) },
65
114
  {
66
115
  name: 'vite',
67
- process: spawn(vite, ['--port', port, '--strictPort'], { cwd: context.root, stdio: 'inherit' }),
116
+ process: spawn(vite, ['--port', String(gamePort), '--strictPort'], { cwd: context.root, stdio: 'inherit' }),
68
117
  },
69
118
  ];
119
+ const watcher = watchProject(context.root, coordinator, (m) => console.log(m));
120
+ writeDevHandle(context.root, { editorPort, gamePort, pid: process.pid });
70
121
  let shuttingDown = false;
71
122
  let requestedByUser = false;
72
123
  const shutdown = () => {
@@ -75,6 +126,11 @@ export const devCommand = defineCommand({
75
126
  shuttingDown = true;
76
127
  for (const child of children)
77
128
  child.process.kill('SIGTERM');
129
+ coordinator.stop();
130
+ watcher.close();
131
+ bus.close();
132
+ removeDevHandle(context.root);
133
+ void editor.close();
78
134
  };
79
135
  process.on('SIGINT', () => {
80
136
  requestedByUser = true;
@@ -84,10 +140,20 @@ export const devCommand = defineCommand({
84
140
  requestedByUser = true;
85
141
  shutdown();
86
142
  });
87
- // Print the URL ourselves once vite actually answers, rather than relying on vite's own
88
- // startup banner — that output is vite's to change, this is ours to keep stable.
89
- void waitForServer(Number(port), 30_000)
90
- .then(() => console.log(`\nServing at http://localhost:${port}/`))
143
+ // Print the URLs ourselves once vite actually answers, rather than relying on vite's own
144
+ // startup banner — that output is vite's to change, this is ours to keep stable. The shell URL
145
+ // leads because it is the one thing to open: the raw game below it is the same game without
146
+ // the tabs, kept addressable for a second window or a bookmark.
147
+ void waitForServer(gamePort, 30_000)
148
+ .then(() => {
149
+ console.log(`\n Open ${editor.url} ← game + editor`);
150
+ console.log(`\n Game only http://localhost:${gamePort}/`);
151
+ // Named on startup so the agent that launched this command knows where to look without
152
+ // being told — the journal is the only record of intentions the editor cannot carry out
153
+ // itself, and of who changed what.
154
+ console.log(` Editor actions ${path.relative(context.root, editor.journalPath)}`);
155
+ console.log('\nThe browser reloads itself when the project changes. `bitmagic reload` forces it.\n');
156
+ })
91
157
  .catch(() => {
92
158
  // The child-exit watcher below reports a vite that never comes up; this poll simply has
93
159
  // nothing to announce in that case.
@@ -114,6 +180,9 @@ export const devCommand = defineCommand({
114
180
  });
115
181
  }
116
182
  });
183
+ // Both children are gone by here — via a signal handler or via the failure path above, each of
184
+ // which has already run shutdown(). This awaits the close that shutdown() could only start.
185
+ await editor.close();
117
186
  if (failure) {
118
187
  throw new CliError(`${failure.name} ${failure.detail}. \`bitmagic dev\` stopped.`);
119
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { type GenerationOutcome } from '../generate/stream.js';
2
2
  import { type PropVoxelizeResult } from '../generate/prop.js';
3
+ import { type VehicleInstallResult } from '../generate/vehicle.js';
3
4
  export interface SkyboxArgs {
4
5
  description: string;
5
6
  referenceImageUrl?: string;
@@ -84,4 +85,23 @@ export declare function runPropGeneration(options: {
84
85
  json: boolean;
85
86
  deps?: GenerateRunDeps;
86
87
  }): Promise<PropVoxelizeResult>;
88
+ /**
89
+ * `generate vehicle`, like `generate prop`, cannot go through {@link runAssetGeneration}: the
90
+ * generator returns a GLB rather than patches, so there is nothing to apply until the CLI has
91
+ * voxelized it in a browser.
92
+ *
93
+ * Unlike prop there is nothing to validate up front — a vehicle creates a NEW asset, so there is no
94
+ * existing one to look up. The one thing that would waste a paid design is asking for neither a
95
+ * prompt nor a preset, which is refused here before anything is spent.
96
+ */
97
+ export declare function runVehicleGeneration(options: {
98
+ prompt?: string;
99
+ presetName?: string;
100
+ name?: string;
101
+ /** Skip the paid design and voxelize this GLB instead — how a failed run is retried. */
102
+ glbUrl?: string;
103
+ minVoxelSize?: number;
104
+ json: boolean;
105
+ deps?: GenerateRunDeps;
106
+ }): Promise<VehicleInstallResult>;
87
107
  export declare const generateCommand: import("citty").CommandDef<import("citty").ArgsDef>;
@@ -10,6 +10,7 @@ import { getAccessToken } from '../auth/session.js';
10
10
  import { requestGeneration } from '../generate/stream.js';
11
11
  import { applyPatchesToWorld } from '../generate/apply-patches.js';
12
12
  import { generateAndInstallProp } from '../generate/prop.js';
13
+ import { generateAndInstallVehicle } from '../generate/vehicle.js';
13
14
  function parseNumberFlag(flagName, raw, options = {}) {
14
15
  if (raw === undefined)
15
16
  return undefined;
@@ -181,7 +182,7 @@ export async function runAssetGeneration(type, label, body, json = false, deps)
181
182
  }
182
183
  runDeps.log(`world.json updated (${applyResult.applied} patch${applyResult.applied === 1 ? '' : 'es'}).`);
183
184
  output.result({ ok: true, kind: label, message: outcome.message, patchesApplied: applyResult.applied });
184
- runDeps.log('If `bitmagic dev` is running, reload the browser tab to see the change.');
185
+ runDeps.log('A running `bitmagic dev` reloads the browser by itself to show the change.');
185
186
  return outcome;
186
187
  }
187
188
  /**
@@ -217,7 +218,60 @@ export async function runPropGeneration(options) {
217
218
  // `result` already carries glbUrl, so a retry after a later failure can find the paid-for mesh
218
219
  // in the JSON document rather than only in the error text.
219
220
  output.result({ ok: true, kind: 'prop', ...result });
220
- runDeps.log('If `bitmagic edit` or `bitmagic dev` is running, reload the browser tab to see it.');
221
+ runDeps.log('A running `bitmagic dev` reloads the browser by itself to show it.');
222
+ return result;
223
+ }
224
+ /**
225
+ * `generate vehicle`, like `generate prop`, cannot go through {@link runAssetGeneration}: the
226
+ * generator returns a GLB rather than patches, so there is nothing to apply until the CLI has
227
+ * voxelized it in a browser.
228
+ *
229
+ * Unlike prop there is nothing to validate up front — a vehicle creates a NEW asset, so there is no
230
+ * existing one to look up. The one thing that would waste a paid design is asking for neither a
231
+ * prompt nor a preset, which is refused here before anything is spent.
232
+ */
233
+ export async function runVehicleGeneration(options) {
234
+ if (options.prompt === undefined && options.presetName === undefined && options.glbUrl === undefined) {
235
+ throw new CliError('Provide --prompt to design a vehicle, or --preset to build a standard one. '
236
+ + 'Run `bitmagic generate vehicle --preset ?` to see the preset names.');
237
+ }
238
+ const output = createOutput(options.json);
239
+ const runDeps = options.deps ?? defaultDeps(options.json);
240
+ const context = loadProjectContext(runDeps.startDir);
241
+ const environment = resolveEnvironment({ storedDefault: readDefaultEnvironment(runDeps.baseDir) });
242
+ const token = await getAccessToken(environment, resolveAuth0ClientId(environment), { fetch: runDeps.fetch, sleep: runDeps.sleep, now: runDeps.now }, runDeps.baseDir);
243
+ let result;
244
+ try {
245
+ result = await generateAndInstallVehicle({
246
+ context,
247
+ environment,
248
+ token,
249
+ ...(options.prompt !== undefined ? { prompt: options.prompt } : {}),
250
+ ...(options.presetName !== undefined ? { presetName: options.presetName } : {}),
251
+ ...(options.name !== undefined ? { name: options.name } : {}),
252
+ ...(options.glbUrl !== undefined ? { glbUrl: options.glbUrl } : {}),
253
+ ...(options.minVoxelSize !== undefined ? { minVoxelSize: options.minVoxelSize } : {}),
254
+ fetchImpl: runDeps.fetch,
255
+ log: runDeps.log,
256
+ });
257
+ }
258
+ catch (error) {
259
+ throw decoratedError(error, (message) => message);
260
+ }
261
+ for (const note of result.notes)
262
+ runDeps.log(`note: ${note}`);
263
+ if (result.drivable) {
264
+ runDeps.log(`Added "${result.assetName}". Spawn it from game code with:\n`
265
+ + ` engine.getVehicleSpawner().spawnAndEnterFromAsset({ x: 0, z: 0 }, `
266
+ + `'${result.assetName}', playerController);`);
267
+ }
268
+ else {
269
+ runDeps.log(`Added "${result.assetName}", but it will not drive — see the note above.`);
270
+ }
271
+ // `result` already carries glbUrl, so a retry after a later failure can find the paid-for vehicle
272
+ // in the JSON document rather than only in the error text.
273
+ output.result({ ok: true, kind: 'vehicle', ...result });
274
+ runDeps.log('A running `bitmagic dev` reloads the browser by itself to show it.');
221
275
  return result;
222
276
  }
223
277
  // ============================================================================
@@ -455,6 +509,49 @@ const propCommand = defineCommand({
455
509
  });
456
510
  },
457
511
  });
512
+ const vehicleCommand = defineCommand({
513
+ meta: {
514
+ name: 'vehicle',
515
+ description: 'Design a drivable vehicle and register it as a new asset.',
516
+ },
517
+ args: {
518
+ prompt: {
519
+ type: 'string',
520
+ description: 'What to design ("a rusty orange pickup with flame decals"). Required unless --preset is given.',
521
+ },
522
+ preset: {
523
+ type: 'string',
524
+ description: 'Build a standard vehicle instead of designing one — faster and free. Run without it to see the valid names.',
525
+ },
526
+ name: {
527
+ type: 'string',
528
+ description: 'Asset name override; defaults to the designed name. This is the name game code spawns by.',
529
+ },
530
+ 'glb-url': {
531
+ type: 'string',
532
+ description: 'Voxelize this existing vehicle instead of designing one — how to retry for free. Needs --voxel-size and --name.',
533
+ },
534
+ 'voxel-size': {
535
+ type: 'string',
536
+ description: 'Bake resolution, only with --glb-url. The failed run prints the exact value to use.',
537
+ },
538
+ json: {
539
+ type: 'boolean',
540
+ description: 'Print the result as JSON on stdout; all progress goes to stderr.',
541
+ },
542
+ },
543
+ async run({ args }) {
544
+ const minVoxelSize = parseNumberFlag('voxel-size', args['voxel-size'], { min: 0.01, max: 1 });
545
+ await runVehicleGeneration({
546
+ ...(args.prompt ? { prompt: args.prompt } : {}),
547
+ ...(args.preset ? { presetName: args.preset } : {}),
548
+ ...(args.name ? { name: args.name } : {}),
549
+ ...(args['glb-url'] ? { glbUrl: args['glb-url'] } : {}),
550
+ ...(minVoxelSize !== undefined ? { minVoxelSize } : {}),
551
+ json: args.json === true,
552
+ });
553
+ },
554
+ });
458
555
  export const generateCommand = defineCommand({
459
556
  meta: {
460
557
  name: 'generate',
@@ -467,6 +564,7 @@ export const generateCommand = defineCommand({
467
564
  character: characterCommand,
468
565
  animation: animationCommand,
469
566
  prop: propCommand,
567
+ vehicle: vehicleCommand,
470
568
  },
471
569
  });
472
570
  //# sourceMappingURL=generate.js.map