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
@@ -5,10 +5,10 @@ allowed-tools: Read Write Edit Glob Grep Bash Skill
5
5
 
6
6
  # /gameskill — capture session learnings
7
7
 
8
- Activate the library skill `summer:gameskill` and follow it exactly; this command is only the entry point. If the `Skill` tool cannot find it, read `library/skills/gameskill/SKILL.md` from the Summer package (the plugin root, or `node_modules/summer-engine/`) and follow that file.
8
+ Activate the library skill `gameskill` and follow it exactly; this command is only the entry point. If the `Skill` tool cannot find it, read `library/skills/gameskill/SKILL.md` from the Summer package (the plugin root, or `node_modules/summer-engine/`) and follow that file.
9
9
 
10
10
  Ground rules the skill enforces, so you do not drift while it loads:
11
11
 
12
- - Default home is the game project's own skills directory for the agent you are in (`.claude/skills/<slug>/`, `.agents/skills/<slug>/`, `.cursor/rules/`). Only inside a checkout of the summer-engine agent repo do you add to `library/skills/<slug>/` (`resource.yaml` + `SKILL.md`, flat slugs); everything in `registry/generated/` and every plugin manifest is generated from it, so run `npm run generate:registry` after editing and never hand-edit those files. From anywhere else, send general lessons through `summer_library_feedback`.
12
+ - Default home is the game project's own skills directory for the agent you are in (`.claude/skills/<slug>/`, `.agents/skills/<slug>/`). Only inside a checkout of the Summer repo (`summerengine/summer`) do you add to `library/skills/<slug>/` (`resource.yaml` + `SKILL.md`, flat slugs); everything in `registry/generated/` and every plugin manifest is generated from it, so run `npm run generate:registry` after editing and never hand-edit those files. From anywhere else, send general lessons through `summer_library_feedback`.
13
13
  - Capture only learnings that are non-obvious AND general. Lead with the why. Real working code from the active project beats invented examples. VFX is shader + GDScript + node setup, never an image-generation pipeline.
14
14
  - It is fine to report "session was tactical, no durable learnings." Do not manufacture skills.
@@ -20,43 +20,43 @@ You know the engine cold. Scenes are `.tscn`, resources are `.tres`, scripts are
20
20
 
21
21
  You are opinionated about scope. When the user describes three features in one sentence, ask which one is the playable demo and defer the other two. "Wouldn't it be cool if" gets "yes, after the core loop runs." Get the core loop into the player's hands by the end of the session, then iterate. Polish happens after the game is playable, not before.
22
22
 
23
- You speak game-dev shorthand (PCs, NPCs, juice, hit-stop, root motion, blendspace, navmesh, kinematic vs rigid) and assume the user knows it. You are confident about cost: every generation has a number, and you say the number before spending the user's money.
23
+ You speak game-dev shorthand (PCs, NPCs, juice, hit-stop, root motion, blendspace, navmesh, kinematic vs rigid) and assume the user knows it. Asset generation spends the user's credits, so you say what you will generate before you spend them.
24
24
 
25
25
  ## What to do
26
26
 
27
27
  1. Detect the request shape (new game / new feature / new asset / bug / discussion / build).
28
- 2. Confirm Summer Engine context. Call `summer_get_project_context` if available. If it returns nothing, the user is not in a Summer project yet — route to `summer:brainstorm-game`.
28
+ 2. Confirm Summer Engine context. Call `summer_get_project_context` if available. If it returns nothing, the user is not in a Summer project yet — route to the `brainstorm-game` skill.
29
29
  3. Invoke the right Summer skill with the `Skill` tool. Do not paraphrase the skill; let the specialist run and follow it exactly.
30
- 4. State the estimated cost (dollars and seconds) before any generation call.
30
+ 4. Before any generation call, say what you will generate and roughly how long it takes, and wait for an OK.
31
31
 
32
32
  ## Routing
33
33
 
34
- Skills are flat slugs under the `summer:` namespace (`summer:<slug>`); there are no category paths.
34
+ Skills are invoked by their bare slug, such as `brainstorm-game`. There is no `summer:` prefix and there are no category paths.
35
35
 
36
36
  | Request shape | First skill |
37
37
  |---|---|
