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
package/dist/commands/skills.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { existsSync, mkdirSync,
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, cpSync, writeFileSync, } from "fs";
|
|
3
3
|
import { join, dirname } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { homedir } from "os";
|
|
6
|
+
import { AGENT_CLIENTS, SKILL_REGISTRY, } from "../lib/skills-registry.js";
|
|
6
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
8
|
// Resolve skills dir: from dist/commands/skills.js -> ../../skills
|
|
8
9
|
const skillsDir = join(__dirname, "..", "..", "skills");
|
|
10
|
+
const SKILL_SCOPES = ["user", "project"];
|
|
9
11
|
function getBuiltinSkills() {
|
|
10
|
-
if (!existsSync(skillsDir))
|
|
11
|
-
return [];
|
|
12
|
-
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
13
12
|
const skills = [];
|
|
14
|
-
for (const entry of
|
|
15
|
-
if (!entry.
|
|
13
|
+
for (const entry of SKILL_REGISTRY) {
|
|
14
|
+
if (!entry.public)
|
|
16
15
|
continue;
|
|
17
|
-
const skillPath = join(skillsDir, entry.name, "SKILL.md");
|
|
16
|
+
const skillPath = join(skillsDir, entry.category, entry.name, "SKILL.md");
|
|
18
17
|
if (!existsSync(skillPath))
|
|
19
18
|
continue;
|
|
20
|
-
const
|
|
21
|
-
if (
|
|
22
|
-
|
|
19
|
+
const frontmatter = parseSkillFrontmatter(skillPath);
|
|
20
|
+
if (!frontmatter)
|
|
21
|
+
continue;
|
|
22
|
+
skills.push({
|
|
23
|
+
...entry,
|
|
24
|
+
name: entry.name,
|
|
25
|
+
description: frontmatter.description,
|
|
26
|
+
});
|
|
23
27
|
}
|
|
24
28
|
return skills;
|
|
25
29
|
}
|
|
@@ -40,12 +44,215 @@ function parseSkillFrontmatter(skillPath) {
|
|
|
40
44
|
return null;
|
|
41
45
|
}
|
|
42
46
|
}
|
|
47
|
+
function getSkillMeta(name) {
|
|
48
|
+
return getBuiltinSkills().find((skill) => skill.name === name) ?? null;
|
|
49
|
+
}
|
|
43
50
|
function getSkillPath(name) {
|
|
44
|
-
const
|
|
51
|
+
const entry = SKILL_REGISTRY.find((s) => s.name === name);
|
|
52
|
+
if (!entry)
|
|
53
|
+
return null;
|
|
54
|
+
const path = join(skillsDir, entry.category, entry.name);
|
|
45
55
|
if (!existsSync(path) || !existsSync(join(path, "SKILL.md")))
|
|
46
56
|
return null;
|
|
47
57
|
return path;
|
|
48
58
|
}
|
|
59
|
+
function getSkillBody(name) {
|
|
60
|
+
const entry = SKILL_REGISTRY.find((s) => s.name === name);
|
|
61
|
+
if (!entry)
|
|
62
|
+
throw new Error(`Unknown skill: ${name}`);
|
|
63
|
+
const skillPath = join(skillsDir, entry.category, entry.name, "SKILL.md");
|
|
64
|
+
const content = readFileSync(skillPath, "utf-8");
|
|
65
|
+
return content.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, "").trim();
|
|
66
|
+
}
|
|
67
|
+
function die(message) {
|
|
68
|
+
console.error(message);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
function isAgentClient(value) {
|
|
72
|
+
return AGENT_CLIENTS.includes(value);
|
|
73
|
+
}
|
|
74
|
+
function isSkillScope(value) {
|
|
75
|
+
return SKILL_SCOPES.includes(value);
|
|
76
|
+
}
|
|
77
|
+
function parseAgent(value) {
|
|
78
|
+
if (isAgentClient(value))
|
|
79
|
+
return value;
|
|
80
|
+
die(`Unknown agent: ${value}. Use one of: ${AGENT_CLIENTS.join(", ")}.`);
|
|
81
|
+
}
|
|
82
|
+
function parseScope(value) {
|
|
83
|
+
if (isSkillScope(value))
|
|
84
|
+
return value;
|
|
85
|
+
die(`Unknown scope: ${value}. Use user or project.`);
|
|
86
|
+
}
|
|
87
|
+
function resolveAgent(opts) {
|
|
88
|
+
if (opts.asClaudeSkill && opts.asCursorSkill) {
|
|
89
|
+
die("Use only one legacy alias: --as-claude-skill or --as-cursor-skill.");
|
|
90
|
+
}
|
|
91
|
+
const legacyAgent = opts.asClaudeSkill
|
|
92
|
+
? "claude-code"
|
|
93
|
+
: opts.asCursorSkill
|
|
94
|
+
? "cursor"
|
|
95
|
+
: undefined;
|
|
96
|
+
if (opts.agent && legacyAgent && opts.agent !== legacyAgent) {
|
|
97
|
+
die(`Conflicting agent options: --agent ${opts.agent} with legacy alias for ${legacyAgent}.`);
|
|
98
|
+
}
|
|
99
|
+
return parseAgent(opts.agent ?? legacyAgent ?? "summer");
|
|
100
|
+
}
|
|
101
|
+
function resolveScope(agent, opts) {
|
|
102
|
+
if (opts.scope)
|
|
103
|
+
return parseScope(opts.scope);
|
|
104
|
+
if (agent === "cursor" || agent === "windsurf")
|
|
105
|
+
return "project";
|
|
106
|
+
return "user";
|
|
107
|
+
}
|
|
108
|
+
function agentLabel(agent) {
|
|
109
|
+
switch (agent) {
|
|
110
|
+
case "claude-code":
|
|
111
|
+
return "Claude Code";
|
|
112
|
+
case "codex":
|
|
113
|
+
return "Codex";
|
|
114
|
+
case "cursor":
|
|
115
|
+
return "Cursor";
|
|
116
|
+
case "windsurf":
|
|
117
|
+
return "Windsurf";
|
|
118
|
+
case "summer":
|
|
119
|
+
return "Summer";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function resolveInstallLocation(agent, scope) {
|
|
123
|
+
const overrideDir = process.env.SUMMER_SKILLS_DIR;
|
|
124
|
+
if (overrideDir) {
|
|
125
|
+
if (agent === "cursor")
|
|
126
|
+
return { kind: "cursor-rule-dir", path: overrideDir };
|
|
127
|
+
if (agent === "windsurf") {
|
|
128
|
+
return { kind: "windsurf-rule-file", path: join(overrideDir, ".windsurfrules") };
|
|
129
|
+
}
|
|
130
|
+
return { kind: "skill-dir", path: overrideDir };
|
|
131
|
+
}
|
|
132
|
+
const root = scope === "user" ? homedir() : process.cwd();
|
|
133
|
+
switch (agent) {
|
|
134
|
+
case "codex":
|
|
135
|
+
return { kind: "skill-dir", path: join(root, ".agents", "skills") };
|
|
136
|
+
case "claude-code":
|
|
137
|
+
return { kind: "skill-dir", path: join(root, ".claude", "skills") };
|
|
138
|
+
case "cursor":
|
|
139
|
+
return { kind: "cursor-rule-dir", path: join(root, ".cursor", "rules") };
|
|
140
|
+
case "windsurf":
|
|
141
|
+
return { kind: "windsurf-rule-file", path: join(root, ".windsurfrules") };
|
|
142
|
+
case "summer":
|
|
143
|
+
return { kind: "skill-dir", path: join(root, ".summer", "skills") };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function selectSkills(name, opts) {
|
|
147
|
+
if (opts.all && opts.recommended) {
|
|
148
|
+
die("Use only one bulk option: --all or --recommended.");
|
|
149
|
+
}
|
|
150
|
+
if (name && (opts.all || opts.recommended)) {
|
|
151
|
+
die("Specify either a skill name or a bulk option, not both.");
|
|
152
|
+
}
|
|
153
|
+
const skills = getBuiltinSkills();
|
|
154
|
+
if (opts.all)
|
|
155
|
+
return skills;
|
|
156
|
+
if (opts.recommended)
|
|
157
|
+
return skills.filter((skill) => skill.recommended);
|
|
158
|
+
if (!name) {
|
|
159
|
+
console.error("Specify a skill name, --recommended, or --all.");
|
|
160
|
+
printAvailableSkillNames();
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
const skill = skills.find((candidate) => candidate.name === name);
|
|
164
|
+
if (!skill) {
|
|
165
|
+
console.error(`Unknown skill: ${name}`);
|
|
166
|
+
printAvailableSkillNames();
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
return [skill];
|
|
170
|
+
}
|
|
171
|
+
function printAvailableSkillNames() {
|
|
172
|
+
const skills = getBuiltinSkills();
|
|
173
|
+
if (skills.length === 0)
|
|
174
|
+
return;
|
|
175
|
+
console.log("\nAvailable skills:");
|
|
176
|
+
for (const skill of skills) {
|
|
177
|
+
console.log(` ${skill.name}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function installSkill(skill, agent, location) {
|
|
181
|
+
if (!skill.clients.includes(agent)) {
|
|
182
|
+
die(`${skill.name} does not support ${agentLabel(agent)}.`);
|
|
183
|
+
}
|
|
184
|
+
switch (location.kind) {
|
|
185
|
+
case "skill-dir":
|
|
186
|
+
return copySkillDirectory(skill, location.path);
|
|
187
|
+
case "cursor-rule-dir":
|
|
188
|
+
return writeCursorRule(skill, location.path);
|
|
189
|
+
case "windsurf-rule-file":
|
|
190
|
+
return upsertWindsurfRule(skill, location.path);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function copySkillDirectory(skill, targetDir) {
|
|
194
|
+
const src = getSkillPath(skill.name);
|
|
195
|
+
if (!src)
|
|
196
|
+
die(`Skill files missing: ${skill.name}`);
|
|
197
|
+
mkdirSync(targetDir, { recursive: true });
|
|
198
|
+
const dest = join(targetDir, skill.name);
|
|
199
|
+
cpSync(src, dest, { recursive: true });
|
|
200
|
+
return { action: "Installed", path: dest };
|
|
201
|
+
}
|
|
202
|
+
function writeCursorRule(skill, rulesDir) {
|
|
203
|
+
mkdirSync(rulesDir, { recursive: true });
|
|
204
|
+
const rulePath = join(rulesDir, `summer-${skill.name}.mdc`);
|
|
205
|
+
writeFileSync(rulePath, renderCursorRule(skill), "utf-8");
|
|
206
|
+
return { action: "Generated", path: rulePath };
|
|
207
|
+
}
|
|
208
|
+
function upsertWindsurfRule(skill, rulePath) {
|
|
209
|
+
mkdirSync(dirname(rulePath), { recursive: true });
|
|
210
|
+
const start = `<!-- summer-skill:start:${skill.name} -->`;
|
|
211
|
+
const end = `<!-- summer-skill:end:${skill.name} -->`;
|
|
212
|
+
const block = `${start}\n${renderWindsurfRule(skill)}\n${end}`;
|
|
213
|
+
const existing = existsSync(rulePath) ? readFileSync(rulePath, "utf-8") : "";
|
|
214
|
+
const pattern = new RegExp(`${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}`);
|
|
215
|
+
const next = pattern.test(existing)
|
|
216
|
+
? existing.replace(pattern, block)
|
|
217
|
+
: `${existing.trimEnd()}${existing.trim() ? "\n\n" : ""}${block}\n`;
|
|
218
|
+
writeFileSync(rulePath, next, "utf-8");
|
|
219
|
+
return { action: "Generated", path: rulePath };
|
|
220
|
+
}
|
|
221
|
+
function renderCursorRule(skill) {
|
|
222
|
+
const description = `Summer skill ${skill.name}: ${skill.description}`;
|
|
223
|
+
return `---\ndescription: ${JSON.stringify(description)}\nglobs: []\nalwaysApply: false\n---\n\n${renderRuleBody(skill)}\n`;
|
|
224
|
+
}
|
|
225
|
+
function renderWindsurfRule(skill) {
|
|
226
|
+
return renderRuleBody(skill);
|
|
227
|
+
}
|
|
228
|
+
function renderRuleBody(skill) {
|
|
229
|
+
return `# Summer skill: ${skill.name}
|
|
230
|
+
|
|
231
|
+
${skill.description}
|
|
232
|
+
|
|
233
|
+
Use Summer MCP tools for scene, editor, asset, play, and diagnostics operations. Use the host agent's normal file editing tools for scripts and other text files.
|
|
234
|
+
|
|
235
|
+
## Skill
|
|
236
|
+
|
|
237
|
+
${getSkillBody(skill.name)}
|
|
238
|
+
`;
|
|
239
|
+
}
|
|
240
|
+
function escapeRegExp(value) {
|
|
241
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
242
|
+
}
|
|
243
|
+
function printInstallSummary(count, agent, scope, location) {
|
|
244
|
+
const label = agentLabel(agent);
|
|
245
|
+
console.log(`\n${count} skill${count === 1 ? "" : "s"} ready for ${label} (${scope} scope).`);
|
|
246
|
+
if (location.kind === "skill-dir") {
|
|
247
|
+
console.log(`${label} can read skills from ${location.path}/<skill>/SKILL.md`);
|
|
248
|
+
}
|
|
249
|
+
else if (location.kind === "cursor-rule-dir") {
|
|
250
|
+
console.log(`Cursor rules are in ${location.path}/summer-<skill>.mdc`);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
console.log(`Windsurf rules are in ${location.path}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
49
256
|
export const skillsCommand = new Command("skills")
|
|
50
257
|
.description("Install and manage best-practice guides for AI agents building games")
|
|
51
258
|
.action(() => {
|
|
@@ -60,124 +267,62 @@ skillsCommand
|
|
|
60
267
|
console.log("No skills found.");
|
|
61
268
|
return;
|
|
62
269
|
}
|
|
63
|
-
console.log("Available skills:\n");
|
|
270
|
+
console.log("Available public skills:\n");
|
|
64
271
|
for (const s of skills) {
|
|
65
|
-
|
|
272
|
+
const badge = s.recommended ? "recommended" : "optional";
|
|
273
|
+
console.log(` ${s.name.padEnd(20)} ${s.category.padEnd(10)} ${badge.padEnd(11)} ${s.description}`);
|
|
66
274
|
}
|
|
67
|
-
console.log("\nInstall: summer skills install
|
|
275
|
+
console.log("\nInstall recommended: summer skills install --recommended");
|
|
276
|
+
console.log("Install one: summer skills install <name>");
|
|
277
|
+
console.log(`Agents: ${AGENT_CLIENTS.join(", ")}`);
|
|
68
278
|
});
|
|
69
|
-
function resolveInstallDir(target) {
|
|
70
|
-
if (process.env.SUMMER_SKILLS_DIR) {
|
|
71
|
-
return process.env.SUMMER_SKILLS_DIR;
|
|
72
|
-
}
|
|
73
|
-
if (target === "claude") {
|
|
74
|
-
return join(homedir(), ".claude", "skills");
|
|
75
|
-
}
|
|
76
|
-
if (target === "cursor") {
|
|
77
|
-
return join(homedir(), ".cursor", "skills");
|
|
78
|
-
}
|
|
79
|
-
return join(homedir(), ".summer", "skills");
|
|
80
|
-
}
|
|
81
|
-
function getTargetFromOpts(opts) {
|
|
82
|
-
if (opts.asClaudeSkill)
|
|
83
|
-
return "claude";
|
|
84
|
-
if (opts.asCursorSkill)
|
|
85
|
-
return "cursor";
|
|
86
|
-
return "summer";
|
|
87
|
-
}
|
|
88
279
|
skillsCommand
|
|
89
280
|
.command("install [name]")
|
|
90
|
-
.description("Install
|
|
281
|
+
.description("Install Summer skills for a target agent")
|
|
91
282
|
.option("--all", "Install all available skills")
|
|
92
|
-
.option("--
|
|
93
|
-
.option("--
|
|
283
|
+
.option("--recommended", "Install recommended public skills (excludes make-game)")
|
|
284
|
+
.option("--agent <agent>", `Target agent: ${AGENT_CLIENTS.join("|")}`)
|
|
285
|
+
.option("--scope <scope>", "Install scope: user or project")
|
|
286
|
+
.option("--as-claude-skill", "Legacy alias for --agent claude-code")
|
|
287
|
+
.option("--as-cursor-skill", "Legacy alias for --agent cursor")
|
|
94
288
|
.action((name, opts) => {
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
console.log("No skills found.");
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
if (!existsSync(targetDir)) {
|
|
105
|
-
mkdirSync(targetDir, { recursive: true });
|
|
106
|
-
}
|
|
107
|
-
for (const s of skills) {
|
|
108
|
-
const src = getSkillPath(s.name);
|
|
109
|
-
if (src) {
|
|
110
|
-
const dest = join(targetDir, s.name);
|
|
111
|
-
cpSync(src, dest, { recursive: true });
|
|
112
|
-
console.log(` Installed ${s.name}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
console.log(`\nInstalled ${skills.length} skills to ${targetDir}`);
|
|
116
|
-
if (target === "claude") {
|
|
117
|
-
console.log("Claude Code will auto-discover these skills.");
|
|
118
|
-
}
|
|
119
|
-
else if (target === "cursor") {
|
|
120
|
-
console.log("Cursor will auto-discover these skills.");
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
console.log("AI agents can read: <dir>/<name>/SKILL.md");
|
|
124
|
-
}
|
|
289
|
+
const agent = resolveAgent(opts);
|
|
290
|
+
const scope = resolveScope(agent, opts);
|
|
291
|
+
const location = resolveInstallLocation(agent, scope);
|
|
292
|
+
const skills = selectSkills(name, opts);
|
|
293
|
+
if (skills.length === 0) {
|
|
294
|
+
console.log("No skills found.");
|
|
125
295
|
return;
|
|
126
296
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
console.log(
|
|
130
|
-
for (const s of getBuiltinSkills()) {
|
|
131
|
-
console.log(` ${s.name}`);
|
|
132
|
-
}
|
|
133
|
-
process.exit(1);
|
|
134
|
-
}
|
|
135
|
-
const src = getSkillPath(name);
|
|
136
|
-
if (!src) {
|
|
137
|
-
console.error(`Unknown skill: ${name}`);
|
|
138
|
-
const skills = getBuiltinSkills();
|
|
139
|
-
if (skills.length > 0) {
|
|
140
|
-
console.log("\nAvailable skills:");
|
|
141
|
-
for (const s of skills) {
|
|
142
|
-
console.log(` ${s.name}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
if (!existsSync(targetDir)) {
|
|
148
|
-
mkdirSync(targetDir, { recursive: true });
|
|
149
|
-
}
|
|
150
|
-
const dest = join(targetDir, name);
|
|
151
|
-
cpSync(src, dest, { recursive: true });
|
|
152
|
-
console.log(`Installed ${name} to ${dest}`);
|
|
153
|
-
if (target === "claude") {
|
|
154
|
-
console.log("Claude Code will auto-discover this skill.");
|
|
155
|
-
}
|
|
156
|
-
else if (target === "cursor") {
|
|
157
|
-
console.log("Cursor will auto-discover this skill.");
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
console.log(`\nAI agents can read: ${dest}/SKILL.md`);
|
|
297
|
+
for (const skill of skills) {
|
|
298
|
+
const result = installSkill(skill, agent, location);
|
|
299
|
+
console.log(` ${result.action} ${skill.name} -> ${result.path}`);
|
|
161
300
|
}
|
|
301
|
+
printInstallSummary(skills.length, agent, scope, location);
|
|
162
302
|
});
|
|
163
303
|
skillsCommand
|
|
164
304
|
.command("info <name>")
|
|
165
305
|
.description("Show skill description and preview")
|
|
166
306
|
.action((name) => {
|
|
167
|
-
const
|
|
168
|
-
if (!
|
|
307
|
+
const meta = getSkillMeta(name);
|
|
308
|
+
if (!meta) {
|
|
169
309
|
console.error(`Unknown skill: ${name}`);
|
|
170
310
|
process.exit(1);
|
|
171
311
|
}
|
|
312
|
+
const src = getSkillPath(name);
|
|
313
|
+
if (!src)
|
|
314
|
+
die(`Skill files missing: ${name}`);
|
|
172
315
|
const skillPath = join(src, "SKILL.md");
|
|
173
316
|
const content = readFileSync(skillPath, "utf-8");
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
317
|
+
console.log(`\n${meta.name}`);
|
|
318
|
+
console.log("-".repeat(40));
|
|
319
|
+
console.log(meta.description);
|
|
320
|
+
console.log(`Category: ${meta.category}`);
|
|
321
|
+
console.log(`Recommended: ${meta.recommended ? "yes" : "no"}`);
|
|
322
|
+
console.log(`Agents: ${meta.clients.join(", ")}`);
|
|
323
|
+
console.log(`MCP tools: ${meta.requiresMcpTools.length > 0 ? meta.requiresMcpTools.join(", ") : "none"}`);
|
|
324
|
+
console.log(`Test scenario: ${meta.testScenario}`);
|
|
325
|
+
console.log("\n" + "-".repeat(40));
|
|
181
326
|
const body = content.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, "");
|
|
182
327
|
const preview = body.split("\n").slice(0, 30).join("\n");
|
|
183
328
|
console.log(preview);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare const SUMMER_MCP_SERVER_NAME = "summer-engine";
|
|
2
|
+
export declare const supportedAgents: readonly ["codex", "claude-code", "cursor", "windsurf"];
|
|
3
|
+
export type SupportedAgent = (typeof supportedAgents)[number];
|
|
4
|
+
export type ConfigScope = "user" | "project";
|
|
5
|
+
export interface StdioMcpServerConfig {
|
|
6
|
+
command: string;
|
|
7
|
+
args: string[];
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export interface AgentConfigOptions {
|
|
11
|
+
agent: SupportedAgent;
|
|
12
|
+
scope: ConfigScope;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
print?: boolean;
|
|
15
|
+
localDev?: boolean;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
}
|
|
19
|
+
export interface AgentConfigResult {
|
|
20
|
+
agent: SupportedAgent;
|
|
21
|
+
scope: ConfigScope;
|
|
22
|
+
path: string;
|
|
23
|
+
serverName: string;
|
|
24
|
+
server: StdioMcpServerConfig;
|
|
25
|
+
format: "json" | "toml";
|
|
26
|
+
snippet: string;
|
|
27
|
+
changed: boolean;
|
|
28
|
+
wrote: boolean;
|
|
29
|
+
dryRun: boolean;
|
|
30
|
+
print: boolean;
|
|
31
|
+
localDev: boolean;
|
|
32
|
+
warnings: string[];
|
|
33
|
+
nextSteps: string[];
|
|
34
|
+
}
|
|
35
|
+
export declare function parseAgent(value: string | undefined): SupportedAgent | null;
|
|
36
|
+
export declare function parseScope(value: string | undefined): ConfigScope | null;
|
|
37
|
+
export declare function configureAgentMcp(options: AgentConfigOptions): Promise<AgentConfigResult>;
|
|
38
|
+
export declare function createSummerMcpServerConfig(localDev: boolean): StdioMcpServerConfig;
|
|
39
|
+
export declare function renderConfigSnippet(agent: SupportedAgent, server: StdioMcpServerConfig): string;
|