summer-engine 3.7.0 → 4.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 (501) hide show
  1. package/.claude-plugin/marketplace.json +2 -13
  2. package/.claude-plugin/plugin.json +25 -22
  3. package/.codex-plugin/plugin.json +8 -14
  4. package/.cursor-plugin/plugin.json +7 -13
  5. package/.factory-plugin/plugin.json +7 -13
  6. package/AGENTS.md +19 -12
  7. package/CHANGELOG.md +112 -0
  8. package/GEMINI.md +3 -3
  9. package/README.md +111 -31
  10. package/assets/icon.png +0 -0
  11. package/commands/start.md +71 -0
  12. package/commands/summer.md +5 -3
  13. package/dist/cli/banner.js +3 -0
  14. package/dist/cli/commands/login.d.ts +27 -0
  15. package/dist/cli/commands/login.js +58 -12
  16. package/dist/cli/commands/ops.d.ts +47 -0
  17. package/dist/cli/commands/ops.js +301 -0
  18. package/dist/cli/commands/setup.d.ts +2 -0
  19. package/dist/cli/commands/setup.js +37 -12
  20. package/dist/cli/commands/skills.js +11 -7
  21. package/dist/cli/index.js +7 -0
  22. package/dist/core/agent-host.d.ts +65 -0
  23. package/dist/core/agent-host.js +193 -0
  24. package/dist/core/capabilities/agent-playbook.d.ts +3 -0
  25. package/dist/core/capabilities/agent-playbook.js +54 -2
  26. package/dist/core/capabilities/apps.d.ts +341 -0
  27. package/dist/core/capabilities/apps.js +353 -0
  28. package/dist/core/capabilities/doctor.d.ts +3 -0
  29. package/dist/core/capabilities/doctor.js +20 -15
  30. package/dist/core/capabilities/enable-plugin.d.ts +27 -0
  31. package/dist/core/capabilities/enable-plugin.js +75 -0
  32. package/dist/core/capabilities/fabricate-mesh.d.ts +2 -2
  33. package/dist/core/capabilities/game-task-plan.d.ts +12 -6
  34. package/dist/core/capabilities/game-task-plan.js +80 -5
  35. package/dist/core/capabilities/motion-generation.js +2 -2
  36. package/dist/core/capabilities/navigation/open.d.ts +6 -2
  37. package/dist/core/capabilities/navigation/open.js +3 -0
  38. package/dist/core/capabilities/publish-build.js +2 -0
  39. package/dist/core/capabilities/runtime-control.d.ts +4 -4
  40. package/dist/core/capabilities/scene-script-target.d.ts +17 -0
  41. package/dist/core/capabilities/scene-script-target.js +70 -0
  42. package/dist/core/capabilities/sfx-choices.d.ts +4 -0
  43. package/dist/core/capabilities/sfx-choices.js +13 -6
  44. package/dist/core/capabilities/tool-dispatch.d.ts +12 -3
  45. package/dist/core/capabilities/tool-dispatch.js +130 -46
  46. package/dist/core/capability-skew.js +4 -0
  47. package/dist/core/embeddings.d.ts +2 -0
  48. package/dist/core/embeddings.js +1 -1
  49. package/dist/core/error-codes.d.ts +62 -0
  50. package/dist/core/error-codes.js +97 -0
  51. package/dist/core/format.d.ts +2 -0
  52. package/dist/core/format.js +2 -1
  53. package/dist/core/hosted-mcp.d.ts +22 -0
  54. package/dist/core/hosted-mcp.js +56 -1
  55. package/dist/core/library-read.js +5 -0
  56. package/dist/core/library-search.js +2 -1
  57. package/dist/core/oauth.js +4 -0
  58. package/dist/core/ops/catalog.d.ts +41 -0
  59. package/dist/core/ops/catalog.js +145 -0
  60. package/dist/core/ops/cloud.d.ts +56 -0
  61. package/dist/core/ops/cloud.js +175 -0
  62. package/dist/core/ops/contract.d.ts +119 -0
  63. package/dist/core/ops/contract.js +142 -0
  64. package/dist/core/ops/engine-answer.d.ts +25 -0
  65. package/dist/core/ops/engine-answer.js +117 -0
  66. package/dist/core/ops/engine.d.ts +55 -0
  67. package/dist/core/ops/engine.js +649 -0
  68. package/dist/core/ops/save-files.d.ts +78 -0
  69. package/dist/core/ops/save-files.js +419 -0
  70. package/dist/core/ops/search.d.ts +9 -0
  71. package/dist/core/ops/search.js +55 -0
  72. package/dist/core/skills-registry.d.ts +16 -1
  73. package/dist/core/skills-registry.js +35 -2
  74. package/dist/core/telemetry.d.ts +32 -0
  75. package/dist/core/telemetry.js +38 -10
  76. package/dist/core/tool-profiles.d.ts +25 -0
  77. package/dist/core/tool-profiles.js +41 -0
  78. package/dist/installer/agent-config.d.ts +17 -4
  79. package/dist/installer/agent-config.js +22 -6
  80. package/dist/installer/agent-table.d.ts +3 -0
  81. package/dist/installer/agent-table.js +10 -7
  82. package/dist/installer/setup.d.ts +2 -0
  83. package/dist/installer/setup.js +9 -4
  84. package/dist/installer/version-check.d.ts +29 -9
  85. package/dist/installer/version-check.js +81 -28
  86. package/dist/mcp/command.js +7 -0
  87. package/dist/mcp/hosted-mount.d.ts +27 -2
  88. package/dist/mcp/hosted-mount.js +66 -24
  89. package/dist/mcp/legacy-toolset.d.ts +27 -0
  90. package/dist/mcp/legacy-toolset.js +43 -0
  91. package/dist/mcp/ops-surface.d.ts +59 -0
  92. package/dist/mcp/ops-surface.js +443 -0
  93. package/dist/mcp/server.d.ts +35 -11
  94. package/dist/mcp/server.js +236 -89
  95. package/dist/mcp/tool-results.d.ts +26 -0
  96. package/dist/mcp/tool-results.js +81 -0
  97. package/dist/mcp/tool-surface.d.ts +65 -0
  98. package/dist/mcp/tool-surface.js +317 -0
  99. package/dist/mcp/tools/app-tools.d.ts +2 -0
  100. package/dist/mcp/tools/app-tools.js +71 -0
  101. package/dist/mcp/tools/asset-tools.js +55 -53
  102. package/dist/mcp/tools/audit-tools.js +21 -21
  103. package/dist/mcp/tools/debug-tools.js +6 -6
  104. package/dist/mcp/tools/fabricate-tools.js +6 -6
  105. package/dist/mcp/tools/generate-tools.js +76 -70
  106. package/dist/mcp/tools/project-tools.d.ts +9 -4
  107. package/dist/mcp/tools/project-tools.js +16 -10
  108. package/dist/mcp/tools/scene-tools.js +12 -23
  109. package/dist/mcp/tools/script-tools.js +9 -5
  110. package/dist/mcp/tools/with-engine.d.ts +6 -0
  111. package/dist/mcp/tools/with-engine.js +19 -0
  112. package/gemini-extension.json +6 -12
  113. package/hooks/pre-commit-doctor.sh +5 -4
  114. package/hooks/session-start.sh +24 -28
  115. package/integrations/claude-desktop/README.md +1 -1
  116. package/integrations/copilot-jetbrains/README.md +1 -1
  117. package/integrations/junie/README.md +1 -1
  118. package/integrations/lm-studio/README.md +1 -1
  119. package/integrations/trae/README.md +1 -1
  120. package/integrations/visual-studio/README.md +1 -1
  121. package/library/references/mcp-tools-reference/mcp-tools-reference.md +85 -35
  122. package/library/references/mcp-tools-reference/resource.yaml +1 -1
  123. package/library/references/product-map/resource.yaml +2 -2
  124. package/library/skills/3d-lighting/SKILL.md +53 -28
  125. package/library/skills/3d-lighting/resource.yaml +1 -1
  126. package/library/skills/README.md +126 -116
  127. package/library/skills/adaptive-music/SKILL.md +19 -23
  128. package/library/skills/adaptive-music/resource.yaml +1 -1
  129. package/library/skills/agent-playtesting/SKILL.md +1 -1
  130. package/library/skills/agent-playtesting/resource.yaml +1 -1
  131. package/library/skills/ai-characters-in-games/SKILL.md +1 -1
  132. package/library/skills/ai-characters-in-games/resource.yaml +1 -1
  133. package/library/skills/ambient-bed/SKILL.md +22 -13
  134. package/library/skills/ambient-bed/resource.yaml +1 -1
  135. package/library/skills/animated-loop/SKILL.md +41 -32
  136. package/library/skills/animated-loop/resource.yaml +1 -1
  137. package/library/skills/animation-tree/SKILL.md +1 -1
  138. package/library/skills/animation-tree/resource.yaml +1 -1
  139. package/library/skills/art-direction/SKILL.md +3 -3
  140. package/library/skills/art-direction/resource.yaml +1 -1
  141. package/library/skills/asset-strategy/SKILL.md +21 -4
  142. package/library/skills/asset-strategy/resource.yaml +2 -1
  143. package/library/skills/audio-direction/SKILL.md +10 -10
  144. package/library/skills/audio-direction/resource.yaml +1 -1
  145. package/library/skills/auto-fire-targeting/SKILL.md +1 -1
  146. package/library/skills/auto-fire-targeting/resource.yaml +1 -1
  147. package/library/skills/bounded-engine-runs/SKILL.md +1 -1
  148. package/library/skills/bounded-engine-runs/resource.yaml +1 -1
  149. package/library/skills/brainstorm-game/SKILL.md +1 -1
  150. package/library/skills/brainstorm-game/resource.yaml +1 -1
  151. package/library/skills/brainstorming/SKILL.md +1 -1
  152. package/library/skills/brainstorming/resource.yaml +1 -1
  153. package/library/skills/browse-templates/SKILL.md +1 -1
  154. package/library/skills/browse-templates/resource.yaml +1 -1
  155. package/library/skills/camera-rigs/SKILL.md +2 -2
  156. package/library/skills/camera-rigs/resource.yaml +1 -1
  157. package/library/skills/celeste-momentum-platforming/resource.yaml +1 -0
  158. package/library/skills/character-animation-wiring/SKILL.md +4 -4
  159. package/library/skills/character-animation-wiring/resource.yaml +1 -1
  160. package/library/skills/character-model/SKILL.md +55 -47
  161. package/library/skills/character-model/resource.yaml +1 -1
  162. package/library/skills/character-movement/SKILL.md +3 -3
  163. package/library/skills/character-movement/resource.yaml +1 -1
  164. package/library/skills/character-portrait/SKILL.md +24 -19
  165. package/library/skills/character-portrait/resource.yaml +1 -1
  166. package/library/skills/cinematic-cutscene/SKILL.md +58 -46
  167. package/library/skills/cinematic-cutscene/resource.yaml +1 -1
  168. package/library/skills/combat-basics/SKILL.md +1 -1
  169. package/library/skills/combat-basics/resource.yaml +1 -1
  170. package/library/skills/compatibility-renderer-traps/SKILL.md +1 -1
  171. package/library/skills/compatibility-renderer-traps/resource.yaml +1 -1
  172. package/library/skills/concept-art/SKILL.md +16 -12
  173. package/library/skills/concept-art/resource.yaml +1 -1
  174. package/library/skills/concept-to-level/SKILL.md +239 -0
  175. package/library/skills/concept-to-level/references/technical-rules.md +150 -0
  176. package/library/skills/concept-to-level/resource.yaml +44 -0
  177. package/library/skills/create-asset-sheet/SKILL.md +19 -13
  178. package/library/skills/create-asset-sheet/resource.yaml +1 -1
  179. package/library/skills/debug/SKILL.md +2 -2
  180. package/library/skills/debug/resource.yaml +1 -1
  181. package/library/skills/debugging-game-feel/SKILL.md +1 -1
  182. package/library/skills/debugging-game-feel/resource.yaml +1 -1
  183. package/library/skills/design-level/SKILL.md +23 -35
  184. package/library/skills/design-level/resource.yaml +1 -1
  185. package/library/skills/design-mechanic/SKILL.md +1 -1
  186. package/library/skills/design-mechanic/resource.yaml +1 -1
  187. package/library/skills/design-npc/SKILL.md +22 -24
  188. package/library/skills/design-npc/resource.yaml +1 -1
  189. package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
  190. package/library/skills/diagnosing-perf-regressions/resource.yaml +1 -1
  191. package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
  192. package/library/skills/driving-the-editor-ui/resource.yaml +1 -1
  193. package/library/skills/environment-kit/SKILL.md +20 -16
  194. package/library/skills/environment-kit/resource.yaml +1 -1
  195. package/library/skills/export-and-ship/SKILL.md +6 -6
  196. package/library/skills/export-and-ship/resource.yaml +1 -1
  197. package/library/skills/fabricating-assets/SKILL.md +7 -7
  198. package/library/skills/fabricating-assets/resource.yaml +3 -3
  199. package/library/skills/facial-and-lipsync/SKILL.md +14 -15
  200. package/library/skills/facial-and-lipsync/resource.yaml +1 -1
  201. package/library/skills/fps-controller/SKILL.md +33 -41
  202. package/library/skills/fps-controller/resource.yaml +1 -1
  203. package/library/skills/game-feel/SKILL.md +8 -8
  204. package/library/skills/game-feel/resource.yaml +1 -1
  205. package/library/skills/gameskill/SKILL.md +4 -4
  206. package/library/skills/gameskill/resource.yaml +1 -1
  207. package/library/skills/gdscript-patterns/SKILL.md +1 -1
  208. package/library/skills/gdscript-patterns/resource.yaml +1 -1
  209. package/library/skills/generate-motion/SKILL.md +30 -21
  210. package/library/skills/generate-motion/resource.yaml +1 -1
  211. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
  212. package/library/skills/godogen-visual-proof-game-generation/resource.yaml +1 -0
  213. package/library/skills/grow-analytics/SKILL.md +3 -3
  214. package/library/skills/grow-analytics/resource.yaml +1 -1
  215. package/library/skills/headless-scripting/SKILL.md +1 -1
  216. package/library/skills/headless-scripting/resource.yaml +1 -1
  217. package/library/skills/in-game-purchases/SKILL.md +1 -1
  218. package/library/skills/in-game-purchases/resource.yaml +1 -1
  219. package/library/skills/instantiate-asset-pack/SKILL.md +2 -2
  220. package/library/skills/instantiate-asset-pack/resource.yaml +1 -1
  221. package/library/skills/lumera-single-image-scene-reconstruction/resource.yaml +1 -0
  222. package/library/skills/make-game/SKILL.md +4 -4
  223. package/library/skills/make-game/references/2d-platformer.md +1 -1
  224. package/library/skills/make-game/references/3d-fps.md +1 -1
  225. package/library/skills/make-game/references/3d-horror.md +1 -1
  226. package/library/skills/make-game/references/3d-third-person.md +2 -2
  227. package/library/skills/make-game/resource.yaml +1 -1
  228. package/library/skills/multiplayer/SKILL.md +1 -1
  229. package/library/skills/multiplayer/resource.yaml +1 -1
  230. package/library/skills/multiplayer-movement/SKILL.md +1 -1
  231. package/library/skills/multiplayer-movement/resource.yaml +1 -1
  232. package/library/skills/multiplayer-project/SKILL.md +1 -1
  233. package/library/skills/multiplayer-project/resource.yaml +1 -1
  234. package/library/skills/multiplayer-publish/SKILL.md +8 -7
  235. package/library/skills/multiplayer-publish/resource.yaml +3 -3
  236. package/library/skills/multiplayer-state/SKILL.md +1 -1
  237. package/library/skills/multiplayer-state/resource.yaml +1 -1
  238. package/library/skills/multiplayer-testing/SKILL.md +1 -1
  239. package/library/skills/multiplayer-testing/resource.yaml +1 -1
  240. package/library/skills/music-track/SKILL.md +22 -13
  241. package/library/skills/music-track/resource.yaml +1 -1
  242. package/library/skills/navigate-summer/SKILL.md +11 -9
  243. package/library/skills/navigate-summer/resource.yaml +1 -1
  244. package/library/skills/new-project/SKILL.md +1 -1
  245. package/library/skills/new-project/resource.yaml +1 -1
  246. package/library/skills/organic-model/SKILL.md +24 -18
  247. package/library/skills/organic-model/resource.yaml +1 -1
  248. package/library/skills/pixel-art/SKILL.md +27 -23
  249. package/library/skills/pixel-art/resource.yaml +1 -1
  250. package/library/skills/play/SKILL.md +1 -1
  251. package/library/skills/play/resource.yaml +1 -1
  252. package/library/skills/playtesting-a-feature/SKILL.md +1 -1
  253. package/library/skills/playtesting-a-feature/resource.yaml +1 -1
  254. package/library/skills/procedural-animation/SKILL.md +20 -16
  255. package/library/skills/procedural-animation/resource.yaml +1 -1
  256. package/library/skills/prop-model/SKILL.md +25 -19
  257. package/library/skills/prop-model/resource.yaml +1 -1
  258. package/library/skills/psx-retro-rendering/resource.yaml +1 -0
  259. package/library/skills/publish-your-game/SKILL.md +16 -6
  260. package/library/skills/publish-your-game/resource.yaml +3 -3
  261. package/library/skills/realtime-wet-surfaces/resource.yaml +1 -0
  262. package/library/skills/release-readiness/SKILL.md +1 -1
  263. package/library/skills/release-readiness/resource.yaml +1 -1
  264. package/library/skills/remote-deploy/SKILL.md +1 -1
  265. package/library/skills/remote-deploy/resource.yaml +1 -1
  266. package/library/skills/retarget/SKILL.md +23 -20
  267. package/library/skills/retarget/resource.yaml +1 -1
  268. package/library/skills/running-in-the-cloud/SKILL.md +1 -1
  269. package/library/skills/running-in-the-cloud/resource.yaml +1 -1
  270. package/library/skills/save-load/SKILL.md +1 -1
  271. package/library/skills/save-load/resource.yaml +1 -1
  272. package/library/skills/scene-composition/SKILL.md +1 -1
  273. package/library/skills/scene-composition/resource.yaml +1 -1
  274. package/library/skills/scene-hierarchy-design/SKILL.md +2 -2
  275. package/library/skills/scene-hierarchy-design/resource.yaml +1 -1
  276. package/library/skills/scene-scripting/SKILL.md +66 -636
  277. package/library/skills/scene-scripting/references/ctx-api.md +184 -0
  278. package/library/skills/scene-scripting/references/recipes-2d-ui.md +193 -0
  279. package/library/skills/scene-scripting/references/recipes-3d.md +280 -0
  280. package/library/skills/scene-scripting/resource.yaml +4 -4
  281. package/library/skills/scene-to-level/SKILL.md +2 -2
  282. package/library/skills/scene-to-level/resource.yaml +1 -1
  283. package/library/skills/skill-create/resource.yaml +1 -0
  284. package/library/skills/skill-improve/resource.yaml +1 -0
  285. package/library/skills/skill-test/SKILL.md +2 -2
  286. package/library/skills/skill-test/resource.yaml +1 -0
  287. package/library/skills/skintokens-auto-rigging/resource.yaml +1 -0
  288. package/library/skills/skybox-panorama/SKILL.md +27 -21
  289. package/library/skills/skybox-panorama/resource.yaml +1 -1
  290. package/library/skills/sound-effect/SKILL.md +31 -20
  291. package/library/skills/sound-effect/resource.yaml +1 -1
  292. package/library/skills/spatial-placement/SKILL.md +14 -9
  293. package/library/skills/spatial-placement/resource.yaml +1 -1
  294. package/library/skills/sprite-sheet/SKILL.md +32 -27
  295. package/library/skills/sprite-sheet/resource.yaml +1 -1
  296. package/library/skills/store-art/SKILL.md +3 -3
  297. package/library/skills/store-art/resource.yaml +2 -2
  298. package/library/skills/store-listing/SKILL.md +3 -3
  299. package/library/skills/store-listing/resource.yaml +2 -2
  300. package/library/skills/summer-analytics/SKILL.md +7 -5
  301. package/library/skills/summer-analytics/resource.yaml +2 -2
  302. package/library/skills/summer-apps/SKILL.md +168 -0
  303. package/library/skills/summer-apps/manifest.md +57 -0
  304. package/library/skills/summer-apps/minimal-app.md +183 -0
  305. package/library/skills/summer-apps/resource.yaml +36 -0
  306. package/library/skills/summer-apps/sdk-reference.md +135 -0
  307. package/library/skills/summer-apps-design/SKILL.md +197 -0
  308. package/library/skills/summer-apps-design/resource.yaml +23 -0
  309. package/library/skills/summer-assets/SKILL.md +56 -0
  310. package/library/skills/summer-assets/resource.yaml +34 -0
  311. package/library/skills/summer-store/SKILL.md +1 -1
  312. package/library/skills/text-to-motion/SKILL.md +30 -23
  313. package/library/skills/text-to-motion/prompts-and-controls.md +5 -5
  314. package/library/skills/text-to-motion/resource.yaml +1 -1
  315. package/library/skills/text-to-motion/rigging-for-text-motion.md +2 -2
  316. package/library/skills/tileable-texture/SKILL.md +19 -15
  317. package/library/skills/tileable-texture/resource.yaml +1 -1
  318. package/library/skills/trailer-shot/SKILL.md +28 -24
  319. package/library/skills/trailer-shot/resource.yaml +1 -1
  320. package/library/skills/tune-performance/SKILL.md +6 -6
  321. package/library/skills/tune-performance/resource.yaml +1 -1
  322. package/library/skills/ui-basics/SKILL.md +41 -36
  323. package/library/skills/ui-basics/resource.yaml +1 -1
  324. package/library/skills/ui-graphics/SKILL.md +47 -38
  325. package/library/skills/ui-graphics/resource.yaml +1 -1
  326. package/library/skills/use-widget-asset/SKILL.md +1 -1
  327. package/library/skills/use-widget-asset/resource.yaml +1 -1
  328. package/library/skills/using-summer/SKILL.md +7 -5
  329. package/library/skills/using-summer/resource.yaml +1 -1
  330. package/library/skills/vehicle-model/SKILL.md +65 -57
  331. package/library/skills/vehicle-model/resource.yaml +1 -1
  332. package/library/skills/verification-before-completion/SKILL.md +1 -1
  333. package/library/skills/verification-before-completion/resource.yaml +1 -1
  334. package/library/skills/verifying-scenes/SKILL.md +2 -2
  335. package/library/skills/verifying-scenes/resource.yaml +1 -1
  336. package/library/skills/vfx-dissolve/SKILL.md +2 -2
  337. package/library/skills/vfx-dissolve/resource.yaml +1 -1
  338. package/library/skills/vfx-fire/SKILL.md +15 -41
  339. package/library/skills/vfx-fire/resource.yaml +1 -1
  340. package/library/skills/vfx-hit-spark/SKILL.md +1 -1
  341. package/library/skills/vfx-hit-spark/resource.yaml +1 -1
  342. package/library/skills/vfx-lightning/SKILL.md +7 -16
  343. package/library/skills/vfx-lightning/resource.yaml +1 -1
  344. package/library/skills/vfx-magic-glow/SKILL.md +23 -32
  345. package/library/skills/vfx-magic-glow/resource.yaml +1 -1
  346. package/library/skills/vfx-muzzle-flash/SKILL.md +20 -35
  347. package/library/skills/vfx-muzzle-flash/resource.yaml +1 -1
  348. package/library/skills/vfx-smoke/SKILL.md +13 -31
  349. package/library/skills/vfx-smoke/resource.yaml +1 -1
  350. package/library/skills/vfx-water-ripple/SKILL.md +12 -31
  351. package/library/skills/vfx-water-ripple/resource.yaml +1 -1
  352. package/library/skills/voice-line/SKILL.md +71 -40
  353. package/library/skills/voice-line/resource.yaml +1 -1
  354. package/library/skills/web-and-touch-input/SKILL.md +1 -1
  355. package/library/skills/web-and-touch-input/resource.yaml +1 -1
  356. package/library/skills/web-compatibility-look/SKILL.md +1 -1
  357. package/library/skills/web-compatibility-look/resource.yaml +1 -1
  358. package/library/skills/world-building-3d/SKILL.md +1 -1
  359. package/library/skills/world-building-3d/resource.yaml +1 -1
  360. package/library/skills/writing-skills/resource.yaml +1 -0
  361. package/library/tools/add-node/GUIDE.md +14 -0
  362. package/library/tools/align-distribute-3d/GUIDE.md +7 -0
  363. package/library/tools/app-call/resource.yaml +59 -0
  364. package/library/tools/app-create/resource.yaml +67 -0
  365. package/library/tools/app-data/resource.yaml +74 -0
  366. package/library/tools/app-dock/resource.yaml +59 -0
  367. package/library/tools/app-events/resource.yaml +68 -0
  368. package/library/tools/app-get/resource.yaml +46 -0
  369. package/library/tools/app-guide/resource.yaml +55 -0
  370. package/library/tools/app-list/resource.yaml +48 -0
  371. package/library/tools/app-page/resource.yaml +74 -0
  372. package/library/tools/app-publish/resource.yaml +90 -0
  373. package/library/tools/app-report-gap/resource.yaml +58 -0
  374. package/library/tools/app-screenshot/resource.yaml +103 -0
  375. package/library/tools/app-tools/resource.yaml +46 -0
  376. package/library/tools/app-update/resource.yaml +68 -0
  377. package/library/tools/attach-to-surface/GUIDE.md +15 -0
  378. package/library/tools/batch/GUIDE.md +27 -0
  379. package/library/tools/camera-bookmark/GUIDE.md +12 -0
  380. package/library/tools/capture-gameplay/GUIDE.md +3 -0
  381. package/library/tools/capture-gameplay/resource.yaml +3 -3
  382. package/library/tools/check-job/resource.yaml +1 -1
  383. package/library/tools/clear-console/GUIDE.md +3 -0
  384. package/library/tools/connect-ports/GUIDE.md +9 -0
  385. package/library/tools/connect-signal/GUIDE.md +14 -0
  386. package/library/tools/create-debug-report/GUIDE.md +10 -0
  387. package/library/tools/create-scene/GUIDE.md +10 -0
  388. package/library/tools/debug-views/GUIDE.md +7 -0
  389. package/library/tools/enable-plugin/GUIDE.md +3 -0
  390. package/library/tools/enable-plugin/resource.yaml +53 -0
  391. package/library/tools/export-game/GUIDE.md +3 -0
  392. package/library/tools/export-game/resource.yaml +3 -3
  393. package/library/tools/export-templates/GUIDE.md +3 -0
  394. package/library/tools/fabricate-3d/GUIDE.md +19 -0
  395. package/library/tools/frame-nodes/GUIDE.md +9 -0
  396. package/library/tools/frame-shot/GUIDE.md +9 -0
  397. package/library/tools/game-control/GUIDE.md +9 -0
  398. package/library/tools/game-input/GUIDE.md +9 -0
  399. package/library/tools/game-probe/GUIDE.md +9 -0
  400. package/library/tools/generate-3d/resource.yaml +3 -3
  401. package/library/tools/generate-motion/resource.yaml +2 -2
  402. package/library/tools/get-console/GUIDE.md +9 -0
  403. package/library/tools/get-console/resource.yaml +5 -0
  404. package/library/tools/get-debugger-errors/GUIDE.md +7 -0
  405. package/library/tools/get-debugger-errors/resource.yaml +5 -0
  406. package/library/tools/get-debugger-warnings/GUIDE.md +7 -0
  407. package/library/tools/get-debugger-warnings/resource.yaml +5 -0
  408. package/library/tools/get-diagnostics/GUIDE.md +13 -0
  409. package/library/tools/get-project-context/GUIDE.md +25 -0
  410. package/library/tools/get-runtime-tree/GUIDE.md +7 -0
  411. package/library/tools/get-runtime-tree/resource.yaml +5 -0
  412. package/library/tools/get-scene-tree/GUIDE.md +11 -0
  413. package/library/tools/get-scene-tree/resource.yaml +5 -0
  414. package/library/tools/get-script-errors/GUIDE.md +5 -0
  415. package/library/tools/grep/GUIDE.md +11 -0
  416. package/library/tools/import-asset/GUIDE.md +8 -0
  417. package/library/tools/import-asset-by-id/GUIDE.md +12 -0
  418. package/library/tools/import-from-url/GUIDE.md +10 -0
  419. package/library/tools/import-from-url-batch/GUIDE.md +3 -0
  420. package/library/tools/import-hdri/GUIDE.md +16 -0
  421. package/library/tools/input-map-bind/GUIDE.md +11 -0
  422. package/library/tools/inspect-asset/GUIDE.md +14 -0
  423. package/library/tools/inspect-asset/resource.yaml +5 -0
  424. package/library/tools/inspect-node/GUIDE.md +11 -0
  425. package/library/tools/inspect-node/resource.yaml +5 -0
  426. package/library/tools/inspect-resource/GUIDE.md +7 -0
  427. package/library/tools/inspect-resource/resource.yaml +5 -0
  428. package/library/tools/inspect-runtime-node/GUIDE.md +7 -0
  429. package/library/tools/inspect-runtime-node/resource.yaml +5 -0
  430. package/library/tools/instantiate-scene/GUIDE.md +12 -0
  431. package/library/tools/is-running/GUIDE.md +3 -0
  432. package/library/tools/measure/GUIDE.md +8 -0
  433. package/library/tools/navigation-probe/GUIDE.md +9 -0
  434. package/library/tools/open/resource.yaml +2 -2
  435. package/library/tools/open-main-scene/GUIDE.md +6 -0
  436. package/library/tools/open-scene/GUIDE.md +8 -0
  437. package/library/tools/place-adjacent/GUIDE.md +7 -0
  438. package/library/tools/play/GUIDE.md +13 -0
  439. package/library/tools/project-setting/GUIDE.md +9 -0
  440. package/library/tools/publish-build/resource.yaml +6 -6
  441. package/library/tools/raycast/GUIDE.md +7 -0
  442. package/library/tools/read-file/GUIDE.md +10 -0
  443. package/library/tools/read-library/resource.yaml +5 -0
  444. package/library/tools/recent-events/GUIDE.md +7 -0
  445. package/library/tools/remove-node/GUIDE.md +3 -0
  446. package/library/tools/repeat-along/GUIDE.md +5 -0
  447. package/library/tools/replace-node/GUIDE.md +9 -0
  448. package/library/tools/replace-text/GUIDE.md +5 -0
  449. package/library/tools/run-editor-script/GUIDE.md +16 -0
  450. package/library/tools/run-script/GUIDE.md +30 -0
  451. package/library/tools/run-script/resource.yaml +6 -3
  452. package/library/tools/runtime-animate/GUIDE.md +7 -0
  453. package/library/tools/runtime-call/GUIDE.md +7 -0
  454. package/library/tools/runtime-set/GUIDE.md +9 -0
  455. package/library/tools/runtime-spawn/GUIDE.md +9 -0
  456. package/library/tools/save-scene/GUIDE.md +3 -0
  457. package/library/tools/scene-audit/GUIDE.md +29 -0
  458. package/library/tools/screenshot/GUIDE.md +17 -0
  459. package/library/tools/select-node/GUIDE.md +3 -0
  460. package/library/tools/set-prop/GUIDE.md +23 -0
  461. package/library/tools/set-resource-property/GUIDE.md +8 -0
  462. package/library/tools/shot-sheet/GUIDE.md +7 -0
  463. package/library/tools/snap-to-surface/GUIDE.md +17 -0
  464. package/library/tools/snapshot-diff/GUIDE.md +7 -0
  465. package/library/tools/starcast/GUIDE.md +12 -0
  466. package/library/tools/stop/GUIDE.md +3 -0
  467. package/library/tools/test-placement/GUIDE.md +7 -0
  468. package/library/tools/ui-actions/GUIDE.md +12 -0
  469. package/library/tools/ui-activate/GUIDE.md +11 -0
  470. package/library/tools/ui-screenshot/GUIDE.md +9 -0
  471. package/library/tools/ui-tree/GUIDE.md +10 -0
  472. package/library/tools/wait-for-event/GUIDE.md +11 -0
  473. package/library/tools/world-snapshot/GUIDE.md +9 -0
  474. package/library/tools/write-file/GUIDE.md +5 -0
  475. package/library/tools/zoom/GUIDE.md +5 -0
  476. package/package.json +6 -4
  477. package/registry/generated/aliases.json +15 -0
  478. package/registry/generated/counts.json +3 -3
  479. package/registry/generated/gemini-extension.json +6 -12
  480. package/registry/generated/index.json +1155 -408
  481. package/registry/generated/marketplace.claude.json +2 -13
  482. package/registry/generated/plugin.claude.json +25 -22
  483. package/registry/generated/plugin.codex.json +8 -14
  484. package/registry/generated/plugin.cursor.json +7 -13
  485. package/registry/generated/plugin.factory.json +7 -13
  486. package/registry/generated/server.json +34 -0
  487. package/registry/generated/skills-index.md +126 -116
  488. package/registry/generated/skills-registry.json +178 -113
  489. package/registry/operations/fixtures/invalid-deprecated-without-replacement.json +60 -0
  490. package/registry/operations/fixtures/invalid-name.json +60 -0
  491. package/registry/operations/fixtures/invalid-publish-without-owner.json +82 -0
  492. package/registry/operations/fixtures/invalid-spend-without-estimate.json +42 -0
  493. package/registry/operations/fixtures/invalid-unknown-field.json +61 -0
  494. package/registry/operations/fixtures/valid-player-facing.json +82 -0
  495. package/registry/operations/fixtures/valid-read.json +60 -0
  496. package/registry/operations/fixtures/valid-spend.json +43 -0
  497. package/registry/operations/legacy-names.json +1206 -0
  498. package/registry/schemas/allowed-hosts.json +4 -2
  499. package/registry/schemas/operation.schema.json +318 -0
  500. package/registry/schemas/skill.schema.json +4 -0
  501. package/CLAUDE.md +0 -7
