@bitmagic/cli 0.1.53-dev.0 → 0.1.53-dev.10

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 (103) hide show
  1. package/README.md +130 -29
  2. package/dist/assets/revoxelize.d.ts +116 -0
  3. package/dist/assets/revoxelize.js +343 -0
  4. package/dist/assets/revoxelize.js.map +1 -0
  5. package/dist/cli.d.ts +27 -1
  6. package/dist/cli.js +18 -1
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/assets.d.ts +18 -0
  9. package/dist/commands/assets.js +110 -1
  10. package/dist/commands/assets.js.map +1 -1
  11. package/dist/commands/cover.d.ts +5 -0
  12. package/dist/commands/cover.js +3 -0
  13. package/dist/commands/cover.js.map +1 -1
  14. package/dist/commands/dev.js +1 -2
  15. package/dist/commands/dev.js.map +1 -1
  16. package/dist/commands/forge.d.ts +4 -0
  17. package/dist/commands/forge.js +9 -0
  18. package/dist/commands/forge.js.map +1 -1
  19. package/dist/commands/generate.d.ts +25 -0
  20. package/dist/commands/generate.js +80 -8
  21. package/dist/commands/generate.js.map +1 -1
  22. package/dist/commands/init.d.ts +4 -0
  23. package/dist/commands/init.js +12 -1
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/publish.d.ts +31 -4
  26. package/dist/commands/publish.js +86 -15
  27. package/dist/commands/publish.js.map +1 -1
  28. package/dist/commands/reload.js +1 -3
  29. package/dist/commands/reload.js.map +1 -1
  30. package/dist/commands/reset-account.js +25 -8
  31. package/dist/commands/reset-account.js.map +1 -1
  32. package/dist/commands/self-update.d.ts +67 -0
  33. package/dist/commands/self-update.js +196 -0
  34. package/dist/commands/self-update.js.map +1 -0
  35. package/dist/commands/upgrade.js +5 -2
  36. package/dist/commands/upgrade.js.map +1 -1
  37. package/dist/editor/asset-detail-panel.d.ts +2 -2
  38. package/dist/editor/asset-detail-panel.js +5 -2
  39. package/dist/editor/asset-detail-panel.js.map +1 -1
  40. package/dist/editor/cli-update.d.ts +32 -0
  41. package/dist/editor/cli-update.js +67 -0
  42. package/dist/editor/cli-update.js.map +1 -0
  43. package/dist/editor/publish-panel.d.ts +31 -0
  44. package/dist/editor/publish-panel.js +69 -0
  45. package/dist/editor/publish-panel.js.map +1 -0
  46. package/dist/editor/server.js +43 -1
  47. package/dist/editor/server.js.map +1 -1
  48. package/dist/editor/shell-page.js +249 -8
  49. package/dist/editor/shell-page.js.map +1 -1
  50. package/dist/forge/upload-proxy.d.ts +14 -0
  51. package/dist/forge/upload-proxy.js +28 -1
  52. package/dist/forge/upload-proxy.js.map +1 -1
  53. package/dist/generate/model.d.ts +7 -0
  54. package/dist/generate/model.js +13 -3
  55. package/dist/generate/model.js.map +1 -1
  56. package/dist/generate/prop.d.ts +20 -0
  57. package/dist/generate/prop.js +22 -2
  58. package/dist/generate/prop.js.map +1 -1
  59. package/dist/generate/vehicle.d.ts +2 -0
  60. package/dist/generate/vehicle.js +1 -0
  61. package/dist/generate/vehicle.js.map +1 -1
  62. package/dist/project/dev-handle.d.ts +28 -0
  63. package/dist/project/dev-handle.js +43 -0
  64. package/dist/project/dev-handle.js.map +1 -1
  65. package/dist/project/jobs.js +11 -9
  66. package/dist/project/jobs.js.map +1 -1
  67. package/dist/publish/client.d.ts +13 -2
  68. package/dist/publish/client.js.map +1 -1
  69. package/dist/publish/record.d.ts +22 -0
  70. package/dist/publish/record.js +62 -0
  71. package/dist/publish/record.js.map +1 -0
  72. package/dist/render/qr-output.d.ts +44 -0
  73. package/dist/render/qr-output.js +71 -0
  74. package/dist/render/qr-output.js.map +1 -0
  75. package/dist/render/qr-png.d.ts +37 -0
  76. package/dist/render/qr-png.js +111 -0
  77. package/dist/render/qr-png.js.map +1 -0
  78. package/dist/render/qr-terminal.d.ts +63 -0
  79. package/dist/render/qr-terminal.js +142 -0
  80. package/dist/render/qr-terminal.js.map +1 -0
  81. package/dist/render/qr.d.ts +51 -0
  82. package/dist/render/qr.js +516 -0
  83. package/dist/render/qr.js.map +1 -0
  84. package/dist/scaffold/project-files.js +44 -27
  85. package/dist/scaffold/project-files.js.map +1 -1
  86. package/dist/scaffold/suggest-template.d.ts +2 -0
  87. package/dist/scaffold/suggest-template.js +2 -1
  88. package/dist/scaffold/suggest-template.js.map +1 -1
  89. package/dist/telemetry/command-context.d.ts +12 -0
  90. package/dist/telemetry/command-context.js +7 -0
  91. package/dist/telemetry/command-context.js.map +1 -1
  92. package/dist/telemetry/creator-prompt.d.ts +35 -0
  93. package/dist/telemetry/creator-prompt.js +45 -0
  94. package/dist/telemetry/creator-prompt.js.map +1 -0
  95. package/dist/update/check.js +2 -1
  96. package/dist/update/check.js.map +1 -1
  97. package/dist/update/notice.d.ts +31 -1
  98. package/dist/update/notice.js +39 -5
  99. package/dist/update/notice.js.map +1 -1
  100. package/dist/update/self-install.d.ts +175 -0
  101. package/dist/update/self-install.js +335 -0
  102. package/dist/update/self-install.js.map +1 -0
  103. package/package.json +4 -4
