summer-engine 3.3.0 → 3.4.1

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 (293) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +4 -2
  3. package/.codex-plugin/plugin.json +5 -3
  4. package/.cursor-plugin/plugin.json +4 -2
  5. package/.factory-plugin/plugin.json +4 -2
  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 +50 -0
  10. package/GEMINI.md +1 -1
  11. package/NOTICE +1 -1
  12. package/README.md +32 -35
  13. package/assets/api-docs.json.gz +0 -0
  14. package/assets/autopilot/run.sh +2 -2
  15. package/assets/navigation/web-routes.json +1 -1
  16. package/commands/gameskill.md +2 -2
  17. package/commands/summer.md +25 -25
  18. package/dist/cli/commands/install.d.ts +10 -0
  19. package/dist/cli/commands/install.js +55 -10
  20. package/dist/cli/commands/open.d.ts +1 -1
  21. package/dist/cli/commands/run.d.ts +1 -1
  22. package/dist/cli/commands/run.js +1 -1
  23. package/dist/cli/commands/skills.js +2 -2
  24. package/dist/cli/commands/tool.d.ts +7 -0
  25. package/dist/cli/commands/tool.js +36 -1
  26. package/dist/core/api-client.d.ts +5 -6
  27. package/dist/core/api-client.js +12 -15
  28. package/dist/core/auth.js +2 -2
  29. package/dist/core/capabilities/asset-import.d.ts +0 -1
  30. package/dist/core/capabilities/camera-view.d.ts +1 -1
  31. package/dist/core/capabilities/camera-view.js +2 -2
  32. package/dist/core/capabilities/capture-gameplay.d.ts +69 -0
  33. package/dist/core/capabilities/capture-gameplay.js +283 -0
  34. package/dist/core/capabilities/connect-signal.d.ts +1 -2
  35. package/dist/core/capabilities/connect-signal.js +1 -2
  36. package/dist/core/capabilities/console-read.d.ts +2 -2
  37. package/dist/core/capabilities/console-read.js +2 -2
  38. package/dist/core/capabilities/creator.js +1 -1
  39. package/dist/core/capabilities/doctor.d.ts +9 -1
  40. package/dist/core/capabilities/doctor.js +47 -4
  41. package/dist/core/capabilities/engine-receipt.d.ts +5 -7
  42. package/dist/core/capabilities/engine-receipt.js +7 -9
  43. package/dist/core/capabilities/engine-run.d.ts +4 -0
  44. package/dist/core/capabilities/engine-run.js +33 -5
  45. package/dist/core/capabilities/export-engine-version.d.ts +15 -0
  46. package/dist/core/capabilities/export-engine-version.js +24 -0
  47. package/dist/core/capabilities/export-game.d.ts +9 -1
  48. package/dist/core/capabilities/export-game.js +115 -39
  49. package/dist/core/capabilities/export-presets.d.ts +1 -1
  50. package/dist/core/capabilities/export-presets.js +1 -1
  51. package/dist/core/capabilities/fabricate-mesh.d.ts +2 -3
  52. package/dist/core/capabilities/fabricate-mesh.js +2 -3
  53. package/dist/core/capabilities/frame-quality.d.ts +4 -4
  54. package/dist/core/capabilities/frame-quality.js +4 -4
  55. package/dist/core/capabilities/grep.d.ts +1 -1
  56. package/dist/core/capabilities/grep.js +1 -1
  57. package/dist/core/capabilities/image-generation.d.ts +9 -0
  58. package/dist/core/capabilities/image-generation.js +19 -1
  59. package/dist/core/capabilities/navigation/open.d.ts +1 -1
  60. package/dist/core/capabilities/navigation/open.js +1 -1
  61. package/dist/core/capabilities/navigation/render-product-map.js +1 -1
  62. package/dist/core/capabilities/navigation/targets.js +2 -2
  63. package/dist/core/capabilities/placement-batch.d.ts +1 -1
  64. package/dist/core/capabilities/placement-batch.js +2 -2
  65. package/dist/core/capabilities/play-determinism.d.ts +1 -1
  66. package/dist/core/capabilities/play-determinism.js +1 -1
  67. package/dist/core/capabilities/publish-build.d.ts +15 -2
  68. package/dist/core/capabilities/publish-build.js +78 -28
  69. package/dist/core/capabilities/publish-download.d.ts +1 -2
  70. package/dist/core/capabilities/publish-download.js +2 -3
  71. package/dist/core/capabilities/replace-node.d.ts +1 -3
  72. package/dist/core/capabilities/replace-node.js +1 -3
  73. package/dist/core/capabilities/runtime-control.d.ts +5 -7
  74. package/dist/core/capabilities/runtime-control.js +7 -9
  75. package/dist/core/capabilities/scene-batch.d.ts +1 -1
  76. package/dist/core/capabilities/scene-batch.js +1 -1
  77. package/dist/core/capabilities/scene-kind.js +1 -1
  78. package/dist/core/capabilities/scene-readback.d.ts +3 -4
  79. package/dist/core/capabilities/scene-readback.js +3 -4
  80. package/dist/core/capabilities/scene-script.d.ts +2 -2
  81. package/dist/core/capabilities/scene-script.js +2 -2
  82. package/dist/core/capabilities/seeing/shot-store.d.ts +1 -1
  83. package/dist/core/capabilities/seeing/shot-store.js +1 -1
  84. package/dist/core/capabilities/summer-bundle.d.ts +2 -3
  85. package/dist/core/capabilities/summer-bundle.js +2 -3
  86. package/dist/core/capabilities/surface-snap.d.ts +1 -1
  87. package/dist/core/capabilities/surface-snap.js +1 -1
  88. package/dist/core/capabilities/tool-dispatch.js +11 -1
  89. package/dist/core/capabilities/ui-control.d.ts +1 -2
  90. package/dist/core/capabilities/ui-control.js +1 -2
  91. package/dist/core/capabilities/world-snapshot.d.ts +1 -1
  92. package/dist/core/capabilities/world-snapshot.js +1 -1
  93. package/dist/core/capability-skew.d.ts +2 -3
  94. package/dist/core/capability-skew.js +4 -5
  95. package/dist/core/config.js +2 -2
  96. package/dist/core/engine-install.d.ts +16 -0
  97. package/dist/core/engine-install.js +32 -2
  98. package/dist/core/feedback/client.js +1 -1
  99. package/dist/core/hosted-mcp.d.ts +115 -0
  100. package/dist/core/hosted-mcp.js +164 -0
  101. package/dist/core/launch-posture.d.ts +6 -3
  102. package/dist/core/launch-posture.js +18 -5
  103. package/dist/core/library-read.js +1 -2
  104. package/dist/core/templates.d.ts +1 -2
  105. package/dist/core/templates.js +1 -2
  106. package/dist/mcp/hosted-mount.d.ts +13 -59
  107. package/dist/mcp/hosted-mount.js +24 -30
  108. package/dist/mcp/server.d.ts +2 -2
  109. package/dist/mcp/server.js +5 -4
  110. package/dist/mcp/tools/creator-tools.js +14 -4
  111. package/dist/mcp/tools/debug-tools.js +1 -1
  112. package/dist/mcp/tools/generate-tools.js +19 -9
  113. package/dist/mcp/tools/navigation-tools.d.ts +1 -1
  114. package/dist/mcp/tools/navigation-tools.js +1 -1
  115. package/dist/mcp/tools/spatial-tools.js +1 -1
  116. package/dist/mcp/tools/visual-tools.js +2 -2
  117. package/dist/mcp/tools/with-engine.d.ts +1 -2
  118. package/dist/mcp/tools/with-engine.js +1 -2
  119. package/gemini-extension.json +3 -1
  120. package/hooks/session-start.sh +2 -2
  121. package/integrations/README.md +70 -76
  122. package/integrations/claude/README.md +0 -3
  123. package/integrations/codex/README.md +1 -2
  124. package/integrations/copilot-jetbrains/README.md +1 -1
  125. package/integrations/cursor/README.md +1 -2
  126. package/integrations/factory/README.md +15 -11
  127. package/integrations/mistral-vibe/README.md +1 -1
  128. package/integrations/opencode/README.md +1 -1
  129. package/integrations/roo-code/README.md +1 -1
  130. package/integrations/rovo-dev/README.md +1 -1
  131. package/integrations/trae/README.md +1 -1
  132. package/integrations/windsurf/README.md +3 -3
  133. package/library/references/collaborative-protocol/collaborative-protocol.md +5 -5
  134. package/library/references/gd-style/gd-style.md +4 -6
  135. package/library/references/godot-version/godot-version.md +3 -3
  136. package/library/references/headless-routing/headless-routing.md +2 -2
  137. package/library/references/mcp-fresh-chat-playbook/mcp-fresh-chat-playbook.md +2 -2
  138. package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -16
  139. package/library/references/product-map/product-map.md +1 -1
  140. package/library/references/public-surface-language/public-surface-language.md +1 -1
  141. package/library/references/summer-folder/summer-folder.md +1 -1
  142. package/library/skills/3d-lighting/SKILL.md +4 -4
  143. package/library/skills/README.md +11 -9
  144. package/library/skills/adaptive-music/SKILL.md +7 -7
  145. package/library/skills/ai-characters-in-games/SKILL.md +1 -1
  146. package/library/skills/ambient-bed/SKILL.md +12 -14
  147. package/library/skills/animated-loop/SKILL.md +42 -42
  148. package/library/skills/animation-tree/SKILL.md +6 -6
  149. package/library/skills/art-direction/SKILL.md +8 -11
  150. package/library/skills/asset-strategy/SKILL.md +3 -3
  151. package/library/skills/audio-direction/SKILL.md +8 -10
  152. package/library/skills/auto-fire-targeting/SKILL.md +4 -3
  153. package/library/skills/bounded-engine-runs/SKILL.md +95 -0
  154. package/library/skills/bounded-engine-runs/resource.yaml +29 -0
  155. package/library/skills/brainstorm-game/SKILL.md +5 -5
  156. package/library/skills/brainstorming/SKILL.md +9 -15
  157. package/library/skills/celeste-momentum-platforming/SKILL.md +8 -13
  158. package/library/skills/celeste-momentum-platforming/resource.yaml +1 -1
  159. package/library/skills/character-animation-wiring/SKILL.md +2 -2
  160. package/library/skills/character-model/SKILL.md +15 -26
  161. package/library/skills/character-movement/SKILL.md +1 -1
  162. package/library/skills/character-movement/references/movement-3d.md +1 -1
  163. package/library/skills/character-portrait/SKILL.md +4 -4
  164. package/library/skills/cinematic-cutscene/SKILL.md +38 -38
  165. package/library/skills/combat-basics/SKILL.md +1 -1
  166. package/library/skills/compatibility-renderer-traps/SKILL.md +78 -0
  167. package/library/skills/compatibility-renderer-traps/resource.yaml +28 -0
  168. package/library/skills/concept-art/SKILL.md +4 -4
  169. package/library/skills/create-asset-sheet/SKILL.md +12 -31
  170. package/library/skills/debug/SKILL.md +5 -4
  171. package/library/skills/debugging-game-feel/SKILL.md +1 -4
  172. package/library/skills/debugging-game-feel/resource.yaml +1 -1
  173. package/library/skills/design-level/SKILL.md +5 -5
  174. package/library/skills/design-mechanic/SKILL.md +6 -6
  175. package/library/skills/design-npc/SKILL.md +8 -15
  176. package/library/skills/diagnosing-perf-regressions/SKILL.md +5 -10
  177. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -19
  178. package/library/skills/environment-kit/SKILL.md +5 -5
  179. package/library/skills/export-and-ship/SKILL.md +25 -24
  180. package/library/skills/fabricating-assets/SKILL.md +1 -1
  181. package/library/skills/facial-and-lipsync/SKILL.md +5 -5
  182. package/library/skills/fps-controller/SKILL.md +17 -16
  183. package/library/skills/fps-controller/resource.yaml +0 -2
  184. package/library/skills/game-feel/SKILL.md +6 -7
  185. package/library/skills/gameskill/SKILL.md +3 -3
  186. package/library/skills/gdscript-patterns/SKILL.md +3 -3
  187. package/library/skills/generate-motion/SKILL.md +5 -22
  188. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +72 -90
  189. package/library/skills/godogen-visual-proof-game-generation/resource.yaml +0 -1
  190. package/library/skills/headless-scripting/SKILL.md +8 -8
  191. package/library/skills/headless-scripting/resource.yaml +1 -0
  192. package/library/skills/in-game-purchases/SKILL.md +123 -118
  193. package/library/skills/in-game-purchases/resource.yaml +2 -2
  194. package/library/skills/instantiate-asset-pack/SKILL.md +7 -3
  195. package/library/skills/investigating-bugs/SKILL.md +3 -11
  196. package/library/skills/investigating-bugs/condition-based-waiting.md +0 -10
  197. package/library/skills/investigating-bugs/root-cause-tracing.md +0 -8
  198. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +15 -15
  199. package/library/skills/lumera-single-image-scene-reconstruction/resource.yaml +0 -1
  200. package/library/skills/make-game/SKILL.md +3 -5
  201. package/library/skills/make-game/references/2d-platformer.md +1 -1
  202. package/library/skills/multiplayer-project/SKILL.md +1 -1
  203. package/library/skills/multiplayer-testing/SKILL.md +4 -4
  204. package/library/skills/music-track/SKILL.md +40 -38
  205. package/library/skills/new-project/SKILL.md +4 -6
  206. package/library/skills/organic-model/SKILL.md +9 -9
  207. package/library/skills/pixel-art/SKILL.md +6 -6
  208. package/library/skills/play/SKILL.md +3 -4
  209. package/library/skills/playtesting-a-feature/SKILL.md +4 -6
  210. package/library/skills/procedural-animation/SKILL.md +10 -11
  211. package/library/skills/prop-model/SKILL.md +4 -4
  212. package/library/skills/psx-retro-rendering/SKILL.md +20 -20
  213. package/library/skills/psx-retro-rendering/resource.yaml +2 -3
  214. package/library/skills/realtime-wet-surfaces/SKILL.md +15 -15
  215. package/library/skills/realtime-wet-surfaces/resource.yaml +1 -2
  216. package/library/skills/remote-deploy/SKILL.md +20 -21
  217. package/library/skills/retarget/SKILL.md +19 -23
  218. package/library/skills/running-in-the-cloud/SKILL.md +5 -5
  219. package/library/skills/scene-composition/SKILL.md +5 -5
  220. package/library/skills/scene-hierarchy-design/SKILL.md +3 -3
  221. package/library/skills/scene-hierarchy-design/resource.yaml +0 -1
  222. package/library/skills/scene-scripting/SKILL.md +3 -3
  223. package/library/skills/scene-to-level/SKILL.md +28 -31
  224. package/library/skills/skill-create/SKILL.md +1 -1
  225. package/library/skills/skill-improve/SKILL.md +9 -9
  226. package/library/skills/skill-test/SKILL.md +10 -10
  227. package/library/skills/skintokens-auto-rigging/SKILL.md +18 -18
  228. package/library/skills/skintokens-auto-rigging/resource.yaml +3 -3
  229. package/library/skills/skybox-panorama/SKILL.md +8 -9
  230. package/library/skills/sound-effect/SKILL.md +19 -19
  231. package/library/skills/spatial-placement/SKILL.md +2 -2
  232. package/library/skills/spatial-placement/references/kit-placement-tools.md +12 -22
  233. package/library/skills/sprite-sheet/SKILL.md +10 -10
  234. package/library/skills/summer-analytics/SKILL.md +3 -3
  235. package/library/skills/summer-friends/SKILL.md +10 -10
  236. package/library/skills/summer-leaderboards/SKILL.md +6 -6
  237. package/library/skills/summer-match-results/SKILL.md +13 -13
  238. package/library/skills/summer-matchmaking/SKILL.md +11 -11
  239. package/library/skills/summer-parties/SKILL.md +9 -9
  240. package/library/skills/summer-player-data/SKILL.md +12 -12
  241. package/library/skills/summer-store/SKILL.md +6 -6
  242. package/library/skills/summer-world-chat/SKILL.md +9 -9
  243. package/library/skills/summer-world-saves/SKILL.md +7 -7
  244. package/library/skills/text-to-motion/rigging-for-text-motion.md +1 -1
  245. package/library/skills/tileable-texture/SKILL.md +1 -1
  246. package/library/skills/trailer-shot/SKILL.md +36 -36
  247. package/library/skills/tune-performance/SKILL.md +13 -13
  248. package/library/skills/tune-performance/resource.yaml +1 -1
  249. package/library/skills/ui-graphics/SKILL.md +7 -7
  250. package/library/skills/use-widget-asset/SKILL.md +7 -7
  251. package/library/skills/using-summer/SKILL.md +5 -7
  252. package/library/skills/vehicle-model/SKILL.md +6 -7
  253. package/library/skills/vehicle-model/resource.yaml +2 -2
  254. package/library/skills/verification-before-completion/SKILL.md +5 -6
  255. package/library/skills/vfx-dissolve/SKILL.md +4 -4
  256. package/library/skills/vfx-fire/SKILL.md +6 -6
  257. package/library/skills/vfx-fire/_building-blocks/additive-billboard-particles.md +3 -3
  258. package/library/skills/vfx-hit-spark/SKILL.md +4 -4
  259. package/library/skills/vfx-hit-spark/_building-blocks/additive-billboard-particles.md +3 -3
  260. package/library/skills/vfx-lightning/SKILL.md +5 -5
  261. package/library/skills/vfx-lightning/_building-blocks/additive-billboard-particles.md +3 -3
  262. package/library/skills/vfx-lightning/_building-blocks/trauma-shake-snippet.md +9 -3
  263. package/library/skills/vfx-magic-glow/SKILL.md +4 -4
  264. package/library/skills/vfx-magic-glow/_building-blocks/additive-billboard-particles.md +3 -3
  265. package/library/skills/vfx-muzzle-flash/SKILL.md +5 -5
  266. package/library/skills/vfx-muzzle-flash/_building-blocks/additive-billboard-particles.md +3 -3
  267. package/library/skills/vfx-muzzle-flash/_building-blocks/trauma-shake-snippet.md +9 -3
  268. package/library/skills/vfx-smoke/SKILL.md +5 -5
  269. package/library/skills/vfx-water-ripple/SKILL.md +2 -2
  270. package/library/skills/vfx-water-ripple/_building-blocks/additive-billboard-particles.md +3 -3
  271. package/library/skills/voice-line/SKILL.md +9 -9
  272. package/library/skills/web-compatibility-look/resource.yaml +1 -0
  273. package/library/skills/world-building-3d/references/spatial-tools.md +2 -2
  274. package/library/skills/writing-plans/SKILL.md +4 -4
  275. package/library/skills/writing-skills/SKILL.md +8 -8
  276. package/library/tools/capture-gameplay/resource.yaml +73 -0
  277. package/library/tools/creator-publish/resource.yaml +4 -4
  278. package/library/tools/creator-releases/resource.yaml +5 -5
  279. package/library/tools/generate-image/resource.yaml +15 -1
  280. package/library/tools/publish-build/resource.yaml +6 -2
  281. package/package.json +1 -1
  282. package/registry/generated/aliases.json +1 -0
  283. package/registry/generated/counts.json +3 -3
  284. package/registry/generated/gemini-extension.json +3 -1
  285. package/registry/generated/index.json +248 -135
  286. package/registry/generated/marketplace.claude.json +2 -2
  287. package/registry/generated/plugin.claude.json +4 -2
  288. package/registry/generated/plugin.codex.json +5 -3
  289. package/registry/generated/plugin.cursor.json +4 -2
  290. package/registry/generated/plugin.factory.json +4 -2
  291. package/registry/generated/skills-index.md +11 -9
  292. package/registry/generated/skills-registry.json +33 -6
  293. package/registry/schemas/domains.json +1 -1
