@bitmagic/world-forger 0.1.0

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 (105) hide show
  1. package/dist/artifact-types.d.ts +295 -0
  2. package/dist/artifact-types.d.ts.map +1 -0
  3. package/dist/artifact-types.js +17 -0
  4. package/dist/artifact-types.js.map +1 -0
  5. package/dist/forge-constants.d.ts +106 -0
  6. package/dist/forge-constants.d.ts.map +1 -0
  7. package/dist/forge-constants.js +111 -0
  8. package/dist/forge-constants.js.map +1 -0
  9. package/dist/index.d.ts +28 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +28 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/log.d.ts +26 -0
  14. package/dist/log.d.ts.map +1 -0
  15. package/dist/log.js +14 -0
  16. package/dist/log.js.map +1 -0
  17. package/dist/pipeline/archetype-skips.d.ts +57 -0
  18. package/dist/pipeline/archetype-skips.d.ts.map +1 -0
  19. package/dist/pipeline/archetype-skips.js +51 -0
  20. package/dist/pipeline/archetype-skips.js.map +1 -0
  21. package/dist/pipeline/artifact-store.d.ts +4 -0
  22. package/dist/pipeline/artifact-store.d.ts.map +1 -0
  23. package/dist/pipeline/artifact-store.js +10 -0
  24. package/dist/pipeline/artifact-store.js.map +1 -0
  25. package/dist/pipeline/asset-catalog.d.ts +27 -0
  26. package/dist/pipeline/asset-catalog.d.ts.map +1 -0
  27. package/dist/pipeline/asset-catalog.js +47 -0
  28. package/dist/pipeline/asset-catalog.js.map +1 -0
  29. package/dist/pipeline/create-level-archetypes.d.ts +45 -0
  30. package/dist/pipeline/create-level-archetypes.d.ts.map +1 -0
  31. package/dist/pipeline/create-level-archetypes.js +197 -0
  32. package/dist/pipeline/create-level-archetypes.js.map +1 -0
  33. package/dist/pipeline/deps.d.ts +72 -0
  34. package/dist/pipeline/deps.d.ts.map +1 -0
  35. package/dist/pipeline/deps.js +2 -0
  36. package/dist/pipeline/deps.js.map +1 -0
  37. package/dist/pipeline/errors.d.ts +10 -0
  38. package/dist/pipeline/errors.d.ts.map +1 -0
  39. package/dist/pipeline/errors.js +13 -0
  40. package/dist/pipeline/errors.js.map +1 -0
  41. package/dist/pipeline/forged-work-store.d.ts +46 -0
  42. package/dist/pipeline/forged-work-store.d.ts.map +1 -0
  43. package/dist/pipeline/forged-work-store.js +69 -0
  44. package/dist/pipeline/forged-work-store.js.map +1 -0
  45. package/dist/pipeline/index.d.ts +36 -0
  46. package/dist/pipeline/index.d.ts.map +1 -0
  47. package/dist/pipeline/index.js +36 -0
  48. package/dist/pipeline/index.js.map +1 -0
  49. package/dist/pipeline/job-types.d.ts +145 -0
  50. package/dist/pipeline/job-types.d.ts.map +1 -0
  51. package/dist/pipeline/job-types.js +2 -0
  52. package/dist/pipeline/job-types.js.map +1 -0
  53. package/dist/pipeline/level-registry.d.ts +57 -0
  54. package/dist/pipeline/level-registry.d.ts.map +1 -0
  55. package/dist/pipeline/level-registry.js +108 -0
  56. package/dist/pipeline/level-registry.js.map +1 -0
  57. package/dist/pipeline/model-types.d.ts +51 -0
  58. package/dist/pipeline/model-types.d.ts.map +1 -0
  59. package/dist/pipeline/model-types.js +2 -0
  60. package/dist/pipeline/model-types.js.map +1 -0
  61. package/dist/pipeline/persist-level.d.ts +82 -0
  62. package/dist/pipeline/persist-level.d.ts.map +1 -0
  63. package/dist/pipeline/persist-level.js +201 -0
  64. package/dist/pipeline/persist-level.js.map +1 -0
  65. package/dist/pipeline/place-and-persist-level.d.ts +83 -0
  66. package/dist/pipeline/place-and-persist-level.d.ts.map +1 -0
  67. package/dist/pipeline/place-and-persist-level.js +405 -0
  68. package/dist/pipeline/place-and-persist-level.js.map +1 -0
  69. package/dist/pipeline/request-id.d.ts +7 -0
  70. package/dist/pipeline/request-id.d.ts.map +1 -0
  71. package/dist/pipeline/request-id.js +10 -0
  72. package/dist/pipeline/request-id.js.map +1 -0
  73. package/dist/pipeline/spawn-points.d.ts +47 -0
  74. package/dist/pipeline/spawn-points.d.ts.map +1 -0
  75. package/dist/pipeline/spawn-points.js +100 -0
  76. package/dist/pipeline/spawn-points.js.map +1 -0
  77. package/dist/pipeline/starter-scatter.d.ts +34 -0
  78. package/dist/pipeline/starter-scatter.d.ts.map +1 -0
  79. package/dist/pipeline/starter-scatter.js +49 -0
  80. package/dist/pipeline/starter-scatter.js.map +1 -0
  81. package/dist/pipeline/storage-types.d.ts +48 -0
  82. package/dist/pipeline/storage-types.d.ts.map +1 -0
  83. package/dist/pipeline/storage-types.js +19 -0
  84. package/dist/pipeline/storage-types.js.map +1 -0
  85. package/dist/pipeline/transport-types.d.ts +35 -0
  86. package/dist/pipeline/transport-types.d.ts.map +1 -0
  87. package/dist/pipeline/transport-types.js +2 -0
  88. package/dist/pipeline/transport-types.js.map +1 -0
  89. package/dist/pipeline/voxelize-level.d.ts +24 -0
  90. package/dist/pipeline/voxelize-level.d.ts.map +1 -0
  91. package/dist/pipeline/voxelize-level.js +63 -0
  92. package/dist/pipeline/voxelize-level.js.map +1 -0
  93. package/dist/pipeline/world-json-source.d.ts +78 -0
  94. package/dist/pipeline/world-json-source.d.ts.map +1 -0
  95. package/dist/pipeline/world-json-source.js +2 -0
  96. package/dist/pipeline/world-json-source.js.map +1 -0
  97. package/dist/pipeline/world-json-types.d.ts +104 -0
  98. package/dist/pipeline/world-json-types.d.ts.map +1 -0
  99. package/dist/pipeline/world-json-types.js +15 -0
  100. package/dist/pipeline/world-json-types.js.map +1 -0
  101. package/dist/terrain-height-grid.d.ts +45 -0
  102. package/dist/terrain-height-grid.d.ts.map +1 -0
  103. package/dist/terrain-height-grid.js +50 -0
  104. package/dist/terrain-height-grid.js.map +1 -0
  105. package/package.json +72 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/pipeline/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAEvC,YAAY,OAAe,EAAE,MAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Forged-work store — the resume state for a world-forger run.