package/README.md CHANGED
@@ -49,6 +49,9 @@ npm install -g @bitmagic/cli
49
49
  bitmagic --version
50
50
  ```
51
51
 
52
+ That is the only time you need npm. From then on, `bitmagic self-update` updates the CLI — see
53
+ [Staying current](#staying-current) for why the npm line is the wrong tool for the second install.
54
+
52
55
  ### The dev line
53
56
 
54
57
  ```bash
@@ -61,9 +64,10 @@ installs the unreleased build the Bitmagic team and external testers run — a p
61
64
  production, so a CLI that uses them has to be installable before it is released. Pair it with
62
65
  `bitmagic login --env dev`.
63
66
 
64
- `npm install -g @bitmagic/cli` puts you back on the release at any time. One global install is a
65
- single `bitmagic` on your PATH, so `bitmagic --version` is how you tell which line you are on: a
66
- `-dev.N` suffix means the dev line. To have both at once, see below.
67
+ `bitmagic self-update --tag latest` puts you back on the release at any time, and `--tag dev` takes
68
+ you the other way. One global install is a single `bitmagic` on your PATH, so `bitmagic --version`
69
+ is how you tell which line you are on: a `-dev.N` suffix means the dev line. To have both at once,
70
+ see below.
67
71
 
68
72
  ### Running both lines side by side
69
73
 
@@ -113,6 +117,11 @@ env=local
113
117
  apiUrl=http://localhost:3102
114
118
  ```
115
119
 
120
+ `bitmagic self-update` works inside this setup unchanged: it reinstalls into the root the
121
+ `bitmagic` you just ran came from, with the same `--global-dir` and `--global-bin-dir`, so updating
122
+ from `dev-games/` cannot disturb the prod root. (Running `pnpm add -g` by hand would, unless you
123
+ repeat both flags.)
124
+
116
125
  `direnv allow` each, and both halves are right in each tree:
117
126
 
118
127
  ```
@@ -184,11 +193,12 @@ browser reloads itself on every change and the assets panel shows each generatio
184
193
  | `bitmagic whoami [--env <env>]` | Show the identity the CLI is authenticated as — the account's email address alongside its user id — and which environment answered, including where that environment was chosen from. |
