summer-engine 4.2.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +3 -1
  3. package/.codex-plugin/plugin.json +5 -3
  4. package/.cursor-plugin/plugin.json +4 -2
  5. package/.factory-plugin/plugin.json +4 -2
  6. package/AGENTS.md +2 -2
  7. package/CHANGELOG.md +98 -0
  8. package/README.md +67 -27
  9. package/commands/start.md +19 -15
  10. package/commands/summer.md +1 -0
  11. package/dist/cli/command-usage.d.ts +10 -0
  12. package/dist/cli/command-usage.js +28 -0
  13. package/dist/cli/commands/create.d.ts +1 -25
  14. package/dist/cli/commands/create.js +10 -138
  15. package/dist/cli/commands/dev.d.ts +66 -0
  16. package/dist/cli/commands/dev.js +234 -0
  17. package/dist/cli/commands/install.d.ts +15 -58
  18. package/dist/cli/commands/install.js +31 -481
  19. package/dist/cli/commands/login.js +2 -2
  20. package/dist/cli/commands/ops.d.ts +17 -1
  21. package/dist/cli/commands/ops.js +102 -9
  22. package/dist/cli/commands/preview.d.ts +58 -0
  23. package/dist/cli/commands/preview.js +181 -0
  24. package/dist/cli/commands/run.d.ts +1 -17
  25. package/dist/cli/commands/run.js +17 -206
  26. package/dist/cli/commands/tool.js +4 -0
  27. package/dist/cli/index.js +7 -0
  28. package/dist/core/agent-host.d.ts +6 -0
  29. package/dist/core/agent-host.js +9 -3
  30. package/dist/core/api-client.d.ts +10 -2
  31. package/dist/core/api-client.js +13 -8
  32. package/dist/core/capabilities/agent-playbook.js +1 -0
  33. package/dist/core/capabilities/apps.d.ts +9 -9
  34. package/dist/core/capabilities/asset-import.d.ts +4 -1
  35. package/dist/core/capabilities/asset-import.js +15 -6
  36. package/dist/core/capabilities/capture-gameplay.js +1 -1
  37. package/dist/core/capabilities/connect-signal.d.ts +2 -2
  38. package/dist/core/capabilities/content-make/index.d.ts +81 -0
  39. package/dist/core/capabilities/content-make/index.js +706 -0
  40. package/dist/core/capabilities/content-make/media.d.ts +57 -0
  41. package/dist/core/capabilities/content-make/media.js +172 -0
  42. package/dist/core/capabilities/content-make/plan.d.ts +130 -0
  43. package/dist/core/capabilities/content-make/plan.js +433 -0
  44. package/dist/core/capabilities/content-make/render.d.ts +64 -0
  45. package/dist/core/capabilities/content-make/render.js +370 -0
  46. package/dist/core/capabilities/content-make/study.d.ts +13 -0
  47. package/dist/core/capabilities/content-make/study.js +165 -0
  48. package/dist/core/capabilities/content-make/types.d.ts +173 -0
  49. package/dist/core/capabilities/content-make/types.js +6 -0
  50. package/dist/core/capabilities/content-make/voice.d.ts +7 -0
  51. package/dist/core/capabilities/content-make/voice.js +27 -0
  52. package/dist/core/capabilities/events.d.ts +2 -2
  53. package/dist/core/capabilities/export-game.d.ts +4 -1
  54. package/dist/core/capabilities/export-game.js +4 -3
  55. package/dist/core/capabilities/export-presets.d.ts +2 -1
  56. package/dist/core/capabilities/export-presets.js +2 -1
  57. package/dist/core/capabilities/go-live.d.ts +14 -0
  58. package/dist/core/capabilities/go-live.js +408 -0
  59. package/dist/core/capabilities/image-generation.d.ts +6 -6
  60. package/dist/core/capabilities/item-manifest.d.ts +92 -0
  61. package/dist/core/capabilities/item-manifest.js +247 -0
  62. package/dist/core/capabilities/placement.d.ts +7 -7
  63. package/dist/core/capabilities/projects-local.d.ts +68 -0
  64. package/dist/core/capabilities/projects-local.js +172 -0
  65. package/dist/core/capabilities/publish-build.d.ts +13 -2
  66. package/dist/core/capabilities/publish-build.js +87 -21
  67. package/dist/core/capabilities/publish-download.js +1 -1
  68. package/dist/core/capabilities/runtime-control.d.ts +7 -2
  69. package/dist/core/capabilities/runtime-control.js +27 -1
  70. package/dist/core/capabilities/seeing/args.d.ts +2 -2
  71. package/dist/core/capabilities/store-checks.d.ts +45 -0
  72. package/dist/core/capabilities/store-checks.js +85 -0
  73. package/dist/core/capabilities/store-details.d.ts +37 -0
  74. package/dist/core/capabilities/store-details.js +94 -0
  75. package/dist/core/capabilities/summer-bundle.d.ts +21 -2
  76. package/dist/core/capabilities/summer-bundle.js +54 -7
  77. package/dist/core/capabilities/sync-items.d.ts +89 -0
  78. package/dist/core/capabilities/sync-items.js +352 -0
  79. package/dist/core/capabilities/tool-dispatch.js +66 -6
  80. package/dist/core/capabilities/video-ogv.d.ts +49 -0
  81. package/dist/core/capabilities/video-ogv.js +260 -0
  82. package/dist/core/capability-skew.js +2 -2
  83. package/dist/core/cli-usage-beacon.d.ts +1 -0
  84. package/dist/core/cli-usage-beacon.js +42 -0
  85. package/dist/core/cli-usage.d.ts +52 -0
  86. package/dist/core/cli-usage.js +114 -0
  87. package/dist/core/engine-install.d.ts +53 -0
  88. package/dist/core/engine-install.js +93 -0
  89. package/dist/core/engine-installer.d.ts +134 -0
  90. package/dist/core/engine-installer.js +760 -0
  91. package/dist/core/engine-launch.d.ts +126 -0
  92. package/dist/core/engine-launch.js +398 -0
  93. package/dist/core/engine-self-start.d.ts +63 -0
  94. package/dist/core/engine-self-start.js +282 -0
  95. package/dist/core/engine.d.ts +7 -1
  96. package/dist/core/engine.js +9 -2
  97. package/dist/core/error-codes.d.ts +4 -1
  98. package/dist/core/error-codes.js +7 -3
  99. package/dist/core/feedback/client.d.ts +1 -1
  100. package/dist/core/feedback/client.js +3 -2
  101. package/dist/core/hosted-mcp.d.ts +7 -1
  102. package/dist/core/hosted-mcp.js +6 -4
  103. package/dist/core/library-read.d.ts +2 -2
  104. package/dist/core/library-search.d.ts +2 -2
  105. package/dist/core/local-project.d.ts +50 -0
  106. package/dist/core/local-project.js +234 -0
  107. package/dist/core/ops/areas.js +9 -3
  108. package/dist/core/ops/catalog.d.ts +16 -0
  109. package/dist/core/ops/catalog.js +67 -4
  110. package/dist/core/ops/engine-answer.d.ts +4 -1
  111. package/dist/core/ops/engine-answer.js +16 -3
  112. package/dist/core/ops/engine.js +4 -4
  113. package/dist/core/ops/save-files.d.ts +6 -1
  114. package/dist/core/ops/save-files.js +67 -50
  115. package/dist/core/ops/search.js +9 -2
  116. package/dist/core/preview/input.d.ts +35 -0
  117. package/dist/core/preview/input.js +105 -0
  118. package/dist/core/preview/launch-config.d.ts +52 -0
  119. package/dist/core/preview/launch-config.js +137 -0
  120. package/dist/core/preview/page.d.ts +22 -0
  121. package/dist/core/preview/page.js +232 -0
  122. package/dist/core/preview/preview-source.d.ts +179 -0
  123. package/dist/core/preview/preview-source.js +350 -0
  124. package/dist/core/preview/server.d.ts +26 -0
  125. package/dist/core/preview/server.js +218 -0
  126. package/dist/core/telemetry.d.ts +29 -15
  127. package/dist/core/telemetry.js +144 -39
  128. package/dist/core/templates.d.ts +20 -0
  129. package/dist/core/templates.js +300 -3
  130. package/dist/core/tool-profiles.d.ts +2 -2
  131. package/dist/core/tool-profiles.js +1 -0
  132. package/dist/core/usage-fields.d.ts +41 -0
  133. package/dist/core/usage-fields.js +150 -0
  134. package/dist/core/util/sleep.d.ts +3 -0
  135. package/dist/core/util/sleep.js +12 -0
  136. package/dist/mcp/ops-surface.js +28 -2
  137. package/dist/mcp/server.d.ts +14 -4
  138. package/dist/mcp/server.js +47 -12
  139. package/dist/mcp/tool-surface.d.ts +8 -0
  140. package/dist/mcp/tool-surface.js +19 -2
  141. package/dist/mcp/tools/creator-tools.js +92 -14
  142. package/dist/mcp/tools/debug-tools.js +2 -0
  143. package/dist/mcp/tools/local-project-tools.d.ts +6 -0
  144. package/dist/mcp/tools/local-project-tools.js +33 -0
  145. package/dist/mcp/tools/navigation-tools.js +2 -1
  146. package/dist/mcp/tools/project-tools.js +5 -8
  147. package/dist/mcp/tools/seeing-tools.js +1 -1
  148. package/dist/mcp/tools/visual-tools.js +1 -1
  149. package/dist/mcp/tools/with-engine.js +1 -1
  150. package/gemini-extension.json +3 -1
  151. package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -5
  152. package/library/skills/README.md +12 -8
  153. package/library/skills/animated-loop/SKILL.md +10 -16
  154. package/library/skills/cinematic-cutscene/SKILL.md +7 -18
  155. package/library/skills/headless-scripting/SKILL.md +7 -4
  156. package/library/skills/in-game-purchases/SKILL.md +25 -8
  157. package/library/skills/in-game-purchases/resource.yaml +2 -1
  158. package/library/skills/launch-ready/SKILL.md +351 -0
  159. package/library/skills/launch-ready/resource.yaml +45 -0
  160. package/library/skills/make-content/SKILL.md +202 -0
  161. package/library/skills/make-content/resource.yaml +32 -0
  162. package/library/skills/make-game/SKILL.md +2 -0
  163. package/library/skills/make-game/resource.yaml +2 -1
  164. package/library/skills/multiplayer-publish/SKILL.md +0 -5
  165. package/library/skills/navigate-summer/SKILL.md +4 -2
  166. package/library/skills/new-project/SKILL.md +15 -22
  167. package/library/skills/new-project/resource.yaml +2 -1
  168. package/library/skills/painted-25d-world/SKILL.md +366 -0
  169. package/library/skills/painted-25d-world/_building-blocks/blender-route.md +33 -0
  170. package/library/skills/painted-25d-world/_building-blocks/blockout_builder.gd +149 -0
  171. package/library/skills/painted-25d-world/_building-blocks/capture_paint_view.gd +32 -0
  172. package/library/skills/painted-25d-world/_building-blocks/paint_projection.gdshader +23 -0
  173. package/library/skills/painted-25d-world/_building-blocks/paintcam_check.gd +25 -0
  174. package/library/skills/painted-25d-world/_building-blocks/painted_door.gd +17 -0
  175. package/library/skills/painted-25d-world/_building-blocks/painted_location.gd +56 -0
  176. package/library/skills/painted-25d-world/_building-blocks/painted_player.gd +125 -0
  177. package/library/skills/painted-25d-world/_building-blocks/painted_world.gd +111 -0
  178. package/library/skills/painted-25d-world/_building-blocks/tools/cam.py +57 -0
  179. package/library/skills/painted-25d-world/_building-blocks/tools/detail4k.py +81 -0
  180. package/library/skills/painted-25d-world/_building-blocks/tools/overlay.py +17 -0
  181. package/library/skills/painted-25d-world/_building-blocks/tools/preview.py +60 -0
  182. package/library/skills/painted-25d-world/resource.yaml +39 -0
  183. package/library/skills/publish-your-game/SKILL.md +13 -14
  184. package/library/skills/publish-your-game/resource.yaml +4 -3
  185. package/library/skills/release-checklist/SKILL.md +188 -0
  186. package/library/skills/release-checklist/resource.yaml +40 -0
  187. package/library/skills/release-readiness/SKILL.md +1 -1
  188. package/library/skills/release-readiness/resource.yaml +1 -1
  189. package/library/skills/store-art/SKILL.md +1 -1
  190. package/library/skills/store-art/resource.yaml +1 -1
  191. package/library/skills/store-listing/SKILL.md +1 -1
  192. package/library/skills/store-listing/resource.yaml +1 -1
  193. package/library/skills/summer-cli/SKILL.md +2 -0
  194. package/library/skills/summer-store/SKILL.md +295 -39
  195. package/library/skills/summer-store/resource.yaml +9 -3
  196. package/library/skills/trailer-shot/SKILL.md +3 -3
  197. package/library/templates/README.md +5 -0
  198. package/library/tools/content-make/resource.yaml +132 -0
  199. package/library/tools/frame-shot/GUIDE.md +1 -1
  200. package/library/tools/go-live/resource.yaml +67 -0
  201. package/library/tools/import-from-url/GUIDE.md +1 -0
  202. package/library/tools/import-from-url-batch/GUIDE.md +1 -1
  203. package/library/tools/play/GUIDE.md +2 -0
  204. package/library/tools/projects-create-local/resource.yaml +55 -0
  205. package/library/tools/projects-open-local/resource.yaml +51 -0
  206. package/library/tools/publish-build/resource.yaml +3 -3
  207. package/library/tools/screenshot/GUIDE.md +1 -1
  208. package/library/tools/store-set-details/resource.yaml +114 -0
  209. package/library/tools/sync-items/resource.yaml +72 -0
  210. package/package.json +1 -1
  211. package/registry/generated/aliases.json +6 -0
  212. package/registry/generated/counts.json +3 -3
  213. package/registry/generated/gemini-extension.json +3 -1
  214. package/registry/generated/index.json +464 -38
  215. package/registry/generated/marketplace.claude.json +1 -1
  216. package/registry/generated/plugin.claude-directory.json +4 -2
  217. package/registry/generated/plugin.claude.json +3 -1
  218. package/registry/generated/plugin.codex.json +5 -3
  219. package/registry/generated/plugin.cursor.json +4 -2
  220. package/registry/generated/plugin.factory.json +4 -2
  221. package/registry/generated/server.json +2 -2
  222. package/registry/generated/skills-index.md +12 -8
  223. package/registry/generated/skills-registry.json +62 -5
  224. package/registry/operations/legacy-names.json +40 -0
  225. package/registry/operations/public-catalog.json +10144 -387
