summer-engine 1.2.0 → 1.3.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/LICENSE +21 -0
- package/README.md +58 -24
- package/dist/bin/summer.js +4 -0
- package/dist/commands/doctor.d.ts +26 -0
- package/dist/commands/doctor.js +248 -0
- package/dist/commands/doctor.test.d.ts +1 -0
- package/dist/commands/doctor.test.js +29 -0
- package/dist/commands/mcp.js +49 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +128 -0
- package/dist/commands/skills.js +254 -109
- package/dist/lib/agent-config.d.ts +39 -0
- package/dist/lib/agent-config.js +284 -0
- package/dist/lib/agent-config.test.d.ts +1 -0
- package/dist/lib/agent-config.test.js +80 -0
- package/dist/lib/api-client.d.ts +19 -2
- package/dist/lib/api-client.js +129 -14
- package/dist/lib/skills-registry.d.ts +75 -0
- package/dist/lib/skills-registry.js +143 -0
- package/dist/mcp/tools/project-tools.js +100 -23
- package/dist/mcp/tools/with-engine.js +3 -53
- package/package.json +5 -2
- package/skills/README.md +96 -0
- package/skills/_meta/skill-create/SKILL.md +143 -0
- package/skills/_meta/skill-improve/SKILL.md +89 -0
- package/skills/_meta/skill-test/SKILL.md +86 -0
- package/skills/_shared/collaborative-protocol.md +50 -0
- package/skills/_shared/gd-style.md +121 -0
- package/skills/_shared/godot-version.md +32 -0
- package/skills/_shared/mcp-tools-reference.md +133 -0
- package/skills/_shared/template-registry.md +40 -0
- package/skills/_tests/runner.md +90 -0
- package/skills/_tests/specs/3d-lighting.md +19 -0
- package/skills/_tests/specs/asset-strategy.md +19 -0
- package/skills/_tests/specs/fps-controller.md +100 -0
- package/skills/_tests/specs/gdscript-patterns.md +19 -0
- package/skills/_tests/specs/make-game.md +19 -0
- package/skills/_tests/specs/scene-composition.md +19 -0
- package/skills/_tests/specs/ui-basics.md +19 -0
- package/skills/{asset-strategy → asset-pipeline/asset-strategy}/SKILL.md +4 -5
- package/skills/catalog.yaml +636 -0
- package/skills/{fps-controller → character-controllers/fps-controller}/SKILL.md +6 -5
- package/skills/{3d-lighting → rendering-and-lighting/3d-lighting}/SKILL.md +5 -5
- package/skills/{make-game → scene-and-project/make-game}/SKILL.md +8 -8
- package/skills/{scene-composition → scene-and-project/scene-composition}/SKILL.md +6 -6
- package/skills/{gdscript-patterns → scripting-patterns/gdscript-patterns}/SKILL.md +7 -7
- package/skills/{ui-basics → ui-and-ux/ui-basics}/SKILL.md +5 -5
- /package/skills/{gdscript-patterns → scripting-patterns/gdscript-patterns}/reference.md +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const AGENT_CLIENTS = [
|
|
2
|
+
"summer",
|
|
3
|
+
"codex",
|
|
4
|
+
"claude-code",
|
|
5
|
+
"cursor",
|
|
6
|
+
"windsurf",
|
|
7
|
+
];
|
|
8
|
+
export const SKILL_CATEGORIES = [
|
|
9
|
+
"_meta",
|
|
10
|
+
"character-controllers",
|
|
11
|
+
"gameplay-mechanics",
|
|
12
|
+
"scripting-patterns",
|
|
13
|
+
"scene-and-project",
|
|
14
|
+
"rendering-and-lighting",
|
|
15
|
+
"shaders",
|
|
16
|
+
"visual-effects",
|
|
17
|
+
"post-processing",
|
|
18
|
+
"animation",
|
|
19
|
+
"audio",
|
|
20
|
+
"physics",
|
|
21
|
+
"multiplayer-and-networking",
|
|
22
|
+
"ai-and-npcs",
|
|
23
|
+
"level-design",
|
|
24
|
+
"performance",
|
|
25
|
+
"ui-and-ux",
|
|
26
|
+
"asset-pipeline",
|
|
27
|
+
"input-and-controls",
|
|
28
|
+
"debugging",
|
|
29
|
+
"deployment",
|
|
30
|
+
];
|
|
31
|
+
const ALL_CLIENTS = AGENT_CLIENTS;
|
|
32
|
+
/**
|
|
33
|
+
* Skills with `status: HAVE` in catalog.yaml. The catalog is the planning source
|
|
34
|
+
* of truth (~85 skills); this TS registry is the install-time list (only skills
|
|
35
|
+
* with shippable content). When a NEXT skill ships, mirror it here.
|
|
36
|
+
*/
|
|
37
|
+
export const SKILL_REGISTRY = [
|
|
38
|
+
{
|
|
39
|
+
name: "gdscript-patterns",
|
|
40
|
+
category: "scripting-patterns",
|
|
41
|
+
public: true,
|
|
42
|
+
clients: ALL_CLIENTS,
|
|
43
|
+
recommended: true,
|
|
44
|
+
requiresMcpTools: [
|
|
45
|
+
"summer_get_script_errors",
|
|
46
|
+
],
|
|
47
|
+
testScenario: "Write a typed GDScript with a signal, attach it to a node, connect the signal, and verify script errors.",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "scene-composition",
|
|
51
|
+
category: "scene-and-project",
|
|
52
|
+
public: true,
|
|
53
|
+
clients: ALL_CLIENTS,
|
|
54
|
+
recommended: true,
|
|
55
|
+
requiresMcpTools: [
|
|
56
|
+
"summer_create_scene",
|
|
57
|
+
"summer_open_scene",
|
|
58
|
+
"summer_get_scene_tree",
|
|
59
|
+
"summer_add_node",
|
|
60
|
+
"summer_instantiate_scene",
|
|
61
|
+
"summer_save_scene",
|
|
62
|
+
],
|
|
63
|
+
testScenario: "Build a small reusable player scene, instantiate it in a main scene, and save both scenes through Summer tools.",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "fps-controller",
|
|
67
|
+
category: "character-controllers",
|
|
68
|
+
public: true,
|
|
69
|
+
clients: ALL_CLIENTS,
|
|
70
|
+
recommended: true,
|
|
71
|
+
requiresMcpTools: [
|
|
72
|
+
"summer_add_node",
|
|
73
|
+
"summer_set_prop",
|
|
74
|
+
"summer_set_resource_property",
|
|
75
|
+
"summer_input_map_bind",
|
|
76
|
+
],
|
|
77
|
+
testScenario: "Create a CharacterBody3D player with collision, camera, input actions, and a host-edited controller script.",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "3d-lighting",
|
|
81
|
+
category: "rendering-and-lighting",
|
|
82
|
+
public: true,
|
|
83
|
+
clients: ALL_CLIENTS,
|
|
84
|
+
recommended: true,
|
|
85
|
+
requiresMcpTools: [
|
|
86
|
+
"summer_add_node",
|
|
87
|
+
"summer_set_prop",
|
|
88
|
+
"summer_set_resource_property",
|
|
89
|
+
],
|
|
90
|
+
testScenario: "Add sun, fill lighting, WorldEnvironment, and shadow settings to a simple 3D scene.",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "ui-basics",
|
|
94
|
+
category: "ui-and-ux",
|
|
95
|
+
public: true,
|
|
96
|
+
clients: ALL_CLIENTS,
|
|
97
|
+
recommended: true,
|
|
98
|
+
requiresMcpTools: [
|
|
99
|
+
"summer_add_node",
|
|
100
|
+
"summer_set_prop",
|
|
101
|
+
"summer_connect_signal",
|
|
102
|
+
],
|
|
103
|
+
testScenario: "Create a HUD CanvasLayer with labels, a ProgressBar, and a connected Button signal.",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "asset-strategy",
|
|
107
|
+
category: "asset-pipeline",
|
|
108
|
+
public: true,
|
|
109
|
+
clients: ALL_CLIENTS,
|
|
110
|
+
recommended: true,
|
|
111
|
+
requiresMcpTools: [
|
|
112
|
+
"summer_search_assets",
|
|
113
|
+
"summer_import_asset",
|
|
114
|
+
"summer_import_from_url",
|
|
115
|
+
"summer_generate_image",
|
|
116
|
+
"summer_generate_3d",
|
|
117
|
+
"summer_generate_audio",
|
|
118
|
+
],
|
|
119
|
+
testScenario: "Choose library, generated, or primitive assets for a small level and import one asset into the project.",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "make-game",
|
|
123
|
+
category: "scene-and-project",
|
|
124
|
+
public: true,
|
|
125
|
+
clients: ALL_CLIENTS,
|
|
126
|
+
recommended: false,
|
|
127
|
+
requiresMcpTools: [
|
|
128
|
+
"summer_get_agent_playbook",
|
|
129
|
+
"summer_get_project_context",
|
|
130
|
+
"summer_create_scene",
|
|
131
|
+
"summer_open_scene",
|
|
132
|
+
"summer_save_scene",
|
|
133
|
+
"summer_add_node",
|
|
134
|
+
"summer_set_prop",
|
|
135
|
+
"summer_set_resource_property",
|
|
136
|
+
"summer_instantiate_scene",
|
|
137
|
+
"summer_play",
|
|
138
|
+
"summer_stop",
|
|
139
|
+
"summer_get_diagnostics",
|
|
140
|
+
],
|
|
141
|
+
testScenario: "Build one narrow playable prototype from requirements through scene setup, host-edited scripts, and diagnostics.",
|
|
142
|
+
},
|
|
143
|
+
];
|
|
@@ -1,18 +1,83 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { withEngine } from "./with-engine.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
function asRecord(value) {
|
|
4
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
5
|
+
? value
|
|
6
|
+
: null;
|
|
7
|
+
}
|
|
8
|
+
function stringFrom(value) {
|
|
9
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
10
|
+
}
|
|
11
|
+
function pickString(record, keys) {
|
|
12
|
+
if (!record)
|
|
7
13
|
return null;
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
for (const key of keys) {
|
|
15
|
+
const value = stringFrom(record[key]);
|
|
16
|
+
if (value)
|
|
17
|
+
return value;
|
|
12
18
|
}
|
|
13
|
-
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function getProjectData(projectState) {
|
|
22
|
+
return asRecord(asRecord(projectState)?.data);
|
|
23
|
+
}
|
|
24
|
+
function getProjectSetting(projectState, keys) {
|
|
25
|
+
const data = getProjectData(projectState);
|
|
26
|
+
const entries = data?.entries;
|
|
27
|
+
if (!Array.isArray(entries))
|
|
14
28
|
return null;
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const item = asRecord(entry);
|
|
31
|
+
const key = stringFrom(item?.key);
|
|
32
|
+
if (key && keys.includes(key)) {
|
|
33
|
+
return stringFrom(item?.value);
|
|
34
|
+
}
|
|
15
35
|
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function getProjectPath(projectState) {
|
|
39
|
+
const root = asRecord(projectState);
|
|
40
|
+
const data = getProjectData(projectState);
|
|
41
|
+
return (pickString(data, [
|
|
42
|
+
"projectPath",
|
|
43
|
+
"project_path",
|
|
44
|
+
"projectRoot",
|
|
45
|
+
"project_root",
|
|
46
|
+
"rootPath",
|
|
47
|
+
"root_path",
|
|
48
|
+
]) ??
|
|
49
|
+
pickString(root, ["projectPath", "project_path", "projectRoot", "project_root"]) ??
|
|
50
|
+
null);
|
|
51
|
+
}
|
|
52
|
+
function getProjectName(projectState) {
|
|
53
|
+
const root = asRecord(projectState);
|
|
54
|
+
const data = getProjectData(projectState);
|
|
55
|
+
return (pickString(data, ["projectName", "project_name", "name"]) ??
|
|
56
|
+
pickString(root, ["projectName", "project_name", "name"]) ??
|
|
57
|
+
getProjectSetting(projectState, ["application/config/name", "config/name"]));
|
|
58
|
+
}
|
|
59
|
+
function getMainScene(projectState) {
|
|
60
|
+
const root = asRecord(projectState);
|
|
61
|
+
const data = getProjectData(projectState);
|
|
62
|
+
return (pickString(data, ["mainScene", "main_scene", "mainScenePath", "main_scene_path"]) ??
|
|
63
|
+
pickString(root, ["mainScene", "main_scene", "mainScenePath", "main_scene_path"]) ??
|
|
64
|
+
getProjectSetting(projectState, [
|
|
65
|
+
"application/run/main_scene",
|
|
66
|
+
"run/main_scene",
|
|
67
|
+
]));
|
|
68
|
+
}
|
|
69
|
+
function getCurrentScene(projectState, sceneState) {
|
|
70
|
+
const sceneRoot = asRecord(sceneState);
|
|
71
|
+
const sceneData = asRecord(sceneRoot?.data);
|
|
72
|
+
const sceneProvenance = asRecord(sceneRoot?.provenance);
|
|
73
|
+
const projectRoot = asRecord(projectState);
|
|
74
|
+
const projectData = getProjectData(projectState);
|
|
75
|
+
const projectProvenance = asRecord(projectRoot?.provenance);
|
|
76
|
+
return (pickString(sceneProvenance, ["scenePath", "scene_path"]) ??
|
|
77
|
+
pickString(sceneData, ["scenePath", "scene_path", "currentScene", "current_scene"]) ??
|
|
78
|
+
pickString(projectData, ["currentScene", "current_scene", "scenePath", "scene_path"]) ??
|
|
79
|
+
pickString(projectProvenance, ["scenePath", "scene_path"]) ??
|
|
80
|
+
null);
|
|
16
81
|
}
|
|
17
82
|
export function registerProjectTools(server) {
|
|
18
83
|
server.tool("summer_get_agent_playbook", `AI-first operating guide for Summer Engine MCP.
|
|
@@ -25,7 +90,8 @@ It returns the safe workflow, anti-patterns, and recovery steps.`, {}, async ()
|
|
|
25
90
|
text: JSON.stringify({
|
|
26
91
|
startupChecklist: [
|
|
27
92
|
"Decide first: file edit or engine operation.",
|
|
28
|
-
"
|
|
93
|
+
"Write .gd/.cs/.json/docs/simple config with host file-edit tools directly.",
|
|
94
|
+
"Use Summer MCP for live scene state, inspector/node edits, imports, play/stop, diagnostics, screenshots/verification.",
|
|
29
95
|
"Call summer_get_project_context first.",
|
|
30
96
|
"If no scene is open, call summer_open_main_scene.",
|
|
31
97
|
"Call summer_get_scene_tree before structural edits.",
|
|
@@ -33,15 +99,16 @@ It returns the safe workflow, anti-patterns, and recovery steps.`, {}, async ()
|
|
|
33
99
|
],
|
|
34
100
|
safeDefaults: [
|
|
35
101
|
"Never guess scene filenames (main.tscn/Main.tscn).",
|
|
36
|
-
"Do not route ordinary
|
|
102
|
+
"Do not route ordinary script, JSON, docs, or simple config edits through MCP when direct file tools are available.",
|
|
37
103
|
"Never remove multiple top-level nodes unless user explicitly requests destructive edits.",
|
|
38
|
-
"
|
|
104
|
+
"Use MCP for scene-tree mutations and inspector-visible values instead of hand-editing live scene state.",
|
|
39
105
|
],
|
|
40
106
|
preferredFlow: [
|
|
41
107
|
"summer_get_project_context",
|
|
42
108
|
"summer_open_main_scene (if needed)",
|
|
43
109
|
"summer_get_scene_tree",
|
|
44
110
|
"edit via summer_add_node / summer_set_prop / summer_set_resource_property",
|
|
111
|
+
"write scripts/data/docs/simple config directly with host file-edit tools",
|
|
45
112
|
"summer_save_scene",
|
|
46
113
|
"summer_get_diagnostics",
|
|
47
114
|
],
|
|
@@ -56,35 +123,45 @@ It returns the safe workflow, anti-patterns, and recovery steps.`, {}, async ()
|
|
|
56
123
|
}));
|
|
57
124
|
server.tool("summer_get_project_context", `Get essential project context before editing. Returns:
|
|
58
125
|
- engine health/status
|
|
59
|
-
- project name and path
|
|
126
|
+
- project name and project path when exposed by project state
|
|
60
127
|
- current scene path (if available)
|
|
61
|
-
- main scene path from project
|
|
128
|
+
- main scene path from project settings
|
|
62
129
|
|
|
63
130
|
Use this first in every fresh chat to avoid guessing scene filenames or editing the wrong scene.`, {}, async () => withEngine(async (client) => {
|
|
64
|
-
const [health, projectState] = await Promise.all([
|
|
131
|
+
const [health, projectState, sceneState] = await Promise.all([
|
|
65
132
|
client.health(),
|
|
66
133
|
client.getProjectState(),
|
|
134
|
+
client.getSceneState().catch((err) => ({
|
|
135
|
+
ok: false,
|
|
136
|
+
error: err instanceof Error ? err.message : String(err),
|
|
137
|
+
})),
|
|
67
138
|
]);
|
|
68
|
-
const
|
|
69
|
-
const
|
|
139
|
+
const projectPath = getProjectPath(projectState);
|
|
140
|
+
const projectName = getProjectName(projectState);
|
|
141
|
+
const mainScene = getMainScene(projectState);
|
|
142
|
+
const currentScene = getCurrentScene(projectState, sceneState);
|
|
70
143
|
return {
|
|
71
144
|
health,
|
|
72
145
|
project: projectState,
|
|
146
|
+
scene: sceneState,
|
|
147
|
+
projectName,
|
|
148
|
+
projectPath,
|
|
149
|
+
currentScene,
|
|
73
150
|
mainScene,
|
|
74
151
|
guidance: mainScene
|
|
75
152
|
? "Use `summer_open_scene` with `mainScene` if no scene is open."
|
|
76
|
-
: "Main scene not found in project.
|
|
153
|
+
: "Main scene not found in project state. Open a known scene path explicitly.",
|
|
154
|
+
fileEditingGuidance: "Write .gd/.cs/.json/docs/simple config directly with host file tools. Use MCP for live scene state, inspector/node edits, imports, play/stop, diagnostics, and visual verification.",
|
|
77
155
|
};
|
|
78
156
|
}));
|
|
79
|
-
server.tool("summer_open_main_scene", `Open the project's configured main scene from project.
|
|
157
|
+
server.tool("summer_open_main_scene", `Open the project's configured main scene from project settings.
|
|
80
158
|
|
|
81
159
|
Safer than guessing scene names like main.tscn/Main.tscn.
|
|
82
160
|
Call this when you get "no scene open".`, {}, async () => withEngine(async (client) => {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const mainScene = await readMainSceneFromProject(projectPath);
|
|
161
|
+
const projectState = await client.getProjectState();
|
|
162
|
+
const mainScene = getMainScene(projectState);
|
|
86
163
|
if (!mainScene) {
|
|
87
|
-
throw new Error("Could not resolve application/run/main_scene from project.
|
|
164
|
+
throw new Error("Could not resolve application/run/main_scene from project state. Call `summer_get_project_context` and open a scene explicitly.");
|
|
88
165
|
}
|
|
89
166
|
return client.executeOps([{ op: "OpenScene", path: mainScene }]);
|
|
90
167
|
}));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { getClient, resetClient } from "../server.js";
|
|
2
|
-
import { getAuthToken } from "../../lib/auth.js";
|
|
3
|
-
const GATEWAY_URL = process.env.SUMMER_GATEWAY_URL || "https://www.summerengine.com";
|
|
4
2
|
function extractOpError(result) {
|
|
5
3
|
if (!result || typeof result !== "object")
|
|
6
4
|
return null;
|
|
7
5
|
const op = result;
|
|
6
|
+
if (op.ok === false && op.error)
|
|
7
|
+
return op.error;
|
|
8
8
|
if (op.status === "error" && op.error)
|
|
9
9
|
return op.error;
|
|
10
10
|
const firstFailed = op.results?.find((r) => r.ok === false && r.error);
|
|
@@ -19,62 +19,12 @@ function buildActionHint(message) {
|
|
|
19
19
|
return "Scene path could not be opened. Call `summer_get_project_context` to get `mainScene`, then open that exact path. Avoid guessing scene filenames.";
|
|
20
20
|
}
|
|
21
21
|
if (normalized.includes("writefile cannot edit .tscn/.scn")) {
|
|
22
|
-
return "
|
|
22
|
+
return "Write .gd/.cs/.json/docs/simple config files with normal file-edit tools. Use Summer MCP for live scene state, inspector/node edits, imports, play/stop, diagnostics, and visual verification.";
|
|
23
23
|
}
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
|
-
async function checkMcpQuota() {
|
|
27
|
-
const token = await getAuthToken();
|
|
28
|
-
if (!token) {
|
|
29
|
-
return {
|
|
30
|
-
allowed: false,
|
|
31
|
-
message: "Not signed in. The user needs to run this in their terminal:\n npx summer-engine login\nOr open: https://www.summerengine.com/login\nMCP tools require a Summer Engine account (free to create).",
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
const res = await fetch(`${GATEWAY_URL}/api/mcp/log-local-call`, {
|
|
36
|
-
method: "POST",
|
|
37
|
-
headers: {
|
|
38
|
-
Authorization: `Bearer ${token}`,
|
|
39
|
-
"Content-Type": "application/json",
|
|
40
|
-
},
|
|
41
|
-
body: JSON.stringify({}),
|
|
42
|
-
signal: AbortSignal.timeout(10000),
|
|
43
|
-
});
|
|
44
|
-
const data = (await res.json().catch(() => ({})));
|
|
45
|
-
// Hard enforcement errors should block tool execution.
|
|
46
|
-
if ([401, 402, 403, 429].includes(res.status)) {
|
|
47
|
-
return {
|
|
48
|
-
allowed: false,
|
|
49
|
-
message: data.message || "Quota check failed. Try again.",
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
// Soft-fail on service/gateway issues so local tools keep working.
|
|
53
|
-
if (!res.ok) {
|
|
54
|
-
return { allowed: true };
|
|
55
|
-
}
|
|
56
|
-
if (data.allowed === false) {
|
|
57
|
-
return {
|
|
58
|
-
allowed: false,
|
|
59
|
-
message: data.message || "MCP call limit reached. Upgrade at https://summerengine.com/pricing",
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return { allowed: true };
|
|
63
|
-
}
|
|
64
|
-
catch (err) {
|
|
65
|
-
// Network/transient errors should not brick local MCP usage.
|
|
66
|
-
return { allowed: true };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
26
|
export async function withEngine(fn) {
|
|
70
27
|
try {
|
|
71
|
-
const quota = await checkMcpQuota();
|
|
72
|
-
if (!quota.allowed) {
|
|
73
|
-
return {
|
|
74
|
-
content: [{ type: "text", text: quota.message || "Quota exceeded" }],
|
|
75
|
-
isError: true,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
28
|
const client = await getClient();
|
|
79
29
|
const result = await fn(client);
|
|
80
30
|
const opError = extractOpError(result);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "summer-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "CLI and MCP tools for Summer Engine — the AI-native game engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"game-engine",
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
"build": "tsc",
|
|
32
32
|
"dev": "tsc --watch",
|
|
33
33
|
"summer": "node dist/bin/summer.js",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
34
36
|
"prepublishOnly": "npm run build"
|
|
35
37
|
},
|
|
36
38
|
"engines": {
|
|
@@ -48,6 +50,7 @@
|
|
|
48
50
|
"devDependencies": {
|
|
49
51
|
"@types/diff": "^7.0.0",
|
|
50
52
|
"@types/node": "^20.0.0",
|
|
51
|
-
"typescript": "^5.5.0"
|
|
53
|
+
"typescript": "^5.5.0",
|
|
54
|
+
"vitest": "^3.2.4"
|
|
52
55
|
}
|
|
53
56
|
}
|
package/skills/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Summer Skill Library
|
|
2
|
+
|
|
3
|
+
The canonical agent-readable game-dev knowledge source for Claude Code, Cursor, Codex, and Windsurf.
|
|
4
|
+
|
|
5
|
+
When an agent is asked to make a game in Godot, this is what it reads to learn how.
|
|
6
|
+
|
|
7
|
+
## Layout
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
skills/
|
|
11
|
+
├── README.md # this file
|
|
12
|
+
├── catalog.yaml # canonical registry (name, category, status, template-id)
|
|
13
|
+
├── _shared/ # cross-skill references every skill can link
|
|
14
|
+
│ ├── godot-version.md
|
|
15
|
+
│ ├── mcp-tools-reference.md
|
|
16
|
+
│ ├── collaborative-protocol.md
|
|
17
|
+
│ ├── template-registry.md
|
|
18
|
+
│ └── gd-style.md
|
|
19
|
+
├── _meta/
|
|
20
|
+
│ ├── skill-test/ # static + behavioral linter
|
|
21
|
+
│ ├── skill-create/ # bootstrap a new skill
|
|
22
|
+
│ └── skill-improve/ # eval-harness iteration
|
|
23
|
+
├── _tests/
|
|
24
|
+
│ ├── runner.md # how /skill-test works
|
|
25
|
+
│ └── specs/ # behavioral specs per skill
|
|
26
|
+
└── <category>/<skill>/
|
|
27
|
+
├── SKILL.md # < 500 lines, frontmatter + body
|
|
28
|
+
├── references/ # loaded on demand
|
|
29
|
+
├── examples/ # working snippets
|
|
30
|
+
└── tests/spec.md # behavioral spec
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Categories (20)
|
|
34
|
+
|
|
35
|
+
`character-controllers`, `gameplay-mechanics`, `scripting-patterns`, `scene-and-project`, `rendering-and-lighting`, `shaders`, `visual-effects`, `post-processing`, `animation`, `audio`, `physics`, `multiplayer-and-networking`, `ai-and-npcs`, `level-design`, `performance`, `ui-and-ux`, `asset-pipeline`, `input-and-controls`, `debugging`, `deployment`.
|
|
36
|
+
|
|
37
|
+
## Standard
|
|
38
|
+
|
|
39
|
+
Adopts the **Anthropic Agent Skills open standard** (`agentskills.io`). Frontmatter:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
---
|
|
43
|
+
name: <kebab-case>
|
|
44
|
+
description: <when-to-use, key trigger phrases first>
|
|
45
|
+
license: MIT
|
|
46
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
47
|
+
category: <one of the 20>
|
|
48
|
+
template-id: <optional, resolved against _shared/template-registry.md>
|
|
49
|
+
allowed-tools: Read Grep summer_add_node summer_set_prop ...
|
|
50
|
+
paths: ["**/*.gd", "**/*.tscn"]
|
|
51
|
+
---
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Cross-portable. Cursor / Codex / Windsurf understand the same SKILL.md.
|
|
55
|
+
|
|
56
|
+
## Authoring rules
|
|
57
|
+
|
|
58
|
+
1. **SKILL.md ≤ 500 lines.** Push detail into `references/`. Progressive disclosure.
|
|
59
|
+
2. **MCP-preferred + file-edit-fallback.** Every code-touching skill must show both paths so the skill works without Summer MCP installed.
|
|
60
|
+
3. **Collaborative protocol.** "May I write…?" before any user-visible mutation. See `_shared/collaborative-protocol.md`.
|
|
61
|
+
4. **Template cross-link.** When a working starter exists, link via `template-id` and the section "Want a working starter?".
|
|
62
|
+
5. **Test spec.** Every non-`_meta` skill ships `tests/spec.md` with at least one Test Case.
|
|
63
|
+
|
|
64
|
+
## Adding a new skill
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
/skill-create
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
(See `_meta/skill-create/SKILL.md`.)
|
|
71
|
+
|
|
72
|
+
## Testing
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
/skill-test <name> # static lint
|
|
76
|
+
/skill-test <name> spec # behavioral spec runner
|
|
77
|
+
/skill-test audit # whole-library audit
|
|
78
|
+
/skill-improve <name> # parallel-eval harness for iteration
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
(See `_meta/skill-test/SKILL.md` and `_tests/runner.md`.)
|
|
82
|
+
|
|
83
|
+
## Roadmap
|
|
84
|
+
|
|
85
|
+
Status legend in `catalog.yaml`:
|
|
86
|
+
|
|
87
|
+
- **HAVE** — ships today.
|
|
88
|
+
- **NEXT** — next wave, in active development.
|
|
89
|
+
- **LATER** — on roadmap.
|
|
90
|
+
|
|
91
|
+
Currently: **7 HAVE / ~50 NEXT / ~30 LATER ≈ 85 skills across 20 categories**. Subagents fill content category by category.
|
|
92
|
+
|
|
93
|
+
## See also
|
|
94
|
+
|
|
95
|
+
- [Architecture spec](../../../publicsummerengine/Docs/superpowers/specs/2026-05-05-skill-library-architecture.md) (lives in publicsummerengine for spec history)
|
|
96
|
+
- [Research notes](../../../publicsummerengine/Docs/superpowers/research/2026-05-05-skill-library-research.md)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-create
|
|
3
|
+
description: Bootstrap a new Summer skill with the canonical folder structure, frontmatter, and stub sections. Use when adding a new skill to the library. Trigger on "create skill", "add skill", "new skill".
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
6
|
+
category: _meta
|
|
7
|
+
allowed-tools: Read Write Glob Grep
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# /skill-create — Bootstrap a New Skill
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
### 1. Get the basics
|
|
15
|
+
|
|
16
|
+
Ask the user:
|
|
17
|
+
- **Name** (kebab-case, ≤ 64 chars). Example: `state-machine-patterns`.
|
|
18
|
+
- **Category** (one of the 20 in `catalog.yaml`). Example: `scripting-patterns`.
|
|
19
|
+
- **One-sentence description** for the frontmatter.
|
|
20
|
+
- **Template-id** (optional). Lookup against `_shared/template-registry.md`.
|
|
21
|
+
|
|
22
|
+
### 2. Create the folder
|
|
23
|
+
|
|
24
|
+
May I create `skills/<category>/<name>/` with this structure?
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
skills/<category>/<name>/
|
|
28
|
+
├── SKILL.md
|
|
29
|
+
├── references/ (empty, populate as needed)
|
|
30
|
+
├── examples/ (empty, populate as needed)
|
|
31
|
+
└── tests/spec.md
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Write SKILL.md (template)
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
---
|
|
38
|
+
name: <name>
|
|
39
|
+
description: <one-sentence what + when. Lead with key trigger phrases.>
|
|
40
|
+
license: MIT
|
|
41
|
+
compatibility: [Cursor, Claude Code, Windsurf, Codex]
|
|
42
|
+
category: <category>
|
|
43
|
+
template-id: <optional template-id from _shared/template-registry.md>
|
|
44
|
+
allowed-tools: Read Grep <summer_* tools this skill uses>
|
|
45
|
+
paths: ["**/*.gd", "**/*.tscn"]
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
# <Title> for Summer Engine
|
|
49
|
+
|
|
50
|
+
<One-paragraph context. Why this exists, who needs it.>
|
|
51
|
+
|
|
52
|
+
## Steps
|
|
53
|
+
|
|
54
|
+
### 1. <First step>
|
|
55
|
+
|
|
56
|
+
**Preferred (Summer MCP):**
|
|
57
|
+
|
|
58
|
+
\`\`\`
|
|
59
|
+
summer_<tool>(...)
|
|
60
|
+
\`\`\`
|
|
61
|
+
|
|
62
|
+
**Fallback (no MCP — edit `<file>` directly):**
|
|
63
|
+
|
|
64
|
+
\`\`\`
|
|
65
|
+
<raw text/code>
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
May I <action>?
|
|
69
|
+
|
|
70
|
+
### 2. <Second step>
|
|
71
|
+
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
## Common mistakes
|
|
75
|
+
|
|
76
|
+
- <mistake 1, with one-line fix>
|
|
77
|
+
- <mistake 2, with one-line fix>
|
|
78
|
+
|
|
79
|
+
## Want a working starter?
|
|
80
|
+
|
|
81
|
+
→ **template-id**: `<template-id>`
|
|
82
|
+
→ **Repo**: <github URL from _shared/template-registry.md>
|
|
83
|
+
→ **Bootstrap**: `summer template clone <template-id> my-game`
|
|
84
|
+
|
|
85
|
+
## See also
|
|
86
|
+
|
|
87
|
+
- `_shared/godot-version.md`
|
|
88
|
+
- `_shared/mcp-tools-reference.md`
|
|
89
|
+
- `_shared/gd-style.md`
|
|
90
|
+
- (other relevant skills)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 4. Write tests/spec.md (template)
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
# Skill Spec: /<name>
|
|
97
|
+
|
|
98
|
+
## Fixture
|
|
99
|
+
- <starting state of the project>
|
|
100
|
+
- <which tools are available — Summer MCP yes/no>
|
|
101
|
+
|
|
102
|
+
## Case 1: Happy Path
|
|
103
|
+
**Input:** "<typical user prompt>"
|
|
104
|
+
**Expected MCP tool sequence (in order):**
|
|
105
|
+
1. <first tool call>
|
|
106
|
+
2. <second>
|
|
107
|
+
|
|
108
|
+
**Assertions:**
|
|
109
|
+
- [ ] <observable outcome>
|
|
110
|
+
- [ ] <skill asks "May I" before any write step>
|
|
111
|
+
|
|
112
|
+
## Case 2: Failure / Edge
|
|
113
|
+
**Fixture:** <something different>
|
|
114
|
+
**Input:** "<edge prompt>"
|
|
115
|
+
**Expected:** <how the skill should adapt>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 5. Register in catalog.yaml
|
|
119
|
+
|
|
120
|
+
Append:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
- name: <name>
|
|
124
|
+
category: <category>
|
|
125
|
+
status: NEXT # or HAVE if shipping immediately
|
|
126
|
+
template-id: <or omit>
|
|
127
|
+
public: true
|
|
128
|
+
recommended: false # flip to true when status: HAVE and tested
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 6. Run /skill-test in static mode
|
|
132
|
+
|
|
133
|
+
Confirm the new skill passes the 7 structural checks before commit.
|
|
134
|
+
|
|
135
|
+
## Collaborative protocol
|
|
136
|
+
|
|
137
|
+
This skill writes files (the new skill folder + catalog update). Always ask before each write step.
|
|
138
|
+
|
|
139
|
+
## See also
|
|
140
|
+
|
|
141
|
+
- `_shared/collaborative-protocol.md`
|
|
142
|
+
- `_meta/skill-test/SKILL.md`
|
|
143
|
+
- `catalog.yaml`
|