summer-engine 2.6.6 → 2.8.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 +4 -1
- package/.codex-plugin/plugin.json +6 -2
- package/.cursor-plugin/plugin.json +5 -1
- package/.opencode/INSTALL.md +1 -1
- package/.opencode/plugins/summer.js +2 -2
- package/AGENTS.md +11 -7
- package/CHANGELOG.md +40 -0
- package/GEMINI.md +9 -7
- package/README.md +63 -21
- package/_persona/summer/SKILL.md +1 -0
- package/assets/autopilot/README.md +51 -0
- package/assets/autopilot/autopilot.gd +222 -0
- package/assets/autopilot/probe_base.gd +262 -0
- package/assets/autopilot/run.sh +78 -0
- package/commands/gameskill.md +11 -2
- package/commands/summer.md +13 -0
- package/dist/bin/summer.js +12 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +53 -0
- package/dist/commands/create.d.ts +1 -0
- package/dist/commands/create.js +38 -6
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +44 -0
- package/dist/commands/doctor.js +112 -8
- package/dist/commands/list.js +1 -1
- package/dist/commands/login.d.ts +19 -0
- package/dist/commands/login.js +123 -36
- package/dist/commands/logout.js +3 -16
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +19 -0
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/open.js +1 -1
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +20 -0
- package/dist/commands/releases.d.ts +2 -0
- package/dist/commands/releases.js +20 -0
- package/dist/commands/run.js +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/lib/api-client.d.ts +15 -4
- package/dist/lib/api-client.js +138 -13
- package/dist/lib/async-op-lifecycle.d.ts +7 -2
- package/dist/lib/async-op-lifecycle.js +32 -9
- package/dist/lib/auth.d.ts +40 -12
- package/dist/lib/auth.js +173 -37
- package/dist/lib/cloud/engine-bridge.d.ts +17 -4
- package/dist/lib/cloud/engine-bridge.js +32 -6
- package/dist/lib/config.d.ts +20 -0
- package/dist/lib/config.js +142 -0
- package/dist/lib/creator.d.ts +93 -0
- package/dist/lib/creator.js +393 -0
- package/dist/lib/debug-report.d.ts +50 -0
- package/dist/lib/debug-report.js +308 -0
- package/dist/lib/engine.d.ts +35 -2
- package/dist/lib/engine.js +240 -6
- package/dist/lib/game-task-plan.js +4 -4
- package/dist/lib/mcp-boot-notice.d.ts +3 -0
- package/dist/lib/mcp-boot-notice.js +7 -0
- package/dist/lib/mcp-log.d.ts +3 -0
- package/dist/lib/mcp-log.js +72 -0
- package/dist/lib/public-surface-paths.d.ts +13 -0
- package/dist/lib/public-surface-paths.js +42 -0
- package/dist/lib/skills-registry.d.ts +33 -1
- package/dist/lib/skills-registry.js +55 -0
- package/dist/lib/store.d.ts +14 -0
- package/dist/lib/store.js +145 -0
- package/dist/lib/summer-compatibility.d.ts +6 -0
- package/dist/lib/summer-compatibility.js +22 -0
- package/dist/mcp/server.d.ts +10 -3
- package/dist/mcp/server.js +104 -11
- package/dist/mcp/tools/asset-tools.js +33 -12
- package/dist/mcp/tools/cloud-tools.js +15 -15
- package/dist/mcp/tools/creator-tools.d.ts +2 -0
- package/dist/mcp/tools/creator-tools.js +105 -0
- package/dist/mcp/tools/debug-tools.js +44 -1
- package/dist/mcp/tools/file-tools.d.ts +2 -0
- package/dist/mcp/tools/file-tools.js +154 -0
- package/dist/mcp/tools/generate-tools.js +159 -11
- package/dist/mcp/tools/project-tools.js +37 -27
- package/dist/mcp/tools/scene-tools.js +106 -29
- package/dist/mcp/tools/visual-tools.js +4 -3
- package/dist/mcp/tools/with-engine.js +4 -4
- package/hooks/session-start.sh +5 -5
- package/package.json +3 -1
- package/references/collaborative-protocol.md +50 -0
- package/references/gd-style.md +121 -0
- package/references/godot-version.md +51 -0
- package/references/mcp-tools-reference.md +199 -0
- package/references/public-surface-language.md +30 -0
- package/references/summer-folder.md +90 -0
- package/references/template-registry.md +73 -0
- package/skills/2d-assets/character-portrait/SKILL.md +17 -12
- package/skills/2d-assets/concept-art/SKILL.md +10 -9
- package/skills/2d-assets/create-asset-sheet/SKILL.md +17 -15
- package/skills/2d-assets/pixel-art/SKILL.md +36 -20
- package/skills/2d-assets/skybox-panorama/SKILL.md +32 -37
- package/skills/2d-assets/sprite-sheet/SKILL.md +40 -35
- package/skills/2d-assets/tileable-texture/SKILL.md +28 -22
- package/skills/2d-assets/ui-graphics/SKILL.md +46 -32
- package/skills/2d-assets/use-widget-asset/SKILL.md +8 -6
- package/skills/3d-assets/character-model/SKILL.md +34 -19
- package/skills/3d-assets/environment-kit/SKILL.md +11 -5
- package/skills/3d-assets/organic-model/SKILL.md +8 -5
- package/skills/3d-assets/prop-model/SKILL.md +9 -3
- package/skills/3d-assets/vehicle-model/SKILL.md +32 -19
- package/skills/README.md +1 -1
- package/skills/ai-and-npcs/design-npc/SKILL.md +31 -13
- package/skills/animation/animation-tree/SKILL.md +39 -15
- package/skills/animation/facial-and-lipsync/SKILL.md +25 -8
- package/skills/animation/generate-motion/SKILL.md +47 -15
- package/skills/animation/procedural-animation/SKILL.md +31 -13
- package/skills/animation/retarget/SKILL.md +127 -79
- package/skills/audio/adaptive-music/SKILL.md +24 -20
- package/skills/audio/ambient-bed/SKILL.md +22 -16
- package/skills/audio/audio-direction/SKILL.md +15 -10
- package/skills/audio/music-track/SKILL.md +18 -12
- package/skills/audio/sound-effect/SKILL.md +17 -12
- package/skills/audio/voice-line/SKILL.md +42 -42
- package/skills/character-controllers/fps-controller/SKILL.md +26 -16
- package/skills/debugging/debug/SKILL.md +74 -20
- package/skills/deployment/export-and-ship/SKILL.md +105 -38
- package/skills/deployment/remote-deploy/SKILL.md +140 -0
- package/skills/gameplay-mechanics/auto-fire-targeting/SKILL.md +26 -1
- package/skills/gameplay-mechanics/design-mechanic/SKILL.md +23 -15
- package/skills/level-design/design-level/SKILL.md +22 -8
- package/skills/level-design/scene-to-level/SKILL.md +13 -7
- package/skills/multiplayer-and-networking/host-authoritative-state/SKILL.md +8 -8
- package/skills/multiplayer-and-networking/peer-to-peer-multiplayer/SKILL.md +2 -7
- package/skills/multiplayer-and-networking/setup-multiplayer/SKILL.md +26 -18
- package/skills/performance/tune-performance/SKILL.md +51 -32
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +34 -5
- package/skills/rendering-and-lighting/art-direction/SKILL.md +6 -8
- package/skills/scene-and-project/brainstorm-game/SKILL.md +7 -9
- package/skills/scene-and-project/make-game/SKILL.md +2 -1
- package/skills/scene-and-project/play/SKILL.md +10 -4
- package/skills/scene-and-project/scene-composition/SKILL.md +21 -8
- package/skills/scene-and-project/summer-cloud/SKILL.md +92 -0
- package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
- package/skills/ui-and-ux/ui-basics/SKILL.md +16 -7
- package/skills/video/animated-loop/SKILL.md +63 -39
- package/skills/video/cinematic-cutscene/SKILL.md +66 -30
- package/skills/video/trailer-shot/SKILL.md +30 -21
- package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +25 -16
- package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +5 -3
- package/skills/visual-effects/game-feel/SKILL.md +51 -33
- package/skills/visual-effects/recipes/dissolve/SKILL.md +51 -9
- package/skills/visual-effects/recipes/fire/SKILL.md +136 -49
- package/skills/visual-effects/recipes/hit-spark/SKILL.md +45 -8
- package/skills/visual-effects/recipes/lightning/SKILL.md +59 -27
- package/skills/visual-effects/recipes/magic-glow/SKILL.md +59 -26
- package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +68 -25
- package/skills/visual-effects/recipes/smoke/SKILL.md +89 -28
- package/skills/visual-effects/recipes/water-ripple/SKILL.md +83 -23
- package/skills/workflow/brainstorming/SKILL.md +1 -1
- package/skills/workflow/debugging-game-feel/SKILL.md +29 -9
- package/skills/workflow/diagnosing-perf-regressions/SKILL.md +46 -21
- package/skills/workflow/gameskill/SKILL.md +11 -2
- package/skills/workflow/headless-scripting/SKILL.md +407 -0
- package/skills/workflow/investigating-bugs/SKILL.md +4 -2
- package/skills/workflow/mcpupdate/SKILL.md +9 -9
- package/skills/workflow/playtesting-a-feature/SKILL.md +94 -21
- package/skills/workflow/skill-create/SKILL.md +7 -7
- package/skills/workflow/skill-test/SKILL.md +3 -3
- package/skills/workflow/using-summer/SKILL.md +32 -3
- package/skills/workflow/verification-before-completion/SKILL.md +2 -0
- package/skills/workflow/writing-plans/SKILL.md +7 -7
- package/skills/workflow/writing-skills/SKILL.md +7 -5
- package/skills/workflow/writing-skills/testing-skills-with-subagents.md +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { getSummerDir } from "./auth.js";
|
|
5
|
+
const MAX_LOG_BYTES = 512 * 1024;
|
|
6
|
+
const RETAIN_LOG_BYTES = 256 * 1024;
|
|
7
|
+
export function getMcpLogPath() {
|
|
8
|
+
return join(getSummerDir(), "mcp.log");
|
|
9
|
+
}
|
|
10
|
+
function redact(value) {
|
|
11
|
+
if (Array.isArray(value))
|
|
12
|
+
return value.map((item) => redact(item));
|
|
13
|
+
if (!value || typeof value !== "object")
|
|
14
|
+
return value;
|
|
15
|
+
const out = {};
|
|
16
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
17
|
+
if (/token|secret|password|authorization|cookie|api[-_]?key/i.test(key)) {
|
|
18
|
+
out[key] = "[REDACTED]";
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
out[key] = redact(nested);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
function rotateIfNeeded(path) {
|
|
27
|
+
try {
|
|
28
|
+
if (statSync(path).size < MAX_LOG_BYTES)
|
|
29
|
+
return;
|
|
30
|
+
const text = readFileSync(path, "utf-8");
|
|
31
|
+
const retained = text.slice(-RETAIN_LOG_BYTES);
|
|
32
|
+
writeFileSync(path, `{"event":"mcp:log_rotated"}\n${retained}`, {
|
|
33
|
+
encoding: "utf-8",
|
|
34
|
+
mode: 0o600,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// No existing log, or not readable. The next append will recreate it.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function appendMcpLogEvent(event, details = {}) {
|
|
42
|
+
try {
|
|
43
|
+
const dir = getSummerDir();
|
|
44
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
45
|
+
const path = getMcpLogPath();
|
|
46
|
+
rotateIfNeeded(path);
|
|
47
|
+
const safeDetails = redact(details);
|
|
48
|
+
const payload = {
|
|
49
|
+
ts: new Date().toISOString(),
|
|
50
|
+
event,
|
|
51
|
+
...safeDetails,
|
|
52
|
+
};
|
|
53
|
+
appendFileSync(path, `${JSON.stringify(payload)}\n`, {
|
|
54
|
+
encoding: "utf-8",
|
|
55
|
+
mode: 0o600,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Logging must never affect MCP behavior.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function readRecentMcpLogLines(maxLines = 120) {
|
|
63
|
+
try {
|
|
64
|
+
const text = await readFile(getMcpLogPath(), "utf-8");
|
|
65
|
+
if (!text.trim())
|
|
66
|
+
return [];
|
|
67
|
+
return text.trimEnd().split(/\r?\n/).slice(-maxLines);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PathFlavor {
|
|
2
|
+
isAbsolute(path: string): boolean;
|
|
3
|
+
relative(from: string, to: string): string;
|
|
4
|
+
resolve(...paths: string[]): string;
|
|
5
|
+
sep: string;
|
|
6
|
+
}
|
|
7
|
+
export interface PublicSurfaceRoots {
|
|
8
|
+
packageRoot: string;
|
|
9
|
+
engineRoot: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function snapshotPublicPath(pathFlavor: PathFlavor, roots: PublicSurfaceRoots, file: string): string;
|
|
12
|
+
export declare function compareByCodePoint(left: string, right: string): number;
|
|
13
|
+
export declare function stablePublicPathInventory(pathFlavor: PathFlavor, roots: PublicSurfaceRoots, files: readonly string[]): string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
function relativeWithin(pathFlavor, root, file) {
|
|
2
|
+
const resolvedRoot = pathFlavor.resolve(root);
|
|
3
|
+
const resolvedFile = pathFlavor.resolve(file);
|
|
4
|
+
const candidate = pathFlavor.relative(resolvedRoot, resolvedFile);
|
|
5
|
+
if (pathFlavor.isAbsolute(candidate) ||
|
|
6
|
+
candidate === ".." ||
|
|
7
|
+
candidate.startsWith(`..${pathFlavor.sep}`)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return candidate;
|
|
11
|
+
}
|
|
12
|
+
function toPosix(pathFlavor, path) {
|
|
13
|
+
return path.split(pathFlavor.sep).join("/");
|
|
14
|
+
}
|
|
15
|
+
export function snapshotPublicPath(pathFlavor, roots, file) {
|
|
16
|
+
const packageRelative = relativeWithin(pathFlavor, roots.packageRoot, file);
|
|
17
|
+
if (packageRelative !== null) {
|
|
18
|
+
return `cli/${toPosix(pathFlavor, packageRelative)}`;
|
|
19
|
+
}
|
|
20
|
+
const engineRelative = relativeWithin(pathFlavor, roots.engineRoot, file);
|
|
21
|
+
if (engineRelative !== null) {
|
|
22
|
+
return `engine/${toPosix(pathFlavor, engineRelative)}`;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`Public surface escapes both inventory roots: ${file}`);
|
|
25
|
+
}
|
|
26
|
+
export function compareByCodePoint(left, right) {
|
|
27
|
+
const leftPoints = [...left].map((character) => character.codePointAt(0));
|
|
28
|
+
const rightPoints = [...right].map((character) => character.codePointAt(0));
|
|
29
|
+
const sharedLength = Math.min(leftPoints.length, rightPoints.length);
|
|
30
|
+
for (let index = 0; index < sharedLength; index += 1) {
|
|
31
|
+
if (leftPoints[index] !== rightPoints[index]) {
|
|
32
|
+
return leftPoints[index] - rightPoints[index];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return leftPoints.length - rightPoints.length;
|
|
36
|
+
}
|
|
37
|
+
export function stablePublicPathInventory(pathFlavor, roots, files) {
|
|
38
|
+
return files
|
|
39
|
+
.map((file) => snapshotPublicPath(pathFlavor, roots, file))
|
|
40
|
+
.sort(compareByCodePoint)
|
|
41
|
+
.join("\n");
|
|
42
|
+
}
|
|
@@ -23,7 +23,7 @@ export declare const SKILL_REGISTRY: readonly [{
|
|
|
23
23
|
readonly public: true;
|
|
24
24
|
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf", "cline", "roo-code", "kilo-code", "gemini", "github-copilot", "vscode-copilot", "opencode"];
|
|
25
25
|
readonly recommended: true;
|
|
26
|
-
readonly requiresMcpTools: readonly ["summer_get_console", "summer_get_debugger_errors", "summer_get_script_errors", "summer_get_diagnostics", "summer_clear_console", "summer_play", "summer_stop", "summer_inspect_node"];
|
|
26
|
+
readonly requiresMcpTools: readonly ["summer_create_debug_report", "summer_get_console", "summer_get_debugger_errors", "summer_get_script_errors", "summer_get_diagnostics", "summer_clear_console", "summer_play", "summer_stop", "summer_inspect_node"];
|
|
27
27
|
readonly testScenario: "Triage a runtime crash end-to-end: read errors, locate code, propose fix, apply on approval, verify.";
|
|
28
28
|
}, {
|
|
29
29
|
readonly name: "play";
|
|
@@ -49,6 +49,14 @@ export declare const SKILL_REGISTRY: readonly [{
|
|
|
49
49
|
readonly recommended: true;
|
|
50
50
|
readonly requiresMcpTools: readonly ["summer_create_scene", "summer_open_scene", "summer_get_scene_tree", "summer_add_node", "summer_instantiate_scene", "summer_save_scene"];
|
|
51
51
|
readonly testScenario: "Build a small reusable player scene, instantiate it in a main scene, and save both scenes through Summer tools.";
|
|
52
|
+
}, {
|
|
53
|
+
readonly name: "summer-cloud";
|
|
54
|
+
readonly category: "scene-and-project";
|
|
55
|
+
readonly public: true;
|
|
56
|
+
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf", "cline", "roo-code", "kilo-code", "gemini", "github-copilot", "vscode-copilot", "opencode"];
|
|
57
|
+
readonly recommended: true;
|
|
58
|
+
readonly requiresMcpTools: readonly ["summer_cloud_init", "summer_cloud_status", "summer_cloud_push", "summer_cloud_pull", "summer_cloud_restore", "summer_cloud_checkpoints", "summer_cloud_conflicts"];
|
|
59
|
+
readonly testScenario: "Enable Cloud for a project, push it, then pull it onto a second machine, taking the bootstrap choice and surfacing the delete count before any guarded deletion.";
|
|
52
60
|
}, {
|
|
53
61
|
readonly name: "fps-controller";
|
|
54
62
|
readonly category: "character-controllers";
|
|
@@ -201,6 +209,14 @@ export declare const SKILL_REGISTRY: readonly [{
|
|
|
201
209
|
readonly recommended: true;
|
|
202
210
|
readonly requiresMcpTools: readonly ["summer_get_scene_tree", "summer_inspect_node", "summer_project_setting", "summer_get_console", "summer_get_diagnostics"];
|
|
203
211
|
readonly testScenario: "Run the Steam pre-flight checklist (Windows + Mac + Linux), validate icons/banners/screenshots/build config, and produce a release build only when green.";
|
|
212
|
+
}, {
|
|
213
|
+
readonly name: "remote-deploy";
|
|
214
|
+
readonly category: "deployment";
|
|
215
|
+
readonly public: true;
|
|
216
|
+
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf", "cline", "roo-code", "kilo-code", "gemini", "github-copilot", "vscode-copilot", "opencode"];
|
|
217
|
+
readonly recommended: true;
|
|
218
|
+
readonly requiresMcpTools: readonly ["summer_project_setting", "summer_get_diagnostics", "summer_get_console", "summer_get_script_errors"];
|
|
219
|
+
readonly testScenario: "User says \"deploy the game to my Android phone\" — skill walks the prerequisites (runnable export preset, installed export templates, USB-debugging device), checks diagnostics are clean, and points them at the topnav Remote Deploy button to deploy a debug build with on-device remote debugging.";
|
|
204
220
|
}, {
|
|
205
221
|
readonly name: "concept-art";
|
|
206
222
|
readonly category: "2d-assets";
|
|
@@ -249,6 +265,14 @@ export declare const SKILL_REGISTRY: readonly [{
|
|
|
249
265
|
readonly recommended: false;
|
|
250
266
|
readonly requiresMcpTools: readonly ["summer_generate_image", "summer_import_from_url", "summer_set_resource_property", "summer_add_node", "summer_set_prop"];
|
|
251
267
|
readonly testScenario: "User requests a '4-frame walk cycle for the goblin' — skill generates per-frame at locked anchor, builds SpriteFrames resource, wires AnimatedSprite2D.";
|
|
268
|
+
}, {
|
|
269
|
+
readonly name: "create-asset-sheet";
|
|
270
|
+
readonly category: "2d-assets";
|
|
271
|
+
readonly public: true;
|
|
272
|
+
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf", "cline", "roo-code", "kilo-code", "gemini", "github-copilot", "vscode-copilot", "opencode"];
|
|
273
|
+
readonly recommended: false;
|
|
274
|
+
readonly requiresMcpTools: readonly ["summer_get_studio_workflow", "summer_generate_image", "summer_slice_asset_sheet", "summer_import_asset_by_id"];
|
|
275
|
+
readonly testScenario: "User requests a Japanese village asset pack — skill loads the Guided asset-pack recipe, generates one coherent sheet, slices it through the shared cloud pipeline, and imports selected results.";
|
|
252
276
|
}, {
|
|
253
277
|
readonly name: "skybox-panorama";
|
|
254
278
|
readonly category: "2d-assets";
|
|
@@ -521,6 +545,14 @@ export declare const SKILL_REGISTRY: readonly [{
|
|
|
521
545
|
readonly recommended: true;
|
|
522
546
|
readonly requiresMcpTools: readonly ["summer_play", "summer_stop", "summer_get_console", "summer_get_debugger_errors", "summer_get_diagnostics"];
|
|
523
547
|
readonly testScenario: "Just finished a gameplay feature — skill drives a golden-path + edge-case playthrough with diagnostics capture before the feature can be marked done.";
|
|
548
|
+
}, {
|
|
549
|
+
readonly name: "headless-scripting";
|
|
550
|
+
readonly category: "workflow";
|
|
551
|
+
readonly public: true;
|
|
552
|
+
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf", "cline", "roo-code", "kilo-code", "gemini", "github-copilot", "vscode-copilot", "opencode"];
|
|
553
|
+
readonly recommended: true;
|
|
554
|
+
readonly requiresMcpTools: readonly ["summer_get_project_context", "summer_write_file"];
|
|
555
|
+
readonly testScenario: "User needs a navmesh baked, collision generated, an Animation authored, or raw assets re-imported — skill runs a GDScript file against the real engine binary instead of reporting the capability as missing, and blocks the 'run it headless and screenshot it' plan that silently returns null.";
|
|
524
556
|
}, {
|
|
525
557
|
readonly name: "debugging-game-feel";
|
|
526
558
|
readonly category: "workflow";
|
|
@@ -53,6 +53,7 @@ export const SKILL_REGISTRY = [
|
|
|
53
53
|
clients: ALL_CLIENTS,
|
|
54
54
|
recommended: true,
|
|
55
55
|
requiresMcpTools: [
|
|
56
|
+
"summer_create_debug_report",
|
|
56
57
|
"summer_get_console",
|
|
57
58
|
"summer_get_debugger_errors",
|
|
58
59
|
"summer_get_script_errors",
|
|
@@ -108,6 +109,23 @@ export const SKILL_REGISTRY = [
|
|
|
108
109
|
],
|
|
109
110
|
testScenario: "Build a small reusable player scene, instantiate it in a main scene, and save both scenes through Summer tools.",
|
|
110
111
|
},
|
|
112
|
+
{
|
|
113
|
+
name: "summer-cloud",
|
|
114
|
+
category: "scene-and-project",
|
|
115
|
+
public: true,
|
|
116
|
+
clients: ALL_CLIENTS,
|
|
117
|
+
recommended: true,
|
|
118
|
+
requiresMcpTools: [
|
|
119
|
+
"summer_cloud_init",
|
|
120
|
+
"summer_cloud_status",
|
|
121
|
+
"summer_cloud_push",
|
|
122
|
+
"summer_cloud_pull",
|
|
123
|
+
"summer_cloud_restore",
|
|
124
|
+
"summer_cloud_checkpoints",
|
|
125
|
+
"summer_cloud_conflicts",
|
|
126
|
+
],
|
|
127
|
+
testScenario: "Enable Cloud for a project, push it, then pull it onto a second machine, taking the bootstrap choice and surfacing the delete count before any guarded deletion.",
|
|
128
|
+
},
|
|
111
129
|
{
|
|
112
130
|
name: "fps-controller",
|
|
113
131
|
category: "character-controllers",
|
|
@@ -413,6 +431,20 @@ export const SKILL_REGISTRY = [
|
|
|
413
431
|
],
|
|
414
432
|
testScenario: "Run the Steam pre-flight checklist (Windows + Mac + Linux), validate icons/banners/screenshots/build config, and produce a release build only when green.",
|
|
415
433
|
},
|
|
434
|
+
{
|
|
435
|
+
name: "remote-deploy",
|
|
436
|
+
category: "deployment",
|
|
437
|
+
public: true,
|
|
438
|
+
clients: ALL_CLIENTS,
|
|
439
|
+
recommended: true,
|
|
440
|
+
requiresMcpTools: [
|
|
441
|
+
"summer_project_setting",
|
|
442
|
+
"summer_get_diagnostics",
|
|
443
|
+
"summer_get_console",
|
|
444
|
+
"summer_get_script_errors",
|
|
445
|
+
],
|
|
446
|
+
testScenario: "User says \"deploy the game to my Android phone\" — skill walks the prerequisites (runnable export preset, installed export templates, USB-debugging device), checks diagnostics are clean, and points them at the topnav Remote Deploy button to deploy a debug build with on-device remote debugging.",
|
|
447
|
+
},
|
|
416
448
|
{
|
|
417
449
|
name: "concept-art",
|
|
418
450
|
category: "2d-assets",
|
|
@@ -494,6 +526,20 @@ export const SKILL_REGISTRY = [
|
|
|
494
526
|
],
|
|
495
527
|
testScenario: "User requests a '4-frame walk cycle for the goblin' — skill generates per-frame at locked anchor, builds SpriteFrames resource, wires AnimatedSprite2D.",
|
|
496
528
|
},
|
|
529
|
+
{
|
|
530
|
+
name: "create-asset-sheet",
|
|
531
|
+
category: "2d-assets",
|
|
532
|
+
public: true,
|
|
533
|
+
clients: ALL_CLIENTS,
|
|
534
|
+
recommended: false,
|
|
535
|
+
requiresMcpTools: [
|
|
536
|
+
"summer_get_studio_workflow",
|
|
537
|
+
"summer_generate_image",
|
|
538
|
+
"summer_slice_asset_sheet",
|
|
539
|
+
"summer_import_asset_by_id",
|
|
540
|
+
],
|
|
541
|
+
testScenario: "User requests a Japanese village asset pack — skill loads the Guided asset-pack recipe, generates one coherent sheet, slices it through the shared cloud pipeline, and imports selected results.",
|
|
542
|
+
},
|
|
497
543
|
{
|
|
498
544
|
name: "skybox-panorama",
|
|
499
545
|
category: "2d-assets",
|
|
@@ -977,6 +1023,15 @@ export const SKILL_REGISTRY = [
|
|
|
977
1023
|
],
|
|
978
1024
|
testScenario: "Just finished a gameplay feature — skill drives a golden-path + edge-case playthrough with diagnostics capture before the feature can be marked done.",
|
|
979
1025
|
},
|
|
1026
|
+
{
|
|
1027
|
+
name: "headless-scripting",
|
|
1028
|
+
category: "workflow",
|
|
1029
|
+
public: true,
|
|
1030
|
+
clients: ALL_CLIENTS,
|
|
1031
|
+
recommended: true,
|
|
1032
|
+
requiresMcpTools: ["summer_get_project_context", "summer_write_file"],
|
|
1033
|
+
testScenario: "User needs a navmesh baked, collision generated, an Animation authored, or raw assets re-imported — skill runs a GDScript file against the real engine binary instead of reporting the capability as missing, and blocks the 'run it headless and screenshot it' plan that silently returns null.",
|
|
1034
|
+
},
|
|
980
1035
|
{
|
|
981
1036
|
name: "debugging-game-feel",
|
|
982
1037
|
category: "workflow",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class SummerStoreError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
constructor(code: string, message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function getSummerDir(): string;
|
|
6
|
+
/** Test-only seam. Passing null restores the real ~/.summer path. */
|
|
7
|
+
export declare function setSummerDirForTests(path: string | null): void;
|
|
8
|
+
export declare function ensureSummerStore(): Promise<string>;
|
|
9
|
+
export declare function readStoreText(name: string): Promise<string | null>;
|
|
10
|
+
export declare function readStoreJson<T>(name: string): Promise<T | null>;
|
|
11
|
+
export declare function writeStoreText(name: string, value: string): Promise<void>;
|
|
12
|
+
export declare function writeStoreJson(name: string, value: unknown): Promise<void>;
|
|
13
|
+
export declare function appendStoreJsonLine(name: string, value: unknown): Promise<void>;
|
|
14
|
+
export declare function removeStoreFile(name: string): Promise<boolean>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { appendFile, chmod, lstat, mkdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
let summerDirOverride = null;
|
|
6
|
+
export class SummerStoreError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.name = "SummerStoreError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function getSummerDir() {
|
|
15
|
+
return summerDirOverride ?? join(homedir(), ".summer");
|
|
16
|
+
}
|
|
17
|
+
/** Test-only seam. Passing null restores the real ~/.summer path. */
|
|
18
|
+
export function setSummerDirForTests(path) {
|
|
19
|
+
summerDirOverride = path;
|
|
20
|
+
}
|
|
21
|
+
function storePath(name) {
|
|
22
|
+
if (!name || basename(name) !== name || name === "." || name === "..") {
|
|
23
|
+
throw new SummerStoreError("invalid_store_path", `Invalid Summer store filename "${name}". Recovery: use a single filename inside ~/.summer/.`);
|
|
24
|
+
}
|
|
25
|
+
return join(getSummerDir(), name);
|
|
26
|
+
}
|
|
27
|
+
async function hardenMode(path, mode) {
|
|
28
|
+
try {
|
|
29
|
+
await chmod(path, mode);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const code = error.code;
|
|
33
|
+
// Windows does not implement POSIX permission bits consistently.
|
|
34
|
+
if (process.platform !== "win32" && code !== "EPERM")
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export async function ensureSummerStore() {
|
|
39
|
+
const dir = getSummerDir();
|
|
40
|
+
try {
|
|
41
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
42
|
+
const info = await lstat(dir);
|
|
43
|
+
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
44
|
+
throw new SummerStoreError("unsafe_store_directory", `${dir} must be a real directory, not a file or symlink. Recovery: move it aside, create a directory at ${dir}, and run the command again.`);
|
|
45
|
+
}
|
|
46
|
+
await hardenMode(dir, 0o700);
|
|
47
|
+
return dir;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof SummerStoreError)
|
|
51
|
+
throw error;
|
|
52
|
+
throw new SummerStoreError("store_unavailable", `Cannot secure ${dir}. Recovery: make sure the directory is owned and writable by your user, then run the command again.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function assertSafeExistingFile(path) {
|
|
56
|
+
try {
|
|
57
|
+
const info = await lstat(path);
|
|
58
|
+
if (info.isSymbolicLink() || !info.isFile()) {
|
|
59
|
+
throw new SummerStoreError("unsafe_store_file", `${path} must be a regular file, not a directory or symlink. Recovery: move it aside and run the command again.`);
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error.code === "ENOENT")
|
|
65
|
+
return false;
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function readStoreText(name) {
|
|
70
|
+
const path = storePath(name);
|
|
71
|
+
if (!(await assertSafeExistingFile(path)))
|
|
72
|
+
return null;
|
|
73
|
+
try {
|
|
74
|
+
await hardenMode(path, 0o600);
|
|
75
|
+
return await readFile(path, "utf8");
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (error instanceof SummerStoreError)
|
|
79
|
+
throw error;
|
|
80
|
+
throw new SummerStoreError("store_read_failed", `Cannot read ${path}. Recovery: make sure the file is owned and readable by your user, then run the command again.`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function readStoreJson(name) {
|
|
84
|
+
const raw = await readStoreText(name);
|
|
85
|
+
if (raw === null)
|
|
86
|
+
return null;
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(raw);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
throw new SummerStoreError("invalid_store_json", `${storePath(name)} is not valid JSON. Recovery: move that file aside and run the command again.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export async function writeStoreText(name, value) {
|
|
95
|
+
const dir = await ensureSummerStore();
|
|
96
|
+
const destination = storePath(name);
|
|
97
|
+
await assertSafeExistingFile(destination);
|
|
98
|
+
const temporary = join(dir, `.${name}.${process.pid}.${randomUUID()}.tmp`);
|
|
99
|
+
try {
|
|
100
|
+
await writeFile(temporary, value, {
|
|
101
|
+
encoding: "utf8",
|
|
102
|
+
mode: 0o600,
|
|
103
|
+
flag: "wx",
|
|
104
|
+
});
|
|
105
|
+
await hardenMode(temporary, 0o600);
|
|
106
|
+
await rename(temporary, destination);
|
|
107
|
+
await hardenMode(destination, 0o600);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
await rm(temporary, { force: true }).catch(() => undefined);
|
|
111
|
+
if (error instanceof SummerStoreError)
|
|
112
|
+
throw error;
|
|
113
|
+
throw new SummerStoreError("store_write_failed", `Cannot write ${destination}. Recovery: make sure ${dir} is owned and writable by your user, then run the command again.`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export async function writeStoreJson(name, value) {
|
|
117
|
+
await writeStoreText(name, `${JSON.stringify(value, null, 2)}\n`);
|
|
118
|
+
}
|
|
119
|
+
export async function appendStoreJsonLine(name, value) {
|
|
120
|
+
await ensureSummerStore();
|
|
121
|
+
const path = storePath(name);
|
|
122
|
+
await assertSafeExistingFile(path);
|
|
123
|
+
try {
|
|
124
|
+
await appendFile(path, `${JSON.stringify(value)}\n`, {
|
|
125
|
+
encoding: "utf8",
|
|
126
|
+
mode: 0o600,
|
|
127
|
+
});
|
|
128
|
+
await hardenMode(path, 0o600);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
throw new SummerStoreError("store_append_failed", `Cannot append to ${path}. Recovery: make sure the file is owned and writable by your user, then run the command again.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export async function removeStoreFile(name) {
|
|
135
|
+
const path = storePath(name);
|
|
136
|
+
if (!(await assertSafeExistingFile(path)))
|
|
137
|
+
return false;
|
|
138
|
+
try {
|
|
139
|
+
await rm(path);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
throw new SummerStoreError("store_remove_failed", `Cannot remove ${path}. Recovery: make sure the file is owned and writable by your user, then run the command again.`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summer CLI compatibility values.
|
|
3
|
+
*
|
|
4
|
+
* Keep the current technical base in one place. The project feature tag is
|
|
5
|
+
* derived from it so `summer create` cannot drift to a different line. This
|
|
6
|
+
* source is cross-checked against the repository compatibility contract by
|
|
7
|
+
* `summer-compatibility.test.ts`.
|
|
8
|
+
*/
|
|
9
|
+
const CURRENT_TECHNICAL_BASE_VERSION = "4.6.1";
|
|
10
|
+
function featureTagFor(version) {
|
|
11
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(version);
|
|
12
|
+
if (!match) {
|
|
13
|
+
throw new Error(`Invalid Summer Engine technical base version: ${version}`);
|
|
14
|
+
}
|
|
15
|
+
return `${match[1]}.${match[2]}`;
|
|
16
|
+
}
|
|
17
|
+
export const SUMMER_ENGINE_COMPATIBILITY = Object.freeze({
|
|
18
|
+
currentTechnicalBaseVersion: CURRENT_TECHNICAL_BASE_VERSION,
|
|
19
|
+
projectFeatureTag: featureTagFor(CURRENT_TECHNICAL_BASE_VERSION),
|
|
20
|
+
plannedNextTechnicalBaseVersion: "4.7.1",
|
|
21
|
+
upstreamPolicy: "continuous-upstream",
|
|
22
|
+
});
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { EngineApiClient } from "../lib/api-client.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import type { EngineSelection } from "../lib/engine.js";
|
|
3
|
+
import { getCachedBootDriftNotice as getCachedNotice } from "../lib/mcp-boot-notice.js";
|
|
4
|
+
export declare const getCachedBootDriftNotice: typeof getCachedNotice;
|
|
5
|
+
export declare function configureMcpEngineSelection(selection?: EngineSelection): void;
|
|
4
6
|
export declare function getClient(): Promise<EngineApiClient>;
|
|
5
7
|
export declare function resetClient(): void;
|
|
6
|
-
export
|
|
8
|
+
export interface StartMcpServerOptions {
|
|
9
|
+
projectPath?: string;
|
|
10
|
+
instanceId?: string;
|
|
11
|
+
cwd?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function startMcpServer(options?: StartMcpServerOptions): Promise<void>;
|