@@ -0,0 +1,317 @@
1
+ import { z } from "zod";
2
+ import { loadLibraryIndex } from "../core/library-search.js";
3
+ import { PROFILES, TOOLSETS, parseProfile } from "../core/tool-profiles.js";
4
+ /**
5
+ * The shape of the MCP tool surface: which toolset each tool belongs to, each
6
+ * local tool's annotations, which results are capped, and which calls count
7
+ * as single scene edits. Read by server.ts (registration, results) and, with
8
+ * the profiles in core/tool-profiles.ts, by hosted-mount.ts (which hosted
9
+ * tools a profile mounts).
10
+ *
11
+ * Tool names never change here: a profile only leaves tools out.
12
+ */
13
+ export { TOOLSETS, PROFILES, PROFILE_TOOL_LIMIT } from "../core/tool-profiles.js";
14
+ const LOCAL_TOOLSETS = {
15
+ core: [
16
+ "summer_search_library",
17
+ "summer_read_library",
18
+ "summer_library_feedback",
19
+ "summer_get_agent_playbook",
20
+ "summer_start_game_task",
21
+ "summer_open",
22
+ ],
23
+ assets: [
24
+ "summer_generate_3d",
25
+ "summer_generate_audio",
26
+ "summer_generate_image",
27
+ "summer_generate_motion",
28
+ "summer_generate_sfx_choices",
29
+ "summer_generate_video",
30
+ "summer_check_job",
31
+ "summer_get_choices",
32
+ "summer_slice_asset_sheet",
33
+ "summer_get_studio_workflow",
34
+ "summer_search_assets",
35
+ "summer_list_my_assets",
36
+ "summer_get_asset",
37
+ "summer_get_asset_download_url",
38
+ ],
39
+ ship: ["summer_export_game", "summer_export_templates", "summer_publish_build", "summer_capture_gameplay"],
40
+ ui: ["summer_ui_actions", "summer_ui_activate", "summer_ui_screenshot", "summer_ui_tree"],
41
+ };
42
+ const localToolset = new Map(Object.entries(LOCAL_TOOLSETS).flatMap(([set, names]) => names.map((name) => [name, set])));
43
+ /** Hosted tool names by pattern, first match wins. Unknown names land in `other` (full only). */
44
+ const HOSTED_TOOLSETS = [
45
+ [/^summer_(account|team)$/, "core"],
46
+ [/^summer_(remove_background|update_asset|delete_asset|upload_image_\w+)$/, "assets"],
47
+ [/^summer_tool_\w+$/, "tools"],
48
+ [/^summer_(store_version_(begin_upload|sign_parts|complete)|build_(begin_upload|sign_parts|complete_upload))$/, "uploads"],
49
+ [/^summer_(store_\w+|list_games)$/, "ship"],
50
+ [/^summer_board_\w+$/, "board"],
51
+ [/^summer_grow_\w+$/, "grow"],
52
+ [/^summer_studio_\w+$/, "studio"],
53
+ [/^summer_app_\w+$/, "apps"],
54
+ [/^summer_(build_\w+|make_game|game|game_\w+|list_projects|get_project)$/, "cloud"],
55
+ ];
56
+ /** The toolset a tool belongs to: local tools by the table above, hosted ones by name. */
57
+ export function toolsetOf(name, local) {
58
+ if (local) {
59
+ if (localToolset.has(name))
60
+ return localToolset.get(name);
61
+ return name.startsWith("summer_app_") ? "apps" : "engine";
62
+ }
63
+ if (localToolset.has(name))
64
+ return localToolset.get(name);
65
+ return HOSTED_TOOLSETS.find(([pattern]) => pattern.test(name))?.[1] ?? "other";
66
+ }
67
+ const splitList = (value) => (value ?? "")
68
+ .split(",")
69
+ .map((part) => part.trim().toLowerCase())
70
+ .filter(Boolean);
71
+ /**
72
+ * `summer mcp --profile <p> --toolsets <a,b>` (env SUMMER_PROFILE,
73
+ * SUMMER_TOOLSETS). Without either: the full profile. `--toolsets` alone
74
+ * selects those toolsets plus core; with a profile it adds to it. `all` is
75
+ * every toolset. Unknown names are ignored and reported, never fatal: a
76
+ * typo must not stop an agent's MCP server from starting.
77
+ */
78
+ export function resolveToolSelection(options = {}, env = process.env) {
79
+ const ignored = [];
80
+ const profileName = (options.profile ?? env.SUMMER_PROFILE ?? "").trim().toLowerCase();
81
+ const requested = splitList(options.toolsets ?? env.SUMMER_TOOLSETS);
82
+ const profile = parseProfile(profileName);
83
+ if (profileName && !profile)
84
+ ignored.push(profileName);
85
+ const extra = new Set();
86
+ let all = false;
87
+ for (const name of requested) {
88
+ if (name === "all")
89
+ all = true;
90
+ else if (TOOLSETS.includes(name))
91
+ extra.add(name);
92
+ else
93
+ ignored.push(name);
94
+ }
95
+ if (all || profile === "full" || (profile === null && extra.size === 0)) {
96
+ return { profile: "full", toolsets: null, ignored };
97
+ }
98
+ if (profile === null)
99
+ return { profile: "custom", toolsets: new Set(["core", ...extra]), ignored };
100
+ return { profile, toolsets: new Set([...PROFILES[profile], ...extra]), ignored };
101
+ }
102
+ /** True when the selection keeps this tool. */
103
+ export function selectionIncludes(selection, name, local) {
104
+ return selection.toolsets === null || selection.toolsets.has(toolsetOf(name, local));
105
+ }
106
+ // ── Annotations ──────────────────────────────────────────────────────────────
107
+ /**
108
+ * Local tools carry the registry's five `authority` booleans
109
+ * (library/tools/<slug>/resource.yaml). They say what a tool may touch, not
110
+ * whether it only reads, so a few sets refine them; the result is the MCP
111
+ * effect hints clients use for approvals.
112
+ */
113
+ /** Tools whose only file output is an image or render for the agent; they never change the game. */
114
+ const EVIDENCE_ONLY = new Set([
115
+ "summer_screenshot",
116
+ "summer_debug_views",
117
+ "summer_shot_sheet",
118
+ "summer_zoom",
119
+ "summer_scene_audit",
120
+ "summer_game_probe",
121
+ "summer_capture_gameplay",
122
+ "summer_app_screenshot",
123
+ ]);
124
+ /** Generation on Summer's servers: costs credits, creates new assets. */
125
+ const SPENDS_CREDITS = new Set([
126
+ "summer_generate_3d",
127
+ "summer_generate_audio",
128
+ "summer_generate_image",
129
+ "summer_generate_motion",
130
+ "summer_generate_sfx_choices",
131
+ "summer_generate_video",
132
+ ]);
133
+ /** Network-only tools that change the person's Summer data (the rest of the network tools read). */
134
+ const NETWORK_WRITES = new Set([
135
+ "summer_app_create",
136
+ "summer_app_data",
137
+ "summer_app_page",
138
+ "summer_app_call",
139
+ "summer_app_report_gap",
140
+ "summer_app_update",
141
+ "summer_slice_asset_sheet",
142
+ ]);
143
+ /** Changes that only add something new, or only touch the editor view or the running game. */
144
+ const ADDITIVE_OR_TRANSIENT = new Set([
145
+ "summer_add_node",
146
+ "summer_create_scene",
147
+ "summer_instantiate_scene",
148
+ "summer_connect_signal",
149
+ "summer_input_map_bind",
150
+ "summer_import_asset",
151
+ "summer_import_asset_by_id",
152
+ "summer_import_from_url",
153
+ "summer_import_from_url_batch",
154
+ "summer_import_hdri",
155
+ "summer_repeat_along",
156
+ "summer_fabricate_3d",
157
+ "summer_frame_nodes",
158
+ "summer_frame_shot",
159
+ "summer_save_scene",
160
+ "summer_enable_plugin",
161
+ "summer_export_game",
162
+ "summer_export_templates",
163
+ "summer_create_debug_report",
164
+ "summer_library_feedback",
165
+ "summer_app_create",
166
+ "summer_app_report_gap",
167
+ "summer_app_dock",
168
+ "summer_slice_asset_sheet",
169
+ "summer_open_scene",
170
+ "summer_open_main_scene",
171
+ "summer_select_node",
172
+ "summer_clear_console",
173
+ "summer_play",
174
+ "summer_stop",
175
+ "summer_game_control",
176
+ "summer_game_input",
177
+ "summer_runtime_animate",
178
+ "summer_runtime_call",
179
+ "summer_runtime_set",
180
+ "summer_runtime_spawn",
181
+ ]);
182
+ /** Changes where a second identical call has no further effect. */
183
+ const IDEMPOTENT_WRITES = new Set([
184
+ "summer_set_prop",
185
+ "summer_set_resource_property",
186
+ "summer_project_setting",
187
+ "summer_remove_node",
188
+ "summer_write_file",
189
+ "summer_create_scene",
190
+ "summer_save_scene",
191
+ "summer_open_scene",
192
+ "summer_open_main_scene",
193
+ "summer_select_node",
194
+ "summer_clear_console",
195
+ "summer_stop",
196
+ "summer_enable_plugin",
197
+ "summer_place_adjacent",
198
+ "summer_attach_to_surface",
199
+ "summer_connect_ports",
200
+ "summer_align_distribute_3d",
201
+ "summer_snap_to_surface",
202
+ "summer_camera_bookmark",
203
+ "summer_frame_nodes",
204
+ "summer_runtime_set",
205
+ "summer_export_game",
206
+ "summer_export_templates",
207
+ "summer_app_update",
208
+ "summer_app_dock",
209
+ ]);
210
+ /** Every name the refinement sets mention (a test checks each is a real tool). */
211
+ export const ANNOTATION_REFINEMENTS = new Set([
212
+ ...EVIDENCE_ONLY,
213
+ ...SPENDS_CREDITS,
214
+ ...NETWORK_WRITES,
215
+ ...ADDITIVE_OR_TRANSIENT,
216
+ ...IDEMPOTENT_WRITES,
217
+ ]);
218
+ /** MCP annotations for one local tool from its registry authority. */
219
+ export function annotationsFor(name, authority) {
220
+ const openWorldHint = Boolean(authority.network || authority.publish);
221
+ if (authority.publish) {
222
+ return { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true };
223
+ }
224
+ if (SPENDS_CREDITS.has(name)) {
225
+ return { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
226
+ }
227
+ const writes = !EVIDENCE_ONLY.has(name) &&
228
+ Boolean(authority.filesystem || authority.editor_mutation || authority.credentials || NETWORK_WRITES.has(name));
229
+ if (!writes) {
230
+ return { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint };
231
+ }
232
+ return {
233
+ readOnlyHint: false,
234
+ destructiveHint: !ADDITIVE_OR_TRANSIENT.has(name),
235
+ idempotentHint: IDEMPOTENT_WRITES.has(name),
236
+ openWorldHint,
237
+ };
238
+ }
239
+ let authorityCache = null;
240
+ /** Registry authority per MCP tool name (registry/generated/index.json). */
241
+ export function registryAuthorities() {
242
+ if (authorityCache)
243
+ return authorityCache;
244
+ const map = new Map();
245
+ try {
246
+ for (const entry of loadLibraryIndex()) {
247
+ if (entry.kind === "tool" && entry.mcp_tool_name && entry.authority)
248
+ map.set(entry.mcp_tool_name, entry.authority);
249
+ }
250
+ }
251
+ catch {
252
+ // A broken install still serves tools; they go out without annotations.
253
+ }
254
+ authorityCache = map;
255
+ return map;
256
+ }
257
+ // ── Output caps ──────────────────────────────────────────────────────────────
258
+ /** Default text cap for tools whose results can be large. */
259
+ export const DEFAULT_MAX_CHARACTERS = 4_000;
260
+ /**
261
+ * Tools whose text results are capped by default, with their default cap.
262
+ * Scene and runtime trees, console and debugger reads, inspect reads and
263
+ * library reads. The scene tree and library reads get more room: a median
264
+ * skill is about 12K characters, and cutting every skill read would double
265
+ * the core search-then-read loop. Writes, job ids and file reads are never
266
+ * capped.
267
+ */
268
+ export const OUTPUT_CAPS = new Map([
269
+ ["summer_get_scene_tree", 8_000],
270
+ ["summer_get_runtime_tree", DEFAULT_MAX_CHARACTERS],
271
+ ["summer_get_console", DEFAULT_MAX_CHARACTERS],
272
+ ["summer_get_debugger_errors", DEFAULT_MAX_CHARACTERS],
273
+ ["summer_get_debugger_warnings", DEFAULT_MAX_CHARACTERS],
274
+ ["summer_inspect_node", DEFAULT_MAX_CHARACTERS],
275
+ ["summer_inspect_resource", DEFAULT_MAX_CHARACTERS],
276
+ ["summer_inspect_runtime_node", DEFAULT_MAX_CHARACTERS],
277
+ ["summer_inspect_asset", DEFAULT_MAX_CHARACTERS],
278
+ ["summer_read_library", 24_000],
279
+ ]);
280
+ /**
281
+ * A capped tool's input shape plus `maxCharacters`. server.ts adds it at
282
+ * registration and strips it before the handler runs; the descriptor parity
283
+ * test applies the same function, so library/tools/<slug>/resource.yaml
284
+ * lists the argument too.
285
+ */
286
+ export function withMaxCharactersArg(name, shape) {
287
+ const cap = OUTPUT_CAPS.get(name);
288
+ if (cap === undefined || "maxCharacters" in shape)
289
+ return shape;
290
+ return {
291
+ ...shape,
292
+ maxCharacters: z
293
+ .number()
294
+ .int()
295
+ .min(500)
296
+ .max(1_000_000)
297
+ .optional()
298
+ .describe(`Most characters of text to return (default ${cap}). A longer result is cut and says so.`),
299
+ };
300
+ }
301
+ // ── Single scene edits ───────────────────────────────────────────────────────
302
+ /** One-change scene tools; a run of them is one summer_run_script. */
303
+ export const SINGLE_EDIT_TOOLS = new Set([
304
+ "summer_set_prop",
305
+ "summer_add_node",
306
+ "summer_remove_node",
307
+ "summer_set_resource_property",
308
+ "summer_instantiate_scene",
309
+ "summer_connect_signal",
310
+ "summer_replace_node",
311
+ ]);
312
+ /** Calls that already batch edits; they end a run of single edits. */
313
+ export const BATCH_EDIT_TOOLS = new Set([
314
+ "summer_run_script",
315
+ "summer_batch",
316
+ "summer_run_editor_script",
317
+ ]);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerAppTools(server: McpServer): void;
@@ -0,0 +1,71 @@
1
+ import { MAX_APP_EVENTS_WAIT_SECONDS, APP_DOCK_FALLBACK, appCall, appCallArgsSchema, appCreate, appCreateArgsSchema, appData, appDataArgsSchema, appDockArgsSchema, appDockOp, appEvents, appEventsArgsSchema, appGet, appGetArgsSchema, appGuide, appGuideArgsSchema, appList, appListArgsSchema, appPage, appPageArgsSchema, appPublish, appPublishArgsSchema, appReportGap, appReportGapArgsSchema, appScreenshot, appScreenshotArgsSchema, appUpdate, appUpdateArgsSchema, appsGateway, appTools, appToolsArgsSchema, } from "../../core/capabilities/apps.js";
2
+ import { enablePluginArgsSchema, enablePluginOp, interpretEnablePluginResult } from "../../core/capabilities/enable-plugin.js";
3
+ import { missingEngineOpResult, withEngine } from "./with-engine.js";
4
+ /**
5
+ * Summer Apps over MCP: tools a game team uses inside Summer Studio, built by
6
+ * the agent. Shared implementation: core/capabilities/apps.ts.
7
+ */
8
+ const CLOUD = "Cloud tool: runs on Summer's servers and works without the Summer Engine app open. Requires sign-in: npx -y summer-engine@latest login.";
9
+ function result(value) {
10
+ return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }], ...(value.ok === false ? { isError: true } : {}) };
11
+ }
12
+ /** The MCP handler of one cloud tool: validate with the shared schema, call the web API. */
13
+ function cloud(name, schema, run) {
14
+ return async (args) => {
15
+ const parsed = schema.safeParse(args ?? {});
16
+ if (!parsed.success)
17
+ return result({ ok: false, code: "invalid", error: parsed.error.issues[0]?.message ?? "Invalid arguments" });
18
+ return result(await run(parsed.data, { request: appsGateway("mcp", name) }));
19
+ };
20
+ }
21
+ export function registerAppTools(server) {
22
+ server.tool("summer_app_guide", `Read this before building or changing a Summer App (a tool for the person's team inside Summer Studio). Start with the default section overview (when to build one, Layout vs code, the build loop, the rules), then read what the app needs: examples (a complete working app to copy), sdk, manifest, kit, design, layout, types (exact SDK TypeScript types).\n\n${CLOUD}`, appGuideArgsSchema.shape, async (args) => {
23
+ const parsed = appGuideArgsSchema.safeParse(args ?? {});
24
+ if (!parsed.success)
25
+ return result({ ok: false, code: "invalid", error: parsed.error.issues[0]?.message ?? "Invalid arguments" });
26
+ const guide = await appGuide(parsed.data, { request: appsGateway("mcp", "summer_app_guide") });
27
+ // The guide reads as Markdown, not as one escaped JSON line.
28
+ return guide.ok === true && typeof guide.markdown === "string" ? { content: [{ type: "text", text: guide.markdown }] } : result(guide);
29
+ });
30
+ server.tool("summer_app_list", `The Summer Apps in the person's workspaces: id, name, purpose, folder, status (scratch, kept, archived), version, format.\n\n${CLOUD}`, appListArgsSchema.shape, cloud("summer_app_list", appListArgsSchema, appList));
31
+ server.tool("summer_app_create", `Create a new scratch Summer App; their open Summer Studio tab opens it. Without workspaceId it goes to the person's team (the one their Studio tab is on, else their latest team, else personal); the result's workspace says which: tell the person. Read summer_app_guide first. format code (index.html + JS/CSS) or layout (a JSON layout of kit nodes for a quick decision UI). Then summer_app_publish.\n\n${CLOUD}`, appCreateArgsSchema.shape, cloud("summer_app_create", appCreateArgsSchema, appCreate));
32
+ server.tool("summer_app_publish", `Publish a new immutable version of a Summer App: dir (a local folder with index.html at its root) or files [{path, content, encoding}] for code apps, layout for layout apps, plus the manifest. Limits: 10 MB, 300 files, 5 MB per file. The person's Studio tab boots it. An error names the file or rule to fix: fix it and publish again.\n\n${CLOUD}`, appPublishArgsSchema.shape, cloud("summer_app_publish", appPublishArgsSchema, appPublish));
33
+ server.tool("summer_app_get", `A Summer App's manifest, its current version's files (or layout) and a summary of its shared data. Use it before changing an app.\n\n${CLOUD}`, appGetArgsSchema.shape, cloud("summer_app_get", appGetArgsSchema, appGet));
34
+ server.tool("summer_app_update", `Rename a Summer App, change its purpose or folder, or set its status: kept (the team keeps it), archived (hidden from the app list; restore with scratch or kept), scratch. Archive the scratch apps you made that the person did not keep.\n\n${CLOUD}`, appUpdateArgsSchema.shape, cloud("summer_app_update", appUpdateArgsSchema, appUpdate));
35
+ server.tool("summer_app_events", `Wait for what a Summer App sends you: summer.agent.send events (kind agent), errors in the app (kind error), feedback (kind feedback), agent tool calls (kind tool). Waits up to timeoutSeconds (max ${MAX_APP_EVENTS_WAIT_SECONDS}) for the first event after the cursor; pass the returned cursor as after next time.\n\n${CLOUD}`, appEventsArgsSchema.shape, cloud("summer_app_events", appEventsArgsSchema, appEvents));
36
+ server.tool("summer_app_page", `Read or use the fields and buttons a Summer App declared while it is open in the person's Studio tab or editor dock: no fill and no press reads the page; fill [{field, value}] and press an action id use it. Critical actions (delete, publish, pay, send) are pressed only by the person. app_not_open when the app is not open.\n\n${CLOUD}`, appPageArgsSchema.shape, cloud("summer_app_page", appPageArgsSchema, appPage));
37
+ server.tool("summer_app_screenshot", `See a Summer App without the person: Summer renders its current version (or version) headless with the person's data and returns the picture plus what to fix: console lines, uncaught errors, refused calls, whether the SDK connected and rendered, and the fields, buttons and agent tools it declared. Read-only: writes, sends and paid calls are refused, nothing changes. width 390 for a phone, theme dark, fullPage for the whole scroll, steps to click or press something first (a dialog, a second state); out also saves the PNG. It waits until the app's calls settle. Use it after every publish.\n\n${CLOUD}`, appScreenshotArgsSchema.shape, async (args) => {
38
+ const parsed = appScreenshotArgsSchema.safeParse(args ?? {});
39
+ if (!parsed.success)
40
+ return result({ ok: false, code: "invalid", error: parsed.error.issues[0]?.message ?? "Invalid arguments" });
41
+ const shot = await appScreenshot(parsed.data, { request: appsGateway("mcp", "summer_app_screenshot") });
42
+ if (shot.ok !== true || !("image" in shot))
43
+ return result(shot);
44
+ const { image, ...report } = shot;
45
+ return { content: [{ type: "image", data: image.base64, mimeType: image.mimeType }, { type: "text", text: JSON.stringify(report, null, 2) }] };
46
+ });
47
+ server.tool("summer_app_data", `Read or write a Summer App's shared data, its API: works with no app open, and everyone in the app sees writes live. Without ops it reads records (paged with after) plus declaredCollections, the record shape the app declares; with ops it writes them in one revision: {op: put|patch|remove, collection, recordId, data|patch, ifRevision?}. Writes show as yours (actor kind agent); as: seed writes starter data for the team (kind seed, no author).\n\n${CLOUD}`, appDataArgsSchema.shape, cloud("summer_app_data", appDataArgsSchema, appData));
48
+ server.tool("summer_app_tools", `The agent tools (name, description, input JSON Schema) and the data collections (record fields and types) a Summer App declares. Run a tool with summer_app_call; read or write the collections with summer_app_data.\n\n${CLOUD}`, appToolsArgsSchema.shape, cloud("summer_app_tools", appToolsArgsSchema, appTools));
49
+ server.tool("summer_app_call", `Run one of a Summer App's agent tools inside the person's open app (Studio tab or editor dock) with their rights; waits up to 60 s. app_not_open when the app is not open: use summer_app_data or ask the person to open it. May spend the person's credits when the tool generates.\n\n${CLOUD}`, appCallArgsSchema.shape, cloud("summer_app_call", appCallArgsSchema, appCall));
50
+ server.tool("summer_app_report_gap", `Tell Summer about an SDK capability a Summer App needed and did not have, so it can be built for everyone.\n\n${CLOUD}`, appReportGapArgsSchema.shape, cloud("summer_app_report_gap", appReportGapArgsSchema, appReportGap));
51
+ server.tool("summer_app_dock", `Dock a Summer App as a panel in the running Summer Engine editor (left, right or bottom), close its dock, or list docked apps. Docks persist per project. Engine builds without app docks return engine_lacks_op: open the app in the Summer Studio tab instead.`, appDockArgsSchema.shape, async (args) => {
52
+ const parsed = appDockArgsSchema.safeParse(args ?? {});
53
+ if (!parsed.success)
54
+ return result({ ok: false, code: "invalid", error: parsed.error.issues[0]?.message ?? "Invalid arguments" });
55
+ if (parsed.data.action !== "list" && !parsed.data.appId)
56
+ return result({ ok: false, code: "invalid", error: `${parsed.data.action} needs appId` });
57
+ const op = appDockOp(parsed.data);
58
+ return withEngine(async (client) => {
59
+ const missing = missingEngineOpResult(client, op.op, APP_DOCK_FALLBACK);
60
+ if (missing)
61
+ return missing;
62
+ return client.executeOps([op]);
63
+ });
64
+ });
65
+ server.tool("summer_enable_plugin", `Enable an editor plugin in the open project (res://addons/<name>/, for example one paired with a Summer App) and report the real result: enabled with the autoloads it registered, or why it failed (code SCRIPT_ERROR, NOT_TOOL, NOT_EDITOR_PLUGIN, CFG_MISSING, TIMEOUT, ...). Older Summer Engine builds only queue the enable; then the result says queued: true and enabled: null, and you check summer_get_debugger_errors before relying on the plugin.`, enablePluginArgsSchema.shape, async (args) => {
66
+ const parsed = enablePluginArgsSchema.safeParse(args ?? {});
67
+ if (!parsed.success)
68
+ return result({ ok: false, code: "invalid", error: parsed.error.issues[0]?.message ?? "Invalid arguments" });
69
+ return withEngine(async (client) => interpretEnablePluginResult(await client.executeOps([enablePluginOp(parsed.data)])));
70
+ });
71
+ }
@@ -4,14 +4,15 @@ import { resolveGatewayUrl } from "../../core/config.js";
4
4
  import { getClient } from "../server.js";