185
194
  | `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. Starts from `empty-3d` unless told otherwise. `--idea` seeds the design doc's pitch **and** picks the template whose camera and controls fit it — "a doom-like corridor shooter" scaffolds `first-person`, "jump between floating islands" scaffolds `sidescroller`. `--template` overrides both; a suggestion that fails for any reason falls back to `empty-3d` rather than failing the scaffold. Dependencies are installed with **pnpm** when your machine has it and npm otherwise — the lockfile that produces is what every later command reads, so it never tells you to run the wrong one. |
186
195
  | `bitmagic check` | Typecheck (`tsc --noEmit`) against the vendored engine. Fast; does not prove the game runs. |
187
- | `bitmagic dev [--port <port>] [--editor-port <port>] [--no-open]` | 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. Opens the view in your browser; `--no-open` (or `BITMAGIC_NO_OPEN=1`) skips that. The one command to leave open. See **The dev view** below. |
196
+ | `bitmagic dev [--port <port>] [--editor-port <port>] [--no-open]` | 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, and shows where the game is published (with a QR code) once it has been. Opens the view in your browser; `--no-open` (or `BITMAGIC_NO_OPEN=1`) skips that. The one command to leave open. See **The dev view** below. |
188
197
  | `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. |
189
198
  | `bitmagic verify [--timeout <ms>] [--renderer webgpu\|webgl] [--platform desktop\|mobile\|both] [--fast] [--watch]` | Build, boot the game in a headless browser, press 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. The settle is adaptive: the run ends as soon as the live engine proves stable gameplay (state, rendered frames, no fresh errors, player standing), with `--timeout` as the cap. The verdict includes live engine state — actual GPU backend, fps, player position, physics body count, gameplay events (see **Gameplay events** below) — recorded in `result.json`. `--renderer` pins the pipeline (default `webgpu`, what players run; a silent WebGPU→WebGL2 fallback **fails** the run, and `--renderer webgl` is the deliberate escape hatch). A run failing on a lost WebGL context retries once on software rendering automatically. `--fast` skips the screenshot pipeline (then there is no thumbnail candidate from this run). `--watch` keeps everything warm — incremental `tsc --watch`, one vite, one browser — and re-verifies on file change in seconds; `--fast` is the watch default (`--no-fast` restores the screenshot). `--platform` picks what the run emulates — see **Verifying the mobile path** below. Every run also reports the engine's mobile-parity check: a desktop action with no touch button is a warning, and a **failure** when `game.json` declares `primaryPlatform: "mobile"`. Writes the artifacts the publish gate reads (see below). |
190
199
  | `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. |
191
- | `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.** |
200
+ | `bitmagic publish [--visibility public\|private] [--name <name>] [--description <desc>] [--force] [--no-qr]` | Verify-gate, build if needed, and upload straight to GCS. **Keeps the game's current visibility**; a new game is private until published with `--visibility public`. Shows the published URL as a QR code so you can scan it onto a phone — drawn in the terminal, or written to `.bitmagic/publish-qr.png` when it cannot be. `--no-qr` skips both. |
201
+ | `bitmagic self-update [--tag latest\|dev]` | Update the **CLI itself** to the newest build of its line, installing into the place this CLI actually lives rather than wherever the `npm` on your `PATH` would put it — which under nvm is routinely somewhere else. Reads the project's line from `bitmagic.json` when there is one, so it also fixes a wrong-line install; `--tag` overrides. Verifies the version on disk moved, and refuses (naming the path) for an `npx` run, a source checkout, or an install shape it cannot recognise. Not to be confused with `upgrade`, which is about the project's engine. |
192
202
  | `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`. Also records the project's `environment` in `bitmagic.json` if it has none yet — the engine it just vendored came from that api-server — and says so when it does. |
193
203
  | `bitmagic generate <skybox\|background\|block-type\|sound\|image\|character\|animation\|model\|prop\|vehicle> ...` | Generate one asset directly into `src/work/world.json`. Costs sparks. `model` mints a **new** 3D object from a prompt, `prop` upgrades an existing placeholder **in place**, `vehicle` adds a new drivable one, `animation` takes a parameter spec rather than a prompt, `block-type` registers a custom voxel block — see below. `skybox` and `background` write the **same** field: pick one. |