@@ -1,110 +1,12 @@
1
1
  import { Command } from "commander";
2
- import { spawn } from "child_process";
3
2
  import { existsSync } from "fs";
4
- import { mkdir, readFile, rm, writeFile } from "fs/promises";
5
3
  import { join, resolve } from "path";
6
- import { getSummerDir } from "../../core/auth.js";
7
- import { getApiPort, checkEngineHealth } from "../../core/engine.js";
8
- import { describeEngineExecutableProblem, ENGINE_BIN_ENV, engineBinaryOverride, findEngineBinary, } from "../../core/engine-install.js";
9
- import { advertisedBackgroundPosture, backgroundLaunchSupport, detectBackgroundLaunchSupport, planLaunch, resolveLaunchPosture, BACKGROUND_LAUNCH_FLAG, BACKGROUND_LAUNCH_MIN_ENGINE_VERSION, } from "../../core/launch-posture.js";
10
- import { sleep } from "../../core/util/sleep.js";
11
- const LAUNCH_LOCK_STALE_MS = 60_000;
12
- const LAUNCH_LOCK_WAIT_MS = 15_000;
13
- function isProcessAlive(pid) {
14
- if (!Number.isInteger(pid) || pid <= 0)
15
- return false;
16
- try {
17
- process.kill(pid, 0);
18
- return true;
19
- }
20
- catch (error) {
21
- const code = error.code;
22
- return code === "EPERM";
23
- }
24
- }
25
- async function removeStaleLaunchLock(lockDir) {
26
- const ownerPath = join(lockDir, "owner.json");
27
- try {
28
- const raw = await readFile(ownerPath, "utf-8");
29
- const owner = JSON.parse(raw);
30
- const pid = typeof owner.pid === "number" ? owner.pid : 0;
31
- const createdAt = typeof owner.createdAt === "number" ? owner.createdAt : 0;
32
- const staleByTime = Date.now() - createdAt > LAUNCH_LOCK_STALE_MS;
33
- const staleByPid = !isProcessAlive(pid);
34
- if (!staleByTime && !staleByPid) {
35
- return false;
36
- }
37
- }
38
- catch {
39
- // Broken owner metadata should not permanently block launches.
40
- }
41
- await rm(lockDir, { recursive: true, force: true });
42
- return true;
43
- }
44
- async function withLaunchLock(fn) {
45
- const summerDir = getSummerDir();
46
- await mkdir(summerDir, { recursive: true, mode: 0o700 });
47
- const lockDir = join(summerDir, "launch.lock");
48
- const ownerPath = join(lockDir, "owner.json");
49
- const startedAt = Date.now();
50
- while (true) {
51
- try {
52
- await mkdir(lockDir, { mode: 0o700 });
53
- try {
54
- await writeFile(ownerPath, JSON.stringify({ pid: process.pid, createdAt: Date.now() }, null, 2), { encoding: "utf-8", mode: 0o600 });
55
- return await fn();
56
- }
57
- finally {
58
- await rm(lockDir, { recursive: true, force: true });
59
- }
60
- }
61
- catch (error) {
62
- const code = error.code;
63
- if (code !== "EEXIST") {
64
- throw error;
65
- }
66
- if (await removeStaleLaunchLock(lockDir)) {
67
- continue;
68
- }
69
- if (Date.now() - startedAt > LAUNCH_LOCK_WAIT_MS) {
70
- throw new Error("Another `summer run` launch is still in progress. Try again in a few seconds.");
71
- }
72
- await sleep(100);
73
- }
74
- }
75
- }
76
- /**
77
- * Which engine executable `summer run` launches (and probes with --help):
78
- * `--bin <path>`, else SUMMER_BIN, else the installed engine
79
- * (findEngineBinary, which also honours the older SUMMER_ENGINE_BINARY).
80
- * An explicit override is never silently swapped for the installed engine:
81
- * a missing path or a bare `.app` bundle is an error, because the caller
82
- * asked for THAT build.
83
- */
84
- export function resolveRunBinary(binFlag, env = process.env) {
85
- const fromEnv = engineBinaryOverride(env);
86
- const explicit = binFlag?.trim()
87
- ? { source: "--bin", path: binFlag.trim() }
88
- : fromEnv?.name === ENGINE_BIN_ENV
89
- ? { source: ENGINE_BIN_ENV, path: fromEnv.path }
90
- : null;
91
- if (explicit) {
92
- const path = resolve(explicit.path);
93
- const problem = describeEngineExecutableProblem(path, explicit.source);
94
- return problem ? { binary: null, error: problem } : { binary: path, source: explicit.source };
95
- }
96
- const installed = findEngineBinary();
97
- if (!installed) {
98
- return {
99
- binary: null,
100
- error: "Summer Engine not found. Install it first:\n" +
101
- " summer install\n" +
102
- " or download from https://summerengine.com/download\n" +
103
- `To launch a build that is not installed, pass --bin <executable> or set ${ENGINE_BIN_ENV}.`,
104
- };
105
- }
106
- return { binary: installed, source: "installed" };
107
- }
4
+ import { launchEditor } from "../../core/engine-launch.js";
5
+ import { ENGINE_BIN_ENV } from "../../core/engine-install.js";
6
+ import { resolveLaunchPosture } from "../../core/launch-posture.js";
7
+ // The launch itself (lock, already-open check, posture flags, health wait)
8
+ // lives in core/engine-launch.ts, shared with `summer dev` and the MCP.
9
+ export { resolveRunBinary } from "../../core/engine-launch.js";
108
10
  export const runCommand = new Command("run")
