summer-engine 3.6.0 → 3.7.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +3 -3
- package/.cursor-plugin/plugin.json +2 -2
- package/.factory-plugin/plugin.json +2 -2
- package/CHANGELOG.md +8 -0
- package/README.md +0 -4
- package/dist/cli/commands/login.d.ts +0 -10
- package/dist/cli/commands/login.js +2 -82
- package/dist/cli/index.js +0 -4
- package/dist/core/auth.d.ts +0 -8
- package/dist/core/auth.js +5 -35
- package/dist/core/capabilities/seeing/args.d.ts +2 -2
- package/dist/core/capabilities/seeing/seeing.d.ts +1 -1
- package/dist/core/capabilities/sfx-choices.d.ts +2 -15
- package/dist/core/capabilities/sfx-choices.js +26 -64
- package/dist/core/capabilities/tool-dispatch.js +2 -54
- package/dist/core/config.d.ts +1 -7
- package/dist/core/config.js +5 -75
- package/dist/mcp/server.d.ts +2 -1
- package/dist/mcp/server.js +6 -5
- package/dist/mcp/tools/creator-tools.js +0 -71
- package/dist/mcp/tools/generate-tools.js +3 -4
- package/gemini-extension.json +1 -1
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +2 -5
- package/library/skills/publish-your-game/SKILL.md +2 -0
- package/library/tools/generate-sfx-choices/resource.yaml +2 -2
- package/package.json +1 -1
- package/registry/generated/aliases.json +0 -3
- package/registry/generated/counts.json +2 -2
- package/registry/generated/gemini-extension.json +1 -1
- package/registry/generated/index.json +4 -107
- package/registry/generated/marketplace.claude.json +2 -2
- package/registry/generated/plugin.claude.json +2 -2
- package/registry/generated/plugin.codex.json +3 -3
- package/registry/generated/plugin.cursor.json +2 -2
- package/registry/generated/plugin.factory.json +2 -2
- package/dist/cli/commands/publish.d.ts +0 -2
- package/dist/cli/commands/publish.js +0 -21
- package/dist/cli/commands/releases.d.ts +0 -2
- package/dist/cli/commands/releases.js +0 -20
- package/dist/core/capabilities/creator.d.ts +0 -65
- package/dist/core/capabilities/creator.js +0 -374
- package/library/tools/creator-config/resource.yaml +0 -63
- package/library/tools/creator-publish/resource.yaml +0 -74
- package/library/tools/creator-releases/resource.yaml +0 -53
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
{
|
|
12
12
|
"name": "summer",
|
|
13
13
|
"source": "./",
|
|
14
|
-
"version": "3.
|
|
15
|
-
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a
|
|
14
|
+
"version": "3.7.0",
|
|
15
|
+
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 104-tool MCP bridge to the local desktop app.",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Summer Engine",
|
|
18
18
|
"email": "founders@summerengine.com"
|
|
@@ -2,8 +2,8 @@
|
|
|
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.
|
|
6
|
-
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a
|
|
5
|
+
"version": "3.7.0",
|
|
6
|
+
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 104-tool MCP bridge to the local desktop app.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Summer Engine",
|
|
9
9
|
"email": "founders@summerengine.com",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_generated": "GENERATED from integrations/codex — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
|
-
"version": "3.
|
|
5
|
-
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a
|
|
4
|
+
"version": "3.7.0",
|
|
5
|
+
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 104-tool MCP bridge. Build games by talking.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Summer Engine",
|
|
8
8
|
"email": "founders@summerengine.com",
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
"interface": {
|
|
152
152
|
"displayName": "Summer",
|
|
153
153
|
"shortDescription": "Superpowers for AI game dev. Build games by talking.",
|
|
154
|
-
"longDescription": "Summer turns Codex into a game-dev studio for Summer Engine. Users make Summer games with the Summer SDK and GDScript. The plugin adds game-dev skills, lifecycle hooks, and a
|
|
154
|
+
"longDescription": "Summer turns Codex into a game-dev studio for Summer Engine. Users make Summer games with the Summer SDK and GDScript. The plugin adds game-dev skills, lifecycle hooks, and a 104-tool MCP bridge for guarded project files, scene editing, asset import, play mode, diagnostics, generation, and creator workflows. Git, shell, and grep stay with the host agent. Summer follows its upstream technical base continuously; version-sensitive work uses the bundled compatibility reference instead of a fixed onboarding version. Session-start orients the session. Pre-commit doctor (opt-in) blocks bad commits.",
|
|
155
155
|
"developerName": "Summer Engine",
|
|
156
156
|
"category": "Coding",
|
|
157
157
|
"capabilities": [
|
|
@@ -3,8 +3,8 @@
|
|
|
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.
|
|
7
|
-
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a
|
|
6
|
+
"version": "3.7.0",
|
|
7
|
+
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 104-tool MCP bridge to the local desktop app.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Summer Engine",
|
|
10
10
|
"email": "founders@summerengine.com"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_generated": "GENERATED from integrations/factory — do not edit; npm run generate:registry",
|
|
3
3
|
"name": "summer",
|
|
4
|
-
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a
|
|
5
|
-
"version": "3.
|
|
4
|
+
"description": "Agent tooling for Summer Engine: game-dev skills, lifecycle hooks, and a 104-tool MCP bridge to the local desktop app.",
|
|
5
|
+
"version": "3.7.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Summer Engine",
|
|
8
8
|
"email": "founders@summerengine.com",
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to summer-engine will be documented here. Following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [3.7.0] - 2026-10-13
|
|
6
|
+
|
|
7
|
+
Sound-effect choices open in your Studio tab right away, agents act on Summer's review feedback, and the legacy creator path is gone.
|
|
8
|
+
|
|
9
|
+
- `summer_generate_sfx_choices` no longer waits 20 s and then reports `studio_tab_timeout` before it opens the page. Summer now sends the choices page to your open Summer Studio tab as it makes the versions, and the tool reads that answer: when your tab took it, no browser opens; when no tab is open, it opens your browser as before. Signing in to the store is no longer needed for the tab to open.
|
|
10
|
+
- **Removed the legacy Summercraft creator path.** The deprecated `summer_creator_publish`, `summer_creator_releases` and `summer_creator_config` MCP tools (and their `summer tool` slugs and library entries), the `summer publish` and `summer releases` commands, `summer login --creator` and the `creator.apiUrl`, `creator.projectId` and `creator.channel` config keys are gone. Publish to summer.games with `summer_export_game`, then `summer_publish_build`, then the hosted `summer_store_submit` and `summer_store_review`. `gateway.url` stays settable with `summer config`; `summer logout` still removes a `~/.summer/creator-token` an older CLI left behind.
|
|
11
|
+
- **Agents read Summer's review feedback and resubmit.** When Summer staff ask for changes to a submitted game, or do not approve it, they can now write feedback for the creator. The hosted `summer_store_review` tool returns the decision, that feedback and the next step; `publish-your-game` and the MCP instructions tell the agent to fix what the feedback names and call `summer_store_submit` again, and never to call the game live before Summer approves it.
|
|
12
|
+
|
|
5
13
|
## [3.6.0] - 2026-10-12
|
|
6
14
|
|
|
7
15
|
Pick your sound effects by ear, and hosted games: agents check that players can actually join before a release.
|
package/README.md
CHANGED
|
@@ -322,7 +322,6 @@ We tell you before we touch your disk.
|
|
|
322
322
|
| `summer-engine` npm package (CLI + MCP + library) | ~2 MB download, ~6 MB unpacked | first `npx -y summer-engine@latest ...` call | [npmjs.com/package/summer-engine](https://www.npmjs.com/package/summer-engine) |
|
|
323
323
|
| Summer Engine app | ~1 GB (engine + bundled Git/runtime tools) | `npx -y summer-engine@latest install` | Summer's signed releases |
|
|
324
324
|
| Auth token | ~1 KB | `npx -y summer-engine@latest login` | Browser to `~/.summer/auth-token` |
|
|
325
|
-
| Creator token | ~50 bytes | only when you run `summer login --creator` and mint one | One-time browser value to `~/.summer/creator-token`; never replaces the auth token |
|
|
326
325
|
| Store sign-in | ~2 KB | only when you run `summer login --store` | Browser OAuth (PKCE, loopback port 47615-47617) to `~/.summer/oauth-token` with its refresh token, plus this machine's public client id in `~/.summer/oauth-client`; never replaces the auth token |
|
|
327
326
|
| Skill files | small, bundled | in the npm package | no extra network call |
|
|
328
327
|
| Generated assets (3D / image / audio / video) | varies | only on explicit `summer_generate_*` calls when that provider route is enabled for the account | Summer Engine Studio |
|
|
@@ -352,11 +351,8 @@ matchmaking are not promised by this package.
|
|
|
352
351
|
| `summer install [--yes]` | Download Summer Engine. Prints URL and size first; never replaces an installed engine without confirmation. |
|
|
353
352
|
| `summer login` | Browser-based core Summer sign-in. |
|
|
354
353
|
| `summer login --store` | Browser sign-in to the Summer store so agents can upload builds (`summer_publish_build`). |
|
|
355
|
-
| `summer login --creator` | Deprecated: connect a creator token for the legacy `summer publish`. |
|
|
356
354
|
| `summer logout` | Clear auth tokens. |
|
|
357
355
|
| `summer config [get\|set\|unset]` | Read or update the shared non-secret `~/.summer/config.json`. |
|
|
358
|
-
| `summer publish [project] --artifact <game.pck> --version <value> [--confirm]` | Deprecated: use `summer tool export-game`, then `summer tool publish-build`. |
|
|
359
|
-
| `summer releases [--cursor <value>]` | List your creator release history. |
|
|
360
356
|
| `summer status` | Engine state, port, auth. |
|
|
361
357
|
| `summer doctor` | Diagnose Node, login, engine, project memory, MCP. |
|
|
362
358
|
| `summer plan <goal>` | Route a game-building goal into skills, MCP tools, gates, and verification. |
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
export declare const loginCommand: Command;
|
|
3
|
-
export interface CreatorLoginDependencies {
|
|
4
|
-
openUrl: (url: string) => Promise<unknown>;
|
|
5
|
-
readSecret: (prompt: string) => Promise<string>;
|
|
6
|
-
log: (message: string) => void;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* The browser session mints the token; the token is pasted once into a hidden
|
|
10
|
-
* prompt. This deliberately does not replace the core Summer login JWT.
|
|
11
|
-
*/
|
|
12
|
-
export declare function runCreatorLogin(overrides?: Partial<CreatorLoginDependencies>): Promise<void>;
|
|
13
3
|
export interface LoginDependencies {
|
|
14
4
|
fetch: typeof fetch;
|
|
15
5
|
openUrl: (url: string) => Promise<unknown>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { randomUUID } from "crypto";
|
|
3
3
|
import open from "open";
|
|
4
|
-
import { getAuthToken,
|
|
5
|
-
import {
|
|
4
|
+
import { getAuthToken, saveLoginSession, } from "../../core/auth.js";
|
|
5
|
+
import { resolveGatewayUrl } from "../../core/config.js";
|
|
6
6
|
import { readStoredOAuthToken, runStoreLogin } from "../../core/oauth.js";
|
|
7
7
|
const POLL_INTERVAL_MS = 2000;
|
|
8
8
|
// One generous window on ONE session id. First-time users may need to create an
|
|
@@ -14,7 +14,6 @@ const POLL_TIMEOUT_MS = 900000;
|
|
|
14
14
|
const HEARTBEAT_MS = 30000;
|
|
15
15
|
export const loginCommand = new Command("login")
|
|
16
16
|
.description("Sign in to Summer Engine via your browser")
|
|
17
|
-
.option("--creator", "Connect a separately scoped Summercraft creator token for publishing")
|
|
18
17
|
.option("--store", "Sign in to the Summer store so agents can upload builds (summer_publish_build)")
|
|
19
18
|
.option("--force", "Force re-authentication even if already logged in")
|
|
20
19
|
.action(async (opts) => {
|
|
@@ -28,15 +27,6 @@ export const loginCommand = new Command("login")
|
|
|
28
27
|
console.log("Signed in to the Summer store. Your core Summer login was not changed.");
|
|
29
28
|
return;
|
|
30
29
|
}
|
|
31
|
-
if (opts.creator) {
|
|
32
|
-
const existingCreator = await getCreatorToken();
|
|
33
|
-
if (existingCreator && !opts.force) {
|
|
34
|
-
console.log("A creator token is already connected. Use --creator --force to replace it.");
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
await runCreatorLogin();
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
30
|
const existing = await getAuthToken();
|
|
41
31
|
if (existing && !opts.force) {
|
|
42
32
|
console.log("Already logged in. Use --force to re-authenticate.");
|
|
@@ -44,76 +34,6 @@ export const loginCommand = new Command("login")
|
|
|
44
34
|
}
|
|
45
35
|
await runLogin();
|
|
46
36
|
});
|
|
47
|
-
async function readHiddenLine(prompt) {
|
|
48
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
49
|
-
process.stdout.write(prompt);
|
|
50
|
-
let value = "";
|
|
51
|
-
for await (const chunk of process.stdin)
|
|
52
|
-
value += String(chunk);
|
|
53
|
-
return value.trim();
|
|
54
|
-
}
|
|
55
|
-
process.stdout.write(prompt);
|
|
56
|
-
const input = process.stdin;
|
|
57
|
-
const wasRaw = input.isRaw;
|
|
58
|
-
input.setRawMode(true);
|
|
59
|
-
input.resume();
|
|
60
|
-
return new Promise((resolve, reject) => {
|
|
61
|
-
let value = "";
|
|
62
|
-
const finish = (error) => {
|
|
63
|
-
input.off("data", onData);
|
|
64
|
-
input.setRawMode(Boolean(wasRaw));
|
|
65
|
-
input.pause();
|
|
66
|
-
process.stdout.write("\n");
|
|
67
|
-
if (error)
|
|
68
|
-
reject(error);
|
|
69
|
-
else
|
|
70
|
-
resolve(value.trim());
|
|
71
|
-
};
|
|
72
|
-
const onData = (chunk) => {
|
|
73
|
-
for (const char of String(chunk)) {
|
|
74
|
-
if (char === "\u0003") {
|
|
75
|
-
finish(new Error("Creator token entry cancelled."));
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (char === "\r" || char === "\n" || char === "\u0004") {
|
|
79
|
-
finish();
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (char === "\u007f" || char === "\b") {
|
|
83
|
-
value = value.slice(0, -1);
|
|
84
|
-
}
|
|
85
|
-
else if (char >= " ") {
|
|
86
|
-
value += char;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
input.on("data", onData);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
const defaultCreatorLoginDependencies = {
|
|
94
|
-
openUrl: open,
|
|
95
|
-
readSecret: readHiddenLine,
|
|
96
|
-
log: console.log,
|
|
97
|
-
};
|
|
98
|
-
/**
|
|
99
|
-
* The browser session mints the token; the token is pasted once into a hidden
|
|
100
|
-
* prompt. This deliberately does not replace the core Summer login JWT.
|
|
101
|
-
*/
|
|
102
|
-
export async function runCreatorLogin(overrides = {}) {
|
|
103
|
-
const deps = { ...defaultCreatorLoginDependencies, ...overrides };
|
|
104
|
-
const settingsUrl = `${await getCreatorApiUrl()}/creator/settings/tokens`;
|
|
105
|
-
deps.log(`Opening creator token settings: ${settingsUrl}`);
|
|
106
|
-
deps.log('Mint a token with the exact "publish" scope, copy its one-time sc_ value, then return here.');
|
|
107
|
-
try {
|
|
108
|
-
await deps.openUrl(settingsUrl);
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
deps.log("Could not open the browser. Copy the URL above and open it manually.");
|
|
112
|
-
}
|
|
113
|
-
const token = await deps.readSecret("Creator token (input hidden): ");
|
|
114
|
-
await saveCreatorToken(token);
|
|
115
|
-
deps.log("Creator publishing connected. Your core Summer login token was not changed.");
|
|
116
|
-
}
|
|
117
37
|
/** The gateway answered with a terminal 4xx — retrying the same URL cannot help. */
|
|
118
38
|
class LoginRejectedError extends Error {
|
|
119
39
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -14,8 +14,6 @@ import { doctorCommand } from "./commands/doctor.js";
|
|
|
14
14
|
import { planCommand } from "./commands/plan.js";
|
|
15
15
|
import { debugCommand } from "./commands/debug.js";
|
|
16
16
|
import { configCommand } from "./commands/config.js";
|
|
17
|
-
import { publishCommand } from "./commands/publish.js";
|
|
18
|
-
import { releasesCommand } from "./commands/releases.js";
|
|
19
17
|
import { eventsCommand } from "./commands/events.js";
|
|
20
18
|
import { toolCommand } from "./commands/tool.js";
|
|
21
19
|
import { getBanner } from "./banner.js";
|
|
@@ -51,8 +49,6 @@ export function runCli(mcpCommand) {
|
|
|
51
49
|
program.addCommand(debugCommand);
|
|
52
50
|
program.addCommand(planCommand);
|
|
53
51
|
program.addCommand(configCommand);
|
|
54
|
-
program.addCommand(publishCommand);
|
|
55
|
-
program.addCommand(releasesCommand);
|
|
56
52
|
program.addCommand(eventsCommand);
|
|
57
53
|
program.addCommand(toolCommand);
|
|
58
54
|
program.parseAsync().catch((err) => {
|
package/dist/core/auth.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ export interface CredentialMetadata {
|
|
|
14
14
|
interface CredentialMetadataDocument {
|
|
15
15
|
schemaVersion: 1;
|
|
16
16
|
auth?: CredentialMetadata;
|
|
17
|
-
creator?: CredentialMetadata;
|
|
18
17
|
}
|
|
19
18
|
export interface LoginSession {
|
|
20
19
|
token: string;
|
|
@@ -37,13 +36,6 @@ export declare function getAuthToken(): Promise<string | null>;
|
|
|
37
36
|
*/
|
|
38
37
|
export declare function hasEnvAuthToken(): boolean;
|
|
39
38
|
export declare function saveAuthToken(token: string, scopes?: string[]): Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
* Summercraft creator tokens are a separate credential audience from the
|
|
42
|
-
* core-compatible Summer CLI JWT. Never store an sc_ token in auth-token:
|
|
43
|
-
* the engine reads that file and expects the summer-cli JWT contract.
|
|
44
|
-
*/
|
|
45
|
-
export declare function getCreatorToken(): Promise<string | null>;
|
|
46
|
-
export declare function saveCreatorToken(token: string): Promise<void>;
|
|
47
39
|
export declare function getUserInfo(): Promise<SummerUserInfo | null>;
|
|
48
40
|
export declare function saveUserInfo(info: SummerUserInfo): Promise<void>;
|
|
49
41
|
export declare function saveLoginSession(session: LoginSession): Promise<void>;
|
package/dist/core/auth.js
CHANGED
|
@@ -3,7 +3,8 @@ export { getSummerDir } from "./store.js";
|
|
|
3
3
|
const AUTH_TOKEN_FILE = "auth-token";
|
|
4
4
|
/** Written by v2 `summer login` for the removed Summer Cloud sync. Only ever removed now (logout). */
|
|
5
5
|
const LEGACY_CLOUD_TOKEN_FILE = "cloud-token";
|
|
6
|
-
|
|
6
|
+
/** Written by the removed `summer login --creator` (Summercraft). Only ever removed now (logout). */
|
|
7
|
+
const LEGACY_CREATOR_TOKEN_FILE = "creator-token";
|
|
7
8
|
const USER_FILE = "user.json";
|
|
8
9
|
const METADATA_FILE = "credential-metadata.json";
|
|
9
10
|
/** The Summer store OAuth token (core/oauth.ts OAUTH_TOKEN_FILE). */
|
|
@@ -78,8 +79,8 @@ async function updateMetadata(kind, value, current) {
|
|
|
78
79
|
};
|
|
79
80
|
if (!next.auth)
|
|
80
81
|
delete next.auth;
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
// Drop the removed Summercraft creator entry left by older CLIs.
|
|
83
|
+
delete next.creator;
|
|
83
84
|
await writeStoreJson(METADATA_FILE, next);
|
|
84
85
|
}
|
|
85
86
|
/**
|
|
@@ -115,27 +116,6 @@ export async function saveAuthToken(token, scopes = []) {
|
|
|
115
116
|
await writeStoreText(AUTH_TOKEN_FILE, `${clean}\n`);
|
|
116
117
|
await updateMetadata("auth", decodeJwtMetadata(clean, scopes), metadata);
|
|
117
118
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Summercraft creator tokens are a separate credential audience from the
|
|
120
|
-
* core-compatible Summer CLI JWT. Never store an sc_ token in auth-token:
|
|
121
|
-
* the engine reads that file and expects the summer-cli JWT contract.
|
|
122
|
-
*/
|
|
123
|
-
export async function getCreatorToken() {
|
|
124
|
-
const token = await readStoreText(CREATOR_TOKEN_FILE);
|
|
125
|
-
return token?.trim() || null;
|
|
126
|
-
}
|
|
127
|
-
export async function saveCreatorToken(token) {
|
|
128
|
-
const clean = token.trim();
|
|
129
|
-
if (!/^sc_[A-Za-z0-9_-]{32,}$/.test(clean)) {
|
|
130
|
-
throw new Error('That is not a Summercraft creator API token. Recovery: open /creator/settings/tokens, mint a token with the "publish" scope, and paste the complete one-time sc_ value.');
|
|
131
|
-
}
|
|
132
|
-
await writeStoreText(CREATOR_TOKEN_FILE, `${clean}\n`);
|
|
133
|
-
await updateMetadata("creator", {
|
|
134
|
-
audience: ["summercraft-creator"],
|
|
135
|
-
scopes: ["publish"],
|
|
136
|
-
tokenType: "api",
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
119
|
export async function getUserInfo() {
|
|
140
120
|
return readStoreJson(USER_FILE);
|
|
141
121
|
}
|
|
@@ -173,21 +153,11 @@ export async function saveLoginSession(session) {
|
|
|
173
153
|
export async function getCredentialMetadata() {
|
|
174
154
|
const metadata = await readMetadata();
|
|
175
155
|
const token = await getAuthToken();
|
|
176
|
-
const creatorToken = await getCreatorToken();
|
|
177
156
|
return {
|
|
178
157
|
schemaVersion: 1,
|
|
179
158
|
...(token
|
|
180
159
|
? { auth: metadata.auth ?? decodeJwtMetadata(token) }
|
|
181
160
|
: {}),
|
|
182
|
-
...(creatorToken
|
|
183
|
-
? {
|
|
184
|
-
creator: metadata.creator ?? {
|
|
185
|
-
audience: ["summercraft-creator"],
|
|
186
|
-
scopes: [],
|
|
187
|
-
tokenType: "api",
|
|
188
|
-
},
|
|
189
|
-
}
|
|
190
|
-
: {}),
|
|
191
161
|
};
|
|
192
162
|
}
|
|
193
163
|
export async function clearAuthCredentials() {
|
|
@@ -195,7 +165,7 @@ export async function clearAuthCredentials() {
|
|
|
195
165
|
for (const file of [
|
|
196
166
|
AUTH_TOKEN_FILE,
|
|
197
167
|
LEGACY_CLOUD_TOKEN_FILE,
|
|
198
|
-
|
|
168
|
+
LEGACY_CREATOR_TOKEN_FILE,
|
|
199
169
|
STORE_OAUTH_TOKEN_FILE,
|
|
200
170
|
USER_FILE,
|
|
201
171
|
METADATA_FILE,
|
|
@@ -306,7 +306,7 @@ export declare const frameShotArgsSchema: z.ZodObject<{
|
|
|
306
306
|
render: z.ZodOptional<z.ZodEnum<["sheet", "best", "none"]>>;
|
|
307
307
|
max_size: z.ZodOptional<z.ZodNumber>;
|
|
308
308
|
}, "strict", z.ZodTypeAny, {
|
|
309
|
-
shot: "
|
|
309
|
+
shot: "establishing" | "eye_level" | "low_angle" | "detail" | "corridor";
|
|
310
310
|
spawn?: string | undefined;
|
|
311
311
|
scenePath?: string | undefined;
|
|
312
312
|
fov?: number | undefined;
|
|
@@ -326,7 +326,7 @@ export declare const frameShotArgsSchema: z.ZodObject<{
|
|
|
326
326
|
max_soft_fraction?: number | undefined;
|
|
327
327
|
save_bookmark?: boolean | undefined;
|
|
328
328
|
}, {
|
|
329
|
-
shot: "
|
|
329
|
+
shot: "establishing" | "eye_level" | "low_angle" | "detail" | "corridor";
|
|
330
330
|
spawn?: string | undefined;
|
|
331
331
|
scenePath?: string | undefined;
|
|
332
332
|
fov?: number | undefined;
|
|
@@ -230,4 +230,4 @@ export interface CorridorScanFloor {
|
|
|
230
230
|
}
|
|
231
231
|
export declare function scanFloorText(floor: CorridorScanFloor, subject: Aabb): string;
|
|
232
232
|
export declare function frameShot(client: SeeingClient, args: FrameShotArgs): Promise<SeeingResult>;
|
|
233
|
-
export declare const SHOT_TYPE_DEFAULTS: Record<"
|
|
233
|
+
export declare const SHOT_TYPE_DEFAULTS: Record<"establishing" | "eye_level" | "low_angle" | "detail" | "corridor", import("./candidates.js").ShotDefaults>;
|
|
@@ -7,6 +7,8 @@ import { z } from "zod";
|
|
|
7
7
|
* POST /api/mcp/generate/audio/choices makes the versions and a choice set,
|
|
8
8
|
* the person listens and approves one or more on the Studio page
|
|
9
9
|
* /studio/choices/<id>, and GET /api/mcp/choices/<id> reads the decision.
|
|
10
|
+
* The server queues the page for the person's open Studio tab itself
|
|
11
|
+
* (studioTab.queued); only when no tab took it does this open a browser.
|
|
10
12
|
* An approval makes that model the person's default for later
|
|
11
13
|
* summer_generate_audio sound_effects calls without a modelId.
|
|
12
14
|
*
|
|
@@ -58,17 +60,9 @@ export interface GatewayReply {
|
|
|
58
60
|
error?: string;
|
|
59
61
|
status: number;
|
|
60
62
|
}
|
|
61
|
-
export type StudioOpenOutcome = {
|
|
62
|
-
ok: true;
|
|
63
|
-
} | {
|
|
64
|
-
ok: false;
|
|
65
|
-
reason: string;
|
|
66
|
-
};
|
|
67
63
|
export interface SfxChoicesDeps {
|
|
68
64
|
post(endpoint: string, body: Record<string, unknown>, timeoutMs: number): Promise<GatewayReply>;
|
|
69
65
|
get(endpoint: string, params: URLSearchParams, timeoutMs: number): Promise<GatewayReply>;
|
|
70
|
-
/** Move the person's open Studio tab to a /studio path (reviewUrl: the same page as a full URL). */
|
|
71
|
-
studioOpen(path: string, reviewUrl: string): Promise<StudioOpenOutcome>;
|
|
72
66
|
openUrl(url: string): Promise<unknown>;
|
|
73
67
|
canOpenBrowser(): boolean;
|
|
74
68
|
}
|
|
@@ -77,13 +71,6 @@ export type ShownIn = "studio_tab" | "browser" | "not_opened";
|
|
|
77
71
|
export declare function canOpenReviewUrl(url: string): boolean;
|
|
78
72
|
/** False where a browser launch cannot reach the person: CI, or Linux with no display. */
|
|
79
73
|
export declare function defaultCanOpenBrowser(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
|
|
80
|
-
/**
|
|
81
|
-
* Move the person's open Studio tab through the hosted Summer Engine MCP's
|
|
82
|
-
* summer_studio_open (needs the store sign-in). Only for the production site:
|
|
83
|
-
* the hosted MCP moves tabs on summerengine.com, so a review page on another
|
|
84
|
-
* origin (a preview deploy, local web dev) is opened in the browser instead.
|
|
85
|
-
*/
|
|
86
|
-
export declare function openInStudioTab(path: string, reviewUrl: string): Promise<StudioOpenOutcome>;
|
|
87
74
|
export declare function sfxChoicesRequestBody(args: z.output<typeof sfxChoicesArgsSchema>): Record<string, unknown>;
|
|
88
75
|
export declare function generateSfxChoices(args: z.output<typeof sfxChoicesArgsSchema>, deps: SfxChoicesDeps): Promise<Record<string, unknown>>;
|
|
89
76
|
export declare function choicesEndpoint(choiceSetId: string): string;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { hasStoreSignIn, hostedResultPayload, withHostedMcp } from "../hosted-mcp.js";
|
|
3
|
-
import { resolveMcpResourceUrl } from "../oauth.js";
|
|
4
2
|
/**
|
|
5
3
|
* Sound-effect choices (summer_generate_sfx_choices + summer_get_choices).
|
|
6
4
|
*
|
|
@@ -9,6 +7,8 @@ import { resolveMcpResourceUrl } from "../oauth.js";
|
|
|
9
7
|
* POST /api/mcp/generate/audio/choices makes the versions and a choice set,
|
|
10
8
|
* the person listens and approves one or more on the Studio page
|
|
11
9
|
* /studio/choices/<id>, and GET /api/mcp/choices/<id> reads the decision.
|
|
10
|
+
* The server queues the page for the person's open Studio tab itself
|
|
11
|
+
* (studioTab.queued); only when no tab took it does this open a browser.
|
|
12
12
|
* An approval makes that model the person's default for later
|
|
13
13
|
* summer_generate_audio sound_effects calls without a modelId.
|
|
14
14
|
*
|
|
@@ -22,7 +22,6 @@ export const CHOICES_ENDPOINT_PREFIX = "/api/mcp/choices/";
|
|
|
22
22
|
/** Three models run in parallel on the server; the slowest decides. */
|
|
23
23
|
export const SFX_CHOICES_TIMEOUT_MS = 240_000;
|
|
24
24
|
export const MAX_CHOICES_WAIT_SECONDS = 50;
|
|
25
|
-
const STUDIO_OPEN_TIMEOUT_MS = 20_000;
|
|
26
25
|
export const sfxChoicesArgsSchema = z.object({
|
|
27
26
|
text: z
|
|
28
27
|
.string()
|
|
@@ -48,7 +47,7 @@ export const sfxChoicesArgsSchema = z.object({
|
|
|
48
47
|
open: z
|
|
49
48
|
.boolean()
|
|
50
49
|
.default(true)
|
|
51
|
-
.describe("Show the choices page
|
|
50
|
+
.describe("Show the choices page in the browser when no open Studio tab took it. false: no browser, only return the URL"),
|
|
52
51
|
});
|
|
53
52
|
export const getChoicesArgsSchema = z.object({
|
|
54
53
|
choiceSetId: z.string().min(1).max(200).describe("The choiceSetId from summer_generate_sfx_choices"),
|
|
@@ -90,70 +89,28 @@ export function defaultCanOpenBrowser(env = process.env, platform = process.plat
|
|
|
90
89
|
return false;
|
|
91
90
|
return true;
|
|
92
91
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
let resource;
|
|
103
|
-
try {
|
|
104
|
-
resource = resolveMcpResourceUrl();
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return { ok: false, reason: "hosted_mcp_url_invalid" };
|
|
108
|
-
}
|
|
109
|
-
if (!isSummerHost(hostOf(resource)))
|
|
110
|
-
return { ok: false, reason: "hosted_mcp_not_summerengine_com" };
|
|
111
|
-
if (!(await hasStoreSignIn()))
|
|
112
|
-
return { ok: false, reason: "no_store_sign_in" };
|
|
113
|
-
let timer;
|
|
114
|
-
const timeout = new Promise((resolve) => {
|
|
115
|
-
timer = setTimeout(() => resolve({ ok: false, reason: "studio_tab_timeout" }), STUDIO_OPEN_TIMEOUT_MS);
|
|
116
|
-
timer.unref?.();
|
|
117
|
-
});
|
|
118
|
-
const attempt = (async () => {
|
|
119
|
-
try {
|
|
120
|
-
const result = await withHostedMcp((client) => client.callTool({ name: "summer_studio_open", arguments: { path } }));
|
|
121
|
-
const payload = hostedResultPayload(result);
|
|
122
|
-
if (payload.isError || payload.json?.ok === false) {
|
|
123
|
-
const code = typeof payload.json?.error === "string" ? payload.json.error : "studio_open_failed";
|
|
124
|
-
return { ok: false, reason: code };
|
|
125
|
-
}
|
|
126
|
-
return { ok: true };
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
130
|
-
}
|
|
131
|
-
})();
|
|
132
|
-
try {
|
|
133
|
-
return await Promise.race([attempt, timeout]);
|
|
134
|
-
}
|
|
135
|
-
finally {
|
|
136
|
-
clearTimeout(timer);
|
|
137
|
-
}
|
|
92
|
+
/** The server's studioTab answer: queued for the person's open tab, or why not. Missing on older servers. */
|
|
93
|
+
function studioTabAnswer(value) {
|
|
94
|
+
if (!value || typeof value !== "object")
|
|
95
|
+
return null;
|
|
96
|
+
const record = value;
|
|
97
|
+
return {
|
|
98
|
+
queued: record.queued === true,
|
|
99
|
+
...(typeof record.reason === "string" ? { reason: record.reason } : {}),
|
|
100
|
+
};
|
|
138
101
|
}
|
|
139
|
-
async function showChoicesPage(reviewUrl,
|
|
140
|
-
|
|
141
|
-
if (studioPath) {
|
|
142
|
-
const moved = await deps.studioOpen(studioPath, reviewUrl);
|
|
143
|
-
if (moved.ok)
|
|
144
|
-
return { shown: "studio_tab" };
|
|
145
|
-
studioTab = moved.reason;
|
|
146
|
-
}
|
|
102
|
+
async function showChoicesPage(reviewUrl, studioTab, deps) {
|
|
103
|
+
const notQueued = studioTab ? (studioTab.reason ?? "not_queued") : undefined;
|
|
147
104
|
if (!canOpenReviewUrl(reviewUrl))
|
|
148
|
-
return { shown: "not_opened", studioTab, browser: "not_a_summer_url" };
|
|
105
|
+
return { shown: "not_opened", studioTab: notQueued, browser: "not_a_summer_url" };
|
|
149
106
|
if (!deps.canOpenBrowser())
|
|
150
|
-
return { shown: "not_opened", studioTab, browser: "no_browser_here" };
|
|
107
|
+
return { shown: "not_opened", studioTab: notQueued, browser: "no_browser_here" };
|
|
151
108
|
try {
|
|
152
109
|
await deps.openUrl(reviewUrl);
|
|
153
|
-
return { shown: "browser", studioTab };
|
|
110
|
+
return { shown: "browser", studioTab: notQueued };
|
|
154
111
|
}
|
|
155
112
|
catch (error) {
|
|
156
|
-
return { shown: "not_opened", studioTab, browser: error instanceof Error ? error.message : String(error) };
|
|
113
|
+
return { shown: "not_opened", studioTab: notQueued, browser: error instanceof Error ? error.message : String(error) };
|
|
157
114
|
}
|
|
158
115
|
}
|
|
159
116
|
// ---------------------------------------------------------------------------
|
|
@@ -198,9 +155,14 @@ export async function generateSfxChoices(args, deps) {
|
|
|
198
155
|
hint: "Read failed[] for each model's error. Fix the request (a longer durationSeconds, a plainer description) or call summer_generate_audio with one modelId.",
|
|
199
156
|
};
|
|
200
157
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
158
|
+
// The server queued the Studio-tab open already; that happens even with
|
|
159
|
+
// open:false, so report it rather than hide it.
|
|
160
|
+
const studioTab = studioTabAnswer(data.studioTab);
|
|
161
|
+
const shown = studioTab?.queued
|
|
162
|
+
? { shown: "studio_tab" }
|
|
163
|
+
: args.open
|
|
164
|
+
? await showChoicesPage(reviewUrl, studioTab, deps)
|
|
165
|
+
: { shown: "not_opened", browser: "open_false" };
|
|
204
166
|
const count = clips.length;
|
|
205
167
|
const where = shown.shown === "studio_tab"
|
|
206
168
|
? "I opened them in your Summer Studio tab"
|