38
- | brainstorm a [genre] game / let's make a [genre] / I'm stuck / what should I work on | `summer:brainstorm-game` |
39
- | start a new project | `summer:new-project` |
40
- | make me a game from scratch | `summer:make-game` |
41
- | add a [character / enemy / NPC / prop / vehicle] | `summer:asset-strategy` |
42
- | add a sound for [event] | `summer:sound-effect` |
43
- | add ambient music | `summer:music-track` |
44
- | make me fire / smoke / lightning / muzzle flash / magic glow / hit spark / dissolve / water ripple | `summer:vfx-fire`, `summer:vfx-smoke`, `summer:vfx-lightning`, `summer:vfx-muzzle-flash`, `summer:vfx-magic-glow`, `summer:vfx-hit-spark`, `summer:vfx-dissolve`, `summer:vfx-water-ripple` |
45
- | build the FPS controller | `summer:fps-controller` |
46
- | debug / the game crashes when [X] / broken behavior / cloud or Codex failure / send this to support | `summer:debug` (support-report mode first: call `summer_create_debug_report` when available and tell the user where the Markdown report was written; keep fixing only if they also asked for a fix) |
47
- | add an animation to [character] | `summer:generate-motion` |
48
- | wire up a state machine for [character] | `summer:animation-tree` |
49
- | the game feels mushy / add juice | `summer:game-feel` |
50
- | ship a trailer | `summer:trailer-shot` |
51
- | cutscene for [X] | `summer:cinematic-cutscene` |
52
- | let me play it | `summer:play` |
53
-
54
- If nothing fits, activate `summer:using-summer` and call `summer_search_library` (then `summer_read_library`) to find the closest skill. Never invent a skill name; verify it exists first.
38
+ | brainstorm a [genre] game / let's make a [genre] / I'm stuck / what should I work on | `brainstorm-game` |
39
+ | start a new project | `new-project` |
40
+ | make me a game from scratch | `make-game` |
41
+ | add a [character / enemy / NPC / prop / vehicle] | `asset-strategy` |
42
+ | add a sound for [event] | `sound-effect` |
43
+ | add ambient music | `music-track` |
44
+ | make me fire / smoke / lightning / muzzle flash / magic glow / hit spark / dissolve / water ripple | `vfx-fire`, `vfx-smoke`, `vfx-lightning`, `vfx-muzzle-flash`, `vfx-magic-glow`, `vfx-hit-spark`, `vfx-dissolve`, `vfx-water-ripple` |
45
+ | build the FPS controller | `fps-controller` |
46
+ | debug / the game crashes when [X] / broken behavior / cloud or Codex failure / send this to support | `debug` (support-report mode first: call `summer_create_debug_report` when available and tell the user where the Markdown report was written; keep fixing only if they also asked for a fix) |
47
+ | add an animation to [character] | `generate-motion` |
48
+ | wire up a state machine for [character] | `animation-tree` |
49
+ | the game feels mushy / add juice | `game-feel` |
50
+ | ship a trailer | `trailer-shot` |
51
+ | cutscene for [X] | `cinematic-cutscene` |
52
+ | let me play it | `play` |
53
+
54
+ If nothing fits, activate `using-summer` and call `summer_search_library` (then `summer_read_library`) to find the closest skill. Never invent a skill name; verify it exists first.
55
55
 
56
56
  ## Tone rules
57
57
 
58
58
  - No corporate hedging. "I'd recommend" becomes "do this." "It might be worth considering" becomes "next step is."
59
- - Cost-aware: "Generating with kling. 5s, ~$0.50. OK?" — never "I'll generate a video now."
59
+ - Ask before spending: "Generating a 5s clip with kling, about 3 minutes. OK?" Never "I'll generate a video now."
60
60
  - Scope-aware: the cut list goes in `.summer/GameSoul.md`, not in V1.
61
61
  - Confirm before destructive moves: replacing nodes, deleting assets, regenerating expensive outputs.
62
62
  - Do not redirect users to external docs; solve it in-conversation.
@@ -70,12 +70,12 @@ If nothing fits, activate `summer:using-summer` and call `summer_search_library`
70
70
 
71
71
  > User: /summer make a knight
72
72
  >
73
- > Summer: Knight character. asset-strategy first to lock the look (concept image), then character-model for the rigged mesh. ~$0.10 for the concept, ~$0.40 for the 3D pass. OK?
73
+ > Summer: Knight character. asset-strategy first to lock the look (concept image), then character-model for the rigged mesh. Two generations. OK?
74
74
  >
75
- > [invokes `summer:asset-strategy`]
75
+ > [invokes `asset-strategy`]
76
76
 
77
77
  > User: /summer the game crashes when I pick up the sword
78
78
  >
79
79
  > Summer: Going to debug. Writing the support report first, then the fix.
80
80
  >
81
- > [invokes `summer:debug`]
81
+ > [invokes `debug`]
@@ -44,6 +44,16 @@ export declare function replaceMacApp(mountPoint: string, destApp: string, exec:
44
44
  * setup.exe CLI). The old NSIS flags (/S, /D=) are rejected by the Velopack
45
45
  * installer with "unexpected argument '/S' found" — this is the wizard bug. */
46
46
  export declare function windowsInstallerArgs(customPath?: string): string;
47
+ /** Printed after an install: the first start of a new engine is slow and silent. */
48
+ export declare const FIRST_START_NOTE: string;
49
+ /** Where the Velopack installer put Summer.exe: <dir>/current/Summer.exe for --path, else the default locations. */
50
+ export declare function windowsInstalledBinary(customPath?: string, exists?: (path: string) => boolean): string | null;
51
+ /**
52
+ * Download progress: rewrites one line on a terminal; elsewhere (an agent,
53
+ * a log file) one line per 10%, so a 1 GB download is about ten lines
54
+ * instead of hundreds of kilobytes.
55
+ */
56
+ export declare function createProgressReporter(isTTY: boolean, write: (text: string) => void): (downloaded: number, total: number) => void;
47
57
  export declare const installCommand: Command;
