@bitmagic/cli 0.1.52-dev.1 → 0.1.52-dev.11

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 (152) hide show
  1. package/README.md +217 -11
  2. package/dist/assets/add.d.ts +40 -0
  3. package/dist/assets/add.js +229 -0
  4. package/dist/assets/add.js.map +1 -0
  5. package/dist/assets/entry.d.ts +44 -0
  6. package/dist/assets/entry.js +71 -0
  7. package/dist/assets/entry.js.map +1 -0
  8. package/dist/assets/file-kind.d.ts +61 -0
  9. package/dist/assets/file-kind.js +195 -0
  10. package/dist/assets/file-kind.js.map +1 -0
  11. package/dist/assets/list.d.ts +27 -0
  12. package/dist/assets/list.js +50 -0
  13. package/dist/assets/list.js.map +1 -0
  14. package/dist/assets/remove.d.ts +50 -0
  15. package/dist/assets/remove.js +91 -0
  16. package/dist/assets/remove.js.map +1 -0
  17. package/dist/assets/voxelize-glb.d.ts +37 -0
  18. package/dist/assets/voxelize-glb.js +65 -0
  19. package/dist/assets/voxelize-glb.js.map +1 -0
  20. package/dist/assets/vxl-summary.d.ts +32 -0
  21. package/dist/assets/vxl-summary.js +118 -0
  22. package/dist/assets/vxl-summary.js.map +1 -0
  23. package/dist/bin.js +25 -0
  24. package/dist/bin.js.map +1 -1
  25. package/dist/cli.d.ts +12 -0
  26. package/dist/cli.js +15 -1
  27. package/dist/cli.js.map +1 -1
  28. package/dist/commands/assets.d.ts +56 -0
  29. package/dist/commands/assets.js +328 -0
  30. package/dist/commands/assets.js.map +1 -0
  31. package/dist/commands/cover.js +2 -3
  32. package/dist/commands/cover.js.map +1 -1
  33. package/dist/commands/forge.d.ts +2 -9
  34. package/dist/commands/forge.js +2 -13
  35. package/dist/commands/forge.js.map +1 -1
  36. package/dist/commands/generate.d.ts +41 -9
  37. package/dist/commands/generate.js +234 -54
  38. package/dist/commands/generate.js.map +1 -1
  39. package/dist/commands/judge.d.ts +7 -7
  40. package/dist/commands/judge.js +53 -25
  41. package/dist/commands/judge.js.map +1 -1
  42. package/dist/commands/levels.d.ts +33 -0
  43. package/dist/commands/levels.js +241 -0
  44. package/dist/commands/levels.js.map +1 -0
  45. package/dist/commands/number-flag.d.ts +7 -0
  46. package/dist/commands/number-flag.js +38 -0
  47. package/dist/commands/number-flag.js.map +1 -0
  48. package/dist/commands/publish.d.ts +6 -1
  49. package/dist/commands/publish.js +42 -15
  50. package/dist/commands/publish.js.map +1 -1
  51. package/dist/commands/run-deps.d.ts +27 -0
  52. package/dist/commands/run-deps.js +43 -0
  53. package/dist/commands/run-deps.js.map +1 -0
  54. package/dist/commands/verify.d.ts +4 -0
  55. package/dist/commands/verify.js +94 -51
  56. package/dist/commands/verify.js.map +1 -1
  57. package/dist/editor/journal.d.ts +48 -1
  58. package/dist/editor/journal.js +44 -0
  59. package/dist/editor/journal.js.map +1 -1
  60. package/dist/editor/previews.d.ts +6 -0
  61. package/dist/editor/previews.js +16 -0
  62. package/dist/editor/previews.js.map +1 -1
  63. package/dist/editor/server.js +228 -53
  64. package/dist/editor/server.js.map +1 -1
  65. package/dist/editor/shell-page.js +221 -116
  66. package/dist/editor/shell-page.js.map +1 -1
  67. package/dist/editor/voxel-save.d.ts +47 -0
  68. package/dist/editor/voxel-save.js +49 -0
  69. package/dist/editor/voxel-save.js.map +1 -0
  70. package/dist/errors.d.ts +10 -0
  71. package/dist/errors.js +16 -0
  72. package/dist/errors.js.map +1 -1
  73. package/dist/forge/apply-modifications.d.ts +18 -1
  74. package/dist/forge/apply-modifications.js +15 -32
  75. package/dist/forge/apply-modifications.js.map +1 -1
  76. package/dist/forge/browser-host.js +9 -4
  77. package/dist/forge/browser-host.js.map +1 -1
  78. package/dist/forge/voxelize-session.d.ts +61 -0
  79. package/dist/forge/voxelize-session.js +137 -0
  80. package/dist/forge/voxelize-session.js.map +1 -0
  81. package/dist/generate/model.d.ts +36 -0
  82. package/dist/generate/model.js +90 -0
  83. package/dist/generate/model.js.map +1 -0
  84. package/dist/generate/prop.d.ts +52 -4
  85. package/dist/generate/prop.js +169 -102
  86. package/dist/generate/prop.js.map +1 -1
  87. package/dist/generate/stream.d.ts +7 -0
  88. package/dist/generate/stream.js +2 -1
  89. package/dist/generate/stream.js.map +1 -1
  90. package/dist/generate/vehicle.js +5 -85
  91. package/dist/generate/vehicle.js.map +1 -1
  92. package/dist/http/signed-upload.d.ts +55 -0
  93. package/dist/http/signed-upload.js +168 -0
  94. package/dist/http/signed-upload.js.map +1 -0
  95. package/dist/judge/facts.js +72 -57
  96. package/dist/judge/facts.js.map +1 -1
  97. package/dist/judge/record.d.ts +3 -0
  98. package/dist/judge/record.js +3 -0
  99. package/dist/judge/record.js.map +1 -1
  100. package/dist/levels/registry.d.ts +88 -0
  101. package/dist/levels/registry.js +309 -0
  102. package/dist/levels/registry.js.map +1 -0
  103. package/dist/messages/check.d.ts +30 -0
  104. package/dist/messages/check.js +119 -0
  105. package/dist/messages/check.js.map +1 -0
  106. package/dist/messages/notice.d.ts +58 -0
  107. package/dist/messages/notice.js +54 -0
  108. package/dist/messages/notice.js.map +1 -0
  109. package/dist/messages/refresh.d.ts +19 -0
  110. package/dist/messages/refresh.js +42 -0
  111. package/dist/messages/refresh.js.map +1 -0
  112. package/dist/project/jobs.d.ts +1 -1
  113. package/dist/project/jobs.js.map +1 -1
  114. package/dist/project/platform-declaration.d.ts +51 -0
  115. package/dist/project/platform-declaration.js +81 -0
  116. package/dist/project/platform-declaration.js.map +1 -0
  117. package/dist/publish/client.d.ts +13 -0
  118. package/dist/publish/client.js +13 -34
  119. package/dist/publish/client.js.map +1 -1
  120. package/dist/publish/platform.d.ts +42 -0
  121. package/dist/publish/platform.js +58 -0
  122. package/dist/publish/platform.js.map +1 -0
  123. package/dist/scaffold/project-files.js +124 -22
  124. package/dist/scaffold/project-files.js.map +1 -1
  125. package/dist/verify/artifacts.d.ts +19 -0
  126. package/dist/verify/artifacts.js +34 -0
  127. package/dist/verify/artifacts.js.map +1 -0
  128. package/dist/verify/browser.d.ts +10 -0
  129. package/dist/verify/browser.js +79 -9
  130. package/dist/verify/browser.js.map +1 -1
  131. package/dist/verify/classify.d.ts +37 -1
  132. package/dist/verify/classify.js +66 -2
  133. package/dist/verify/classify.js.map +1 -1
  134. package/dist/verify/device.d.ts +43 -0
  135. package/dist/verify/device.js +59 -0
  136. package/dist/verify/device.js.map +1 -0
  137. package/dist/verify/iterate.d.ts +21 -2
  138. package/dist/verify/iterate.js +43 -36
  139. package/dist/verify/iterate.js.map +1 -1
  140. package/dist/verify/mobile-parity.d.ts +42 -0
  141. package/dist/verify/mobile-parity.js +84 -0
  142. package/dist/verify/mobile-parity.js.map +1 -0
  143. package/dist/verify/platform.d.ts +47 -0
  144. package/dist/verify/platform.js +89 -0
  145. package/dist/verify/platform.js.map +1 -0
  146. package/dist/verify/result.d.ts +90 -6
  147. package/dist/verify/result.js +89 -10
  148. package/dist/verify/result.js.map +1 -1
  149. package/dist/verify/url.d.ts +9 -1
  150. package/dist/verify/url.js +10 -2
  151. package/dist/verify/url.js.map +1 -1
  152. package/package.json +4 -4