194
204
  | `bitmagic assets add <file> [--name <n>] [--asset-id <id>] [--keep-glb] [--voxel-size <m>] [--max-voxel-size <m>] [--height <m>] [--hollow\|--solid] [--force]` | Upload **your own** file — `.glb`, `.vxl`, `.png/.jpg/.webp`, `.opus/.ogg/.m4a/.mp3`, `.json` — into the game's assets and write its entry into `src/work/world.json`. A `.glb` is voxelized in a headless browser (Chrome + a free port in 3000–3199, like `prop`) unless `--keep-glb`. Free — no sparks. See **Adding your own assets** below. |
@@ -411,6 +421,21 @@ While the game boots, the mark hops over the stage — the first time only. Late
411
421
  still, and only if the reload is slow enough to be worth explaining. If a boot fails it stays put,
412
422
  says what went wrong and offers to try again, instead of leaving you a black rectangle.
413
423
 
424
+ ### Where your game is published
425
+
426
+ Once the project has been published, a **Published** pill appears in the top bar. It opens the
427
+ game's address, the visibility it went out with, which publish this is and how long ago — and the
428
+ same QR code the terminal draws, so the phone in your hand can reach the build without you typing
429
+ anything.
430
+
431
+ The pill lights up on its own within a second or two of a publish finishing, with no reload: the
432
+ page polls, and the publish it should show almost always happens in another terminal — often your
433
+ agent's, which you never look at. Until the first publish the pill is there but dead, because a
434
+ control that opens an empty dialog is worse than one that is plainly not ready.
435
+
436
+ It works even when the game will not boot, which is deliberate: that is the moment the link matters
437
+ most, since the last good build is still live at that address.
438
+
414
439
  Put the page beside your agent's window. It is one page with
415
440
  two tabs over the same running game, so switching costs nothing and does not restart anything:
416
441
 
@@ -727,12 +752,18 @@ manage the registry, not gameplay.
727
752
  publish rebuilds automatically; a prior manual `bitmagic build` is never required, only useful
728
753
  if you want to inspect `.bitmagic/build/index.html` before it ships.
729
754
 
730
- **Publishing does not make a game public.** Every `bitmagic publish` uploads and registers the
731
- game, but by default `visibility` is `private` reachable by URL, not listed anywhere on
732
- bitmagic.ai. You must pass `--visibility public` explicitly, every time you want the game listed;
733
- omitting it on a later publish makes it private again — and takes the game's `/play/` page out of
734
- service, so a previously-public game re-published bare is gone from bitmagic.ai until you publish
735
- publicly again.
755
+ **Publishing does not make a game public.** A new game starts `private` reachable by URL, not
756
+ listed anywhere on bitmagic.ai. Pass `--visibility public` when you want it listed.
757
+
758
+ **Visibility is sticky.** `bitmagic publish` with no `--visibility` keeps the game exactly as it
759
+ is, so shipping an update to a public game leaves it public. You only need `--visibility` when you
760
+ want to *change* something: `public` to list it, `private` to take it out of service.
761
+
762
+ **Managing a published game** — changing its visibility, or taking it down for good — happens on
763
+ the web, at the **My games** page `publish` prints a link to (`bitmagic.ai/my-games/`). It is
764
+ the same page web-lane creators use, so there is one place to manage a game regardless of how it
765
+ was built. Withdrawing a game there unlists it and frees any custom `/play/` address; it does not
766
+ touch your project, and you can publish it again afterwards.
736
767
 
737
768
  `--force` overrides a **stale or failed** verify verdict. It does **not** override a missing
738
769
  verify record — a project with no cover art has only the verify screenshot to publish a thumbnail