48
58
  export declare function downloadFile(url: string, dest: string): Promise<{
49
59
  sha256: string;
@@ -6,8 +6,8 @@ import { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renam
6
6
  import { pipeline } from "stream/promises";
7
7
  import { Readable } from "stream";
8
8
  import { tmpdir, platform } from "os";
9
- import { join, resolve } from "path";
10
- import { ENGINE_BINARY_ENV, LINUX_ENGINE_BINARY_NAME, findExtractedEngineBinary, linuxArchiveKind, linuxEngineInstallDir, pickLinuxReleaseAsset, resolveLinuxInstallSource, } from "../../core/engine-install.js";
9
+ import { dirname, join, resolve } from "path";
10
+ import { ENGINE_BINARY_ENV, LINUX_ENGINE_BINARY_NAME, macInstallDestination, recordEngineInstall, windowsEnginePaths, findExtractedEngineBinary, linuxArchiveKind, linuxEngineInstallDir, pickLinuxReleaseAsset, resolveLinuxInstallSource, } from "../../core/engine-install.js";
11
11
  const RELEASES_URL = "https://www.summerengine.com/api/desktop/releases";
12
12
  /** Guard a download URL from the releases endpoint. A missing/empty URL (an
13
13
  * outdated or misconfigured endpoint) otherwise becomes a cryptic
@@ -116,9 +116,42 @@ async function confirm(question) {
116
116
  export function windowsInstallerArgs(customPath) {
117
117
  return customPath ? `--silent --installto "${customPath}"` : "--silent";
118
118
  }
119
+ /** Printed after an install: the first start of a new engine is slow and silent. */
120
+ export const FIRST_START_NOTE = "The first start of a new engine version can take several minutes with no output " +
121
+ "(the system checks the new app and the engine builds its caches). Later starts are fast.";
122
+ /** Where the Velopack installer put Summer.exe: <dir>/current/Summer.exe for --path, else the default locations. */
123
+ export function windowsInstalledBinary(customPath, exists = existsSync) {
124
+ const candidates = customPath
125
+ ? [join(customPath, "current", "Summer.exe"), join(customPath, "Summer.exe")]
126
+ : windowsEnginePaths();
127
+ return candidates.find((path) => exists(path)) ?? null;
128
+ }
129
+ /**
130
+ * Download progress: rewrites one line on a terminal; elsewhere (an agent,
131
+ * a log file) one line per 10%, so a 1 GB download is about ten lines
132
+ * instead of hundreds of kilobytes.
133
+ */
134
+ export function createProgressReporter(isTTY, write) {
135
+ let lastStep = -1;
136
+ return (downloaded, total) => {
137
+ if (total <= 0)
138
+ return;
139
+ const pct = Math.min(100, Math.floor((downloaded / total) * 100));
140
+ const mb = (downloaded / 1024 / 1024).toFixed(1);
141
+ if (isTTY) {
142
+ write(`\r ${pct}% (${mb}MB)`);
143
+ return;
144
+ }
145
+ const step = Math.floor(pct / 10);
146
+ if (step > lastStep) {
147
+ lastStep = step;
148
+ write(` ${pct}% (${mb}MB)\n`);
149
+ }
150
+ };
151
+ }
119
152
  export const installCommand = new Command("install")
120
153
  .description("Download and install Summer Engine")
121
- .option("--path <dir>", "Custom install directory")
154
+ .option("--path <dir>", "Custom install directory (macOS: the engine goes in <dir>/Summer.app). summer remembers it, so later commands find this engine")
122
155
  .option("--yes", "Replace an already-installed engine without prompting")
123
156
  .action(async (opts) => {
124
157
  const os = platform();
@@ -160,7 +193,8 @@ async function installMac(releases, customPath, yes = false) {
160
193
  }
161
194
  const dmgUrl = requireDownloadUrl(info.dmg_url, "macOS DMG");
162
195
  console.log(`Latest version: ${info.version}`);
163
- const destApp = customPath || "/Applications/Summer.app";
196
+ const destApp = macInstallDestination(customPath);
197
+ const destBinary = join(destApp, "Contents", "MacOS", "Summer");
164
198
  const exists = existsSync(destApp);
165
199
  const installedVersion = exists ? readMacBundleVersion(destApp) : null;
166
200
  const plan = planMacInstall({
@@ -171,6 +205,7 @@ async function installMac(releases, customPath, yes = false) {
171
205
  isTTY: Boolean(process.stdin.isTTY),
172
206
  });
173
207
  if (plan.action === "up-to-date") {
208
+ await recordEngineInstall(destBinary, plan.version);
174
209
  console.log(`Summer Engine v${plan.version} is already installed at ${destApp} (up to date).`);
175
210
  return;
176
211
  }
@@ -218,6 +253,7 @@ async function installMac(releases, customPath, yes = false) {
218
253
  }
219
254
  try {
220
255
  console.log("Installing to " + destApp + "...");
256
+ mkdirSync(dirname(destApp), { recursive: true });
221
257
  replaceMacApp(mountPoint, destApp, (command) => execSync(command, { stdio: "ignore" }));
222
258
  console.log("Done!");
223
259
  }
@@ -235,7 +271,9 @@ async function installMac(releases, customPath, yes = false) {
235
271
  catch { }
236
272
  releaseSignals();
237
273
  }
274
+ await recordEngineInstall(destBinary, info.version);
238
275
  console.log(`\nSummer Engine v${info.version} installed to ${destApp}`);
276
+ console.log(FIRST_START_NOTE);
239
277
  console.log("\nNext steps:");
240
278
  console.log(" summer login # Sign in to your account");
241
279
  console.log(" summer run # Launch the engine");
@@ -276,7 +314,11 @@ async function installWindows(releases, customPath) {
276
314
  execSync(`del "${exePath}"`, { stdio: "ignore" });
277
315
  }
278
316
  catch { }
279
- console.log(`\nSummer Engine v${info.version} installed!`);
317
+ const installed = windowsInstalledBinary(customPath);
318
+ if (installed)
319
+ await recordEngineInstall(installed, info.version);
320
+ console.log(`\nSummer Engine v${info.version} installed${installed ? ` to ${installed}` : "!"}`);
321
+ console.log(FIRST_START_NOTE);
280
322
  console.log("\nNext steps:");
281
323
  console.log(" summer login # Sign in to your account");
282
324
  console.log(" summer run # Launch the engine");
@@ -338,6 +380,7 @@ async function installLinux(customPath) {
338
380
  const source = resolveLinuxInstallSource();
339
381
  if (source.kind === "binary") {
340
382
  registerExistingLinuxBinary(source.path, destDir, destBinary);
383
+ await recordEngineInstall(destBinary, null);
341
384
  printLinuxNextSteps(destBinary);
342
385
  return;
343
386
  }
@@ -409,7 +452,9 @@ async function installLinux(customPath) {
409
452
  finally {
410
453
  rmSync(downloadPath, { force: true });
411
454
  }
455
+ await recordEngineInstall(destBinary, versionLabel === "custom" ? null : versionLabel);
412
456
  console.log(`\nSummer Engine (${versionLabel}) installed to ${destBinary}`);
457
+ console.log(FIRST_START_NOTE);
413
458
  printLinuxNextSteps(destBinary);
414
459
  }
415
460
  function printLinuxNextSteps(binary) {
@@ -433,15 +478,15 @@ export async function downloadFile(url, dest) {
433
478
  const hash = createHash("sha256");
434
479
  let downloaded = 0;
435
480
  const total = parseInt(res.headers.get("content-length") || "0", 10);
481
+ const isTTY = Boolean(process.stdout.isTTY);
482
+ const report = createProgressReporter(isTTY, (text) => process.stdout.write(text));
436
483
  readable.on("data", (chunk) => {
437
484
  hash.update(chunk);
438
485
  downloaded += chunk.length;
439
- if (total > 0) {
440
- const pct = Math.round((downloaded / total) * 100);
441
- process.stdout.write(`\r ${pct}% (${(downloaded / 1024 / 1024).toFixed(1)}MB)`);
442
- }
486
+ report(downloaded, total);
443
487
  });
444
488
  await pipeline(readable, fileStream);
445
- process.stdout.write("\n");
489
+ if (isTTY)
490
+ process.stdout.write("\n");
446
491
  return { sha256: hash.digest("hex") };
447
492
  }
@@ -7,7 +7,7 @@ import { type OpenDeps, type OpenResult, type OpenSurface } from "../../core/cap
7
7
  * Summer Engine (launching it when it is not running). Any argument that is
8
8
  * an existing directory or looks like a filesystem path takes this branch,
9
9
  * so nothing that worked before changes.
10
- * 2. `summer open <target>` — navigation (docs/design/NAVIGATION-DESIGN.md):
10
+ * 2. `summer open <target>` — navigation:
11
11
  * a product-map id ("billing"), an intent phrase ("change my plan"), a
12
12
  * res:// path, or a summerengine.com path. Same behavior as the
13
13
  * summer_open MCP tool and `summer tool open` (core/capabilities/navigation).
@@ -13,7 +13,7 @@ export type RunBinaryResolution = {
13
13
  * (findEngineBinary, which also honours the older SUMMER_ENGINE_BINARY).
14
14
  * An explicit override is never silently swapped for the installed engine:
15
15
  * a missing path or a bare `.app` bundle is an error, because the caller
16
- * asked for THAT build (docs/design/archive/TK-VS-FOLD-2026-09-07.md, gap 5).
16
+ * asked for THAT build.
17
17
  */
18
18
  export declare function resolveRunBinary(binFlag: string | undefined, env?: NodeJS.ProcessEnv): RunBinaryResolution;
19
19
  export declare const runCommand: Command;
@@ -79,7 +79,7 @@ async function withLaunchLock(fn) {
79
79
  * (findEngineBinary, which also honours the older SUMMER_ENGINE_BINARY).
80
80
  * An explicit override is never silently swapped for the installed engine:
81
81
  * a missing path or a bare `.app` bundle is an error, because the caller
82
- * asked for THAT build (docs/design/archive/TK-VS-FOLD-2026-09-07.md, gap 5).
82
+ * asked for THAT build.
83
83
  */
84
84
  export function resolveRunBinary(binFlag, env = process.env) {
85
85
  const fromEnv = engineBinaryOverride(env);
@@ -340,7 +340,7 @@ skillsCommand
340
340
  console.log(previewIncludedLine(previewIncluded));
341
341
  if (previewSkipped > 0)
342
342
  console.log(previewSkippedLine(previewSkipped));
343
- // Claude Code: also install slash commands (`tools/summer-cli/commands/*.md`)
343
+ // Claude Code: also install slash commands (`commands/*.md`)
344
344
  // into `~/.claude/commands/`. Other agents don't have an equivalent today.
345
345
  if (agent === "claude-code") {
346
346
  const commandResults = installClaudeCommands(scope, Boolean(opts.force));
@@ -352,7 +352,7 @@ skillsCommand
352
352
  printInstallSummary(skills.length, agent, scope, location);
353
353
  });
354
354
  /**
355
- * Copy every `.md` file in `tools/summer-cli/commands/` to the user's
355
+ * Copy every `.md` file in the package's `commands/` to the user's
356
356
  * `~/.claude/commands/` directory so the slash commands (e.g. `/gameskill`)
357
357
  * are available on every machine that runs `summer skills install`.
358
358
  *
@@ -1,5 +1,12 @@
1
1
  import { Command } from "commander";
2
2
  import { type ToolDispatchEntry } from "../../core/capabilities/tool-dispatch.js";
3
+ import { callHostedToolForCli, listHostedToolsForCli, type HostedToolsListing } from "../../core/hosted-mcp.js";
4
+ /** The hosted store and publishing tools (Summer Engine MCP); replaceable in tests. */
5
+ export declare const hostedCli: {
6
+ list: typeof listHostedToolsForCli;
7
+ call: typeof callHostedToolForCli;
8
+ };
9
+ export declare function formatHostedToolList(listing: HostedToolsListing): string;
3
10
  /** Resolve a name through the compiled registry index when it exists —
4
11
  * accepts full ids ("tool/add-node") and legacy aliases, returning the slug
5
12
  * the dispatch table knows. Returns null when the index is absent or the
@@ -14,6 +14,25 @@ import { PACKAGE_ROOT } from "../../core/package-root.js";
14
14
  import { Command, Option } from "commander";
15
15
  import { ToolDispatchError, ToolResultError, dispatchTool, listToolDispatches, resolveToolDispatch, } from "../../core/capabilities/tool-dispatch.js";
16
16
  import { c } from "../../core/format.js";
17
+ import { callHostedToolForCli, hostedResultPayload, listHostedToolsForCli, } from "../../core/hosted-mcp.js";
18
+ /** The hosted store and publishing tools (Summer Engine MCP); replaceable in tests. */
19
+ export const hostedCli = { list: listHostedToolsForCli, call: callHostedToolForCli };
20
+ const STORE_SIGN_IN_HINT = "Store and publishing tools (summer_store_*, summer_upload_image_*, summer_list_projects, ...) come from the hosted Summer Engine MCP: run 'summer login --store' to use them here.";
21
+ export function formatHostedToolList(listing) {
22
+ if (listing.status === "not_signed_in")
23
+ return c.dim(STORE_SIGN_IN_HINT);
24
+ if (listing.status === "unavailable")
25
+ return c.dim(`Store and publishing tools: the hosted Summer Engine MCP did not answer (${listing.message}).`);
26
+ const local = new Set(listToolDispatches().map((entry) => `summer_${entry.slug.replace(/-/g, "_")}`));
27
+ const tools = listing.tools.filter((tool) => !local.has(tool.name)).sort((a, b) => a.name.localeCompare(b.name));
28
+ if (!tools.length)
29
+ return c.dim("Store and publishing tools: none listed by the hosted Summer Engine MCP.");
30
+ const width = Math.max(...tools.map((tool) => tool.name.length));
31
+ return [
32
+ c.bold(`Store and publishing tools (${tools.length}, hosted, with your store sign-in)`),
33
+ ...tools.map((tool) => ` ${tool.name.padEnd(width)} ${(tool.description ?? "").split(/(?<=\.)\s/)[0].slice(0, 120)}`),
34
+ ].join("\n");
35
+ }
17
36
  /** Resolve a name through the compiled registry index when it exists —
18
37
  * accepts full ids ("tool/add-node") and legacy aliases, returning the slug
19
38
  * the dispatch table knows. Returns null when the index is absent or the
@@ -86,6 +105,8 @@ export const toolCommand = new Command("tool")
86
105
  .action(async (name, options) => {
87
106
  if (options.list || name === undefined) {
88
107
  console.log(formatToolList(listToolDispatches()));
108
+ console.log("");
109
+ console.log(formatHostedToolList(await hostedCli.list()));
89
110
  if (name === undefined && !options.list) {
90
111
  console.log("");
91
112
  console.log(c.dim("Pass a tool name to run one."));
@@ -94,7 +115,21 @@ export const toolCommand = new Command("tool")
94
115
  }
95
116
  const entry = resolveToolForCli(name);
96
117
  if (!entry) {
97
- throw new ToolDispatchError(`Unknown tool "${name}". Run 'summer tool --list' to see all ${listToolDispatches().length} tools.`);
118
+ // Not a local tool: the hosted store and publishing tools, with the store sign-in.
119
+ const hosted = await hostedCli.call(name, parseJsonArgs(options.args ?? options.json));
120
+ if (hosted.status === "called") {
121
+ const payload = hostedResultPayload(hosted.result);
122
+ console.log(payload.json ? JSON.stringify(payload.json, null, 2) : payload.text);
123
+ if (payload.isError)
124
+ process.exitCode = 1;
125
+ return;
126
+ }
127
+ const why = hosted.status === "not_signed_in"
128
+ ? ` ${STORE_SIGN_IN_HINT}`
129
+ : hosted.status === "unavailable"
130
+ ? ` The hosted Summer Engine MCP did not answer: ${hosted.message}.`
131
+ : "";
132
+ throw new ToolDispatchError(`Unknown tool "${name}". Run 'summer tool --list' to see every tool.${why}`);
98
133
  }
99
134
  if (options.json !== undefined && options.args === undefined) {
100
135
  console.error("Note: 'summer tool --json <args>' is deprecated; use --args <json>.");
@@ -22,7 +22,7 @@ export type EngineSnapshot = {
22
22
  /** Structured failure classifier the engine returns on a game snapshot over
23
23
  * local HTTP (409 `bridge_required`) — surfaced verbatim so the tool can give
24
24
  * an honest, actionable message instead of a truncated generic 409 string.
25
- * When P4.4 lands (game snapshots answer 200/202 over HTTP) this simply
25
+ * Once game snapshots answer 200/202 over HTTP this simply
26
26
  * never fires and the tool works. */
27
27
  failureReason?: string;
28
28
  /** Scene-preview confession fields (P4.3). Populated only for target:"scene".
@@ -194,8 +194,8 @@ export declare class EngineApiClient {
194
194
  private _parseSnapshotResponse;
195
195
  /**
196
196
  * Turn a 409 from /api/snapshot/game into a structured failure. The engine's
197
- * structural refusal carries `bridge_required` / `unsupported_transport`
198
- * (tool_net_thread.cpp:495-503); a 409 without that shape is surfaced as a
197
+ * structural refusal carries `bridge_required` / `unsupported_transport`;
198
+ * a 409 without that shape is surfaced as a
199
199
  * plain error rather than silently claiming "bridge required".
200
200
  */
201
201
  private _bridgeRequiredFromResponse;
@@ -246,9 +246,8 @@ export declare class EngineApiClient {
246
246
  getPort(): number;
247
247
  /**
248
248
  * Cheap drift probe for the MCP client cache. The engine mints a fresh
249
- * api-token on every launch (local_api_server.cpp::_generate_api_token) and can
250
- * bind a different port (tool_net_thread.cpp::start increments 6550..6565 when
251
- * the old socket lingers), so a client built before an engine restart holds
249
+ * api-token on every launch and can bind a different port (it increments
250
+ * 6550..6565 when the old socket lingers), so a client built before an engine restart holds
252
251
  * dead credentials. Re-read the on-disk creds and report whether they no longer
253
252
  * match this client's snapshot.
254
253
  *
@@ -492,8 +492,7 @@ export class EngineApiClient {
492
492
  async getSceneState(scenePath, options) {
493
493
  // depth/limit/root only take effect on targeted (scene=) reads: the engine
494
494
  // routes those through the live command queue and forwards every query
495
- // param into StateProvider::scene_state (tool_net_thread.cpp
496
- // _parse_state_args). An UNtargeted read is answered from a pre-published
495
+ // param into the engine's scene-state reader. An UNtargeted read is answered from a pre-published
497
496
  // snapshot built with the defaults (depth 2, limit 200) and its query
498
497
  // params are ignored — callers who need depth/limit must pass scenePath
499
498
  // (summer_get_scene_tree resolves the current scene path for this).
@@ -515,9 +514,8 @@ export class EngineApiClient {
515
514
  async getProjectState(prefix) {
516
515
  // ?prefix= is sent for forward-compatibility, but current engine builds
517
516
  // IGNORE it: /api/state/project is always served from the snapshot, which
518
- // is published with empty args (local_api_server.cpp
519
- // _maybe_publish_snapshot), so StateProvider::project_state never sees the
520
- // query. Callers that need a prefix subset must also filter client-side
517
+ // is published with empty args, so the engine's project-state reader never
518
+ // sees the query. Callers that need a prefix subset must also filter client-side
521
519
  // (summer_get_project_context does).
522
520
  const query = prefix ? `?prefix=${encodeURIComponent(prefix)}` : "";
523
521
  return this.request("GET", `/api/state/project${query}`);
@@ -542,13 +540,13 @@ export class EngineApiClient {
542
540
  if (pins) {
543
541
  // Determinism params (seed / fixed_fps / time_scale) — the /api/play rung
544
542
  // copies ONLY `scene` from options into the PlayGame op
545
- // (local_api_server.cpp play branch), so a pinned launch travels as an
543
+ // (the engine's /api/play handler), so a pinned launch travels as an
546
544
  // explicit PlayGame op through /api/ops. executeOps stamps the bound
547
545
  // identity like every other op. An engine that predates the params
548
546
  // ignores the extra keys and answers the v1 result (no `determinism`).
549
547
  return this.executeOps([{ op: "PlayGame", ...(scene ? { scene } : {}), ...pins }], undefined, 60_000);
550
548
  }
551
- // The engine reads play params from body.options (tool_net_thread.cpp:503),
549
+ // The engine reads play params from body.options,
552
550
  // and the play handler reads options["scene"] — a top-level { scene } is
553
551
  // dropped, so the scene MUST be nested inside options. The bound identity
554
552
  // rides in the same options dict so play is refused on a mismatched project.
@@ -593,10 +591,10 @@ export class EngineApiClient {
593
591
  // with the same payload shape — _requestQueued resolves both.
594
592
  //
595
593
  // Game capture over local HTTP structurally 409s today with a STRUCTURED
596
- // reason (`failure_reason:"unsupported_transport"`, `bridge_required:true`,
597
- // tool_net_thread.cpp:495-503). Detect that specific shape and return it
594
+ // reason (`failure_reason:"unsupported_transport"`, `bridge_required:true`).
595
+ // Detect that specific shape and return it
598
596
  // verbatim so the tool can give an honest message — do NOT hardcode "game
599
- // always fails": once the engine answers 200/202 (P4.4), the same response
597
+ // always fails": once the engine answers 200/202, the same response
600
598
  // flows into the normal queued path. ONE request either way: a probe that
601
599
  // discarded a 200 (or orphaned an accepted 202 requestId) and then asked
602
600
  // again would capture the game twice.
@@ -681,8 +679,8 @@ export class EngineApiClient {
681
679
  }
682
680
  /**
683
681
  * Turn a 409 from /api/snapshot/game into a structured failure. The engine's
684
- * structural refusal carries `bridge_required` / `unsupported_transport`
685
- * (tool_net_thread.cpp:495-503); a 409 without that shape is surfaced as a
682
+ * structural refusal carries `bridge_required` / `unsupported_transport`;
683
+ * a 409 without that shape is surfaced as a
686
684
  * plain error rather than silently claiming "bridge required".
687
685
  */
688
686
  async _bridgeRequiredFromResponse(res) {
@@ -777,9 +775,8 @@ export class EngineApiClient {
777
775
  }
778
776
  /**
779
777
  * Cheap drift probe for the MCP client cache. The engine mints a fresh
780
- * api-token on every launch (local_api_server.cpp::_generate_api_token) and can
781
- * bind a different port (tool_net_thread.cpp::start increments 6550..6565 when
782
- * the old socket lingers), so a client built before an engine restart holds
778
+ * api-token on every launch and can bind a different port (it increments
779
+ * 6550..6565 when the old socket lingers), so a client built before an engine restart holds
783
780
  * dead credentials. Re-read the on-disk creds and report whether they no longer
784
781
  * match this client's snapshot.
785
782
  *
package/dist/core/auth.js CHANGED
@@ -161,8 +161,8 @@ export async function saveLoginSession(session) {
161
161
  // those exact files. credential-metadata.json adds audience/scope information
162
162
  // without changing or duplicating the secret.
163
163
  // Write order: user.json, then auth-token, then the advisory metadata. The
164
- // desktop engine cross-checks token.sub against user.json's id
165
- // (summerengine auth_manager.cpp, inspect_cli_bootstrap_credential), so a
164
+ // desktop engine cross-checks token.sub against user.json's id when it
165
+ // adopts the CLI credential, so a
166
166
  // write interrupted between the first two files fails closed instead of
167
167
  // adopting a mismatched identity. The metadata write is last and is NOT a
168
168
  // gate: the token is already live by then, and its contents are re-derived
@@ -2,7 +2,6 @@
2
2
  * Asset import into the engine-bound project (Kenney texture pairing + path
3
3
  * inference + optional scene placement). ONE copy shared by the MCP asset tools
4
4
  * and the CLI dispatch table.
5
- * See: publicsummerengine/Docs/ASSET_IMPORT_END_TO_END.md
6
5
  */
7
6
  import type { EngineApiClient } from "../api-client.js";
8
7
  /** An asset record as returned by the Summer gateway asset APIs. */
@@ -4,7 +4,7 @@ export type CameraBookmarkAction = (typeof CAMERA_BOOKMARK_ACTIONS)[number];
4
4
  export declare const CAMERA_BOOKMARK_OPS: Record<CameraBookmarkAction, string>;
5
5
  /** What the engine_lacks_op result tells the model to do instead. */
6
6
  export declare const CAMERA_BOOKMARK_FALLBACK = "pass the pose explicitly on every capture with summer_screenshot framing:\"free\" (camera_position + camera_look_at), or render through a Camera3D placed in the scene with framing:\"camera\"";
7
- /** Bookmark name grammar (preview_ops.cpp): 1-64 of [A-Za-z0-9_-]. */
7
+ /** Bookmark name grammar (same as the engine's): 1-64 of [A-Za-z0-9_-]. */
8
8
  export declare const BOOKMARK_NAME_PATTERN: RegExp;
9
9
  export interface CameraBookmarkArgs {
10
10
  action: CameraBookmarkAction;
@@ -4,7 +4,7 @@
4
4
  * and the CLI dispatcher so both faces validate the same way and send the same
5
5
  * op.
6
6
  *
7
- * Engine contract (doc/SUMMER/SCENE_SCRIPTING_CONTRACTS.md, "Wave I"):
7
+ * Engine contract:
8
8
  * SaveCameraBookmark { name, position?, look_at?, fov? } -> pose_source
9
9
  * ListCameraBookmarks {} -> names, bookmarks
10
10
  * DeleteCameraBookmark { name } -> remaining
@@ -25,7 +25,7 @@ export const CAMERA_BOOKMARK_OPS = {
25
25
  };
26
26
  /** What the engine_lacks_op result tells the model to do instead. */
27
27
  export const CAMERA_BOOKMARK_FALLBACK = "pass the pose explicitly on every capture with summer_screenshot framing:\"free\" (camera_position + camera_look_at), or render through a Camera3D placed in the scene with framing:\"camera\"";
28
- /** Bookmark name grammar (preview_ops.cpp): 1-64 of [A-Za-z0-9_-]. */
28
+ /** Bookmark name grammar (same as the engine's): 1-64 of [A-Za-z0-9_-]. */
29
29
  export const BOOKMARK_NAME_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
30
30
  function requireBookmarkName(name, action) {
31
31
  const trimmed = name?.trim() ?? "";
@@ -0,0 +1,69 @@
1
+ import { type EngineRun } from "./engine-run.js";
2
+ /**
3
+ * summer_capture_gameplay: real gameplay frames without a running editor.
4
+ *
5
+ * Reuses the engine's offscreen verify instance (the one RunVerification and
6
+ * tests/autopilot spawn): a real renderer in a window parked offscreen with no
7
+ * focus, so it never shows on screen, unlike --headless, which has no pixels.
8
+ *
9
+ * <engine> --disable-crash-handler --summer-no-api --path <project> --resolution WxH
10
+ * [--scene res://...] --summer-verify <probe.gd>
11
+ * --summer-verify-out <dir> --summer-verify-max <s>
12
+ *
13
+ * The stock probe waits for the scene to draw and settle, saves PNG frames of
14
+ * the game viewport, and writes results.json. The frames are what the game
15
+ * really draws, HUD included: use them as store screenshots.
16
+ */
17
+ export interface CaptureGameplayInput {
18
+ /** Project root (has project.godot). Defaults to the MCP's --project, then the working directory. */
19
+ project?: string;
20
+ /** Scene to start (res:// or uid://). Default: the project's main scene. */
21
+ scene?: string;
22
+ /** Window size, WIDTHxHEIGHT. Default 1920x1080; 1080x1920 for portrait. */
23
+ resolution?: string;
24
+ /** Frames to save. Default 1. */
25
+ frames?: number;
26
+ /** Seconds to let the game run before the first frame. Default 3. */
27
+ waitSeconds?: number;
28
+ /** Seconds between frames. Default 1. */
29
+ intervalSeconds?: number;
30
+ /** Output folder. Default <project>/.summer/captures/<time>/. */
31
+ out?: string;
32
+ }
33
+ export interface CapturedFrame {
34
+ path: string;
35
+ width: number;
36
+ height: number;
37
+ }
38
+ export interface CaptureGameplayResult {
39
+ ok: true;
40
+ project: string;
41
+ scene: string;
42
+ resolution: string;
43
+ frames: CapturedFrame[];
44
+ out: string;
45
+ engine: string;
46
+ imported: boolean;
47
+ durationMs: number;
48
+ warnings?: string[];
49
+ next: string;
50
+ }
51
+ export interface CaptureGameplayDependencies {
52
+ findBinary: () => string | null;
53
+ run: (binary: string, args: string[], timeoutMs: number) => Promise<EngineRun>;
54
+ now: () => Date;
55
+ }
56
+ /** Width and height from a PNG's IHDR chunk, or null when the file is not a PNG. */
57
+ export declare function pngSize(bytes: Buffer): {
58
+ width: number;
59
+ height: number;
60
+ } | null;
61
+ /**
62
+ * The stock probe. Self-contained (extends Node, no base class to copy into the
63
+ * project); follows the verify-instance contract of assets/autopilot/probe_base.gd:
64
+ * the engine sets summer_out_dir and summer_max_seconds before _ready(), the
65
+ * first frames are empty until the scene has drawn twice, results.json is
66
+ * always written.
67
+ */
68
+ export declare function captureProbeSource(frames: number, waitSeconds: number, intervalSeconds: number): string;
69
+ export declare function captureGameplay(input: CaptureGameplayInput, overrides?: Partial<CaptureGameplayDependencies>): Promise<CaptureGameplayResult>;