@@ -0,0 +1,47 @@
1
+ /**
2
+ * What an object voxel sculpt has to write into world.json.
3
+ *
4
+ * The engine bakes the edited object, uploads the new `.vxl` itself, and posts `VOXEL_ASSET_SAVED`
5
+ * with the asset record. It mutates only its own in-memory copy — `EditorManager` says why at the
6
+ * post site: "Mutating gameData alone would leave the new url in memory only, and the next load
7
+ * would fetch the legacy file again as if nothing had happened." Persisting it is the host's job,
8
+ * and this builds the modifications that do it.
9
+ *
10
+ * Pure and filesystem-free, like `save.ts`: the shapes here come off a postMessage from another
11
+ * origin, so they are treated as untrusted input and tested without a project on disk.
12
+ *
13
+ * ── Why an updater rather than a straight upsert ─────────────────────────────────────────────
14
+ *
15
+ * The Creator replaces the whole asset record, and that is safe THERE: its in-memory `gameData` is
16
+ * the document. Here it is not. `bitmagic dev`'s defining condition is that the creator's agent
17
+ * edits `src/work/world.json` concurrently, and the engine's copy was read once at `LOAD_GAME` —
18
+ * so a field the agent added since (a `light`, a `collision`, a regenerated `fitBox`) is absent
19
+ * from the record coming back, and writing that record wholesale would silently revert it. Exactly
20
+ * the hazard `game/docs/editor-host-contract.md` gives for keeping `saveModifications` off the
21
+ * host interface. So an existing asset is MERGED field by field, and only a genuinely new one is
22
+ * pushed whole.
23
+ */
24
+ import type { WorldJsonModification } from '@bitmagic/world-forger/pipeline/index.js';
25
+ import { type JsonObject } from '../project/world-json.js';
26
+ /** The engine's `VOXEL_ASSET_SAVED`, as far as this cares. */
27
+ export interface VoxelSavePayload {
28
+ /** The asset record the engine just wrote its new url onto. Useless without an id. */
29
+ asset?: unknown;
30
+ /** Instances the save created — a make-unique produces one. */
31
+ environmentObjects?: unknown;
32
+ }
33
+ export interface VoxelSavePlan {
34
+ modifications: WorldJsonModification[];
35
+ assetId: string;
36
+ assetName: string;
37
+ /** True when the asset was already in world.json, so its other fields were merged rather than lost. */
38
+ merged: boolean;
39
+ }
40
+ /**
41
+ * Returns null when there is nothing safe to write.
42
+ *
43
+ * An asset with no id is the one shape that must never be guessed at: the engine has already
44
+ * uploaded the bytes and reported success, so a host that shrugs here produces a save that "worked"
45
+ * and reaches no file. The caller turns this into a loud refusal instead.
46
+ */
47
+ export declare function buildVoxelSaveModifications(payload: VoxelSavePayload, world: JsonObject): VoxelSavePlan | null;
@@ -0,0 +1,49 @@
1
+ import { isJsonObject } from '../project/world-json.js';
2
+ /** Match an array item by its `id`, the predicate every write below uses. Mirrors `save.ts`. */
3
+ function byId(id) {
4
+ return (item) => isJsonObject(item) && item.id === id;
5
+ }
6
+ /**
7
+ * Returns null when there is nothing safe to write.
8
+ *
9
+ * An asset with no id is the one shape that must never be guessed at: the engine has already
10
+ * uploaded the bytes and reported success, so a host that shrugs here produces a save that "worked"
11
+ * and reaches no file. The caller turns this into a loud refusal instead.
12
+ */
13
+ export function buildVoxelSaveModifications(payload, world) {
14
+ const asset = payload.asset;
15
+ if (!isJsonObject(asset) || typeof asset.id !== 'string' || asset.id === '')
16
+ return null;
17
+ const assetId = asset.id;
18
+ const isThisAsset = byId(assetId);
19
+ const existing = (Array.isArray(world.assets) ? world.assets : []).some(isThisAsset);
20
+ const modifications = [existing
21
+ ? {
22
+ type: 'updateRoot',
23
+ path: ['assets'],
24
+ predicate: isThisAsset,
25
+ // Field by field, so anything the agent added since LOAD_GAME survives. See the header.
26
+ value: (item) => ({ ...(isJsonObject(item) ? item : {}), ...asset }),
27
+ }
28
+ : { type: 'upsertRoot', path: ['assets'], predicate: isThisAsset, value: asset }];
29
+ // Instances the save minted. Upserted by id rather than pushed, so a retry of the same save does
30
+ // not leave two copies of one object standing in the same place.
31
+ const instances = Array.isArray(payload.environmentObjects) ? payload.environmentObjects : [];
32
+ for (const instance of instances) {
33
+ if (!isJsonObject(instance) || typeof instance.id !== 'string' || instance.id === '')
34
+ continue;
35
+ modifications.push({
36
+ type: 'upsertRoot',
37
+ path: ['environmentObjects'],
38
+ predicate: byId(instance.id),
39
+ value: instance,
40
+ });
41
+ }
42
+ return {
43
+ modifications,
44
+ assetId,
45
+ assetName: typeof asset.name === 'string' && asset.name !== '' ? asset.name : assetId,
46
+ merged: existing,
47
+ };
48
+ }
49
+ //# sourceMappingURL=voxel-save.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voxel-save.js","sourceRoot":"","sources":["../../src/editor/voxel-save.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,YAAY,EAAmB,MAAM,0BAA0B,CAAC;AAkBzE,gGAAgG;AAChG,SAAS,IAAI,CAAC,EAAU;IACtB,OAAO,CAAC,IAAa,EAAW,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;AAC1E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAyB,EACzB,KAAiB;IAEjB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACzF,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC;IAEzB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrF,MAAM,aAAa,GAA4B,CAAC,QAAQ;YACtD,CAAC,CAAC;gBACA,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,CAAC,QAAQ,CAAC;gBAChB,SAAS,EAAE,WAAW;gBACtB,wFAAwF;gBACxF,KAAK,EAAE,CAAC,IAAa,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;aAC9E;YACD,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAEpF,iGAAiG;IACjG,iEAAiE;IACjE,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9F,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,EAAE,KAAK,QAAQ,IAAI,QAAQ,CAAC,EAAE,KAAK,EAAE;YAAE,SAAS;QAC/F,aAAa,CAAC,IAAI,CAAC;YACjB,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,CAAC,oBAAoB,CAAC;YAC5B,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,aAAa;QACb,OAAO;QACP,SAAS,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;QACrF,MAAM,EAAE,QAAQ;KACjB,CAAC;AACJ,CAAC"}
package/dist/errors.d.ts CHANGED
@@ -15,3 +15,13 @@ export declare class CliError extends Error {
15
15
  readonly code: string | undefined;
16
16
  constructor(message: string, exitCode?: number, code?: string);
17
17
  }
