summer-engine 4.3.0 → 4.6.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +3 -1
- package/.codex-plugin/plugin.json +5 -3
- package/.cursor-plugin/plugin.json +4 -2
- package/.factory-plugin/plugin.json +4 -2
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +100 -0
- package/README.md +67 -27
- package/commands/start.md +19 -15
- package/commands/summer.md +1 -0
- package/dist/cli/command-usage.d.ts +3 -1
- package/dist/cli/command-usage.js +10 -4
- package/dist/cli/commands/create.d.ts +1 -25
- package/dist/cli/commands/create.js +10 -138
- package/dist/cli/commands/dev.d.ts +66 -0
- package/dist/cli/commands/dev.js +234 -0
- package/dist/cli/commands/install.d.ts +15 -58
- package/dist/cli/commands/install.js +31 -481
- package/dist/cli/commands/login.js +1 -1
- package/dist/cli/commands/ops.d.ts +17 -1
- package/dist/cli/commands/ops.js +97 -9
- package/dist/cli/commands/preview.d.ts +58 -0
- package/dist/cli/commands/preview.js +181 -0
- package/dist/cli/commands/run.d.ts +1 -17
- package/dist/cli/commands/run.js +17 -206
- package/dist/cli/commands/setup.js +175 -32
- package/dist/cli/index.js +5 -0
- package/dist/core/agent-host.d.ts +3 -0
- package/dist/core/agent-host.js +1 -1
- package/dist/core/api-client.d.ts +10 -2
- package/dist/core/api-client.js +13 -8
- package/dist/core/capabilities/agent-playbook.js +1 -0
- package/dist/core/capabilities/apps.d.ts +9 -9
- package/dist/core/capabilities/asset-import.d.ts +4 -1
- package/dist/core/capabilities/asset-import.js +15 -6
- package/dist/core/capabilities/capture-gameplay.js +1 -1
- package/dist/core/capabilities/connect-signal.d.ts +2 -2
- package/dist/core/capabilities/content-make/index.d.ts +81 -0
- package/dist/core/capabilities/content-make/index.js +706 -0
- package/dist/core/capabilities/content-make/media.d.ts +57 -0
- package/dist/core/capabilities/content-make/media.js +172 -0
- package/dist/core/capabilities/content-make/plan.d.ts +130 -0
- package/dist/core/capabilities/content-make/plan.js +433 -0
- package/dist/core/capabilities/content-make/render.d.ts +64 -0
- package/dist/core/capabilities/content-make/render.js +370 -0
- package/dist/core/capabilities/content-make/study.d.ts +13 -0
- package/dist/core/capabilities/content-make/study.js +165 -0
- package/dist/core/capabilities/content-make/types.d.ts +173 -0
- package/dist/core/capabilities/content-make/types.js +6 -0
- package/dist/core/capabilities/content-make/voice.d.ts +7 -0
- package/dist/core/capabilities/content-make/voice.js +27 -0
- package/dist/core/capabilities/events.d.ts +2 -2
- package/dist/core/capabilities/export-game.d.ts +4 -1
- package/dist/core/capabilities/export-game.js +4 -3
- package/dist/core/capabilities/export-presets.d.ts +2 -1
- package/dist/core/capabilities/export-presets.js +2 -1
- package/dist/core/capabilities/go-live.d.ts +14 -0
- package/dist/core/capabilities/go-live.js +408 -0
- package/dist/core/capabilities/image-generation.d.ts +6 -6
- package/dist/core/capabilities/item-manifest.d.ts +92 -0
- package/dist/core/capabilities/item-manifest.js +247 -0
- package/dist/core/capabilities/placement.d.ts +7 -7
- package/dist/core/capabilities/projects-local.d.ts +68 -0
- package/dist/core/capabilities/projects-local.js +172 -0
- package/dist/core/capabilities/publish-build.d.ts +13 -2
- package/dist/core/capabilities/publish-build.js +87 -21
- package/dist/core/capabilities/publish-download.js +1 -1
- package/dist/core/capabilities/runtime-control.d.ts +7 -2
- package/dist/core/capabilities/runtime-control.js +27 -1
- package/dist/core/capabilities/seeing/args.d.ts +2 -2
- package/dist/core/capabilities/store-checks.d.ts +45 -0
- package/dist/core/capabilities/store-checks.js +85 -0
- package/dist/core/capabilities/store-details.d.ts +37 -0
- package/dist/core/capabilities/store-details.js +94 -0
- package/dist/core/capabilities/summer-bundle.d.ts +21 -2
- package/dist/core/capabilities/summer-bundle.js +54 -7
- package/dist/core/capabilities/sync-items.d.ts +89 -0
- package/dist/core/capabilities/sync-items.js +352 -0
- package/dist/core/capabilities/tool-dispatch.js +66 -6
- package/dist/core/capabilities/video-ogv.d.ts +49 -0
- package/dist/core/capabilities/video-ogv.js +260 -0
- package/dist/core/capability-skew.js +2 -2
- package/dist/core/cli-usage-beacon.js +26 -2
- package/dist/core/cli-usage.d.ts +5 -2
- package/dist/core/cli-usage.js +8 -2
- package/dist/core/engine-install.d.ts +53 -0
- package/dist/core/engine-install.js +93 -0
- package/dist/core/engine-installer.d.ts +134 -0
- package/dist/core/engine-installer.js +760 -0
- package/dist/core/engine-launch.d.ts +126 -0
- package/dist/core/engine-launch.js +398 -0
- package/dist/core/engine-self-start.d.ts +63 -0
- package/dist/core/engine-self-start.js +282 -0
- package/dist/core/engine.d.ts +7 -1
- package/dist/core/engine.js +9 -2
- package/dist/core/error-codes.d.ts +4 -1
- package/dist/core/error-codes.js +7 -3
- package/dist/core/library-read.d.ts +2 -2
- package/dist/core/library-search.d.ts +2 -2
- package/dist/core/local-project.d.ts +50 -0
- package/dist/core/local-project.js +234 -0
- package/dist/core/ops/areas.js +9 -3
- package/dist/core/ops/catalog.d.ts +9 -0
- package/dist/core/ops/catalog.js +56 -4
- package/dist/core/ops/engine-answer.d.ts +4 -1
- package/dist/core/ops/engine-answer.js +16 -3
- package/dist/core/ops/engine.js +4 -4
- package/dist/core/ops/save-files.d.ts +6 -1
- package/dist/core/ops/save-files.js +67 -50
- package/dist/core/ops/search.js +9 -2
- package/dist/core/preview/input.d.ts +35 -0
- package/dist/core/preview/input.js +105 -0
- package/dist/core/preview/launch-config.d.ts +52 -0
- package/dist/core/preview/launch-config.js +137 -0
- package/dist/core/preview/page.d.ts +22 -0
- package/dist/core/preview/page.js +232 -0
- package/dist/core/preview/preview-source.d.ts +179 -0
- package/dist/core/preview/preview-source.js +350 -0
- package/dist/core/preview/server.d.ts +26 -0
- package/dist/core/preview/server.js +218 -0
- package/dist/core/telemetry.d.ts +20 -16
- package/dist/core/telemetry.js +92 -16
- package/dist/core/templates.d.ts +20 -0
- package/dist/core/templates.js +300 -3
- package/dist/core/tool-profiles.d.ts +2 -2
- package/dist/core/tool-profiles.js +1 -0
- package/dist/core/usage-fields.d.ts +41 -0
- package/dist/core/usage-fields.js +150 -0
- package/dist/core/util/sleep.d.ts +3 -0
- package/dist/core/util/sleep.js +12 -0
- package/dist/installer/agent-config.d.ts +29 -0
- package/dist/installer/agent-config.js +75 -11
- package/dist/installer/agent-detect.d.ts +44 -0
- package/dist/installer/agent-detect.js +166 -0
- package/dist/installer/agent-table.d.ts +19 -0
- package/dist/installer/agent-table.js +130 -0
- package/dist/installer/setup-error.d.ts +19 -0
- package/dist/installer/setup-error.js +34 -0
- package/dist/installer/version-check.d.ts +5 -0
- package/dist/installer/version-check.js +21 -0
- package/dist/mcp/ops-surface.d.ts +7 -0
- package/dist/mcp/ops-surface.js +40 -3
- package/dist/mcp/server.d.ts +14 -4
- package/dist/mcp/server.js +42 -8
- package/dist/mcp/tool-surface.d.ts +8 -0
- package/dist/mcp/tool-surface.js +19 -2
- package/dist/mcp/tools/creator-tools.js +92 -14
- package/dist/mcp/tools/debug-tools.js +2 -0
- package/dist/mcp/tools/local-project-tools.d.ts +6 -0
- package/dist/mcp/tools/local-project-tools.js +33 -0
- package/dist/mcp/tools/navigation-tools.js +2 -1
- package/dist/mcp/tools/project-tools.js +5 -8
- package/dist/mcp/tools/seeing-tools.js +1 -1
- package/dist/mcp/tools/visual-tools.js +1 -1
- package/dist/mcp/tools/with-engine.js +1 -1
- package/dist/project-memory/agent-instructions.js +11 -3
- package/gemini-extension.json +3 -1
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +18 -5
- package/library/skills/README.md +12 -8
- package/library/skills/animated-loop/SKILL.md +10 -16
- package/library/skills/cinematic-cutscene/SKILL.md +7 -18
- package/library/skills/headless-scripting/SKILL.md +7 -4
- package/library/skills/in-game-purchases/SKILL.md +25 -8
- package/library/skills/in-game-purchases/resource.yaml +2 -1
- package/library/skills/launch-ready/SKILL.md +351 -0
- package/library/skills/launch-ready/resource.yaml +45 -0
- package/library/skills/make-content/SKILL.md +202 -0
- package/library/skills/make-content/resource.yaml +32 -0
- package/library/skills/make-game/SKILL.md +6 -4
- package/library/skills/make-game/resource.yaml +2 -1
- package/library/skills/navigate-summer/SKILL.md +4 -2
- package/library/skills/new-project/SKILL.md +15 -22
- package/library/skills/new-project/resource.yaml +2 -1
- package/library/skills/painted-25d-world/SKILL.md +366 -0
- package/library/skills/painted-25d-world/_building-blocks/blender-route.md +33 -0
- package/library/skills/painted-25d-world/_building-blocks/blockout_builder.gd +149 -0
- package/library/skills/painted-25d-world/_building-blocks/capture_paint_view.gd +32 -0
- package/library/skills/painted-25d-world/_building-blocks/paint_projection.gdshader +23 -0
- package/library/skills/painted-25d-world/_building-blocks/paintcam_check.gd +25 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_door.gd +17 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_location.gd +56 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_player.gd +125 -0
- package/library/skills/painted-25d-world/_building-blocks/painted_world.gd +111 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/cam.py +57 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/detail4k.py +81 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/overlay.py +17 -0
- package/library/skills/painted-25d-world/_building-blocks/tools/preview.py +60 -0
- package/library/skills/painted-25d-world/resource.yaml +39 -0
- package/library/skills/publish-your-game/SKILL.md +13 -14
- package/library/skills/publish-your-game/resource.yaml +4 -3
- package/library/skills/release-checklist/SKILL.md +188 -0
- package/library/skills/release-checklist/resource.yaml +40 -0
- package/library/skills/release-readiness/SKILL.md +1 -1
- package/library/skills/release-readiness/resource.yaml +1 -1
- package/library/skills/store-art/SKILL.md +1 -1
- package/library/skills/store-art/resource.yaml +1 -1
- package/library/skills/store-listing/SKILL.md +1 -1
- package/library/skills/store-listing/resource.yaml +1 -1
- package/library/skills/summer-cli/SKILL.md +2 -0
- package/library/skills/summer-store/SKILL.md +295 -39
- package/library/skills/summer-store/resource.yaml +9 -3
- package/library/skills/trailer-shot/SKILL.md +3 -3
- package/library/templates/README.md +5 -0
- package/library/tools/content-make/resource.yaml +132 -0
- package/library/tools/frame-shot/GUIDE.md +1 -1
- package/library/tools/go-live/resource.yaml +67 -0
- package/library/tools/import-from-url/GUIDE.md +1 -0
- package/library/tools/import-from-url-batch/GUIDE.md +1 -1
- package/library/tools/play/GUIDE.md +2 -0
- package/library/tools/projects-create-local/resource.yaml +55 -0
- package/library/tools/projects-open-local/resource.yaml +51 -0
- package/library/tools/publish-build/resource.yaml +3 -3
- package/library/tools/screenshot/GUIDE.md +1 -1
- package/library/tools/store-set-details/resource.yaml +114 -0
- package/library/tools/sync-items/resource.yaml +72 -0
- package/package.json +1 -1
- package/registry/generated/aliases.json +6 -0
- package/registry/generated/counts.json +3 -3
- package/registry/generated/gemini-extension.json +3 -1
- package/registry/generated/index.json +463 -37
- package/registry/generated/marketplace.claude.json +1 -1
- package/registry/generated/plugin.claude-directory.json +4 -2
- package/registry/generated/plugin.claude.json +3 -1
- package/registry/generated/plugin.codex.json +5 -3
- package/registry/generated/plugin.cursor.json +4 -2
- package/registry/generated/plugin.factory.json +4 -2
- package/registry/generated/server.json +2 -2
- package/registry/generated/skills-index.md +12 -8
- package/registry/generated/skills-registry.json +62 -5
- package/registry/operations/legacy-names.json +40 -0
- package/registry/operations/public-catalog.json +10144 -387
|
@@ -2,8 +2,10 @@ import { spawnSync } from "child_process";
|
|
|
2
2
|
import { existsSync, readFileSync } from "fs";
|
|
3
3
|
import { relative } from "path";
|
|
4
4
|
import { Command, Option } from "commander";
|
|
5
|
-
import { configureAgentMcp, configureSummerGamesMcp, resolveAgentSelection, resolveConfigScope, supportedAgents, } from "../../installer/agent-config.js";
|
|
5
|
+
import { configureAgentMcp, configureSummerGamesMcp, resolveAgentSelection, resolveBundledRuntime, resolveConfigScope, supportedAgents, } from "../../installer/agent-config.js";
|
|
6
6
|
import { previewNote, setupSkills } from "../../installer/setup.js";
|
|
7
|
+
import { detectAgents } from "../../installer/agent-detect.js";
|
|
8
|
+
import { SetupError, toStepError } from "../../installer/setup-error.js";
|
|
7
9
|
import { printDoctorResult, runDoctor } from "../../core/capabilities/doctor.js";
|
|
8
10
|
import { brandLine, c, sym, tildeify } from "../../core/format.js";
|
|
9
11
|
import { TOOLKIT_VERSION as cliVersion } from "../../core/version.js";
|
|
@@ -23,6 +25,8 @@ const MCP_ENTRY_FLAGS = [
|
|
|
23
25
|
["localDev", "--local-dev"],
|
|
24
26
|
["channel", "--channel"],
|
|
25
27
|
["profile", "--profile"],
|
|
28
|
+
["runtime", "--runtime"],
|
|
29
|
+
["packageDir", "--package-dir"],
|
|
26
30
|
];
|
|
27
31
|
export const setupCommand = new Command("setup")
|
|
28
32
|
.description("Configure Summer Engine for an AI agent and run diagnostics. For agents that can sign in to it, it also adds Summer Games (summer-games). --cli installs the skills only: the agent runs summer commands in its shell, with no MCP server.")
|
|
@@ -32,6 +36,9 @@ export const setupCommand = new Command("setup")
|
|
|
32
36
|
.option("--dry-run", "Show planned changes without writing files")
|
|
33
37
|
.option("--print", "Print the MCP config snippet instead of writing files")
|
|
34
38
|
.option("--local-dev", "Point the agent at this checkout's built CLI (node <repo>/dist/bin/summer.js mcp) instead of npx summer-engine@latest — for testing unpublished builds. SUMMER_DEV=1 does the same.")
|
|
39
|
+
.option("--runtime <node>", "Run the MCP server with this node executable instead of npx: <node> <package-dir>/dist/bin/summer.js mcp. Needs --package-dir. For installers that ship their own Node.js")
|
|
40
|
+
.option("--package-dir <dir>", "The summer-engine package folder (package.json and dist/bin/summer.js) that --runtime runs")
|
|
41
|
+
.option("--detect", "List every supported agent: installed or not, its MCP config file, and whether it already lists summer-engine. Writes nothing; takes no agent. Use with --json")
|
|
35
42
|
.option("--channel <dist-tag>", "npm dist-tag or exact version the agent's MCP entry runs: npx -y summer-engine@<dist-tag> mcp (default latest; a CLI newer than npm latest pins next when next is this version, else this version). SUMMER_CHANNEL does the same.")
|
|
36
43
|
.option("--yes", "Apply practical setup steps without prompting")
|
|
37
44
|
.option("--no-games", "Do not add the Summer Games MCP (summer-games: friends, parties and messages as you, signed in through summer.games)")
|
|
@@ -49,8 +56,52 @@ export const setupCommand = new Command("setup")
|
|
|
49
56
|
// Pre-reversal opt-in, kept one release as a hidden no-op so old scripts still parse.
|
|
50
57
|
.addOption(new Option("--include-preview", "No-op: preview skills install by default").hideHelp())
|
|
51
58
|
.action(async (agentArg, opts) => {
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
if (opts.detect) {
|
|
60
|
+
runDetect(agentArg, opts);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!opts.json) {
|
|
64
|
+
await setupAgent(agentArg, opts);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// --json: one JSON document on stdout, also when setup cannot start.
|
|
68
|
+
try {
|
|
69
|
+
await setupAgent(agentArg, opts);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.log(JSON.stringify({ ok: false, error: toStepError(error, "setup_failed"), steps: [] }, null, 2));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Runs one step. With --json a throw becomes the step's coded error and the
|
|
78
|
+
* other steps still run; without it the throw ends setup as it always did.
|
|
79
|
+
*/
|
|
80
|
+
async function runStep(json, fallbackCode, run) {
|
|
81
|
+
if (!json)
|
|
82
|
+
return { value: await run() };
|
|
83
|
+
try {
|
|
84
|
+
return { value: await run() };
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return { value: null, error: toStepError(error, fallbackCode) };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function setupAgent(agentArg, opts) {
|
|
91
|
+
let agent;
|
|
92
|
+
try {
|
|
93
|
+
agent = resolveAgentSelection(agentArg, opts.agent);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw new SetupError("unknown_agent", error instanceof Error ? error.message : String(error));
|
|
97
|
+
}
|
|
98
|
+
let scope;
|
|
99
|
+
try {
|
|
100
|
+
scope = resolveConfigScope(opts.scope);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new SetupError("invalid_scope", error instanceof Error ? error.message : String(error));
|
|
104
|
+
}
|
|
54
105
|
if (opts.removeAllowRules) {
|
|
55
106
|
await removeCliAllowRules(agent, scope, opts);
|
|
56
107
|
return;
|
|
@@ -63,8 +114,14 @@ export const setupCommand = new Command("setup")
|
|
|
63
114
|
if (opts.allowRules)
|
|
64
115
|
console.error(` ${sym.warn()} ${c.yellow("--allow-rules works with --cli only (the MCP server asks through the agent's own tool approvals); no rules were added.")}`);
|
|
65
116
|
const profile = resolveSetupProfile(opts);
|
|
66
|
-
const
|
|
67
|
-
|
|
117
|
+
const runtime = resolveBundledRuntime(opts.runtime, opts.packageDir);
|
|
118
|
+
if (runtime && (opts.localDev || opts.channel)) {
|
|
119
|
+
throw new SetupError("invalid_option", `--runtime runs a bundled summer-engine; leave out ${opts.localDev ? "--local-dev" : "--channel"}.`);
|
|
120
|
+
}
|
|
121
|
+
const json = Boolean(opts.json);
|
|
122
|
+
// A bundled runtime runs the package beside it, so npm's tags do not matter (and no network call is made).
|
|
123
|
+
const defaultChannel = runtime ? { channel: "latest" } : await resolveDefaultChannel(cliVersion);
|
|
124
|
+
const mcp = await runStep(json, "mcp_entry_failed", () => configureAgentMcp({
|
|
68
125
|
agent,
|
|
69
126
|
scope,
|
|
70
127
|
dryRun: opts.dryRun,
|
|
@@ -72,14 +129,19 @@ export const setupCommand = new Command("setup")
|
|
|
72
129
|
localDev: Boolean(opts.localDev) || process.env.SUMMER_DEV === "1",
|
|
73
130
|
channel: opts.channel ?? process.env.SUMMER_CHANNEL ?? defaultChannel.channel,
|
|
74
131
|
profile,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
132
|
+
runtime: runtime ?? undefined,
|
|
133
|
+
}));
|
|
134
|
+
const config = mcp.value;
|
|
135
|
+
const gamesSkipped = opts.games === false || opts.assetsOnly || opts.print;
|
|
136
|
+
const gamesStep = gamesSkipped
|
|
137
|
+
? { value: null }
|
|
138
|
+
: await runStep(json, "summer_games_failed", () => configureSummerGamesMcp({ agent, scope, dryRun: opts.dryRun }));
|
|
139
|
+
const games = gamesStep.value;
|
|
140
|
+
if (!runtime && !opts.channel && !process.env.SUMMER_CHANNEL && defaultChannel.note && !opts.print) {
|
|
141
|
+
// On stderr with --json, so stdout stays one JSON document.
|
|
142
|
+
(json ? console.error : console.log)(` ${c.dim(defaultChannel.note)}`);
|
|
143
|
+
}
|
|
144
|
+
const skillsStep = await runStep(json, "skills_install_failed", () => setupSkills(agent, {
|
|
83
145
|
dryRun: Boolean(opts.dryRun || opts.print),
|
|
84
146
|
yes: Boolean(opts.yes),
|
|
85
147
|
force: Boolean(opts.force),
|
|
@@ -87,26 +149,104 @@ export const setupCommand = new Command("setup")
|
|
|
87
149
|
recommended: Boolean(opts.recommended),
|
|
88
150
|
stableOnly: Boolean(opts.stableOnly),
|
|
89
151
|
assetsOnly: Boolean(opts.assetsOnly),
|
|
90
|
-
});
|
|
91
|
-
const
|
|
152
|
+
}));
|
|
153
|
+
const skills = skillsStep.value ?? { status: "failed", message: skillsStep.error?.message ?? "Skill install failed." };
|
|
154
|
+
const projectStep = await runStep(json, "project_files_failed", () => setupProjectInstructions(opts));
|
|
155
|
+
const projectFiles = projectStep.value;
|
|
92
156
|
const doctor = await runDoctor({ quiet: true });
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
157
|
+
if (json) {
|
|
158
|
+
const steps = [
|
|
159
|
+
mcpEntryStep(config, mcp.error),
|
|
160
|
+
summerGamesStep(agent, games, gamesSkipped ? "skipped" : null, gamesStep.error, Boolean(opts.dryRun)),
|
|
161
|
+
skillsStepResult(skills, skillsStep.error),
|
|
162
|
+
projectFilesStep(projectFiles, projectStep.error, opts),
|
|
163
|
+
doctorStep(doctor),
|
|
164
|
+
];
|
|
165
|
+
const ok = steps.every((step) => step.ok);
|
|
166
|
+
console.log(JSON.stringify({ ok, agent, scope, steps, config, games, skills, projectFiles, doctor }, null, 2));
|
|
167
|
+
if (!ok)
|
|
168
|
+
process.exit(1);
|
|
169
|
+
return;
|
|
105
170
|
}
|
|
171
|
+
printSetupResult(config, games, skills, doctor, projectFiles);
|
|
106
172
|
if (!doctor.ok || skills.status === "failed") {
|
|
107
173
|
process.exit(1);
|
|
108
174
|
}
|
|
109
|
-
}
|
|
175
|
+
}
|
|
176
|
+
function mcpEntryStep(config, error) {
|
|
177
|
+
if (!config)
|
|
178
|
+
return { step: "mcp_entry", ok: false, status: "failed", error: error ?? { code: "mcp_entry_failed", message: "The MCP entry was not written." } };
|
|
179
|
+
const status = config.print ? "printed" : config.dryRun ? (config.changed ? "planned" : "unchanged") : config.wrote ? "written" : "unchanged";
|
|
180
|
+
return { step: "mcp_entry", ok: true, status, path: config.path, ...(config.warnings.length ? { warnings: config.warnings } : {}) };
|
|
181
|
+
}
|
|
182
|
+
function summerGamesStep(agent, games, skipped, error, dryRun) {
|
|
183
|
+
if (error)
|
|
184
|
+
return { step: "summer_games", ok: false, status: "failed", error };
|
|
185
|
+
if (skipped)
|
|
186
|
+
return { step: "summer_games", ok: true, status: "skipped" };
|
|
187
|
+
// configureSummerGamesMcp returns null only for agents without a Summer Games entry shape.
|
|
188
|
+
if (!games)
|
|
189
|
+
return { step: "summer_games", ok: true, status: "not_supported", warnings: [`${agentLabel(agent)} gets no Summer Games entry from setup.`] };
|
|
190
|
+
const status = games.existingName ? "exists" : dryRun ? (games.changed ? "planned" : "unchanged") : games.wrote ? "written" : "unchanged";
|
|
191
|
+
return { step: "summer_games", ok: true, status, path: games.path };
|
|
192
|
+
}
|
|
193
|
+
function skillsStepResult(skills, error) {
|
|
194
|
+
if (skills.status === "failed") {
|
|
195
|
+
return {
|
|
196
|
+
step: "skills",
|
|
197
|
+
ok: false,
|
|
198
|
+
status: "failed",
|
|
199
|
+
error: error ?? { code: "skills_install_failed", message: [skills.message, skills.stderr].filter(Boolean).join(" ") },
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return { step: "skills", ok: true, status: skills.status, ...(skills.destination ? { path: skills.destination } : {}) };
|
|
203
|
+
}
|
|
204
|
+
function projectFilesStep(project, error, opts) {
|
|
205
|
+
if (error)
|
|
206
|
+
return { step: "project_files", ok: false, status: "failed", error };
|
|
207
|
+
if (!project) {
|
|
208
|
+
const skipped = opts.projectFiles === false || opts.print || opts.assetsOnly;
|
|
209
|
+
return { step: "project_files", ok: true, status: skipped ? "skipped" : "not_in_project" };
|
|
210
|
+
}
|
|
211
|
+
// A file setup leaves alone (a link out of the project, a broken Summer block) is a warning, as in the human output.
|
|
212
|
+
const warnings = project.files.filter((file) => file.reason).map((file) => `${file.path}: ${file.reason}`);
|
|
213
|
+
return { step: "project_files", ok: true, status: project.written ? "written" : "planned", path: project.root, ...(warnings.length ? { warnings } : {}) };
|
|
214
|
+
}
|
|
215
|
+
function doctorStep(doctor) {
|
|
216
|
+
if (doctor.ok)
|
|
217
|
+
return { step: "doctor", ok: true, status: "passed" };
|
|
218
|
+
const failed = doctor.checks.filter((check) => check.status === "fail");
|
|
219
|
+
return {
|
|
220
|
+
step: "doctor",
|
|
221
|
+
ok: false,
|
|
222
|
+
status: "failed",
|
|
223
|
+
error: { code: "doctor_failed", message: failed.map((check) => `${check.label}: ${check.message}`).join("; ") || "Doctor found a problem." },
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** `summer setup --detect`: every agent, installed or not, and whether it is linked. Writes nothing. */
|
|
227
|
+
function runDetect(agentArg, opts) {
|
|
228
|
+
if (agentArg || opts.agent) {
|
|
229
|
+
const message = "--detect lists every agent; leave out the agent name.";
|
|
230
|
+
if (!opts.json)
|
|
231
|
+
throw new Error(message);
|
|
232
|
+
console.log(JSON.stringify({ ok: false, error: { code: "invalid_option", message }, agents: [] }, null, 2));
|
|
233
|
+
process.exit(1);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const agents = detectAgents();
|
|
237
|
+
if (opts.json) {
|
|
238
|
+
console.log(JSON.stringify({ ok: true, os: process.platform, agents }, null, 2));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
console.log("");
|
|
242
|
+
for (const agent of agents) {
|
|
243
|
+
if (agent.status === "legacy" && !agent.installed)
|
|
244
|
+
continue;
|
|
245
|
+
const mark = agent.installed ? sym.ok() : c.dim("-");
|
|
246
|
+
const linked = agent.mcpEntry ? c.dim(`linked ${tildeify(agent.configPath)}`) : agent.installed ? c.dim(`not linked: summer setup ${agent.id}`) : c.dim("not found");
|
|
247
|
+
console.log(` ${mark} ${agent.label} ${linked}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
110
250
|
/**
|
|
111
251
|
* `summer setup <agent> --cli`: the skills (the asset skills with --assets-only)
|
|
112
252
|
* and no MCP server, so the agent runs Summer as `summer <area> <action>` in its
|
|
@@ -117,7 +257,7 @@ async function setupCliOnly(agent, scope, opts) {
|
|
|
117
257
|
const spec = agentSpec(agent);
|
|
118
258
|
const mcpFlags = MCP_ENTRY_FLAGS.filter(([key]) => opts[key] !== undefined && opts[key] !== false).map(([, flag]) => flag);
|
|
119
259
|
if (mcpFlags.length > 0) {
|
|
120
|
-
throw new
|
|
260
|
+
throw new SetupError("invalid_option", `${mcpFlags.join(", ")} sets up the MCP entry, and --cli writes none. Leave ${mcpFlags.length === 1 ? "it" : "them"} out, or leave out --cli.`);
|
|
121
261
|
}
|
|
122
262
|
const refusal = cliSetupRefusal(spec);
|
|
123
263
|
if (refusal)
|
|
@@ -278,11 +418,11 @@ async function recordedMcpEntry(agent, scope) {
|
|
|
278
418
|
function resolveSetupProfile(opts) {
|
|
279
419
|
const profile = opts.profile === undefined ? undefined : parseProfile(opts.profile);
|
|
280
420
|
if (profile === null) {
|
|
281
|
-
throw new
|
|
421
|
+
throw new SetupError("invalid_option", `Unknown --profile "${opts.profile}". Use one of: ${Object.keys(PROFILES).join(", ")}.`);
|
|
282
422
|
}
|
|
283
423
|
if (opts.assetsOnly) {
|
|
284
424
|
if (profile && profile !== "assets")
|
|
285
|
-
throw new
|
|
425
|
+
throw new SetupError("invalid_option", "--assets-only uses the assets profile; leave out --profile.");
|
|
286
426
|
return "assets";
|
|
287
427
|
}
|
|
288
428
|
return profile;
|
|
@@ -305,7 +445,10 @@ function printSetupResult(config, games, skills, doctor, projectFiles) {
|
|
|
305
445
|
else {
|
|
306
446
|
console.log(` ${sym.ok()} Already linked to ${c.bold(label)} ${c.dim(tildeify(config.path))}`);
|
|
307
447
|
}
|
|
308
|
-
if (config.
|
|
448
|
+
if (config.runtime) {
|
|
449
|
+
console.log(` ${c.dim("(bundled runtime)")} MCP server command: ${c.dim(`${config.server.command} ${config.server.args.join(" ")}`)}`);
|
|
450
|
+
}
|
|
451
|
+
else if (config.localDev) {
|
|
309
452
|
console.log(` ${c.dim("(local dev)")} MCP server command: ${c.dim(`${config.server.command} ${config.server.args.join(" ")}`)}`);
|
|
310
453
|
}
|
|
311
454
|
else if (config.channel !== "latest") {
|
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,6 +16,7 @@ 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";
|
|
@@ -36,6 +38,7 @@ export function runCli(mcpCommand) {
|
|
|
36
38
|
.action((_opts, command) => {
|
|
37
39
|
runRootAction(command.args, () => printIntro(version));
|
|
38
40
|
});
|
|
41
|
+
program.addCommand(devCommand);
|
|
39
42
|
program.addCommand(installCommand);
|
|
40
43
|
program.addCommand(loginCommand);
|
|
41
44
|
program.addCommand(logoutCommand);
|
|
@@ -53,6 +56,7 @@ export function runCli(mcpCommand) {
|
|
|
53
56
|
program.addCommand(planCommand);
|
|
54
57
|
program.addCommand(configCommand);
|
|
55
58
|
program.addCommand(eventsCommand);
|
|
59
|
+
program.addCommand(previewCommand);
|
|
56
60
|
program.addCommand(toolCommand);
|
|
57
61
|
// The 4.0 operation catalog (`summer <area> <action>`); SUMMER_SURFACE=v3 leaves it out.
|
|
58
62
|
if (resolveSurface(undefined) === "v4") {
|
|
@@ -76,6 +80,7 @@ function printIntro(version) {
|
|
|
76
80
|
console.log(` ${c.brand("\"Install Summer Engine and let's make a game.\"")}`);
|
|
77
81
|
console.log("");
|
|
78
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")}`);
|
|
79
84
|
console.log(` ${c.dim("$")} npx -y summer-engine@latest setup claude-code --yes`);
|
|
80
85
|
console.log(` ${c.dim("$")} npx -y summer-engine@latest create 3d-basic my-game`);
|
|
81
86
|
console.log(` ${c.dim("$")} npx -y summer-engine@latest plan make a small arena shooter`);
|
|
@@ -52,6 +52,9 @@ export declare function resolveAgentHost(env?: Env, client?: McpClientInfo | und
|
|
|
52
52
|
interface ToolContext {
|
|
53
53
|
tool: string;
|
|
54
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>;
|
|
55
58
|
}
|
|
56
59
|
/** Run one tool call so every Summer request it makes names the tool and surface. */
|
|
57
60
|
export declare function runWithToolContext<T>(tool: string, surface: ClientSurface, fn: () => T): T;
|
package/dist/core/agent-host.js
CHANGED
|
@@ -160,7 +160,7 @@ export function resolveAgentHost(env = process.env, client = currentMcpClient())
|
|
|
160
160
|
const toolContext = new AsyncLocalStorage();
|
|
161
161
|
/** Run one tool call so every Summer request it makes names the tool and surface. */
|
|
162
162
|
export function runWithToolContext(tool, surface, fn) {
|
|
163
|
-
return toolContext.run({ tool, surface }, fn);
|
|
163
|
+
return toolContext.run({ tool, surface, usage: toolContext.getStore()?.usage ?? {} }, fn);
|
|
164
164
|
}
|
|
165
165
|
/** The tool call running now, if any (a tool that runs inside another one sees the outer call). */
|
|
166
166
|
export function currentToolContext() {
|
|
@@ -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
|
package/dist/core/api-client.js
CHANGED
|
@@ -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: "
|
|
21
|
+
section: "examples" | "all" | "kit" | "layout" | "manifest" | "overview" | "sdk" | "design" | "types";
|
|
22
22
|
}, {
|
|
23
|
-
section?: "
|
|
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" | "
|
|
115
|
+
kinds?: ("error" | "tool" | "agent" | "feedback")[] | undefined;
|
|
116
116
|
}, {
|
|
117
117
|
appId: string;
|
|
118
|
-
kinds?: ("error" | "
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
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
|
}
|
|
@@ -43,14 +43,14 @@ export declare const connectSignalInputSchema: z.ZodObject<{
|
|
|
43
43
|
method: z.ZodString;
|
|
44
44
|
}, "strict", z.ZodTypeAny, {
|
|
45
45
|
method: string;
|
|
46
|
-
scenePath: string;
|
|
47
46
|
signal: string;
|
|
47
|
+
scenePath: string;
|
|
48
48
|
emitter: string;
|
|
49
49
|
receiver: string;
|
|
50
50
|
}, {
|
|
51
51
|
method: string;
|
|
52
|
-
scenePath: string;
|
|
53
52
|
signal: string;
|
|
53
|
+
scenePath: string;
|
|
54
54
|
emitter: string;
|
|
55
55
|
receiver: string;
|
|
56
56
|
}>;
|