summer-engine 3.4.0 → 3.5.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 (290) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +5 -1
  3. package/.codex-plugin/plugin.json +5 -1
  4. package/.cursor-plugin/plugin.json +5 -1
  5. package/.factory-plugin/plugin.json +5 -1
  6. package/.opencode/INSTALL.md +8 -8
  7. package/.opencode/plugins/summer.js +2 -2
  8. package/AGENTS.md +7 -7
  9. package/CHANGELOG.md +37 -0
  10. package/GEMINI.md +1 -1
  11. package/NOTICE +1 -1
  12. package/README.md +35 -35
  13. package/assets/autopilot/run.sh +2 -2
  14. package/assets/navigation/web-routes.json +1 -1
  15. package/commands/gameskill.md +2 -2
  16. package/commands/summer.md +25 -25
  17. package/dist/cli/commands/open.d.ts +1 -1
  18. package/dist/cli/commands/run.d.ts +1 -1
  19. package/dist/cli/commands/run.js +1 -1
  20. package/dist/cli/commands/setup.js +24 -4
  21. package/dist/cli/commands/skills.js +2 -2
  22. package/dist/core/api-client.d.ts +5 -6
  23. package/dist/core/api-client.js +12 -15
  24. package/dist/core/auth.js +2 -2
  25. package/dist/core/capabilities/asset-import.d.ts +0 -1
  26. package/dist/core/capabilities/camera-view.d.ts +1 -1
  27. package/dist/core/capabilities/camera-view.js +2 -2
  28. package/dist/core/capabilities/capture-gameplay.d.ts +72 -7
  29. package/dist/core/capabilities/capture-gameplay.js +386 -25
  30. package/dist/core/capabilities/connect-signal.d.ts +1 -2
  31. package/dist/core/capabilities/connect-signal.js +1 -2
  32. package/dist/core/capabilities/console-read.d.ts +2 -2
  33. package/dist/core/capabilities/console-read.js +2 -2
  34. package/dist/core/capabilities/engine-receipt.d.ts +5 -7
  35. package/dist/core/capabilities/engine-receipt.js +7 -9
  36. package/dist/core/capabilities/export-engine-version.d.ts +7 -0
  37. package/dist/core/capabilities/export-engine-version.js +9 -0
  38. package/dist/core/capabilities/export-game.d.ts +4 -0
  39. package/dist/core/capabilities/export-game.js +53 -10
  40. package/dist/core/capabilities/export-presets.d.ts +1 -1
  41. package/dist/core/capabilities/export-presets.js +1 -1
  42. package/dist/core/capabilities/fabricate-mesh.d.ts +2 -3
  43. package/dist/core/capabilities/fabricate-mesh.js +2 -3
  44. package/dist/core/capabilities/frame-quality.d.ts +4 -4
  45. package/dist/core/capabilities/frame-quality.js +4 -4
  46. package/dist/core/capabilities/grep.d.ts +1 -1
  47. package/dist/core/capabilities/grep.js +1 -1
  48. package/dist/core/capabilities/image-generation.d.ts +12 -2
  49. package/dist/core/capabilities/image-generation.js +31 -2
  50. package/dist/core/capabilities/navigation/open.d.ts +1 -1
  51. package/dist/core/capabilities/navigation/open.js +1 -1
  52. package/dist/core/capabilities/navigation/render-product-map.js +1 -1
  53. package/dist/core/capabilities/navigation/targets.js +2 -2
  54. package/dist/core/capabilities/placement-batch.d.ts +1 -1
  55. package/dist/core/capabilities/placement-batch.js +2 -2
  56. package/dist/core/capabilities/play-determinism.d.ts +1 -1
  57. package/dist/core/capabilities/play-determinism.js +1 -1
  58. package/dist/core/capabilities/publish-build.d.ts +1 -1
  59. package/dist/core/capabilities/publish-build.js +21 -9
  60. package/dist/core/capabilities/publish-download.d.ts +1 -2
  61. package/dist/core/capabilities/publish-download.js +2 -3
  62. package/dist/core/capabilities/replace-node.d.ts +1 -3
  63. package/dist/core/capabilities/replace-node.js +1 -3
  64. package/dist/core/capabilities/runtime-control.d.ts +5 -7
  65. package/dist/core/capabilities/runtime-control.js +7 -9
  66. package/dist/core/capabilities/scene-batch.d.ts +1 -1
  67. package/dist/core/capabilities/scene-batch.js +1 -1
  68. package/dist/core/capabilities/scene-kind.js +1 -1
  69. package/dist/core/capabilities/scene-readback.d.ts +3 -4
  70. package/dist/core/capabilities/scene-readback.js +3 -4
  71. package/dist/core/capabilities/scene-script.d.ts +2 -2
  72. package/dist/core/capabilities/scene-script.js +2 -2
  73. package/dist/core/capabilities/seeing/shot-store.d.ts +1 -1
  74. package/dist/core/capabilities/seeing/shot-store.js +1 -1
  75. package/dist/core/capabilities/summer-bundle.d.ts +11 -3
  76. package/dist/core/capabilities/summer-bundle.js +21 -3
  77. package/dist/core/capabilities/surface-snap.d.ts +1 -1
  78. package/dist/core/capabilities/surface-snap.js +1 -1
  79. package/dist/core/capabilities/tool-dispatch.js +14 -3
  80. package/dist/core/capabilities/ui-control.d.ts +1 -2
  81. package/dist/core/capabilities/ui-control.js +1 -2
  82. package/dist/core/capabilities/world-snapshot.d.ts +1 -1
  83. package/dist/core/capabilities/world-snapshot.js +1 -1
  84. package/dist/core/capability-skew.d.ts +2 -3
  85. package/dist/core/capability-skew.js +4 -5
  86. package/dist/core/feedback/client.js +1 -1
  87. package/dist/core/launch-posture.d.ts +3 -3
  88. package/dist/core/launch-posture.js +3 -3
  89. package/dist/core/library-read.d.ts +7 -0
  90. package/dist/core/library-read.js +60 -9
  91. package/dist/core/library-search.d.ts +2 -0
  92. package/dist/core/templates.d.ts +1 -2
  93. package/dist/core/templates.js +1 -2
  94. package/dist/installer/agent-config.d.ts +25 -0
  95. package/dist/installer/agent-config.js +114 -3
  96. package/dist/installer/agent-table.d.ts +12 -0
  97. package/dist/installer/agent-table.js +9 -0
  98. package/dist/mcp/server.d.ts +2 -2
  99. package/dist/mcp/server.js +2 -2
  100. package/dist/mcp/tools/creator-tools.js +33 -4
  101. package/dist/mcp/tools/debug-tools.js +1 -1
  102. package/dist/mcp/tools/generate-tools.js +18 -37
  103. package/dist/mcp/tools/library-tools.d.ts +2 -1
  104. package/dist/mcp/tools/library-tools.js +1 -0
  105. package/dist/mcp/tools/navigation-tools.d.ts +1 -1
  106. package/dist/mcp/tools/navigation-tools.js +1 -1
  107. package/dist/mcp/tools/spatial-tools.js +1 -1
  108. package/dist/mcp/tools/visual-tools.js +2 -2
  109. package/dist/mcp/tools/with-engine.d.ts +1 -2
  110. package/dist/mcp/tools/with-engine.js +1 -2
  111. package/gemini-extension.json +5 -1
  112. package/hooks/session-start.sh +2 -2
  113. package/integrations/README.md +70 -76
  114. package/integrations/claude/README.md +0 -3
  115. package/integrations/codex/README.md +1 -2
  116. package/integrations/copilot-jetbrains/README.md +1 -1
  117. package/integrations/cursor/README.md +1 -2
  118. package/integrations/factory/README.md +15 -11
  119. package/integrations/mistral-vibe/README.md +1 -1
  120. package/integrations/opencode/README.md +1 -1
  121. package/integrations/roo-code/README.md +1 -1
  122. package/integrations/rovo-dev/README.md +1 -1
  123. package/integrations/trae/README.md +1 -1
  124. package/integrations/windsurf/README.md +3 -3
  125. package/library/references/collaborative-protocol/collaborative-protocol.md +5 -5
  126. package/library/references/gd-style/gd-style.md +4 -6
  127. package/library/references/godot-version/godot-version.md +3 -3
  128. package/library/references/headless-routing/headless-routing.md +2 -2
  129. package/library/references/mcp-fresh-chat-playbook/mcp-fresh-chat-playbook.md +2 -2
  130. package/library/references/mcp-tools-reference/mcp-tools-reference.md +16 -15
  131. package/library/references/product-map/product-map.md +1 -1
  132. package/library/references/public-surface-language/public-surface-language.md +1 -1
  133. package/library/references/summer-folder/summer-folder.md +1 -1
  134. package/library/skills/3d-lighting/SKILL.md +4 -4
  135. package/library/skills/README.md +16 -6
  136. package/library/skills/adaptive-music/SKILL.md +7 -7
  137. package/library/skills/ai-characters-in-games/SKILL.md +1 -1
  138. package/library/skills/ambient-bed/SKILL.md +12 -14
  139. package/library/skills/animated-loop/SKILL.md +42 -42
  140. package/library/skills/animation-tree/SKILL.md +6 -6
  141. package/library/skills/art-direction/SKILL.md +8 -11
  142. package/library/skills/asset-strategy/SKILL.md +3 -3
  143. package/library/skills/audio-direction/SKILL.md +8 -10
  144. package/library/skills/auto-fire-targeting/SKILL.md +4 -3
  145. package/library/skills/bounded-engine-runs/SKILL.md +6 -7
  146. package/library/skills/brainstorm-game/SKILL.md +5 -5
  147. package/library/skills/brainstorming/SKILL.md +9 -15
  148. package/library/skills/celeste-momentum-platforming/SKILL.md +8 -13
  149. package/library/skills/celeste-momentum-platforming/resource.yaml +1 -1
  150. package/library/skills/character-animation-wiring/SKILL.md +2 -2
  151. package/library/skills/character-model/SKILL.md +15 -26
  152. package/library/skills/character-movement/SKILL.md +1 -1
  153. package/library/skills/character-movement/references/movement-3d.md +1 -1
  154. package/library/skills/character-portrait/SKILL.md +4 -4
  155. package/library/skills/cinematic-cutscene/SKILL.md +38 -38
  156. package/library/skills/combat-basics/SKILL.md +1 -1
  157. package/library/skills/compatibility-renderer-traps/SKILL.md +2 -2
  158. package/library/skills/concept-art/SKILL.md +3 -3
  159. package/library/skills/create-asset-sheet/SKILL.md +12 -31
  160. package/library/skills/debug/SKILL.md +5 -4
  161. package/library/skills/debugging-game-feel/SKILL.md +1 -4
  162. package/library/skills/debugging-game-feel/resource.yaml +1 -1
  163. package/library/skills/design-level/SKILL.md +5 -5
  164. package/library/skills/design-mechanic/SKILL.md +6 -6
  165. package/library/skills/design-npc/SKILL.md +8 -15
  166. package/library/skills/diagnosing-perf-regressions/SKILL.md +5 -10
  167. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -19
  168. package/library/skills/environment-kit/SKILL.md +5 -5
  169. package/library/skills/export-and-ship/SKILL.md +24 -25
  170. package/library/skills/export-and-ship/resource.yaml +2 -1
  171. package/library/skills/fabricating-assets/SKILL.md +1 -1
  172. package/library/skills/facial-and-lipsync/SKILL.md +5 -5
  173. package/library/skills/fps-controller/SKILL.md +17 -16
  174. package/library/skills/fps-controller/resource.yaml +0 -2
  175. package/library/skills/game-feel/SKILL.md +6 -7
  176. package/library/skills/gameskill/SKILL.md +3 -3
  177. package/library/skills/gdscript-patterns/SKILL.md +3 -3
  178. package/library/skills/generate-motion/SKILL.md +5 -22
  179. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +72 -90
  180. package/library/skills/godogen-visual-proof-game-generation/resource.yaml +0 -1
  181. package/library/skills/grow-analytics/SKILL.md +21 -0
  182. package/library/skills/grow-analytics/resource.yaml +27 -0
  183. package/library/skills/headless-scripting/SKILL.md +8 -8
  184. package/library/skills/instantiate-asset-pack/SKILL.md +7 -3
  185. package/library/skills/investigating-bugs/SKILL.md +3 -11
  186. package/library/skills/investigating-bugs/condition-based-waiting.md +0 -10
  187. package/library/skills/investigating-bugs/root-cause-tracing.md +0 -8
  188. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +15 -15
  189. package/library/skills/lumera-single-image-scene-reconstruction/resource.yaml +0 -1
  190. package/library/skills/make-game/SKILL.md +3 -5
  191. package/library/skills/make-game/references/2d-platformer.md +1 -1
  192. package/library/skills/multiplayer-project/SKILL.md +1 -1
  193. package/library/skills/multiplayer-testing/SKILL.md +4 -4
  194. package/library/skills/music-track/SKILL.md +40 -38
  195. package/library/skills/new-project/SKILL.md +4 -6
  196. package/library/skills/organic-model/SKILL.md +9 -9
  197. package/library/skills/pixel-art/SKILL.md +6 -6
  198. package/library/skills/play/SKILL.md +3 -4
  199. package/library/skills/playtesting-a-feature/SKILL.md +4 -6
  200. package/library/skills/procedural-animation/SKILL.md +10 -11
  201. package/library/skills/prop-model/SKILL.md +4 -4
  202. package/library/skills/psx-retro-rendering/SKILL.md +20 -20
  203. package/library/skills/psx-retro-rendering/resource.yaml +2 -3
  204. package/library/skills/publish-your-game/SKILL.md +21 -0
  205. package/library/skills/publish-your-game/resource.yaml +29 -0
  206. package/library/skills/realtime-wet-surfaces/SKILL.md +15 -15
  207. package/library/skills/realtime-wet-surfaces/resource.yaml +1 -2
  208. package/library/skills/remote-deploy/SKILL.md +20 -21
  209. package/library/skills/retarget/SKILL.md +19 -23
  210. package/library/skills/running-in-the-cloud/SKILL.md +5 -5
  211. package/library/skills/scene-composition/SKILL.md +5 -5
  212. package/library/skills/scene-hierarchy-design/SKILL.md +3 -3
  213. package/library/skills/scene-hierarchy-design/resource.yaml +0 -1
  214. package/library/skills/scene-scripting/SKILL.md +3 -3
  215. package/library/skills/scene-to-level/SKILL.md +28 -31
  216. package/library/skills/skill-create/SKILL.md +1 -1
  217. package/library/skills/skill-improve/SKILL.md +9 -9
  218. package/library/skills/skill-test/SKILL.md +10 -10
  219. package/library/skills/skintokens-auto-rigging/SKILL.md +18 -18
  220. package/library/skills/skintokens-auto-rigging/resource.yaml +3 -3
  221. package/library/skills/skybox-panorama/SKILL.md +8 -9
  222. package/library/skills/sound-effect/SKILL.md +19 -19
  223. package/library/skills/spatial-placement/SKILL.md +2 -2
  224. package/library/skills/spatial-placement/references/kit-placement-tools.md +12 -22
  225. package/library/skills/sprite-sheet/SKILL.md +10 -10
  226. package/library/skills/store-art/SKILL.md +23 -0
  227. package/library/skills/store-art/resource.yaml +30 -0
  228. package/library/skills/store-listing/SKILL.md +21 -0
  229. package/library/skills/store-listing/resource.yaml +25 -0
  230. package/library/skills/summer-analytics/SKILL.md +3 -3
  231. package/library/skills/summer-analytics/resource.yaml +1 -0
  232. package/library/skills/summer-friends/SKILL.md +10 -10
  233. package/library/skills/summer-leaderboards/SKILL.md +6 -6
  234. package/library/skills/summer-match-results/SKILL.md +13 -13
  235. package/library/skills/summer-matchmaking/SKILL.md +11 -11
  236. package/library/skills/summer-parties/SKILL.md +9 -9
  237. package/library/skills/summer-player-data/SKILL.md +12 -12
  238. package/library/skills/summer-store/SKILL.md +6 -6
  239. package/library/skills/summer-world-chat/SKILL.md +9 -9
  240. package/library/skills/summer-world-saves/SKILL.md +7 -7
  241. package/library/skills/text-to-motion/rigging-for-text-motion.md +1 -1
  242. package/library/skills/tileable-texture/SKILL.md +1 -1
  243. package/library/skills/trailer-shot/SKILL.md +36 -36
  244. package/library/skills/tune-performance/SKILL.md +13 -13
  245. package/library/skills/tune-performance/resource.yaml +1 -1
  246. package/library/skills/ui-graphics/SKILL.md +7 -7
  247. package/library/skills/use-widget-asset/SKILL.md +7 -7
  248. package/library/skills/using-summer/SKILL.md +5 -7
  249. package/library/skills/vehicle-model/SKILL.md +6 -7
  250. package/library/skills/vehicle-model/resource.yaml +2 -2
  251. package/library/skills/verification-before-completion/SKILL.md +5 -6
  252. package/library/skills/vfx-dissolve/SKILL.md +4 -4
  253. package/library/skills/vfx-fire/SKILL.md +6 -6
  254. package/library/skills/vfx-fire/_building-blocks/additive-billboard-particles.md +3 -3
  255. package/library/skills/vfx-hit-spark/SKILL.md +4 -4
  256. package/library/skills/vfx-hit-spark/_building-blocks/additive-billboard-particles.md +3 -3
  257. package/library/skills/vfx-lightning/SKILL.md +5 -5
  258. package/library/skills/vfx-lightning/_building-blocks/additive-billboard-particles.md +3 -3
  259. package/library/skills/vfx-lightning/_building-blocks/trauma-shake-snippet.md +9 -3
  260. package/library/skills/vfx-magic-glow/SKILL.md +4 -4
  261. package/library/skills/vfx-magic-glow/_building-blocks/additive-billboard-particles.md +3 -3
  262. package/library/skills/vfx-muzzle-flash/SKILL.md +5 -5
  263. package/library/skills/vfx-muzzle-flash/_building-blocks/additive-billboard-particles.md +3 -3
  264. package/library/skills/vfx-muzzle-flash/_building-blocks/trauma-shake-snippet.md +9 -3
  265. package/library/skills/vfx-smoke/SKILL.md +5 -5
  266. package/library/skills/vfx-water-ripple/SKILL.md +2 -2
  267. package/library/skills/vfx-water-ripple/_building-blocks/additive-billboard-particles.md +3 -3
  268. package/library/skills/voice-line/SKILL.md +9 -9
  269. package/library/skills/world-building-3d/references/spatial-tools.md +2 -2
  270. package/library/skills/writing-plans/SKILL.md +4 -4
  271. package/library/skills/writing-skills/SKILL.md +8 -8
  272. package/library/tools/capture-gameplay/resource.yaml +66 -1
  273. package/library/tools/creator-publish/resource.yaml +4 -4
  274. package/library/tools/creator-releases/resource.yaml +5 -5
  275. package/library/tools/export-game/resource.yaml +3 -0
  276. package/library/tools/generate-image/resource.yaml +4 -2
  277. package/library/tools/publish-build/resource.yaml +5 -1
  278. package/package.json +1 -1
  279. package/registry/generated/counts.json +2 -2
  280. package/registry/generated/gemini-extension.json +5 -1
  281. package/registry/generated/index.json +280 -137
  282. package/registry/generated/marketplace.claude.json +1 -1
  283. package/registry/generated/plugin.claude.json +5 -1
  284. package/registry/generated/plugin.codex.json +5 -1
  285. package/registry/generated/plugin.cursor.json +5 -1
  286. package/registry/generated/plugin.factory.json +5 -1
  287. package/registry/generated/skills-index.md +16 -6
  288. package/registry/generated/skills-registry.json +57 -5
  289. package/registry/schemas/domains.json +1 -1
  290. package/registry/schemas/skill.schema.json +5 -0