@@ -744,6 +775,33 @@ from, so `bitmagic verify` must have produced at least one screenshot — `scree
744
775
  stick — and note that writing them into `game.json` yourself would change the fingerprint and
745
776
  invalidate the verify you just checked.
746
777
 
778
+ ### Testing it on a phone
779
+
780
+ Publish draws the URL it just printed as a QR code, so you can point a phone at the terminal
781
+ instead of retyping a twelve-character game id into a mobile browser. Scan it and the game opens.
782
+
783
+ This is the pro lane's "try it on my phone" loop, and `--visibility private` is the whole of it: a
784
+ private game is *unlisted*, not access-controlled, so its URL works from any device while the game
785
+ stays off bitmagic.ai. Publish as often as you like and scan the code each time.
786
+
787
+ **When the code cannot be drawn, publish writes it as a file instead** — `.bitmagic/publish-qr.png`
788
+ — and names the path (`qrPath` in the `--json` result). That is the normal case for an agent-driven
789
+ publish: your agent's stdout is a pipe, not a terminal, so there is nothing to paint a code onto,
790
+ and the person who would scan it is on the other side of that pipe. The image is how it reaches
791
+ them. The same happens under `--json`, for `TERM=dumb`, and when the terminal is narrower than the
792
+ code (37 columns for a typical publish URL), since a wrapped code cannot be scanned anyway. A
793
+ terminal that draws the code successfully writes no file.
794
+
795
+ `.bitmagic/` is excluded from the publish fingerprint, so the image cannot invalidate a verify.
796
+
797
+ The code is extra, never a substitute — the URL is always printed as a plain line above it, and
798
+ everything still works if neither a drawing nor a file appears. `--no-qr` and `BITMAGIC_NO_QR`
799
+ suppress both.
800
+
801
+ `bitmagic dev` deliberately has no equivalent. Its servers bind `127.0.0.1`, and the asset CDN
802
+ only serves assets to `localhost` origins — a phone pointed at your machine's LAN address would
803
+ load the game with no terrain and drop the player through the floor. Publish privately instead.
804
+
747
805
  ### Which platform the game is catalogued as
748
806
 
749
807
  Publish syncs two indicators from your project files, so bitmagic.ai lists the game as what it
@@ -867,7 +925,12 @@ parses one stream whether the command succeeded or not. The exit code remains au
867
925
 
868
926
  Without `--json` nothing changes: prose goes to stdout as before and no JSON is emitted.
869
927
 
870
- The result shape is per-command `publish` reports `url`/`visibility`/`publishVersion`, `init`
928
+ `--json` suppresses `publish`'s *drawn* QR code, which uses terminal escape sequences: under
929
+ `--json` stdout carries the result document and nothing else. The image is still written, and
930
+ `qrPath` in the result names it — that is the only way an agent learns the file exists.
931
+
932
+ The result shape is per-command — `publish` reports
933
+ `url`/`visibility`/`publishVersion`/`manageUrl`, plus `qrPath` when it wrote a QR image, `init`
871
934
  reports `gameId`/`root`/`dependenciesInstalled`/`packageManager`, `upgrade` reports `replaced` and any
872
935
  `missingDependencies` as structured entries rather than only as a printed install command, plus
873
936
  `cliUpdate` (`{ current, latest, updateAvailable }`, or `null` when the engine did not move and so
@@ -877,7 +940,39 @@ no check was made — which is not the same as "no update"), and `legacyAssetsRe
877
940
 
878
941
  ## Staying current
879
942
 