5
5
  import { ImportHdriError, importPolyHavenHdri, } from "../../core/capabilities/hdri-import.js";
6
6
  import { importResolvedAsset } from "../../core/capabilities/asset-import.js";
7
+ import { summerRequestHeaders } from "../../core/agent-host.js";
8
+ import { codedFailure, describeNetworkError, EngineNotRunningError, networkDetails, NOT_SIGNED_IN, SIGN_IN_AGAIN_RECOVERY, } from "../../core/error-codes.js";
9
+ import { engineNotRunningResult } from "./with-engine.js";
10
+ /** No Summer account token: the same failure for every asset tool. */
11
+ const notSignedIn = { error: "not_logged_in", message: NOT_SIGNED_IN, code: "not_signed_in" };
7
12
  async function searchAssetsApi(params) {
8
13
  const token = await getAuthToken();
9
- if (!token) {
10
- return {
11
- error: "Not logged in",
12
- message: "Not signed in. The user needs to run this in their terminal:\n npx -y summer-engine@latest login\nOr open: https://www.summerengine.com/login\nAsset search requires a Summer Engine account (free to create).",
13
- };
14
- }
14
+ if (!token)
15
+ return { ...notSignedIn };
15
16
  const searchParams = new URLSearchParams();
16
17
  searchParams.set("query", params.query);
17
18
  if (params.assetType && params.assetType !== "all") {
@@ -30,17 +31,24 @@ async function searchAssetsApi(params) {
30
31
  if (params.preview)
31
32
  searchParams.set("contactSheet", "true");
32
33
  const gatewayUrl = await resolveGatewayUrl();
33
- const res = await fetch(`${gatewayUrl}/api/mcp/assets?${searchParams}`, {
34
- headers: { Authorization: `Bearer ${token}` },
35
- signal: AbortSignal.timeout(15000),
36
- });
34
+ let res;
35
+ try {
36
+ res = await fetch(`${gatewayUrl}/api/mcp/assets?${searchParams}`, {
37
+ headers: { ...summerRequestHeaders({ surface: "mcp" }), Authorization: `Bearer ${token}` },
38
+ signal: AbortSignal.timeout(15000),
39
+ });
40
+ }
41
+ catch (err) {
42
+ return { error: "network_error", message: `Asset request failed: ${describeNetworkError(err)}`, code: "unavailable", ...networkDetails(err) };
43
+ }
37
44
  const data = (await res.json());
38
45
  if (!res.ok) {
39
46
  if (res.status === 401) {
40
47
  return {
41
48
  error: "unauthorized",
42
- message: (data.message || "Auth token expired.") +
43
- " The user needs to re-authenticate:\n npx -y summer-engine@latest login --force",
49
+ message: data.message || "Auth token expired.",
50
+ code: "not_signed_in",
51
+ recovery: SIGN_IN_AGAIN_RECOVERY,
44
52
  };
45
53
  }
46
54
  if (res.status === 429) {
@@ -59,18 +67,19 @@ async function searchAssetsApi(params) {
59
67
  }
60
68
  async function authedGetJson(endpoint, timeoutMs = 15_000) {
61
69
  const token = await getAuthToken();
62
- if (!token) {
63
- return {
64
- status: 401,
65
- error: "not_logged_in",
66
- message: "Not signed in. Run in your terminal:\n npx -y summer-engine@latest login",
67
- };
68
- }
70
+ if (!token)
71
+ return { status: 401, ...notSignedIn };
69
72
  const gatewayUrl = await resolveGatewayUrl();
70
- const res = await fetch(`${gatewayUrl}${endpoint}`, {
71
- headers: { Authorization: `Bearer ${token}` },
72
- signal: AbortSignal.timeout(timeoutMs),
73
- });
73
+ let res;
74
+ try {
75
+ res = await fetch(`${gatewayUrl}${endpoint}`, {
76
+ headers: { ...summerRequestHeaders({ surface: "mcp" }), Authorization: `Bearer ${token}` },
77
+ signal: AbortSignal.timeout(timeoutMs),
78
+ });
79
+ }
80
+ catch (err) {
81
+ return { status: 0, error: "network_error", message: `Asset request failed: ${describeNetworkError(err)}`, code: "unavailable", ...networkDetails(err) };
82
+ }
74
83
  const data = (await res.json());
75
84
  if (!res.ok) {
76
85
  return {
@@ -78,6 +87,7 @@ async function authedGetJson(endpoint, timeoutMs = 15_000) {
78
87
  data,
79
88
  error: data?.error || "request_failed",
80
89
  message: data?.message || "Request failed",
90
+ ...(res.status === 401 ? { code: "not_signed_in", recovery: SIGN_IN_AGAIN_RECOVERY } : {}),
81
91
  };
82
92
  }
83
93
  return { status: res.status, data };
@@ -85,14 +95,14 @@ async function authedGetJson(endpoint, timeoutMs = 15_000) {
85
95
  async function getAssetApi(assetId) {
86
96
  const result = await authedGetJson(`/api/mcp/assets/${encodeURIComponent(assetId)}`);
87
97
  if (result.error) {
88
- return { error: result.error, message: result.message };
98
+ return { error: result.error, message: result.message, code: result.code, recovery: result.recovery, details: result.details };
89
99
  }
90
100
  return { asset: result.data?.asset };
91
101
  }
92
102
  async function getAssetDownloadUrlApi(assetId, role) {
93
103
  const result = await authedGetJson(`/api/mcp/assets/${encodeURIComponent(assetId)}/download-url?role=${encodeURIComponent(role)}`);
94
104
  if (result.error) {
95
- return { error: result.error, message: result.message };
105
+ return { error: result.error, message: result.message, code: result.code, recovery: result.recovery, details: result.details };
96
106
  }
97
107
  return { data: result.data };
98
108
  }
@@ -106,6 +116,14 @@ function jsonSuccess(data) {
106
116
  ],
107
117
  };
108
118
  }
119
+ /** The body of a failed lookup: `{ok:false, code, error, recovery, message}`
120
+ * for the shared failures, else the older `{error, message}`. */
121
+ function failureBody(result, fallback) {
122
+ const message = result.message || fallback.message;
123
+ return result.code
124
+ ? codedFailure(result.code, message, { message, ...(result.details ? { details: result.details } : {}) }, result.recovery)
125
+ : { error: result.error || fallback.error, message };
126
+ }
109
127
  function jsonError(data) {
110
128
  return {
111
129
  content: [
@@ -146,15 +164,7 @@ Requires authentication (so we can attribute usage and apply per-user rate limit
146
164
  }, async ({ query, assetType, limit, source, style, preview, includeCommunity }) => {
147
165
  const result = await searchAssetsApi({ query, assetType, limit: Math.min(limit, 20), source, style, preview, includeCommunity });
148
166
  if (result.error) {
149
- return {
150
- content: [
151
- {
152
- type: "text",
153
- text: JSON.stringify({ error: result.error, message: result.message }, null, 2),
154
- },
155
- ],
156
- isError: true,
157
- };
167
+ return jsonError(failureBody(result, { error: "Search failed", message: "Asset search failed" }));
158
168
  }
159
169
  const sheet = result.contactSheet?.match(/^data:(image\/[a-z]+);base64,(.+)$/);
160
170
  return {
@@ -200,7 +210,7 @@ Cloud tool — works WITHOUT the Summer Engine app open.`, {
200
210
  source: "my_assets",
201
211
  });
202
212
  if (result.error) {
203
- return jsonError({ error: result.error, message: result.message });
213
+ return jsonError(failureBody(result, { error: "List failed", message: "Listing your assets failed" }));
204
214
  }
205
215
  return jsonSuccess({
206
216
  assets: result.assets,
@@ -220,10 +230,7 @@ Cloud tool — works WITHOUT the Summer Engine app open.`, {
220
230
  }, async ({ assetId }) => {
221
231
  const result = await getAssetApi(assetId);
222
232
  if (result.error || !result.asset) {
223
- return jsonError({
224
- error: result.error || "asset_not_found",
225
- message: result.message || "Asset not found.",
226
- });
233
+ return jsonError(failureBody(result, { error: "asset_not_found", message: "Asset not found." }));
227
234
  }
228
235
  return jsonSuccess({ asset: result.asset });
229
236
  });
@@ -242,7 +249,7 @@ Cloud tool — works WITHOUT the Summer Engine app open.`, {
242
249
  }, async ({ assetId, role }) => {
243
250
  const result = await getAssetDownloadUrlApi(assetId, role);
244
251
  if (result.error) {
245
- return jsonError({ error: result.error, message: result.message });
252
+ return jsonError(failureBody(result, { error: "request_failed", message: "Request failed" }));
246
253
  }
247
254
  return jsonSuccess(result.data);
248
255
  });
@@ -276,10 +283,7 @@ itself does not — only this import step does).`, {
276
283
  }, async ({ assetId, path, parent, scenePath, name }) => {
277
284
  const fetched = await getAssetApi(assetId);
278
285
  if (fetched.error || !fetched.asset) {
279
- return jsonError({
280
- error: fetched.error || "asset_not_found",
281
- message: fetched.message || "Asset not found.",
282
- });
286
+ return jsonError(failureBody(fetched, { error: "asset_not_found", message: "Asset not found." }));
283
287
  }
284
288
  try {
285
289
  const imported = await importResolvedAsset(await getClient(), {
@@ -297,6 +301,8 @@ itself does not — only this import step does).`, {
297
301
  });
298
302
  }
299
303
  catch (err) {
304
+ if (err instanceof EngineNotRunningError)
305
+ return engineNotRunningResult(err);
300
306
  const msg = err instanceof Error ? err.message : String(err);
301
307
  return jsonError({
302
308
  error: "import_failed",
@@ -319,15 +325,7 @@ Requires authentication. If the user gets an auth error, they need to run 'npx -
319
325
  }, async ({ query, parent, scenePath, assetType, source }) => {
320
326
  const searchResult = await searchAssetsApi({ query, assetType, limit: 5, source });
321
327
  if (searchResult.error) {
322
- return {
323
- content: [
324
- {
325
- type: "text",
326
- text: JSON.stringify({ error: searchResult.error, message: searchResult.message }, null, 2),
327
- },
328
- ],
329
- isError: true,
330
- };
328
+ return jsonError(failureBody(searchResult, { error: "Search failed", message: "Asset search failed" }));
331
329
  }
332
330
  const assets = searchResult.assets || [];
333
331
  if (assets.length === 0) {
@@ -378,6 +376,8 @@ Requires authentication. If the user gets an auth error, they need to run 'npx -
378
376
  };
379
377
  }
380
378
  catch (err) {
379
+ if (err instanceof EngineNotRunningError)
380
+ return engineNotRunningResult(err);
381
381
  const msg = err instanceof Error ? err.message : String(err);
382
382
  return {
383
383
  content: [
@@ -433,6 +433,8 @@ runs through the engine). No Summer login needed.`, {
433
433
  ...(err.hint ? { hint: err.hint } : {}),
434
434
  });
435
435
  }
436
+ if (err instanceof EngineNotRunningError)
437
+ return engineNotRunningResult(err);
436
438
  const msg = err instanceof Error ? err.message : String(err);
437
439
  return jsonError({
438
440
  error: "hdri_import_failed",