18
+ /**
19
+ * The `code` off a Node fs/child-process error, without pulling in the NodeJS global namespace.
20
+ *
21
+ * Shared because both copies existed to answer the same question — "is this the ENOENT I have a
22
+ * sentence for, or something I must not swallow?" — and a lane that maps only the codes it thought
23
+ * of lets the rest escape as a raw stack trace, past whatever guarantee its command documents.
24
+ */
25
+ export declare function errnoCode(error: unknown): string | undefined;
26
+ /** The errno, or the message when there is none — so no failure mode is left unmapped. */
27
+ export declare function describeErrno(error: unknown): string;
package/dist/errors.js CHANGED
@@ -20,4 +20,20 @@ export class CliError extends Error {
20
20
  this.code = code;
21
21
  }
22
22
  }
23
+ /**
24
+ * The `code` off a Node fs/child-process error, without pulling in the NodeJS global namespace.
25
+ *
26
+ * Shared because both copies existed to answer the same question — "is this the ENOENT I have a
27
+ * sentence for, or something I must not swallow?" — and a lane that maps only the codes it thought
28
+ * of lets the rest escape as a raw stack trace, past whatever guarantee its command documents.
29
+ */
30
+ export function errnoCode(error) {
31
+ return typeof error === 'object' && error !== null && 'code' in error
32
+ ? String(error.code)
33
+ : undefined;
34
+ }
35
+ /** The errno, or the message when there is none — so no failure mode is left unmapped. */
36
+ export function describeErrno(error) {
37
+ return errnoCode(error) ?? (error instanceof Error ? error.message : String(error));
38
+ }
23
39
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,QAAQ,CAAS;IACjB,IAAI,CAAqB;IAElC,YAAY,OAAe,EAAE,QAAQ,GAAG,CAAC,EAAE,IAAa;QACtD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,QAAQ,CAAS;IACjB,IAAI,CAAqB;IAElC,YAAY,OAAe,EAAE,QAAQ,GAAG,CAAC,EAAE,IAAa;QACtD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK;QACnE,CAAC,CAAC,MAAM,CAAE,KAA2B,CAAC,IAAI,CAAC;QAC3C,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACtF,CAAC"}
@@ -3,6 +3,15 @@ export interface ApplyModificationsOutcome {
3
3
  applied: number;
4
4
  /** One human-readable line per modification, for the command to print. */
5
5
  summary: string[];
6
+ /**
7
+ * How many entries each modification actually changed, in the same order.
8
+ *
9
+ * Reported from the write itself rather than counted off an earlier read. A caller that counts
10
+ * beforehand — "removing this asset will take 3 placed instances with it" — is describing a
11
+ * document that may not be the one written: `bitmagic dev`'s whole premise is that the creator's
12
+ * agent edits world.json concurrently, and the applier re-reads it under its own atomic write.
13
+ */
14
+ changed: number[];
6
15
  }