@@ -7,7 +7,7 @@ export { runEngine, SUMMER_GAMES_PRESET, type EngineRun };
7
7
  * summer_export_game: run the installed Summer Engine headless and return the
8
8
  * file the Summer Games store takes for the chosen targets.
9
9
  *
10
- * <engine> --headless --path <project> --export-release "<preset>" <out>
10
+ * <engine> --headless --summer-no-api --path <project> --export-release "<preset>" <out>
11
11
  *
12
12
  * format "bundle" (default): the summer.bundle.v1 .zip for build-publications
13
13
  * (summer_publish_build). Summer runs its client.pck on its own templates in
@@ -69,10 +69,16 @@ export interface ExportGameResult {
69
69
  icon?: string | null;
70
70
  /** Download format: what signing the file carries. */
71
71
  signing?: string;
72
+ /** Files in the project folder the export created, changed or removed (export_presets.cfg, project.godot, ...). */
73
+ projectChanges?: ProjectChange[];
72
74
  /** Things the store will still refuse or warn about, in plain words. */
73
75
  warnings?: string[];
74
76
  next: string;
75
77
  }
78
+ export interface ProjectChange {
79
+ file: string;
80
+ change: "created" | "modified" | "deleted";
81
+ }
76
82
  export interface LastExport {
77
83
  path: string;
78
84
  project: string;
@@ -84,6 +90,8 @@ export interface LastExport {
84
90
  }
85
91
  export interface ExportGameDependencies {
86
92
  findBinary: () => string | null;
93
+ /** Installed Summer version of the binary (Info.plist, sq.version), or null. */
94
+ engineVersion: (binary: string) => string | null;
87
95
  run: (binary: string, args: string[], timeoutMs: number) => Promise<EngineRun>;
88
96
  now: () => Date;
89
97
  /** Template lookup for download exports (overridable in tests). */
@@ -6,7 +6,8 @@ import { engineSelectionFromEnv } from "../engine.js";
6
6
  import { findEngineBinary } from "../engine-install.js";
7
7
  import { readStoreJson, writeStoreJson } from "../store.js";
8
8
  import { writeZip } from "../util/zip-write.js";
9
- import { runEngine } from "./engine-run.js";
9
+ import { engineErrorLines, runEngine } from "./engine-run.js";
10
+ import { assertExportEngine, installedEngineVersion } from "./export-engine-version.js";
10
11
  import { BUNDLE_TARGETS, DOWNLOAD_TARGETS, SUMMER_GAMES_PRESET, bundlePresetSpec, ensurePreset, normalizeTargets, variantString, } from "./export-presets.js";
11
12
  import { engineTemplateInfo, findInstalledTemplate, templateFileFor } from "./export-templates.js";
12
13
  import { BuildToolError, hashFile, readSummerBundle } from "./summer-bundle.js";
@@ -15,7 +16,7 @@ export { runEngine, SUMMER_GAMES_PRESET };
15
16
  * summer_export_game: run the installed Summer Engine headless and return the
16
17
  * file the Summer Games store takes for the chosen targets.
17
18
  *
18
- * <engine> --headless --path <project> --export-release "<preset>" <out>
19
+ * <engine> --headless --summer-no-api --path <project> --export-release "<preset>" <out>
19
20
  *
20
21
  * format "bundle" (default): the summer.bundle.v1 .zip for build-publications
21
22
  * (summer_publish_build). Summer runs its client.pck on its own templates in
@@ -35,15 +36,15 @@ export { runEngine, SUMMER_GAMES_PRESET };
35
36
  */
36
37
  export const LAST_EXPORT_FILE = "last-export.json";
37
38
  const DEFAULT_TIMEOUT_MS = 15 * 60_000;
38
- /** Store platform ids of the versions intake (summer-platform creatorstore). */
39
+ /** Store platform ids of the store's versions intake. */
39
40
  const STORE_VERSION_PLATFORM = {
40
41
  web: "web",
41
42
  macos: "macos-universal",
42
43
  windows: "windows-x64",
43
44
  };
44
- /** Web zip limits of the store (summer-platform internal/creatorstore/webzip.go). */
45
+ /** Web zip limits of the store. */
45
46
  const WEB_LIMITS = { zipBytes: 500 * 1024 * 1024, fileBytes: 200 * 1024 * 1024, files: 2000 };
46
- /** 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). */
47
48
  const STANDALONE_TARGETS = ["ios", "android"];
48
49
  /** Engine support per bundle target, for the recovery text when a target is missing. */
49
50
  const TARGET_ENGINE_NOTE = {
@@ -51,6 +52,7 @@ const TARGET_ENGINE_NOTE = {
51
52
  };
52
53
  const defaultDependencies = {
53
54
  findBinary: () => findEngineBinary(platform()),
55
+ engineVersion: installedEngineVersion,
54
56
  run: runEngine,
55
57
  now: () => new Date(),
56
58
  };
@@ -81,6 +83,69 @@ async function defaultExportDir(project) {
81
83
  function outputTail(output) {
82
84
  return output.trim().split("\n").slice(-40).join("\n");
83
85
  }
86
+ /** size and mtime of every file at the top of the project folder (project.godot, export_presets.cfg, ...). */
87
+ async function snapshotProjectFiles(project) {
88
+ const files = new Map();
89
+ for (const entry of await readdir(project, { withFileTypes: true })) {
90
+ if (!entry.isFile())
91
+ continue;
92
+ const info = await stat(join(project, entry.name)).catch(() => null);
93
+ if (info)
94
+ files.set(entry.name, `${info.size}:${info.mtimeMs}`);
95
+ }
96
+ return files;
97
+ }
98
+ async function projectChangesSince(project, before, output) {
99
+ const after = await snapshotProjectFiles(project);
100
+ const changes = [];
101
+ for (const [file, value] of after) {
102
+ if (output && resolve(project, file) === resolve(output))
103
+ continue;
104
+ if (!before.has(file))
105
+ changes.push({ file, change: "created" });
106
+ else if (before.get(file) !== value)
107
+ changes.push({ file, change: "modified" });
108
+ }
109
+ for (const file of before.keys())
110
+ if (!after.has(file))
111
+ changes.push({ file, change: "deleted" });
112
+ return changes.sort((a, b) => a.file.localeCompare(b.file));
113
+ }
114
+ function projectChangeWarnings(changes) {
115
+ return changes.some((entry) => entry.file === "project.godot" && entry.change === "modified")
116
+ ? ["Summer Engine rewrote project.godot while it exported (an engine update cleans up old settings; the previous file is project.godot.bak). Review the change and commit or revert it."]
117
+ : [];
118
+ }
119
+ /** Re-throw an export failure with the project files it already changed. */
120
+ async function withProjectChanges(project, before, work) {
121
+ try {
122
+ return await work();
123
+ }
124
+ catch (error) {
125
+ if (!(error instanceof BuildToolError))
126
+ throw error;
127
+ const changes = await projectChangesSince(project, before).catch(() => []);
128
+ if (!changes.length)
129
+ throw error;
130
+ throw new BuildToolError(error.code, error.message.replace(` ${error.recovery}`, ""), error.recovery, error.status, { ...error.detail, projectChanges: changes });
131
+ }
132
+ }
133
+ /** Plain recovery for what the engine printed; the generic preset hint only when a preset is what it names. */
134
+ function exportFailureRecovery(errors, preset) {
135
+ const text = errors.join("\n");
136
+ if (/export preset/i.test(text) && /(invalid|not found|no such|unknown)/i.test(text)) {
137
+ return `Recovery: this engine has no "${preset}" export preset, which means it predates summer.games exports: update Summer Engine to 0.7.0+ (run "summer install --yes"), then export again.`;
138
+ }
139
+ if (/source graph|client pack|authority|domain/i.test(text)) {
140
+ return ("Recovery: this is a hosted game whose source graph puts a resource the client loads in a server-only (authority) domain. " +
141
+ "Open the source graph summer.build.json names (source_graph, usually source-domains.json) and narrow the authority root to the server-only files " +
142
+ "(for example the authority scene and its script), so the scenes and resources the client starts (such as the network composition .tres) sit under a shared or client root. " +
143
+ "The multiplayer-project skill explains the domains. Then export again.");
144
+ }
145
+ return errors.length
146
+ ? "Recovery: fix what the engine names above and export again."
147
+ : "Recovery: the engine printed no ERROR line; read output, fix what it names, and export again.";
148
+ }
84
149
  /** One value from project.godot ([section] key=value), unquoted. */
85
150
  export function projectSetting(project, section, key) {
86
151
  let current = "";
@@ -189,7 +254,8 @@ async function listFiles(root) {
189
254
  return files.sort();
190
255
  }
191
256
  async function runExport(deps, binary, project, preset, out, debug, timeoutMs, notes) {
192
- const args = ["--headless", "--path", project, debug ? "--export-debug" : "--export-release", preset, out];
257
+ // --summer-no-api: an export needs no local HTTP API; nothing binds 127.0.0.1:6550 or writes discovery files.
258
+ const args = ["--headless", "--summer-no-api", "--path", project, debug ? "--export-debug" : "--export-release", preset, out];
193
259
  let run;
194
260
  try {
195
261
  run = await deps.run(binary, args, timeoutMs);
@@ -201,10 +267,9 @@ async function runExport(deps, binary, project, preset, out, debug, timeoutMs, n
201
267
  throw new BuildToolError("export_timeout", `The export did not finish within ${Math.round(timeoutMs / 1000)} seconds and was stopped.`, "Recovery: a first export imports every asset; retry with a larger timeoutSeconds.", undefined, { output: outputTail(run.output) });
202
268
  }
203
269
  if (run.code !== 0 || !existsSync(out)) {
204
- throw new BuildToolError("export_failed", `Summer Engine did not export the game (exit ${run.code ?? run.signal}).`, [
205
- `Recovery: read the engine output, fix what it names, and export again. A missing "${preset}" preset means this engine predates summer.games exports: update Summer Engine.`,
206
- ...notes,
207
- ].join(" "), undefined, { output: outputTail(run.output) });
270
+ const errors = run.errors?.length ? run.errors : engineErrorLines(run.output);
271
+ const named = errors.slice(0, 3).map((line) => line.replace(/^(SCRIPT )?ERROR:\s*/, ""));
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) });
208
273
  }
209
274
  }
210
275
  export async function exportGame(input, overrides = {}) {
@@ -227,15 +292,19 @@ export async function exportGame(input, overrides = {}) {
227
292
  if (!binary) {
228
293
  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.');
229
294
  }
295
+ // Before any preset is written: an old engine cannot read them.
296
+ assertExportEngine(binary, deps.engineVersion(binary));
230
297
  if (format === "download") {
231
298
  return exportDownload(deps, binary, project, targets[0], out, debug, timeoutMs, started);
232
299
  }
233
300
  out ??= join(await defaultExportDir(project), `${basename(project)}-${stamp(started)}.zip`);
234
301
  const before = existsSync(out) ? statSync(out).mtimeMs : null;
302
+ const projectBefore = await snapshotProjectFiles(project);
235
303
  const ensured = targets ? await ensurePreset(project, bundlePresetSpec(targets)) : undefined;
236
304
  const preset = ensured?.name ?? (input.preset?.trim() || SUMMER_GAMES_PRESET);
237
305
  const notes = (targets ?? []).flatMap((target) => TARGET_ENGINE_NOTE[target] ?? []);
238
- await runExport(deps, binary, project, preset, out, debug, timeoutMs, notes);
306
+ await withProjectChanges(project, projectBefore, () => runExport(deps, binary, project, preset, out, debug, timeoutMs, notes));
307
+ const projectChanges = await projectChangesSince(project, projectBefore, out);
239
308
  if (before !== null && statSync(out).mtimeMs === before) {
240
309
  throw new BuildToolError("export_failed", "Summer Engine exited without writing a new bundle.", "Recovery: read the engine output and export again.");
241
310
  }
@@ -244,7 +313,7 @@ export async function exportGame(input, overrides = {}) {
244
313
  if (missing.length) {
245
314
  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 });
246
315
  }
247
- const warnings = [];
316
+ const warnings = projectChangeWarnings(projectChanges);
248
317
  const desktopOnly = bundle.hosted ? [] : bundle.targetPlatforms.filter((target) => !STANDALONE_TARGETS.includes(target));
249
318
  if (desktopOnly.length) {
250
319
  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(", ")}. ` +
@@ -267,6 +336,7 @@ export async function exportGame(input, overrides = {}) {
267
336
  engine: binary,
268
337
  durationMs: deps.now().getTime() - started.getTime(),
269
338
  bundle: { ...summary, fileCount: files.length },
339
+ ...(projectChanges.length ? { projectChanges } : {}),
270
340
  ...(warnings.length ? { warnings } : {}),
271
341
  next: "Upload it to the game's store listing with summer_publish_build (gameId, clientVersion).",
272
342
  };
@@ -296,6 +366,7 @@ async function exportDownload(deps, binary, project, target, requestedOut, debug
296
366
  throw error;
297
367
  }
298
368
  const spec = downloadPresetSpec(target, slug);
369
+ const projectBefore = await snapshotProjectFiles(project);
299
370
  const ensured = await ensurePreset(project, spec);
300
371
  const exportsDir = await defaultExportDir(project);
301
372
  const work = join(exportsDir, `${slug}-${target}-${stamp(started)}`);
@@ -304,37 +375,41 @@ async function exportDownload(deps, binary, project, target, requestedOut, debug
304
375
  const out = requestedOut ?? join(exportsDir, `${slug}-${storePlatform}-${stamp(started)}.zip`);
305
376
  const warnings = [];
306
377
  let fileCount = 1;
307
- try {
308
- if (target === "macos") {
309
- // The macOS exporter writes the .app inside a .zip itself.
310
- const engineOut = join(work, `${slug}.zip`);
311
- await runExport(deps, binary, project, spec.name, engineOut, debug, timeoutMs, []);
312
- await rename(engineOut, out);
313
- warnings.push("macOS shows players an unidentified-developer prompt for an ad hoc signed app; the store accepts it as is.");
314
- }
315
- else {
316
- const engineOut = join(work, target === "web" ? "index.html" : `${slug}.exe`);
317
- await runExport(deps, binary, project, spec.name, engineOut, debug, timeoutMs, []);
318
- const files = await listFiles(work);
319
- const entries = files.map((file) => ({ name: relative(work, file).split(sep).join("/"), source: file }));
320
- if (target === "web") {
321
- const sizes = await Promise.all(files.map(async (file) => (await stat(file)).size));
322
- const total = sizes.reduce((sum, size) => sum + size, 0);
323
- const tooBig = entries.find((_entry, index) => sizes[index] > WEB_LIMITS.fileBytes);
324
- if (entries.length > WEB_LIMITS.files || total > WEB_LIMITS.zipBytes || tooBig) {
325
- throw new BuildToolError("web_build_too_large", `The web build has ${entries.length} files and ${Math.round(total / 1048576)} MiB${tooBig ? `; ${tooBig.name} is over 200 MiB` : ""}. The store takes at most ${WEB_LIMITS.files} files, 500 MiB, 200 MiB per file.`, "Recovery: exclude unused assets from the export (Project > Export > Resources) or compress textures, then export again.");
326
- }
378
+ await withProjectChanges(project, projectBefore, async () => {
379
+ try {
380
+ if (target === "macos") {
381
+ // The macOS exporter writes the .app inside a .zip itself.
382
+ const engineOut = join(work, `${slug}.zip`);
383
+ await runExport(deps, binary, project, spec.name, engineOut, debug, timeoutMs, []);
384
+ await rename(engineOut, out);
385
+ warnings.push("macOS shows players an unidentified-developer prompt for an ad hoc signed app; the store accepts it as is.");
327
386
  }
328
387
  else {
329
- warnings.push("The .exe is not code signed; Windows SmartScreen may warn players. The store accepts it as is.");
388
+ const engineOut = join(work, target === "web" ? "index.html" : `${slug}.exe`);
389
+ await runExport(deps, binary, project, spec.name, engineOut, debug, timeoutMs, []);
390
+ const files = await listFiles(work);
391
+ const entries = files.map((file) => ({ name: relative(work, file).split(sep).join("/"), source: file }));
392
+ if (target === "web") {
393
+ const sizes = await Promise.all(files.map(async (file) => (await stat(file)).size));
394
+ const total = sizes.reduce((sum, size) => sum + size, 0);
395
+ const tooBig = entries.find((_entry, index) => sizes[index] > WEB_LIMITS.fileBytes);
396
+ if (entries.length > WEB_LIMITS.files || total > WEB_LIMITS.zipBytes || tooBig) {
397
+ throw new BuildToolError("web_build_too_large", `The web build has ${entries.length} files and ${Math.round(total / 1048576)} MiB${tooBig ? `; ${tooBig.name} is over 200 MiB` : ""}. The store takes at most ${WEB_LIMITS.files} files, 500 MiB, 200 MiB per file.`, "Recovery: exclude unused assets from the export (Project > Export > Resources) or compress textures, then export again.");
398
+ }
399
+ }
400
+ else {
401
+ warnings.push("The .exe is not code signed; Windows SmartScreen may warn players. The store accepts it as is.");
402
+ }
403
+ await writeZip(out, entries);
404
+ fileCount = entries.length;
330
405
  }
331
- await writeZip(out, entries);
332
- fileCount = entries.length;
333
406
  }
334
- }
335
- finally {
336
- await rm(work, { recursive: true, force: true });
337
- }
407
+ finally {
408
+ await rm(work, { recursive: true, force: true });
409
+ }
410
+ });
411
+ const projectChanges = await projectChangesSince(project, projectBefore, out);
412
+ warnings.unshift(...projectChangeWarnings(projectChanges));
338
413
  const icon = projectSetting(project, "application", "config/icon");
339
414
  if (!icon)
340
415
  warnings.push("The project has no icon (Project Settings > Application > Config > Icon); the export uses the Summer default.");
@@ -358,6 +433,7 @@ async function exportDownload(deps, binary, project, target, requestedOut, debug
358
433
  fileCount,
359
434
  icon,
360
435
  signing: target === "macos" ? "ad hoc (built-in), not notarized" : "none",
436
+ ...(projectChanges.length ? { projectChanges } : {}),
361
437
  ...(warnings.length ? { warnings } : {}),
362
438
  next: `Upload it as the game's ${storePlatform} store version with summer_publish_build (gameId, clientVersion); it reads the platform from this export.`,
363
439
  };
@@ -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
@@ -6,19 +6,28 @@ export declare const imageGenerationArgsSchema: z.ZodObject<{
6
6
  style: z.ZodDefault<z.ZodString>;
7
7
  referenceImageUrl: z.ZodOptional<z.ZodString>;
8
8
  removeBackground: z.ZodOptional<z.ZodBoolean>;
9
+ aspectRatio: z.ZodOptional<z.ZodEnum<["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "5:4", "4:5", "21:9"]>>;
10
+ width: z.ZodOptional<z.ZodNumber>;
11
+ height: z.ZodOptional<z.ZodNumber>;
9
12
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
10
13
  }, "strip", z.ZodTypeAny, {
11
14
  prompt: string;
12
15
  model: string;
13
16
  style: string;
17
+ width?: number | undefined;
18
+ height?: number | undefined;
14
19
  options?: Record<string, any> | undefined;
15
20
  referenceImageUrl?: string | undefined;
16
21
  removeBackground?: boolean | undefined;
22
+ aspectRatio?: "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "5:4" | "4:5" | "21:9" | undefined;
17
23
  }, {
18
24
  prompt: string;
25
+ width?: number | undefined;
26
+ height?: number | undefined;
19
27
  options?: Record<string, any> | undefined;
20
28
  model?: string | undefined;
21
29
  style?: string | undefined;
22
30
  referenceImageUrl?: string | undefined;
23
31
  removeBackground?: boolean | undefined;
32
+ aspectRatio?: "1:1" | "16:9" | "9:16" | "4:3" | "3:4" | "3:2" | "2:3" | "5:4" | "4:5" | "21:9" | undefined;
24
33
  }>;
@@ -15,8 +15,26 @@ export const imageGenerationArgsSchema = z.object({
15
15
  .optional()
16
16
  .describe("Source image URL for img2img / edit mode. The prompt describes how to transform this image."),
17
17
  removeBackground: z.boolean().optional().describe("Remove the background server-side and return an alpha PNG for sprites, icons, or isolated objects."),
18
+ aspectRatio: z
19
+ .enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "5:4", "4:5", "21:9"])
20
+ .optional()
21
+ .describe("Aspect ratio of the output (default 1:1). The result reports the real width and height."),
22
+ width: z
23
+ .number()
24
+ .int()
25
+ .min(64)
26
+ .max(4096)
27
+ .optional()
28
+ .describe("Smallest output width in pixels; pass with height. 1920 with height 1080 for store key art, 1080 with 1920 for a tall cover."),
29
+ height: z
30
+ .number()
31
+ .int()
32
+ .min(64)
33
+ .max(4096)
34
+ .optional()
35
+ .describe("Smallest output height in pixels; pass with width."),
18
36
  options: z
19
37
  .record(z.any())
20
38
  .optional()
21
- .describe("Provider-specific params (guidance_scale, seed, image_size, negative_prompt, etc.)"),
39
+ .describe("Extra model params (seed, negative_prompt, ...). The result lists any it did not use in ignoredOptions."),
22
40
  });
@@ -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;
@@ -32,7 +32,7 @@ export interface Store {
32
32
  key?: string;
33
33
  }): Promise<T>;
34
34
  }