3
+ *
4
+ * The pipeline is split into independent steps (design → forge+upload →
5
+ * archetypes → voxelize → place+persist), some of which take many minutes
6
+ * (a level bake can run up to 20). To make a failed long step resumable
7
+ * WITHOUT redoing the expensive ones, every step writes its serializable
8
+ * output as a small JSON artifact under `worlds/v3/forged-work/{jobId}/`.
9
+ * A resumed run skips any step whose output artifact already exists.
10
+ *
11
+ * Nothing binary crosses a step boundary: the world GLB and each archetype
12
+ * GLB are uploaded to storage by the forge step and referenced by URL, so
13
+ * every artifact here is plain JSON.
14
+ *
15
+ * jobId is minted fresh per logical run (see {@link newForgeJobId}); a retry
16
+ * RESUMES by passing the same jobId back. Because each fresh run gets a unique
17
+ * id, artifacts never collide across unrelated runs — so the store needs no
18
+ * delete primitive. Leftover artifacts are tiny JSON and consistent with the
19
+ * un-GC'd source GLB uploads the forge already makes; bucket lifecycle rules
20
+ * can sweep the prefix.
21
+ *
22
+ * Moved from game-play-agent verbatim, keeping the SAME two-parameter seam
23
+ * (`createForgedWorkStore(jobId, env)`) — see ForgeDeps.storage in deps.ts.
24
+ * No default `env` here: unlike the game-play-agent original (which defaulted
25
+ * to `getStorageEnv()`), this package has no host storage config to fall
26
+ * back to, so every caller must pass one explicitly.
27
+ */
28
+ import type { ForgeStorageEnv } from './storage-types.js';
29
+ /** One artifact per pipeline step, plus `input` (the job's frozen request) and
30
+ * `persisted` (the job-complete marker = the final tool summary). */
31
+ export type ForgeArtifactName = 'input' | 'spec' | 'platformer-movement' | 'forge' | 'archetype-progress' | 'archetype-assets' | 'level-bake' | 'persisted';
32
+ export interface ForgedWorkStore {
33
+ readonly jobId: string;
34
+ put(name: ForgeArtifactName, value: unknown): Promise<void>;
35
+ get<T>(name: ForgeArtifactName): Promise<T | null>;
36
+ has(name: ForgeArtifactName): Promise<boolean>;
37
+ }
38
+ /** Create a store bound to one jobId, backed by the host's storage env. */
39
+ export declare function createForgedWorkStore(jobId: string, env: ForgeStorageEnv): ForgedWorkStore;
40
+ /**
41
+ * Mint a fresh, unique job id for a new world-forger run. A retry that wants to
42
+ * resume passes this id back instead of minting a new one. The level name is
43
+ * embedded for readability when browsing the bucket.
44
+ */
45
+ export declare function newForgeJobId(levelName: string): string;
46
+ //# sourceMappingURL=forged-work-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forged-work-store.d.ts","sourceRoot":"","sources":["../../src/pipeline/forged-work-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAK1D;sEACsE;AACtE,MAAM,MAAM,iBAAiB,GACzB,OAAO,GACP,MAAM,GAGN,qBAAqB,GACrB,OAAO,GAIP,oBAAoB,GACpB,kBAAkB,GAClB,YAAY,GACZ,WAAW,CAAC;AAIhB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACnD,GAAG,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD;AAMD,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,eAAe,CAuB1F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGvD"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Forged-work store — the resume state for a world-forger run.
3
+ *
4
+ * The pipeline is split into independent steps (design → forge+upload →
5
+ * archetypes → voxelize → place+persist), some of which take many minutes
6
+ * (a level bake can run up to 20). To make a failed long step resumable
7
+ * WITHOUT redoing the expensive ones, every step writes its serializable
8
+ * output as a small JSON artifact under `worlds/v3/forged-work/{jobId}/`.
9
+ * A resumed run skips any step whose output artifact already exists.
10
+ *
11
+ * Nothing binary crosses a step boundary: the world GLB and each archetype
12
+ * GLB are uploaded to storage by the forge step and referenced by URL, so
13
+ * every artifact here is plain JSON.
14
+ *
15
+ * jobId is minted fresh per logical run (see {@link newForgeJobId}); a retry
16
+ * RESUMES by passing the same jobId back. Because each fresh run gets a unique
17
+ * id, artifacts never collide across unrelated runs — so the store needs no
18
+ * delete primitive. Leftover artifacts are tiny JSON and consistent with the
19
+ * un-GC'd source GLB uploads the forge already makes; bucket lifecycle rules
20
+ * can sweep the prefix.
21
+ *
22
+ * Moved from game-play-agent verbatim, keeping the SAME two-parameter seam
23
+ * (`createForgedWorkStore(jobId, env)`) — see ForgeDeps.storage in deps.ts.
24
+ * No default `env` here: unlike the game-play-agent original (which defaulted
25
+ * to `getStorageEnv()`), this package has no host storage config to fall
26
+ * back to, so every caller must pass one explicitly.
27
+ */
28
+ import { createLogger } from '../log.js';
29
+ const log = createLogger('forged-work-store');
30
+ const PREFIX = 'worlds/v3/forged-work';
31
+ function keyFor(jobId, name) {
32
+ return `${PREFIX}/${jobId}/${name}.json`;
33
+ }
34
+ /** Create a store bound to one jobId, backed by the host's storage env. */
35
+ export function createForgedWorkStore(jobId, env) {
36
+ return {
37
+ jobId,
38
+ async put(name, value) {
39
+ await env.storageClient.putObject({
40
+ bucket: env.bucket,
41
+ key: keyFor(jobId, name),
42
+ body: new TextEncoder().encode(JSON.stringify(value)),
43
+ contentType: 'application/json',
44
+ // Resume state — must never be served stale from a CDN cache.
45
+ cacheControl: 'no-store, max-age=0',
46
+ });
47
+ log.info({ jobId, artifact: name }, 'Forged-work artifact written');
48
+ },
49
+ async get(name) {
50
+ const bytes = await env.storageClient.getObject({ bucket: env.bucket, key: keyFor(jobId, name) });
51
+ if (!bytes)
52
+ return null;
53
+ return JSON.parse(new TextDecoder().decode(bytes));
54
+ },
55
+ async has(name) {
56
+ return env.storageClient.headObject({ bucket: env.bucket, key: keyFor(jobId, name) });
57
+ },
58
+ };
59
+ }
60
+ /**
61
+ * Mint a fresh, unique job id for a new world-forger run. A retry that wants to
62
+ * resume passes this id back instead of minting a new one. The level name is
63
+ * embedded for readability when browsing the bucket.
64
+ */
65
+ export function newForgeJobId(levelName) {
66
+ const safe = levelName.replace(/[^a-zA-Z0-9_-]+/g, '_').slice(0, 24) || 'level';
67
+ return `${safe}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
68
+ }
69
+ //# sourceMappingURL=forged-work-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forged-work-store.js","sourceRoot":"","sources":["../../src/pipeline/forged-work-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAmB9C,MAAM,MAAM,GAAG,uBAAuB,CAAC;AASvC,SAAS,MAAM,CAAC,KAAa,EAAE,IAAuB;IACpD,OAAO,GAAG,MAAM,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC;AAC3C,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CAAC,KAAa,EAAE,GAAoB;IACvE,OAAO;QACL,KAAK;QACL,KAAK,CAAC,GAAG,CAAC,IAAuB,EAAE,KAAc;YAC/C,MAAM,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC;gBAChC,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC;gBACxB,IAAI,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBACrD,WAAW,EAAE,kBAAkB;gBAC/B,8DAA8D;gBAC9D,YAAY,EAAE,qBAAqB;aACpC,CAAC,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,8BAA8B,CAAC,CAAC;QACtE,CAAC;QACD,KAAK,CAAC,GAAG,CAAI,IAAuB;YAClC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAClG,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YACxB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAM,CAAC;QAC1D,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,IAAuB;YAC/B,OAAO,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC;IAChF,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Public entry point for the CLIENT half of the world-forger pipeline: steps
3
+ * 3-5 (archetype creation, level bake, place + persist) plus the host seams
4
+ * they run behind. Reachable as `@bitmagic/world-forger/pipeline/index.js`.
5
+ *
6
+ * Steps 1-2 — designing the scene with an LLM and forging its geometry — are
7
+ * private and are not published. A host that runs the whole five-step pipeline
8
+ * imports from both halves; a host that only drives the browser (the CLI)
9
+ * imports only this one.
10
+ *
11
+ * (Neither comment names the private package. `publish-npm.yml` hard-fails on
12
+ * that name appearing anywhere under the packed `dist/`, which is how an
13
+ * `import type` from it — erased from the .js but preserved verbatim in the
14
+ * emitted .d.ts — gets caught. A plain string search is only trustworthy if
15
+ * there is nothing legitimate for it to match.)
16
+ */
17
+ export * from './storage-types.js';
18
+ export * from './model-types.js';
19
+ export * from './transport-types.js';
20
+ export * from './world-json-types.js';
21
+ export * from './world-json-source.js';
22
+ export * from './deps.js';
23
+ export * from './forged-work-store.js';
24
+ export * from './job-types.js';
25
+ export * from './errors.js';
26
+ export * from './artifact-store.js';
27
+ export * from './asset-catalog.js';
28
+ export * from './create-level-archetypes.js';
29
+ export * from './voxelize-level.js';
30
+ export * from './place-and-persist-level.js';
31
+ export * from './persist-level.js';
32
+ export * from './level-registry.js';
33
+ export * from './spawn-points.js';
34
+ export * from './starter-scatter.js';
35
+ export * from './archetype-skips.js';
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Public entry point for the CLIENT half of the world-forger pipeline: steps
3
+ * 3-5 (archetype creation, level bake, place + persist) plus the host seams
4
+ * they run behind. Reachable as `@bitmagic/world-forger/pipeline/index.js`.
5
+ *
6
+ * Steps 1-2 — designing the scene with an LLM and forging its geometry — are
7
+ * private and are not published. A host that runs the whole five-step pipeline
8
+ * imports from both halves; a host that only drives the browser (the CLI)
9
+ * imports only this one.
10
+ *
11
+ * (Neither comment names the private package. `publish-npm.yml` hard-fails on
12
+ * that name appearing anywhere under the packed `dist/`, which is how an
13
+ * `import type` from it — erased from the .js but preserved verbatim in the
14
+ * emitted .d.ts — gets caught. A plain string search is only trustworthy if
15
+ * there is nothing legitimate for it to match.)
16
+ */
17
+ export * from './storage-types.js';
18
+ export * from './model-types.js';
19
+ export * from './transport-types.js';
20
+ export * from './world-json-types.js';
21
+ export * from './world-json-source.js';
22
+ export * from './deps.js';
23
+ export * from './forged-work-store.js';
24
+ export * from './job-types.js';
25
+ export * from './errors.js';
26
+ export * from './artifact-store.js';
27
+ export * from './asset-catalog.js';
28
+ export * from './create-level-archetypes.js';
29
+ export * from './voxelize-level.js';
30
+ export * from './place-and-persist-level.js';
31
+ export * from './persist-level.js';
32
+ export * from './level-registry.js';
33
+ export * from './spawn-points.js';
34
+ export * from './starter-scatter.js';
35
+ export * from './archetype-skips.js';
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pipeline/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,WAAW,CAAC;AAC1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Job input & artifact shapes shared across the pipeline steps (all
3
+ * JSON-serializable — nothing binary crosses a step boundary). Moved from
4
+ * game-play-agent's `pipeline.ts` verbatim: steps 3-5 (archetype creation,
5
+ * level bake, place+persist) consume `ForgeJobInput` and `ForgeArtifact`
6
+ * exactly as produced here.
7
+ */
8
+ import type { DungeonDoorDef, DungeonKeyItemDef, DungeonLightConfig, ForgedObjectSummary, ForgedPlacement, ForgedSpecView, ForgedTerrainBand, LevelVoxelizeOptions, ResolvedFeature, ResolvedPathFeature, WorldMarker } from '../artifact-types.js';
9
+ import type { ForgedHeightGrid } from '../terrain-height-grid.js';
10
+ /** The frozen request for one run, written once as the `input` artifact. */
11
+ export interface ForgeJobInput {
12
+ name: string;
13
+ prompt: string;
14
+ /** The user's request in their own words (the `prompt` above is the orchestrator's
15
+ * paraphrase). Threaded to the director + designer and persisted on the level asset
16
+ * so intent survives every handoff. */
17
+ originalUserPrompt?: string;
18
+ /** Build a city (street grid + buildings + landmarks) instead of natural terrain. */
19
+ cityMode?: boolean;
20
+ /** Build a third-person platformer journey (regions + gated passages + a golden-path spine). */
21
+ platformerMode?: boolean;
22
+ /** Build a freeform custom place (arena, fortress, camp — terrain + walk-in structures). */
23
+ freeformMode?: boolean;
24
+ /** Build a mission-graph DUNGEON (enclosed rooms + corridors under a flat terrain plate). */
25
+ dungeonMode?: boolean;
26
+ /** GAME-DESIGN.md contents (the overall game's type/scope/vision) — frozen at job start so the
27
+ * designer builds a level that fits the whole game, not just the prompt. */
28
+ gameDesign?: string;
29
+ sizeX?: number;
30
+ sizeZ?: number;
31
+ /** Pre-minted level asset id from the orchestrator's manifest. */
32
+ assetId?: string;
33
+ /** Explicit boot-level intent: true = the forged level becomes the start
34
+ * level, false = keep the current start. Omitted = first forge on a game
35
+ * becomes the start; later forges keep the current start. */
36
+ makeStartLevel?: boolean;
37
+ maxTerrainSurfaceVoxels?: number;
38
+ /** Game id resolved from world.json at job start (for upload key namespacing). */
39
+ gameId: string;
40
+ }
41
+ /** An archetype after its GLB has been uploaded — URL replaces the bytes. */
42
+ export interface ForgeArchetypeRef {
43
+ name: string;
44
+ /** Empty string for reused archetypes (no GLB is generated for them). */
45
+ glbUrl: string;
46
+ instanceCount: number;
47
+ collision: boolean;
48
+ /** Absent for reused archetypes (nothing is voxelized). */
49
+ assetVoxelOptions?: {
50
+ minVoxelSize: number;
51
+ maxVoxelSize: number;
52
+ fillInterior: boolean;
53
+ fitBox: {
54
+ x: number;
55
+ z: number;
56
+ height: number;
57
+ };
58
+ lod0Budget?: number;
59
+ };
60
+ /** Reuses an existing library asset: bake skipped, instances reference this id. */
61
+ reuse?: {
62
+ assetId: string;
63
+ assetName: string;
64
+ };
65
+ }
66
+ /** The serializable subset of the forged world — `glbBytes` become URLs. */
67
+ export interface ForgeArtifact {
68
+ glbUrl: string;
69
+ voxelizeOptions: LevelVoxelizeOptions;
70
+ archetypes: ForgeArchetypeRef[];
71
+ placements: ForgedPlacement[];
72
+ /** World-space terrain heightfield, persisted as a sidecar for post-forge placements. */
73
+ terrainHeightGrid: ForgedHeightGrid;
74
+ markers: WorldMarker[];
75
+ playerStart: WorldMarker;
76
+ playerStartYaw: number | null;
77
+ gameplayFeatures: Array<ResolvedFeature | ResolvedPathFeature>;
78
+ objectSummaries: ForgedObjectSummary[];
79
+ terrainBands: ForgedTerrainBand[];
80
+ /** WORLD-space sea level (null = no water). Optional: resumed runs may hold artifacts that predate it. */
81
+ waterLevelYWorld?: number | null;
82
+ /** Door leaves in WORLD space. `assetId` is injected at persist, `levelId` by the persist builder. */
83
+ dungeonDoors?: DungeonDoorDef[];
84
+ /** Key pickups in WORLD space; same injection points as the doors. */
85
+ dungeonKeyItems?: DungeonKeyItemDef[];
86
+ /** Archetype name → the `assets[].light` payload its instances emit (`EnvironmentLightSystem`). */
87
+ dungeonLightConfigs?: Record<string, DungeonLightConfig>;
88
+ /**
89
+ * Authored `#RRGGBB` → emissive strength. Also inside `voxelizeOptions` for
90
+ * the level bake; mirrored here because the ARCHETYPE bakes need it too and
91
+ * they run from this artifact alone.
92
+ */
93
+ dungeonEmissiveByColor?: Record<string, number>;
94
+ /**
95
+ * Uploaded `.bmnav` navmesh sidecar. Compiled against THIS forge's level
96
+ * transform, so it is uploaded with the GLBs (step 2) and pinned onto the
97
+ * baked level asset as `navUrl` (step 4).
98
+ */
99
+ navUrl?: string;
100
+ notes: string[];
101
+ /**
102
+ * The validated scene spec, carried verbatim onto the level asset record. The
103
+ * declared type is the NARROWED view (see artifact-types.ts) — the fields the
104
+ * persist step actually reads — because the full spec's schema is the
105
+ * designer's, not the client's.
106
+ */
107
+ spec: ForgedSpecView;
108
+ }
109
+ /** Result of the level bake (the engine's records). */
110
+ export interface LevelBakeArtifact {
111
+ vwldUrl: string;
112
+ bakedRecord: Record<string, unknown>;
113
+ nonEmptyChunkCount?: number;
114
+ totalLod0Leaves?: number;
115
+ totalTrimeshTriangles?: number;
116
+ /** Bake-time advisories (unmatched emissive colors) surfaced in the summary. */
117
+ notes?: string[];
118
+ }
119
+ /** The final tool summary — also the `persisted` job-complete marker. */
120
+ export interface ForgeLevelSummary {
121
+ asset_id: string;
122
+ asset_name: string;
123
+ asset_url: string;
124
+ glb_url: string;
125
+ player_start: {
126
+ x: number;
127
+ y: number;
128
+ z: number;
129
+ };
130
+ markers: Array<{
131
+ name: string;
132
+ x: number;
133
+ y: number;
134
+ z: number;
135
+ }>;
136
+ library_assets: Array<{
137
+ name: string;
138
+ asset_id: string;
139
+ instances: number;
140
+ }>;
141
+ gameplay_features: Array<ResolvedFeature | ResolvedPathFeature>;
142
+ terrain_bands: ForgedTerrainBand[];
143
+ message: string;
144
+ }
145
+ //# sourceMappingURL=job-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-types.d.ts","sourceRoot":"","sources":["../../src/pipeline/job-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=job-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-types.js","sourceRoot":"","sources":["../../src/pipeline/job-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import type { LevelEntry, WorldJsonModification, WorldJsonShape } from './world-json-types.js';
2
+ /**
3
+ * Shared helpers for the multi-level registry (`worldProfileData.levels`).
4
+ * Used by the manage-levels tool, set-map-asset, and the world-forger persist
5
+ * step so every writer applies the SAME invariants:
6
+ *
7
+ * - A level references a `type:'vwld'` asset by id.
8
+ * - Instances tagged `levelId` belong to that level; untagged = global.
9
+ * - Legacy mirror: `voxelUrl`, `spawnPoints`, `playerSpawnPosition` always
10
+ * mirror the START level so frozen game code boots correctly.
11
+ * - Conversion moment: the first level entry created for a game with an
12
+ * existing baked world (voxelUrl) synthesizes level 1 from that world and
13
+ * tags all currently-untagged instances with it.
14
+ *
15
+ * Moved here from game-play-agent's `utils/level-registry.ts` (which now
16
+ * re-exports this module) because the persist step it serves lives in this
17
+ * package. Pure: it computes modifications, it never applies them.
18
+ */
19
+ export declare function mintLevelId(): string;
20
+ export declare function getLevels(worldJson: WorldJsonShape): LevelEntry[];
21
+ export declare function isLevelsMode(worldJson: WorldJsonShape): boolean;
22
+ /** The start level entry (startLevelId else levels[0]); null in legacy mode. */
23
+ export declare function getStartLevel(worldJson: WorldJsonShape): LevelEntry | null;
24
+ /**
25
+ * Legacy-mirror modifications for a START level: frozen game code reads only
26
+ * `voxelUrl` / `spawnPoints` / `playerSpawnPosition`, so they must track the
27
+ * start level. Spawn mirrors are only written when the level owns spawn
28
+ * points — a level without its own spawns inherits the globals, which are
29
+ * then already correct.
30
+ */
31
+ export declare function buildStartLevelMirrors(level: LevelEntry, vwldUrl: string): WorldJsonModification[];
32
+ export interface ConversionResult {
33
+ modifications: WorldJsonModification[];
34
+ level1: LevelEntry;
35
+ }
36
+ /**
37
+ * Synthesize level 1 from the game's current baked world (the conversion
38
+ * moment's first half). Returns null for a procedural game (no voxelUrl);
39
+ * throws when `voxelUrl` matches no `type:'vwld'` asset (legacy .vxl
40
+ * heightfield maps and unregistered bakes cannot become levels).
41
+ */
42
+ export declare function synthesizeLevel1(worldJson: WorldJsonShape): LevelEntry | null;
43
+ /**
44
+ * Tag every currently-untagged instance with the given level id — after
45
+ * conversion, "untagged" means global-by-intent, so the legacy content must
46
+ * not silently become global.
47
+ */
48
+ export declare function tagUntaggedInstances(instances: Array<Record<string, unknown>>, levelId: string): Array<Record<string, unknown>>;
49
+ /**
50
+ * Conversion moment: synthesize level 1 from the game's current baked world.
51
+ *
52
+ * Returns null when the game is already in levels mode or has no baked world
53
+ * (procedural — the caller's new level becomes levels[0]). Throws when the
54
+ * current world is not a registered vwld asset (see synthesizeLevel1).
55
+ */
56
+ export declare function buildConversionModifications(worldJson: WorldJsonShape): ConversionResult | null;
57
+ //# sourceMappingURL=level-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level-registry.d.ts","sourceRoot":"","sources":["../../src/pipeline/level-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE/F;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,cAAc,GAAG,UAAU,EAAE,CAEjE;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAE/D;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,SAAS,EAAE,cAAc,GAAG,UAAU,GAAG,IAAI,CAK1E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,GACd,qBAAqB,EAAE,CAazB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,GAAG,UAAU,GAAG,IAAI,CAmB7E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,OAAO,EAAE,MAAM,GACd,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAEhC;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,cAAc,GAAG,gBAAgB,GAAG,IAAI,CAW/F"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Shared helpers for the multi-level registry (`worldProfileData.levels`).
3
+ * Used by the manage-levels tool, set-map-asset, and the world-forger persist
4
+ * step so every writer applies the SAME invariants:
5
+ *
6
+ * - A level references a `type:'vwld'` asset by id.
7
+ * - Instances tagged `levelId` belong to that level; untagged = global.
8
+ * - Legacy mirror: `voxelUrl`, `spawnPoints`, `playerSpawnPosition` always
9
+ * mirror the START level so frozen game code boots correctly.
10
+ * - Conversion moment: the first level entry created for a game with an
11
+ * existing baked world (voxelUrl) synthesizes level 1 from that world and
12
+ * tags all currently-untagged instances with it.
13
+ *
14
+ * Moved here from game-play-agent's `utils/level-registry.ts` (which now
15
+ * re-exports this module) because the persist step it serves lives in this
16
+ * package. Pure: it computes modifications, it never applies them.
17
+ */
18
+ export function mintLevelId() {
19
+ return `level_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
20
+ }
21
+ export function getLevels(worldJson) {
22
+ return worldJson.worldProfileData?.levels ?? [];
23
+ }
24
+ export function isLevelsMode(worldJson) {
25
+ return getLevels(worldJson).length > 0;
26
+ }
27
+ /** The start level entry (startLevelId else levels[0]); null in legacy mode. */
28
+ export function getStartLevel(worldJson) {
29
+ const levels = getLevels(worldJson);
30
+ if (levels.length === 0)
31
+ return null;
32
+ const startId = worldJson.worldProfileData?.startLevelId;
33
+ return levels.find((l) => l.id === startId) ?? levels[0];
34
+ }
35
+ /**
36
+ * Legacy-mirror modifications for a START level: frozen game code reads only
37
+ * `voxelUrl` / `spawnPoints` / `playerSpawnPosition`, so they must track the
38
+ * start level. Spawn mirrors are only written when the level owns spawn
39
+ * points — a level without its own spawns inherits the globals, which are
40
+ * then already correct.
41
+ */
42
+ export function buildStartLevelMirrors(level, vwldUrl) {
43
+ const mods = [
44
+ { type: 'set', path: ['voxelUrl'], value: vwldUrl },
45
+ ];
46
+ const spawns = level.spawnPoints ?? [];
47
+ if (spawns.length > 0) {
48
+ mods.push({ type: 'set', path: ['spawnPoints'], value: spawns });
49
+ const playerSpawn = spawns.find((s) => s.type === 'player');
50
+ if (playerSpawn?.position) {
51
+ mods.push({ type: 'set', path: ['playerSpawnPosition'], value: playerSpawn.position });
52
+ }
53
+ }
54
+ return mods;
55
+ }
56
+ /**
57
+ * Synthesize level 1 from the game's current baked world (the conversion
58
+ * moment's first half). Returns null for a procedural game (no voxelUrl);
59
+ * throws when `voxelUrl` matches no `type:'vwld'` asset (legacy .vxl
60
+ * heightfield maps and unregistered bakes cannot become levels).
61
+ */
62
+ export function synthesizeLevel1(worldJson) {
63
+ const voxelUrl = worldJson.worldProfileData?.voxelUrl;
64
+ if (!voxelUrl)
65
+ return null; // procedural game — nothing to synthesize
66
+ const vwldAsset = (worldJson.assets ?? []).find((a) => a.type === 'vwld' && a.url === voxelUrl);
67
+ if (!vwldAsset) {
68
+ throw new Error('This game\'s current world is not a registered vwld level asset (legacy map or unregistered bake) — re-bake the level before enabling multi-level.');
69
+ }
70
+ return {
71
+ id: mintLevelId(),
72
+ name: String(vwldAsset.name ?? 'Level 1'),
73
+ vwldAssetId: String(vwldAsset.id),
74
+ ...(worldJson.worldProfileData?.spawnPoints?.length
75
+ ? { spawnPoints: worldJson.worldProfileData.spawnPoints }
76
+ : {}),
77
+ };
78
+ }
79
+ /**
80
+ * Tag every currently-untagged instance with the given level id — after
81
+ * conversion, "untagged" means global-by-intent, so the legacy content must
82
+ * not silently become global.
83
+ */
84
+ export function tagUntaggedInstances(instances, levelId) {
85
+ return instances.map((o) => (o.levelId === undefined ? { ...o, levelId } : o));
86
+ }
87
+ /**
88
+ * Conversion moment: synthesize level 1 from the game's current baked world.
89
+ *
90
+ * Returns null when the game is already in levels mode or has no baked world
91
+ * (procedural — the caller's new level becomes levels[0]). Throws when the
92
+ * current world is not a registered vwld asset (see synthesizeLevel1).
93
+ */
94
+ export function buildConversionModifications(worldJson) {
95
+ if (isLevelsMode(worldJson))
96
+ return null;
97
+ const level1 = synthesizeLevel1(worldJson);
98
+ if (!level1)
99
+ return null;
100
+ const tagged = tagUntaggedInstances(worldJson.environmentObjects ?? [], level1.id);
101
+ const modifications = [
102
+ { type: 'set', path: ['levels'], value: [level1] },
103
+ { type: 'set', path: ['startLevelId'], value: level1.id },
104
+ { type: 'setRoot', path: ['environmentObjects'], value: tagged },
105
+ ];
106
+ return { modifications, level1 };
107
+ }
108
+ //# sourceMappingURL=level-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level-registry.js","sourceRoot":"","sources":["../../src/pipeline/level-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The model seam — the LLM client the director and designer call through.
3
+ *
4
+ * Shape mirrors the `ai` SDK's `LanguageModelUsage` (already the usage shape
5
+ * `streamText(...).usage` resolves to everywhere else in game-play-agent),
6
+ * not a reinvented one: the web lane's `ForgeModelClient` hands this back
7
+ * almost verbatim, and api-server's CLI-lane host prices straight from it
8
+ * without reshaping (`cli-forge.ts`'s `priceForgeUsageSparks`). `model` is
9
+ * the id that actually SERVED the call (from
10
+ * the provider's response, e.g. `LanguageModelResponseMetadata.modelId`) —
11
+ * fallback middleware can swap models mid-flight, and pricing must key on
12
+ * what ran, not what was requested.
13
+ *
14
+ * The designer permits up to MAX_ATTEMPTS design attempts (each up to 64k
15
+ * output tokens) plus JSON-repair calls, and the director makes its own
16
+ * calls — every one of them goes through `generateText` and reports its own
17
+ * usage here. Summing a job's cost is therefore the HOST's job (it is the
18
+ * one implementing this interface, so it sees every call as it happens);
19
+ * this package never aggregates usage itself.
20
+ */
21
+ export interface ForgeModelUsage {
22
+ /** The model id that actually served this call. */
23
+ model: string;
24
+ inputTokens: number;
25
+ outputTokens: number;
26
+ totalTokens: number;
27
+ /** Cached-read input tokens, when the provider reports them. */
28
+ cacheReadTokens?: number;
29
+ /** Cache-write (cache-creation) input tokens, when the provider reports them. */
30
+ cacheWriteTokens?: number;
31
+ }
32
+ export interface ForgeModelResult {
33
+ text: string;
34
+ usage: ForgeModelUsage;
35
+ }
36
+ export interface ForgeModelGenerateParams {
37
+ system: string;
38
+ prompt: string;
39
+ /** Output-token ceiling. The designer sets this explicitly and deliberately
40
+ * large (see DESIGNER_MAX_OUTPUT_TOKENS in designer.ts) — omit only for
41
+ * small calls (the director's one-line decision) where a provider default
42
+ * is fine. */
43
+ maxOutputTokens?: number;
44
+ }
45
+ /** The LLM seam the designer + director call through. No model selection,
46
+ * no fallback policy, no provider SDK — the host decides all of that and
47
+ * hands in a client that already embeds the choice. */
48
+ export interface ForgeModelClient {
49
+ generateText(params: ForgeModelGenerateParams): Promise<ForgeModelResult>;
50
+ }
51
+ //# sourceMappingURL=model-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-types.d.ts","sourceRoot":"","sources":["../../src/pipeline/model-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;;mBAGe;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;wDAEwD;AACxD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC3E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=model-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-types.js","sourceRoot":"","sources":["../../src/pipeline/model-types.ts"],"names":[],"mappings":""}