7
16
  /**
8
17
  * Read world.json, apply every modification in order, write once.
@@ -16,4 +25,12 @@ export interface ApplyModificationsOutcome {
16
25
  * worse than an unchanged one — the creator has no way to tell which half landed, and a forge is
17
26
  * expensive enough that "run it again" is not an acceptable recovery.
18
27
  */
19
- export declare function applyModificationsToWorld(worldPath: string, modifications: WorldJsonModification[]): ApplyModificationsOutcome;
28
+ export interface ApplyModificationsOptions {
29
+ /**
30
+ * What the batch IS, for the schema-gate message: "The forged level" by default, since the forge
31
+ * was this applier's first caller — `bitmagic assets add` says "The uploaded asset" instead, so
32
+ * a refusal names the thing the creator just did rather than one they did not.
33
+ */
34
+ subject?: string;
35
+ }
36
+ export declare function applyModificationsToWorld(worldPath: string, modifications: WorldJsonModification[], options?: ApplyModificationsOptions): ApplyModificationsOutcome;
@@ -47,13 +47,6 @@ function ensureArray(parent, key) {
47
47
  }
48
48
  return parent[key];
49
49
  }
50
- /**
51
- * Apply one modification in place, returning the path it touched for the summary line.
52
- *
53
- * `*Root` types address the document root; the rest address paths inside `worldProfileData`.
54
- * Writing a `set` at the root instead would put it where the engine never looks, which reads as
55
- * success — the same trap `generate/apply-patches.ts` documents for `WorldPatch`.
56
- */
57
50
  function applyOne(world, modification) {
58
51
  const isRoot = modification.type.endsWith('Root');
59
52
  let target;
@@ -85,35 +78,35 @@ function applyOne(world, modification) {
85
78
  case 'set':
86
79
  case 'setRoot':
87
80
  parent[lastKey] = modification.value;
88
- return `set ${where}`;
81
+ return { summary: `set ${where}`, changed: 1 };
89
82
  case 'push':
90
83
  case 'pushRoot':
91
84
  ensureArray(parent, lastKey).push(modification.value);
92
- return `added to ${where}`;
85
+ return { summary: `added to ${where}`, changed: 1 };
93
86
  case 'update':
94
87
  case 'updateRoot': {
95
88
  const { predicate, value } = modification;
96
89
  const array = parent[lastKey];
97
90
  if (!Array.isArray(array))
98
- return `skipped ${where} (not an array)`;
91
+ return { summary: `skipped ${where} (not an array)`, changed: 0 };
99
92
  const index = array.findIndex(predicate);
100
93
  if (index === -1)
101
- return `no match to update in ${where}`;
94
+ return { summary: `no match to update in ${where}`, changed: 0 };
102
95
  array[index] = typeof value === 'function'
103
96
  ? value(array[index])
104
97
  : value;
105
- return `updated ${where}[${index}]`;
98
+ return { summary: `updated ${where}[${index}]`, changed: 1 };
106
99
  }
107
100
  case 'remove':
108
101
  case 'removeRoot': {
109
102
  const { predicate } = modification;
110
103
  const array = parent[lastKey];
111
104
  if (!Array.isArray(array))
112
- return `skipped ${where} (not an array)`;
105
+ return { summary: `skipped ${where} (not an array)`, changed: 0 };
113
106
  const kept = array.filter((item) => !predicate(item));
114
107
  const removed = array.length - kept.length;
115
108
  parent[lastKey] = kept;
116
- return `removed ${removed} from ${where}`;
109
+ return { summary: `removed ${removed} from ${where}`, changed: removed };
117
110
  }
118
111
  case 'upsert':
119
112
  case 'upsertRoot': {
@@ -122,10 +115,10 @@ function applyOne(world, modification) {
122
115
  const index = array.findIndex(predicate);
123
116
  if (index === -1) {
124
117
  array.push(value);
125
- return `added to ${where}`;
118
+ return { summary: `added to ${where}`, changed: 1 };
126
119
  }
127
120
  array[index] = value;
128
- return `updated ${where}[${index}]`;
121
+ return { summary: `updated ${where}[${index}]`, changed: 1 };
129
122
  }
130
123
  default: {
131
124
  // Not a degradation to swallow: an unknown type means this applier and the shared package's
@@ -138,24 +131,14 @@ function applyOne(world, modification) {
138
131
  }
139
132
  }
140
133
  }
141
- /**
142
- * Read world.json, apply every modification in order, write once.
143
- *
144
- * ORDER IS THE CONTRACT: `placeAndPersistLevel` returns the starter-scatter removals ahead of the
145
- * level's own upserts, and applying them in any other order changes the result.
146
- *
147
- * Atomicity: nothing is written until every modification has been applied to the in-memory
148
- * document, and the write itself goes through a temp file in the same directory then a rename, so
149
- * a crash mid-command leaves world.json either wholly old or wholly new. A half-written world is
150
- * worse than an unchanged one — the creator has no way to tell which half landed, and a forge is
151
- * expensive enough that "run it again" is not an acceptable recovery.
152
- */
153
- export function applyModificationsToWorld(worldPath, modifications) {
134
+ export function applyModificationsToWorld(worldPath, modifications, options = {}) {
135
+ const subject = options.subject ?? 'The forged level';
154
136
  const world = readWorldJson(worldPath);
155
137
  // Baseline BEFORE applying: a violation already present in a legacy or imported world must not
156
138
  // block an unrelated write. Only violations this batch INTRODUCES are refused.
157
139
  const preExisting = new Set(validateWorldData(world));
158
- const summary = modifications.map((modification) => applyOne(world, modification));
140
+ const results = modifications.map((modification) => applyOne(world, modification));
141
+ const summary = results.map((result) => result.summary);
159
142
  // The engine statically casts world.json to Partial<GameData> (game/src/bundle/WorldDataLoader.ts),
160
143
  // so a non-conforming document breaks `tsc` in a file the creator cannot edit. The gate matters
161
144
  // more in this lane than in the web one: by the time it runs the design and geometry are already
@@ -166,10 +149,10 @@ export function applyModificationsToWorld(worldPath, modifications) {
166
149
  // failure path in this function already makes.
167
150
  const introduced = validateWorldData(world).filter((error) => !preExisting.has(error));
168
151
  if (introduced.length > 0) {
169
- throw new CliError(`The forged level would make ${path.basename(worldPath)} invalid against the engine's GameData `
152
+ throw new CliError(`${subject} would make ${path.basename(worldPath)} invalid against the engine's GameData `
170
153
  + `schema, so nothing was written. Violations: ${introduced.join('; ')}`);
171
154
  }
172
155
  writeWorldJsonAtomic(worldPath, world);
173
- return { applied: modifications.length, summary };
156
+ return { applied: modifications.length, summary, changed: results.map((result) => result.changed) };
174
157
  }
175
158
  //# sourceMappingURL=apply-modifications.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply-modifications.js","sourceRoot":"","sources":["../../src/forge/apply-modifications.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apply-modifications.js","sourceRoot":"","sources":["../../src/forge/apply-modifications.ts"],"names":[],"mappings":"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"}
@@ -187,10 +187,15 @@ export class ForgeBrowserHost {
187
187
  });
188
188
  }
189
189
  catch {
190
- // Not a forge failure. Saying so plainly matters: an agent told "the forge failed" would
191
- // start editing game code to fix a missing browser.
192
- throw new CliError('Could not launch Google Chrome. `bitmagic forge` bakes the world in the Chrome ' +
193
- 'installed on this machine install it from https://www.google.com/chrome/ and try again.');
190
+ // Not a failure of whatever the creator actually asked for. Saying so plainly matters: an
191
+ // agent told "the forge failed" would start editing game code to fix a missing browser.
192
+ //
193
+ // Deliberately does NOT name a command. Four of them reach this line — `forge`, `generate
194
+ // prop`, `generate vehicle` and `assets add` — so naming one sends the other three's users
195
+ // looking at something they never ran.
196
+ throw new CliError('Could not launch Google Chrome. Only the engine can voxelize, so this command drives the ' +
197
+ 'Chrome installed on this machine — install it from https://www.google.com/chrome/ and ' +
198
+ 'try again.');
194
199
  }
195
200
  this.log('Forge browser launched (headless Chrome).');
196
201
  }
@@ -1 +1 @@
1
- {"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/forge/browser-host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/forge/browser-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * One headless engine, ready to voxelize — the arrangement `bitmagic generate prop`, `generate
3
+ * vehicle` and `assets add <file.glb>` all need and none should own.
4
+ *
5
+ * Only the engine can voxelize, so each of those runs the project's own game in a headless Chrome
6
+ * and talks to it over the forge transport. Getting there is five steps in a fixed order, and the
7
+ * teardown has to run in the reverse order whatever happened:
8
+ *
9
+ * 1. reserve a port in 3000–3199 — the only origins the asset CDN allows, so the page can fetch
10
+ * the project's assets and the GLB it is about to bake;
11
+ * 2. spawn the project's vendored `vite` on it, and wait for it;
12
+ * 3. start the upload proxy — the engine uploads the baked `.vxl` itself, to a presigned URL it
13
+ * asks for at a hardcoded path with no credentials, and the proxy turns that into the
14
+ * authenticated api-server route while keeping the token out of the page
15
+ * (see `upload-proxy.ts`);
16
+ * 4. launch Chrome on the page and wait for the game to load;
17
+ * 5. run the caller's body against `host.transport`, then close the page (it may be mid-upload),
18
+ * then the proxy it was uploading through, then the server underneath both.
19
+ *
20
+ * Three commands carrying three copies of this is how a fix to one of them fails to reach the
21
+ * other two, so it lives here once. The two setup failures a creator can actually hit — no free
22
+ * port, vite not coming up — are reported with the caller's own `retryHint`, because what is kept
23
+ * and how to retry differs per command (a paid mesh, a paid vehicle design, an already-uploaded
24
+ * file) and that sentence is the useful part of the message.
25
+ */
26
+ import { type ChildProcess } from 'child_process';
27
+ import type { Environment } from '../config/environments.js';
28
+ import { ForgeBrowserHost } from './browser-host.js';
29
+ import { type ProjectContext } from '../project/context.js';
30
+ /** Voxelizing a dense mesh is minutes of work in the browser, not seconds. */
31
+ export declare const VOXELIZE_TIMEOUT_MS: number;
32
+ export interface VoxelizeSessionOptions {
33
+ context: ProjectContext;
34
+ environment: Environment;
35
+ token: string;
36
+ log: (message: string) => void;
37
+ /**
38
+ * What cannot happen if the browser does not come up — "the mesh", "the vehicle",
39
+ * `"tree.glb"` — completing "…so ${subject} cannot be voxelized."
40
+ */
41
+ subject: string;
42
+ /** Appended to a setup failure: what has been kept and the command that retries it. */
43
+ retryHint: string;
44
+ }
45
+ export interface VoxelizeSession {
46
+ host: ForgeBrowserHost;
47
+ /** The port the game is served on — handy for a unique transport `requestId`. */
48
+ port: number;
49
+ }
50
+ export declare function withVoxelizeSession<T>(options: VoxelizeSessionOptions, body: (session: VoxelizeSession) => Promise<T>): Promise<T>;
51
+ /**
52
+ * Run one teardown step, reporting a failure rather than propagating it. Cleanup must never mask
53
+ * the error that caused it, and must never stop the steps that follow.
54
+ */
55
+ export declare function closeQuietly(what: string, close: () => Promise<void> | undefined, log: (message: string) => void): Promise<void>;
56
+ /**
57
+ * Stop vite, then stop waiting for it. `unref` matters as much as the signal: the child was
58
+ * spawned with a piped stderr, so its handle keeps the parent's event loop alive and a vite that
59
+ * ignores SIGTERM left the CLI hanging after it had already printed its result.
60
+ */
61
+ export declare function killQuietly(server: ChildProcess, log: (message: string) => void): void;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * One headless engine, ready to voxelize — the arrangement `bitmagic generate prop`, `generate
3
+ * vehicle` and `assets add <file.glb>` all need and none should own.
4
+ *
5
+ * Only the engine can voxelize, so each of those runs the project's own game in a headless Chrome
6
+ * and talks to it over the forge transport. Getting there is five steps in a fixed order, and the
7
+ * teardown has to run in the reverse order whatever happened:
8
+ *
9
+ * 1. reserve a port in 3000–3199 — the only origins the asset CDN allows, so the page can fetch
10
+ * the project's assets and the GLB it is about to bake;
11
+ * 2. spawn the project's vendored `vite` on it, and wait for it;
12
+ * 3. start the upload proxy — the engine uploads the baked `.vxl` itself, to a presigned URL it
13
+ * asks for at a hardcoded path with no credentials, and the proxy turns that into the
14
+ * authenticated api-server route while keeping the token out of the page
15
+ * (see `upload-proxy.ts`);
16
+ * 4. launch Chrome on the page and wait for the game to load;
17
+ * 5. run the caller's body against `host.transport`, then close the page (it may be mid-upload),
18
+ * then the proxy it was uploading through, then the server underneath both.
19
+ *
20
+ * Three commands carrying three copies of this is how a fix to one of them fails to reach the
21
+ * other two, so it lives here once. The two setup failures a creator can actually hit — no free
22
+ * port, vite not coming up — are reported with the caller's own `retryHint`, because what is kept
23
+ * and how to retry differs per command (a paid mesh, a paid vehicle design, an already-uploaded
24
+ * file) and that sentence is the useful part of the message.
25
+ */
26
+ import { spawn } from 'child_process';
27
+ import { CliError } from '../errors.js';
28
+ import { ForgeBrowserHost, readProjectGameData } from './browser-host.js';
29
+ import { startUploadProxy } from './upload-proxy.js';
30
+ import { reserveCorsAllowedPort } from '../local-port.js';
31
+ import { projectBin } from '../project/context.js';
32
+ import { waitForServer } from '../verify/wait-for-server.js';
33
+ /** Voxelizing a dense mesh is minutes of work in the browser, not seconds. */
34
+ export const VOXELIZE_TIMEOUT_MS = 10 * 60 * 1000;
35
+ /** Enough of vite's stderr to diagnose a failed start; see the accumulator in withVoxelizeSession. */
36
+ const MAX_VITE_STDERR_CHARS = 16_000;
37
+ export async function withVoxelizeSession(options, body) {
38
+ const { context, environment, token, log, subject, retryHint } = options;
39
+ const port = await reserveCorsAllowedPort();
40
+ if (port === null) {
41
+ throw new CliError('No free port between 3000 and 3199, which is the only range the asset CDN serves. '
42
+ + `Stop something in that range and retry.\n${retryHint}`);
43
+ }
44
+ const vite = projectBin(context.root, 'vite');
45
+ let server;
46
+ let host;
47
+ let uploadProxy;
48
+ try {
49
+ server = spawn(vite, ['--port', String(port), '--strictPort'], {
50
+ cwd: context.root,
51
+ stdio: ['ignore', 'ignore', 'pipe'],
52
+ });
53
+ // A ChildProcess is an EventEmitter, and an 'error' event with NO listener is rethrown as an
54
+ // uncaught exception — killing the process before the `finally` below and before the designed
55
+ // message. `projectBin` only checks that the file exists, so a node_modules restored from an
56
+ // archive that dropped the executable bit spawns EACCES and used to end in a raw Node crash
57
+ // dump. Recorded and left to `waitForServer` to report.
58
+ let spawnError = null;
59
+ server.on('error', (error) => { spawnError = error; });
60
+ // Bounded: this is only ever read by the failure path below, and an unbounded accumulator over
61
+ // a ten-minute bake of a chatty vite is a leak in the same process that holds the voxel payload.
62
+ let viteStderr = '';
63
+ server.stderr?.on('data', (chunk) => {
64
+ if (viteStderr.length < MAX_VITE_STDERR_CHARS)
65
+ viteStderr += String(chunk);
66
+ });
67
+ try {
68
+ await waitForServer(port, 30_000);
69
+ }
70
+ catch {
71
+ const spawnDetail = spawnError !== null ? `\nCould not start ${vite}: ${spawnError.message}` : '';
72
+ throw new CliError(`The project's dev server did not come up on port ${port}, so ${subject} cannot be voxelized.`
73
+ + spawnDetail
74
+ + (viteStderr.trim() ? `\n${viteStderr.trim()}` : '')
75
+ + `\n${retryHint}`);
76
+ }
77
+ uploadProxy = await startUploadProxy({
78
+ apiUrl: environment.apiUrl,
79
+ token,
80
+ gameId: context.metadata.gameId,
81
+ log,
82
+ });
83
+ host = new ForgeBrowserHost({
84
+ gamePort: port,
85
+ gameId: context.metadata.gameId,
86
+ gameData: readProjectGameData(context.root, context.metadata),
87
+ agentUrl: uploadProxy.url,
88
+ log,
89
+ });
90
+ await host.launch();
91
+ await host.loadGame();
92
+ return await body({ host, port });
93
+ }
94
+ finally {
95
+ // Ordered: the page first (it may still be mid-upload), then the proxy it was uploading
96
+ // through, then the server underneath both.
97
+ //
98
+ // EACH STEP IS INDEPENDENT. These used to be three bare awaits, so a rejection from
99
+ // `host.close()` — routine after a renderer crash, since it ends in an rmSync over a live
100
+ // Chrome profile dir — skipped the other two: the proxy holding the creator's token stayed
101
+ // bound and vite survived as an orphan squatting one of the 200 ports the asset CDN allows,
102
+ // until every later bake failed with "No free port between 3000 and 3199". A teardown error
103
+ // also replaced the real failure (and the return value) on its way out.
104
+ await closeQuietly('the forge browser', () => host?.close(), log);
105
+ await closeQuietly('the upload proxy', () => uploadProxy?.close(), log);
106
+ if (server)
107
+ killQuietly(server, log);
108
+ }
109
+ }
110
+ /**
111
+ * Run one teardown step, reporting a failure rather than propagating it. Cleanup must never mask
112
+ * the error that caused it, and must never stop the steps that follow.
113
+ */
114
+ export async function closeQuietly(what, close, log) {
115
+ try {
116
+ await close();
117
+ }
118
+ catch (error) {
119
+ log(`Warning: could not close ${what}: ${error instanceof Error ? error.message : String(error)}`);
120
+ }
121
+ }
122
+ /**
123
+ * Stop vite, then stop waiting for it. `unref` matters as much as the signal: the child was
124
+ * spawned with a piped stderr, so its handle keeps the parent's event loop alive and a vite that
125
+ * ignores SIGTERM left the CLI hanging after it had already printed its result.
126
+ */
127
+ export function killQuietly(server, log) {
128
+ try {
129
+ server.kill('SIGTERM');
130
+ server.stderr?.removeAllListeners('data');
131
+ server.unref();
132
+ }
133
+ catch (error) {
134
+ log(`Warning: could not stop the dev server: ${error instanceof Error ? error.message : String(error)}`);
135
+ }
136
+ }
137
+ //# sourceMappingURL=voxelize-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voxelize-session.js","sourceRoot":"","sources":["../../src/forge/voxelize-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { Environment } from '../config/environments.js';
2
+ import { type VoxelizeFlags, type VoxelizeGlb } from '../assets/voxelize-glb.js';
3
+ import type { ProjectContext } from '../project/context.js';
4
+ export interface GenerateModelOptions {
5
+ context: ProjectContext;
6
+ environment: Environment;
7
+ token: string;
8
+ prompt: string;
9
+ /** Asset name; defaults to a slug of the prompt. This is the name game code places by. */
10
+ name?: string;
11
+ /** Pre-minted `asset_…` id, so code already referencing it resolves once this lands. */
12
+ assetId?: string;
13
+ voxel: VoxelizeFlags;
14
+ /** Skip the paid generation and bake this mesh instead — how a failed run is retried for free. */
15
+ glbUrl?: string;
16
+ fetchImpl?: typeof globalThis.fetch;
17
+ /** Injected in tests so the lane is exercised without Chrome. */
18
+ voxelize?: VoxelizeGlb;
19
+ now?: () => Date;
20
+ log: (message: string) => void;
21
+ }
22
+ export interface GenerateModelResult {
23
+ assetId: string;
24
+ assetName: string;
25
+ assetUrl?: string;
26
+ voxelCount?: number;
27
+ /** The mesh this was baked from — carried so a later failure can be retried without paying. */
28
+ glbUrl: string;
29
+ }
30
+ /**
31
+ * A usable asset name from the creator's sentence. Names are what game code places by, so this
32
+ * favours something short and typeable over something faithful: the prompt itself is kept on the
33
+ * asset's `description`, which is where the full wording belongs.
34
+ */
35
+ export declare function modelNameFromPrompt(prompt: string): string;
36
+ export declare function generateAndInstallModel(options: GenerateModelOptions): Promise<GenerateModelResult>;