35
- export declare function storeError(status: number, code: string, message: string | undefined): BuildToolError;
35
+ export declare function storeError(status: number, code: string, message: string | undefined, requestId?: string): BuildToolError;
36
36
  export declare function createStore(baseUrl: string, token: string, deps: PublishBuildDependencies): Store;
37
37
  /** Whole-file and per-part SHA-256 ("sha256:<hex>") in one pass. */
38
38
  export declare function hashParts(path: string, partSize: number): Promise<{
@@ -57,6 +57,19 @@ export declare function uploadParts(sign: (partNumbers: number[]) => Promise<Gra
57
57
  partCount: number;
58
58
  }, deps: PublishBuildDependencies, parts?: number[]): Promise<void>;
59
59
  export declare function normalizeClientVersion(value?: string): string;
60
+ /**
61
+ * Before the person confirms, prove the target is real: the game exists for
62
+ * this account, and its store page lists the platforms the export targets.
63
+ */
64
+ export declare function checkStoreGame(gameId: string, exportTargets: string[], deps: PublishBuildDependencies): Promise<{
65
+ game: {
66
+ gameId: string;
67
+ name: string | null;
68
+ status: string | null;
69
+ targets: string[];
70
+ };
71
+ warnings: string[];
72
+ }>;
60
73
  export type PublishBuildResult = Record<string, unknown> & {
61
74
  ok: true;
62
75
  status: string;