880
- Three nudges, all advisory — nothing is ever blocked because something is out of date.
943
+ ```bash
944
+ bitmagic self-update
945
+ ```
946
+
947
+ updates the CLI itself. Use it rather than `npm install -g @bitmagic/cli`, which is only for the
948
+ first install — see [Why self-update and not npm](#why-self-update-and-not-npm) below.
949
+
950
+ It installs into the exact place this CLI is already installed, on the line it is already on. Inside
951
+ a project it uses that project's line instead (`environment` in `bitmagic.json`), so running it in a
952
+ `dev` project from a release build crosses you over; `--tag dev` / `--tag latest` overrides both. It
953
+ reads back the version on disk afterwards and fails if it did not move, so a successful-looking
954
+ update that changed nothing is reported rather than believed.
955
+
956
+ It refuses, with the path it looked at, when there is nothing for it to do: a run through `npx`
957
+ (nothing is installed), a source checkout (`git pull` and rebuild), or an install shape it does not
958
+ recognise — it will not guess at where to write.
959
+
960
+ ### Why self-update and not npm
961
+
962
+ `npm install -g @bitmagic/cli` installs into whichever Node the `npm` on your `PATH` belongs to,
963
+ which is not necessarily the one this CLI is installed in. Under a version manager — nvm, fnm,
964
+ Volta — those two are routinely different, and a coding agent's non-interactive shell makes it
965
+ worse: it sources no profile, so nvm never loads and `npm` is whatever else is on the system path.
966
+ The install then succeeds, into a prefix nothing on your `PATH` points at, and `bitmagic --version`
967
+ never moves. The same applies to the two-root pnpm setup below, where a bare `npm i -g` writes to a
968
+ third place entirely.
969
+
970
+ `self-update` resolves its own install from the Node binary running it, so it cannot be aimed
971
+ anywhere else.
972
+
973
+ ### The nudges
974
+
975
+ Three, all advisory — nothing is ever blocked because something is out of date.
881
976
 
882
977
  - **The CLI itself.** Commands print a line when a newer `@bitmagic/cli` is on npm. The check reads
883
978
  a cache written by an earlier run, so it costs no time; the cache refreshes in the background at
@@ -885,15 +980,17 @@ Three nudges, all advisory — nothing is ever blocked because something is out
885
980
  every merge to `main` and can move several times an hour, so an older answer there is usually
886
981
  about a build several versions back. It asks about the line you are actually on — a build
887
982
  installed from `@dev` asks the `dev` dist-tag and hears about the next dev build, rather than
888
- being told the production release is "newer" and it names the install command for that line. An
889
- unreachable registry, a first-ever run, and a version with no recognisable numeric core all stay
890
- quiet.
983
+ being told the production release is "newer". An unreachable registry, a first-ever run, and a
984
+ version with no recognisable numeric core all stay quiet. `bitmagic dev` also shows it as a
985
+ banner in the browser, because that command runs for hours and the terminal line scrolls away.
891
986
  - **The CLI, after an engine bump.** When `bitmagic upgrade` actually moves the engine version, it
892
987
  asks npm there and then instead of trusting that cache — which can be a whole interval stale, and
893
988
  so silent about the CLI published alongside the engine you just vendored. The CLI and the engine
894
989
  ship together, so a newer engine can need build config or a command only the newer CLI has, and
895
- finding that out as a failed `bitmagic build` is worse than being told here. No request is made when the
896
- engine version did not change, and an unreachable registry costs the hint and nothing else.
990
+ finding that out as a failed `bitmagic build` is worse than being told here. It names the line the
991
+ *project* is on rather than the one you happen to be running, so it says `bitmagic self-update
992
+ --tag dev` where that is the crossing you need. No request is made when the engine version did not
993
+ change, and an unreachable registry costs the hint and nothing else.
897
994
  - **The vendored engine.** `bitmagic dev` and `bitmagic publish` say when a newer engine exists and
898
995
  suggest `bitmagic upgrade`. Publishing is never refused for an old engine — the prompt belongs
899
996
  where rebuilding is cheap, not at the moment you ship.
@@ -916,19 +1013,23 @@ and where the generators fall short. It is the same thing the web editor already
916
1013
  typed there, and it goes to the same place. None of it reaches Google Analytics, which only ever
917
1014
  receives counts, outcomes and timings.
918
1015
 
919
- If your agent passes it, the wording *you* used when you asked it is kept alongside the command's
920
- own text. That is optional and most agents will not send it.
921
-
922
- This does not include what you type into Claude Code, Codex or any other agent. Bitmagic never sees
923
- that the CLI only ever receives the arguments your agent chooses to pass it.
1016
+ **What you asked your agent for is kept too, when it passes it on.** The scaffolded project docs
1017
+ tell your agent to add `--original-prompt "<your request, verbatim>"`, so on those commands the
1018
+ wording *you* used — typically what you typed into Claude Code or Codex — is stored beside the
1019
+ command's own text and as a record of its own. The CLI has no other view of your agent's
1020
+ conversation: it sees only the arguments your agent chooses to pass it, and this is the one
1021
+ argument that is your words rather than its paraphrase. It is optional, never required, and never
1022
+ influences what gets generated.
924
1023
 
925
1024
  Set `DO_NOT_TRACK=1` in your environment to switch the end-of-command report off. Nothing is
926
- collected for it in that case — not even the file reads it would have needed.
927
-
928
- It does **not** switch off the paragraph above. The text you pass to `forge`, `generate`, `cover`
929
- and `init --idea` is not telemetry: it is the request, and the server cannot generate anything
930
- without it. If you would rather it were not kept, the honest answer is that today there is no flag
931
- for that tell us and we will add one.
1025
+ collected for it in that case — not even the file reads it would have needed. It also stops
1026
+ `--original-prompt` being forwarded: the CLI drops it at the point every command reads its flags,
1027
+ so no request carries it, whether or not your agent passed it.
1028
+
1029
+ It does **not** switch off the paragraph before that one. The text you pass to `forge`, `generate`,
1030
+ `cover` and `init --idea` is not telemetry: it is the request, and the server cannot generate
1031
+ anything without it. If you would rather it were not kept, the honest answer is that today there is
1032
+ no flag for that — tell us and we will add one.
932
1033
 
933
1034
  The report is deliberately unobtrusive but it is not free: it is capped at 1.5 seconds per request
934
1035
  (two at worst, when your access token is due for a refresh first), it never prints, and it can never
@@ -0,0 +1,116 @@
1
+ import type { Environment } from '../config/environments.js';
2
+ import { withVoxelizeSession } from '../forge/voxelize-session.js';
3
+ import type { ProjectContext } from '../project/context.js';
4
+ import { type VoxelizeFlags, type VoxelizeGlb } from './voxelize-glb.js';
5
+ /** Which stored source a re-bake will read. */
6
+ export type RevoxelizeSource = {
7
+ kind: 'master';
8
+ masterUrl: string;
9
+ } | {
10
+ kind: 'glb';
11
+ glbUrl: string;
12
+ };
13
+ export interface RevoxelizeOptions {
14
+ context: ProjectContext;
15
+ environment: Environment;
16
+ token: string;
17
+ assetId: string;
18
+ voxel: VoxelizeFlags;
19
+ log: (message: string) => void;
20
+ fetchImpl?: typeof globalThis.fetch;
21
+ /** Injected in tests so the lane runs without Chrome. */
22
+ session?: typeof withVoxelizeSession;
23
+ /** Injected in tests; used for the GLB source, which reuses the shared bake. */
24
+ voxelize?: VoxelizeGlb;
25
+ }
26
+ export interface RevoxelizeResult {
27
+ assetId: string;
28
+ assetName: string;
29
+ source: RevoxelizeSource['kind'];
30
+ assetUrl?: string;
31
+ voxelCount?: number;
32
+ /** Placed instances that changed with it — the blast radius, reported rather than assumed. */
33
+ instanceCount: number;
34
+ }
35
+ /**
36
+ * The stored source to re-bake, preferring the master.
37
+ *
38
+ * The master is preferred when both are present because it is a hundredth of the bytes for the
39
+ * same answer at or below its own resolution. `assertCanGoFiner` is what catches the case where
40
+ * that preference would cost detail.
41
+ */
42
+ export declare function chooseSource(asset: Record<string, unknown>): RevoxelizeSource | null;
43
+ /** The asset to re-bake, refused before the browser starts if it cannot be. */
44
+ export declare function findRevoxelizableAsset(world: Record<string, unknown>, assetId: string): {
45
+ asset: Record<string, unknown>;
46
+ source: RevoxelizeSource;
47
+ };
48
+ /**
49
+ * A voxel size fit to show a person and to store.
50
+ *
51
+ * The `.vxl` header holds float32, so the size read back out of it is `0.019999999552965164` where
52
+ * the creator asked for `0.01` and got a doubling. Six significant figures is far beyond any
53
+ * resolution this means anything at, and it puts the number back in the vocabulary the flag uses —
54
+ * both in the note and in world.json, which would otherwise carry the artifact into every diff.
55
+ */
56
+ export declare function tidyVoxelSize(value: number): number;
57
+ /**
58
+ * What the bake actually produced, when that is not what was asked for.
59
+ *
60
+ * The engine's compiler halves resolution until the model fits a leaf budget
61
+ * (`compileVoxelModelToVxlAsset`: `while (cells.size > maxLeaves) { downsample; vs *= 2 }`, budget
62
+ * 600k for a working asset). It says so — but only as a `console.warn` inside the headless Chrome
63
+ * the CLI drives, which reaches nobody, and `REVOXELIZE_FROM_VXL_MASTER_RESULT` did not carry it.
64
+ * So a request just under the knee came back at exactly twice the size, silently, with a zero exit
65
+ * code.
66
+ *
67
+ * The effect is worse than "not quite what you asked for", which is why this is said out loud
68
+ * rather than left to whoever compares two numbers in world.json: the result is NON-MONOTONIC.
69
+ * One step below the knee the asset is coarser than a COARSER request would have produced —
70
+ * measured on a 2.78 m stall with a 512³ master, 0.011 m gave 556k voxels and 0.0105 m gave 141k.
71
+ * Nothing about "I asked for finer voxels and got a blockier model" suggests looking at a budget.
72
+ *
73
+ * Detected from the .vxl header rather than from anything the engine says, deliberately: the
74
+ * header is what was actually written, and the CLI drives whatever engine the project vendored —
75
+ * including ones that predate any reply field carrying this.
76
+ */
77
+ export declare function describeBudgetCoarsening(requested: number, achieved: number): {
78
+ coarsened: boolean;
79
+ factor: number;
80
+ note: string;
81
+ };
82
+ /**
83
+ * The height a master re-bake will be resampled to.
84
+ *
85
+ * `--height` wins. Otherwise the height the asset was BAKED at, which the master path records in
86
+ * `voxelizeSettings` for exactly this. Falling through to neither is the case worth naming: a
87
+ * master is a grid, not a size, so the engine has nothing to derive a height from and lands on its
88
+ * own `DEFAULT_TARGET_HEIGHT` of 2 m — silently returning a 10 m building as a 2 m one. The mesh
89
+ * branch has no such gap, which is why `--height`'s "omit to keep the source's own size" only ever
90
+ * described half of this command.
91
+ */
92
+ export declare function resolveMasterTargetHeight(asset: Record<string, unknown>, requested: number | undefined): number | undefined;
93
+ /**
94
+ * Refuse a master re-bake that asks for more detail than the master holds.
95
+ *
96
+ * The engine would refuse it too — `resampleMaster` throws "re-forge at a higher resolution rather
97
+ * than upsampling" — but only after the browser, vite and the page have started. Saying it here
98
+ * costs nothing and names the thing to do instead, which the engine's message cannot know.
99
+ *
100
+ * The floor is derived from the MASTER, not from the previous bake. Those are very different
101
+ * numbers: a 512³ master baked once at 0.1 m holds detail down to about `targetHeight / 512`, and
102
+ * refusing everything below 0.1 m would make that headroom unreachable from the CLI — which is the
103
+ * whole reason the master is stored rather than the working asset.
104
+ *
105
+ * Deliberately PERMISSIVE. The engine's real limit is the master's occupied span along the up
106
+ * axis, which is at most its resolution and usually less, so a request between
107
+ * `targetHeight / resolution` and `targetHeight / spanUp` still throws in the browser. That is the
108
+ * right way round: this pre-flight exists to avoid paying for a browser on a request that cannot
109
+ * work, never to refuse a size the master can serve. The engine stays the authority.
110
+ *
111
+ * Falls back to the old "no finer than the last bake" rule when either field is missing, so assets
112
+ * written before `sourceVxlMasterResolution` existed — or hand-edited ones — keep a guard rather
113
+ * than losing it.
114
+ */
115
+ export declare function assertMasterCanGoFiner(asset: Record<string, unknown>, requestedVoxelSize: number, targetHeight: number | undefined, name: string): void;
116
+ export declare function revoxelizeAsset(options: RevoxelizeOptions): Promise<RevoxelizeResult>;