summer-engine 1.3.0 → 1.3.1
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/README.md +7 -2
- package/dist/bin/summer.js +24 -1
- package/dist/commands/doctor.js +44 -20
- package/dist/commands/setup.js +77 -6
- package/dist/commands/skills.js +5 -3
- package/dist/lib/format.d.ts +23 -0
- package/dist/lib/format.js +60 -0
- package/dist/lib/format.test.d.ts +1 -0
- package/dist/lib/format.test.js +36 -0
- package/dist/lib/skills-registry.d.ts +16 -0
- package/dist/lib/skills-registry.js +35 -0
- package/package.json +1 -1
- package/skills/_tests/specs/debug.md +94 -0
- package/skills/_tests/specs/play.md +88 -0
- package/skills/asset-pipeline/asset-strategy/SKILL.md +1 -0
- package/skills/catalog.yaml +13 -3
- package/skills/character-controllers/fps-controller/SKILL.md +1 -0
- package/skills/debugging/debug/SKILL.md +137 -0
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +1 -0
- package/skills/scene-and-project/make-game/SKILL.md +1 -0
- package/skills/scene-and-project/play/SKILL.md +108 -0
- package/skills/scene-and-project/scene-composition/SKILL.md +1 -0
- package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -0
- package/skills/ui-and-ux/ui-basics/SKILL.md +1 -0
package/README.md
CHANGED
|
@@ -32,9 +32,14 @@ Verify:
|
|
|
32
32
|
summer doctor
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Then open your agent and try the
|
|
35
|
+
Then open your agent and try one of the slash commands:
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
| Command | What it does |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `/debug` | Triage and fix a bug end-to-end (reads engine errors, locates code, proposes fix) |
|
|
40
|
+
| `/play` | Run the game and report state (clean run, warnings, or crash) |
|
|
41
|
+
|
|
42
|
+
Or just describe what you want — the specialist skills (FPS controller, lighting, GDScript patterns, scene composition, UI, asset strategy) auto-trigger on natural language: "make me an FPS", "add lighting", "I need a HUD".
|
|
38
43
|
|
|
39
44
|
## Commands
|
|
40
45
|
|
package/dist/bin/summer.js
CHANGED
|
@@ -14,13 +14,18 @@ import { skillsCommand } from "../commands/skills.js";
|
|
|
14
14
|
import { orchestratorCommand } from "../commands/orchestrator.js";
|
|
15
15
|
import { setupCommand } from "../commands/setup.js";
|
|
16
16
|
import { doctorCommand } from "../commands/doctor.js";
|
|
17
|
+
import { getBanner } from "../lib/banner.js";
|
|
18
|
+
import { c, sym } from "../lib/format.js";
|
|
17
19
|
const require = createRequire(import.meta.url);
|
|
18
20
|
const { version } = require("../../package.json");
|
|
19
21
|
const program = new Command();
|
|
20
22
|
program
|
|
21
23
|
.name("summer")
|
|
22
24
|
.description("CLI and MCP tools for Summer Engine — the AI-native game engine")
|
|
23
|
-
.version(version)
|
|
25
|
+
.version(version)
|
|
26
|
+
.action(() => {
|
|
27
|
+
printIntro(version);
|
|
28
|
+
});
|
|
24
29
|
program.addCommand(installCommand);
|
|
25
30
|
program.addCommand(loginCommand);
|
|
26
31
|
program.addCommand(logoutCommand);
|
|
@@ -38,3 +43,21 @@ program.parseAsync().catch((err) => {
|
|
|
38
43
|
console.error(err instanceof Error ? err.message : String(err));
|
|
39
44
|
process.exit(1);
|
|
40
45
|
});
|
|
46
|
+
function printIntro(version) {
|
|
47
|
+
console.log("");
|
|
48
|
+
console.log(getBanner());
|
|
49
|
+
console.log("");
|
|
50
|
+
console.log(` ${sym.arrow()} ${c.bold("Summer Engine")} ${c.dim("v" + version)} ${c.dim("·")} AI-native game engine`);
|
|
51
|
+
console.log("");
|
|
52
|
+
console.log(` ${c.bold("Get started")}`);
|
|
53
|
+
console.log(` ${c.dim("$")} summer setup claude-code ${c.dim("Configure Claude Code (or codex/cursor/windsurf)")}`);
|
|
54
|
+
console.log(` ${c.dim("$")} summer create 3d-basic my-game ${c.dim("Start a project")}`);
|
|
55
|
+
console.log(` ${c.dim("$")} summer doctor ${c.dim("Check setup")}`);
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log(` ${c.bold("Slash commands")} ${c.dim("(in your AI agent)")}`);
|
|
58
|
+
console.log(` ${c.brand("/debug")} ${c.dim("Triage and fix a bug end-to-end")}`);
|
|
59
|
+
console.log(` ${c.brand("/play")} ${c.dim("Run the game and report state")}`);
|
|
60
|
+
console.log("");
|
|
61
|
+
console.log(` ${c.dim("Docs:")} https://summerengine.com/docs`);
|
|
62
|
+
console.log("");
|
|
63
|
+
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -5,6 +5,7 @@ import { platform } from "os";
|
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { getAuthToken, getUserInfo } from "../lib/auth.js";
|
|
7
7
|
import { checkEngineHealth, getApiPort, getApiToken } from "../lib/engine.js";
|
|
8
|
+
import { brandLine, c, pad, sym, tildeify } from "../lib/format.js";
|
|
8
9
|
const require = createRequire(import.meta.url);
|
|
9
10
|
const { version } = require("../../package.json");
|
|
10
11
|
const MAC_ENGINE_PATHS = [
|
|
@@ -17,11 +18,17 @@ const WIN_ENGINE_PATHS = [
|
|
|
17
18
|
`${process.env.PROGRAMFILES}\\Summer Engine\\Summer.exe`,
|
|
18
19
|
];
|
|
19
20
|
export const doctorCommand = new Command("doctor")
|
|
20
|
-
.description("
|
|
21
|
+
.description("Diagnose Node, login, engine, local API, and MCP boot")
|
|
21
22
|
.option("--json", "Print diagnostics as JSON")
|
|
22
|
-
.option("--human", "Print diagnostics in a human-readable format")
|
|
23
23
|
.action(async (opts) => {
|
|
24
|
-
|
|
24
|
+
if (!opts.json) {
|
|
25
|
+
const { createRequire: req } = await import("node:module");
|
|
26
|
+
const ver = req(import.meta.url)("../../package.json").version;
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log(brandLine(ver));
|
|
29
|
+
console.log("");
|
|
30
|
+
}
|
|
31
|
+
const result = await runDoctor({ json: Boolean(opts.json) });
|
|
25
32
|
if (!result.ok) {
|
|
26
33
|
process.exit(1);
|
|
27
34
|
}
|
|
@@ -33,7 +40,7 @@ export async function runDoctor(options = {}) {
|
|
|
33
40
|
id: "cli-version",
|
|
34
41
|
label: "Summer CLI",
|
|
35
42
|
status: "ok",
|
|
36
|
-
message: `
|
|
43
|
+
message: `v${version}`,
|
|
37
44
|
});
|
|
38
45
|
checks.push(await checkLogin());
|
|
39
46
|
checks.push(checkEngineInstall());
|
|
@@ -57,14 +64,14 @@ function checkNodeVersion() {
|
|
|
57
64
|
id: "node-version",
|
|
58
65
|
label: "Node.js",
|
|
59
66
|
status: "ok",
|
|
60
|
-
message:
|
|
67
|
+
message: process.version,
|
|
61
68
|
};
|
|
62
69
|
}
|
|
63
70
|
return {
|
|
64
71
|
id: "node-version",
|
|
65
72
|
label: "Node.js",
|
|
66
73
|
status: "fail",
|
|
67
|
-
message:
|
|
74
|
+
message: `${process.version} (need 18+)`,
|
|
68
75
|
};
|
|
69
76
|
}
|
|
70
77
|
async function checkLogin() {
|
|
@@ -75,32 +82,34 @@ async function checkLogin() {
|
|
|
75
82
|
id: "login",
|
|
76
83
|
label: "Login",
|
|
77
84
|
status: "warning",
|
|
78
|
-
message: "
|
|
85
|
+
message: "not signed in (run: summer login)",
|
|
79
86
|
};
|
|
80
87
|
}
|
|
81
88
|
return {
|
|
82
89
|
id: "login",
|
|
83
90
|
label: "Login",
|
|
84
91
|
status: "ok",
|
|
85
|
-
message: user ?
|
|
92
|
+
message: user ? user.email : "signed in",
|
|
86
93
|
};
|
|
87
94
|
}
|
|
88
95
|
function checkEngineInstall() {
|
|
89
96
|
const binary = findEngineBinary();
|
|
90
97
|
if (binary) {
|
|
98
|
+
// Shorten /Applications/Summer.app/Contents/MacOS/Summer -> /Applications/Summer.app
|
|
99
|
+
const display = binary.replace(/\/Contents\/MacOS\/Summer$/, "");
|
|
91
100
|
return {
|
|
92
101
|
id: "engine-install",
|
|
93
|
-
label: "Engine
|
|
102
|
+
label: "Engine",
|
|
94
103
|
status: "ok",
|
|
95
|
-
message:
|
|
104
|
+
message: tildeify(display),
|
|
96
105
|
details: { path: binary },
|
|
97
106
|
};
|
|
98
107
|
}
|
|
99
108
|
return {
|
|
100
109
|
id: "engine-install",
|
|
101
|
-
label: "Engine
|
|
110
|
+
label: "Engine",
|
|
102
111
|
status: "warning",
|
|
103
|
-
message: "
|
|
112
|
+
message: "not installed (run: summer install)",
|
|
104
113
|
};
|
|
105
114
|
}
|
|
106
115
|
async function checkLocalApi() {
|
|
@@ -111,7 +120,7 @@ async function checkLocalApi() {
|
|
|
111
120
|
id: "local-api",
|
|
112
121
|
label: "Local API",
|
|
113
122
|
status: "warning",
|
|
114
|
-
message: "
|
|
123
|
+
message: "engine not running",
|
|
115
124
|
details: { port },
|
|
116
125
|
};
|
|
117
126
|
}
|
|
@@ -121,7 +130,7 @@ async function checkLocalApi() {
|
|
|
121
130
|
id: "local-api",
|
|
122
131
|
label: "Local API",
|
|
123
132
|
status: "warning",
|
|
124
|
-
message: `
|
|
133
|
+
message: `not responding on :${port}`,
|
|
125
134
|
details: { port },
|
|
126
135
|
};
|
|
127
136
|
}
|
|
@@ -129,7 +138,7 @@ async function checkLocalApi() {
|
|
|
129
138
|
id: "local-api",
|
|
130
139
|
label: "Local API",
|
|
131
140
|
status: "ok",
|
|
132
|
-
message:
|
|
141
|
+
message: `:${port}`,
|
|
133
142
|
details: {
|
|
134
143
|
port,
|
|
135
144
|
version: health.version,
|
|
@@ -182,7 +191,7 @@ async function checkMcpBoot() {
|
|
|
182
191
|
id: "mcp-boot",
|
|
183
192
|
label: "MCP Server",
|
|
184
193
|
status: "ok",
|
|
185
|
-
message: "
|
|
194
|
+
message: "ready",
|
|
186
195
|
});
|
|
187
196
|
}
|
|
188
197
|
});
|
|
@@ -225,12 +234,27 @@ function summarizeChecks(checks) {
|
|
|
225
234
|
};
|
|
226
235
|
}
|
|
227
236
|
export function printDoctorResult(result) {
|
|
228
|
-
console.log("
|
|
237
|
+
console.log(c.bold("Doctor"));
|
|
238
|
+
console.log("");
|
|
239
|
+
const labelWidth = 14;
|
|
229
240
|
for (const check of result.checks) {
|
|
230
|
-
const mark = check.status === "ok"
|
|
231
|
-
|
|
241
|
+
const mark = check.status === "ok"
|
|
242
|
+
? sym.ok()
|
|
243
|
+
: check.status === "warning"
|
|
244
|
+
? sym.warn()
|
|
245
|
+
: sym.fail();
|
|
246
|
+
console.log(` ${mark} ${pad(c.bold(check.label), labelWidth)}${c.dim(check.message)}`);
|
|
247
|
+
}
|
|
248
|
+
console.log("");
|
|
249
|
+
if (result.summary.failures > 0) {
|
|
250
|
+
console.log(c.red(`${result.summary.failures} ${result.summary.failures === 1 ? "issue" : "issues"} to fix.`));
|
|
251
|
+
}
|
|
252
|
+
else if (result.summary.warnings > 0) {
|
|
253
|
+
console.log(c.yellow(`${result.summary.warnings} ${result.summary.warnings === 1 ? "warning" : "warnings"}, ${result.summary.ok} OK.`));
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
console.log(c.green("Everything's wired up."));
|
|
232
257
|
}
|
|
233
|
-
console.log(`\n${result.summary.ok} ok, ${result.summary.warnings} warnings, ${result.summary.failures} failures`);
|
|
234
258
|
}
|
|
235
259
|
function findEngineBinary() {
|
|
236
260
|
const paths = platform() === "darwin" ? MAC_ENGINE_PATHS : WIN_ENGINE_PATHS;
|
package/dist/commands/setup.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { spawnSync } from "child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import { Command } from "commander";
|
|
3
4
|
import { configureAgentMcp, parseAgent, parseScope, supportedAgents, } from "../lib/agent-config.js";
|
|
4
5
|
import { printDoctorResult, runDoctor } from "./doctor.js";
|
|
6
|
+
import { brandLine, c, sym, tildeify } from "../lib/format.js";
|
|
7
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
8
|
+
const { version: cliVersion } = requireFromHere("../../package.json");
|
|
9
|
+
const AGENT_LABEL = {
|
|
10
|
+
"claude-code": "Claude Code",
|
|
11
|
+
codex: "Codex",
|
|
12
|
+
cursor: "Cursor",
|
|
13
|
+
windsurf: "Windsurf",
|
|
14
|
+
};
|
|
5
15
|
export const setupCommand = new Command("setup")
|
|
6
16
|
.description("Configure Summer Engine for an AI agent and run diagnostics")
|
|
7
17
|
.argument("[agent]", `Agent to configure: ${supportedAgents.join(", ")}`)
|
|
@@ -109,20 +119,81 @@ function skillInstallInvocation(agent) {
|
|
|
109
119
|
function printSetupResult(config, skills, doctor) {
|
|
110
120
|
if (config.print) {
|
|
111
121
|
console.log(config.snippet.trimEnd());
|
|
122
|
+
return;
|
|
112
123
|
}
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
console.log("");
|
|
125
|
+
console.log(brandLine(cliVersion));
|
|
126
|
+
console.log("");
|
|
127
|
+
const agentLabel = AGENT_LABEL[config.agent] ?? config.agent;
|
|
128
|
+
if (config.dryRun) {
|
|
129
|
+
console.log(` ${c.dim("(dry run)")} Would link to ${agentLabel} ${c.dim(tildeify(config.path))}`);
|
|
115
130
|
}
|
|
116
131
|
else if (config.wrote) {
|
|
117
|
-
console.log(`
|
|
132
|
+
console.log(` ${sym.ok()} Linked to ${c.bold(agentLabel)} ${c.dim(tildeify(config.path))}`);
|
|
118
133
|
}
|
|
119
134
|
else {
|
|
120
|
-
console.log(`
|
|
135
|
+
console.log(` ${sym.ok()} Already linked to ${c.bold(agentLabel)} ${c.dim(tildeify(config.path))}`);
|
|
136
|
+
}
|
|
137
|
+
if (skills.status === "installed") {
|
|
138
|
+
const installed = parseInstalledSkills(skills.stdout);
|
|
139
|
+
if (installed.length > 0) {
|
|
140
|
+
const where = parseSkillTargetDir(skills.stdout);
|
|
141
|
+
console.log(` ${sym.ok()} Installed ${c.bold(String(installed.length) + " skills")} ${where ? c.dim(tildeify(where)) : ""}`);
|
|
142
|
+
const grouped = installed.reduce((rows, name, i) => {
|
|
143
|
+
const row = Math.floor(i / 3);
|
|
144
|
+
rows[row] = rows[row] ?? [];
|
|
145
|
+
rows[row].push(name);
|
|
146
|
+
return rows;
|
|
147
|
+
}, []);
|
|
148
|
+
for (const row of grouped) {
|
|
149
|
+
console.log(` ${c.dim(row.join(" · "))}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(` ${sym.ok()} Installed recommended skills`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (skills.status === "planned" || skills.status === "skipped") {
|
|
157
|
+
console.log(` ${sym.warn()} Skills: ${c.dim(skills.message)}`);
|
|
158
|
+
}
|
|
159
|
+
else if (skills.status === "failed") {
|
|
160
|
+
console.log(` ${sym.fail()} Skills install failed`);
|
|
161
|
+
if (skills.stderr)
|
|
162
|
+
console.log(` ${c.dim(skills.stderr)}`);
|
|
121
163
|
}
|
|
122
164
|
for (const warning of config.warnings) {
|
|
123
|
-
console.
|
|
165
|
+
console.log(` ${sym.warn()} ${c.yellow(warning)}`);
|
|
124
166
|
}
|
|
125
|
-
console.log(`Skills: ${skills.message}`);
|
|
126
167
|
console.log("");
|
|
127
168
|
printDoctorResult(doctor);
|
|
169
|
+
if (doctor.ok && skills.status !== "failed" && !config.dryRun) {
|
|
170
|
+
console.log("");
|
|
171
|
+
console.log(`${c.dim("Try it:")} open ${AGENT_LABEL[config.agent] ?? config.agent} and ask: ${c.bold("\"add a DirectionalLight3D and Camera3D to my scene\"")}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function parseInstalledSkills(stdout) {
|
|
175
|
+
if (!stdout)
|
|
176
|
+
return [];
|
|
177
|
+
// Lines look like: " Installed fps-controller -> /path/.../fps-controller"
|
|
178
|
+
const names = [];
|
|
179
|
+
for (const line of stdout.split("\n")) {
|
|
180
|
+
const m = line.match(/^\s*Installed\s+([a-z0-9-]+)\s+->/i);
|
|
181
|
+
if (m)
|
|
182
|
+
names.push(m[1]);
|
|
183
|
+
}
|
|
184
|
+
return names;
|
|
185
|
+
}
|
|
186
|
+
function parseSkillTargetDir(stdout) {
|
|
187
|
+
if (!stdout)
|
|
188
|
+
return null;
|
|
189
|
+
for (const line of stdout.split("\n")) {
|
|
190
|
+
const m = line.match(/^\s*Installed\s+[a-z0-9-]+\s+->\s+(.+)$/i);
|
|
191
|
+
if (m) {
|
|
192
|
+
const path = m[1].trim();
|
|
193
|
+
// Strip trailing /<skill-name> to get the parent dir
|
|
194
|
+
const parent = path.replace(/\/[a-z0-9-]+$/i, "/");
|
|
195
|
+
return parent;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
128
199
|
}
|
package/dist/commands/skills.js
CHANGED
|
@@ -4,6 +4,7 @@ import { join, dirname } from "path";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { homedir } from "os";
|
|
6
6
|
import { AGENT_CLIENTS, SKILL_REGISTRY, } from "../lib/skills-registry.js";
|
|
7
|
+
import { tildeify } from "../lib/format.js";
|
|
7
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
9
|
// Resolve skills dir: from dist/commands/skills.js -> ../../skills
|
|
9
10
|
const skillsDir = join(__dirname, "..", "..", "skills");
|
|
@@ -242,15 +243,16 @@ function escapeRegExp(value) {
|
|
|
242
243
|
}
|
|
243
244
|
function printInstallSummary(count, agent, scope, location) {
|
|
244
245
|
const label = agentLabel(agent);
|
|
246
|
+
const tildeified = tildeify(location.path);
|
|
245
247
|
console.log(`\n${count} skill${count === 1 ? "" : "s"} ready for ${label} (${scope} scope).`);
|
|
246
248
|
if (location.kind === "skill-dir") {
|
|
247
|
-
console.log(`${label} can read skills from ${
|
|
249
|
+
console.log(`${label} can read skills from ${tildeified}/<skill>/SKILL.md`);
|
|
248
250
|
}
|
|
249
251
|
else if (location.kind === "cursor-rule-dir") {
|
|
250
|
-
console.log(`Cursor rules are in ${
|
|
252
|
+
console.log(`Cursor rules are in ${tildeified}/summer-<skill>.mdc`);
|
|
251
253
|
}
|
|
252
254
|
else {
|
|
253
|
-
console.log(`Windsurf rules are in ${
|
|
255
|
+
console.log(`Windsurf rules are in ${tildeified}`);
|
|
254
256
|
}
|
|
255
257
|
}
|
|
256
258
|
export const skillsCommand = new Command("skills")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare function useColor(): boolean;
|
|
2
|
+
export declare const c: {
|
|
3
|
+
bold: (s: string) => string;
|
|
4
|
+
dim: (s: string) => string;
|
|
5
|
+
red: (s: string) => string;
|
|
6
|
+
green: (s: string) => string;
|
|
7
|
+
yellow: (s: string) => string;
|
|
8
|
+
cyan: (s: string) => string;
|
|
9
|
+
brand: (s: string) => string;
|
|
10
|
+
};
|
|
11
|
+
export declare const sym: {
|
|
12
|
+
ok: () => string;
|
|
13
|
+
warn: () => string;
|
|
14
|
+
fail: () => string;
|
|
15
|
+
arrow: () => string;
|
|
16
|
+
};
|
|
17
|
+
export declare function tildeify(path: string | undefined | null): string;
|
|
18
|
+
export declare function brandLine(version: string): string;
|
|
19
|
+
export declare function stripAnsi(s: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Pad a string to a visible width, accounting for ANSI codes.
|
|
22
|
+
*/
|
|
23
|
+
export declare function pad(s: string, width: number): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { homedir } from "os";
|
|
2
|
+
const ANSI = {
|
|
3
|
+
reset: "\x1b[0m",
|
|
4
|
+
bold: "\x1b[1m",
|
|
5
|
+
dim: "\x1b[2m",
|
|
6
|
+
red: "\x1b[31m",
|
|
7
|
+
green: "\x1b[32m",
|
|
8
|
+
yellow: "\x1b[33m",
|
|
9
|
+
cyan: "\x1b[36m",
|
|
10
|
+
// Summer brand orange (matches banner.ts mid gradient)
|
|
11
|
+
brand: "\x1b[38;2;255;143;23m",
|
|
12
|
+
};
|
|
13
|
+
export function useColor() {
|
|
14
|
+
if (process.env.NO_COLOR)
|
|
15
|
+
return false;
|
|
16
|
+
if (process.env.FORCE_COLOR)
|
|
17
|
+
return true;
|
|
18
|
+
return Boolean(process.stdout.isTTY);
|
|
19
|
+
}
|
|
20
|
+
function paint(code, s) {
|
|
21
|
+
return useColor() ? `${code}${s}${ANSI.reset}` : s;
|
|
22
|
+
}
|
|
23
|
+
export const c = {
|
|
24
|
+
bold: (s) => paint(ANSI.bold, s),
|
|
25
|
+
dim: (s) => paint(ANSI.dim, s),
|
|
26
|
+
red: (s) => paint(ANSI.red, s),
|
|
27
|
+
green: (s) => paint(ANSI.green, s),
|
|
28
|
+
yellow: (s) => paint(ANSI.yellow, s),
|
|
29
|
+
cyan: (s) => paint(ANSI.cyan, s),
|
|
30
|
+
brand: (s) => paint(ANSI.brand, s),
|
|
31
|
+
};
|
|
32
|
+
export const sym = {
|
|
33
|
+
ok: () => c.green("✓"),
|
|
34
|
+
warn: () => c.yellow("⚠"),
|
|
35
|
+
fail: () => c.red("✗"),
|
|
36
|
+
arrow: () => c.brand("▶"),
|
|
37
|
+
};
|
|
38
|
+
export function tildeify(path) {
|
|
39
|
+
if (!path)
|
|
40
|
+
return "";
|
|
41
|
+
const home = homedir();
|
|
42
|
+
if (path === home)
|
|
43
|
+
return "~";
|
|
44
|
+
if (path.startsWith(home + "/"))
|
|
45
|
+
return "~" + path.slice(home.length);
|
|
46
|
+
return path;
|
|
47
|
+
}
|
|
48
|
+
export function brandLine(version) {
|
|
49
|
+
return `${sym.arrow()} ${c.bold("Summer Engine")} ${c.dim("v" + version)}`;
|
|
50
|
+
}
|
|
51
|
+
export function stripAnsi(s) {
|
|
52
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Pad a string to a visible width, accounting for ANSI codes.
|
|
56
|
+
*/
|
|
57
|
+
export function pad(s, width) {
|
|
58
|
+
const visLen = stripAnsi(s).length;
|
|
59
|
+
return s + " ".repeat(Math.max(0, width - visLen));
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { homedir } from "os";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { stripAnsi, tildeify } from "./format.js";
|
|
4
|
+
describe("tildeify", () => {
|
|
5
|
+
it("replaces home directory prefix with ~", () => {
|
|
6
|
+
const home = homedir();
|
|
7
|
+
expect(tildeify(home + "/.claude.json")).toBe("~/.claude.json");
|
|
8
|
+
expect(tildeify(home + "/projects/foo")).toBe("~/projects/foo");
|
|
9
|
+
});
|
|
10
|
+
it("returns ~ when path is the home directory exactly", () => {
|
|
11
|
+
expect(tildeify(homedir())).toBe("~");
|
|
12
|
+
});
|
|
13
|
+
it("does not touch non-home paths", () => {
|
|
14
|
+
expect(tildeify("/Applications/Summer.app")).toBe("/Applications/Summer.app");
|
|
15
|
+
expect(tildeify("/tmp/foo")).toBe("/tmp/foo");
|
|
16
|
+
});
|
|
17
|
+
it("does not partial-match (e.g. /Users/Mat vs /Users/MathiasWork)", () => {
|
|
18
|
+
const home = homedir();
|
|
19
|
+
const sibling = home.slice(0, -2) + "Other";
|
|
20
|
+
expect(tildeify(sibling + "/file")).toBe(sibling + "/file");
|
|
21
|
+
});
|
|
22
|
+
it("handles empty/null/undefined input", () => {
|
|
23
|
+
expect(tildeify(undefined)).toBe("");
|
|
24
|
+
expect(tildeify(null)).toBe("");
|
|
25
|
+
expect(tildeify("")).toBe("");
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe("stripAnsi", () => {
|
|
29
|
+
it("removes ANSI color codes", () => {
|
|
30
|
+
expect(stripAnsi("\x1b[31mhello\x1b[0m")).toBe("hello");
|
|
31
|
+
expect(stripAnsi("\x1b[1;32mbold green\x1b[0m text")).toBe("bold green text");
|
|
32
|
+
});
|
|
33
|
+
it("leaves clean strings untouched", () => {
|
|
34
|
+
expect(stripAnsi("hello")).toBe("hello");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -17,6 +17,22 @@ export interface SkillRegistryEntry {
|
|
|
17
17
|
* with shippable content). When a NEXT skill ships, mirror it here.
|
|
18
18
|
*/
|
|
19
19
|
export declare const SKILL_REGISTRY: readonly [{
|
|
20
|
+
readonly name: "debug";
|
|
21
|
+
readonly category: "debugging";
|
|
22
|
+
readonly public: true;
|
|
23
|
+
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf"];
|
|
24
|
+
readonly recommended: true;
|
|
25
|
+
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 testScenario: "Triage a runtime crash end-to-end: read errors, locate code, propose fix, apply on approval, verify.";
|
|
27
|
+
}, {
|
|
28
|
+
readonly name: "play";
|
|
29
|
+
readonly category: "scene-and-project";
|
|
30
|
+
readonly public: true;
|
|
31
|
+
readonly clients: readonly ["summer", "codex", "claude-code", "cursor", "windsurf"];
|
|
32
|
+
readonly recommended: true;
|
|
33
|
+
readonly requiresMcpTools: readonly ["summer_is_running", "summer_play", "summer_stop", "summer_clear_console", "summer_get_diagnostics", "summer_get_debugger_errors", "summer_get_script_errors"];
|
|
34
|
+
readonly testScenario: "Run the game from a clean state, wait for first frame, report whether it runs cleanly or has errors.";
|
|
35
|
+
}, {
|
|
20
36
|
readonly name: "gdscript-patterns";
|
|
21
37
|
readonly category: "scripting-patterns";
|
|
22
38
|
readonly public: true;
|
|
@@ -35,6 +35,41 @@ const ALL_CLIENTS = AGENT_CLIENTS;
|
|
|
35
35
|
* with shippable content). When a NEXT skill ships, mirror it here.
|
|
36
36
|
*/
|
|
37
37
|
export const SKILL_REGISTRY = [
|
|
38
|
+
{
|
|
39
|
+
name: "debug",
|
|
40
|
+
category: "debugging",
|
|
41
|
+
public: true,
|
|
42
|
+
clients: ALL_CLIENTS,
|
|
43
|
+
recommended: true,
|
|
44
|
+
requiresMcpTools: [
|
|
45
|
+
"summer_get_console",
|
|
46
|
+
"summer_get_debugger_errors",
|
|
47
|
+
"summer_get_script_errors",
|
|
48
|
+
"summer_get_diagnostics",
|
|
49
|
+
"summer_clear_console",
|
|
50
|
+
"summer_play",
|
|
51
|
+
"summer_stop",
|
|
52
|
+
"summer_inspect_node",
|
|
53
|
+
],
|
|
54
|
+
testScenario: "Triage a runtime crash end-to-end: read errors, locate code, propose fix, apply on approval, verify.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "play",
|
|
58
|
+
category: "scene-and-project",
|
|
59
|
+
public: true,
|
|
60
|
+
clients: ALL_CLIENTS,
|
|
61
|
+
recommended: true,
|
|
62
|
+
requiresMcpTools: [
|
|
63
|
+
"summer_is_running",
|
|
64
|
+
"summer_play",
|
|
65
|
+
"summer_stop",
|
|
66
|
+
"summer_clear_console",
|
|
67
|
+
"summer_get_diagnostics",
|
|
68
|
+
"summer_get_debugger_errors",
|
|
69
|
+
"summer_get_script_errors",
|
|
70
|
+
],
|
|
71
|
+
testScenario: "Run the game from a clean state, wait for first frame, report whether it runs cleanly or has errors.",
|
|
72
|
+
},
|
|
38
73
|
{
|
|
39
74
|
name: "gdscript-patterns",
|
|
40
75
|
category: "scripting-patterns",
|
package/package.json
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Skill Spec: /debug
|
|
2
|
+
|
|
3
|
+
## Fixture
|
|
4
|
+
|
|
5
|
+
- A Godot/Summer project with one or more reproducible bugs.
|
|
6
|
+
- Summer Engine running, MCP available.
|
|
7
|
+
- Host file tools available (Read, Edit, Write).
|
|
8
|
+
|
|
9
|
+
## Case 1: Happy Path — runtime error with clear stack trace
|
|
10
|
+
|
|
11
|
+
**Fixture:** `scripts/player.gd` has `velocity.y -= GRAVTY * delta` (typo: GRAVTY instead of GRAVITY). Player crashes on `_physics_process` first frame.
|
|
12
|
+
|
|
13
|
+
**Input:** "Debug my game. The player crashes the moment I press play."
|
|
14
|
+
|
|
15
|
+
**Expected MCP tool sequence (in order):**
|
|
16
|
+
|
|
17
|
+
1. (Skill asks the user one clarifying question and waits.)
|
|
18
|
+
2. `summer_get_script_errors` — finds `Identifier "GRAVTY" not declared` at scripts/player.gd:14
|
|
19
|
+
3. (Optional: `summer_get_console` to confirm no other errors hiding)
|
|
20
|
+
4. `Read scripts/player.gd` — read 20–40 lines around line 14
|
|
21
|
+
5. (Skill states hypothesis: typo, GRAVTY → GRAVITY)
|
|
22
|
+
6. (Skill asks: "May I edit `scripts/player.gd` to rename GRAVTY → GRAVITY?")
|
|
23
|
+
7. `Edit scripts/player.gd` — apply fix on user OK
|
|
24
|
+
8. `summer_get_script_errors` — verify clean
|
|
25
|
+
|
|
26
|
+
**Assertions:**
|
|
27
|
+
|
|
28
|
+
- [ ] Skill asks for the user's description before any tool call.
|
|
29
|
+
- [ ] First diagnostic tool called is `summer_get_script_errors` (cheapest).
|
|
30
|
+
- [ ] Skill does NOT grep the whole codebase before reading the error.
|
|
31
|
+
- [ ] Skill reads only the file + lines indicated by the error, not the whole file.
|
|
32
|
+
- [ ] Skill states a single specific hypothesis before proposing a fix.
|
|
33
|
+
- [ ] Skill asks "May I edit …" before writing.
|
|
34
|
+
- [ ] After the fix, skill re-runs `summer_get_script_errors` to verify.
|
|
35
|
+
- [ ] Skill never calls `summer_set_resource_property` on an inline sub-resource (silent-fail trap).
|
|
36
|
+
|
|
37
|
+
## Case 2: Failure Path — bug only reproduces at runtime
|
|
38
|
+
|
|
39
|
+
**Fixture:** Game compiles fine but crashes when player picks up a coin: `Invalid call. Nonexistent function 'play' in base 'Nil'.` AudioStreamPlayer node was deleted in editor but pickup script still references it.
|
|
40
|
+
|
|
41
|
+
**Input:** "When I pick up a coin, the game crashes."
|
|
42
|
+
|
|
43
|
+
**Expected behavior:**
|
|
44
|
+
|
|
45
|
+
- Skill calls `summer_get_script_errors` first → clean.
|
|
46
|
+
- Skill realizes it's runtime: `summer_clear_console`, `summer_play`.
|
|
47
|
+
- Skill asks user: "Reproduce the bug now — pick up a coin."
|
|
48
|
+
- After confirmation, calls `summer_get_debugger_errors`.
|
|
49
|
+
- Stack trace points to `coin.gd:32`, function `_on_body_entered`, calling `audio.play()` where `audio` is `null`.
|
|
50
|
+
- Skill calls `summer_inspect_node "./Coin/AudioStreamPlayer"` to confirm the node is missing.
|
|
51
|
+
- Skill proposes: re-add the AudioStreamPlayer (via `summer_add_node`) OR null-check in code.
|
|
52
|
+
- Asks the user which.
|
|
53
|
+
|
|
54
|
+
**Assertions:**
|
|
55
|
+
|
|
56
|
+
- [ ] Skill recognizes that script-errors-clean + crash-on-runtime = runtime-only bug.
|
|
57
|
+
- [ ] Skill explicitly invokes the play→reproduce→read-debugger loop, not just one shot.
|
|
58
|
+
- [ ] Skill verifies the missing-node hypothesis with `summer_inspect_node` BEFORE editing code.
|
|
59
|
+
- [ ] Skill offers BOTH options (fix scene OR fix code) instead of unilaterally picking.
|
|
60
|
+
|
|
61
|
+
## Case 3: Edge Case — user gives a vague description
|
|
62
|
+
|
|
63
|
+
**Fixture:** Same as Case 1.
|
|
64
|
+
|
|
65
|
+
**Input:** "Something's broken."
|
|
66
|
+
|
|
67
|
+
**Expected behavior:**
|
|
68
|
+
|
|
69
|
+
- Skill asks one focused follow-up: "What's happening, and when?"
|
|
70
|
+
- Does NOT start grepping code or running tools blindly.
|
|
71
|
+
|
|
72
|
+
**Assertions:**
|
|
73
|
+
|
|
74
|
+
- [ ] No tool calls happen until the user gives a concrete symptom.
|
|
75
|
+
- [ ] Skill's follow-up is one short question, not a checklist.
|
|
76
|
+
|
|
77
|
+
## Case 4: No Summer MCP — fallback path
|
|
78
|
+
|
|
79
|
+
**Fixture:** Same as Case 1, but Summer MCP is unavailable (engine not connected).
|
|
80
|
+
|
|
81
|
+
**Input:** "Debug my game."
|
|
82
|
+
|
|
83
|
+
**Expected behavior:**
|
|
84
|
+
|
|
85
|
+
- Skill detects MCP unavailable.
|
|
86
|
+
- Asks the user to copy-paste from Godot's Output and Debugger panels.
|
|
87
|
+
- Reasons over the pasted text the same way it would over MCP output.
|
|
88
|
+
- Continues with the rest of the workflow (read code, hypothesize, propose fix).
|
|
89
|
+
|
|
90
|
+
**Assertions:**
|
|
91
|
+
|
|
92
|
+
- [ ] Skill does not blindly call `summer_*` tools and fail.
|
|
93
|
+
- [ ] Skill explicitly asks for the panel output instead of guessing.
|
|
94
|
+
- [ ] The rest of the loop (hypothesis → "May I edit?" → verify) still runs.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Skill Spec: /play
|
|
2
|
+
|
|
3
|
+
## Fixture
|
|
4
|
+
|
|
5
|
+
- A Godot/Summer project with a main scene set in `project.godot`.
|
|
6
|
+
- Summer Engine running, MCP available.
|
|
7
|
+
|
|
8
|
+
## Case 1: Happy Path — clean run
|
|
9
|
+
|
|
10
|
+
**Fixture:** Project compiles cleanly. Game is not currently running.
|
|
11
|
+
|
|
12
|
+
**Input:** "Play."
|
|
13
|
+
|
|
14
|
+
**Expected MCP tool sequence (in order):**
|
|
15
|
+
|
|
16
|
+
1. `summer_is_running` — false
|
|
17
|
+
2. `summer_get_script_errors` — clean
|
|
18
|
+
3. `summer_clear_console`
|
|
19
|
+
4. `summer_play`
|
|
20
|
+
5. (~2 second wait)
|
|
21
|
+
6. `summer_get_diagnostics`
|
|
22
|
+
7. `summer_get_debugger_errors`
|
|
23
|
+
8. (Skill reports "Running. No errors or warnings.")
|
|
24
|
+
|
|
25
|
+
**Assertions:**
|
|
26
|
+
|
|
27
|
+
- [ ] First call is `summer_is_running` to avoid double-launch.
|
|
28
|
+
- [ ] `summer_get_script_errors` runs BEFORE `summer_play` (avoid noisy fail).
|
|
29
|
+
- [ ] `summer_clear_console` runs before `summer_play` (so post-run output is clean).
|
|
30
|
+
- [ ] Skill waits before reading post-play state (≥1 second).
|
|
31
|
+
- [ ] Skill does NOT call `summer_stop` on its own.
|
|
32
|
+
- [ ] Skill reports state in one short sentence, doesn't dump raw tool output.
|
|
33
|
+
|
|
34
|
+
## Case 2: Failure — game is already running
|
|
35
|
+
|
|
36
|
+
**Fixture:** Game already running.
|
|
37
|
+
|
|
38
|
+
**Input:** "Play."
|
|
39
|
+
|
|
40
|
+
**Expected behavior:**
|
|
41
|
+
|
|
42
|
+
- `summer_is_running` returns true.
|
|
43
|
+
- Skill asks: "It's already playing. Stop and restart, or leave it?"
|
|
44
|
+
- Waits for user.
|
|
45
|
+
- On "leave it": no further calls. On "stop and restart": `summer_stop`, then continues from step 2.
|
|
46
|
+
|
|
47
|
+
**Assertions:**
|
|
48
|
+
|
|
49
|
+
- [ ] Skill does not unilaterally restart.
|
|
50
|
+
- [ ] Skill does not unilaterally `summer_stop` without asking.
|
|
51
|
+
|
|
52
|
+
## Case 3: Compile error before play
|
|
53
|
+
|
|
54
|
+
**Fixture:** Script error in `scripts/player.gd:14` (typo). Game not running.
|
|
55
|
+
|
|
56
|
+
**Input:** "Play."
|
|
57
|
+
|
|
58
|
+
**Expected behavior:**
|
|
59
|
+
|
|
60
|
+
- `summer_is_running` → false.
|
|
61
|
+
- `summer_get_script_errors` → returns error.
|
|
62
|
+
- Skill stops, surfaces the error, suggests `/debug`.
|
|
63
|
+
- Does NOT call `summer_play` (would just produce more noise).
|
|
64
|
+
|
|
65
|
+
**Assertions:**
|
|
66
|
+
|
|
67
|
+
- [ ] No `summer_play` call when script errors are present.
|
|
68
|
+
- [ ] Error message is one line, not raw tool output.
|
|
69
|
+
- [ ] Skill explicitly mentions `/debug` as the next move.
|
|
70
|
+
|
|
71
|
+
## Case 4: Runtime crash
|
|
72
|
+
|
|
73
|
+
**Fixture:** Compiles fine. Game crashes on first frame (e.g. null pointer in `_ready`).
|
|
74
|
+
|
|
75
|
+
**Input:** "Play."
|
|
76
|
+
|
|
77
|
+
**Expected behavior:**
|
|
78
|
+
|
|
79
|
+
- Steps 1–5 run normally.
|
|
80
|
+
- `summer_get_debugger_errors` returns a stack trace.
|
|
81
|
+
- Skill reports the crash in one line and offers `/debug`.
|
|
82
|
+
- Does NOT auto-`summer_stop` — the user might want to inspect.
|
|
83
|
+
|
|
84
|
+
**Assertions:**
|
|
85
|
+
|
|
86
|
+
- [ ] Skill detects the crash via `summer_get_debugger_errors`, not by absence of output.
|
|
87
|
+
- [ ] Crash report is concise: error class, location, message.
|
|
88
|
+
- [ ] Skill explicitly mentions `/debug` as the next move.
|
|
@@ -4,6 +4,7 @@ description: Decision guide for how to create different game asset types — gen
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: asset-pipeline
|
|
7
|
+
user-invocable: false
|
|
7
8
|
allowed-tools: Read Grep summer_search_assets summer_import_asset summer_generate_image summer_generate_3d summer_generate_audio summer_import_from_url
|
|
8
9
|
---
|
|
9
10
|
|
package/skills/catalog.yaml
CHANGED
|
@@ -138,6 +138,13 @@ skills:
|
|
|
138
138
|
public: true
|
|
139
139
|
recommended: true
|
|
140
140
|
last-tested: 2026-05-05
|
|
141
|
+
- name: play
|
|
142
|
+
category: scene-and-project
|
|
143
|
+
status: HAVE
|
|
144
|
+
public: true
|
|
145
|
+
recommended: true
|
|
146
|
+
user-invocable: true
|
|
147
|
+
last-tested: 2026-05-05
|
|
141
148
|
- name: make-game
|
|
142
149
|
category: scene-and-project
|
|
143
150
|
status: HAVE
|
|
@@ -600,11 +607,14 @@ skills:
|
|
|
600
607
|
public: true
|
|
601
608
|
|
|
602
609
|
# ── debugging ──
|
|
603
|
-
- name:
|
|
610
|
+
- name: debug
|
|
604
611
|
category: debugging
|
|
605
|
-
status:
|
|
612
|
+
status: HAVE
|
|
606
613
|
public: true
|
|
607
|
-
|
|
614
|
+
recommended: true
|
|
615
|
+
user-invocable: true
|
|
616
|
+
last-tested: 2026-05-05
|
|
617
|
+
- name: debugger-basics
|
|
608
618
|
category: debugging
|
|
609
619
|
status: NEXT
|
|
610
620
|
public: true
|
|
@@ -4,6 +4,7 @@ description: First-person character controller with WASD movement, mouse look, j
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: character-controllers
|
|
7
|
+
user-invocable: false
|
|
7
8
|
template-id: template-3d-fps
|
|
8
9
|
allowed-tools: Read Grep summer_add_node summer_set_prop summer_set_resource_property summer_input_map_bind summer_save_scene summer_get_script_errors
|
|
9
10
|
paths: ["**/*.gd", "**/*.tscn"]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug
|
|
3
|
+
description: Use when the user reports their game is broken, crashing, behaving unexpectedly, or says "debug", "fix", "something's wrong", or "it's not working". Triages the bug end-to-end via Summer Engine's diagnostic tools (console, debugger errors, script errors), locates the offending code, proposes a fix, and verifies the fix.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: debugging
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: Read Grep Glob Edit summer_get_console summer_get_debugger_errors summer_get_script_errors summer_get_diagnostics summer_clear_console summer_play summer_stop summer_is_running summer_get_scene_tree summer_inspect_node
|
|
9
|
+
paths: ["**/*.gd", "**/*.tscn", "**/*.cs"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /debug — Triage and Fix a Bug
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
A bug in a Godot/Summer game can hide in three places: scripts (GDScript/C# compile or runtime errors), the engine console (printed messages, warnings), or the scene/resource state (wrong property, missing collider, broken signal connection). This skill walks all three before guessing.
|
|
17
|
+
|
|
18
|
+
**Core principle:** read what the engine actually saw, not what the code looks like it does.
|
|
19
|
+
|
|
20
|
+
## Steps
|
|
21
|
+
|
|
22
|
+
### 1. Get the user's description first
|
|
23
|
+
|
|
24
|
+
Ask one short question:
|
|
25
|
+
|
|
26
|
+
> What's happening? Briefly: when does it go wrong, and what do you expect vs. what you see?
|
|
27
|
+
|
|
28
|
+
Wait for the answer before doing anything else. Don't start grepping code yet — the user's words narrow the search 10x.
|
|
29
|
+
|
|
30
|
+
### 2. Read the engine's actual error state
|
|
31
|
+
|
|
32
|
+
Always do this in order. Each tool answers a different question.
|
|
33
|
+
|
|
34
|
+
**Preferred (Summer MCP):**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
summer_get_script_errors # Compile errors? (cheapest, do first)
|
|
38
|
+
summer_get_console # Print() output, warnings, info
|
|
39
|
+
summer_get_debugger_errors # Runtime errors with stack traces
|
|
40
|
+
summer_get_diagnostics # Aggregated count + summary
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If the bug is reproducible only at runtime and the engine isn't currently playing:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
summer_clear_console # Clean slate
|
|
47
|
+
summer_play # Run it
|
|
48
|
+
# (let the user reproduce the bug)
|
|
49
|
+
summer_get_debugger_errors # Now read what blew up
|
|
50
|
+
summer_stop # When done
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Fallback (no MCP — engine isn't connected):**
|
|
54
|
+
|
|
55
|
+
Ask the user to copy-paste the engine's Output panel and Debugger errors. Inspect manually.
|
|
56
|
+
|
|
57
|
+
### 3. Locate the offending code
|
|
58
|
+
|
|
59
|
+
For each error, follow the stack trace to the file + line. Use host file tools:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Read <file>:<line-near-error>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Read 20–40 lines around the error site. Don't open the whole file unless you need to — context budget matters.
|
|
66
|
+
|
|
67
|
+
If the error mentions a node path (e.g. `./World/Player/Camera`), inspect it:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
summer_inspect_node "./World/Player/Camera"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 4. Form a hypothesis and propose the fix
|
|
74
|
+
|
|
75
|
+
State it in one sentence:
|
|
76
|
+
|
|
77
|
+
> The error happens because <root cause>. The fix is <one-line summary>.
|
|
78
|
+
|
|
79
|
+
Then ask:
|
|
80
|
+
|
|
81
|
+
> May I edit `<file>` to <do exactly this>?
|
|
82
|
+
|
|
83
|
+
Don't guess at multiple fixes at once. Pick one. If wrong, the next iteration is cheap.
|
|
84
|
+
|
|
85
|
+
### 5. Apply the fix
|
|
86
|
+
|
|
87
|
+
On user yes, edit the file with host tools (`Edit`/`Write`). Single focused change.
|
|
88
|
+
|
|
89
|
+
### 6. Verify
|
|
90
|
+
|
|
91
|
+
Re-run the relevant check:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
summer_get_script_errors # If it was a compile error
|
|
95
|
+
summer_play → summer_get_debugger_errors → summer_stop # If runtime
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Report:
|
|
99
|
+
|
|
100
|
+
> Fixed. <One-line description of what changed.>
|
|
101
|
+
|
|
102
|
+
If still broken: go back to step 4 with the new error state. State explicitly that the first hypothesis was wrong.
|
|
103
|
+
|
|
104
|
+
## Common bug patterns and how to spot them
|
|
105
|
+
|
|
106
|
+
| Symptom | Likely cause | First check |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| `Invalid set index 'X' (on base: Nil)` | Node path resolved to null | `summer_inspect_node` the path |
|
|
109
|
+
| `Identifier not declared` (script error) | Missing `class_name` or wrong scope | `summer_get_script_errors` |
|
|
110
|
+
| Game runs but sprite doesn't appear | Node added but not visible (transform / parent / layer) | `summer_get_scene_tree` + inspect parent |
|
|
111
|
+
| Signal handler never fires | Connection not made, or connected to wrong instance | `summer_inspect_node` of emitter, check connections |
|
|
112
|
+
| Player falls through floor | CollisionShape3D has no shape, or shape is inline sub_resource | `summer_inspect_resource` on the CollisionShape |
|
|
113
|
+
| Mouse capture stuck | `Input.set_mouse_mode` not paired with release on focus loss | `summer_get_console` for warnings |
|
|
114
|
+
| Game hangs on start | Infinite loop in `_ready()` or `_process()` | `summer_get_debugger_errors` after a forced stop |
|
|
115
|
+
|
|
116
|
+
## Anti-patterns (don't do these)
|
|
117
|
+
|
|
118
|
+
- **Don't** start by reading the user's whole codebase. The error tells you where to look.
|
|
119
|
+
- **Don't** propose a sweeping refactor for a single bug. One file, one change, verify.
|
|
120
|
+
- **Don't** call `summer_set_resource_property` on an inline `sub_resource` — it silently fails. See `_shared/mcp-tools-reference.md` § "Trap".
|
|
121
|
+
- **Don't** call `summer_play` without `summer_clear_console` first if you want clean output to read.
|
|
122
|
+
- **Don't** skip the user's description in step 1. "What were you trying to do" beats "what does the code do" 9/10 times.
|
|
123
|
+
|
|
124
|
+
## Collaborative protocol
|
|
125
|
+
|
|
126
|
+
This skill writes files. Always ask before each edit step. See `_shared/collaborative-protocol.md`.
|
|
127
|
+
|
|
128
|
+
## Want a working starter?
|
|
129
|
+
|
|
130
|
+
No template — this is a workflow, not a project scaffold. It works against any Godot/Summer project that has Summer MCP wired up.
|
|
131
|
+
|
|
132
|
+
## See also
|
|
133
|
+
|
|
134
|
+
- `_shared/mcp-tools-reference.md` — full tool list
|
|
135
|
+
- `_shared/godot-version.md` — engine version + LLM cutoff risks
|
|
136
|
+
- `scripting-patterns/gdscript-patterns/SKILL.md` — what good GDScript looks like
|
|
137
|
+
- `scene-and-project/play/SKILL.md` — running the game
|
|
@@ -4,6 +4,7 @@ description: Lighting setup, WorldEnvironment, sky, and shadows for 3D scenes. U
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: rendering-and-lighting
|
|
7
|
+
user-invocable: false
|
|
7
8
|
allowed-tools: Read Grep summer_add_node summer_set_prop summer_set_resource_property summer_save_scene
|
|
8
9
|
paths: ["**/*.tscn", "**/*.tres"]
|
|
9
10
|
---
|
|
@@ -4,6 +4,7 @@ description: End-to-end game creation workflow that orchestrates project setup,
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: scene-and-project
|
|
7
|
+
user-invocable: false
|
|
7
8
|
allowed-tools: Read Grep Glob Write Edit summer_get_project_context summer_get_agent_playbook summer_create_scene summer_open_scene summer_save_scene summer_add_node summer_set_prop summer_set_resource_property summer_instantiate_scene summer_play summer_stop summer_get_diagnostics
|
|
8
9
|
paths: ["**/*.gd", "**/*.tscn", "**/project.godot"]
|
|
9
10
|
---
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: play
|
|
3
|
+
description: Use when the user says "play", "run it", "test it", "let me see it", or "start the game". Runs the project in Summer Engine, briefly waits, then reports what's happening — clean run, errors, or warnings.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: scene-and-project
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: summer_is_running summer_play summer_stop summer_clear_console summer_get_console summer_get_debugger_errors summer_get_script_errors summer_get_diagnostics
|
|
9
|
+
paths: ["**/project.godot", "**/*.tscn"]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /play — Run the Game
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
Press play. Watch what happens. Report it back.
|
|
17
|
+
|
|
18
|
+
## Steps
|
|
19
|
+
|
|
20
|
+
### 1. Check if it's already running
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
summer_is_running
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If running:
|
|
27
|
+
> The game is already playing. Stop and restart, or leave it?
|
|
28
|
+
|
|
29
|
+
Wait for the user. Don't unilaterally stop.
|
|
30
|
+
|
|
31
|
+
If not running, continue.
|
|
32
|
+
|
|
33
|
+
### 2. Pre-check for compile errors
|
|
34
|
+
|
|
35
|
+
Cheapest call. If the script won't compile, play will fail with a noisy error — better to surface that clearly first.
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
summer_get_script_errors
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If errors found:
|
|
42
|
+
> Won't run yet — there's a script error: `<one-line summary>`. Want me to /debug it?
|
|
43
|
+
|
|
44
|
+
Stop here on user's no.
|
|
45
|
+
|
|
46
|
+
### 3. Clear and play
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
summer_clear_console
|
|
50
|
+
summer_play
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 4. Brief wait, then read state
|
|
54
|
+
|
|
55
|
+
Wait ~2 seconds (so the engine has time to process at least one frame). Then:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
summer_get_diagnostics
|
|
59
|
+
summer_get_debugger_errors
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 5. Report
|
|
63
|
+
|
|
64
|
+
Three outcomes:
|
|
65
|
+
|
|
66
|
+
**Clean:** `summer_get_diagnostics` shows zero errors and zero warnings.
|
|
67
|
+
|
|
68
|
+
> Running. No errors or warnings. Tell me what you see and I'll dig in if needed.
|
|
69
|
+
|
|
70
|
+
**Warnings only:**
|
|
71
|
+
|
|
72
|
+
> Running. <N> warnings — `<one-line summary of the most important one>`. Want me to look at them?
|
|
73
|
+
|
|
74
|
+
**Runtime error:**
|
|
75
|
+
|
|
76
|
+
> Crashed: `<error class>` at `<file>:<line>` — `<message>`. Want me to /debug?
|
|
77
|
+
|
|
78
|
+
### 6. Don't auto-stop
|
|
79
|
+
|
|
80
|
+
Leave the game running. The user wants to play it. Stop only on explicit ask.
|
|
81
|
+
|
|
82
|
+
## Common patterns
|
|
83
|
+
|
|
84
|
+
| Situation | Right move |
|
|
85
|
+
|---|---|
|
|
86
|
+
| User says "play" with no context | Steps 1–5 above |
|
|
87
|
+
| User says "play and watch it for me" | After step 5, set a timer / poll `summer_get_debugger_errors` every few seconds for the duration the user specifies |
|
|
88
|
+
| User says "play the boss fight scene" | Open the specific scene first (`summer_open_scene "scenes/boss_fight.tscn"`), then steps 1–5 |
|
|
89
|
+
| Game is already running and user says "play" again | Step 1's check covers it — ask before restarting |
|
|
90
|
+
|
|
91
|
+
## Anti-patterns
|
|
92
|
+
|
|
93
|
+
- **Don't** auto-stop a running game just because the user said "play". They probably mean "make sure it's playing", not "stop and restart".
|
|
94
|
+
- **Don't** call `summer_get_console` instead of `summer_get_debugger_errors` for runtime errors. Console has print() output and warnings; debugger errors has the stack traces.
|
|
95
|
+
- **Don't** report "no errors" before waiting for the engine to actually run a frame. A 0-frame snapshot is meaningless.
|
|
96
|
+
|
|
97
|
+
## Collaborative protocol
|
|
98
|
+
|
|
99
|
+
This skill mutates engine state (clearing console, starting play). It's a read-side workflow with one safe write (`summer_play`). No "May I" needed — this is what the user asked for. Do confirm before stopping a running game.
|
|
100
|
+
|
|
101
|
+
## Want a working starter?
|
|
102
|
+
|
|
103
|
+
No template — works against any Godot/Summer project that has a main scene set in `project.godot`.
|
|
104
|
+
|
|
105
|
+
## See also
|
|
106
|
+
|
|
107
|
+
- `_shared/mcp-tools-reference.md` — full tool list
|
|
108
|
+
- `debugging/debug/SKILL.md` — what to do when /play surfaces an error
|
|
@@ -4,6 +4,7 @@ description: How to structure scenes, when to use sub-scenes, node hierarchy con
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: scene-and-project
|
|
7
|
+
user-invocable: false
|
|
7
8
|
allowed-tools: Read Grep summer_create_scene summer_open_scene summer_get_scene_tree summer_add_node summer_instantiate_scene summer_save_scene
|
|
8
9
|
paths: ["**/*.tscn"]
|
|
9
10
|
---
|
|
@@ -4,6 +4,7 @@ description: Common GDScript idioms — type hints, signals, exports, onready, l
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: scripting-patterns
|
|
7
|
+
user-invocable: false
|
|
7
8
|
allowed-tools: Read Grep summer_get_script_errors
|
|
8
9
|
paths: ["**/*.gd"]
|
|
9
10
|
---
|
|
@@ -4,6 +4,7 @@ description: HUD, menus, health bars, progress bars, and Control-based UI layout
|
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
6
|
category: ui-and-ux
|
|
7
|
+
user-invocable: false
|
|
7
8
|
allowed-tools: Read Grep summer_add_node summer_set_prop summer_connect_signal summer_save_scene
|
|
8
9
|
paths: ["**/*.tscn", "**/*.gd"]
|
|
9
10
|
---
|