109
11
  .description("Launch Summer Engine with a project. Without a path it launches a bare " +
110
12
  "detached editor (project manager), which requires --no-project.")
@@ -148,108 +50,17 @@ export const runCommand = new Command("run")
148
50
  process.exit(1);
149
51
  }
150
52
  }
151
- await withLaunchLock(async () => {
152
- const port = await getApiPort();
153
- const health = await checkEngineHealth(port);
154
- if (health) {
155
- const runningProjectPath = health.project_path
156
- ? resolve(health.project_path)
157
- : null;
158
- if (!fullProjectPath || runningProjectPath === fullProjectPath) {
159
- console.log(`Summer Engine is already running (v${health.version}) on port ${port}`);
160
- if (health.project_name) {
161
- console.log(` Project: ${health.project_name}`);
162
- }
163
- if (health.project_path) {
164
- console.log(` Path: ${health.project_path}`);
165
- }
166
- return;
167
- }
168
- console.log(`Summer Engine is already running (v${health.version}) on port ${port}`);
169
- console.log(` Current project: ${health.project_path ?? health.project_name ?? "unknown"}`);
170
- console.error(`Refusing to launch a second editor for: ${fullProjectPath}\n` +
171
- "Close or switch the current Summer Engine project first, then run this command again.");
172
- process.exitCode = 1;
173
- return;
174
- }
175
- const resolved = resolveRunBinary(opts.bin);
176
- if (resolved.binary === null) {
177
- console.error(resolved.error);
178
- process.exitCode = 1;
179
- return;
180
- }
181
- const binary = resolved.binary;
182
- if (resolved.source !== "installed") {
183
- console.log(`Using engine from ${resolved.source}: ${binary}`);
184
- }
185
- // The engine is not running yet, so /api/health cannot tell us whether
186
- // it honours --summer-background. Ask THAT binary itself (`--help`, which
187
- // exits headless before any window exists; cached per install) with the
188
- // installed version as pre-check and fallback; pass the flag only when
189
- // the engine is known to support it. Focus launches have nothing to decide.
190
- const support = posture === "background" ? await detectBackgroundLaunchSupport(binary) : backgroundLaunchSupport(null);
191
- const plan = planLaunch(posture, support);
192
- const args = ["--editor", ...plan.extraArgs];
193
- if (fullProjectPath) {
194
- args.unshift("--path", fullProjectPath);
195
- }
196
- if (plan.note)
197
- console.log(plan.note);
198
- console.log(plan.background
199
- ? "Launching Summer Engine in the background (the window will not take focus until you click it)..."
200
- : "Launching Summer Engine...");
201
- // Direct executable, never `open -a`: LaunchServices activates whatever
202
- // it opens and would defeat --summer-background regardless of flags.
203
- const child = spawn(binary, args, { detached: true, stdio: "ignore" });
204
- // A stale or non-executable binary surfaces as an async "error" event
205
- // (ENOENT/EACCES). Without a listener Node raises it as an uncaught
206
- // exception with a raw stack; catch it and report the path instead.
207
- const spawnState = { error: null };
208
- child.on("error", (error) => {
209
- spawnState.error = error;
210
- });
211
- child.unref();
212
- // Wait for engine to start responding
213
- const startTime = Date.now();
214
- const timeout = 20000;
215
- while (Date.now() - startTime < timeout) {
216
- await sleep(500);
217
- if (spawnState.error) {
218
- reportSpawnFailure(spawnState.error, binary);
219
- return;
220
- }
221
- const newPort = await getApiPort();
222
- const h = await checkEngineHealth(newPort);
223
- if (h) {
224
- console.log(`Summer Engine running (v${h.version}) on port ${newPort}`);
225
- if (h.project_name) {
226
- console.log(` Project: ${h.project_name}`);
227
- }
228
- // Background was wanted but the flag was withheld, and the running
229
- // engine now says (capabilities.launchPostures, else its version)
230
- // that it would have honoured it: say so, so the next launch can be
231
- // fixed rather than silently repeating a focus launch.
232
- if (posture === "background" && !plan.background) {
233
- const advert = advertisedBackgroundPosture(h.capabilities);
234
- const wouldHonour = advert ?? backgroundLaunchSupport(h.version).supported;
235
- if (wouldHonour) {
236
- console.log(` Note: this engine (v${h.version}) ${advert ? "advertises" : "should support"} background launches (${BACKGROUND_LAUNCH_FLAG}, ${BACKGROUND_LAUNCH_MIN_ENGINE_VERSION}+), but that could not be confirmed before launch on this platform.`);
237
- }
238
- }
239
- return;
240
- }
241
- }
242
- if (spawnState.error) {
243
- reportSpawnFailure(spawnState.error, binary);
244
- return;
245
- }
53
+ const result = await launchEditor({
54
+ projectPath: fullProjectPath,
55
+ posture,
56
+ bin: opts.bin,
57
+ out: { log: (line) => console.log(line), error: (line) => console.error(line) },
58
+ });
59
+ if (result.status === "starting") {
246
60
  console.log("Summer Engine launched but API not responding yet.\n" +
247
61
  "It may still be loading. Run 'summer status' to check.");
248
- });
62
+ }
63
+ else if (result.status !== "running") {
64
+ process.exitCode = 1;
65
+ }
249
66
  });
