summer-engine 2.8.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (742) hide show
  1. package/.claude-plugin/marketplace.json +27 -7
  2. package/.claude-plugin/plugin.json +99 -83
  3. package/.codex-plugin/plugin.json +112 -82
  4. package/.cursor-plugin/plugin.json +119 -83
  5. package/.factory-plugin/plugin.json +100 -3
  6. package/.mcp.json +6 -1
  7. package/.opencode/INSTALL.md +7 -4
  8. package/.opencode/plugins/summer.js +31 -18
  9. package/AGENTS.md +107 -34
  10. package/CHANGELOG.md +134 -41
  11. package/CLAUDE.md +4 -2
  12. package/GEMINI.md +7 -53
  13. package/NOTICE +31 -0
  14. package/README.md +159 -391
  15. package/assets/api-docs.json.gz +0 -0
  16. package/assets/autopilot/README.md +20 -6
  17. package/assets/autopilot/autopilot.gd +80 -26
  18. package/assets/autopilot/run.sh +132 -7
  19. package/assets/navigation/web-routes.json +719 -0
  20. package/commands/gameskill.md +10 -108
  21. package/commands/summer.md +72 -4
  22. package/dist/bin/summer.js +6 -87
  23. package/dist/cli/banner.d.ts +1 -0
  24. package/dist/cli/banner.js +33 -0
  25. package/dist/{commands → cli/commands}/config.js +1 -1
  26. package/dist/cli/commands/create.d.ts +30 -0
  27. package/dist/cli/commands/create.js +212 -0
  28. package/dist/{commands → cli/commands}/debug.js +2 -2
  29. package/dist/cli/commands/doctor.d.ts +2 -0
  30. package/dist/cli/commands/doctor.js +18 -0
  31. package/dist/cli/commands/events.d.ts +57 -0
  32. package/dist/cli/commands/events.js +158 -0
  33. package/dist/cli/commands/install.d.ts +50 -0
  34. package/dist/cli/commands/install.js +447 -0
  35. package/dist/cli/commands/list.js +72 -0
  36. package/dist/{commands → cli/commands}/login.js +33 -17
  37. package/dist/{commands → cli/commands}/logout.d.ts +1 -0
  38. package/dist/cli/commands/logout.js +19 -0
  39. package/dist/{commands → cli/commands}/memory.d.ts +1 -8
  40. package/dist/{commands → cli/commands}/memory.js +20 -11
  41. package/dist/cli/commands/open.d.ts +45 -0
  42. package/dist/cli/commands/open.js +216 -0
  43. package/dist/{commands → cli/commands}/plan.js +2 -2
  44. package/dist/{commands → cli/commands}/publish.js +1 -1
  45. package/dist/{commands → cli/commands}/releases.js +1 -1
  46. package/dist/cli/commands/run.d.ts +19 -0
  47. package/dist/cli/commands/run.js +255 -0
  48. package/dist/{commands → cli/commands}/setup.js +43 -89
  49. package/dist/{commands → cli/commands}/skills.js +85 -222
  50. package/dist/{commands → cli/commands}/status.d.ts +1 -0
  51. package/dist/cli/commands/status.js +62 -0
  52. package/dist/cli/commands/tool.d.ts +11 -0
  53. package/dist/cli/commands/tool.js +121 -0
  54. package/dist/cli/index.d.ts +6 -0
  55. package/dist/cli/index.js +89 -0
  56. package/dist/cli/root-action.d.ts +7 -0
  57. package/dist/cli/root-action.js +15 -0
  58. package/dist/{lib → core}/api-client.d.ts +106 -15
  59. package/dist/{lib → core}/api-client.js +267 -75
  60. package/dist/{lib → core}/async-op-lifecycle.d.ts +3 -4
  61. package/dist/{lib → core}/async-op-lifecycle.js +3 -4
  62. package/dist/{lib → core}/auth.d.ts +14 -6
  63. package/dist/{lib → core}/auth.js +56 -40
  64. package/dist/core/capabilities/agent-playbook.d.ts +20 -0
  65. package/dist/core/capabilities/agent-playbook.js +218 -0
  66. package/dist/core/capabilities/api-docs.d.ts +36 -0
  67. package/dist/core/capabilities/api-docs.js +118 -0
  68. package/dist/core/capabilities/asset-import.d.ts +49 -0
  69. package/dist/core/capabilities/asset-import.js +134 -0
  70. package/dist/core/capabilities/camera-view.d.ts +98 -0
  71. package/dist/core/capabilities/camera-view.js +222 -0
  72. package/dist/core/capabilities/capture.d.ts +63 -0
  73. package/dist/core/capabilities/capture.js +67 -0
  74. package/dist/core/capabilities/console-read.d.ts +17 -0
  75. package/dist/core/capabilities/console-read.js +21 -0
  76. package/dist/{lib → core/capabilities}/creator.d.ts +1 -29
  77. package/dist/{lib → core/capabilities}/creator.js +14 -33
  78. package/dist/{lib → core/capabilities}/debug-report.d.ts +1 -1
  79. package/dist/{lib → core/capabilities}/debug-report.js +12 -31
  80. package/dist/{commands → core/capabilities}/doctor.d.ts +7 -2
  81. package/dist/{commands → core/capabilities}/doctor.js +47 -73
  82. package/dist/core/capabilities/engine-fallbacks.d.ts +26 -0
  83. package/dist/core/capabilities/engine-fallbacks.js +36 -0
  84. package/dist/core/capabilities/engine-ops.d.ts +33 -0
  85. package/dist/core/capabilities/engine-ops.js +145 -0
  86. package/dist/core/capabilities/engine-receipt.d.ts +53 -0
  87. package/dist/core/capabilities/engine-receipt.js +134 -0
  88. package/dist/core/capabilities/events.d.ts +200 -0
  89. package/dist/core/capabilities/events.js +383 -0
  90. package/dist/core/capabilities/fabricate-mesh.d.ts +111 -0
  91. package/dist/core/capabilities/fabricate-mesh.js +165 -0
  92. package/dist/core/capabilities/frame-quality.d.ts +71 -0
  93. package/dist/core/capabilities/frame-quality.js +449 -0
  94. package/dist/core/capabilities/game-task-plan.d.ts +66 -0
  95. package/dist/{lib → core/capabilities}/game-task-plan.js +59 -8
  96. package/dist/core/capabilities/hdri-import.d.ts +90 -0
  97. package/dist/core/capabilities/hdri-import.js +250 -0
  98. package/dist/core/capabilities/image-generation.d.ts +24 -0
  99. package/dist/core/capabilities/image-generation.js +22 -0
  100. package/dist/core/capabilities/navigation/open.d.ts +156 -0
  101. package/dist/core/capabilities/navigation/open.js +567 -0
  102. package/dist/core/capabilities/navigation/render-product-map.d.ts +1 -0
  103. package/dist/core/capabilities/navigation/render-product-map.js +84 -0
  104. package/dist/core/capabilities/navigation/targets.d.ts +87 -0
  105. package/dist/core/capabilities/navigation/targets.js +250 -0
  106. package/dist/core/capabilities/play-determinism.d.ts +35 -0
  107. package/dist/core/capabilities/play-determinism.js +86 -0
  108. package/dist/core/capabilities/project-context.d.ts +114 -0
  109. package/dist/core/capabilities/project-context.js +249 -0
  110. package/dist/core/capabilities/runtime-control.d.ts +540 -0
  111. package/dist/core/capabilities/runtime-control.js +1011 -0
  112. package/dist/core/capabilities/scene-kind.d.ts +19 -0
  113. package/dist/core/capabilities/scene-kind.js +137 -0
  114. package/dist/core/capabilities/scene-script.d.ts +38 -0
  115. package/dist/core/capabilities/scene-script.js +45 -0
  116. package/dist/core/capabilities/tool-dispatch.d.ts +42 -0
  117. package/dist/core/capabilities/tool-dispatch.js +1490 -0
  118. package/dist/core/capabilities/ui-control.d.ts +179 -0
  119. package/dist/core/capabilities/ui-control.js +423 -0
  120. package/dist/core/capabilities/variant-types.d.ts +22 -0
  121. package/dist/core/capabilities/variant-types.js +101 -0
  122. package/dist/core/capability-skew.d.ts +205 -0
  123. package/dist/core/capability-skew.js +386 -0
  124. package/dist/{lib → core}/config.d.ts +11 -1
  125. package/dist/{lib → core}/config.js +13 -2
  126. package/dist/core/embeddings.d.ts +78 -0
  127. package/dist/core/embeddings.js +166 -0
  128. package/dist/core/engine-install.d.ts +105 -0
  129. package/dist/core/engine-install.js +190 -0
  130. package/dist/core/engine.d.ts +94 -0
  131. package/dist/{lib → core}/engine.js +74 -28
  132. package/dist/core/feedback/client.d.ts +88 -0
  133. package/dist/core/feedback/client.js +182 -0
  134. package/dist/{lib → core}/format.d.ts +0 -1
  135. package/dist/{lib → core}/format.js +1 -1
  136. package/dist/core/headless/connection.d.ts +86 -0
  137. package/dist/core/headless/connection.js +97 -0
  138. package/dist/core/headless/editor-connection.d.ts +26 -0
  139. package/dist/core/headless/editor-connection.js +81 -0
  140. package/dist/core/headless/mcp-routing.d.ts +38 -0
  141. package/dist/core/headless/mcp-routing.js +83 -0
  142. package/dist/core/headless/registry.d.ts +91 -0
  143. package/dist/core/headless/registry.js +226 -0
  144. package/dist/core/headless/resolve.d.ts +46 -0
  145. package/dist/core/headless/resolve.js +75 -0
  146. package/dist/core/headless/spawn.d.ts +46 -0
  147. package/dist/core/headless/spawn.js +205 -0
  148. package/dist/core/headless/worker-connection.d.ts +96 -0
  149. package/dist/core/headless/worker-connection.js +353 -0
  150. package/dist/core/headless/worker-engine-client.d.ts +58 -0
  151. package/dist/core/headless/worker-engine-client.js +246 -0
  152. package/dist/core/launch-posture.d.ts +170 -0
  153. package/dist/core/launch-posture.js +317 -0
  154. package/dist/core/library-read.d.ts +73 -0
  155. package/dist/core/library-read.js +279 -0
  156. package/dist/core/library-search.d.ts +143 -0
  157. package/dist/core/library-search.js +301 -0
  158. package/dist/{lib → core}/log-filters.js +4 -2
  159. package/dist/{lib → core}/mcp-log.js +2 -17
  160. package/dist/core/package-root.d.ts +9 -0
  161. package/dist/core/package-root.js +11 -0
  162. package/dist/core/redact.d.ts +20 -0
  163. package/dist/core/redact.js +64 -0
  164. package/dist/core/registry-search.d.ts +167 -0
  165. package/dist/core/registry-search.js +358 -0
  166. package/dist/core/skills-registry.d.ts +47 -0
  167. package/dist/core/skills-registry.js +83 -0
  168. package/dist/{lib → core}/store.js +11 -7
  169. package/dist/{lib → core}/summer-compatibility.js +3 -3
  170. package/dist/{lib → core}/telemetry.js +5 -2
  171. package/dist/core/templates.d.ts +98 -0
  172. package/dist/core/templates.js +241 -0
  173. package/dist/core/tool-errors.d.ts +30 -0
  174. package/dist/core/tool-errors.js +40 -0
  175. package/dist/core/trajectory.d.ts +80 -0
  176. package/dist/core/trajectory.js +307 -0
  177. package/dist/core/util/http.d.ts +13 -0
  178. package/dist/core/util/http.js +28 -0
  179. package/dist/core/util/json.d.ts +12 -0
  180. package/dist/core/util/json.js +21 -0
  181. package/dist/core/util/process.d.ts +3 -0
  182. package/dist/core/util/process.js +13 -0
  183. package/dist/core/util/sleep.d.ts +1 -0
  184. package/dist/core/util/sleep.js +3 -0
  185. package/dist/core/version.d.ts +3 -0
  186. package/dist/core/version.js +5 -0
  187. package/dist/{lib → installer}/agent-config.d.ts +20 -1
  188. package/dist/{lib → installer}/agent-config.js +148 -23
  189. package/dist/installer/legacy-skills.d.ts +26 -0
  190. package/dist/installer/legacy-skills.js +53 -0
  191. package/dist/installer/setup.d.ts +76 -0
  192. package/dist/installer/setup.js +146 -0
  193. package/dist/installer/skill-locations.d.ts +45 -0
  194. package/dist/installer/skill-locations.js +170 -0
  195. package/dist/installer/version-check.d.ts +174 -0
  196. package/dist/{lib → installer}/version-check.js +173 -42
  197. package/dist/{lib/mcp-boot-notice.d.ts → mcp/boot-notice.d.ts} +1 -1
  198. package/dist/{commands/mcp.js → mcp/command.js} +18 -6
  199. package/dist/mcp/server.d.ts +23 -3
  200. package/dist/mcp/server.js +122 -28
  201. package/dist/mcp/tools/asset-tools.js +62 -142
  202. package/dist/mcp/tools/creator-tools.js +5 -23
  203. package/dist/mcp/tools/debug-tools.js +61 -18
  204. package/dist/mcp/tools/event-tools.d.ts +14 -0
  205. package/dist/mcp/tools/event-tools.js +41 -0
  206. package/dist/mcp/tools/fabricate-tools.d.ts +2 -0
  207. package/dist/mcp/tools/fabricate-tools.js +28 -0
  208. package/dist/mcp/tools/feedback-tools.d.ts +77 -0
  209. package/dist/mcp/tools/feedback-tools.js +88 -0
  210. package/dist/mcp/tools/file-tools.js +6 -53
  211. package/dist/mcp/tools/generate-tools.js +37 -63
  212. package/dist/mcp/tools/library-tools.d.ts +11 -0
  213. package/dist/mcp/tools/library-tools.js +42 -0
  214. package/dist/mcp/tools/navigation-tools.d.ts +7 -0
  215. package/dist/mcp/tools/navigation-tools.js +37 -0
  216. package/dist/mcp/tools/perception-tools.d.ts +20 -0
  217. package/dist/mcp/tools/perception-tools.js +146 -0
  218. package/dist/mcp/tools/project-tools.d.ts +14 -0
  219. package/dist/mcp/tools/project-tools.js +72 -281
  220. package/dist/mcp/tools/runtime-tools.d.ts +2 -0
  221. package/dist/mcp/tools/runtime-tools.js +92 -0
  222. package/dist/mcp/tools/scene-tools.d.ts +3 -0
  223. package/dist/mcp/tools/scene-tools.js +68 -119
  224. package/dist/mcp/tools/script-tools.d.ts +3 -0
  225. package/dist/mcp/tools/script-tools.js +118 -0
  226. package/dist/mcp/tools/spatial-tools.d.ts +2 -0
  227. package/dist/mcp/tools/spatial-tools.js +485 -0
  228. package/dist/mcp/tools/text-json.d.ts +8 -0
  229. package/dist/mcp/tools/text-json.js +12 -0
  230. package/dist/mcp/tools/{cloud-tools.d.ts → ui-tools.d.ts} +1 -1
  231. package/dist/mcp/tools/ui-tools.js +82 -0
  232. package/dist/mcp/tools/visual-tools.d.ts +2 -7
  233. package/dist/mcp/tools/visual-tools.js +383 -101
  234. package/dist/mcp/tools/with-engine.d.ts +9 -15
  235. package/dist/mcp/tools/with-engine.js +60 -96
  236. package/dist/project-memory/project-manifest.d.ts +36 -0
  237. package/dist/project-memory/project-manifest.js +50 -0
  238. package/dist/project-memory/project-memory.d.ts +57 -0
  239. package/dist/{lib → project-memory}/project-memory.js +46 -0
  240. package/gemini-extension.json +103 -2
  241. package/hooks/hooks-cursor.json +2 -2
  242. package/hooks/hooks.json +2 -1
  243. package/hooks/pre-commit-doctor.sh +45 -39
  244. package/hooks/run-hook.cmd +30 -23
  245. package/hooks/run-hook.sh +20 -0
  246. package/hooks/session-start.sh +18 -7
  247. package/integrations/README.md +70 -0
  248. package/integrations/claude/README.md +19 -0
  249. package/integrations/claude/manifest-target.json +16 -0
  250. package/integrations/cline/README.md +13 -0
  251. package/integrations/cline/manifest-target.json +3 -0
  252. package/integrations/codex/README.md +15 -0
  253. package/integrations/codex/manifest-target.json +5 -0
  254. package/integrations/cursor/README.md +16 -0
  255. package/integrations/cursor/manifest-target.json +5 -0
  256. package/integrations/factory/README.md +26 -0
  257. package/integrations/factory/manifest-target.json +5 -0
  258. package/integrations/gemini/README.md +26 -0
  259. package/integrations/gemini/manifest-target.json +5 -0
  260. package/integrations/github-copilot/README.md +12 -0
  261. package/integrations/github-copilot/manifest-target.json +3 -0
  262. package/integrations/kilo-code/README.md +16 -0
  263. package/integrations/kilo-code/manifest-target.json +3 -0
  264. package/integrations/lm-studio/README.md +12 -0
  265. package/integrations/lm-studio/manifest-target.json +3 -0
  266. package/integrations/opencode/README.md +15 -0
  267. package/integrations/opencode/manifest-target.json +3 -0
  268. package/integrations/roo-code/README.md +13 -0
  269. package/integrations/roo-code/manifest-target.json +3 -0
  270. package/integrations/vscode-copilot/README.md +12 -0
  271. package/integrations/vscode-copilot/manifest-target.json +3 -0
  272. package/integrations/windsurf/README.md +13 -0
  273. package/integrations/windsurf/manifest-target.json +3 -0
  274. package/library/references/collaborative-protocol/resource.yaml +24 -0
  275. package/library/references/gd-style/resource.yaml +24 -0
  276. package/{references → library/references/godot-version}/godot-version.md +6 -6
  277. package/library/references/godot-version/resource.yaml +22 -0
  278. package/library/references/headless-routing/headless-routing.md +46 -0
  279. package/library/references/headless-routing/resource.yaml +24 -0
  280. package/library/references/mcp-fresh-chat-playbook/mcp-fresh-chat-playbook.md +49 -0
  281. package/library/references/mcp-fresh-chat-playbook/resource.yaml +23 -0
  282. package/library/references/mcp-tools-reference/mcp-tools-reference.md +271 -0
  283. package/library/references/mcp-tools-reference/resource.yaml +17 -0
  284. package/library/references/product-map/product-map.md +103 -0
  285. package/library/references/product-map/resource.yaml +33 -0
  286. package/{references → library/references/public-surface-language}/public-surface-language.md +5 -7
  287. package/library/references/public-surface-language/resource.yaml +17 -0
  288. package/library/references/summer-folder/resource.yaml +20 -0
  289. package/{references → library/references/summer-folder}/summer-folder.md +22 -21
  290. package/{skills/rendering-and-lighting → library/skills}/3d-lighting/SKILL.md +15 -11
  291. package/library/skills/3d-lighting/resource.yaml +27 -0
  292. package/{skills/audio → library/skills}/adaptive-music/SKILL.md +1 -1
  293. package/library/skills/adaptive-music/resource.yaml +28 -0
  294. package/library/skills/agent-playtesting/SKILL.md +148 -0
  295. package/library/skills/agent-playtesting/resource.yaml +52 -0
  296. package/library/skills/ambient-bed/resource.yaml +24 -0
  297. package/{skills/video → library/skills}/animated-loop/SKILL.md +1 -1
  298. package/library/skills/animated-loop/resource.yaml +27 -0
  299. package/{skills/animation → library/skills}/animation-tree/SKILL.md +29 -14
  300. package/library/skills/animation-tree/resource.yaml +33 -0
  301. package/{skills/rendering-and-lighting → library/skills}/art-direction/SKILL.md +3 -3
  302. package/library/skills/art-direction/resource.yaml +29 -0
  303. package/{skills/asset-pipeline → library/skills}/asset-strategy/SKILL.md +44 -44
  304. package/library/skills/asset-strategy/resource.yaml +63 -0
  305. package/{skills/audio → library/skills}/audio-direction/SKILL.md +7 -7
  306. package/library/skills/audio-direction/resource.yaml +32 -0
  307. package/library/skills/auto-fire-targeting/resource.yaml +22 -0
  308. package/{skills/scene-and-project → library/skills}/brainstorm-game/SKILL.md +8 -8
  309. package/library/skills/brainstorm-game/resource.yaml +30 -0
  310. package/{skills/workflow → library/skills}/brainstorming/SKILL.md +2 -22
  311. package/library/skills/brainstorming/resource.yaml +23 -0
  312. package/{skills/workflow → library/skills}/brainstorming/spec-document-reviewer-prompt.md +1 -1
  313. package/{skills/scene-and-project → library/skills}/browse-templates/SKILL.md +18 -18
  314. package/library/skills/browse-templates/resource.yaml +23 -0
  315. package/library/skills/celeste-momentum-platforming/SKILL.md +366 -0
  316. package/library/skills/celeste-momentum-platforming/resource.yaml +33 -0
  317. package/library/skills/character-animation-wiring/SKILL.md +249 -0
  318. package/library/skills/character-animation-wiring/resource.yaml +39 -0
  319. package/{skills/3d-assets → library/skills}/character-model/SKILL.md +25 -25
  320. package/library/skills/character-model/resource.yaml +36 -0
  321. package/{skills/2d-assets → library/skills}/character-portrait/SKILL.md +14 -14
  322. package/library/skills/character-portrait/resource.yaml +30 -0
  323. package/{skills/video → library/skills}/cinematic-cutscene/SKILL.md +2 -2
  324. package/library/skills/cinematic-cutscene/resource.yaml +29 -0
  325. package/{skills/2d-assets → library/skills}/concept-art/SKILL.md +15 -15
  326. package/library/skills/concept-art/resource.yaml +34 -0
  327. package/{skills/2d-assets → library/skills}/create-asset-sheet/SKILL.md +8 -8
  328. package/library/skills/create-asset-sheet/resource.yaml +33 -0
  329. package/{skills/debugging → library/skills}/debug/SKILL.md +3 -3
  330. package/library/skills/debug/resource.yaml +31 -0
  331. package/{skills/workflow → library/skills}/debugging-game-feel/SKILL.md +11 -11
  332. package/library/skills/debugging-game-feel/resource.yaml +25 -0
  333. package/{skills/level-design → library/skills}/design-level/SKILL.md +6 -6
  334. package/library/skills/design-level/resource.yaml +31 -0
  335. package/{skills/gameplay-mechanics → library/skills}/design-mechanic/SKILL.md +3 -3
  336. package/library/skills/design-mechanic/resource.yaml +31 -0
  337. package/{skills/ai-and-npcs → library/skills}/design-npc/SKILL.md +7 -3
  338. package/library/skills/design-npc/resource.yaml +29 -0
  339. package/{skills/workflow → library/skills}/diagnosing-perf-regressions/SKILL.md +10 -10
  340. package/library/skills/diagnosing-perf-regressions/resource.yaml +25 -0
  341. package/{skills/workflow → library/skills}/dispatching-parallel-agents/SKILL.md +8 -8
  342. package/library/skills/dispatching-parallel-agents/resource.yaml +23 -0
  343. package/library/skills/driving-the-editor-ui/SKILL.md +85 -0
  344. package/library/skills/driving-the-editor-ui/resource.yaml +46 -0
  345. package/{skills/3d-assets → library/skills}/environment-kit/SKILL.md +11 -11
  346. package/library/skills/environment-kit/resource.yaml +29 -0
  347. package/{skills/deployment → library/skills}/export-and-ship/SKILL.md +5 -5
  348. package/library/skills/export-and-ship/resource.yaml +32 -0
  349. package/library/skills/fabricating-assets/SKILL.md +195 -0
  350. package/library/skills/fabricating-assets/resource.yaml +52 -0
  351. package/{skills/animation → library/skills}/facial-and-lipsync/SKILL.md +23 -11
  352. package/library/skills/facial-and-lipsync/resource.yaml +36 -0
  353. package/{skills/character-controllers → library/skills}/fps-controller/SKILL.md +8 -4
  354. package/library/skills/fps-controller/resource.yaml +29 -0
  355. package/{skills/visual-effects → library/skills}/game-feel/SKILL.md +7 -7
  356. package/library/skills/game-feel/resource.yaml +27 -0
  357. package/library/skills/gameskill/SKILL.md +64 -0
  358. package/library/skills/gameskill/resource.yaml +22 -0
  359. package/library/skills/gdscript-patterns/resource.yaml +23 -0
  360. package/{skills/animation → library/skills}/generate-motion/SKILL.md +16 -16
  361. package/library/skills/generate-motion/resource.yaml +34 -0
  362. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +223 -0
  363. package/library/skills/godogen-visual-proof-game-generation/resource.yaml +33 -0
  364. package/{skills/workflow → library/skills}/headless-scripting/SKILL.md +14 -7
  365. package/library/skills/headless-scripting/resource.yaml +26 -0
  366. package/{skills/multiplayer-and-networking → library/skills}/host-authoritative-state/SKILL.md +1 -1
  367. package/library/skills/host-authoritative-state/resource.yaml +28 -0
  368. package/{skills/2d-assets → library/skills}/instantiate-asset-pack/SKILL.md +10 -12
  369. package/library/skills/instantiate-asset-pack/resource.yaml +29 -0
  370. package/{skills/workflow → library/skills}/investigating-bugs/SKILL.md +4 -4
  371. package/{skills/workflow → library/skills}/investigating-bugs/condition-based-waiting.md +8 -8
  372. package/library/skills/investigating-bugs/resource.yaml +24 -0
  373. package/{skills/workflow → library/skills}/investigating-bugs/root-cause-tracing.md +1 -7
  374. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +164 -0
  375. package/library/skills/lumera-single-image-scene-reconstruction/resource.yaml +35 -0
  376. package/{skills/scene-and-project → library/skills}/make-game/SKILL.md +23 -23
  377. package/library/skills/make-game/resource.yaml +35 -0
  378. package/library/skills/music-track/resource.yaml +28 -0
  379. package/library/skills/navigate-summer/SKILL.md +61 -0
  380. package/library/skills/navigate-summer/resource.yaml +35 -0
  381. package/{skills/scene-and-project → library/skills}/new-project/SKILL.md +10 -10
  382. package/library/skills/new-project/resource.yaml +28 -0
  383. package/{skills/3d-assets → library/skills}/organic-model/SKILL.md +16 -16
  384. package/library/skills/organic-model/resource.yaml +32 -0
  385. package/{skills/multiplayer-and-networking → library/skills}/peer-to-peer-multiplayer/SKILL.md +2 -2
  386. package/library/skills/peer-to-peer-multiplayer/resource.yaml +28 -0
  387. package/{skills/2d-assets → library/skills}/pixel-art/SKILL.md +13 -13
  388. package/library/skills/pixel-art/resource.yaml +31 -0
  389. package/library/skills/play/resource.yaml +26 -0
  390. package/{skills/workflow → library/skills}/playtesting-a-feature/SKILL.md +41 -22
  391. package/library/skills/playtesting-a-feature/resource.yaml +31 -0
  392. package/{skills/animation → library/skills}/procedural-animation/SKILL.md +25 -10
  393. package/library/skills/procedural-animation/resource.yaml +33 -0
  394. package/{skills/3d-assets → library/skills}/prop-model/SKILL.md +13 -13
  395. package/library/skills/prop-model/resource.yaml +33 -0
  396. package/library/skills/psx-retro-rendering/SKILL.md +416 -0
  397. package/library/skills/psx-retro-rendering/resource.yaml +36 -0
  398. package/library/skills/realtime-wet-surfaces/SKILL.md +189 -0
  399. package/library/skills/realtime-wet-surfaces/resource.yaml +31 -0
  400. package/{skills/deployment → library/skills}/remote-deploy/SKILL.md +3 -3
  401. package/library/skills/remote-deploy/resource.yaml +23 -0
  402. package/{skills/animation → library/skills}/retarget/SKILL.md +15 -14
  403. package/library/skills/retarget/resource.yaml +33 -0
  404. package/library/skills/running-in-the-cloud/SKILL.md +103 -0
  405. package/library/skills/running-in-the-cloud/resource.yaml +33 -0
  406. package/{skills/scene-and-project → library/skills}/scene-composition/SKILL.md +9 -1
  407. package/library/skills/scene-composition/resource.yaml +27 -0
  408. package/library/skills/scene-hierarchy-design/SKILL.md +102 -0
  409. package/library/skills/scene-hierarchy-design/resource.yaml +31 -0
  410. package/library/skills/scene-scripting/SKILL.md +764 -0
  411. package/library/skills/scene-scripting/resource.yaml +58 -0
  412. package/{skills/level-design → library/skills}/scene-to-level/SKILL.md +16 -17
  413. package/library/skills/scene-to-level/resource.yaml +33 -0
  414. package/{skills/multiplayer-and-networking → library/skills}/setup-multiplayer/SKILL.md +1 -1
  415. package/library/skills/setup-multiplayer/resource.yaml +28 -0
  416. package/library/skills/skill-create/SKILL.md +138 -0
  417. package/library/skills/skill-create/resource.yaml +25 -0
  418. package/{skills/workflow → library/skills}/skill-improve/SKILL.md +2 -2
  419. package/library/skills/skill-improve/resource.yaml +25 -0
  420. package/{skills/workflow → library/skills}/skill-test/SKILL.md +4 -4
  421. package/library/skills/skill-test/resource.yaml +26 -0
  422. package/library/skills/skintokens-auto-rigging/SKILL.md +200 -0
  423. package/library/skills/skintokens-auto-rigging/resource.yaml +38 -0
  424. package/{skills/2d-assets → library/skills}/skybox-panorama/SKILL.md +8 -8
  425. package/library/skills/skybox-panorama/resource.yaml +28 -0
  426. package/{skills/audio → library/skills}/sound-effect/SKILL.md +2 -2
  427. package/library/skills/sound-effect/resource.yaml +27 -0
  428. package/library/skills/spatial-placement/SKILL.md +74 -0
  429. package/library/skills/spatial-placement/resource.yaml +42 -0
  430. package/library/skills/spatial-placement/tests/spec.md +65 -0
  431. package/{skills/2d-assets → library/skills}/sprite-sheet/SKILL.md +12 -12
  432. package/library/skills/sprite-sheet/resource.yaml +32 -0
  433. package/{skills/2d-assets → library/skills}/tileable-texture/SKILL.md +9 -9
  434. package/library/skills/tileable-texture/resource.yaml +31 -0
  435. package/{skills/video → library/skills}/trailer-shot/SKILL.md +1 -1
  436. package/library/skills/trailer-shot/resource.yaml +27 -0
  437. package/{skills/performance → library/skills}/tune-performance/SKILL.md +6 -6
  438. package/library/skills/tune-performance/resource.yaml +31 -0
  439. package/{skills/ui-and-ux → library/skills}/ui-basics/SKILL.md +1 -1
  440. package/library/skills/ui-basics/resource.yaml +25 -0
  441. package/{skills/2d-assets → library/skills}/ui-graphics/SKILL.md +11 -11
  442. package/library/skills/ui-graphics/resource.yaml +29 -0
  443. package/{skills/2d-assets → library/skills}/use-widget-asset/SKILL.md +4 -4
  444. package/library/skills/use-widget-asset/resource.yaml +29 -0
  445. package/{skills/workflow → library/skills}/using-summer/SKILL.md +12 -9
  446. package/library/skills/using-summer/resource.yaml +41 -0
  447. package/{skills/3d-assets → library/skills}/vehicle-model/SKILL.md +18 -18
  448. package/library/skills/vehicle-model/resource.yaml +34 -0
  449. package/{skills/workflow → library/skills}/verification-before-completion/SKILL.md +10 -10
  450. package/library/skills/verification-before-completion/resource.yaml +23 -0
  451. package/library/skills/verifying-scenes/SKILL.md +98 -0
  452. package/library/skills/verifying-scenes/resource.yaml +42 -0
  453. package/{skills/visual-effects/recipes/dissolve → library/skills/vfx-dissolve}/SKILL.md +31 -11
  454. package/library/skills/vfx-dissolve/resource.yaml +33 -0
  455. package/{skills/visual-effects/recipes/fire → library/skills/vfx-fire}/SKILL.md +43 -12
  456. package/library/skills/vfx-fire/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
  457. package/library/skills/vfx-fire/resource.yaml +35 -0
  458. package/{skills/visual-effects/recipes/hit-spark → library/skills/vfx-hit-spark}/SKILL.md +16 -10
  459. package/library/skills/vfx-hit-spark/_building-blocks/additive-billboard-particles.md +37 -0
  460. package/library/skills/vfx-hit-spark/resource.yaml +34 -0
  461. package/{skills/visual-effects/recipes/lightning → library/skills/vfx-lightning}/SKILL.md +24 -11
  462. package/library/skills/vfx-lightning/_building-blocks/additive-billboard-particles.md +37 -0
  463. package/library/skills/vfx-lightning/resource.yaml +33 -0
  464. package/{skills/visual-effects/recipes/magic-glow → library/skills/vfx-magic-glow}/SKILL.md +31 -11
  465. package/library/skills/vfx-magic-glow/_building-blocks/additive-billboard-particles.md +37 -0
  466. package/library/skills/vfx-magic-glow/resource.yaml +34 -0
  467. package/{skills/visual-effects/recipes/muzzle-flash → library/skills/vfx-muzzle-flash}/SKILL.md +29 -9
  468. package/library/skills/vfx-muzzle-flash/_building-blocks/additive-billboard-particles.md +37 -0
  469. package/library/skills/vfx-muzzle-flash/_building-blocks/trauma-shake-snippet.md +53 -0
  470. package/library/skills/vfx-muzzle-flash/resource.yaml +35 -0
  471. package/{skills/visual-effects/recipes/smoke → library/skills/vfx-smoke}/SKILL.md +35 -9
  472. package/library/skills/vfx-smoke/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
  473. package/library/skills/vfx-smoke/resource.yaml +32 -0
  474. package/{skills/visual-effects/recipes/water-ripple → library/skills/vfx-water-ripple}/SKILL.md +31 -9
  475. package/library/skills/vfx-water-ripple/_building-blocks/additive-billboard-particles.md +37 -0
  476. package/library/skills/vfx-water-ripple/resource.yaml +31 -0
  477. package/library/skills/voice-line/resource.yaml +27 -0
  478. package/library/skills/world-building-3d/SKILL.md +105 -0
  479. package/library/skills/world-building-3d/references/spatial-tools.md +50 -0
  480. package/library/skills/world-building-3d/resource.yaml +44 -0
  481. package/library/skills/world-building-3d/tests/spec.md +48 -0
  482. package/{skills/workflow → library/skills}/writing-plans/SKILL.md +19 -14
  483. package/library/skills/writing-plans/resource.yaml +23 -0
  484. package/{skills/workflow → library/skills}/writing-skills/SKILL.md +38 -44
  485. package/library/skills/writing-skills/resource.yaml +29 -0
  486. package/{skills/workflow → library/skills}/writing-skills/testing-skills-with-subagents.md +13 -14
  487. package/library/templates/2d-brario-platformer/resource.yaml +21 -0
  488. package/library/templates/2d-dungeon-roguelike/resource.yaml +23 -0
  489. package/library/templates/2d-grid-puzzle/resource.yaml +21 -0
  490. package/library/templates/2d-plants-and-zombies-tower-defense/resource.yaml +21 -0
  491. package/library/templates/2d-platformer/resource.yaml +24 -0
  492. package/library/templates/2d-rpg/resource.yaml +21 -0
  493. package/library/templates/2d-vampire-survivor-roguelike/resource.yaml +21 -0
  494. package/library/templates/3d-basic/resource.yaml +16 -0
  495. package/library/templates/3d-city-kit/resource.yaml +24 -0
  496. package/library/templates/3d-fps-old-school/resource.yaml +21 -0
  497. package/library/templates/3d-fps-simple-animated-npc/resource.yaml +21 -0
  498. package/library/templates/3d-lan-multiplayer-starter/resource.yaml +22 -0
  499. package/library/templates/3d-open-world-explore-tps/resource.yaml +21 -0
  500. package/library/templates/3d-procedural-road-world/resource.yaml +21 -0
  501. package/library/templates/3d-racing-game/resource.yaml +21 -0
  502. package/library/templates/3d-royale-clash-type/resource.yaml +21 -0
  503. package/library/templates/3d-third-person-controller/resource.yaml +21 -0
  504. package/library/templates/3d-voxel-sandbox/resource.yaml +24 -0
  505. package/library/templates/README.md +94 -0
  506. package/library/templates/empty/resource.yaml +16 -0
  507. package/library/tools/add-node/resource.yaml +60 -0
  508. package/library/tools/align-distribute-3d/resource.yaml +87 -0
  509. package/library/tools/api-docs/resource.yaml +57 -0
  510. package/library/tools/batch/resource.yaml +52 -0
  511. package/library/tools/camera-bookmark/resource.yaml +73 -0
  512. package/library/tools/check-job/resource.yaml +45 -0
  513. package/library/tools/clear-console/resource.yaml +40 -0
  514. package/library/tools/connect-signal/resource.yaml +63 -0
  515. package/library/tools/create-debug-report/resource.yaml +67 -0
  516. package/library/tools/create-scene/resource.yaml +59 -0
  517. package/library/tools/creator-config/resource.yaml +63 -0
  518. package/library/tools/creator-publish/resource.yaml +73 -0
  519. package/library/tools/creator-releases/resource.yaml +53 -0
  520. package/library/tools/fabricate-3d/resource.yaml +108 -0
  521. package/library/tools/game-control/resource.yaml +84 -0
  522. package/library/tools/game-input/resource.yaml +159 -0
  523. package/library/tools/game-probe/resource.yaml +90 -0
  524. package/library/tools/generate-3d/resource.yaml +112 -0
  525. package/library/tools/generate-audio/resource.yaml +80 -0
  526. package/library/tools/generate-image/resource.yaml +62 -0
  527. package/library/tools/generate-motion/resource.yaml +66 -0
  528. package/library/tools/generate-video/resource.yaml +66 -0
  529. package/library/tools/get-agent-playbook/resource.yaml +40 -0
  530. package/library/tools/get-asset/resource.yaml +42 -0
  531. package/library/tools/get-asset-download-url/resource.yaml +52 -0
  532. package/library/tools/get-console/resource.yaml +69 -0
  533. package/library/tools/get-debugger-errors/resource.yaml +56 -0
  534. package/library/tools/get-debugger-warnings/resource.yaml +52 -0
  535. package/library/tools/get-diagnostics/resource.yaml +42 -0
  536. package/library/tools/get-project-context/resource.yaml +45 -0
  537. package/library/tools/get-runtime-tree/resource.yaml +62 -0
  538. package/library/tools/get-scene-tree/resource.yaml +52 -0
  539. package/library/tools/get-script-errors/resource.yaml +45 -0
  540. package/library/tools/get-studio-workflow/resource.yaml +43 -0
  541. package/library/tools/import-asset/resource.yaml +73 -0
  542. package/library/tools/import-asset-by-id/resource.yaml +56 -0
  543. package/library/tools/import-from-url/resource.yaml +51 -0
  544. package/library/tools/import-from-url-batch/resource.yaml +60 -0
  545. package/library/tools/import-hdri/resource.yaml +69 -0
  546. package/library/tools/input-map-bind/resource.yaml +52 -0
  547. package/library/tools/inspect-node/resource.yaml +46 -0
  548. package/library/tools/inspect-resource/resource.yaml +45 -0
  549. package/library/tools/inspect-runtime-node/resource.yaml +54 -0
  550. package/library/tools/instantiate-scene/resource.yaml +62 -0
  551. package/library/tools/is-running/resource.yaml +40 -0
  552. package/library/tools/library-feedback/resource.yaml +89 -0
  553. package/library/tools/list-my-assets/resource.yaml +56 -0
  554. package/library/tools/navigation-probe/resource.yaml +85 -0
  555. package/library/tools/open/resource.yaml +80 -0
  556. package/library/tools/open-main-scene/resource.yaml +40 -0
  557. package/library/tools/open-scene/resource.yaml +46 -0
  558. package/library/tools/play/resource.yaml +91 -0
  559. package/library/tools/project-setting/resource.yaml +53 -0
  560. package/library/tools/read-file/resource.yaml +47 -0
  561. package/library/tools/read-library/resource.yaml +67 -0
  562. package/library/tools/recent-events/resource.yaml +71 -0
  563. package/library/tools/remove-node/resource.yaml +51 -0
  564. package/library/tools/replace-node/resource.yaml +57 -0
  565. package/library/tools/replace-text/resource.yaml +61 -0
  566. package/library/tools/run-editor-script/resource.yaml +61 -0
  567. package/library/tools/run-script/resource.yaml +73 -0
  568. package/library/tools/runtime-animate/resource.yaml +140 -0
  569. package/library/tools/runtime-call/resource.yaml +74 -0
  570. package/library/tools/runtime-set/resource.yaml +80 -0
  571. package/library/tools/runtime-spawn/resource.yaml +95 -0
  572. package/library/tools/save-scene/resource.yaml +50 -0
  573. package/library/tools/screenshot/resource.yaml +112 -0
  574. package/library/tools/search-assets/resource.yaml +67 -0
  575. package/library/tools/search-library/resource.yaml +81 -0
  576. package/library/tools/select-node/resource.yaml +48 -0
  577. package/library/tools/set-prop/resource.yaml +64 -0
  578. package/library/tools/set-resource-property/resource.yaml +66 -0
  579. package/library/tools/slice-asset-sheet/resource.yaml +47 -0
  580. package/library/tools/snap-to-surface/resource.yaml +90 -0
  581. package/library/tools/snapshot-diff/resource.yaml +58 -0
  582. package/library/tools/starcast/resource.yaml +120 -0
  583. package/library/tools/start-game-task/resource.yaml +91 -0
  584. package/library/tools/stop/resource.yaml +51 -0
  585. package/library/tools/test-placement/resource.yaml +109 -0
  586. package/library/tools/ui-actions/resource.yaml +77 -0
  587. package/library/tools/ui-activate/resource.yaml +88 -0
  588. package/library/tools/ui-screenshot/resource.yaml +63 -0
  589. package/library/tools/ui-tree/resource.yaml +69 -0
  590. package/library/tools/wait-for-event/resource.yaml +84 -0
  591. package/library/tools/world-snapshot/resource.yaml +60 -0
  592. package/library/tools/write-file/resource.yaml +54 -0
  593. package/package.json +22 -16
  594. package/registry/generated/aliases.json +207 -0
  595. package/registry/generated/counts.json +12 -0
  596. package/registry/generated/gemini-extension.json +122 -0
  597. package/registry/generated/index.json +7709 -0
  598. package/registry/generated/marketplace.claude.json +44 -0
  599. package/registry/generated/mcp.json +13 -0
  600. package/registry/generated/plugin.claude.json +135 -0
  601. package/registry/generated/plugin.codex.json +144 -0
  602. package/registry/generated/plugin.cursor.json +134 -0
  603. package/registry/generated/plugin.factory.json +117 -0
  604. package/registry/generated/skills-registry.json +851 -0
  605. package/registry/generated/templates-registry.json +455 -0
  606. package/registry/schemas/allowed-hosts.json +19 -0
  607. package/registry/schemas/collection.schema.json +68 -0
  608. package/registry/schemas/domains.json +96 -0
  609. package/registry/schemas/example.schema.json +11 -0
  610. package/registry/schemas/reference.schema.json +10 -0
  611. package/registry/schemas/resource.schema.json +154 -0
  612. package/registry/schemas/skill.schema.json +14 -0
  613. package/registry/schemas/template.schema.json +46 -0
  614. package/registry/schemas/tool.schema.json +61 -0
  615. package/_persona/summer/SKILL.md +0 -113
  616. package/dist/bin/postinstall.d.ts +0 -2
  617. package/dist/bin/postinstall.js +0 -3
  618. package/dist/commands/cloud.d.ts +0 -2
  619. package/dist/commands/cloud.js +0 -80
  620. package/dist/commands/create.d.ts +0 -3
  621. package/dist/commands/create.js +0 -171
  622. package/dist/commands/install.d.ts +0 -19
  623. package/dist/commands/install.js +0 -194
  624. package/dist/commands/list.js +0 -67
  625. package/dist/commands/logout.js +0 -13
  626. package/dist/commands/logs.d.ts +0 -2
  627. package/dist/commands/logs.js +0 -19
  628. package/dist/commands/open.d.ts +0 -2
  629. package/dist/commands/open.js +0 -32
  630. package/dist/commands/orchestrator.d.ts +0 -8
  631. package/dist/commands/orchestrator.js +0 -143
  632. package/dist/commands/run.d.ts +0 -2
  633. package/dist/commands/run.js +0 -167
  634. package/dist/commands/status.js +0 -46
  635. package/dist/lib/banner.d.ts +0 -4
  636. package/dist/lib/banner.js +0 -122
  637. package/dist/lib/cloud/api.d.ts +0 -79
  638. package/dist/lib/cloud/api.js +0 -107
  639. package/dist/lib/cloud/apply.d.ts +0 -32
  640. package/dist/lib/cloud/apply.js +0 -294
  641. package/dist/lib/cloud/checkpoint.d.ts +0 -26
  642. package/dist/lib/cloud/checkpoint.js +0 -142
  643. package/dist/lib/cloud/conflicts.d.ts +0 -55
  644. package/dist/lib/cloud/conflicts.js +0 -131
  645. package/dist/lib/cloud/containment.d.ts +0 -8
  646. package/dist/lib/cloud/containment.js +0 -52
  647. package/dist/lib/cloud/diff.d.ts +0 -39
  648. package/dist/lib/cloud/diff.js +0 -138
  649. package/dist/lib/cloud/engine-bridge.d.ts +0 -34
  650. package/dist/lib/cloud/engine-bridge.js +0 -139
  651. package/dist/lib/cloud/hash-cache.d.ts +0 -23
  652. package/dist/lib/cloud/hash-cache.js +0 -44
  653. package/dist/lib/cloud/hash.d.ts +0 -10
  654. package/dist/lib/cloud/hash.js +0 -111
  655. package/dist/lib/cloud/http.d.ts +0 -17
  656. package/dist/lib/cloud/http.js +0 -47
  657. package/dist/lib/cloud/lock-path.d.ts +0 -1
  658. package/dist/lib/cloud/lock-path.js +0 -5
  659. package/dist/lib/cloud/lock.d.ts +0 -14
  660. package/dist/lib/cloud/lock.js +0 -143
  661. package/dist/lib/cloud/manifest.d.ts +0 -6
  662. package/dist/lib/cloud/manifest.js +0 -41
  663. package/dist/lib/cloud/paths.d.ts +0 -20
  664. package/dist/lib/cloud/paths.js +0 -90
  665. package/dist/lib/cloud/project-godot-merge.d.ts +0 -32
  666. package/dist/lib/cloud/project-godot-merge.js +0 -185
  667. package/dist/lib/cloud/rules.d.ts +0 -39
  668. package/dist/lib/cloud/rules.js +0 -159
  669. package/dist/lib/cloud/sync.d.ts +0 -21
  670. package/dist/lib/cloud/sync.js +0 -518
  671. package/dist/lib/cloud/transfer.d.ts +0 -23
  672. package/dist/lib/cloud/transfer.js +0 -184
  673. package/dist/lib/cloud/types.d.ts +0 -62
  674. package/dist/lib/cloud/types.js +0 -1
  675. package/dist/lib/cloud/validate-path.d.ts +0 -23
  676. package/dist/lib/cloud/validate-path.js +0 -103
  677. package/dist/lib/engine.d.ts +0 -51
  678. package/dist/lib/game-task-plan.d.ts +0 -42
  679. package/dist/lib/project-memory.d.ts +0 -33
  680. package/dist/lib/public-surface-paths.d.ts +0 -13
  681. package/dist/lib/public-surface-paths.js +0 -42
  682. package/dist/lib/remote-templates.d.ts +0 -25
  683. package/dist/lib/remote-templates.js +0 -86
  684. package/dist/lib/skills-registry.d.ts +0 -572
  685. package/dist/lib/skills-registry.js +0 -1061
  686. package/dist/lib/version-check.d.ts +0 -106
  687. package/dist/mcp/tools/cloud-tools.js +0 -42
  688. package/references/mcp-tools-reference.md +0 -199
  689. package/references/template-registry.md +0 -73
  690. package/skills/README.md +0 -103
  691. package/skills/scene-and-project/summer-cloud/SKILL.md +0 -92
  692. package/skills/workflow/brainstorming/scripts/frame-template.html +0 -214
  693. package/skills/workflow/brainstorming/scripts/helper.js +0 -88
  694. package/skills/workflow/brainstorming/scripts/server.cjs +0 -354
  695. package/skills/workflow/brainstorming/scripts/start-server.sh +0 -148
  696. package/skills/workflow/brainstorming/scripts/stop-server.sh +0 -56
  697. package/skills/workflow/brainstorming/visual-companion.md +0 -287
  698. package/skills/workflow/gameskill/SKILL.md +0 -120
  699. package/skills/workflow/investigating-bugs/CREATION-LOG.md +0 -119
  700. package/skills/workflow/investigating-bugs/condition-based-waiting-example.ts +0 -158
  701. package/skills/workflow/investigating-bugs/find-polluter.sh +0 -63
  702. package/skills/workflow/investigating-bugs/test-academic.md +0 -14
  703. package/skills/workflow/investigating-bugs/test-pressure-1.md +0 -58
  704. package/skills/workflow/investigating-bugs/test-pressure-2.md +0 -68
  705. package/skills/workflow/investigating-bugs/test-pressure-3.md +0 -69
  706. package/skills/workflow/mcpupdate/SKILL.md +0 -134
  707. package/skills/workflow/skill-create/SKILL.md +0 -153
  708. package/skills/workflow/writing-skills/anthropic-best-practices.md +0 -1150
  709. package/skills/workflow/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
  710. package/skills/workflow/writing-skills/graphviz-conventions.dot +0 -172
  711. package/skills/workflow/writing-skills/persuasion-principles.md +0 -187
  712. package/skills/workflow/writing-skills/render-graphs.js +0 -168
  713. /package/dist/{commands → cli/commands}/config.d.ts +0 -0
  714. /package/dist/{commands → cli/commands}/debug.d.ts +0 -0
  715. /package/dist/{commands → cli/commands}/list.d.ts +0 -0
  716. /package/dist/{commands → cli/commands}/login.d.ts +0 -0
  717. /package/dist/{commands → cli/commands}/plan.d.ts +0 -0
  718. /package/dist/{commands → cli/commands}/publish.d.ts +0 -0
  719. /package/dist/{commands → cli/commands}/releases.d.ts +0 -0
  720. /package/dist/{commands → cli/commands}/setup.d.ts +0 -0
  721. /package/dist/{commands → cli/commands}/skills.d.ts +0 -0
  722. /package/dist/{lib → core}/log-filters.d.ts +0 -0
  723. /package/dist/{lib → core}/mcp-log.d.ts +0 -0
  724. /package/dist/{lib → core}/store.d.ts +0 -0
  725. /package/dist/{lib → core}/summer-compatibility.d.ts +0 -0
  726. /package/dist/{lib → core}/telemetry.d.ts +0 -0
  727. /package/dist/{lib/mcp-boot-notice.js → mcp/boot-notice.js} +0 -0
  728. /package/dist/{commands/mcp.d.ts → mcp/command.d.ts} +0 -0
  729. /package/{references → library/references/collaborative-protocol}/collaborative-protocol.md +0 -0
  730. /package/{references → library/references/gd-style}/gd-style.md +0 -0
  731. /package/{skills/audio → library/skills}/ambient-bed/SKILL.md +0 -0
  732. /package/{skills/gameplay-mechanics → library/skills}/auto-fire-targeting/SKILL.md +0 -0
  733. /package/{skills/scripting-patterns → library/skills}/gdscript-patterns/SKILL.md +0 -0
  734. /package/{skills/scripting-patterns → library/skills}/gdscript-patterns/reference.md +0 -0
  735. /package/{skills/workflow → library/skills}/investigating-bugs/defense-in-depth.md +0 -0
  736. /package/{skills/audio → library/skills}/music-track/SKILL.md +0 -0
  737. /package/{skills/scene-and-project → library/skills}/play/SKILL.md +0 -0
  738. /package/{skills/visual-effects → library/skills/vfx-dissolve}/_building-blocks/noise-3d-fbm.gdshaderinc +0 -0
  739. /package/{skills/visual-effects → library/skills/vfx-fire}/_building-blocks/additive-billboard-particles.md +0 -0
  740. /package/{skills/visual-effects → library/skills/vfx-lightning}/_building-blocks/trauma-shake-snippet.md +0 -0
  741. /package/{skills/audio → library/skills}/voice-line/SKILL.md +0 -0
  742. /package/{skills/workflow → library/skills}/writing-plans/plan-document-reviewer-prompt.md +0 -0
