summer-engine 3.5.0 → 3.5.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.factory-plugin/plugin.json +1 -1
- package/CHANGELOG.md +8 -0
- package/README.md +3 -3
- package/dist/cli/commands/setup.js +2 -2
- package/dist/core/capabilities/publish-build.d.ts +4 -0
- package/dist/core/capabilities/publish-build.js +67 -34
- package/dist/core/capabilities/runtime-control.d.ts +2 -2
- package/dist/installer/agent-config.d.ts +5 -5
- package/dist/installer/agent-config.js +96 -32
- package/dist/installer/agent-table.d.ts +7 -6
- package/dist/installer/agent-table.js +117 -6
- package/gemini-extension.json +1 -1
- package/integrations/README.md +6 -0
- package/package.json +1 -1
- package/registry/generated/gemini-extension.json +1 -1
- package/registry/generated/marketplace.claude.json +1 -1
- package/registry/generated/plugin.claude.json +1 -1
- package/registry/generated/plugin.codex.json +1 -1
- package/registry/generated/plugin.cursor.json +1 -1
- package/registry/generated/plugin.factory.json +1 -1
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
{
|
|
12
12
|
"name": "summer",
|
|
13
13
|
"source": "./",
|
|
14
|
-
"version": "3.5.
|
|
14
|
+
"version": "3.5.1",
|
|
15
15
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Summer Engine",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"_generated": "GENERATED from integrations/claude — do not edit; npm run generate:registry",
|
|
4
4
|
"name": "summer",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.1",
|
|
6
6
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Summer Engine",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_generated": "GENERATED from integrations/codex — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.1",
|
|
5
5
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge. Build games by talking.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Summer Engine",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"_generated": "GENERATED from integrations/cursor — do not edit; npm run generate:registry",
|
|
4
4
|
"name": "summer",
|
|
5
5
|
"displayName": "Summer",
|
|
6
|
-
"version": "3.5.
|
|
6
|
+
"version": "3.5.1",
|
|
7
7
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Summer Engine",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"_generated": "GENERATED from integrations/factory — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
4
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Summer Engine",
|
|
8
8
|
"email": "founders@summerengine.com",
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to summer-engine will be documented here. Following [Keep a
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [3.5.1] - 2026-10-10
|
|
8
|
+
|
|
9
|
+
Summer Games now connects from almost every agent setup supports, and large store uploads finish.
|
|
10
|
+
|
|
11
|
+
- **Summer Games in more agents.** `summer setup` now adds `summer-games` (`https://mcp.summer.games/mcp`: friends, parties and messages as you) for Cursor, GitHub Copilot in VS Code, the Copilot CLI and Copilot in JetBrains, Zed, Cline and Cline CLI, Kilo Code, OpenCode, Devin Desktop (Windsurf), Antigravity, Kiro, Trae, Warp, Goose, Hermes, Crush, Amp, Factory Droid, Junie, Qwen Code, Kimi Code, Grok Build and Mistral Vibe, as well as Claude Code and Codex. Each gets the entry in its own format, and setup prints the one sign-in step for that agent. As in 3.5.0, setup adds no second entry when the same address is already listed under another name, and `--no-games` skips it.
|
|
12
|
+
- Not included, because they cannot sign in to it from their config file: Claude Desktop (add Summer Games as a custom connector in its settings), Roo Code and Rovo Dev (no sign-in for remote servers), and Visual Studio, Qoder and LM Studio (sign-in not yet checked).
|
|
13
|
+
- `summer_publish_build` and `summer_publish_download` no longer fail an upload of 3 or more parts with `store_sign_failed: The store did not sign part N` when the store signed every part. Each sign now asks for every part still to upload, a part counts as unsigned only when the store was asked for it and left it out, a signing error is retried like a failed part upload, and the first failure stops the other parts' uploads.
|
|
14
|
+
|
|
7
15
|
## [3.5.0] - 2026-10-10
|
|
8
16
|
|
|
9
17
|
Setup now connects Summer Games too, and agents that publish a game get further on their own. 3.4.2 was never published; its changes ship here.
|
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ The first run will:
|
|
|
57
57
|
4. Open your browser for one-click sign-in.
|
|
58
58
|
5. Scaffold a starter project and open the engine.
|
|
59
59
|
|
|
60
|
-
In Claude Code and
|
|
60
|
+
In most agents (Claude Code, Codex, Cursor, GitHub Copilot (VS Code, CLI, JetBrains), Zed, Cline, Kilo Code, OpenCode, Devin Desktop, Antigravity, Kiro, Trae, Warp, Goose, Hermes, Crush, Amp, Factory, Junie, Qwen Code, Kimi Code, Grok Build and Mistral Vibe), setup also connects Summer Games (`summer-games`), so the agent can see your friends, start parties and send messages as you. You sign in once; setup prints the step for your agent (Claude Code: `/mcp`, choose `summer-games`; Codex: `/mcp login summer-games`; Cursor: Connect next to `summer-games` in its MCP settings). A summer.games page opens in your browser; sign in and choose Allow.
|
|
61
61
|
|
|
62
62
|
Then ask the agent to build something.
|
|
63
63
|
|
|
@@ -125,7 +125,7 @@ npx -y summer-engine@latest setup claude-code --yes --force
|
|
|
125
125
|
|
|
126
126
|
Replace `claude-code` with the user's actual agent: `claude-desktop`, `codex`, `cursor`, `windsurf`, `antigravity`, `cline`, `cline-cli`, `kilo-code`, `github-copilot`, `vscode-copilot`, `visual-studio`, `copilot-jetbrains`, `opencode`, `zed`, `kiro`, `goose`, `hermes`, `trae`, `qwen-code`, `kimi-code`, `crush`, `amp`, `factory`, `junie`, `warp`, `rovo-dev`, `qoder`, `grok-build`, `mistral-vibe`, `lm-studio`. Use `github-copilot` for Copilot CLI, `vscode-copilot` for GitHub Copilot Chat/Agent in VS Code, `visual-studio` for Copilot in Visual Studio, and `copilot-jetbrains` for Copilot in JetBrains IDEs. Legacy targets `gemini` and `roo-code` still work; for Google's agent use `antigravity`. This installs **every skill in the library** to `~/.claude/skills/<slug>/SKILL.md` (or the agent's own skill directory), writes the MCP server config, runs doctor, and prints what it installed and where. Preview skills are included and labelled; `--stable-only` skips them. `--force` wipes stale skill copies first. Don't use `--recommended` from this playbook; it installs only a subset.
|
|
127
127
|
|
|
128
|
-
**Summer Games:** for `claude-
|
|
128
|
+
**Summer Games:** for every agent whose sign-in summer.games accepts (all targets except `claude-desktop`, `visual-studio`, `qoder`, `rovo-dev`, `lm-studio` and the legacy ones), setup also adds the remote `summer-games` MCP (`https://mcp.summer.games/mcp`) and prints a `Sign in once:` line. Tell the user that line once, in plain words. Their browser opens summer.games; they sign in and choose Allow. Do not wait for it; continue the playbook. If the user already added the same URL under another name (for example `summer`), setup keeps theirs and adds no second entry.
|
|
129
129
|
|
|
130
130
|
**First-install detection:** if `~/.claude/skills/` didn't exist before this command, Claude Code wasn't watching it and won't auto-detect the new files this session. Tell the user **once**: "Skills installed - restart your agent so they load." On subsequent installs (directory already existed), skills auto-detect mid-session and no restart is needed. **You can detect first-install vs upgrade by checking if `~/.claude/skills/` existed before Step 1; record the result before running setup.**
|
|
131
131
|
|
|
@@ -374,7 +374,7 @@ matchmaking are not promised by this package.
|
|
|
374
374
|
| `summer tool <name> --args '<json>'` | Run any Summer tool from the shell — the same implementation the MCP tool uses. `summer tool --list` prints them all. |
|
|
375
375
|
| `summer mcp [--project <path> \| --instance <id>]` | Start MCP; normally auto-binds from the agent's project directory. |
|
|
376
376
|
| `summer mcp setup <agent>` | Deprecated alias of `summer setup <agent>`. |
|
|
377
|
-
| `summer setup <agent> [--yes] [--force] [--recommended] [--stable-only] [--no-games]` | One shot: MCP config + all skills, preview included (`--recommended` for the subset, `--stable-only` to skip preview) + doctor. Idempotent. For Claude
|
|
377
|
+
| `summer setup <agent> [--yes] [--force] [--recommended] [--stable-only] [--no-games]` | One shot: MCP config + all skills, preview included (`--recommended` for the subset, `--stable-only` to skip preview) + doctor. Idempotent. For most agents (not Claude Desktop, Visual Studio, Qoder, Rovo Dev, LM Studio or the legacy targets) it also adds `summer-games` (`https://mcp.summer.games/mcp`: friends, parties and messages as you) unless the same URL is already listed; you sign in once through summer.games. `--no-games` skips it. |
|
|
378
378
|
|
|
379
379
|
Agents: `claude-code`, `claude-desktop`, `codex`, `cursor`, `windsurf`, `antigravity`, `cline`, `cline-cli`, `kilo-code`, `github-copilot`, `vscode-copilot`, `visual-studio`, `copilot-jetbrains`, `opencode`, `zed`, `kiro`, `goose`, `hermes`, `trae`, `qwen-code`, `kimi-code`, `crush`, `amp`, `factory`, `junie`, `warp`, `rovo-dev`, `qoder`, `grok-build`, `mistral-vibe`, `lm-studio`. Legacy (still accepted, warn on use): `gemini`, `roo-code`. Aliases: `devin`/`devin-desktop` → `windsurf`, `agy` → `antigravity`, `droid` → `factory`, `copilot` → `github-copilot`, `vscode` → `vscode-copilot`, `kilo` → `kilo-code`, `qwen` → `qwen-code`, `kimi` → `kimi-code`. Scopes: `--scope user` (default), `--scope project`.
|
|
380
380
|
|
|
@@ -7,7 +7,7 @@ import { TOOLKIT_VERSION as cliVersion } from "../../core/version.js";
|
|
|
7
7
|
import { resolveDefaultChannel } from "../../installer/version-check.js";
|
|
8
8
|
import { agentLabel } from "../../installer/agent-table.js";
|
|
9
9
|
export const setupCommand = new Command("setup")
|
|
10
|
-
.description("Configure Summer Engine for an AI agent and run diagnostics. For
|
|
10
|
+
.description("Configure Summer Engine for an AI agent and run diagnostics. For agents that can sign in to it, it also adds Summer Games (summer-games).")
|
|
11
11
|
.argument("[agent]", `Agent to configure: ${supportedAgents.join(", ")}`)
|
|
12
12
|
.option("--agent <agent>", `Agent to configure: ${supportedAgents.join(", ")}`)
|
|
13
13
|
.option("--scope <scope>", "Configuration scope: user or project", "user")
|
|
@@ -16,7 +16,7 @@ export const setupCommand = new Command("setup")
|
|
|
16
16
|
.option("--local-dev", "Point the agent at this checkout's built CLI (node <repo>/dist/bin/summer.js mcp) instead of npx summer-engine@latest — for testing unpublished builds. SUMMER_DEV=1 does the same.")
|
|
17
17
|
.option("--channel <dist-tag>", "npm dist-tag the agent's MCP entry runs: npx -y summer-engine@<dist-tag> mcp (default latest; use next while a release soaks on the next tag). SUMMER_CHANNEL does the same.")
|
|
18
18
|
.option("--yes", "Apply practical setup steps without prompting")
|
|
19
|
-
.option("--no-games", "Do not add the Summer Games MCP (summer-games: friends, parties and messages as you, signed in through summer.games
|
|
19
|
+
.option("--no-games", "Do not add the Summer Games MCP (summer-games: friends, parties and messages as you, signed in through summer.games)")
|
|
20
20
|
.option("--json", "Print setup result as JSON")
|
|
21
21
|
.option("--force", "Overwrite existing skill content (passes --force through to skills install)")
|
|
22
22
|
.option("--recommended", "Install only the recommended skill subset instead of the whole library")
|
|
@@ -51,6 +51,10 @@ export declare function readGrants(body: Record<string, any>): Grant[];
|
|
|
51
51
|
* Upload the given parts: signed in batches, PUT from disk, re-signed when
|
|
52
52
|
* refused or about to expire. `sign` asks the store for URLs (build
|
|
53
53
|
* publications bind each to its part SHA-256; store versions to its length).
|
|
54
|
+
* Each sign asks for every part not yet uploaded, including the parts other
|
|
55
|
+
* workers hold, so one sign usually covers them all. A part fails to sign only
|
|
56
|
+
* when the store was asked for it and did not sign it; the first fatal error
|
|
57
|
+
* stops the other workers and aborts their uploads.
|
|
54
58
|
*/
|
|
55
59
|
export declare function uploadParts(sign: (partNumbers: number[]) => Promise<Grant[]>, file: string, sizeBytes: number, plan: {
|
|
56
60
|
partSizeBytes: number;
|
|
@@ -185,19 +185,28 @@ async function readPart(path, partNumber, partSize, sizeBytes) {
|
|
|
185
185
|
* Upload the given parts: signed in batches, PUT from disk, re-signed when
|
|
186
186
|
* refused or about to expire. `sign` asks the store for URLs (build
|
|
187
187
|
* publications bind each to its part SHA-256; store versions to its length).
|
|
188
|
+
* Each sign asks for every part not yet uploaded, including the parts other
|
|
189
|
+
* workers hold, so one sign usually covers them all. A part fails to sign only
|
|
190
|
+
* when the store was asked for it and did not sign it; the first fatal error
|
|
191
|
+
* stops the other workers and aborts their uploads.
|
|
188
192
|
*/
|
|
189
193
|
export async function uploadParts(sign, file, sizeBytes, plan, deps, parts = Array.from({ length: plan.partCount }, (_, index) => index + 1)) {
|
|
190
194
|
const queue = [...parts];
|
|
195
|
+
const unfinished = new Set(parts);
|
|
191
196
|
const grants = new Map();
|
|
197
|
+
const stop = new AbortController();
|
|
198
|
+
let failure;
|
|
192
199
|
let signing = null;
|
|
193
200
|
const fresh = (grant) => grant !== undefined && grant.expiresAt - deps.now() > 60_000;
|
|
194
201
|
const grantFor = async (partNumber) => {
|
|
195
|
-
for (
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
for (;;) {
|
|
203
|
+
const grant = grants.get(partNumber);
|
|
204
|
+
if (fresh(grant))
|
|
205
|
+
return grant;
|
|
198
206
|
if (!signing) {
|
|
199
|
-
const
|
|
200
|
-
|
|
207
|
+
const others = [...unfinished].filter((n) => n !== partNumber && !fresh(grants.get(n)));
|
|
208
|
+
const batch = [partNumber, ...others].slice(0, MAX_SIGNED_PARTS);
|
|
209
|
+
const done = sign(batch)
|
|
201
210
|
.then((signed) => {
|
|
202
211
|
for (const grant of signed)
|
|
203
212
|
grants.set(grant.partNumber, grant);
|
|
@@ -205,43 +214,67 @@ export async function uploadParts(sign, file, sizeBytes, plan, deps, parts = Arr
|
|
|
205
214
|
.finally(() => {
|
|
206
215
|
signing = null;
|
|
207
216
|
});
|
|
217
|
+
signing = { batch, done };
|
|
218
|
+
}
|
|
219
|
+
const { batch, done } = signing;
|
|
220
|
+
await done;
|
|
221
|
+
// The store was asked for this part and did not sign it (or signed it already expiring).
|
|
222
|
+
if (batch.includes(partNumber) && !fresh(grants.get(partNumber))) {
|
|
223
|
+
throw new BuildToolError("store_sign_failed", `The store did not sign part ${partNumber}.`, "Recovery: retry; a retry continues the same upload.");
|
|
208
224
|
}
|
|
209
|
-
await signing;
|
|
210
225
|
}
|
|
211
|
-
throw new BuildToolError("store_sign_failed", `The store did not sign part ${partNumber}.`, "Recovery: retry; a retry continues the same upload.");
|
|
212
226
|
};
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
227
|
+
const upload = async (partNumber) => {
|
|
228
|
+
const body = await readPart(file, partNumber, plan.partSizeBytes, sizeBytes);
|
|
229
|
+
for (let attempt = 0;; attempt++) {
|
|
230
|
+
let status = null;
|
|
231
|
+
let error = null;
|
|
232
|
+
try {
|
|
217
233
|
const grant = await grantFor(partNumber);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
234
|
+
const response = await deps.fetch(grant.url, {
|
|
235
|
+
method: "PUT",
|
|
236
|
+
headers: grant.headers,
|
|
237
|
+
body,
|
|
238
|
+
redirect: "error",
|
|
239
|
+
signal: AbortSignal.any([stop.signal, AbortSignal.timeout(600_000)]),
|
|
240
|
+
});
|
|
241
|
+
if (response.ok)
|
|
242
|
+
return;
|
|
243
|
+
status = response.status;
|
|
244
|
+
}
|
|
245
|
+
catch (caught) {
|
|
246
|
+
error = caught;
|
|
247
|
+
}
|
|
248
|
+
if (stop.signal.aborted)
|
|
249
|
+
return;
|
|
250
|
+
// An expired or refused signature gets a new URL on the next try.
|
|
251
|
+
if (status === 400 || status === 403)
|
|
252
|
+
grants.delete(partNumber);
|
|
253
|
+
if (attempt >= PART_RETRIES) {
|
|
254
|
+
if (error instanceof BuildToolError)
|
|
255
|
+
throw error;
|
|
256
|
+
throw new BuildToolError("store_part_upload_failed", `Part ${partNumber} of ${plan.partCount} did not upload${status ? ` (${status})` : ""}.`, "Recovery: retry with the same file and clientVersion; the upload continues where it stopped.");
|
|
257
|
+
}
|
|
258
|
+
await deps.sleep(500 * 2 ** attempt);
|
|
259
|
+
if (stop.signal.aborted)
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const worker = async () => {
|
|
264
|
+
for (let partNumber = queue.shift(); partNumber !== undefined && !stop.signal.aborted; partNumber = queue.shift()) {
|
|
265
|
+
try {
|
|
266
|
+
await upload(partNumber);
|
|
267
|
+
unfinished.delete(partNumber);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
failure ??= error;
|
|
271
|
+
stop.abort();
|
|
241
272
|
}
|
|
242
273
|
}
|
|
243
274
|
};
|
|
244
275
|
await Promise.all(Array.from({ length: Math.min(CONCURRENCY, queue.length) }, worker));
|
|
276
|
+
if (stop.signal.aborted)
|
|
277
|
+
throw failure;
|
|
245
278
|
}
|
|
246
279
|
export function normalizeClientVersion(value) {
|
|
247
280
|
const raw = value?.trim() ?? "";
|
|
@@ -186,8 +186,8 @@ export declare const runtimeAnimateArgsSchema: z.ZodObject<{
|
|
|
186
186
|
value?: string | number | boolean | undefined;
|
|
187
187
|
instance?: string | undefined;
|
|
188
188
|
name?: string | undefined;
|
|
189
|
-
cmd?: "state" | "pause" | "play" | "stop" | "seek" | "speed" | "travel" | "start" | "set_param" | "get_param" | undefined;
|
|
190
189
|
space?: "local" | "global" | "both" | undefined;
|
|
190
|
+
cmd?: "state" | "pause" | "play" | "stop" | "seek" | "speed" | "travel" | "start" | "set_param" | "get_param" | undefined;
|
|
191
191
|
blend?: number | undefined;
|
|
192
192
|
position?: number | undefined;
|
|
193
193
|
speed?: number | undefined;
|
|
@@ -205,8 +205,8 @@ export declare const runtimeAnimateArgsSchema: z.ZodObject<{
|
|
|
205
205
|
value?: string | number | boolean | undefined;
|
|
206
206
|
instance?: string | undefined;
|
|
207
207
|
name?: string | undefined;
|
|
208
|
-
cmd?: "state" | "pause" | "play" | "stop" | "seek" | "speed" | "travel" | "start" | "set_param" | "get_param" | undefined;
|
|
209
208
|
space?: "local" | "global" | "both" | undefined;
|
|
209
|
+
cmd?: "state" | "pause" | "play" | "stop" | "seek" | "speed" | "travel" | "start" | "set_param" | "get_param" | undefined;
|
|
210
210
|
blend?: number | undefined;
|
|
211
211
|
position?: number | undefined;
|
|
212
212
|
speed?: number | undefined;
|
|
@@ -64,10 +64,10 @@ export interface RemoteMcpResult {
|
|
|
64
64
|
signIn: string;
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
* Adds the Summer Games MCP next to summer-engine in the same config file
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
67
|
+
* Adds the Summer Games MCP next to summer-engine in the same config file, in
|
|
68
|
+
* the agent's own entry shape (remoteMcp in agent-table.ts). An entry that
|
|
69
|
+
* already points at the same URL, under any name, counts as added and is left
|
|
70
|
+
* as it is. Returns null for agents without remoteMcp.
|
|
71
71
|
*/
|
|
72
72
|
export declare function configureSummerGamesMcp(options: Pick<AgentConfigOptions, "agent" | "scope" | "dryRun" | "cwd" | "env">): Promise<RemoteMcpResult | null>;
|
|
73
73
|
export declare const DEFAULT_CHANNEL = "latest";
|
|
@@ -85,4 +85,4 @@ export declare function mcpEntry(format: McpFormat, server: StdioMcpServerConfig
|
|
|
85
85
|
export declare function resolvePackageRoot(): string;
|
|
86
86
|
/** Directory name Gemini expects the extension under; the manifest `name` must match it. */
|
|
87
87
|
export declare const GEMINI_EXTENSION_DIR_NAME = "summer-engine";
|
|
88
|
-
export declare function upsertTomlArrayBlock(content: string, block: string): string;
|
|
88
|
+
export declare function upsertTomlArrayBlock(content: string, block: string, name?: string): string;
|
|
@@ -79,10 +79,10 @@ export async function configureAgentMcp(options) {
|
|
|
79
79
|
export const SUMMER_GAMES_MCP_SERVER_NAME = "summer-games";
|
|
80
80
|
export const SUMMER_GAMES_MCP_URL = "https://mcp.summer.games/mcp";
|
|
81
81
|
/**
|
|
82
|
-
* Adds the Summer Games MCP next to summer-engine in the same config file
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
82
|
+
* Adds the Summer Games MCP next to summer-engine in the same config file, in
|
|
83
|
+
* the agent's own entry shape (remoteMcp in agent-table.ts). An entry that
|
|
84
|
+
* already points at the same URL, under any name, counts as added and is left
|
|
85
|
+
* as it is. Returns null for agents without remoteMcp.
|
|
86
86
|
*/
|
|
87
87
|
export async function configureSummerGamesMcp(options) {
|
|
88
88
|
const spec = agentSpec(options.agent);
|
|
@@ -92,39 +92,68 @@ export async function configureSummerGamesMcp(options) {
|
|
|
92
92
|
const target = resolveConfigTarget(spec, options.scope, resolve(options.cwd ?? process.cwd()), env);
|
|
93
93
|
const write = !options.dryRun;
|
|
94
94
|
const url = SUMMER_GAMES_MCP_URL;
|
|
95
|
+
const name = SUMMER_GAMES_MCP_SERVER_NAME;
|
|
96
|
+
const entry = spec.remoteMcp.entry(url);
|
|
97
|
+
const key = topLevelKey(spec.format);
|
|
95
98
|
let existing;
|
|
96
99
|
let changed = false;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
switch (spec.format) {
|
|
101
|
+
case "toml":
|
|
102
|
+
case "toml-array": {
|
|
103
|
+
const current = await readTextFileIfExists(target.path);
|
|
104
|
+
existing = spec.format === "toml" ? findTomlServerByUrl(current, url) : findTomlArrayServerByUrl(current, url);
|
|
105
|
+
if (existing)
|
|
106
|
+
break;
|
|
107
|
+
const next = spec.format === "toml"
|
|
108
|
+
? upsertTomlTable(current, renderTomlTable(`[mcp_servers.${name}]`, entry), name)
|
|
109
|
+
: upsertTomlArrayBlock(current, renderTomlTable("[[mcp_servers]]", entry), name);
|
|
103
110
|
changed = current !== next;
|
|
104
111
|
if (write && changed)
|
|
105
112
|
await writeTextFile(target.path, next);
|
|
113
|
+
break;
|
|
106
114
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
case "yaml-goose":
|
|
116
|
+
case "yaml-hermes": {
|
|
117
|
+
const current = await readTextFileIfExists(target.path);
|
|
118
|
+
const parsed = current.trim() === "" ? {} : parseDocument(current).toJS();
|
|
119
|
+
existing = isJsonObject(parsed) ? findServerByUrl([parsed[key]], url) : undefined;
|
|
120
|
+
if (existing)
|
|
121
|
+
break;
|
|
122
|
+
({ changed } = await upsertYamlConfig(target.path, [key, name], entry, write));
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case "json-gemini":
|
|
126
|
+
throw new Error("The Gemini extension manifest has no Summer Games entry.");
|
|
127
|
+
default: {
|
|
128
|
+
const current = await readJsonConfig(target.path);
|
|
129
|
+
const maps = [current[key]];
|
|
130
|
+
// Claude Code's ~/.claude.json also keeps per-project servers (`claude
|
|
131
|
+
// mcp add` without --scope user) under projects.<dir>.mcpServers.
|
|
132
|
+
if (isJsonObject(current.projects)) {
|
|
133
|
+
for (const project of Object.values(current.projects)) {
|
|
134
|
+
if (isJsonObject(project))
|
|
135
|
+
maps.push(project.mcpServers);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
existing = findServerByUrl(maps, url);
|
|
139
|
+
if (existing)
|
|
140
|
+
break;
|
|
112
141
|
const next = copyJsonObject(current);
|
|
113
|
-
next
|
|
142
|
+
next[key] = mergeNamedObject(next[key], name, entry, key);
|
|
114
143
|
const nextRendered = renderJsonFile(next);
|
|
115
144
|
changed = renderJsonFile(current) !== nextRendered;
|
|
116
145
|
if (write && changed)
|
|
117
146
|
await writeTextFile(target.path, nextRendered);
|
|
118
147
|
}
|
|
119
148
|
}
|
|
120
|
-
const serverName = existing ??
|
|
149
|
+
const serverName = existing ?? name;
|
|
121
150
|
return {
|
|
122
151
|
serverName,
|
|
123
152
|
url,
|
|
124
153
|
path: target.path,
|
|
125
154
|
changed,
|
|
126
155
|
wrote: write && changed,
|
|
127
|
-
...(existing && existing !==
|
|
156
|
+
...(existing && existing !== name ? { existingName: existing } : {}),
|
|
128
157
|
signIn: spec.remoteMcp.signIn(serverName),
|
|
129
158
|
};
|
|
130
159
|
}
|
|
@@ -142,27 +171,62 @@ function sameMcpUrl(a, b) {
|
|
|
142
171
|
};
|
|
143
172
|
return normalize(a) === normalize(b);
|
|
144
173
|
}
|
|
145
|
-
/**
|
|
146
|
-
*
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (isJsonObject(config.projects)) {
|
|
151
|
-
for (const project of Object.values(config.projects)) {
|
|
152
|
-
if (isJsonObject(project))
|
|
153
|
-
maps.push(project.mcpServers);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
174
|
+
/** Agents name a remote server's address url, serverUrl (Windsurf,
|
|
175
|
+
* Antigravity), httpUrl (Qwen Code) or uri (Goose). */
|
|
176
|
+
const REMOTE_URL_FIELDS = ["url", "serverUrl", "httpUrl", "uri"];
|
|
177
|
+
/** The name of a server with this URL in any of these name -> entry maps. */
|
|
178
|
+
function findServerByUrl(maps, url) {
|
|
156
179
|
for (const map of maps) {
|
|
157
180
|
if (!isJsonObject(map))
|
|
158
181
|
continue;
|
|
159
182
|
for (const [name, entry] of Object.entries(map)) {
|
|
160
|
-
if (isJsonObject(entry) && sameMcpUrl(entry
|
|
183
|
+
if (isJsonObject(entry) && REMOTE_URL_FIELDS.some((field) => sameMcpUrl(entry[field], url)))
|
|
161
184
|
return name;
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
187
|
return undefined;
|
|
165
188
|
}
|
|
189
|
+
/** The name of a [[mcp_servers]] block (Mistral Vibe) whose url is this URL. */
|
|
190
|
+
function findTomlArrayServerByUrl(content, url) {
|
|
191
|
+
let block;
|
|
192
|
+
const done = () => (block?.matches ? block.name : undefined);
|
|
193
|
+
for (const line of content.split(/\r?\n/)) {
|
|
194
|
+
if (/^\s*\[/.test(line)) {
|
|
195
|
+
if (done())
|
|
196
|
+
return done();
|
|
197
|
+
block = /^\s*\[\[mcp_servers\]\]\s*(?:#.*)?$/.test(line) ? { matches: false } : undefined;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (!block)
|
|
201
|
+
continue;
|
|
202
|
+
const field = /^\s*(name|url)\s*=\s*(?:"([^"]*)"|'([^']*)')/.exec(line);
|
|
203
|
+
if (!field)
|
|
204
|
+
continue;
|
|
205
|
+
const value = field[2] ?? field[3];
|
|
206
|
+
if (field[1] === "name")
|
|
207
|
+
block.name = value;
|
|
208
|
+
else if (sameMcpUrl(value, url))
|
|
209
|
+
block.matches = true;
|
|
210
|
+
}
|
|
211
|
+
return done();
|
|
212
|
+
}
|
|
213
|
+
/** A TOML table: the header line, then key = value for each entry field. */
|
|
214
|
+
function renderTomlTable(header, entry) {
|
|
215
|
+
return `${[header, ...Object.entries(entry).map(([field, value]) => `${field} = ${tomlValue(value)}`)].join("\n")}\n`;
|
|
216
|
+
}
|
|
217
|
+
function tomlValue(value) {
|
|
218
|
+
if (typeof value === "string")
|
|
219
|
+
return tomlString(value);
|
|
220
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
221
|
+
return String(value);
|
|
222
|
+
if (Array.isArray(value))
|
|
223
|
+
return `[${value.map(tomlValue).join(", ")}]`;
|
|
224
|
+
if (isJsonObject(value)) {
|
|
225
|
+
const fields = Object.entries(value).map(([field, inner]) => `${field} = ${tomlValue(inner)}`);
|
|
226
|
+
return fields.length === 0 ? "{}" : `{ ${fields.join(", ")} }`;
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`Cannot write ${JSON.stringify(value)} as TOML.`);
|
|
229
|
+
}
|
|
166
230
|
/** The name of a [mcp_servers.<name>] table whose url is this URL. */
|
|
167
231
|
function findTomlServerByUrl(content, url) {
|
|
168
232
|
let table;
|
|
@@ -430,10 +494,10 @@ async function upsertTomlArrayConfig(path, server, write) {
|
|
|
430
494
|
}
|
|
431
495
|
return { changed };
|
|
432
496
|
}
|
|
433
|
-
export function upsertTomlArrayBlock(content, block) {
|
|
497
|
+
export function upsertTomlArrayBlock(content, block, name = SUMMER_MCP_SERVER_NAME) {
|
|
434
498
|
const lines = content.split(/\r?\n/);
|
|
435
499
|
const header = /^\s*\[\[mcp_servers\]\]\s*(?:#.*)?$/;
|
|
436
|
-
const nameLine = new RegExp(`^\\s*name\\s*=\\s*"${
|
|
500
|
+
const nameLine = new RegExp(`^\\s*name\\s*=\\s*"${name}"\\s*(?:#.*)?$`);
|
|
437
501
|
let start = -1;
|
|
438
502
|
let end = lines.length;
|
|
439
503
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -22,7 +22,6 @@ export type ConfigScope = "user" | "project";
|
|
|
22
22
|
* json-gemini the Gemini extension manifest (legacy)
|
|
23
23
|
*/
|
|
24
24
|
export type McpFormat = "json" | "json-stdio" | "json-vscode" | "json-copilot" | "json-opencode" | "json-servers" | "json-zed" | "json-amp" | "json-crush" | "json-transport" | "toml" | "toml-array" | "yaml-goose" | "yaml-hermes" | "json-gemini";
|
|
25
|
-
export type RemoteMcpFormat = "json-http" | "toml-url";
|
|
26
25
|
export type SkillLocationKind = "skill-dir" | "cursor-rule-dir" | "windsurf-rule-file" | "cline-rule-dir" | "opencode-skill-dir";
|
|
27
26
|
export interface PathContext {
|
|
28
27
|
home: string;
|
|
@@ -72,14 +71,16 @@ export interface AgentSpec {
|
|
|
72
71
|
envOverride: string;
|
|
73
72
|
format: McpFormat;
|
|
74
73
|
/**
|
|
75
|
-
*
|
|
76
|
-
* own
|
|
77
|
-
*
|
|
78
|
-
* toml-url [mcp_servers.<name>] url (Codex)
|
|
74
|
+
* The Summer Games player MCP (a remote server that signs in with OAuth on
|
|
75
|
+
* its own) in this agent's file, under the same key as summer-engine.
|
|
76
|
+
* entry is the server's value; for TOML it is written as key = value lines.
|
|
79
77
|
* signIn tells the person how to sign in once, for the entry's name.
|
|
78
|
+
* Absent: setup links the engine only (no OAuth sign-in for remote servers,
|
|
79
|
+
* no file entry for them, or a sign-in api.summer.games has not been checked
|
|
80
|
+
* to accept).
|
|
80
81
|
*/
|
|
81
82
|
remoteMcp?: {
|
|
82
|
-
|
|
83
|
+
entry: (url: string) => Record<string, unknown>;
|
|
83
84
|
signIn: (name: string) => string;
|
|
84
85
|
};
|
|
85
86
|
mcp: {
|
|
@@ -108,7 +108,10 @@ const SPECS = [
|
|
|
108
108
|
status: "active",
|
|
109
109
|
envOverride: "SUMMER_CLAUDE_CONFIG_FILE",
|
|
110
110
|
format: "json-stdio",
|
|
111
|
-
remoteMcp: {
|
|
111
|
+
remoteMcp: {
|
|
112
|
+
entry: (url) => ({ type: "http", url }),
|
|
113
|
+
signIn: (name) => `In Claude Code, run /mcp, choose ${name} and sign in.`,
|
|
114
|
+
},
|
|
112
115
|
mcp: { user: home(".claude.json"), project: project(".mcp.json") },
|
|
113
116
|
restart: "Restart Claude Code or run /mcp in a new session.",
|
|
114
117
|
skills: skillDirs(home(".claude", "skills"), project(".claude", "skills")),
|
|
@@ -120,6 +123,7 @@ const SPECS = [
|
|
|
120
123
|
status: "active",
|
|
121
124
|
envOverride: "SUMMER_CLAUDE_DESKTOP_CONFIG_FILE",
|
|
122
125
|
format: "json",
|
|
126
|
+
// No Summer Games entry: Claude Desktop's file takes local servers only; remote ones are added as Connectors in its settings.
|
|
123
127
|
mcp: {
|
|
124
128
|
user: (ctx) => join(appConfigRoot(ctx), "Claude", "claude_desktop_config.json"),
|
|
125
129
|
project: null,
|
|
@@ -136,7 +140,7 @@ const SPECS = [
|
|
|
136
140
|
envOverride: "SUMMER_CODEX_CONFIG_FILE",
|
|
137
141
|
format: "toml",
|
|
138
142
|
remoteMcp: {
|
|
139
|
-
|
|
143
|
+
entry: (url) => ({ url }),
|
|
140
144
|
signIn: (name) => `In Codex, run /mcp login ${name} (or \`codex mcp login ${name}\` in a terminal) and sign in.`,
|
|
141
145
|
},
|
|
142
146
|
mcp: {
|
|
@@ -154,10 +158,10 @@ const SPECS = [
|
|
|
154
158
|
status: "active",
|
|
155
159
|
envOverride: "SUMMER_CURSOR_MCP_CONFIG_FILE",
|
|
156
160
|
format: "json-stdio",
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
remoteMcp: {
|
|
162
|
+
entry: (url) => ({ url }),
|
|
163
|
+
signIn: (name) => `In Cursor Settings, open MCP and click Connect (or Authenticate) next to ${name}.`,
|
|
164
|
+
},
|
|
161
165
|
mcp: { user: home(".cursor", "mcp.json"), project: project(".cursor", "mcp.json") },
|
|
162
166
|
restart: "Restart Cursor and enable the summer-engine MCP server if prompted.",
|
|
163
167
|
skills: sharedSkills({
|
|
@@ -173,6 +177,10 @@ const SPECS = [
|
|
|
173
177
|
status: "active",
|
|
174
178
|
envOverride: "SUMMER_WINDSURF_MCP_CONFIG_FILE",
|
|
175
179
|
format: "json",
|
|
180
|
+
remoteMcp: {
|
|
181
|
+
entry: (url) => ({ serverUrl: url }),
|
|
182
|
+
signIn: (name) => `Devin Desktop opens summer.games in your browser the first time ${name} connects; sign in there.`,
|
|
183
|
+
},
|
|
176
184
|
mcp: {
|
|
177
185
|
user: home(".codeium", "windsurf", "mcp_config.json"),
|
|
178
186
|
project: null,
|
|
@@ -187,6 +195,10 @@ const SPECS = [
|
|
|
187
195
|
status: "active",
|
|
188
196
|
envOverride: "SUMMER_ANTIGRAVITY_CONFIG_FILE",
|
|
189
197
|
format: "json",
|
|
198
|
+
remoteMcp: {
|
|
199
|
+
entry: (url) => ({ serverUrl: url }),
|
|
200
|
+
signIn: (name) => `In Antigravity, open Settings > Customizations, choose Authenticate next to ${name}, sign in on summer.games, then paste the code back and choose Submit.`,
|
|
201
|
+
},
|
|
190
202
|
mcp: {
|
|
191
203
|
user: home(".gemini", "config", "mcp_config.json"),
|
|
192
204
|
project: project(".agents", "mcp_config.json"),
|
|
@@ -202,6 +214,7 @@ const SPECS = [
|
|
|
202
214
|
legacyNote: "Gemini CLI was retired for individual accounts on 2026-06-18 and replaced by Antigravity. Use `summer setup antigravity` unless you are on a Workspace/enterprise Gemini CLI.",
|
|
203
215
|
envOverride: "SUMMER_GEMINI_CONFIG_FILE",
|
|
204
216
|
format: "json-gemini",
|
|
217
|
+
// No Summer Games entry: legacy target; use antigravity.
|
|
205
218
|
mcp: {
|
|
206
219
|
user: home(".gemini", "extensions", "summer-engine", "gemini-extension.json"),
|
|
207
220
|
project: null,
|
|
@@ -216,6 +229,10 @@ const SPECS = [
|
|
|
216
229
|
status: "active",
|
|
217
230
|
envOverride: "SUMMER_CLINE_CONFIG_FILE",
|
|
218
231
|
format: "json",
|
|
232
|
+
remoteMcp: {
|
|
233
|
+
entry: (url) => ({ type: "streamableHttp", url }),
|
|
234
|
+
signIn: (name) => `In Cline, open MCP Servers and click Authenticate next to ${name}.`,
|
|
235
|
+
},
|
|
219
236
|
mcp: {
|
|
220
237
|
user: (ctx) => vsCodeGlobalStorage(ctx, "saoudrizwan.claude-dev", "cline_mcp_settings.json"),
|
|
221
238
|
project: null,
|
|
@@ -230,6 +247,10 @@ const SPECS = [
|
|
|
230
247
|
status: "active",
|
|
231
248
|
envOverride: "SUMMER_CLINE_CLI_CONFIG_FILE",
|
|
232
249
|
format: "json",
|
|
250
|
+
remoteMcp: {
|
|
251
|
+
entry: (url) => ({ type: "streamableHttp", url }),
|
|
252
|
+
signIn: (name) => `Run \`cline mcp\`, pick ${name} and choose Authorize OAuth.`,
|
|
253
|
+
},
|
|
233
254
|
mcp: { user: home(".cline", "data", "settings", "cline_mcp_settings.json"), project: null },
|
|
234
255
|
restart: "Restart the Cline CLI so it reloads its MCP settings.",
|
|
235
256
|
skills: skillDirs(home(".cline", "skills"), project(".cline", "skills")),
|
|
@@ -242,6 +263,7 @@ const SPECS = [
|
|
|
242
263
|
legacyNote: "Roo Code shut down on 2026-05-15. The extension may still run, but it is no longer maintained; consider Cline or Kilo Code.",
|
|
243
264
|
envOverride: "SUMMER_ROO_CODE_CONFIG_FILE",
|
|
244
265
|
format: "json",
|
|
266
|
+
// No Summer Games entry: Roo Code has no OAuth sign-in for remote MCP servers.
|
|
245
267
|
mcp: {
|
|
246
268
|
user: (ctx) => vsCodeGlobalStorage(ctx, "rooveterinaryinc.roo-cline", "cline_mcp_settings.json"),
|
|
247
269
|
project: null,
|
|
@@ -261,6 +283,10 @@ const SPECS = [
|
|
|
261
283
|
status: "active",
|
|
262
284
|
envOverride: "SUMMER_KILO_CODE_CONFIG_FILE",
|
|
263
285
|
format: "json-opencode",
|
|
286
|
+
remoteMcp: {
|
|
287
|
+
entry: (url) => ({ type: "remote", url }),
|
|
288
|
+
signIn: (name) => `In Kilo, click the sign-in notice for ${name} (Kilo CLI: \`kilo mcp auth ${name}\`).`,
|
|
289
|
+
},
|
|
264
290
|
mcp: {
|
|
265
291
|
user: (ctx) => join(xdgOrAppData(ctx), "kilo", "kilo.json"),
|
|
266
292
|
project: project("kilo.json"),
|
|
@@ -275,6 +301,10 @@ const SPECS = [
|
|
|
275
301
|
status: "active",
|
|
276
302
|
envOverride: "SUMMER_GITHUB_COPILOT_CONFIG_FILE",
|
|
277
303
|
format: "json-copilot",
|
|
304
|
+
remoteMcp: {
|
|
305
|
+
entry: (url) => ({ type: "http", url, tools: ["*"] }),
|
|
306
|
+
signIn: (name) => `Copilot CLI opens summer.games to sign in when ${name} first connects; /mcp signs in again.`,
|
|
307
|
+
},
|
|
278
308
|
mcp: { user: home(".copilot", "mcp-config.json"), project: project(".mcp.json") },
|
|
279
309
|
restart: "Restart Copilot CLI, or run /mcp reload and /skills reload in the active session.",
|
|
280
310
|
skills: skillDirs(home(".copilot", "skills"), project(".github", "skills")),
|
|
@@ -286,6 +316,10 @@ const SPECS = [
|
|
|
286
316
|
status: "active",
|
|
287
317
|
envOverride: "SUMMER_VSCODE_COPILOT_CONFIG_FILE",
|
|
288
318
|
format: "json-vscode",
|
|
319
|
+
remoteMcp: {
|
|
320
|
+
entry: (url) => ({ type: "http", url }),
|
|
321
|
+
signIn: (name) => `In VS Code, click Allow when ${name} asks to authenticate, then sign in on summer.games.`,
|
|
322
|
+
},
|
|
289
323
|
mcp: { user: (ctx) => join(vsCodeUserDir(ctx), "mcp.json"), project: project(".vscode", "mcp.json") },
|
|
290
324
|
restart: "Restart VS Code or run MCP: List Servers, then start summer-engine in Copilot Agent mode.",
|
|
291
325
|
skills: sharedSkills({ legacyDirs: { user: home(".copilot", "skills"), project: project(".github", "skills") } }),
|
|
@@ -297,6 +331,7 @@ const SPECS = [
|
|
|
297
331
|
status: "active",
|
|
298
332
|
envOverride: "SUMMER_VISUAL_STUDIO_CONFIG_FILE",
|
|
299
333
|
format: "json-vscode",
|
|
334
|
+
// No Summer Games entry: Visual Studio's OAuth redirect for MCP is not documented; not checked against api.summer.games.
|
|
300
335
|
mcp: { user: home(".mcp.json"), project: project(".mcp.json") },
|
|
301
336
|
restart: "Restart Visual Studio, open Copilot Chat in Agent mode, and enable summer-engine in the tools picker.",
|
|
302
337
|
skills: null,
|
|
@@ -309,6 +344,10 @@ const SPECS = [
|
|
|
309
344
|
status: "active",
|
|
310
345
|
envOverride: "SUMMER_COPILOT_JETBRAINS_CONFIG_FILE",
|
|
311
346
|
format: "json-servers",
|
|
347
|
+
remoteMcp: {
|
|
348
|
+
entry: (url) => ({ url }),
|
|
349
|
+
signIn: (name) => `In your JetBrains IDE, click OK when ${name} asks to authenticate, then sign in on summer.games.`,
|
|
350
|
+
},
|
|
312
351
|
mcp: {
|
|
313
352
|
user: (ctx) => join(xdgOrAppData(ctx), "github-copilot", "intellij", "mcp.json"),
|
|
314
353
|
project: null,
|
|
@@ -324,6 +363,10 @@ const SPECS = [
|
|
|
324
363
|
status: "active",
|
|
325
364
|
envOverride: "SUMMER_OPENCODE_CONFIG_FILE",
|
|
326
365
|
format: "json-opencode",
|
|
366
|
+
remoteMcp: {
|
|
367
|
+
entry: (url) => ({ type: "remote", url }),
|
|
368
|
+
signIn: (name) => `Run \`opencode mcp auth ${name}\`; it opens summer.games to sign in.`,
|
|
369
|
+
},
|
|
327
370
|
mcp: {
|
|
328
371
|
user: (ctx) => join(xdgOrAppData(ctx), "opencode", "opencode.json"),
|
|
329
372
|
project: project("opencode.json"),
|
|
@@ -342,6 +385,10 @@ const SPECS = [
|
|
|
342
385
|
status: "active",
|
|
343
386
|
envOverride: "SUMMER_ZED_CONFIG_FILE",
|
|
344
387
|
format: "json-zed",
|
|
388
|
+
remoteMcp: {
|
|
389
|
+
entry: (url) => ({ url }),
|
|
390
|
+
signIn: (name) => `In Zed, open the agent settings and click Authenticate next to ${name}.`,
|
|
391
|
+
},
|
|
345
392
|
mcp: {
|
|
346
393
|
user: (ctx) => join(xdgOrAppData(ctx), "zed", "settings.json"),
|
|
347
394
|
project: null,
|
|
@@ -356,6 +403,10 @@ const SPECS = [
|
|
|
356
403
|
status: "active",
|
|
357
404
|
envOverride: "SUMMER_KIRO_CONFIG_FILE",
|
|
358
405
|
format: "json",
|
|
406
|
+
remoteMcp: {
|
|
407
|
+
entry: (url) => ({ url }),
|
|
408
|
+
signIn: (name) => `Kiro opens summer.games to sign in when ${name} connects (Kiro CLI: /mcp auth).`,
|
|
409
|
+
},
|
|
359
410
|
mcp: { user: home(".kiro", "settings", "mcp.json"), project: project(".kiro", "settings", "mcp.json") },
|
|
360
411
|
restart: "Kiro reloads MCP config on save; open the MCP Servers view to confirm summer-engine is connected.",
|
|
361
412
|
skills: skillDirs(home(".kiro", "skills"), project(".kiro", "skills")),
|
|
@@ -367,6 +418,19 @@ const SPECS = [
|
|
|
367
418
|
status: "active",
|
|
368
419
|
envOverride: "SUMMER_GOOSE_CONFIG_FILE",
|
|
369
420
|
format: "yaml-goose",
|
|
421
|
+
remoteMcp: {
|
|
422
|
+
entry: (url) => ({
|
|
423
|
+
type: "streamable_http",
|
|
424
|
+
name: "summer-games",
|
|
425
|
+
description: "Summer Games: friends, parties and messages as you",
|
|
426
|
+
uri: url,
|
|
427
|
+
enabled: true,
|
|
428
|
+
timeout: 300,
|
|
429
|
+
env_keys: [],
|
|
430
|
+
envs: {},
|
|
431
|
+
}),
|
|
432
|
+
signIn: (name) => `Goose opens summer.games to sign in when the ${name} extension starts.`,
|
|
433
|
+
},
|
|
370
434
|
mcp: {
|
|
371
435
|
user: (ctx) => ctx.os === "win32"
|
|
372
436
|
? join(appData(ctx), "Block", "goose", "config", "config.yaml")
|
|
@@ -383,6 +447,10 @@ const SPECS = [
|
|
|
383
447
|
status: "active",
|
|
384
448
|
envOverride: "SUMMER_HERMES_CONFIG_FILE",
|
|
385
449
|
format: "yaml-hermes",
|
|
450
|
+
remoteMcp: {
|
|
451
|
+
entry: (url) => ({ url, auth: "oauth" }),
|
|
452
|
+
signIn: (name) => `Run \`hermes mcp login ${name}\`, or sign in on summer.games when Hermes first connects.`,
|
|
453
|
+
},
|
|
386
454
|
mcp: { user: home(".hermes", "config.yaml"), project: null },
|
|
387
455
|
restart: "Run /reload-mcp in Hermes Agent (or restart it).",
|
|
388
456
|
skills: skillDirs(home(".hermes", "skills"), SHARED_SKILLS_PROJECT, {
|
|
@@ -397,6 +465,10 @@ const SPECS = [
|
|
|
397
465
|
status: "active",
|
|
398
466
|
envOverride: "SUMMER_TRAE_CONFIG_FILE",
|
|
399
467
|
format: "json",
|
|
468
|
+
remoteMcp: {
|
|
469
|
+
entry: (url) => ({ url }),
|
|
470
|
+
signIn: (name) => `Trae opens summer.games to sign in when ${name} connects.`,
|
|
471
|
+
},
|
|
400
472
|
mcp: {
|
|
401
473
|
user: null,
|
|
402
474
|
project: project(".trae", "mcp.json"),
|
|
@@ -413,6 +485,10 @@ const SPECS = [
|
|
|
413
485
|
status: "active",
|
|
414
486
|
envOverride: "SUMMER_QWEN_CODE_CONFIG_FILE",
|
|
415
487
|
format: "json",
|
|
488
|
+
remoteMcp: {
|
|
489
|
+
entry: (url) => ({ httpUrl: url }),
|
|
490
|
+
signIn: (name) => `In Qwen Code, run /mcp auth ${name} and sign in.`,
|
|
491
|
+
},
|
|
416
492
|
mcp: { user: home(".qwen", "settings.json"), project: project(".qwen", "settings.json") },
|
|
417
493
|
restart: "Restart Qwen Code or run /mcp in a new session.",
|
|
418
494
|
skills: skillDirs(home(".qwen", "skills"), project(".qwen", "skills")),
|
|
@@ -424,6 +500,10 @@ const SPECS = [
|
|
|
424
500
|
status: "active",
|
|
425
501
|
envOverride: "SUMMER_KIMI_CODE_CONFIG_FILE",
|
|
426
502
|
format: "json",
|
|
503
|
+
remoteMcp: {
|
|
504
|
+
entry: (url) => ({ url, auth: "oauth" }),
|
|
505
|
+
signIn: (name) => `Run \`kimi mcp auth ${name}\`; it opens summer.games to sign in.`,
|
|
506
|
+
},
|
|
427
507
|
mcp: { user: home(".kimi-code", "mcp.json"), project: project(".kimi-code", "mcp.json") },
|
|
428
508
|
restart: "Restart Kimi Code CLI so it reconnects its MCP servers.",
|
|
429
509
|
skills: sharedSkills({ legacyDirs: { user: home(".kimi-code", "skills"), project: project(".kimi-code", "skills") } }),
|
|
@@ -435,6 +515,10 @@ const SPECS = [
|
|
|
435
515
|
status: "active",
|
|
436
516
|
envOverride: "SUMMER_CRUSH_CONFIG_FILE",
|
|
437
517
|
format: "json-crush",
|
|
518
|
+
remoteMcp: {
|
|
519
|
+
entry: (url) => ({ type: "http", url, oauth: true }),
|
|
520
|
+
signIn: (name) => `Crush opens summer.games to sign in when ${name} connects.`,
|
|
521
|
+
},
|
|
438
522
|
mcp: {
|
|
439
523
|
user: home(".config", "crush", "crushrc"),
|
|
440
524
|
project: project(".crushrc"),
|
|
@@ -449,6 +533,10 @@ const SPECS = [
|
|
|
449
533
|
status: "active",
|
|
450
534
|
envOverride: "SUMMER_AMP_CONFIG_FILE",
|
|
451
535
|
format: "json-amp",
|
|
536
|
+
remoteMcp: {
|
|
537
|
+
entry: (url) => ({ url }),
|
|
538
|
+
signIn: (name) => `Amp opens summer.games to sign in for ${name} when it starts.`,
|
|
539
|
+
},
|
|
452
540
|
mcp: { user: (ctx) => join(xdgOrAppData(ctx), "amp", "settings.json"), project: null },
|
|
453
541
|
restart: "Restart Amp so it reloads settings.json.",
|
|
454
542
|
skills: sharedSkills({ legacyDirs: { user: (ctx) => join(xdgOrAppData(ctx), "amp", "skills"), project: null } }),
|
|
@@ -460,6 +548,10 @@ const SPECS = [
|
|
|
460
548
|
status: "active",
|
|
461
549
|
envOverride: "SUMMER_FACTORY_CONFIG_FILE",
|
|
462
550
|
format: "json-stdio",
|
|
551
|
+
remoteMcp: {
|
|
552
|
+
entry: (url) => ({ type: "http", url }),
|
|
553
|
+
signIn: (name) => `In Droid, run /mcp, choose ${name} and Authenticate.`,
|
|
554
|
+
},
|
|
463
555
|
mcp: { user: home(".factory", "mcp.json"), project: project(".factory", "mcp.json") },
|
|
464
556
|
restart: "Restart droid or run /mcp in the active session.",
|
|
465
557
|
skills: sharedSkills({ legacyDirs: { user: home(".factory", "skills"), project: project(".factory", "skills") } }),
|
|
@@ -471,6 +563,10 @@ const SPECS = [
|
|
|
471
563
|
status: "active",
|
|
472
564
|
envOverride: "SUMMER_JUNIE_CONFIG_FILE",
|
|
473
565
|
format: "json",
|
|
566
|
+
remoteMcp: {
|
|
567
|
+
entry: (url) => ({ url }),
|
|
568
|
+
signIn: (name) => `In Junie, run /mcp, open ${name} and choose Authorize.`,
|
|
569
|
+
},
|
|
474
570
|
mcp: { user: home(".junie", "mcp", "mcp.json"), project: project(".junie", "mcp", "mcp.json") },
|
|
475
571
|
restart: "Restart the JetBrains IDE so Junie reloads its MCP config.",
|
|
476
572
|
skills: null,
|
|
@@ -483,6 +579,10 @@ const SPECS = [
|
|
|
483
579
|
status: "active",
|
|
484
580
|
envOverride: "SUMMER_WARP_CONFIG_FILE",
|
|
485
581
|
format: "json",
|
|
582
|
+
remoteMcp: {
|
|
583
|
+
entry: (url) => ({ url }),
|
|
584
|
+
signIn: (name) => `Warp opens summer.games to sign in when ${name} starts.`,
|
|
585
|
+
},
|
|
486
586
|
mcp: { user: home(".warp", ".mcp.json"), project: project(".warp", ".mcp.json") },
|
|
487
587
|
restart: "Warp detects the file and spawns the server; check Settings > AI > MCP servers.",
|
|
488
588
|
skills: sharedSkills({ legacyDirs: { user: home(".warp", "skills"), project: project(".warp", "skills") } }),
|
|
@@ -494,6 +594,7 @@ const SPECS = [
|
|
|
494
594
|
status: "active",
|
|
495
595
|
envOverride: "SUMMER_ROVO_DEV_CONFIG_FILE",
|
|
496
596
|
format: "json-transport",
|
|
597
|
+
// No Summer Games entry: Rovo Dev CLI has no OAuth sign-in for remote MCP servers (headers only).
|
|
497
598
|
mcp: { user: home(".rovodev", "mcp.json"), project: null },
|
|
498
599
|
restart: "Restart Rovo Dev CLI so it reconnects its MCP servers.",
|
|
499
600
|
skills: sharedSkills({ legacyDirs: { user: home(".rovodev", "skills"), project: project(".rovodev", "skills") } }),
|
|
@@ -505,6 +606,7 @@ const SPECS = [
|
|
|
505
606
|
status: "active",
|
|
506
607
|
envOverride: "SUMMER_QODER_CONFIG_FILE",
|
|
507
608
|
format: "json",
|
|
609
|
+
// No Summer Games entry: Qoder's remote-server fields in settings.json are not documented.
|
|
508
610
|
mcp: { user: home(".qoder", "settings.json"), project: project(".mcp.json") },
|
|
509
611
|
restart: "Restart Qoder CLI so it reloads its MCP settings (the Qoder IDE manages servers in its UI).",
|
|
510
612
|
skills: skillDirs(home(".qoder", "skills"), project(".qoder", "skills")),
|
|
@@ -516,6 +618,10 @@ const SPECS = [
|
|
|
516
618
|
status: "active",
|
|
517
619
|
envOverride: "SUMMER_GROK_BUILD_CONFIG_FILE",
|
|
518
620
|
format: "toml",
|
|
621
|
+
remoteMcp: {
|
|
622
|
+
entry: (url) => ({ url }),
|
|
623
|
+
signIn: (name) => `In Grok Build, run /mcps, select ${name} and press i to sign in.`,
|
|
624
|
+
},
|
|
519
625
|
mcp: { user: home(".grok", "config.toml"), project: project(".grok", "config.toml") },
|
|
520
626
|
restart: "Restart Grok Build so it reloads config.toml (it also reads ~/.claude.json and .cursor/mcp.json).",
|
|
521
627
|
skills: sharedSkills({ legacyDirs: { user: home(".grok", "skills"), project: project(".grok", "skills") } }),
|
|
@@ -527,6 +633,10 @@ const SPECS = [
|
|
|
527
633
|
status: "active",
|
|
528
634
|
envOverride: "SUMMER_MISTRAL_VIBE_CONFIG_FILE",
|
|
529
635
|
format: "toml-array",
|
|
636
|
+
remoteMcp: {
|
|
637
|
+
entry: (url) => ({ name: "summer-games", transport: "streamable-http", url, auth: { type: "oauth", scopes: [] } }),
|
|
638
|
+
signIn: (name) => `In Vibe, run /mcp login ${name}.`,
|
|
639
|
+
},
|
|
530
640
|
mcp: { user: home(".vibe", "config.toml"), project: project(".vibe", "config.toml") },
|
|
531
641
|
restart: "Restart Vibe so it reloads config.toml.",
|
|
532
642
|
skills: skillDirs(home(".vibe", "skills"), SHARED_SKILLS_PROJECT, { legacyDirs: { user: home(".vibe", "skills"), project: project(".vibe", "skills") } }),
|
|
@@ -538,6 +648,7 @@ const SPECS = [
|
|
|
538
648
|
status: "active",
|
|
539
649
|
envOverride: "SUMMER_LM_STUDIO_CONFIG_FILE",
|
|
540
650
|
format: "json",
|
|
651
|
+
// No Summer Games entry: LM Studio's MCP client registration is closed and unverified.
|
|
541
652
|
mcp: { user: home(".lmstudio", "mcp.json"), project: null },
|
|
542
653
|
restart: "Open LM Studio, toggle on the summer-engine MCP server in the Program tab, and raise the loaded model's context length to 32k or higher.",
|
|
543
654
|
skills: null,
|
package/gemini-extension.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_generated": "GENERATED from integrations/gemini — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.1",
|
|
5
5
|
"description": "Agent tooling for Summer Engine: MCP bridge, context primer, and game-dev skills. Use with the npm CLI for skill files on disk.",
|
|
6
6
|
"contextFileName": "GEMINI.md",
|
|
7
7
|
"mcpServers": {
|
package/integrations/README.md
CHANGED
|
@@ -24,6 +24,12 @@ never sits beside project-scope skills. `--scope project` moves both;
|
|
|
24
24
|
`--recommended` installs only the recommended subset. Clients whose MCP config
|
|
25
25
|
is user-only fall back to user scope with a warning.
|
|
26
26
|
|
|
27
|
+
For every client with `remoteMcp` in `agent-table.ts`, setup also writes the
|
|
28
|
+
remote `summer-games` server (`https://mcp.summer.games/mcp`) into the same
|
|
29
|
+
file, in that client's entry shape, and prints its one sign-in step. A client
|
|
30
|
+
gets `remoteMcp` only after its OAuth redirect is checked against what
|
|
31
|
+
api.summer.games accepts; the table comments name why the rest have none.
|
|
32
|
+
|
|
27
33
|
Generated root files (`.claude-plugin/plugin.json`, `gemini-extension.json`,
|
|
28
34
|
`.mcp.json`, …) are build artifacts of `integrations/<agent>` + `library/`.
|
|
29
35
|
Their `_generated` banner says so. CI `--check` fails on any drift between
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "summer-engine",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.1",
|
|
4
4
|
"description": "Local Summer CLI and MCP server for Summer Engine. Install and run the engine, connect Claude Code, Cursor, Codex, Gemini, and other agents, and build real games with bundled skills, hooks, and plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"summer-engine",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_generated": "GENERATED from integrations/gemini — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.1",
|
|
5
5
|
"description": "Agent tooling for Summer Engine: MCP bridge, context primer, and game-dev skills. Use with the npm CLI for skill files on disk.",
|
|
6
6
|
"contextFileName": "GEMINI.md",
|
|
7
7
|
"mcpServers": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
{
|
|
12
12
|
"name": "summer",
|
|
13
13
|
"source": "./",
|
|
14
|
-
"version": "3.5.
|
|
14
|
+
"version": "3.5.1",
|
|
15
15
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Summer Engine",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"_generated": "GENERATED from integrations/claude — do not edit; npm run generate:registry",
|
|
4
4
|
"name": "summer",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.1",
|
|
6
6
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Summer Engine",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_generated": "GENERATED from integrations/codex — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.1",
|
|
5
5
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge. Build games by talking.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Summer Engine",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"_generated": "GENERATED from integrations/cursor — do not edit; npm run generate:registry",
|
|
4
4
|
"name": "summer",
|
|
5
5
|
"displayName": "Summer",
|
|
6
|
-
"version": "3.5.
|
|
6
|
+
"version": "3.5.1",
|
|
7
7
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Summer Engine",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"_generated": "GENERATED from integrations/factory — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
4
|
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 105-tool MCP bridge to the local desktop app.",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Summer Engine",
|
|
8
8
|
"email": "founders@summerengine.com",
|