250
- function reportSpawnFailure(error, binary) {
251
- const code = error.code ?? error.message;
252
- console.error(`Summer Engine binary failed to start: ${code} (${binary})\n` +
253
- "Re-run 'summer install' to repair the installation, or check the binary path.");
254
- process.exitCode = 1;
255
- }
@@ -14,6 +14,7 @@ import { PACKAGE_ROOT } from "../../core/package-root.js";
14
14
  import { Command, Option } from "commander";
15
15
  import { ToolDispatchError, ToolResultError, dispatchTool, listToolDispatches, resolveToolDispatch, } from "../../core/capabilities/tool-dispatch.js";
16
16
  import { c } from "../../core/format.js";
17
+ import { noteCliHosted, noteCliTool } from "../../core/cli-usage.js";
17
18
  import { callHostedToolForCli, hostedResultPayload, listHostedToolsForCli, } from "../../core/hosted-mcp.js";
18
19
  /** The hosted store and publishing tools (Summer Engine MCP); replaceable in tests. */
19
20
  export const hostedCli = { list: listHostedToolsForCli, call: callHostedToolForCli };
@@ -116,6 +117,8 @@ export const toolCommand = new Command("tool")
116
117
  const entry = resolveToolForCli(name);
117
118
  if (!entry) {
118
119
  // Not a local tool: the hosted store and publishing tools, with the store sign-in.
120
+ // Summer's server records the call itself (X-Summer-Client-Surface: cli).
121
+ noteCliHosted();
119
122
  const hosted = await hostedCli.call(name, parseJsonArgs(options.args ?? options.json));
120
123
  if (hosted.status === "called") {
121
124
  const payload = hostedResultPayload(hosted.result);
@@ -135,6 +138,7 @@ export const toolCommand = new Command("tool")
135
138
  console.error("Note: 'summer tool --json <args>' is deprecated; use --args <json>.");
136
139
  }
137
140
  const args = parseJsonArgs(options.args ?? options.json);
141
+ noteCliTool(entry.name);
138
142
  let result;
139
143
  try {
140
144
  result = await dispatchTool(entry.slug, args);
package/dist/cli/index.js CHANGED
@@ -6,6 +6,7 @@ import { runCommand } from "./commands/run.js";
6
6
  import { openCommand } from "./commands/open.js";
7
7
  import { installCommand } from "./commands/install.js";
8
8
  import { createCommand } from "./commands/create.js";
9
+ import { devCommand } from "./commands/dev.js";
9
10
  import { listCommand } from "./commands/list.js";
10
11
  import { memoryCommand } from "./commands/memory.js";
11
12
  import { skillsCommand } from "./commands/skills.js";
@@ -15,12 +16,14 @@ import { planCommand } from "./commands/plan.js";
15
16
  import { debugCommand } from "./commands/debug.js";
16
17
  import { configCommand } from "./commands/config.js";
17
18
  import { eventsCommand } from "./commands/events.js";
19
+ import { previewCommand } from "./commands/preview.js";
18
20
  import { toolCommand } from "./commands/tool.js";
19
21
  import { opsCliCommands } from "./commands/ops.js";
20
22
  import { getBanner } from "./banner.js";
21
23
  import { runRootAction } from "./root-action.js";
22
24
  import { c, sym } from "../core/format.js";
23
25
  import { resolveSurface } from "../core/tool-profiles.js";
26
+ import { trackCommandUsage } from "./command-usage.js";
24
27
  import { TOOLKIT_VERSION as version } from "../core/version.js";
25
28
  /**
26
29
  * Build and run the summer CLI. The `mcp` command is injected by the bin
@@ -35,6 +38,7 @@ export function runCli(mcpCommand) {
35
38
  .action((_opts, command) => {
36
39
  runRootAction(command.args, () => printIntro(version));
37
40
  });
41
+ program.addCommand(devCommand);
38
42
  program.addCommand(installCommand);
39
43
  program.addCommand(loginCommand);
40
44
  program.addCommand(logoutCommand);
@@ -52,12 +56,14 @@ export function runCli(mcpCommand) {
52
56
  program.addCommand(planCommand);
53
57
  program.addCommand(configCommand);
54
58
  program.addCommand(eventsCommand);
59
+ program.addCommand(previewCommand);
55
60
  program.addCommand(toolCommand);
56
61
  // The 4.0 operation catalog (`summer <area> <action>`); SUMMER_SURFACE=v3 leaves it out.
57
62
  if (resolveSurface(undefined) === "v4") {
58
63
  for (const command of opsCliCommands())
59
64
  program.addCommand(command);
60
65
  }
66
+ trackCommandUsage(program);
61
67
  program.parseAsync().catch((err) => {
62
68
  console.error(err instanceof Error ? err.message : String(err));
63
69
  process.exit(1);
@@ -74,6 +80,7 @@ function printIntro(version) {
74
80
  console.log(` ${c.brand("\"Install Summer Engine and let's make a game.\"")}`);
75
81
  console.log("");
76
82
  console.log(` ${c.bold("Manual commands")}`);
83
+ console.log(` ${c.dim("$")} npx -y summer-engine@latest dev ${c.dim("# install, create a starter project, open it")}`);
77
84
  console.log(` ${c.dim("$")} npx -y summer-engine@latest setup claude-code --yes`);
78
85
  console.log(` ${c.dim("$")} npx -y summer-engine@latest create 3d-basic my-game`);
79
86
  console.log(` ${c.dim("$")} npx -y summer-engine@latest plan make a small arena shooter`);
@@ -36,6 +36,7 @@ export interface McpClientInfo {
36
36
  }
37
37
  type Env = Record<string, string | undefined>;
38
38
  /** The opt-out switches, the same two the library feedback mailbox honors. */
39
+ /** SUMMER_NO_TELEMETRY or DO_NOT_TRACK set to 1, true, yes or on. */
39
40
  export declare function isTelemetryDisabled(env?: Env): boolean;
40
41
  /** Lowercase `[a-z0-9-]`, at most 40 characters: the server's host id shape. */
41
42
  export declare function sanitizeHostId(raw: string): string;
@@ -43,12 +44,17 @@ export declare function sanitizeHostId(raw: string): string;
43
44
  export declare function hostFromClientName(name: string | undefined | null): string | null;
44
45
  /** AI_AGENT ("<name>_<version>_<mode>") first, then the per-host variables. */
45
46
  export declare function hostFromEnv(env: Env): string | null;
47
+ /** `mcp` inside `summer mcp` (it registers its handshake), `cli` for every other command. */
48
+ export declare function processSurface(): ClientSurface;
46
49
  export declare function registerMcpClientSource(source: (() => McpClientInfo | undefined) | null): void;
47
50
  export declare function currentMcpClient(): McpClientInfo | undefined;
48
51
  export declare function resolveAgentHost(env?: Env, client?: McpClientInfo | undefined): AgentHost;
49
52
  interface ToolContext {
50
53
  tool: string;
51
54
  surface: ClientSurface;
55
+ /** Usage fields the call noted for its usage line (telemetry.ts noteToolUsage);
56
+ * one object shared with any tool it runs, so the outer call's line has them. */
57
+ usage: Record<string, unknown>;
52
58
  }
53
59
  /** Run one tool call so every Summer request it makes names the tool and surface. */
54
60
  export declare function runWithToolContext<T>(tool: string, surface: ClientSurface, fn: () => T): T;
@@ -27,8 +27,10 @@ export const AGENT_HOST_VERSION_HEADER = "X-Summer-Agent-Host-Version";
27
27
  export const MCP_TOOL_HEADER = "X-Summer-MCP-Tool";
28
28
  export const AGENT_HOST_OVERRIDE_ENV = "SUMMER_AGENT_HOST";
29
29
  /** The opt-out switches, the same two the library feedback mailbox honors. */
30
+ /** SUMMER_NO_TELEMETRY or DO_NOT_TRACK set to 1, true, yes or on. */
30
31
  export function isTelemetryDisabled(env = process.env) {
31
- return env.SUMMER_NO_TELEMETRY === "1" || env.DO_NOT_TRACK === "1";
32
+ const on = (value) => value !== undefined && /^(1|true|yes|on)$/i.test(value.trim());
33
+ return on(env.SUMMER_NO_TELEMETRY) || on(env.DO_NOT_TRACK);
32
34
  }
33
35
  const set = (env, key) => {
34
36
  const value = env[key];
@@ -128,6 +130,10 @@ export function hostFromEnv(env) {
128
130
  // The MCP server registers a getter; it is read at request time, after the
129
131
  // initialize handshake has given the client's name and version.
130
132
  let mcpClientSource = null;
133
+ /** `mcp` inside `summer mcp` (it registers its handshake), `cli` for every other command. */
134
+ export function processSurface() {
135
+ return mcpClientSource ? "mcp" : "cli";
136
+ }
131
137
  export function registerMcpClientSource(source) {
132
138
  mcpClientSource = source;
133
139
  }
@@ -154,7 +160,7 @@ export function resolveAgentHost(env = process.env, client = currentMcpClient())
154
160
  const toolContext = new AsyncLocalStorage();
155
161
  /** Run one tool call so every Summer request it makes names the tool and surface. */
156
162
  export function runWithToolContext(tool, surface, fn) {
157
- return toolContext.run({ tool, surface }, fn);
163
+ return toolContext.run({ tool, surface, usage: toolContext.getStore()?.usage ?? {} }, fn);
158
164
  }
159
165
  /** The tool call running now, if any (a tool that runs inside another one sees the outer call). */
160
166
  export function currentToolContext() {
@@ -168,7 +174,7 @@ const headerValue = (value, max) => value.replace(/[^\x20-\x7e]/g, "").trim().sl
168
174
  */
169
175
  export function summerRequestHeaders(options = {}, env = process.env) {
170
176
  const context = toolContext.getStore();
171
- const surface = context?.surface ?? options.surface ?? (mcpClientSource ? "mcp" : "cli");
177
+ const surface = context?.surface ?? options.surface ?? processSurface();
172
178
  const headers = {
173
179
  "X-Summer-Client": "summer-cli",
174
180
  "X-Summer-Client-Version": TOOLKIT_VERSION,
@@ -45,6 +45,14 @@ export type EngineSnapshot = {
45
45
  * (item 4, client-side drift check). */
46
46
  projectMismatch?: boolean;
47
47
  };
48
+ /** Options for a viewport or game capture. */
49
+ export type SnapshotOptions = {
50
+ /** Write the frame into the snapshots folder and return its localPath
51
+ * (default true). The live preview (`summer preview`) passes false: it
52
+ * sends each frame straight to the browser, so polling a few frames a
53
+ * second never fills the temp folder. */
54
+ saveFile?: boolean;
55
+ };
48
56
  type EngineTargetIdentity = {
49
57
  instanceId?: string;
50
58
  projectId?: string;
@@ -199,8 +207,8 @@ export declare class EngineApiClient {
199
207
  * plain error rather than silently claiming "bridge required".
200
208
  */
201
209
  private _bridgeRequiredFromResponse;
202
- viewportSnapshot(): Promise<EngineSnapshot>;
203
- gameSnapshot(): Promise<EngineSnapshot>;
210
+ viewportSnapshot(options?: SnapshotOptions): Promise<EngineSnapshot>;
211
+ gameSnapshot(options?: SnapshotOptions): Promise<EngineSnapshot>;
204
212
  /**
205
213
  * Offscreen scene render via the `ScenePreview` op over /api/ops (no game
206
214
  * boot; physics/animations are static). Mirrors the web previewScene op input
@@ -7,6 +7,7 @@ import { asRecord, boolFrom, numberFrom, stringFrom } from "./util/json.js";
7
7
  import { classifyOpsResponse, pollOpToTerminal, } from "./async-op-lifecycle.js";
8
8
  import { pickPlayDeterminism } from "./capabilities/play-determinism.js";
9
9
  import { honestSceneReceipt } from "./capabilities/engine-receipt.js";
10
+ import { noteBoundProject } from "./usage-fields.js";
10
11
  function findSnapshotPayload(value) {
11
12
  const record = asRecord(value);
12
13
  if (!record)
@@ -139,6 +140,7 @@ export class EngineApiClient {
139
140
  projectIdHash: connection.health.projectIdHash,
140
141
  }, { ...effective });
141
142
  client.lastHealth = connection.health;
143
+ noteBoundProject(connection.health.projectIdHash);
142
144
  return client;
143
145
  }
144
146
  // Bind to whatever project is open right now. On a genuine engine restart the
@@ -157,6 +159,7 @@ export class EngineApiClient {
157
159
  projectIdHash: health.projectIdHash,
158
160
  });
159
161
  client.lastHealth = health;
162
+ noteBoundProject(health.projectIdHash);
160
163
  return client;
161
164
  }
162
165
  }
@@ -169,6 +172,7 @@ export class EngineApiClient {
169
172
  projectIdHash: connection.health.projectIdHash,
170
173
  });
171
174
  client.lastHealth = connection.health;
175
+ noteBoundProject(connection.health.projectIdHash);
172
176
  client.registryDiscovery = { ...discovery };
173
177
  return client;
174
178
  }
@@ -215,6 +219,7 @@ export class EngineApiClient {
215
219
  projectId: health.projectId,
216
220
  projectIdHash: health.projectIdHash,
217
221
  };
222
+ noteBoundProject(health.projectIdHash);
218
223
  return this.targetIdentity.projectIdHash;
219
224
  }
220
225
  /** Identity to attach to a MUTATING command's options so the engine can reject
@@ -584,7 +589,7 @@ export class EngineApiClient {
584
589
  await writeFile(localPath, buffer);
585
590
  return localPath;
586
591
  }
587
- async snapshot(kind) {
592
+ async snapshot(kind, options = {}) {
588
593
  // Block E: /api/snapshot/* is queued (GET -> 202 -> poll /api/ops/result).
589
594
  // The terminal result is the apply dict; the image rides as base64 inside it
590
595
  // (no raw-binary channel). Legacy/dormant engines answer 200 synchronously
@@ -609,11 +614,11 @@ export class EngineApiClient {
609
614
  catch (err) {
610
615
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
611
616
  }
612
- return this._parseSnapshotResponse(response, kind);
617
+ return this._parseSnapshotResponse(response, kind, options.saveFile !== false);
613
618
  }
614
619
  /** Shared: turn an ops/snapshot response envelope into an EngineSnapshot.
615
620
  * Used by viewport/game snapshots and by scenePreview. */
616
- async _parseSnapshotResponse(response, kind) {
621
+ async _parseSnapshotResponse(response, kind, saveFile = true) {
617
622
  const payload = findSnapshotPayload(response);
618
623
  if (!payload) {
619
624
  return {
@@ -635,7 +640,7 @@ export class EngineApiClient {
635
640
  }
636
641
  const { format, mime, ext } = snapshotFormat(payload);
637
642
  const buffer = Buffer.from(base64, "base64");
638
- const localPath = await this.writeSnapshotFile(kind, buffer, ext);
643
+ const localPath = saveFile ? await this.writeSnapshotFile(kind, buffer, ext) : undefined;
639
644
  // Client-side identity drift check (item 4). Current engines validate the
640
645
  // identity query on snapshot reads, but older builds may ignore it. Re-read
641
646
  // health and compare to the bound hash so a frame from a switched project is
@@ -701,11 +706,11 @@ export class EngineApiClient {
701
706
  error: stringFrom(body.error) ?? "Game snapshots require the desktop bridge async transport.",
702
707
  };
703
708
  }
704
- async viewportSnapshot() {
705
- return this.snapshot("viewport");
709
+ async viewportSnapshot(options) {
710
+ return this.snapshot("viewport", options);
706
711
  }
707
- async gameSnapshot() {
708
- return this.snapshot("game");
712
+ async gameSnapshot(options) {
713
+ return this.snapshot("game", options);
709
714
  }
710
715
  /**
711
716
  * Offscreen scene render via the `ScenePreview` op over /api/ops (no game
@@ -17,6 +17,7 @@ export function buildAgentPlaybook(options = {}) {
17
17
  // VISUAL VERIFICATION — pixels are the second signal.
18
18
  // ------------------------------------------------------------------
19
19
  visualVerification: [
20
+ "Opening the Summer editor and playing the game in a window is allowed and expected: summer_play, then summer_screenshot or summer_frame_shot to see the result. Close what you opened when you are done (summer_stop); one editor at a time.",
20
21
  "Use summer_screenshot BEFORE making changes to see the current state, and AFTER every mutation batch or asset import to verify the result. Two signals, two jobs: summer_snapshot_diff proves exact structural facts; the screenshot proves appearance. Run both.",
21
22
  "For lighting, mood, environment, or emissive materials, use summer_screenshot target:'scene' framing:'camera' — it renders through the scene's OWN camera with its REAL WorldEnvironment. The preset framings (iso/top/...) substitute a flat preview environment and CANNOT verify lighting.",
22
23
  "When executing multiple batches, screenshot between them — catch the wrong turn at batch 2, not batch 7.",
@@ -18,9 +18,9 @@ export declare const APP_DOCK_SLOTS: readonly ["left", "right", "bottom"];
18
18
  export declare const appGuideArgsSchema: z.ZodObject<{
19
19
  section: z.ZodDefault<z.ZodEnum<["all", "overview", "manifest", "sdk", "kit", "layout", "design", "examples", "types"]>>;
20
20
  }, "strip", z.ZodTypeAny, {
21
- section: "all" | "examples" | "kit" | "layout" | "manifest" | "overview" | "sdk" | "design" | "types";
21
+ section: "examples" | "all" | "kit" | "layout" | "manifest" | "overview" | "sdk" | "design" | "types";
22
22
  }, {
23
- section?: "all" | "examples" | "kit" | "layout" | "manifest" | "overview" | "sdk" | "design" | "types" | undefined;
23
+ section?: "examples" | "all" | "kit" | "layout" | "manifest" | "overview" | "sdk" | "design" | "types" | undefined;
24
24
  }>;
25
25
  export declare const appListArgsSchema: z.ZodObject<{
26
26
  workspaceId: z.ZodOptional<z.ZodString>;
@@ -112,10 +112,10 @@ export declare const appEventsArgsSchema: z.ZodObject<{
112
112
  after: number;
113
113
  timeoutSeconds: number;
114
114
  appId: string;
115
- kinds?: ("error" | "agent" | "tool" | "feedback")[] | undefined;
115
+ kinds?: ("error" | "tool" | "agent" | "feedback")[] | undefined;
116
116
  }, {
117
117
  appId: string;
118
- kinds?: ("error" | "agent" | "tool" | "feedback")[] | undefined;
118
+ kinds?: ("error" | "tool" | "agent" | "feedback")[] | undefined;
119
119
  after?: number | undefined;
120
120
  timeoutSeconds?: number | undefined;
121
121
  }>;
@@ -195,8 +195,8 @@ export declare const appScreenshotArgsSchema: z.ZodObject<{
195
195
  appId: string;
196
196
  fullPage: boolean;
197
197
  version?: number | undefined;
198
- params?: Record<string, string> | undefined;
199
198
  out?: string | undefined;
199
+ params?: Record<string, string> | undefined;
200
200
  steps?: {
201
201
  wait?: number | undefined;
202
202
  press?: string | undefined;
@@ -205,10 +205,10 @@ export declare const appScreenshotArgsSchema: z.ZodObject<{
205
205
  }, {
206
206
  appId: string;
207
207
  version?: number | undefined;
208
+ out?: string | undefined;
209
+ params?: Record<string, string> | undefined;
208
210
  width?: number | undefined;
209
211
  height?: number | undefined;
210
- params?: Record<string, string> | undefined;
211
- out?: string | undefined;
212
212
  theme?: "light" | "dark" | undefined;
213
213
  steps?: {
214
214
  wait?: number | undefined;
@@ -234,9 +234,9 @@ export declare const appDataArgsSchema: z.ZodObject<{
234
234
  }, {
235
235
  appId: string;
236
236
  ops?: Record<string, unknown>[] | undefined;
237
- limit?: number | undefined;
238
237
  as?: "seed" | "agent" | undefined;
239
238
  collection?: string | undefined;
239
+ limit?: number | undefined;
240
240
  after?: string | undefined;
241
241
  }>;
242
242
  export declare const appToolsArgsSchema: z.ZodObject<{
@@ -251,8 +251,8 @@ export declare const appCallArgsSchema: z.ZodObject<{
251
251
  tool: z.ZodString;
252
252
  input: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
253
253
  }, "strip", z.ZodTypeAny, {
254
- input: Record<string, unknown>;
255
254
  tool: string;
255
+ input: Record<string, unknown>;
256
256
  appId: string;
257
257
  }, {
258
258
  tool: string;
@@ -14,6 +14,8 @@ export type GatewayAsset = {
14
14
  pack?: string | null;
15
15
  packSlug?: string | null;
16
16
  importUrl?: string;
17
+ /** A video's Ogg Theora rendition (summerengine.com names it): the one video file Summer Engine can load. */
18
+ ogvUrl?: string | null;
17
19
  downloadUrl?: string;
18
20
  fileName?: string | null;
19
21
  mimeType?: string | null;
@@ -36,7 +38,6 @@ export interface ImportResolvedAssetArgs {
36
38
  * packs) and, for 3D models with a `parent`, instantiate it into `scenePath`
37
39
  * and save. Throws with a user-facing message on any engine refusal. */
38
40
  export declare function importResolvedAsset(client: EngineApiClient, args: ImportResolvedAssetArgs): Promise<{
39
- success: boolean;
40
41
  assetId: string;
41
42
  asset: string;
42
43
  type: string;
@@ -45,4 +46,6 @@ export declare function importResolvedAsset(client: EngineApiClient, args: Impor
45
46
  parent: string | null;
46
47
  scenePath: string | null;
47
48
  sceneReceipt: unknown;
49
+ note?: string | undefined;
50
+ success: boolean;
48
51
  }>;
@@ -1,4 +1,5 @@
1
1
  import { ToolInputError } from "../tool-errors.js";
2
+ import { importUrls, ogvResPath } from "./video-ogv.js";
2
3
  /** Kenney Cloudinary URL pattern: .../summer_art/kenney/3d/{pack-slug}/{filename}.glb */
3
4
  const KENNEY_URL_PATTERN = /\/kenney\/3d\/([^/]+)\//;
4
5
  function getPackSlugFromUrl(fileUrl) {
@@ -49,6 +50,12 @@ async function buildImportEntriesForAsset(asset, targetPath) {
49
50
  const fileUrl = asset.importUrl || asset.fileUrl;
50
51
  if (!fileUrl)
51
52
  throw new Error("Asset has no import URL.");
53
+ if (asset.ogvUrl) {
54
+ // A video: import its .ogv rendition, the one video file Summer Engine can load.
55
+ const name = asset.fileName || fileNameFromUrl(asset.fileUrl || fileUrl);
56
+ const path = ogvResPath({ url: asset.fileUrl || fileUrl, path: targetPath ?? `res://assets/videos/${name}` });
57
+ return { importPath: path, imports: [{ url: asset.ogvUrl, path }] };
58
+ }
52
59
  const fileName = targetPath?.split("/").pop() || asset.fileName || fileNameFromUrl(fileUrl);
53
60
  const packSlug = asset.packSlug ?? getPackSlugFromUrl(fileUrl) ?? "misc";
54
61
  if (targetPath) {
@@ -88,12 +95,11 @@ export async function importResolvedAsset(client, args) {
88
95
  if (parent && !scenePath) {
89
96
  throw new ToolInputError("scenePath is required when importing an asset into a scene");
90
97
  }
91
- const { imports, importPath } = await buildImportEntriesForAsset(asset, path);
92
- const importResult = imports.length === 1
93
- ? await client.executeOps([
94
- { op: "ImportFromUrl", url: imports[0].url, path: imports[0].path },
95
- ])
96
- : await client.executeOps([{ op: "ImportFromUrlBatch", imports }]);
98
+ const { imports, importPath: plannedPath } = await buildImportEntriesForAsset(asset, path);
99
+ // A video without a rendition is converted to .ogv on the way in (video-ogv.ts).
100
+ const importResult = await importUrls(client, imports, { batch: imports.length > 1 });
101
+ const conversions = importResult?.videoConversions;
102
+ const importPath = conversions?.[conversions.length - 1]?.to ?? plannedPath;
97
103
  const importReceipts = importResult?.results ?? [];
98
104
  const importFailure = importReceipts.find((receipt) => receipt?.ok === false);
99
105
  if (importResult?.status === "error" || importFailure) {
@@ -122,6 +128,9 @@ export async function importResolvedAsset(client, args) {
122
128
  }
123
129
  return {
124
130
  success: true,
131
+ ...(conversions?.length || asset.ogvUrl
132
+ ? { note: `Summer Engine plays video only as Ogg Theora (.ogv), so the video was imported as ${importPath}. Load it from that path.` }
133
+ : {}),
125
134
  assetId: asset.id,
126
135
  asset: asset.title,
127
136
  type: asset.type,
@@ -639,6 +639,6 @@ export async function captureGameplay(input, overrides = {}) {
639
639
  ...(imported && importReason ? { importReason } : {}),
640
640
  durationMs: deps.now().getTime() - started.getTime(),
641
641
  ...(warnings.length ? { warnings } : {}),
642
- next: "Look at each frame before using it. For the store: upload with summer_upload_image_begin/complete and set them as desktop.screenshots or mobile.screenshots (summer_store_set_art). The game's own HUD may show; add no captions, logos or overlays.",
642
+ next: "Look at each frame before using it. For the store: upload with assets.upload_begin and assets.upload_complete and set them as desktop.screenshots or mobile.screenshots (store.set_art). The game's own HUD may show; add no captions, logos or overlays.",
643
643
  };
644
644
  }