@@ -0,0 +1,1011 @@
1
+ /**
2
+ * Runtime control & playtest ops (runtime control) — the "see and touch the
3
+ * RUNNING game" surface. One copy of the argument contracts, op builders,
4
+ * client budgets and failure hints, shared by the MCP tools
5
+ * (src/mcp/tools/runtime-tools.ts) and the CLI dispatcher (`summer tool …`) so
6
+ * both faces validate the same inputs, send the same op and wait the same
7
+ * budget.
8
+ *
9
+ * Engine contract (frozen): doc/SUMMER/SCENE_SCRIPTING_CONTRACTS.md "Wave I —
10
+ * Runtime control & playtest ops" + editor/ops/runtime_ops.h. Every op except
11
+ * ListGameInstances is SINGLE-ONLY and ASYNC (a debugger round-trip needs the
12
+ * reply channel), requires a RUNNING game, accepts `instance?` (default
13
+ * "main"), stamps the game frame it describes, rounds floats to 3dp and
14
+ * serialises math values as Godot literal strings ("Vector3(1, 2, 3)").
15
+ *
16
+ * Sixteen engine kinds are grouped into seven tools:
17
+ * summer_runtime_set SetRuntimeProp
18
+ * summer_runtime_call CallRuntimeMethod
19
+ * summer_runtime_spawn SpawnRuntimeScene | FreeRuntimeNode (action)
20
+ * summer_runtime_animate RuntimeAnimation | RuntimeAnimationTree |
21
+ * GetRuntimeBones (target)
22
+ * summer_game_control GamePause | GameStep | GameSpeed |
23
+ * ListGameInstances (action)
24
+ * summer_game_input SimulateInputScript | InputRecordStart |
25
+ * InputRecordStop | InputReplay (action)
26
+ * summer_game_probe GameProbe
27
+ * plus the instance-aware PlayGame / StopGame variants behind summer_play /
28
+ * summer_stop.
29
+ */
30
+ import { z } from "zod";
31
+ import { ToolInputError } from "../tool-errors.js";
32
+ import { missingEngineOpResult } from "../capability-skew.js";
33
+ import { extractOpError, getFailureReason, withOldEngineHint } from "./engine-receipt.js";
34
+ // ---------------------------------------------------------------------------
35
+ // Op kinds
36
+ // ---------------------------------------------------------------------------
37
+ /** The fifteen async single-only kinds (RuntimeOps::async_op_kinds). */
38
+ export const RUNTIME_ASYNC_OP_KINDS = [
39
+ "SetRuntimeProp",
40
+ "CallRuntimeMethod",
41
+ "SpawnRuntimeScene",
42
+ "FreeRuntimeNode",
43
+ "RuntimeAnimation",
44
+ "RuntimeAnimationTree",
45
+ "GetRuntimeBones",
46
+ "GamePause",
47
+ "GameSpeed",
48
+ "GameStep",
49
+ "SimulateInputScript",
50
+ "InputRecordStart",
51
+ "InputRecordStop",
52
+ "InputReplay",
53
+ "GameProbe",
54
+ ];
55
+ /** All sixteen runtime-control kinds — the fifteen above plus the synchronous
56
+ * ListGameInstances read. */
57
+ export const RUNTIME_CONTROL_OP_KINDS = [
58
+ ...RUNTIME_ASYNC_OP_KINDS,
59
+ "ListGameInstances",
60
+ ];
61
+ // ---------------------------------------------------------------------------
62
+ // Budgets — mirror the engine's watchdogs (runtime_ops.cpp) plus relay headroom.
63
+ // ---------------------------------------------------------------------------
64
+ /** Default editor-side watchdog for a runtime op (_RT_DEFAULT_TIMEOUT_SEC). */
65
+ export const RUNTIME_WATCHDOG_DEFAULT_SEC = 10;
66
+ /** Hard cap on any runtime watchdog (_RT_MAX_TIMEOUT_SEC). */
67
+ export const RUNTIME_WATCHDOG_MAX_SEC = 20;
68
+ /** GameProbe watchdog: screenshot + PNG -> JPEG decode (_RT_PROBE_TIMEOUT_SEC). */
69
+ export const RUNTIME_PROBE_WATCHDOG_SEC = 15;
70
+ /** Offscreen child attach budget before the engine kills it (_RT_ATTACH_TIMEOUT_SEC). */
71
+ export const RUNTIME_ATTACH_TIMEOUT_SEC = 15;
72
+ /** The op is staged on the editor's async lane and polled over HTTP; the
73
+ * watchdog fires editor-side, so the client always waits longer than it. */
74
+ export const RUNTIME_CLIENT_HEADROOM_MS = 15_000;
75
+ /** GameStep frames cap (_RT_STEP_MAX_FRAMES). */
76
+ export const GAME_STEP_MAX_FRAMES = 600;
77
+ /** SimulateInputScript / InputReplay event cap (_RT_SCRIPT_MAX_EVENTS). */
78
+ export const INPUT_SCRIPT_MAX_EVENTS = 1000;
79
+ /** Last-event horizon: 36000 frames = 600 s at 60 fps (_RT_SCRIPT_HORIZON_FRAMES). */
80
+ export const INPUT_SCRIPT_HORIZON_FRAMES = 36_000;
81
+ /** GameProbe props cap and tree bounds. */
82
+ export const GAME_PROBE_MAX_PROPS = 64;
83
+ export const GAME_PROBE_MAX_DEPTH = 8;
84
+ export const GAME_PROBE_MAX_LIMIT = 4000;
85
+ export const GAME_PROBE_MIN_DIM = 16;
86
+ export const GAME_PROBE_MAX_DIM = 4096;
87
+ /** Offscreen instance cap (4 debugger sessions total, the run bar's game included). */
88
+ export const MAX_OFFSCREEN_INSTANCES = 3;
89
+ /** PlayGame default seed when deterministic and no seed is given (_RT_DEFAULT_SEED). */
90
+ export const PLAY_DEFAULT_SEED = 20260725;
91
+ /** Client poll budget for an engine watchdog of `watchdogSec` seconds. */
92
+ export function runtimeBudgetMs(watchdogSec) {
93
+ return Math.round(watchdogSec * 1000) + RUNTIME_CLIENT_HEADROOM_MS;
94
+ }
95
+ /** Instance-aware PlayGame: the child must attach within 15 s, and a cold
96
+ * load of a large project can take 25-40 s on top — same 60 s as /api/play. */
97
+ export const PLAY_INSTANCE_TIMEOUT_MS = 60_000;
98
+ /** StopGame {instance}: kills a PID — same 15 s budget as /api/stop. */
99
+ export const STOP_INSTANCE_TIMEOUT_MS = 15_000;
100
+ // ---------------------------------------------------------------------------
101
+ // Fallbacks named by engine_lacks_op (pre-flight and post-hoc alike).
102
+ // ---------------------------------------------------------------------------
103
+ export const RUNTIME_FALLBACKS = {
104
+ SetRuntimeProp: "drive the RUNNING game from a RunVerification probe (it can set properties and report them back), or edit the scene with summer_set_prop and restart the game",
105
+ CallRuntimeMethod: "call the method from a RunVerification probe (report(key, value) carries the return), or send SimulateInput for input-driven behaviour",
106
+ SpawnRuntimeScene: "spawn from a RunVerification probe, or instantiate into the EDITED scene with summer_instantiate_scene and restart the game",
107
+ FreeRuntimeNode: "free the node from a RunVerification probe, or remove it from the EDITED scene with summer_remove_node and restart the game",
108
+ RuntimeAnimation: "drive the AnimationPlayer from a RunVerification probe and save_frame the result",
109
+ RuntimeAnimationTree: "drive the AnimationTree state machine from a RunVerification probe and report its playback state",
110
+ GetRuntimeBones: "read bone poses from a RunVerification probe (Skeleton3D.get_bone_global_pose) or verify visually with summer_screenshot target:'game'",
111
+ GamePause: "pause from a RunVerification probe (get_tree().paused = true) or observe with summer_screenshot target:'game'",
112
+ GameStep: "await get_tree().physics_frame N times inside a RunVerification probe and assert there — this engine cannot step the live game frame by frame",
113
+ GameSpeed: "set Engine.time_scale from a RunVerification probe, or accept real-time observation",
114
+ SimulateInputScript: "send SimulateInput ops one at a time (summer_batch, single op each) or script the sequence in a RunVerification probe with press()/key()",
115
+ InputRecordStart: "script the inputs by hand in a RunVerification probe — this engine cannot record live input",
116
+ InputRecordStop: "script the inputs by hand in a RunVerification probe — this engine cannot record live input",
117
+ InputReplay: "replay the sequence as SimulateInput ops or a RunVerification probe — this engine cannot replay a recording",
118
+ GameProbe: "read live state from a RunVerification probe (dump_tree/report — see the playbook's rawOpsViaBatch) and capture pixels with summer_screenshot target:'game' (two calls, two frames — not one atomic frame)",
119
+ ListGameInstances: "use summer_is_running for the main game — this engine has no parallel offscreen instances",
120
+ };
121
+ /** Instance-aware PlayGame rides the same engine wave as ListGameInstances;
122
+ * an engine that lacks the latter would start the MAIN game and silently
123
+ * ignore instance/mode, so the pre-flight keys on this kind. */
124
+ export const PLAY_INSTANCE_FALLBACK = "start the main game with summer_play without instance/mode (seed and fixed_fps still apply there) and observe it with summer_screenshot target:'game' or a RunVerification probe — this engine has no parallel offscreen instances";
125
+ // ---------------------------------------------------------------------------
126
+ // Failure hints — prescriptive recovery text keyed by failure_reason.
127
+ // ---------------------------------------------------------------------------
128
+ export const RUNTIME_FAILURE_HINTS = {
129
+ game_not_running: "No game is running for this instance, so there is nothing to drive. Start it with summer_play (add instance + mode:'offscreen' for a disposable parallel instance; deterministic:true with seed for a reproducible run), confirm with summer_is_running or summer_game_control action:'instances' (attached:true), then retry. For the scene being EDITED use the scene tools or summer_run_script instead.",
130
+ unknown_instance: "No live game instance has that name. summer_game_control action:'instances' lists the live ones; start a new one with summer_play {instance, mode:'offscreen'}.",
131
+ request_failed: "The game's debug session has not attached yet (it may still be booting). Wait a moment, confirm with summer_game_control action:'instances' (attached:true) or summer_is_running, then retry.",
132
+ game_breaked: "The game is stopped at a script breakpoint, so mutating runtime ops are refused until it continues. Resume it in the editor debugger (or summer_stop then summer_play), then retry. summer_game_probe, GetRuntimeBones and the input recorder still answer while breaked.",
133
+ busy: "Another input script is already in flight on this instance (one per instance). Wait for it to finish — summer_game_probe shows the frame advancing and the result of the first script arrives on its own call — then retry; never fire two scripts at the same instance in parallel.",
134
+ timeout: "The running game did not answer within the engine's watchdog. It may be wedged, minimized (a window that draws no frames cannot step or probe), or stopped at a breakpoint. Check summer_get_debugger_errors; if the game is gone, summer_stop then summer_play, and retry.",
135
+ unsupported: "The running game build predates the summer runtime capture and this op has no zero-game-code fallback. Restart the game after updating Summer Engine (the capture lives in the game binary); until then use a RunVerification probe.",
136
+ unsupported_transport: "This op was batched with others or sent over a channel without an async reply lane. Send it as the ONLY op in the request (the dedicated summer_* runtime tools already do); nothing from the rejected batch was applied.",
137
+ not_applied: "applied:false — the read-back after the write did not match. The property is probably overwritten every frame by a script, read-only, or typed differently from the literal you sent (math values need Godot literal strings such as 'Vector3(1, 2, 3)'). Probe the value with summer_game_probe props, then either set it through the owning script's setter with summer_runtime_call or step the game and re-probe.",
138
+ nondeterministic_instance: "seed only means something on a deterministic offscreen instance. Start one with summer_play {instance, mode:'offscreen', deterministic:true, seed} and replay there, or drop seed to replay on this instance without a reproducibility claim.",
139
+ body_too_big: "The reply exceeded the 1 MiB body cap. Narrow it: smaller tree depth/limit, fewer props, a lower max_dim or screenshot:false on the probe; page bones with the bones filter.",
140
+ rejected_identity: "The editor switched projects while the op was in flight; nothing was applied. Call summer_get_project_context to rebind (only if you meant to follow the switch), then retry.",
141
+ node_not_found: "That path does not exist in the RUNNING game. Runtime paths are absolute ('/root/Main/Player') and often differ from the edited scene because nodes are spawned, renamed or reparented at runtime. List what actually exists with summer_game_probe tree (or summer_get_runtime_tree) and retry with a path from its result.",
142
+ parent_not_found: "The spawn parent does not exist in the RUNNING game. Read the live tree with summer_game_probe tree and pass an absolute runtime path such as '/root/Main/Enemies'.",
143
+ scene_load_failed: "The scene could not be loaded in the running game. Check the res:// path with summer_read_file and the console (summer_get_console) for the loader's error.",
144
+ not_packed_scene: "That res:// path is not a PackedScene (.tscn/.scn). Pass a scene file, not a script or resource.",
145
+ refused_root: "The scene root cannot be freed (it would end the game). Free a child node, or summer_stop to end the run.",
146
+ refused_property: "script and owner are never set at runtime through this op (it would detach the node's behaviour). Change the script in the EDITED scene and restart, or call a method on the node instead.",
147
+ property_not_found: "The node has no such property. summer_inspect_runtime_node lists its live properties; summer_api_docs lists the class's declared ones.",
148
+ method_not_found: "The node has no such method. Check summer_api_docs for the class (walk inherits for inherited methods) or the node's script.",
149
+ call_error: "The method ran and raised (call_error_detail carries the message). Fix the arguments or the script; nothing further was applied.",
150
+ bad_args: "The engine rejected the arguments (the error names which). Fix them and retry — nothing was applied.",
151
+ too_many_events: "More than 1000 events in one script. Split it into sequential scripts (each waits for the previous result).",
152
+ horizon_exceeded: "The last event lands beyond the 36000-frame / 600 s horizon. Shorten the script or run it as several scripts.",
153
+ all_rejected: "Every event was rejected (see rejected[] for each index and reason). unknown_action means the action is not in the project InputMap — bind it with summer_input_map_bind and restart the game, or drive keys directly with type:'key'.",
154
+ already_recording: "A recording is already running on this instance. Stop it with action:'record_stop' (it returns the file) before starting another.",
155
+ not_recording: "No recording is running on this instance. Start one with action:'record_start', play or script the inputs, then stop it.",
156
+ recording_not_found: "No recording at that res:// path. action:'record_stop' returns the path it wrote (res://.summer/replays/<id>.json); pass that exact string.",
157
+ bad_recording: "The recording file is not the version:1 schema {version, events[]}. Re-record it, or pass inline events instead.",
158
+ not_animation_player: "That node is not an AnimationPlayer. Use target:'tree' for an AnimationTree or find the player under the character with summer_game_probe tree.",
159
+ not_animation_tree: "That node is not an AnimationTree. Use target:'player' for an AnimationPlayer or find the tree with summer_game_probe tree.",
160
+ no_state_machine: "playback_path does not resolve to an AnimationNodeStateMachinePlayback. Pass the parameter path of the state machine (default 'parameters/playback'; nested machines use 'parameters/<Node>/playback').",
161
+ unknown_animation: "No clip with that name (the error lists the player's clips). Pass one of them exactly.",
162
+ unknown_state: "No state with that name (the error lists the states). Pass one exactly.",
163
+ unknown_parameter: "No such AnimationTree parameter. cmd:'state' lists the readable ones under parameters.",
164
+ read_only_parameter: "That AnimationTree parameter is read-only (a playback object or a computed value). Drive it with travel/start/stop instead.",
165
+ not_skeleton: "That node is not a Skeleton3D. Find the skeleton under the character with summer_game_probe tree and pass its absolute path.",
166
+ unknown_bone: "No bone with that name (the error lists the rig's names, capped at 64). Omit bones to read the first 256, then filter.",
167
+ too_many_instances: "At most 3 offscreen instances live at once. summer_stop {instance} one you no longer need, then retry.",
168
+ session_timeout: "The child game did not attach to the debugger within 15 s and was killed. Check the editor Output for its stderr (summer_get_console), summer_stop {instance} to clear it, then summer_play again.",
169
+ instance_exists: "A live instance already has that name. summer_stop {instance} first, or pick a new name.",
170
+ unsupported_mode: "mode:'offscreen' needs an instance name other than 'main' (the main slot is the editor's embedded game). Pass instance:'a' (any name) with mode:'offscreen'.",
171
+ spawn_failed: "The child game process could not be spawned. Check the console (summer_get_console) for the launcher's error and that the project runs with plain summer_play first.",
172
+ main_scene_not_configured: "No valid main scene is configured. Set application/run/main_scene with summer_project_setting (or pass scene) and retry.",
173
+ screenshot_failed: "The game could not capture its viewport this frame (minimized window or no drawn frame). Retry after summer_game_control action:'step', or pass screenshot:false to read state only.",
174
+ decode_failed: "The editor could not decode the game's PNG. Retry once; if it persists pass screenshot:false and capture with summer_screenshot target:'game'.",
175
+ };
176
+ /**
177
+ * Amend a runtime-op envelope with prescriptive recovery text. The structured
178
+ * failure_reason stays intact for programmatic callers; on a failure only the
179
+ * model-facing `error` string is taught. A SUCCESSFUL envelope that still
180
+ * carries a reason (SetRuntimeProp applied:false + not_applied, InputReplay's
181
+ * advisory nondeterministic_instance) gets a `hint` field instead — the op
182
+ * did run, so its `error` must not be invented.
183
+ */
184
+ export function withRuntimeFailureHints(result, extraHints = {}) {
185
+ if (!result || typeof result !== "object")
186
+ return result;
187
+ const envelope = result;
188
+ const failed = envelope.results?.find((entry) => entry.ok === false);
189
+ const first = envelope.results?.[0];
190
+ const hints = { ...RUNTIME_FAILURE_HINTS, ...extraHints };
191
+ let reason = getFailureReason(envelope) ??
192
+ (failed ? getFailureReason(failed) : undefined) ??
193
+ (first ? getFailureReason(first) : undefined);
194
+ if (!reason && first?.applied === false)
195
+ reason = "not_applied";
196
+ if (typeof reason !== "string" || !(reason in hints))
197
+ return result;
198
+ const hint = hints[reason];
199
+ if (extractOpError(result)) {
200
+ const engineError = (typeof envelope.error === "string" && envelope.error) ||
201
+ (typeof failed?.error === "string" && failed.error) ||
202
+ reason;
203
+ return { ...envelope, error: `${hint} Engine said: ${engineError}` };
204
+ }
205
+ const existing = typeof envelope.hint === "string" ? `${envelope.hint} ` : "";
206
+ return { ...envelope, hint: `${existing}${hint}` };
207
+ }
208
+ // ---------------------------------------------------------------------------
209
+ // Shared pieces
210
+ // ---------------------------------------------------------------------------
211
+ const INSTANCE_DESCRIPTION = "Game instance to address (default 'main' = the editor's embedded game). Offscreen instances are named by summer_play {instance, mode:'offscreen'}; summer_game_control action:'instances' lists the live ones.";
212
+ const instanceSchema = z.string().optional().describe(INSTANCE_DESCRIPTION);
213
+ /** Godot literal string ("Vector3(1, 2, 3)", "Color(1, 0, 0)") or a JSON scalar. */
214
+ const literalValueSchema = z.union([z.string(), z.number(), z.boolean()]);
215
+ function withInstance(op, instance) {
216
+ const trimmed = typeof instance === "string" ? instance.trim() : "";
217
+ if (trimmed.length > 0)
218
+ op.instance = trimmed;
219
+ return op;
220
+ }
221
+ function requireRuntimePath(value, field, example) {
222
+ if (typeof value !== "string" || value.trim().length === 0) {
223
+ throw new ToolInputError(`${field} is required: the ABSOLUTE runtime node path in the running game, e.g. '${example}' (read it from summer_game_probe tree or summer_get_runtime_tree).`);
224
+ }
225
+ return value.trim();
226
+ }
227
+ function isInt(value) {
228
+ return typeof value === "number" && Number.isInteger(value);
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // summer_runtime_set — SetRuntimeProp
232
+ // ---------------------------------------------------------------------------
233
+ export const runtimeSetArgsSchema = z.object({
234
+ path: z
235
+ .string()
236
+ .describe("ABSOLUTE runtime node path, e.g. '/root/Main/Player' (from summer_game_probe tree)."),
237
+ property: z
238
+ .string()
239
+ .describe("Property name, e.g. 'position', 'health', 'visible'. 'script' and 'owner' are refused."),
240
+ value: literalValueSchema.describe("New value. JSON scalars for primitives; Godot literal strings for math types ('Vector3(1, 2, 3)', 'Color(1, 0, 0, 1)', 'Vector2(10, 0)'). Compared with Variant equality, so 1 and 1.0 both count as applied."),
241
+ field: z
242
+ .string()
243
+ .optional()
244
+ .describe("Optional sub-field to set instead of the whole value, e.g. 'x' on a Vector3 property."),
245
+ instance: instanceSchema,
246
+ });
247
+ export function buildRuntimeSetOp(args) {
248
+ const path = requireRuntimePath(args.path, "path", "/root/Main/Player");
249
+ if (typeof args.property !== "string" || args.property.trim().length === 0) {
250
+ throw new ToolInputError("property is required: the property name to set on the running node.");
251
+ }
252
+ if (args.value === undefined) {
253
+ throw new ToolInputError("value is required: a JSON scalar, or a Godot literal string such as 'Vector3(1, 2, 3)' for math types.");
254
+ }
255
+ const op = {
256
+ op: "SetRuntimeProp",
257
+ path,
258
+ property: args.property.trim(),
259
+ value: args.value,
260
+ };
261
+ if (typeof args.field === "string" && args.field.trim().length > 0)
262
+ op.field = args.field.trim();
263
+ return { kind: "SetRuntimeProp", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
264
+ }
265
+ // ---------------------------------------------------------------------------
266
+ // summer_runtime_call — CallRuntimeMethod
267
+ // ---------------------------------------------------------------------------
268
+ export const runtimeCallArgsSchema = z.object({
269
+ path: z.string().describe("ABSOLUTE runtime node path, e.g. '/root/Main/Player'."),
270
+ method: z.string().describe("Method name to call on the node, e.g. 'take_damage', 'get_velocity'."),
271
+ args: z
272
+ .array(z.unknown())
273
+ .optional()
274
+ .describe("Positional arguments. JSON scalars, arrays and objects pass as-is; math values as Godot literal strings ('Vector3(0, 1, 0)'). Object and RID arguments are refused (bad_args)."),
275
+ instance: instanceSchema,
276
+ });
277
+ export function buildRuntimeCallOp(args) {
278
+ const path = requireRuntimePath(args.path, "path", "/root/Main/Player");
279
+ if (typeof args.method !== "string" || args.method.trim().length === 0) {
280
+ throw new ToolInputError("method is required: the method name to call on the running node.");
281
+ }
282
+ const op = { op: "CallRuntimeMethod", path, method: args.method.trim() };
283
+ if (args.args !== undefined) {
284
+ if (!Array.isArray(args.args))
285
+ throw new ToolInputError("args must be an array of positional arguments.");
286
+ op.args = args.args;
287
+ }
288
+ return { kind: "CallRuntimeMethod", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
289
+ }
290
+ // ---------------------------------------------------------------------------
291
+ // summer_runtime_spawn — SpawnRuntimeScene | FreeRuntimeNode
292
+ // ---------------------------------------------------------------------------
293
+ export const runtimeSpawnArgsSchema = z.object({
294
+ action: z
295
+ .enum(["spawn", "free"])
296
+ .describe("'spawn' instantiates a PackedScene under parent (SpawnRuntimeScene); 'free' removes a node (FreeRuntimeNode)."),
297
+ parent: z
298
+ .string()
299
+ .optional()
300
+ .describe("action:'spawn' — ABSOLUTE runtime path of the parent, e.g. '/root/Main/Enemies'."),
301
+ scene: z
302
+ .string()
303
+ .optional()
304
+ .describe("action:'spawn' — PackedScene to instantiate, e.g. 'res://enemies/goblin.tscn'."),
305
+ name: z
306
+ .string()
307
+ .optional()
308
+ .describe("action:'spawn' — node name; the engine renames on collision and reports renamed_to."),
309
+ props: z
310
+ .record(literalValueSchema)
311
+ .optional()
312
+ .describe("action:'spawn' — properties set on the new node before it enters the tree ({position: 'Vector3(0, 1, 0)', health: 50}). Unknown ones land in prop_warnings, never fail the spawn."),
313
+ path: z.string().optional().describe("action:'free' — ABSOLUTE runtime path of the node to free."),
314
+ mode: z
315
+ .enum(["queue_free", "free"])
316
+ .optional()
317
+ .describe("action:'free' — 'queue_free' (default, safe: frees at the end of the frame) or 'free' (immediate)."),
318
+ instance: instanceSchema,
319
+ });
320
+ export function buildRuntimeSpawnOp(args) {
321
+ if (args.action === "spawn") {
322
+ const parent = requireRuntimePath(args.parent, "parent", "/root/Main/Enemies");
323
+ if (typeof args.scene !== "string" || !args.scene.trim().startsWith("res://")) {
324
+ throw new ToolInputError("scene is required for action:'spawn': a res:// PackedScene path such as 'res://enemies/goblin.tscn'.");
325
+ }
326
+ const op = { op: "SpawnRuntimeScene", parent, scene: args.scene.trim() };
327
+ if (typeof args.name === "string" && args.name.trim().length > 0)
328
+ op.name = args.name.trim();
329
+ if (args.props !== undefined) {
330
+ if (!args.props || typeof args.props !== "object" || Array.isArray(args.props)) {
331
+ throw new ToolInputError("props must be an object of property -> value.");
332
+ }
333
+ op.props = args.props;
334
+ }
335
+ return { kind: "SpawnRuntimeScene", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
336
+ }
337
+ if (args.action === "free") {
338
+ const path = requireRuntimePath(args.path, "path", "/root/Main/Enemies/Goblin3");
339
+ const op = { op: "FreeRuntimeNode", path };
340
+ if (args.mode !== undefined) {
341
+ if (args.mode !== "queue_free" && args.mode !== "free") {
342
+ throw new ToolInputError("mode must be 'queue_free' (default) or 'free'.");
343
+ }
344
+ op.mode = args.mode;
345
+ }
346
+ return { kind: "FreeRuntimeNode", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
347
+ }
348
+ throw new ToolInputError("action must be 'spawn' or 'free'.");
349
+ }
350
+ // ---------------------------------------------------------------------------
351
+ // summer_runtime_animate — RuntimeAnimation | RuntimeAnimationTree | GetRuntimeBones
352
+ // ---------------------------------------------------------------------------
353
+ export const ANIMATION_PLAYER_CMDS = ["state", "play", "pause", "stop", "seek", "speed"];
354
+ export const ANIMATION_TREE_CMDS = ["state", "travel", "start", "stop", "set_param", "get_param"];
355
+ export const runtimeAnimateArgsSchema = z.object({
356
+ target: z
357
+ .enum(["player", "tree", "bones"])
358
+ .describe("'player' = AnimationPlayer (RuntimeAnimation), 'tree' = AnimationTree state machine (RuntimeAnimationTree), 'bones' = Skeleton3D poses (GetRuntimeBones)."),
359
+ path: z.string().describe("ABSOLUTE runtime path of the AnimationPlayer / AnimationTree / Skeleton3D."),
360
+ cmd: z
361
+ .enum(["state", "play", "pause", "stop", "seek", "speed", "travel", "start", "set_param", "get_param"])
362
+ .optional()
363
+ .describe("Default 'state' (read-only). target:'player': state|play|pause|stop|seek|speed. target:'tree': state|travel|start|stop|set_param|get_param. Ignored for target:'bones'."),
364
+ name: z.string().optional().describe("target:'player' play — clip name (unknown_animation lists the clips)."),
365
+ position: z.number().optional().describe("target:'player' seek — position in seconds."),
366
+ speed: z.number().optional().describe("target:'player' speed — speed_scale (1.0 = normal, negative plays backwards)."),
367
+ from_end: z.boolean().optional().describe("target:'player' play — start from the end (backwards)."),
368
+ blend: z.number().optional().describe("target:'player' play — custom blend time in seconds."),
369
+ update: z.boolean().optional().describe("target:'player' seek — apply the pose immediately (default true)."),
370
+ state: z.string().optional().describe("target:'tree' travel/start — state machine node name (unknown_state lists them)."),
371
+ reset: z.boolean().optional().describe("target:'tree' travel/start — reset the destination clip (default true)."),
372
+ param: z.string().optional().describe("target:'tree' set_param/get_param — parameter path, e.g. 'parameters/Blend/blend_amount'."),
373
+ value: literalValueSchema
374
+ .optional()
375
+ .describe("target:'tree' set_param — new value (JSON scalar or Godot literal string)."),
376
+ playback_path: z
377
+ .string()
378
+ .optional()
379
+ .describe("target:'tree' — state machine playback parameter (default 'parameters/playback'; nested machines use 'parameters/<Node>/playback')."),
380
+ bones: z
381
+ .array(z.string())
382
+ .optional()
383
+ .describe("target:'bones' — bone names to read (omit for the first 256; page larger rigs with this filter)."),
384
+ space: z
385
+ .enum(["global", "local", "both"])
386
+ .optional()
387
+ .describe("target:'bones' — 'global' (default, skeleton-space global_pose), 'local' (pose), or 'both'."),
388
+ include_rest: z.boolean().optional().describe("target:'bones' — also return each bone's rest Transform3D."),
389
+ instance: instanceSchema,
390
+ });
391
+ export function buildRuntimeAnimateOp(args) {
392
+ const path = requireRuntimePath(args.path, "path", "/root/Main/Player/AnimationPlayer");
393
+ if (args.target === "player") {
394
+ const cmd = args.cmd ?? "state";
395
+ if (!ANIMATION_PLAYER_CMDS.includes(cmd)) {
396
+ throw new ToolInputError(`cmd '${cmd}' is not an AnimationPlayer command; target:'player' accepts ${ANIMATION_PLAYER_CMDS.join("|")}.`);
397
+ }
398
+ if (cmd === "seek" && typeof args.position !== "number") {
399
+ throw new ToolInputError("cmd:'seek' needs position (seconds).");
400
+ }
401
+ if (cmd === "speed" && typeof args.speed !== "number") {
402
+ throw new ToolInputError("cmd:'speed' needs speed (speed_scale, 1.0 = normal).");
403
+ }
404
+ const op = { op: "RuntimeAnimation", path, cmd };
405
+ if (typeof args.name === "string" && args.name.length > 0)
406
+ op.name = args.name;
407
+ if (typeof args.position === "number")
408
+ op.position = args.position;
409
+ if (typeof args.speed === "number")
410
+ op.speed = args.speed;
411
+ if (typeof args.from_end === "boolean")
412
+ op.from_end = args.from_end;
413
+ if (typeof args.blend === "number")
414
+ op.blend = args.blend;
415
+ if (typeof args.update === "boolean")
416
+ op.update = args.update;
417
+ return { kind: "RuntimeAnimation", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
418
+ }
419
+ if (args.target === "tree") {
420
+ const cmd = args.cmd ?? "state";
421
+ if (!ANIMATION_TREE_CMDS.includes(cmd)) {
422
+ throw new ToolInputError(`cmd '${cmd}' is not an AnimationTree command; target:'tree' accepts ${ANIMATION_TREE_CMDS.join("|")}.`);
423
+ }
424
+ if ((cmd === "travel" || cmd === "start") && (typeof args.state !== "string" || args.state.length === 0)) {
425
+ throw new ToolInputError(`cmd:'${cmd}' needs state (the state machine node name).`);
426
+ }
427
+ if ((cmd === "set_param" || cmd === "get_param") && (typeof args.param !== "string" || args.param.length === 0)) {
428
+ throw new ToolInputError(`cmd:'${cmd}' needs param (e.g. 'parameters/Blend/blend_amount').`);
429
+ }
430
+ if (cmd === "set_param" && args.value === undefined) {
431
+ throw new ToolInputError("cmd:'set_param' needs value.");
432
+ }
433
+ const op = { op: "RuntimeAnimationTree", path, cmd };
434
+ if (typeof args.state === "string" && args.state.length > 0)
435
+ op.state = args.state;
436
+ if (typeof args.reset === "boolean")
437
+ op.reset = args.reset;
438
+ if (typeof args.param === "string" && args.param.length > 0)
439
+ op.param = args.param;
440
+ if (args.value !== undefined)
441
+ op.value = args.value;
442
+ if (typeof args.playback_path === "string" && args.playback_path.length > 0)
443
+ op.playback_path = args.playback_path;
444
+ return { kind: "RuntimeAnimationTree", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
445
+ }
446
+ if (args.target === "bones") {
447
+ const op = { op: "GetRuntimeBones", path };
448
+ if (args.bones !== undefined) {
449
+ if (!Array.isArray(args.bones) || args.bones.some((bone) => typeof bone !== "string")) {
450
+ throw new ToolInputError("bones must be an array of bone names.");
451
+ }
452
+ op.bones = args.bones;
453
+ }
454
+ if (args.space !== undefined) {
455
+ if (args.space !== "global" && args.space !== "local" && args.space !== "both") {
456
+ throw new ToolInputError("space must be 'global', 'local' or 'both'.");
457
+ }
458
+ op.space = args.space;
459
+ }
460
+ if (typeof args.include_rest === "boolean")
461
+ op.include_rest = args.include_rest;
462
+ return { kind: "GetRuntimeBones", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
463
+ }
464
+ throw new ToolInputError("target must be 'player', 'tree' or 'bones'.");
465
+ }
466
+ // ---------------------------------------------------------------------------
467
+ // summer_game_control — GamePause | GameStep | GameSpeed | ListGameInstances
468
+ // ---------------------------------------------------------------------------
469
+ export const gameControlArgsSchema = z.object({
470
+ action: z
471
+ .enum(["pause", "resume", "step", "speed", "instances"])
472
+ .describe("'pause' suspends the game (Engine time frozen, physics inactive); 'resume' lifts the suspension; 'step' advances exactly N frames and leaves the game suspended; 'speed' sets the user time scale; 'instances' lists the live game instances (main + offscreen)."),
473
+ frames: z
474
+ .number()
475
+ .int()
476
+ .optional()
477
+ .describe("action:'step' — frames to advance, 1..600 (default 1)."),
478
+ kind: z
479
+ .enum(["physics", "process"])
480
+ .optional()
481
+ .describe("action:'step' — 'physics' (default: exact physics ticks, max_physics_steps_per_frame pinned to 1) or 'process' (rendered frames)."),
482
+ speed: z
483
+ .number()
484
+ .optional()
485
+ .describe("action:'speed' — user time scale in (0, 100]: 0.25 = quarter speed, 2 = double."),
486
+ instance: instanceSchema,
487
+ });
488
+ export function buildGameControlOp(args) {
489
+ switch (args.action) {
490
+ case "pause":
491
+ return { kind: "GamePause", op: withInstance({ op: "GamePause", paused: true }, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
492
+ case "resume":
493
+ return { kind: "GamePause", op: withInstance({ op: "GamePause", paused: false }, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
494
+ case "step": {
495
+ const frames = args.frames ?? 1;
496
+ if (!isInt(frames) || frames < 1 || frames > GAME_STEP_MAX_FRAMES) {
497
+ throw new ToolInputError(`frames must be an integer 1..${GAME_STEP_MAX_FRAMES} (got ${String(args.frames)}).`);
498
+ }
499
+ const kind = args.kind ?? "physics";
500
+ if (kind !== "physics" && kind !== "process") {
501
+ throw new ToolInputError("kind must be 'physics' (default) or 'process'.");
502
+ }
503
+ // Engine watchdog: max(10 s, frames / 10 s), capped at 20 s.
504
+ const watchdogSec = Math.min(RUNTIME_WATCHDOG_MAX_SEC, Math.max(RUNTIME_WATCHDOG_DEFAULT_SEC, frames / 10));
505
+ return { kind: "GameStep", op: withInstance({ op: "GameStep", frames, kind }, args.instance), timeoutMs: runtimeBudgetMs(watchdogSec) };
506
+ }
507
+ case "speed": {
508
+ const speed = args.speed;
509
+ if (typeof speed !== "number" || !Number.isFinite(speed) || speed <= 0 || speed > 100) {
510
+ throw new ToolInputError("speed must be a number in (0, 100] — e.g. 0.25 for quarter speed, 2 for double.");
511
+ }
512
+ return { kind: "GameSpeed", op: withInstance({ op: "GameSpeed", speed }, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
513
+ }
514
+ case "instances":
515
+ // Synchronous editor read; `instance` does not apply.
516
+ return { kind: "ListGameInstances", op: { op: "ListGameInstances" }, timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
517
+ default:
518
+ throw new ToolInputError("action must be 'pause', 'resume', 'step', 'speed' or 'instances'.");
519
+ }
520
+ }
521
+ // ---------------------------------------------------------------------------
522
+ // summer_game_input — SimulateInputScript | InputRecordStart | InputRecordStop | InputReplay
523
+ // ---------------------------------------------------------------------------
524
+ export const inputEventSchema = z.object({
525
+ at_frame: z
526
+ .number()
527
+ .int()
528
+ .optional()
529
+ .describe("When to fire, in frames after scheduling (clock:'frame'). Default 0 = the next frame."),
530
+ at_ms: z
531
+ .number()
532
+ .int()
533
+ .optional()
534
+ .describe("When to fire, in milliseconds after scheduling (clock:'ms'); mapped through --fixed-fps when the instance has one (clock_mapping 'exact'), else the physics tick rate ('approximate')."),
535
+ type: z
536
+ .enum(["action", "key", "mouse_click", "axis", "raw"])
537
+ .describe("'action' = InputMap action press/release; 'key' = keycode; 'mouse_click' = click at a position; 'axis' = analog strength between two actions; 'raw' = a recorded InputEvent replayed as {class, props}."),
538
+ action: z.string().optional().describe("type:'action' — InputMap action name (unknown_action if not bound)."),
539
+ pressed: z.boolean().optional().describe("type:'action'|'key' — press (default true) or release."),
540
+ strength: z.number().optional().describe("type:'action' — press strength 0..1 (default 1). type:'axis' — signed strength; negative selects action_negative."),
541
+ hold_ms: z.number().int().optional().describe("type:'action'|'key' — auto-release after this many ms (0 = stays pressed until a release event)."),
542
+ keycode: z.number().int().optional().describe("type:'key' — Godot Key enum value (e.g. 32 = Space, 4194320 = Right arrow)."),
543
+ physical_keycode: z.number().int().optional().describe("type:'key' — physical Key enum value (alternative to keycode)."),
544
+ position: z
545
+ .tuple([z.number(), z.number()])
546
+ .optional()
547
+ .describe("type:'mouse_click' — [x, y] in window pixels."),
548
+ button: z.number().int().optional().describe("type:'mouse_click' — MouseButton (1 = left, 2 = right, 3 = middle)."),
549
+ action_negative: z.string().optional().describe("type:'axis' — action for negative strength (e.g. 'move_left')."),
550
+ action_positive: z.string().optional().describe("type:'axis' — action for positive strength (e.g. 'move_right')."),
551
+ duration_ms: z.number().int().optional().describe("type:'axis' — auto-release after this many ms."),
552
+ class: z.string().optional().describe("type:'raw' — InputEvent class to instantiate (e.g. 'InputEventKey')."),
553
+ props: z.record(z.unknown()).optional().describe("type:'raw' — properties set on the instantiated event."),
554
+ });
555
+ export const gameInputArgsSchema = z.object({
556
+ action: z
557
+ .enum(["script", "record_start", "record_stop", "replay"])
558
+ .describe("'script' schedules a timed sequence of synthetic inputs (SimulateInputScript); 'record_start'/'record_stop' capture the game's real input into res://.summer/replays/<id>.json; 'replay' plays a recording (or inline events) back."),
559
+ events: z
560
+ .array(inputEventSchema)
561
+ .optional()
562
+ .describe("action:'script' (required) or 'replay' (instead of recording) — up to 1000 timed events; last event within 36000 frames / 600 s."),
563
+ clock: z
564
+ .enum(["frame", "ms"])
565
+ .optional()
566
+ .describe("action:'script' — whether at_frame ('frame', default, exact) or at_ms ('ms') schedules the events."),
567
+ wait: z
568
+ .boolean()
569
+ .optional()
570
+ .describe("action:'script'|'replay' — wait for the last event to fire (default true; the engine caps a waited script at 20 s). Scripts longer than that: wait:false and observe with summer_game_probe."),
571
+ include_motion: z
572
+ .boolean()
573
+ .optional()
574
+ .describe("action:'record_start' — also record mouse/joypad motion events (default false; large)."),
575
+ save_as: z
576
+ .string()
577
+ .optional()
578
+ .describe("action:'record_stop' — res://.summer/replays/<name>.json to write instead of a generated id."),
579
+ recording: z
580
+ .string()
581
+ .optional()
582
+ .describe("action:'replay' — the res://.summer/replays/<id>.json path returned by record_stop."),
583
+ seed: z
584
+ .number()
585
+ .int()
586
+ .optional()
587
+ .describe("action:'replay' — assert the replay is reproducible; only accepted on an instance started with summer_play {mode:'offscreen', deterministic:true} (else nondeterministic_instance)."),
588
+ instance: instanceSchema,
589
+ });
590
+ /** Last-event horizon in frames (at_ms mapped at 60 fps, like the engine's pre-check). */
591
+ export function inputScriptHorizonFrames(events) {
592
+ let horizon = 0;
593
+ for (const event of events) {
594
+ if (typeof event.at_frame === "number")
595
+ horizon = Math.max(horizon, Math.floor(event.at_frame));
596
+ else if (typeof event.at_ms === "number")
597
+ horizon = Math.max(horizon, Math.floor((event.at_ms * 60) / 1000));
598
+ }
599
+ return horizon;
600
+ }
601
+ /** Engine watchdog for a waited script: min(20 s, max(10 s, horizon/60 + 3 s)). */
602
+ export function inputScriptWatchdogSec(horizonFrames, wait) {
603
+ if (!wait)
604
+ return RUNTIME_WATCHDOG_DEFAULT_SEC;
605
+ return Math.min(RUNTIME_WATCHDOG_MAX_SEC, Math.max(RUNTIME_WATCHDOG_DEFAULT_SEC, horizonFrames / 60 + 3));
606
+ }
607
+ function validateEvents(events, action) {
608
+ if (!Array.isArray(events) || events.length === 0) {
609
+ throw new ToolInputError(`action:'${action}' needs a non-empty events array ([{type:'action', action:'jump', hold_ms:50}, ...]).`);
610
+ }
611
+ if (events.length > INPUT_SCRIPT_MAX_EVENTS) {
612
+ throw new ToolInputError(`${events.length} events exceeds the ${INPUT_SCRIPT_MAX_EVENTS}-event cap; split the script into sequential calls.`);
613
+ }
614
+ events.forEach((event, index) => {
615
+ if (!event || typeof event !== "object" || Array.isArray(event)) {
616
+ throw new ToolInputError(`events[${index}] is not an object.`);
617
+ }
618
+ const type = event.type;
619
+ if (typeof type !== "string" || !["action", "key", "mouse_click", "axis", "raw"].includes(type)) {
620
+ throw new ToolInputError(`events[${index}].type must be action|key|mouse_click|axis|raw.`);
621
+ }
622
+ });
623
+ const horizon = inputScriptHorizonFrames(events);
624
+ if (horizon > INPUT_SCRIPT_HORIZON_FRAMES) {
625
+ throw new ToolInputError(`The last event lands at frame ${horizon}, beyond the ${INPUT_SCRIPT_HORIZON_FRAMES}-frame (600 s) horizon; shorten the script or split it.`);
626
+ }
627
+ return events;
628
+ }
629
+ export function buildGameInputOp(args) {
630
+ switch (args.action) {
631
+ case "script": {
632
+ const events = validateEvents(args.events, "script");
633
+ const clock = args.clock ?? "frame";
634
+ if (clock !== "frame" && clock !== "ms")
635
+ throw new ToolInputError("clock must be 'frame' (default) or 'ms'.");
636
+ const wait = args.wait ?? true;
637
+ const op = { op: "SimulateInputScript", events, clock, wait };
638
+ const watchdogSec = inputScriptWatchdogSec(inputScriptHorizonFrames(events), wait);
639
+ return { kind: "SimulateInputScript", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(watchdogSec) };
640
+ }
641
+ case "record_start": {
642
+ const op = { op: "InputRecordStart" };
643
+ if (typeof args.include_motion === "boolean")
644
+ op.include_motion = args.include_motion;
645
+ return { kind: "InputRecordStart", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
646
+ }
647
+ case "record_stop": {
648
+ const op = { op: "InputRecordStop" };
649
+ if (typeof args.save_as === "string" && args.save_as.trim().length > 0) {
650
+ const saveAs = args.save_as.trim();
651
+ if (!saveAs.startsWith("res://") || saveAs.includes("..")) {
652
+ throw new ToolInputError("save_as must be a traversal-free res:// path (the engine writes under res://.summer/replays/).");
653
+ }
654
+ op.save_as = saveAs;
655
+ }
656
+ return { kind: "InputRecordStop", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_WATCHDOG_DEFAULT_SEC) };
657
+ }
658
+ case "replay": {
659
+ const hasRecording = typeof args.recording === "string" && args.recording.trim().length > 0;
660
+ const hasEvents = Array.isArray(args.events) && args.events.length > 0;
661
+ if (!hasRecording && !hasEvents) {
662
+ throw new ToolInputError("action:'replay' needs recording (the res://.summer/replays/<id>.json path from record_stop) or inline events.");
663
+ }
664
+ const op = { op: "InputReplay" };
665
+ let horizon = 0;
666
+ if (hasRecording) {
667
+ const recording = args.recording.trim();
668
+ if (!recording.startsWith("res://")) {
669
+ throw new ToolInputError("recording must be the res:// path record_stop returned (res://.summer/replays/<id>.json).");
670
+ }
671
+ op.recording = recording;
672
+ }
673
+ if (hasEvents) {
674
+ const events = validateEvents(args.events, "replay");
675
+ op.events = events;
676
+ horizon = inputScriptHorizonFrames(events);
677
+ }
678
+ if (args.seed !== undefined) {
679
+ if (!isInt(args.seed))
680
+ throw new ToolInputError("seed must be an integer.");
681
+ op.seed = args.seed;
682
+ }
683
+ const wait = args.wait ?? true;
684
+ op.wait = wait;
685
+ // A recording's horizon is only known engine-side; budget the cap.
686
+ const watchdogSec = hasRecording ? (wait ? RUNTIME_WATCHDOG_MAX_SEC : RUNTIME_WATCHDOG_DEFAULT_SEC) : inputScriptWatchdogSec(horizon, wait);
687
+ return { kind: "InputReplay", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(watchdogSec) };
688
+ }
689
+ default:
690
+ throw new ToolInputError("action must be 'script', 'record_start', 'record_stop' or 'replay'.");
691
+ }
692
+ }
693
+ // ---------------------------------------------------------------------------
694
+ // summer_game_probe — GameProbe
695
+ // ---------------------------------------------------------------------------
696
+ export const gameProbeArgsSchema = z.object({
697
+ tree: z
698
+ .object({
699
+ path: z.string().optional().describe("Subtree root, ABSOLUTE runtime path (default the scene tree root)."),
700
+ depth: z.number().int().optional().describe("Depth to walk, 1..8 (default 2)."),
701
+ limit: z.number().int().optional().describe("Node cap, 1..4000 (default 200); truncated is reported."),
702
+ })
703
+ .optional()
704
+ .describe("Include the live scene tree ({name, class, path, children}) built game-side on the SAME frame as the pixels. Omit for no tree."),
705
+ props: z
706
+ .array(z.string())
707
+ .optional()
708
+ .describe("Up to 64 '<absolute path>:<property>' keys read on the same frame, e.g. '/root/Main/Player:position'. Values come back as Godot literal strings; misses land in `missing`."),
709
+ screenshot: z
710
+ .boolean()
711
+ .optional()
712
+ .describe("Capture the game viewport (default true). false = state only, cheaper and works when the window draws nothing."),
713
+ max_dim: z
714
+ .number()
715
+ .int()
716
+ .optional()
717
+ .describe("Longest image side in pixels, 16..4096 (default 1280); the frame is downscaled to fit."),
718
+ instance: instanceSchema,
719
+ });
720
+ export function buildGameProbeOp(args) {
721
+ const op = { op: "GameProbe" };
722
+ if (args.tree !== undefined) {
723
+ if (!args.tree || typeof args.tree !== "object" || Array.isArray(args.tree)) {
724
+ throw new ToolInputError("tree must be an object {path?, depth?, limit?}.");
725
+ }
726
+ const tree = {};
727
+ if (typeof args.tree.path === "string" && args.tree.path.trim().length > 0)
728
+ tree.path = args.tree.path.trim();
729
+ if (args.tree.depth !== undefined) {
730
+ if (!isInt(args.tree.depth) || args.tree.depth < 1 || args.tree.depth > GAME_PROBE_MAX_DEPTH) {
731
+ throw new ToolInputError(`tree.depth must be an integer 1..${GAME_PROBE_MAX_DEPTH}.`);
732
+ }
733
+ tree.depth = args.tree.depth;
734
+ }
735
+ if (args.tree.limit !== undefined) {
736
+ if (!isInt(args.tree.limit) || args.tree.limit < 1 || args.tree.limit > GAME_PROBE_MAX_LIMIT) {
737
+ throw new ToolInputError(`tree.limit must be an integer 1..${GAME_PROBE_MAX_LIMIT}.`);
738
+ }
739
+ tree.limit = args.tree.limit;
740
+ }
741
+ op.tree = tree;
742
+ }
743
+ if (args.props !== undefined) {
744
+ if (!Array.isArray(args.props) || args.props.some((key) => typeof key !== "string" || !key.includes(":"))) {
745
+ throw new ToolInputError("props must be an array of '<absolute path>:<property>' strings, e.g. '/root/Main/Player:position'.");
746
+ }
747
+ if (args.props.length > GAME_PROBE_MAX_PROPS) {
748
+ throw new ToolInputError(`props is capped at ${GAME_PROBE_MAX_PROPS} keys per probe; split the read.`);
749
+ }
750
+ op.props = args.props;
751
+ }
752
+ if (typeof args.screenshot === "boolean")
753
+ op.screenshot = args.screenshot;
754
+ if (args.max_dim !== undefined) {
755
+ if (!isInt(args.max_dim) || args.max_dim < GAME_PROBE_MIN_DIM || args.max_dim > GAME_PROBE_MAX_DIM) {
756
+ throw new ToolInputError(`max_dim must be an integer ${GAME_PROBE_MIN_DIM}..${GAME_PROBE_MAX_DIM}.`);
757
+ }
758
+ op.max_dim = args.max_dim;
759
+ }
760
+ return { kind: "GameProbe", op: withInstance(op, args.instance), timeoutMs: runtimeBudgetMs(RUNTIME_PROBE_WATCHDOG_SEC) };
761
+ }
762
+ /** The GameProbe result inside an ops envelope (or the bare op result). */
763
+ export function findProbePayload(result) {
764
+ if (!result || typeof result !== "object")
765
+ return null;
766
+ const record = result;
767
+ if (record.op === "GameProbe")
768
+ return record;
769
+ if (Array.isArray(record.results)) {
770
+ for (const entry of record.results) {
771
+ if (entry && typeof entry === "object" && entry.op === "GameProbe") {
772
+ return entry;
773
+ }
774
+ }
775
+ const first = record.results[0];
776
+ if (first && typeof first === "object")
777
+ return first;
778
+ }
779
+ return null;
780
+ }
781
+ /** The same envelope with the image bytes removed (for text rendering and logs). */
782
+ export function stripProbeImage(result) {
783
+ if (!result || typeof result !== "object")
784
+ return result;
785
+ const record = result;
786
+ const strip = (entry) => {
787
+ if (!entry || typeof entry !== "object")
788
+ return entry;
789
+ const { image_base64: _dropped, ...rest } = entry;
790
+ return rest;
791
+ };
792
+ if (Array.isArray(record.results)) {
793
+ return { ...strip(record), results: record.results.map(strip) };
794
+ }
795
+ return strip(record);
796
+ }
797
+ /** One-line frame stamp for a probe payload: which frame the state and the
798
+ * pixels describe, so a claim can cite it. */
799
+ export function probeFrameStamp(payload) {
800
+ const frame = (payload.frame ?? {});
801
+ const parts = [];
802
+ if (typeof frame.process_frames === "number")
803
+ parts.push(`frame ${frame.process_frames}`);
804
+ if (typeof frame.physics_frames === "number")
805
+ parts.push(`physics ${frame.physics_frames}`);
806
+ if (typeof frame.frames_drawn === "number")
807
+ parts.push(`drawn ${frame.frames_drawn}`);
808
+ if (typeof payload.image_frame === "number")
809
+ parts.push(`image_frame ${payload.image_frame}`);
810
+ if (typeof payload.instance === "string")
811
+ parts.push(`instance ${payload.instance}`);
812
+ if (payload.suspended === true)
813
+ parts.push("SUSPENDED");
814
+ if (payload.paused === true)
815
+ parts.push("SceneTree.paused");
816
+ if (typeof payload.time_scale === "number" && payload.time_scale !== 1)
817
+ parts.push(`time_scale ${payload.time_scale}`);
818
+ return parts.length > 0 ? parts.join(", ") : "frame unknown";
819
+ }
820
+ // ---------------------------------------------------------------------------
821
+ // summer_play / summer_stop — instance-aware PlayGame / StopGame
822
+ // ---------------------------------------------------------------------------
823
+ export const playGameExtensionSchema = {
824
+ instance: z
825
+ .string()
826
+ .optional()
827
+ .describe("Name a game instance. 'main' (default) = the editor's embedded game. Any other name with mode:'offscreen' spawns a disposable parallel instance (at most 3) that the runtime tools address by this name."),
828
+ mode: z
829
+ .enum(["embedded", "offscreen"])
830
+ .optional()
831
+ .describe("'embedded' (default) plays in the editor; 'offscreen' spawns a hidden child process (requires instance != 'main')."),
832
+ deterministic: z
833
+ .boolean()
834
+ .optional()
835
+ .describe("Offscreen only: launch with --fixed-fps 60 --summer-seed <seed> --audio-driver Dummy so the run is reproducible and input replays with seed are accepted."),
836
+ seed: z
837
+ .number()
838
+ .int()
839
+ .optional()
840
+ .describe("Pin the game's GLOBAL RNG for this launch (child gets --summer-seed <seed>; default 20260725 when deterministic:true and seed is omitted). Pins randi/randf/randi_range/randf_range/randfn, Array.shuffle/pick_random. Does NOT pin RandomNumberGenerator instances, scripts calling randomize(), or wall-clock reads. Omitted = randomized, as always."),
841
+ fixed_fps: z
842
+ .number()
843
+ .int()
844
+ .positive()
845
+ .optional()
846
+ .describe("Fixed timestep for this launch (child gets --fixed-fps <n>): scene time decouples from the wall clock, the game runs as fast as it renders, frame-count-derived state repeats run to run, and at_ms input timing / GameStep frames map exactly. Opt-in per launch, never the default."),
847
+ time_scale: z
848
+ .number()
849
+ .positive()
850
+ .optional()
851
+ .describe("Engine time scale for this launch (child gets --time-scale <f>). Not a determinism pin on its own."),
852
+ speed: z
853
+ .number()
854
+ .optional()
855
+ .describe("User time scale applied on session start, (0, 100] — e.g. 0.5 for half speed."),
856
+ focus: z
857
+ .boolean()
858
+ .optional()
859
+ .describe("Default false = QUIET play (PlayGame agent:true): the editor does not switch to the Game tab or grab focus for the embedded game, so the user keeps working. Pass true to launch the way the toolbar Play button does (Game tab + focus) — only when the user is watching and asked to see it."),
860
+ };
861
+ /**
862
+ * Quiet is the default whenever an agent drives play — both faces of this tool
863
+ * (MCP and `summer tool`) ARE agent faces, so the only way to a focus-stealing
864
+ * launch is an explicit focus:true. Quiet travels as PlayGame `agent:true`
865
+ * (debug_ops.cpp play_game -> GameView::set_agent_quiet_play), which the engine
866
+ * has honoured since 0.5.45 (c7c490d84f3, 2026-07-02).
867
+ */
868
+ export function playIsQuiet(args) {
869
+ return args.focus !== true;
870
+ }
871
+ /** True when the call needs the PlayGame OP (instance-aware / determinism
872
+ * params) rather than the legacy /api/play route, which forwards only `scene`. */
873
+ export function playNeedsOp(args) {
874
+ return (
875
+ // The /api/play rung builds a PlayGame op with ONLY `scene`
876
+ // (local_api_server.cpp play branch), so `agent:true` has to ride the op.
877
+ playIsQuiet(args) ||
878
+ (typeof args.instance === "string" && args.instance.trim().length > 0) ||
879
+ args.mode !== undefined ||
880
+ args.deterministic !== undefined ||
881
+ args.seed !== undefined ||
882
+ args.fixed_fps !== undefined ||
883
+ args.time_scale !== undefined ||
884
+ args.speed !== undefined);
885
+ }
886
+ /** True when the call addresses a non-main instance or an offscreen mode —
887
+ * the part of PlayGame that only a runtime-control engine understands. */
888
+ export function playTargetsInstance(args) {
889
+ const instance = typeof args.instance === "string" ? args.instance.trim() : "";
890
+ return (instance.length > 0 && instance !== "main") || args.mode === "offscreen";
891
+ }
892
+ export function buildPlayGameOp(args) {
893
+ const instance = typeof args.instance === "string" ? args.instance.trim() : "";
894
+ if (args.mode !== undefined && args.mode !== "embedded" && args.mode !== "offscreen") {
895
+ throw new ToolInputError("mode must be 'embedded' (default) or 'offscreen'.");
896
+ }
897
+ if (args.mode === "offscreen" && (instance.length === 0 || instance === "main")) {
898
+ throw new ToolInputError("mode:'offscreen' needs an instance name other than 'main' (the main slot is the editor's embedded game), e.g. instance:'a'.");
899
+ }
900
+ if (instance.length > 0 && instance !== "main" && args.mode !== "offscreen") {
901
+ throw new ToolInputError(`instance:'${instance}' needs mode:'offscreen' — only the 'main' instance plays embedded in the editor.`);
902
+ }
903
+ if (args.deterministic === true && args.mode !== "offscreen") {
904
+ throw new ToolInputError("deterministic:true is offscreen-only (it launches a child with --fixed-fps 60 --summer-seed --audio-driver Dummy). Pass instance + mode:'offscreen', or use seed/fixed_fps alone for the embedded game.");
905
+ }
906
+ if (args.seed !== undefined && !isInt(args.seed))
907
+ throw new ToolInputError("seed must be an integer.");
908
+ if (args.fixed_fps !== undefined && (!isInt(args.fixed_fps) || args.fixed_fps <= 0)) {
909
+ throw new ToolInputError("fixed_fps must be an integer > 0.");
910
+ }
911
+ if (args.time_scale !== undefined && (typeof args.time_scale !== "number" || !Number.isFinite(args.time_scale) || args.time_scale <= 0)) {
912
+ throw new ToolInputError("time_scale must be a number > 0.");
913
+ }
914
+ if (args.speed !== undefined && (typeof args.speed !== "number" || !Number.isFinite(args.speed) || args.speed <= 0 || args.speed > 100)) {
915
+ throw new ToolInputError("speed must be a number in (0, 100].");
916
+ }
917
+ const op = { op: "PlayGame" };
918
+ if (typeof args.scene === "string" && args.scene.trim().length > 0)
919
+ op.scene = args.scene.trim();
920
+ // Quiet concerns the editor's embedded Game view only; an offscreen
921
+ // instance is a hidden child and never touches the editor's tab or focus.
922
+ if (playIsQuiet(args) && !playTargetsInstance(args))
923
+ op.agent = true;
924
+ if (instance.length > 0)
925
+ op.instance = instance;
926
+ if (args.mode !== undefined)
927
+ op.mode = args.mode;
928
+ if (args.deterministic !== undefined)
929
+ op.deterministic = args.deterministic;
930
+ if (args.seed !== undefined)
931
+ op.seed = args.seed;
932
+ if (args.fixed_fps !== undefined)
933
+ op.fixed_fps = args.fixed_fps;
934
+ if (args.time_scale !== undefined)
935
+ op.time_scale = args.time_scale;
936
+ if (args.speed !== undefined)
937
+ op.speed = args.speed;
938
+ return { kind: "PlayGame", op, timeoutMs: PLAY_INSTANCE_TIMEOUT_MS };
939
+ }
940
+ export function buildStopGameOp(instance) {
941
+ const trimmed = instance.trim();
942
+ if (trimmed.length === 0)
943
+ throw new ToolInputError("instance must be a non-empty instance name.");
944
+ return { kind: "StopGame", op: { op: "StopGame", instance: trimmed }, timeoutMs: STOP_INSTANCE_TIMEOUT_MS };
945
+ }
946
+ /**
947
+ * An engine that predates instance-aware PlayGame ignores `instance`/`mode`
948
+ * and starts the MAIN embedded game. When the caller asked for an instance
949
+ * and the result does not echo one, say so instead of letting the model
950
+ * believe a parallel instance is up.
951
+ */
952
+ export function withPlayInstanceEcho(result, args) {
953
+ if (!playTargetsInstance(args) || !result || typeof result !== "object")
954
+ return result;
955
+ if (extractOpError(result))
956
+ return result;
957
+ const envelope = result;
958
+ const payload = envelope.results?.[0] ?? envelope;
959
+ if (typeof payload.instance === "string")
960
+ return result;
961
+ return {
962
+ ...envelope,
963
+ warning: `This Summer Engine build did not echo \`instance\` in its PlayGame result — it predates instance-aware play and has most likely started the MAIN embedded game, ignoring instance:'${args.instance ?? ""}' / mode:'${args.mode ?? "embedded"}'. Verify with summer_is_running or summer_game_control action:'instances' before addressing that instance, and update Summer Engine for parallel instances.`,
964
+ };
965
+ }
966
+ export const PLAY_QUIET_NOT_SUPPORTED = "This Summer Engine build did not echo `agent_quiet` in its PlayGame result — it predates quiet play and has most likely switched the editor to the Game tab and taken focus. Update Summer Engine (restart it after updating) for launches that leave the user's screen alone.";
967
+ /**
968
+ * Quiet was requested: the engine echoes `agent_quiet` when it understood the
969
+ * flag (debug_ops.cpp play_game — in the launch branch AND the already-running
970
+ * branch on current engines). No echo at all means an engine that predates
971
+ * the flag ignored it — say so instead of letting the model believe the user
972
+ * was left alone. The field is the contract; the `note` text is never matched.
973
+ */
974
+ export function withPlayPostureEcho(result, args) {
975
+ if (!playIsQuiet(args) || playTargetsInstance(args) || !result || typeof result !== "object")
976
+ return result;
977
+ if (extractOpError(result))
978
+ return result;
979
+ const envelope = result;
980
+ const payload = envelope.results?.[0] ?? envelope;
981
+ if (typeof payload.agent_quiet === "boolean")
982
+ return result;
983
+ return { ...envelope, posture_note: PLAY_QUIET_NOT_SUPPORTED };
984
+ }
985
+ /**
986
+ * summer_play, ONE implementation for both faces (MCP debug-tools.ts and the
987
+ * CLI dispatcher). Throws ToolInputError for a bad parameter combination
988
+ * (nothing sent); returns the engine envelope, a structured engine_lacks_op
989
+ * pre-flight result, or the envelope with the old-engine / posture / instance
990
+ * annotations. Each face only decides how to RENDER failures.
991
+ *
992
+ * Routing: focus:true with no other parameter is the legacy /api/play route,
993
+ * byte-for-byte the v1 call. Everything else — including the quiet default —
994
+ * travels as the explicit PlayGame op, because the /api/play rung copies only
995
+ * `scene` into the op and would drop agent/seed/instance.
996
+ */
997
+ export async function playGame(client, args) {
998
+ if (!playNeedsOp(args))
999
+ return client.play(args.scene);
1000
+ // Validate the combination first (nothing sent); then, because an engine
1001
+ // without the runtime-control wave would start the MAIN game and silently
1002
+ // ignore instance/mode, the pre-flight keys on a runtime-control kind.
1003
+ const { op, timeoutMs } = buildPlayGameOp(args);
1004
+ if (playTargetsInstance(args)) {
1005
+ const missing = missingEngineOpResult(client, "ListGameInstances", PLAY_INSTANCE_FALLBACK);
1006
+ if (missing)
1007
+ return missing;
1008
+ }
1009
+ const result = await client.executeOps([op], undefined, timeoutMs);
1010
+ return withPlayPostureEcho(withPlayInstanceEcho(withRuntimeFailureHints(withOldEngineHint(result, "PlayGame", PLAY_INSTANCE_FALLBACK)), args), args);
1011
+ }