@@ -7,6 +7,15 @@ import { BuildToolError } from "./summer-bundle.js";
7
7
  * summer_export_game writes and fails after a full engine start.
8
8
  */
9
9
  export const EXPORT_MIN_ENGINE_VERSION = "0.7.0";
10
+ /** Bundle targets that need a newer engine than EXPORT_MIN_ENGINE_VERSION. */
11
+ export const TARGET_MIN_ENGINE_VERSION = { android: "0.7.1" };
12
+ /** The requested targets this engine version cannot export; an unreadable version skips none. */
13
+ export function targetsNeedingNewerEngine(targets, version) {
14
+ return targets.flatMap((target) => {
15
+ const needs = TARGET_MIN_ENGINE_VERSION[target];
16
+ return needs && isVersionAtLeast(version, needs) === false ? [{ target, needs }] : [];
17
+ });
18
+ }
10
19
  export const ENGINE_UPDATE_HOW = 'run "summer install --yes" (or download it from summerengine.com/download)';
11
20
  /** Installed Summer version of an engine binary, or null when this system cannot read it. */
12
21
  export function installedEngineVersion(binary) {
@@ -34,6 +34,8 @@ export interface ExportGameInput {
34
34
  out?: string;
35
35
  /** Export with debug enabled (--export-debug). */
36
36
  debug?: boolean;
37
+ /** Bundle with targets: set summer.build.json targetPlatforms to the targets first, so the store takes the declaration. */
38
+ alignDeclaration?: boolean;
37
39
  /** Export preset name; the engine's own is "summer.games". Bundle format without targets only. */
38
40
  preset?: string;
39
41
  /** Store platforms: macos, windows, ios, android, web. */
@@ -52,6 +54,8 @@ export interface ExportGameResult {
52
54
  preset: string;
53
55
  /** The targets asked for, when any were. */
54
56
  targets?: StoreTarget[];
57
+ /** Asked-for targets left out of the bundle (an engine too old for them); warnings say why. */
58
+ skippedTargets?: StoreTarget[];
55
59
  /** What happened to export_presets.cfg for the preset this export used. */
56
60
  presetChange?: EnsuredPreset["change"];
57
61
  debug: boolean;
@@ -1,5 +1,5 @@
1
1
  import { existsSync, readFileSync, statSync } from "node:fs";
2
- import { mkdir, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
2
+ import { mkdir, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
3
3
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { platform } from "node:os";
5
5
  import { engineSelectionFromEnv } from "../engine.js";
@@ -7,10 +7,10 @@ import { findEngineBinary } from "../engine-install.js";
7
7
  import { readStoreJson, writeStoreJson } from "../store.js";
8
8
  import { writeZip } from "../util/zip-write.js";
9
9
  import { engineErrorLines, runEngine } from "./engine-run.js";
10
- import { assertExportEngine, installedEngineVersion } from "./export-engine-version.js";
10
+ import { assertExportEngine, ENGINE_UPDATE_HOW, installedEngineVersion, targetsNeedingNewerEngine } from "./export-engine-version.js";
11
11
  import { BUNDLE_TARGETS, DOWNLOAD_TARGETS, SUMMER_GAMES_PRESET, bundlePresetSpec, ensurePreset, normalizeTargets, variantString, } from "./export-presets.js";
12
12
  import { engineTemplateInfo, findInstalledTemplate, templateFileFor } from "./export-templates.js";
13
- import { BuildToolError, hashFile, readSummerBundle } from "./summer-bundle.js";
13
+ import { BuildToolError, declarationMismatch, hashFile, readSummerBundle, samePlatforms } from "./summer-bundle.js";
14
14
  export { runEngine, SUMMER_GAMES_PRESET };
15
15
  /**
16
16
  * summer_export_game: run the installed Summer Engine headless and return the
@@ -36,15 +36,15 @@ export { runEngine, SUMMER_GAMES_PRESET };
36
36
  */
37
37
  export const LAST_EXPORT_FILE = "last-export.json";
38
38
  const DEFAULT_TIMEOUT_MS = 15 * 60_000;
39
- /** Store platform ids of the versions intake (summer-platform creatorstore). */
39
+ /** Store platform ids of the store's versions intake. */
40
40
  const STORE_VERSION_PLATFORM = {
41
41
  web: "web",
42
42
  macos: "macos-universal",
43
43
  windows: "windows-x64",
44
44
  };
45
- /** Web zip limits of the store (summer-platform internal/creatorstore/webzip.go). */
45
+ /** Web zip limits of the store. */
46
46
  const WEB_LIMITS = { zipBytes: 500 * 1024 * 1024, fileBytes: 200 * 1024 * 1024, files: 2000 };
47
- /** Games without a server run on the phone apps only (summer-platform gameplatforms.StandaloneTargets). */
47
+ /** Games without a server run on the phone apps only (the store's standalone targets). */
48
48
  const STANDALONE_TARGETS = ["ios", "android"];
49
49
  /** Engine support per bundle target, for the recovery text when a target is missing. */
50
50
  const TARGET_ENGINE_NOTE = {
@@ -272,10 +272,27 @@ async function runExport(deps, binary, project, preset, out, debug, timeoutMs, n
272
272
  throw new BuildToolError("export_failed", `Summer Engine did not export the game (exit ${run.code ?? run.signal})${named.length ? `: ${named.join(" | ")}` : "."}`, [exportFailureRecovery(errors, preset), ...notes].join(" "), undefined, { errors, output: outputTail(run.output) });
273
273
  }
274
274
  }
275
+ /** Set the project's summer.build.json targetPlatforms to the export targets (a hosted game's Build declaration). */
276
+ async function alignBuildDeclaration(project, targets) {
277
+ const path = join(project, "summer.build.json");
278
+ if (!existsSync(path))
279
+ return;
280
+ let build;
281
+ try {
282
+ build = JSON.parse(await readFile(path, "utf8"));
283
+ }
284
+ catch {
285
+ throw new BuildToolError("build_declaration_invalid", "summer.build.json is not valid JSON.", "Recovery: fix summer.build.json, then export again.");
286
+ }
287
+ if (Array.isArray(build.targetPlatforms) && samePlatforms(build.targetPlatforms.map(String), targets))
288
+ return;
289
+ build.targetPlatforms = [...targets];
290
+ await writeFile(path, `${JSON.stringify(build, null, 2)}\n`);
291
+ }
275
292
  export async function exportGame(input, overrides = {}) {
276
293
  const deps = { ...defaultDependencies, ...overrides };
277
294
  const project = resolveExportProject(input.project);
278
- const targets = input.targets?.length ? normalizeTargets(input.targets) : undefined;
295
+ let targets = input.targets?.length ? normalizeTargets(input.targets) : undefined;
279
296
  const format = resolveFormat(input, targets);
280
297
  const debug = input.debug === true;
281
298
  const started = deps.now();
@@ -293,13 +310,26 @@ export async function exportGame(input, overrides = {}) {
293
310
  throw new BuildToolError("engine_not_installed", "Summer Engine is not installed on this machine.", 'Recovery: run "summer install", or set SUMMER_BIN to the engine executable, then export again.');
294
311
  }
295
312
  // Before any preset is written: an old engine cannot read them.
296
- assertExportEngine(binary, deps.engineVersion(binary));
313
+ const engineVersion = deps.engineVersion(binary);
314
+ assertExportEngine(binary, engineVersion);
315
+ // A target this engine cannot build is left out, not the whole export.
316
+ const skipped = format === "bundle" && targets ? targetsNeedingNewerEngine(targets, engineVersion) : [];
317
+ const skippedWarnings = skipped.map(({ target, needs }) => `${target} was not exported: it needs Summer Engine ${needs} or newer, and ${engineVersion} is installed. Update (${ENGINE_UPDATE_HOW}) and export ${target} again.`);
318
+ if (skipped.length) {
319
+ const left = targets.filter((target) => !skipped.some((entry) => entry.target === target));
320
+ if (!left.length) {
321
+ throw new BuildToolError("export_target_unsupported", `Summer Engine ${engineVersion} cannot export ${skipped.map((entry) => entry.target).join(", ")}.`, `Recovery: ${skippedWarnings.join(" ")}`, undefined, { engineVersion, skippedTargets: skipped });
322
+ }
323
+ targets = left;
324
+ }
297
325
  if (format === "download") {
298
326
  return exportDownload(deps, binary, project, targets[0], out, debug, timeoutMs, started);
299
327
  }
300
328
  out ??= join(await defaultExportDir(project), `${basename(project)}-${stamp(started)}.zip`);
301
329
  const before = existsSync(out) ? statSync(out).mtimeMs : null;
302
330
  const projectBefore = await snapshotProjectFiles(project);
331
+ if (targets && input.alignDeclaration === true)
332
+ await alignBuildDeclaration(project, targets);
303
333
  const ensured = targets ? await ensurePreset(project, bundlePresetSpec(targets)) : undefined;
304
334
  const preset = ensured?.name ?? (input.preset?.trim() || SUMMER_GAMES_PRESET);
305
335
  const notes = (targets ?? []).flatMap((target) => TARGET_ENGINE_NOTE[target] ?? []);
@@ -310,10 +340,20 @@ export async function exportGame(input, overrides = {}) {
310
340
  }
311
341
  const bundle = await readSummerBundle(out);
312
342
  const missing = (targets ?? []).filter((target) => !bundle.targetPlatforms.includes(target));
313
- if (missing.length) {
343
+ // Some targets made it: keep the bundle and say which did not.
344
+ const partial = missing.length > 0 && missing.length < (targets ?? []).length;
345
+ if (missing.length && !partial) {
314
346
  throw new BuildToolError("export_target_unsupported", `This Summer Engine exported the bundle without ${missing.join(", ")}: its summer.games preset has no such platform.`, ["Recovery: update Summer Engine and export again, or export without those targets.", ...missing.flatMap((target) => TARGET_ENGINE_NOTE[target] ?? [])].join(" "), undefined, { exportedPlatforms: bundle.targetPlatforms, path: out });
315
347
  }
316
- const warnings = projectChangeWarnings(projectChanges);
348
+ const warnings = [...skippedWarnings, ...projectChangeWarnings(projectChanges)];
349
+ const mismatch = declarationMismatch(bundle);
350
+ if (mismatch) {
351
+ warnings.unshift(`summer_publish_build will refuse this export (declaration_mismatch): ${mismatch}. Export again with alignDeclaration:true to set summer.build.json targetPlatforms to [${bundle.targetPlatforms.join(", ")}], or with targets equal to what it declares.`);
352
+ }
353
+ if (partial) {
354
+ warnings.push(`This Summer Engine exported the bundle without ${missing.join(", ")}: its summer.games preset has no such platform. ` +
355
+ ["Update Summer Engine and export them again.", ...missing.flatMap((target) => TARGET_ENGINE_NOTE[target] ?? [])].join(" "));
356
+ }
317
357
  const desktopOnly = bundle.hosted ? [] : bundle.targetPlatforms.filter((target) => !STANDALONE_TARGETS.includes(target));
318
358
  if (desktopOnly.length) {
319
359
  warnings.push(`This game has no server, and the store runs games without a server on iPhone and Android only: summer_publish_build will refuse ${desktopOnly.join(", ")}. ` +
@@ -332,6 +372,9 @@ export async function exportGame(input, overrides = {}) {
332
372
  project,
333
373
  preset,
334
374
  ...(targets ? { targets, presetChange: ensured.change } : {}),
375
+ ...(skipped.length || partial
376
+ ? { skippedTargets: [...skipped.map((entry) => entry.target), ...(partial ? missing : [])] }
377
+ : {}),
335
378
  debug,
336
379
  engine: binary,
337
380
  durationMs: deps.now().getTime() - started.getTime(),
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Store targets for summer_export_game, and the export presets that make them.
3
3
  *
4
- * The Summer Games store has two intakes (summer-platform):
4
+ * The Summer Games store has two intakes:
5
5
  * - build-publications takes ONE summer.bundle.v1 .zip per Build. Summer runs
6
6
  * its client.pck on its own client templates (the Summer Games iOS and
7
7
  * Android apps, the Summer desktop app on macOS and Windows), so the creator
@@ -5,7 +5,7 @@ import { BuildToolError } from "./summer-bundle.js";
5
5
  /**
6
6
  * Store targets for summer_export_game, and the export presets that make them.
7
7
  *
8
- * The Summer Games store has two intakes (summer-platform):
8
+ * The Summer Games store has two intakes:
9
9
  * - build-publications takes ONE summer.bundle.v1 .zip per Build. Summer runs
10
10
  * its client.pck on its own client templates (the Summer Games iOS and
11
11
  * Android apps, the Summer desktop app on macOS and Windows), so the creator
@@ -4,7 +4,7 @@
4
4
  * (`summer tool fabricate-3d`) so both faces validate the same arguments, send
5
5
  * the same op with the same clamps, and wait the same client poll budget.
6
6
  *
7
- * What the op does on the engine side (fabricate_ops.cpp, mesh fabrication): run one
7
+ * What the op does on the engine side: run one
8
8
  * agent-authored bpy script in a supervised headless child of the USER'S OWN
9
9
  * Blender install, validate the .glb the child exported, move it under res://,
10
10
  * wait for the editor import to settle, and optionally instantiate it into the
@@ -28,8 +28,7 @@ export declare const FABRICATE_DEFAULT_OUT_DIR = "res://assets/fabricated/";
28
28
  /** What the tool tells the model to do when the engine lacks FabricateMesh. */
29
29
  export declare const FABRICATE_FALLBACK = "generate the asset with summer_generate_3d, import one from the free library with summer_search_assets / summer_import_asset, use summer_import_hdri for environment lighting, or build blockout geometry in-scene with summer_add_node / summer_set_prop or a summer_run_editor_script";
30
30
  /**
31
- * Mirror of the engine's out_path pre-validation (fabricate_ops.cpp
32
- * _resolve_out_path) so a bad destination is refused on this side with the
31
+ * Mirror of the engine's out_path pre-validation so a bad destination is refused on this side with the
33
32
  * same words, and nothing is sent. Returns null when the path is acceptable.
34
33
  */
35
34
  export declare function fabricateOutPathProblem(rawPath: string): string | null;
@@ -4,7 +4,7 @@
4
4
  * (`summer tool fabricate-3d`) so both faces validate the same arguments, send
5
5
  * the same op with the same clamps, and wait the same client poll budget.
6
6
  *
7
- * What the op does on the engine side (fabricate_ops.cpp, mesh fabrication): run one
7
+ * What the op does on the engine side: run one
8
8
  * agent-authored bpy script in a supervised headless child of the USER'S OWN
9
9
  * Blender install, validate the .glb the child exported, move it under res://,
10
10
  * wait for the editor import to settle, and optionally instantiate it into the
@@ -30,8 +30,7 @@ export const FABRICATE_DEFAULT_OUT_DIR = "res://assets/fabricated/";
30
30
  export const FABRICATE_FALLBACK = "generate the asset with summer_generate_3d, import one from the free library with summer_search_assets / summer_import_asset, use summer_import_hdri for environment lighting, or build blockout geometry in-scene with summer_add_node / summer_set_prop or a summer_run_editor_script";
31
31
  const VECTOR3_VARIANT_RE = /^Vector3\(\s*[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?\s*,\s*[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?\s*,\s*[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?\s*\)$/;
32
32
  /**
33
- * Mirror of the engine's out_path pre-validation (fabricate_ops.cpp
34
- * _resolve_out_path) so a bad destination is refused on this side with the
33
+ * Mirror of the engine's out_path pre-validation so a bad destination is refused on this side with the
35
34
  * same words, and nothing is sent. Returns null when the path is acceptable.
36
35
  */
37
36
  export function fabricateOutPathProblem(rawPath) {
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Frame-quality probe for engine screenshots (tool/screenshot).
3
3
  *
4
- * WHY THIS EXISTS. In the 2026-09-03 end-to-end run (docs/design/archive/E2E-2026-09-03.md,
5
- * F-01) `summer_screenshot target:"viewport"` returned an entirely black
4
+ * WHY THIS EXISTS. In the 2026-09-03 end-to-end run,
5
+ * `summer_screenshot target:"viewport"` returned an entirely black
6
6
  * 1072x1280 JPEG (src/core/capabilities/__fixtures__/frames/01-mcp-viewport-black.jpg)
7
7
  * with a caption
8
8
  * telling the agent to describe what it saw. It was the first viewport capture
9
9
  * after scene mutations had flipped the editor from the 3D to the 2D tab; the
10
10
  * same call 67 s later returned real content. Engine side, the ViewportSnapshot
11
- * op (summerengine modules/1summer_engine/editor/ops/debug_ops.cpp) reads the
11
+ * op reads the
12
12
  * editor SubViewport's texture with get_texture()->get_image() AS-IS — no forced
13
13
  * RenderingServer draw and no blank-frame retry, both of which ScenePreview has
14
- * (preview_ops.cpp "render-readiness hardening") because a not-yet-drawn
14
+ * because a not-yet-drawn
15
15
  * texture reads back black. That is consistent with a 2D subviewport that had
16
16
  * not been redrawn since the tab switch, but it has NOT been proven by
17
17
  * instrumenting the engine, so this module detects the SYMPTOM (a flat frame)
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Frame-quality probe for engine screenshots (tool/screenshot).
3
3
  *
4
- * WHY THIS EXISTS. In the 2026-09-03 end-to-end run (docs/design/archive/E2E-2026-09-03.md,
5
- * F-01) `summer_screenshot target:"viewport"` returned an entirely black
4
+ * WHY THIS EXISTS. In the 2026-09-03 end-to-end run,
5
+ * `summer_screenshot target:"viewport"` returned an entirely black
6
6
  * 1072x1280 JPEG (src/core/capabilities/__fixtures__/frames/01-mcp-viewport-black.jpg)
7
7
  * with a caption
8
8
  * telling the agent to describe what it saw. It was the first viewport capture
9
9
  * after scene mutations had flipped the editor from the 3D to the 2D tab; the
10
10
  * same call 67 s later returned real content. Engine side, the ViewportSnapshot
11
- * op (summerengine modules/1summer_engine/editor/ops/debug_ops.cpp) reads the
11
+ * op reads the
12
12
  * editor SubViewport's texture with get_texture()->get_image() AS-IS — no forced
13
13
  * RenderingServer draw and no blank-frame retry, both of which ScenePreview has
14
- * (preview_ops.cpp "render-readiness hardening") because a not-yet-drawn
14
+ * because a not-yet-drawn
15
15
  * texture reads back black. That is consistent with a 2D subviewport that had
16
16
  * not been redrawn since the tab switch, but it has NOT been proven by
17
17
  * instrumenting the engine, so this module detects the SYMPTOM (a flat frame)
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * grep — ONE implementation of `summer_grep` for both faces
3
3
  * (src/mcp/tools/file-tools.ts and tool-dispatch.ts), over the engine's
4
- * ripgrep-backed Grep op (modules/1summer_engine/editor/ops/search_ops.cpp).
4
+ * ripgrep-backed Grep op.
5
5
  *
6
6
  * The engine op returns {file, line, content} per match and parses only
7
7
  * ripgrep's "match" events, so its contextLines flag adds nothing to the
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * grep — ONE implementation of `summer_grep` for both faces
3
3
  * (src/mcp/tools/file-tools.ts and tool-dispatch.ts), over the engine's
4
- * ripgrep-backed Grep op (modules/1summer_engine/editor/ops/search_ops.cpp).
4
+ * ripgrep-backed Grep op.
5
5
  *
6
6
  * The engine op returns {file, line, content} per match and parses only
7
7
  * ripgrep's "match" events, so its contextLines flag adds nothing to the
@@ -1,8 +1,10 @@
1
1
  import { z } from "zod";
2
+ /** Image generation can take over a minute on the larger models; wait this long for the server. */
3
+ export declare const IMAGE_GENERATION_TIMEOUT_MS = 180000;
2
4
  /** Shared MCP/CLI image request contract; optional flags preserve omission. */
3
5
  export declare const imageGenerationArgsSchema: z.ZodObject<{
4
6
  prompt: z.ZodString;
5
- model: z.ZodDefault<z.ZodString>;
7
+ model: z.ZodOptional<z.ZodString>;
6
8
  style: z.ZodDefault<z.ZodString>;
7
9
  referenceImageUrl: z.ZodOptional<z.ZodString>;
8
10
  removeBackground: z.ZodOptional<z.ZodBoolean>;
@@ -10,13 +12,15 @@ export declare const imageGenerationArgsSchema: z.ZodObject<{
10
12
  width: z.ZodOptional<z.ZodNumber>;
11
13
  height: z.ZodOptional<z.ZodNumber>;
12
14
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
15
+ out: z.ZodOptional<z.ZodString>;
13
16
  }, "strip", z.ZodTypeAny, {
14
17
  prompt: string;
15
- model: string;
16
18
  style: string;
17
19
  width?: number | undefined;
18
20
  height?: number | undefined;
19
21
  options?: Record<string, any> | undefined;
22
+ out?: string | undefined;
23
+ model?: string | undefined;
20
24
  referenceImageUrl?: string | undefined;
21
25
  removeBackground?: boolean | undefined;
22
26
  aspectRatio?: "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "5:4" | "4:5" | "21:9" | undefined;
@@ -25,9 +29,15 @@ export declare const imageGenerationArgsSchema: z.ZodObject<{
25
29
  width?: number | undefined;
26
30
  height?: number | undefined;
27
31
  options?: Record<string, any> | undefined;
32
+ out?: string | undefined;
28
33
  model?: string | undefined;
29
34
  style?: string | undefined;
30
35
  referenceImageUrl?: string | undefined;
31
36
  removeBackground?: boolean | undefined;
32
37
  aspectRatio?: "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "5:4" | "4:5" | "21:9" | undefined;
33
38
  }>;
39
+ /**
40
+ * Save a generated image where the caller asked (a folder or a file path), or
41
+ * under TMPDIR/summer-gen. Returns the path, or null when the download failed.
42
+ */
43
+ export declare function saveGeneratedImage(url: string, out?: string, prefix?: string): Promise<string | null>;
@@ -1,11 +1,17 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { dirname, extname, join, resolve } from "node:path";
1
4
  import { z } from "zod";
5
+ /** Image generation can take over a minute on the larger models; wait this long for the server. */
6
+ export const IMAGE_GENERATION_TIMEOUT_MS = 180_000;
7
+ const IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".webp"]);
2
8
  /** Shared MCP/CLI image request contract; optional flags preserve omission. */
3
9
  export const imageGenerationArgsSchema = z.object({
4
10
  prompt: z.string().describe("Description of the image to generate"),
5
11
  model: z
6
12
  .string()
7
- .default("nano-banana-2")
8
- .describe("Model name or full provider ID"),
13
+ .optional()
14
+ .describe("Model name or full provider ID. Omit it and the server picks one that reaches the requested size (nano-banana-2 when no size is asked)."),
9
15
  style: z
10
16
  .string()
11
17
  .default("realistic")
@@ -37,4 +43,27 @@ export const imageGenerationArgsSchema = z.object({
37
43
  .record(z.any())
38
44
  .optional()
39
45
  .describe("Extra model params (seed, negative_prompt, ...). The result lists any it did not use in ignoredOptions."),
46
+ out: z
47
+ .string()
48
+ .optional()
49
+ .describe("Where to save the image on this machine: a folder, or a file path ending in .png, .jpg or .webp. Default: <TMPDIR>/summer-gen/."),
40
50
  });
51
+ /**
52
+ * Save a generated image where the caller asked (a folder or a file path), or
53
+ * under TMPDIR/summer-gen. Returns the path, or null when the download failed.
54
+ */
55
+ export async function saveGeneratedImage(url, out, prefix = "img") {
56
+ try {
57
+ const target = out?.trim() ? resolve(out.trim()) : join(tmpdir(), "summer-gen");
58
+ const file = IMAGE_EXTENSIONS.has(extname(target).toLowerCase()) ? target : join(target, `${prefix}-${Date.now()}.png`);
59
+ await mkdir(dirname(file), { recursive: true });
60
+ const res = await fetch(url, { signal: AbortSignal.timeout(60_000) });
61
+ if (!res.ok)
62
+ return null;
63
+ await writeFile(file, Buffer.from(await res.arrayBuffer()));
64
+ return file;
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
@@ -12,7 +12,7 @@
12
12
  * advertises `capabilities.navigation` the tool sends the one-table op
13
13
  * `Navigate { target, ...args }`; on an engine that predates it the few ids the
14
14
  * original ops can serve (scene, node, script, file, the three docks) use those
15
- * ops and everything else answers `engine_lacks_op`. See NAVIGATION-PLAN.md.
15
+ * ops and everything else answers `engine_lacks_op`.
16
16
  *
17
17
  * Both faces call runOpen(); the CLI (tool-dispatch + `summer open`) and the
18
18
  * MCP tool (src/mcp/tools/navigation-tools.ts) only differ in how the engine
@@ -12,7 +12,7 @@
12
12
  * advertises `capabilities.navigation` the tool sends the one-table op
13
13
  * `Navigate { target, ...args }`; on an engine that predates it the few ids the
14
14
  * original ops can serve (scene, node, script, file, the three docks) use those
15
- * ops and everything else answers `engine_lacks_op`. See NAVIGATION-PLAN.md.
15
+ * ops and everything else answers `engine_lacks_op`.
16
16
  *
17
17
  * Both faces call runOpen(); the CLI (tool-dispatch + `summer open`) and the
18
18
  * MCP tool (src/mcp/tools/navigation-tools.ts) only differ in how the engine
@@ -49,7 +49,7 @@ export function renderProductMap() {
49
49
  lines.push("## Who owns what");
50
50
  lines.push("");
51
51
  lines.push("- **Web rows** come from summerengine.com's own route catalog (`/agent-routes.json`, published from the web repo's `src/lib/navigation/routes.ts`). The toolkit vendors a snapshot (`assets/navigation/web-routes.json`, refreshed with `npm run sync:web-routes`); it does not invent pages.");
52
- lines.push("- **Editor rows** are ids of Summer Engine's one navigation table (`navigate_ops.cpp`, op `Navigate`). The running engine advertises which ids it can open in `/api/health` `capabilities.navigation`; `summer open --list` shows availability from the connected engine. Engines that predate the `Navigate` op can still serve the rows with a legacy op (last-but-one column); every other row answers `engine_lacks_op` with an update hint.");
52
+ lines.push("- **Editor rows** are ids of Summer Engine's one navigation table (the `Navigate` op). The running engine advertises which ids it can open in `/api/health` `capabilities.navigation`; `summer open --list` shows availability from the connected engine. Engines that predate the `Navigate` op can still serve the rows with a legacy op (last-but-one column); every other row answers `engine_lacks_op` with an update hint.");
53
53
  lines.push("");
54
54
  lines.push("## How to read a row");
55
55
  lines.push("");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The product map as the toolkit sees it (docs/design/NAVIGATION-PLAN.md).
2
+ * The product map as the toolkit sees it (rendered for agents as library/references/product-map).
3
3
  *
4
4
  * The toolkit does NOT own where things are. Each product does:
5
5
  *
@@ -7,7 +7,7 @@
7
7
  * src/lib/navigation/routes.ts). A vendored snapshot lives at
8
8
  * assets/navigation/web-routes.json (refresh: `npm run sync:web-routes`) and
9
9
  * every web row below is built from it — nothing hand-written.
10
- * - Summer Engine owns one table of editor destinations (navigate_ops.cpp) and
10
+ * - Summer Engine owns one table of editor destinations (the Navigate op) and
11
11
  * advertises the ids it can open in /api/health capabilities.navigation.
12
12
  * The rows below are METADATA for those ids (titles, intents, argument
13
13
  * names) plus, for the few ids an older engine can serve through its
@@ -8,7 +8,7 @@ export type PlacementField = (typeof PLACEMENT_FIELDS)[number];
8
8
  /** Model-visible budget for compact receipts (the 5 KB tool-result contract). */
9
9
  export declare const COMPACT_LIMIT_BYTES: number;
10
10
  /** Held-back transform SetProps sent per request; the engine refuses requests
11
- * over 256 ops (local_api_server.cpp). */
11
+ * over 256 ops. */
12
12
  export declare const TRANSFORM_OPS_PER_REQUEST = 200;
13
13
  export interface PlacementProp {
14
14
  key: PlacementField;
@@ -4,7 +4,7 @@
4
4
  * twins.
5
5
  *
6
6
  * The engine's InstantiateScene accepts only parent / scene / name /
7
- * target_size (scene_ops.cpp instantiate_scene) and must travel as its own
7
+ * target_size and must travel as its own
8
8
  * request (single-only). A placed piece is therefore an InstantiateScene plus
9
9
  * SetProps on the node path its receipt reports (meta.nodePath, which already
10
10
  * carries any collision rename). The caller writes ONE op; this module expands
@@ -35,7 +35,7 @@ export const PLACEMENT_FIELDS = ["position", "rotation_degrees", "scale", "trans
35
35
  /** Model-visible budget for compact receipts (the 5 KB tool-result contract). */
36
36
  export const COMPACT_LIMIT_BYTES = 5 * 1024;
37
37
  /** Held-back transform SetProps sent per request; the engine refuses requests
38
- * over 256 ops (local_api_server.cpp). */
38
+ * over 256 ops. */
39
39
  export const TRANSFORM_OPS_PER_REQUEST = 200;
40
40
  const SUMMARY_TARGET_BYTES = 4600;
41
41
  const ERROR_TEXT_LIMIT = 240;
@@ -5,7 +5,7 @@
5
5
  * summer_play tool and the CLI dispatcher.
6
6
  *
7
7
  * Transport note: the engine's /api/play rung copies only `scene` into the
8
- * PlayGame op (local_api_server.cpp play branch), so a launch that carries a
8
+ * PlayGame op, so a launch that carries a
9
9
  * pin is sent as an explicit PlayGame op through /api/ops instead. A launch
10
10
  * without any pin stays on /api/play, byte-for-byte the v1 call.
11
11
  *
@@ -5,7 +5,7 @@
5
5
  * summer_play tool and the CLI dispatcher.
6
6
  *
7
7
  * Transport note: the engine's /api/play rung copies only `scene` into the
8
- * PlayGame op (local_api_server.cpp play branch), so a launch that carries a
8
+ * PlayGame op, so a launch that carries a
9
9
  * pin is sent as an explicit PlayGame op through /api/ops instead. A launch
10
10
  * without any pin stays on /api/play, byte-for-byte the v1 call.
11
11
  *
@@ -1,5 +1,5 @@
1
1
  import { BuildToolError } from "./summer-bundle.js";
2
- /** summer-platform client versions: vMAJOR.MINOR.PATCH[-rN]. */
2
+ /** Store client versions: vMAJOR.MINOR.PATCH[-rN]. */
3
3
  export declare const CLIENT_VERSION: RegExp;
4
4
  export interface PublishBuildInput {
5
5
  gameId?: string;
@@ -8,12 +8,11 @@ import { appendStoreJsonLine } from "../store.js";
8
8
  import { readJsonResponse } from "../util/http.js";
9
9
  import { readLastExport } from "./export-game.js";
10
10
  import { publishDownload } from "./publish-download.js";
11
- import { BuildToolError, readSummerBundle } from "./summer-bundle.js";
11
+ import { BuildToolError, declarationMismatch, readSummerBundle } from "./summer-bundle.js";
12
12
  /**
13
13
  * summer_publish_build: upload a summer.games export to the creator's game
14
14
  * through the same creator store routes Studio's export upload uses
15
- * (publicsummerengine /api/creator-store/* -> summer-platform
16
- * /v1/management/*, build-publications, ADR 0033):
15
+ * (/api/creator-store/*, build-publications):
17
16
  *
18
17
  * POST games/{g}/build-publications declare the export (idempotent)
19
18
  * POST .../{p}:source-upload open the part plan (64 MiB parts)
@@ -24,8 +23,7 @@ import { BuildToolError, readSummerBundle } from "./summer-bundle.js";
24
23
  * POST games/{g}/builds/{b}/client-packages name the Build's client pack
25
24
  * POST .../{p}:publish only with publish=true
26
25
  *
27
- * Mirrors publicsummerengine src/lib/creator-store/pack-upload.ts
28
- * (uploadExportedGame), including its idempotency keys, so a retry continues
26
+ * Mirrors Studio's export upload, including its idempotency keys, so a retry continues
29
27
  * the same publication instead of creating another one.
30
28
  *
31
29
  * Auth: the Summer store OAuth token from "summer login --store" (audience
@@ -38,18 +36,18 @@ const CONCURRENCY = 3;
38
36
  const PART_RETRIES = 3;
39
37
  const DEFAULT_WAIT_SECONDS = 600;
40
38
  const POLL_MS = 3_000;
41
- /** summer-platform client versions: vMAJOR.MINOR.PATCH[-rN]. */
39
+ /** Store client versions: vMAJOR.MINOR.PATCH[-rN]. */
42
40
  export const CLIENT_VERSION = /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-r[1-9]\d*)?$/;
43
41
  const INTAKE_DONE = ["preview_ready", "published", "ready", "succeeded"];
44
42
  const NOT_ACTIONABLE = "deployment_not_actionable";
45
- /** Games without a server run on the Summer Games phone apps only (summer-platform gameplatforms.StandaloneTargets). */
43
+ /** Games without a server run on the Summer Games phone apps only (the store's standalone targets). */
46
44
  const STANDALONE_TARGETS = ["ios", "android"];
47
45
  /** Why the Platform did not take the export, in plain words (same text Studio shows). */
48
46
  const INTAKE_FAILURES = {
49
47
  game_identity_mismatch: "This export belongs to another game. Upload it to its original game, or make a portable export for this game.",
50
48
  bundle_invalid: "Summer could not read this export. Export the game again and upload the new file.",
51
49
  declaration_mismatch: "The export's game or settings do not match this upload. Use the original game or export a new version with the intended settings.",
52
- template_set_unavailable: "Summer Games cannot run this Summer version yet. Update Summer Engine, export again and upload the new file.",
50
+ template_set_unavailable: "Summer Games cannot run this Summer version yet. If you exported with the newest Summer Engine, Summer Games may still be turning that version on: retry the same upload later, there is nothing to update. With an older engine, update Summer Engine and export again.",
53
51
  client_version_conflict: "This version number already belongs to a different export. Use a new clientVersion.",
54
52
  artifact_exists: "This exact export is already uploaded for this game. Export a new version and upload that.",
55
53
  approval_denied: "Summer Games did not approve this game, so it cannot take new builds.",
@@ -254,6 +252,10 @@ export function normalizeClientVersion(value) {
254
252
  return version;
255
253
  }
256
254
  function targetPlatforms(bundle) {
255
+ const mismatch = declarationMismatch(bundle);
256
+ if (mismatch) {
257
+ throw new BuildToolError("declaration_mismatch", `The store would refuse this upload (declaration_mismatch): ${mismatch}. Nothing was uploaded and no version was used.`, "Recovery: export again with summer_export_game alignDeclaration:true (it sets summer.build.json targetPlatforms to the targets you export), or with targets equal to what summer.build.json declares; then upload the new export.");
258
+ }
257
259
  if (bundle.hosted)
258
260
  return bundle.targetPlatforms;
259
261
  const other = bundle.targetPlatforms.filter((platform) => !STANDALONE_TARGETS.includes(platform));
@@ -423,7 +425,17 @@ export async function publishBuild(input, overrides = {}) {
423
425
  break;
424
426
  if (publication.state === "failed" || publication.state === "cancelled") {
425
427
  const code = typeof publication.errorCode === "string" ? publication.errorCode : "publication_failed";
426
- throw new BuildToolError(code, (code === "declaration_mismatch" && publication.errorMessage) || INTAKE_FAILURES[code] || publication.errorMessage || "Summer could not make a build from this upload.", "Recovery: export again, use a new clientVersion, and retry.", undefined, { publicationId });
428
+ throw new BuildToolError(code, ((code === "declaration_mismatch" || code === "template_set_unavailable") && publication.errorMessage) ||
429
+ INTAKE_FAILURES[code] ||
430
+ publication.errorMessage ||
431
+ "Summer could not make a build from this upload.",
432
+ // The store checks the declaration and the bundle before it records a
433
+ // client pack, so those refusals leave the version free.
434
+ code === "declaration_mismatch" || code === "bundle_invalid"
435
+ ? "Recovery: fix what the message names, export again and retry; the same clientVersion still works, because a refused upload records no version."
436
+ : code === "template_set_unavailable"
437
+ ? `Recovery: ${INTAKE_FAILURES.template_set_unavailable.replace(/^Summer Games cannot run this Summer version yet\. /, "")} The same clientVersion works on the retry.`
438
+ : "Recovery: export again, use a new clientVersion, and retry.", undefined, { publicationId });
427
439
  }
428
440
  if (deps.now() >= deadline) {
429
441
  const result = {
@@ -1,7 +1,6 @@
1
1
  import { type PublishBuildDependencies } from "./publish-build.js";
2
2
  /**
3
- * The store's second build path (summer-platform store versions,
4
- * internal/creatorstore): a web build (an HTML5 .zip played on summer.games)
3
+ * The store's second build path (store versions): a web build (an HTML5 .zip played on summer.games)
5
4
  * or a native download (macOS universal, Windows x64, Linux x64) that players
6
5
  * download. summer_export_game format "download" makes these files;
7
6
  * summer_publish_build uploads them here, through the same creator store
@@ -7,8 +7,7 @@ import { readZipEntries } from "../util/zip.js";
7
7
  import { BuildToolError } from "./summer-bundle.js";
8
8
  import { createStore, readGrants, uploadParts } from "./publish-build.js";
9
9
  /**
10
- * The store's second build path (summer-platform store versions,
11
- * internal/creatorstore): a web build (an HTML5 .zip played on summer.games)
10
+ * The store's second build path (store versions): a web build (an HTML5 .zip played on summer.games)
12
11
  * or a native download (macOS universal, Windows x64, Linux x64) that players
13
12
  * download. summer_export_game format "download" makes these files;
14
13
  * summer_publish_build uploads them here, through the same creator store
@@ -25,7 +24,7 @@ import { createStore, readGrants, uploadParts } from "./publish-build.js";
25
24
  * already live the store refuses an agent's :complete (the owner finishes it).
26
25
  */
27
26
  export const DOWNLOAD_PLATFORMS = ["web", "macos-universal", "windows-x64", "linux-x64"];
28
- /** summer-platform creatorstore limits (versions.go, webzip.go). */
27
+ /** The store's upload limits for store versions and web zips. */
29
28
  const WEB_MAX_BYTES = 500 * 1024 * 1024;
30
29
  const WEB_MAX_FILES = 2000;
31
30
  const WEB_MAX_FILE_BYTES = 200 * 1024 * 1024;
@@ -3,9 +3,7 @@
3
3
  * (src/mcp/tools/scene-tools.ts and tool-dispatch.ts), built from ops whose
4
4
  * results persist, and verified against the SAVED scene file.
5
5
  *
6
- * Why not the engine's ReplaceNode op for scenes: SceneOps::replace_node
7
- * (engine modules/1summer_engine/editor/ops/scene_ops.cpp, scene branch and
8
- * the async _finish_replace_node) instantiates the new PackedScene and hands
6
+ * Why not the engine's ReplaceNode op for scenes: for a scene it instantiates the new PackedScene and hands
9
7
  * it to SceneTreeDock::replace_node — the editor's "Change Type" path — which
10
8
  * ends in Node::replace_by (scene/main/node.cpp). replace_by finishes with
11
9
  * `p_node->set_scene_file_path(get_scene_file_path())`: the new instance is
@@ -3,9 +3,7 @@
3
3
  * (src/mcp/tools/scene-tools.ts and tool-dispatch.ts), built from ops whose
4
4
  * results persist, and verified against the SAVED scene file.
5
5
  *
6
- * Why not the engine's ReplaceNode op for scenes: SceneOps::replace_node
7
- * (engine modules/1summer_engine/editor/ops/scene_ops.cpp, scene branch and
8
- * the async _finish_replace_node) instantiates the new PackedScene and hands
6
+ * Why not the engine's ReplaceNode op for scenes: for a scene it instantiates the new PackedScene and hands
9
7
  * it to SceneTreeDock::replace_node — the editor's "Change Type" path — which
10
8
  * ends in Node::replace_by (scene/main/node.cpp). replace_by finishes with
11
9
  * `p_node->set_scene_file_path(get_scene_file_path())`: the new instance is