summer-engine 2.0.0 → 2.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/{marketplace.json → .claude-plugin/marketplace.json} +3 -3
- package/.claude-plugin/plugin.json +37 -4
- package/.codex-plugin/plugin.json +38 -5
- package/.cursor-plugin/plugin.json +37 -4
- package/.factory-plugin/plugin.json +20 -0
- package/.opencode/INSTALL.md +9 -3
- package/.opencode/plugins/summer.js +0 -2
- package/AGENTS.md +51 -0
- package/CLAUDE.md +5 -0
- package/GEMINI.md +56 -0
- package/README.md +211 -61
- package/_persona/summer/SKILL.md +113 -0
- package/dist/commands/install.js +2 -2
- package/dist/commands/setup.js +4 -0
- package/dist/commands/skills.js +115 -2
- package/dist/lib/agent-config.d.ts +2 -2
- package/dist/lib/agent-config.js +171 -5
- package/dist/lib/skills-registry.d.ts +290 -26
- package/dist/lib/skills-registry.js +503 -1
- package/dist/mcp/tools/generate-tools.js +101 -0
- package/gemini-extension.json +2 -2
- package/package.json +9 -3
- package/skills/2d-assets/character-portrait/SKILL.md +196 -0
- package/skills/2d-assets/concept-art/SKILL.md +152 -0
- package/skills/2d-assets/pixel-art/SKILL.md +180 -0
- package/skills/2d-assets/skybox-panorama/SKILL.md +207 -0
- package/skills/2d-assets/sprite-sheet/SKILL.md +239 -0
- package/skills/2d-assets/tileable-texture/SKILL.md +205 -0
- package/skills/2d-assets/ui-graphics/SKILL.md +210 -0
- package/skills/3d-assets/character-model/SKILL.md +225 -0
- package/skills/3d-assets/environment-kit/SKILL.md +164 -0
- package/skills/3d-assets/organic-model/SKILL.md +192 -0
- package/skills/3d-assets/prop-model/SKILL.md +133 -0
- package/skills/3d-assets/vehicle-model/SKILL.md +202 -0
- package/skills/ai-and-npcs/design-npc/SKILL.md +3 -1
- package/skills/animation/animation-tree/SKILL.md +260 -0
- package/skills/animation/facial-and-lipsync/SKILL.md +282 -0
- package/skills/animation/generate-motion/SKILL.md +129 -0
- package/skills/animation/procedural-animation/SKILL.md +234 -0
- package/skills/animation/retarget/SKILL.md +172 -0
- package/skills/asset-pipeline/asset-strategy/SKILL.md +102 -212
- package/skills/audio/adaptive-music/SKILL.md +326 -0
- package/skills/audio/ambient-bed/SKILL.md +278 -0
- package/skills/audio/music-track/SKILL.md +268 -0
- package/skills/audio/sound-effect/SKILL.md +237 -0
- package/skills/audio/voice-line/SKILL.md +253 -0
- package/skills/catalog.yaml +249 -3
- package/skills/video/animated-loop/SKILL.md +200 -0
- package/skills/video/cinematic-cutscene/SKILL.md +204 -0
- package/skills/video/trailer-shot/SKILL.md +203 -0
- package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +28 -0
- package/skills/visual-effects/_building-blocks/noise-3d-fbm.gdshaderinc +45 -0
- package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +51 -0
- package/skills/visual-effects/{vfx → game-feel}/SKILL.md +1 -1
- package/skills/visual-effects/recipes/dissolve/SKILL.md +349 -0
- package/skills/visual-effects/recipes/fire/SKILL.md +387 -0
- package/skills/visual-effects/recipes/hit-spark/SKILL.md +330 -0
- package/skills/visual-effects/recipes/lightning/SKILL.md +372 -0
- package/skills/visual-effects/recipes/magic-glow/SKILL.md +377 -0
- package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +326 -0
- package/skills/visual-effects/recipes/smoke/SKILL.md +381 -0
- package/skills/visual-effects/recipes/water-ripple/SKILL.md +340 -0
package/dist/commands/skills.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Command } from "commander";
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, cpSync, writeFileSync, } from "fs";
|
|
3
3
|
import { join, dirname } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
-
import { homedir } from "os";
|
|
5
|
+
import { homedir, platform } from "os";
|
|
6
6
|
import { AGENT_CLIENTS, SKILL_REGISTRY, } from "../lib/skills-registry.js";
|
|
7
7
|
import { tildeify } from "../lib/format.js";
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -102,8 +102,12 @@ function resolveAgent(opts) {
|
|
|
102
102
|
function resolveScope(agent, opts) {
|
|
103
103
|
if (opts.scope)
|
|
104
104
|
return parseScope(opts.scope);
|
|
105
|
-
if (agent === "cursor" ||
|
|
105
|
+
if (agent === "cursor" ||
|
|
106
|
+
agent === "windsurf" ||
|
|
107
|
+
agent === "cline" ||
|
|
108
|
+
agent === "roo-code") {
|
|
106
109
|
return "project";
|
|
110
|
+
}
|
|
107
111
|
return "user";
|
|
108
112
|
}
|
|
109
113
|
function agentLabel(agent) {
|
|
@@ -116,6 +120,14 @@ function agentLabel(agent) {
|
|
|
116
120
|
return "Cursor";
|
|
117
121
|
case "windsurf":
|
|
118
122
|
return "Windsurf";
|
|
123
|
+
case "cline":
|
|
124
|
+
return "Cline";
|
|
125
|
+
case "roo-code":
|
|
126
|
+
return "Roo Code";
|
|
127
|
+
case "gemini":
|
|
128
|
+
return "Gemini CLI";
|
|
129
|
+
case "opencode":
|
|
130
|
+
return "OpenCode";
|
|
119
131
|
case "summer":
|
|
120
132
|
return "Summer";
|
|
121
133
|
}
|
|
@@ -128,6 +140,15 @@ function resolveInstallLocation(agent, scope) {
|
|
|
128
140
|
if (agent === "windsurf") {
|
|
129
141
|
return { kind: "windsurf-rule-file", path: join(overrideDir, ".windsurfrules") };
|
|
130
142
|
}
|
|
143
|
+
if (agent === "cline" || agent === "roo-code") {
|
|
144
|
+
return { kind: "cline-rule-dir", path: overrideDir };
|
|
145
|
+
}
|
|
146
|
+
if (agent === "gemini") {
|
|
147
|
+
return { kind: "gemini-skill-dir", path: overrideDir };
|
|
148
|
+
}
|
|
149
|
+
if (agent === "opencode") {
|
|
150
|
+
return { kind: "opencode-skill-dir", path: overrideDir };
|
|
151
|
+
}
|
|
131
152
|
return { kind: "skill-dir", path: overrideDir };
|
|
132
153
|
}
|
|
133
154
|
const root = scope === "user" ? homedir() : process.cwd();
|
|
@@ -140,10 +161,55 @@ function resolveInstallLocation(agent, scope) {
|
|
|
140
161
|
return { kind: "cursor-rule-dir", path: join(root, ".cursor", "rules") };
|
|
141
162
|
case "windsurf":
|
|
142
163
|
return { kind: "windsurf-rule-file", path: join(root, ".windsurfrules") };
|
|
164
|
+
case "cline":
|
|
165
|
+
return {
|
|
166
|
+
kind: "cline-rule-dir",
|
|
167
|
+
path: scope === "user"
|
|
168
|
+
? clineUserRulesDir()
|
|
169
|
+
: join(process.cwd(), ".clinerules"),
|
|
170
|
+
};
|
|
171
|
+
case "roo-code":
|
|
172
|
+
return {
|
|
173
|
+
kind: "cline-rule-dir",
|
|
174
|
+
path: scope === "user"
|
|
175
|
+
? rooCodeUserRulesDir()
|
|
176
|
+
: join(process.cwd(), ".clinerules"),
|
|
177
|
+
};
|
|
178
|
+
case "gemini":
|
|
179
|
+
return {
|
|
180
|
+
kind: "gemini-skill-dir",
|
|
181
|
+
path: join(homedir(), ".gemini", "extensions", "summer-engine", "skills"),
|
|
182
|
+
};
|
|
183
|
+
case "opencode":
|
|
184
|
+
return {
|
|
185
|
+
kind: "opencode-skill-dir",
|
|
186
|
+
path: scope === "user"
|
|
187
|
+
? opencodeUserAgentsDir()
|
|
188
|
+
: join(process.cwd(), ".opencode", "agents", "summer"),
|
|
189
|
+
};
|
|
143
190
|
case "summer":
|
|
144
191
|
return { kind: "skill-dir", path: join(root, ".summer", "skills") };
|
|
145
192
|
}
|
|
146
193
|
}
|
|
194
|
+
function clineUserRulesDir() {
|
|
195
|
+
// Cline reads global rules from the user's Documents/Cline/Rules folder.
|
|
196
|
+
return join(homedir(), "Documents", "Cline", "Rules");
|
|
197
|
+
}
|
|
198
|
+
function rooCodeUserRulesDir() {
|
|
199
|
+
// Roo Code reads global rules from the user's Documents/Roo/Rules folder.
|
|
200
|
+
return join(homedir(), "Documents", "Roo", "Rules");
|
|
201
|
+
}
|
|
202
|
+
function opencodeUserAgentsDir() {
|
|
203
|
+
// OpenCode's user-scope agent definition directory varies by OS.
|
|
204
|
+
// On Windows, OpenCode reads from %APPDATA%/opencode/agents/summer.
|
|
205
|
+
// On Linux/macOS, it reads from $XDG_CONFIG_HOME or ~/.config/opencode/agents/summer.
|
|
206
|
+
if (platform() === "win32") {
|
|
207
|
+
const appData = process.env.APPDATA ?? join(homedir(), "AppData", "Roaming");
|
|
208
|
+
return join(appData, "opencode", "agents", "summer");
|
|
209
|
+
}
|
|
210
|
+
const xdg = process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
|
|
211
|
+
return join(xdg, "opencode", "agents", "summer");
|
|
212
|
+
}
|
|
147
213
|
function selectSkills(name, opts) {
|
|
148
214
|
if (opts.all && opts.recommended) {
|
|
149
215
|
die("Use only one bulk option: --all or --recommended.");
|
|
@@ -189,6 +255,12 @@ function installSkill(skill, agent, location) {
|
|
|
189
255
|
return writeCursorRule(skill, location.path);
|
|
190
256
|
case "windsurf-rule-file":
|
|
191
257
|
return upsertWindsurfRule(skill, location.path);
|
|
258
|
+
case "cline-rule-dir":
|
|
259
|
+
return writeClineRule(skill, location.path);
|
|
260
|
+
case "gemini-skill-dir":
|
|
261
|
+
return writeGeminiSkill(skill, location.path);
|
|
262
|
+
case "opencode-skill-dir":
|
|
263
|
+
return writeOpencodeSkill(skill, location.path);
|
|
192
264
|
}
|
|
193
265
|
}
|
|
194
266
|
function copySkillDirectory(skill, targetDir) {
|
|
@@ -219,6 +291,35 @@ function upsertWindsurfRule(skill, rulePath) {
|
|
|
219
291
|
writeFileSync(rulePath, next, "utf-8");
|
|
220
292
|
return { action: "Generated", path: rulePath };
|
|
221
293
|
}
|
|
294
|
+
function writeClineRule(skill, rulesDir) {
|
|
295
|
+
// Cline + Roo Code read project rules from .clinerules/ and global rules
|
|
296
|
+
// from Documents/Cline (or Roo)/Rules. Both expect plain markdown files.
|
|
297
|
+
// SKILL.md isn't recognized as a special filename, so we name files <skill>.md.
|
|
298
|
+
mkdirSync(rulesDir, { recursive: true });
|
|
299
|
+
const rulePath = join(rulesDir, `summer-${skill.name}.md`);
|
|
300
|
+
writeFileSync(rulePath, renderRuleBody(skill) + "\n", "utf-8");
|
|
301
|
+
return { action: "Generated", path: rulePath };
|
|
302
|
+
}
|
|
303
|
+
function writeGeminiSkill(skill, skillsDir) {
|
|
304
|
+
// Gemini extensions support a contextFileName, but skill discovery for
|
|
305
|
+
// arbitrary markdown is not standardized. We drop each SKILL.md alongside
|
|
306
|
+
// the extension so the agent can reference them by path; the install
|
|
307
|
+
// summary surfaces this so the user knows where to point Gemini.
|
|
308
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
309
|
+
const rulePath = join(skillsDir, `${skill.name}.md`);
|
|
310
|
+
writeFileSync(rulePath, renderRuleBody(skill) + "\n", "utf-8");
|
|
311
|
+
return { action: "Generated", path: rulePath };
|
|
312
|
+
}
|
|
313
|
+
function writeOpencodeSkill(skill, skillsDir) {
|
|
314
|
+
// OpenCode supports agent markdown definitions; the exact discovery
|
|
315
|
+
// convention for ad-hoc skills isn't fully documented. We write each skill
|
|
316
|
+
// as a markdown file under agents/summer/ so OpenCode can reference them
|
|
317
|
+
// directly. The install summary shows the path.
|
|
318
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
319
|
+
const rulePath = join(skillsDir, `${skill.name}.md`);
|
|
320
|
+
writeFileSync(rulePath, renderRuleBody(skill) + "\n", "utf-8");
|
|
321
|
+
return { action: "Generated", path: rulePath };
|
|
322
|
+
}
|
|
222
323
|
function renderCursorRule(skill) {
|
|
223
324
|
const description = `Summer skill ${skill.name}: ${skill.description}`;
|
|
224
325
|
return `---\ndescription: ${JSON.stringify(description)}\nglobs: []\nalwaysApply: false\n---\n\n${renderRuleBody(skill)}\n`;
|
|
@@ -251,6 +352,18 @@ function printInstallSummary(count, agent, scope, location) {
|
|
|
251
352
|
else if (location.kind === "cursor-rule-dir") {
|
|
252
353
|
console.log(`Cursor rules are in ${tildeified}/summer-<skill>.mdc`);
|
|
253
354
|
}
|
|
355
|
+
else if (location.kind === "cline-rule-dir") {
|
|
356
|
+
console.log(`${label} rules are in ${tildeified}/summer-<skill>.md`);
|
|
357
|
+
console.log("Restart VS Code to pick up new rules.");
|
|
358
|
+
}
|
|
359
|
+
else if (location.kind === "gemini-skill-dir") {
|
|
360
|
+
console.log(`Skill files are in ${tildeified}/<skill>.md`);
|
|
361
|
+
console.log("Reference them from Gemini by path, or run `gemini extensions enable summer-engine` to load the bundled context.");
|
|
362
|
+
}
|
|
363
|
+
else if (location.kind === "opencode-skill-dir") {
|
|
364
|
+
console.log(`Skill files are in ${tildeified}/<skill>.md`);
|
|
365
|
+
console.log("Restart OpenCode so it picks up the new agent definitions.");
|
|
366
|
+
}
|
|
254
367
|
else {
|
|
255
368
|
console.log(`Windsurf rules are in ${tildeified}`);
|
|
256
369
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const SUMMER_MCP_SERVER_NAME = "summer-engine";
|
|
2
|
-
export declare const supportedAgents: readonly ["codex", "claude-code", "cursor", "windsurf"];
|
|
2
|
+
export declare const supportedAgents: readonly ["codex", "claude-code", "cursor", "windsurf", "cline", "roo-code", "gemini", "opencode"];
|
|
3
3
|
export type SupportedAgent = (typeof supportedAgents)[number];
|
|
4
4
|
export type ConfigScope = "user" | "project";
|
|
5
5
|
export interface StdioMcpServerConfig {
|
|
@@ -22,7 +22,7 @@ export interface AgentConfigResult {
|
|
|
22
22
|
path: string;
|
|
23
23
|
serverName: string;
|
|
24
24
|
server: StdioMcpServerConfig;
|
|
25
|
-
format: "json" | "toml";
|
|
25
|
+
format: "json" | "toml" | "json-opencode";
|
|
26
26
|
snippet: string;
|
|
27
27
|
changed: boolean;
|
|
28
28
|
wrote: boolean;
|
package/dist/lib/agent-config.js
CHANGED
|
@@ -2,13 +2,17 @@ import { existsSync } from "fs";
|
|
|
2
2
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname, join, resolve } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
-
import { homedir } from "os";
|
|
5
|
+
import { homedir, platform } from "os";
|
|
6
6
|
export const SUMMER_MCP_SERVER_NAME = "summer-engine";
|
|
7
7
|
export const supportedAgents = [
|
|
8
8
|
"codex",
|
|
9
9
|
"claude-code",
|
|
10
10
|
"cursor",
|
|
11
11
|
"windsurf",
|
|
12
|
+
"cline",
|
|
13
|
+
"roo-code",
|
|
14
|
+
"gemini",
|
|
15
|
+
"opencode",
|
|
12
16
|
];
|
|
13
17
|
const agentAliases = {
|
|
14
18
|
claude: "claude-code",
|
|
@@ -16,6 +20,14 @@ const agentAliases = {
|
|
|
16
20
|
codex: "codex",
|
|
17
21
|
cursor: "cursor",
|
|
18
22
|
windsurf: "windsurf",
|
|
23
|
+
cline: "cline",
|
|
24
|
+
"roo-code": "roo-code",
|
|
25
|
+
roo: "roo-code",
|
|
26
|
+
roocode: "roo-code",
|
|
27
|
+
gemini: "gemini",
|
|
28
|
+
"gemini-cli": "gemini",
|
|
29
|
+
opencode: "opencode",
|
|
30
|
+
"open-code": "opencode",
|
|
19
31
|
};
|
|
20
32
|
export function parseAgent(value) {
|
|
21
33
|
if (!value)
|
|
@@ -43,7 +55,11 @@ export async function configureAgentMcp(options) {
|
|
|
43
55
|
? { changed: true }
|
|
44
56
|
: target.format === "toml"
|
|
45
57
|
? await upsertCodexConfig(target.path, server, shouldWrite)
|
|
46
|
-
:
|
|
58
|
+
: target.format === "json-opencode"
|
|
59
|
+
? await upsertOpencodeConfig(target.path, server, shouldWrite)
|
|
60
|
+
: options.agent === "gemini"
|
|
61
|
+
? await upsertGeminiExtension(target.path, server, shouldWrite)
|
|
62
|
+
: await upsertJsonMcpConfig(target.path, server, shouldWrite);
|
|
47
63
|
return {
|
|
48
64
|
agent: options.agent,
|
|
49
65
|
scope: options.scope,
|
|
@@ -70,13 +86,24 @@ export function createSummerMcpServerConfig(localDev) {
|
|
|
70
86
|
}
|
|
71
87
|
return {
|
|
72
88
|
command: "npx",
|
|
73
|
-
args: ["summer-engine", "mcp"],
|
|
89
|
+
args: ["-y", "summer-engine@latest", "mcp"],
|
|
74
90
|
};
|
|
75
91
|
}
|
|
76
92
|
export function renderConfigSnippet(agent, server) {
|
|
77
93
|
if (agent === "codex") {
|
|
78
94
|
return renderCodexServerTable(server);
|
|
79
95
|
}
|
|
96
|
+
if (agent === "opencode") {
|
|
97
|
+
return (JSON.stringify({
|
|
98
|
+
$schema: "https://opencode.ai/config.json",
|
|
99
|
+
mcp: {
|
|
100
|
+
[SUMMER_MCP_SERVER_NAME]: opencodeServerEntry(server),
|
|
101
|
+
},
|
|
102
|
+
}, null, 2) + "\n");
|
|
103
|
+
}
|
|
104
|
+
if (agent === "gemini") {
|
|
105
|
+
return (JSON.stringify(geminiExtensionManifest(server), null, 2) + "\n");
|
|
106
|
+
}
|
|
80
107
|
return (JSON.stringify({
|
|
81
108
|
mcpServers: {
|
|
82
109
|
[SUMMER_MCP_SERVER_NAME]: server,
|
|
@@ -91,9 +118,17 @@ function resolveConfigTarget(agent, scope, cwd, env) {
|
|
|
91
118
|
const override = getConfigPathOverride(agent, env);
|
|
92
119
|
const warnings = [];
|
|
93
120
|
if (override) {
|
|
121
|
+
if (scope === "project" &&
|
|
122
|
+
(agent === "cline" || agent === "roo-code" || agent === "gemini")) {
|
|
123
|
+
warnings.push(`${agent} MCP config has no project scope today; treating as user scope.`);
|
|
124
|
+
}
|
|
94
125
|
return {
|
|
95
126
|
path: resolve(override),
|
|
96
|
-
format: agent === "codex"
|
|
127
|
+
format: agent === "codex"
|
|
128
|
+
? "toml"
|
|
129
|
+
: agent === "opencode"
|
|
130
|
+
? "json-opencode"
|
|
131
|
+
: "json",
|
|
97
132
|
warnings,
|
|
98
133
|
};
|
|
99
134
|
}
|
|
@@ -124,6 +159,45 @@ function resolveConfigTarget(agent, scope, cwd, env) {
|
|
|
124
159
|
warnings,
|
|
125
160
|
};
|
|
126
161
|
}
|
|
162
|
+
if (agent === "cline") {
|
|
163
|
+
if (scope === "project") {
|
|
164
|
+
warnings.push("Cline MCP config has no project scope today; writing to user-scope global VS Code storage instead.");
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
path: vsCodeGlobalStoragePath(env, "saoudrizwan.claude-dev"),
|
|
168
|
+
format: "json",
|
|
169
|
+
warnings,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (agent === "roo-code") {
|
|
173
|
+
if (scope === "project") {
|
|
174
|
+
warnings.push("Roo Code MCP config has no project scope today; writing to user-scope global VS Code storage instead.");
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
path: vsCodeGlobalStoragePath(env, "rooveterinaryinc.roo-cline"),
|
|
178
|
+
format: "json",
|
|
179
|
+
warnings,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (agent === "gemini") {
|
|
183
|
+
if (scope === "project") {
|
|
184
|
+
warnings.push("Gemini extensions are user-scoped today; writing to ~/.gemini/extensions/summer-engine/ instead of project.");
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
path: join(homedir(), ".gemini", "extensions", "summer-engine", "gemini-extension.json"),
|
|
188
|
+
format: "json",
|
|
189
|
+
warnings,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (agent === "opencode") {
|
|
193
|
+
return {
|
|
194
|
+
path: scope === "user"
|
|
195
|
+
? opencodeUserConfigPath(env)
|
|
196
|
+
: join(cwd, "opencode.json"),
|
|
197
|
+
format: "json-opencode",
|
|
198
|
+
warnings,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
127
201
|
if (scope === "project") {
|
|
128
202
|
warnings.push("Windsurf documents MCP configuration as user-scoped; project scope writes .windsurf/mcp_config.json for teams that load workspace config.");
|
|
129
203
|
}
|
|
@@ -135,6 +209,28 @@ function resolveConfigTarget(agent, scope, cwd, env) {
|
|
|
135
209
|
warnings,
|
|
136
210
|
};
|
|
137
211
|
}
|
|
212
|
+
function vsCodeGlobalStoragePath(env, extensionId) {
|
|
213
|
+
const os = platform();
|
|
214
|
+
if (os === "win32") {
|
|
215
|
+
const appData = env.APPDATA ?? join(homedir(), "AppData", "Roaming");
|
|
216
|
+
return join(appData, "Code", "User", "globalStorage", extensionId, "settings", "cline_mcp_settings.json");
|
|
217
|
+
}
|
|
218
|
+
if (os === "darwin") {
|
|
219
|
+
return join(homedir(), "Library", "Application Support", "Code", "User", "globalStorage", extensionId, "settings", "cline_mcp_settings.json");
|
|
220
|
+
}
|
|
221
|
+
// Linux and other Unix
|
|
222
|
+
const xdg = env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
|
|
223
|
+
return join(xdg, "Code", "User", "globalStorage", extensionId, "settings", "cline_mcp_settings.json");
|
|
224
|
+
}
|
|
225
|
+
function opencodeUserConfigPath(env) {
|
|
226
|
+
const os = platform();
|
|
227
|
+
if (os === "win32") {
|
|
228
|
+
const appData = env.APPDATA ?? join(homedir(), "AppData", "Roaming");
|
|
229
|
+
return join(appData, "opencode", "opencode.json");
|
|
230
|
+
}
|
|
231
|
+
const xdg = env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
|
|
232
|
+
return join(xdg, "opencode", "opencode.json");
|
|
233
|
+
}
|
|
138
234
|
function getConfigPathOverride(agent, env) {
|
|
139
235
|
if (agent === "codex")
|
|
140
236
|
return env.SUMMER_CODEX_CONFIG_FILE;
|
|
@@ -142,6 +238,14 @@ function getConfigPathOverride(agent, env) {
|
|
|
142
238
|
return env.SUMMER_CLAUDE_CONFIG_FILE;
|
|
143
239
|
if (agent === "cursor")
|
|
144
240
|
return env.SUMMER_CURSOR_MCP_CONFIG_FILE;
|
|
241
|
+
if (agent === "cline")
|
|
242
|
+
return env.SUMMER_CLINE_CONFIG_FILE;
|
|
243
|
+
if (agent === "roo-code")
|
|
244
|
+
return env.SUMMER_ROO_CODE_CONFIG_FILE;
|
|
245
|
+
if (agent === "gemini")
|
|
246
|
+
return env.SUMMER_GEMINI_CONFIG_FILE;
|
|
247
|
+
if (agent === "opencode")
|
|
248
|
+
return env.SUMMER_OPENCODE_CONFIG_FILE;
|
|
145
249
|
return env.SUMMER_WINDSURF_MCP_CONFIG_FILE;
|
|
146
250
|
}
|
|
147
251
|
async function upsertJsonMcpConfig(path, server, write) {
|
|
@@ -198,6 +302,60 @@ async function upsertCodexConfig(path, server, write) {
|
|
|
198
302
|
}
|
|
199
303
|
return { changed };
|
|
200
304
|
}
|
|
305
|
+
async function upsertOpencodeConfig(path, server, write) {
|
|
306
|
+
const current = await readJsonConfig(path);
|
|
307
|
+
const next = copyJsonObject(current);
|
|
308
|
+
if (typeof next.$schema !== "string") {
|
|
309
|
+
next.$schema = "https://opencode.ai/config.json";
|
|
310
|
+
}
|
|
311
|
+
const existingMcp = isJsonObject(next.mcp) ? next.mcp : {};
|
|
312
|
+
next.mcp = {
|
|
313
|
+
...existingMcp,
|
|
314
|
+
[SUMMER_MCP_SERVER_NAME]: opencodeServerEntry(server),
|
|
315
|
+
};
|
|
316
|
+
const currentRendered = renderJsonFile(current);
|
|
317
|
+
const nextRendered = renderJsonFile(next);
|
|
318
|
+
const changed = currentRendered !== nextRendered;
|
|
319
|
+
if (write && changed) {
|
|
320
|
+
await writeTextFile(path, nextRendered);
|
|
321
|
+
}
|
|
322
|
+
return { changed };
|
|
323
|
+
}
|
|
324
|
+
async function upsertGeminiExtension(path, server, write) {
|
|
325
|
+
const current = await readJsonConfig(path);
|
|
326
|
+
const next = geminiExtensionManifest(server, current);
|
|
327
|
+
const currentRendered = renderJsonFile(current);
|
|
328
|
+
const nextRendered = renderJsonFile(next);
|
|
329
|
+
const changed = currentRendered !== nextRendered;
|
|
330
|
+
if (write && changed) {
|
|
331
|
+
await writeTextFile(path, nextRendered);
|
|
332
|
+
}
|
|
333
|
+
return { changed };
|
|
334
|
+
}
|
|
335
|
+
function opencodeServerEntry(server) {
|
|
336
|
+
const entry = {
|
|
337
|
+
type: "local",
|
|
338
|
+
command: [server.command, ...server.args],
|
|
339
|
+
};
|
|
340
|
+
if (server.env && Object.keys(server.env).length > 0) {
|
|
341
|
+
entry.environment = { ...server.env };
|
|
342
|
+
}
|
|
343
|
+
return entry;
|
|
344
|
+
}
|
|
345
|
+
function geminiExtensionManifest(server, base = {}) {
|
|
346
|
+
const manifest = { ...base };
|
|
347
|
+
manifest.name = "summer";
|
|
348
|
+
manifest.description =
|
|
349
|
+
"Superpowers for AI game dev. MCP bridge to the local Summer Engine plus a context primer that teaches Gemini the Summer skills.";
|
|
350
|
+
manifest.contextFileName = "GEMINI.md";
|
|
351
|
+
manifest.mcpServers = {
|
|
352
|
+
[SUMMER_MCP_SERVER_NAME]: {
|
|
353
|
+
command: server.command,
|
|
354
|
+
args: server.args,
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
return manifest;
|
|
358
|
+
}
|
|
201
359
|
async function readTextFileIfExists(path) {
|
|
202
360
|
if (!existsSync(path))
|
|
203
361
|
return "";
|
|
@@ -273,7 +431,15 @@ function createNextSteps(agent, scope, path) {
|
|
|
273
431
|
? "Restart Codex or run /mcp in a new session."
|
|
274
432
|
: agent === "cursor"
|
|
275
433
|
? "Restart Cursor and enable the summer-engine MCP server if prompted."
|
|
276
|
-
:
|
|
434
|
+
: agent === "cline"
|
|
435
|
+
? "Restart VS Code so Cline reloads its MCP config."
|
|
436
|
+
: agent === "roo-code"
|
|
437
|
+
? "Restart VS Code so Roo Code reloads its MCP config."
|
|
438
|
+
: agent === "gemini"
|
|
439
|
+
? "Run `gemini extensions enable summer-engine` (if not already enabled), then restart Gemini CLI."
|
|
440
|
+
: agent === "opencode"
|
|
441
|
+
? "Restart OpenCode so it reloads opencode.json."
|
|
442
|
+
: "Restart Windsurf and refresh MCP servers from Cascade settings.";
|
|
277
443
|
const projectTrust = scope === "project" && agent === "codex"
|
|
278
444
|
? "Codex only loads project .codex/config.toml from trusted projects."
|
|
279
445
|
: null;
|