summer-engine 3.2.1 → 3.4.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 +4 -2
- package/.codex-plugin/plugin.json +5 -3
- package/.cursor-plugin/plugin.json +4 -2
- package/.factory-plugin/plugin.json +4 -2
- package/CHANGELOG.md +61 -0
- package/README.md +7 -4
- package/assets/api-docs.json.gz +0 -0
- package/dist/cli/commands/install.d.ts +10 -0
- package/dist/cli/commands/install.js +55 -10
- package/dist/cli/commands/login.js +12 -0
- package/dist/cli/commands/publish.js +2 -1
- package/dist/cli/commands/tool.d.ts +7 -0
- package/dist/cli/commands/tool.js +36 -1
- package/dist/core/auth.js +3 -0
- package/dist/core/capabilities/audit/args.d.ts +14 -14
- package/dist/core/capabilities/capture-gameplay.d.ts +69 -0
- package/dist/core/capabilities/capture-gameplay.js +283 -0
- package/dist/core/capabilities/creator.js +1 -1
- package/dist/core/capabilities/doctor.d.ts +9 -1
- package/dist/core/capabilities/doctor.js +47 -4
- package/dist/core/capabilities/engine-run.d.ts +12 -0
- package/dist/core/capabilities/engine-run.js +61 -0
- package/dist/core/capabilities/export-engine-version.d.ts +15 -0
- package/dist/core/capabilities/export-engine-version.js +24 -0
- package/dist/core/capabilities/export-game.d.ts +107 -0
- package/dist/core/capabilities/export-game.js +445 -0
- package/dist/core/capabilities/export-presets.d.ts +50 -0
- package/dist/core/capabilities/export-presets.js +177 -0
- package/dist/core/capabilities/export-templates.d.ts +118 -0
- package/dist/core/capabilities/export-templates.js +291 -0
- package/dist/core/capabilities/image-generation.d.ts +9 -0
- package/dist/core/capabilities/image-generation.js +19 -1
- package/dist/core/capabilities/publish-build.d.ts +77 -0
- package/dist/core/capabilities/publish-build.js +500 -0
- package/dist/core/capabilities/publish-download.d.ts +37 -0
- package/dist/core/capabilities/publish-download.js +168 -0
- package/dist/core/capabilities/runtime-control.d.ts +10 -10
- package/dist/core/capabilities/summer-bundle.d.ts +49 -0
- package/dist/core/capabilities/summer-bundle.js +156 -0
- package/dist/core/capabilities/tool-dispatch.js +43 -1
- package/dist/core/capabilities/ui-control.d.ts +2 -2
- package/dist/core/config.js +2 -2
- package/dist/core/engine-install.d.ts +16 -0
- package/dist/core/engine-install.js +32 -2
- package/dist/core/hosted-mcp.d.ts +115 -0
- package/dist/core/hosted-mcp.js +164 -0
- package/dist/core/launch-posture.d.ts +3 -0
- package/dist/core/launch-posture.js +15 -2
- package/dist/core/library-read.d.ts +2 -2
- package/dist/core/oauth.d.ts +78 -0
- package/dist/core/oauth.js +309 -0
- package/dist/core/util/zip-write.d.ts +18 -0
- package/dist/core/util/zip-write.js +112 -0
- package/dist/core/util/zip.d.ts +22 -0
- package/dist/core/util/zip.js +140 -0
- package/dist/mcp/hosted-mount.d.ts +50 -0
- package/dist/mcp/hosted-mount.js +200 -0
- package/dist/mcp/server.d.ts +2 -1
- package/dist/mcp/server.js +14 -6
- package/dist/mcp/tools/creator-tools.js +64 -1
- package/dist/mcp/tools/generate-tools.js +12 -2
- package/gemini-extension.json +3 -1
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +7 -3
- package/library/skills/README.md +6 -4
- package/library/skills/bounded-engine-runs/SKILL.md +96 -0
- package/library/skills/bounded-engine-runs/resource.yaml +29 -0
- package/library/skills/compatibility-renderer-traps/SKILL.md +78 -0
- package/library/skills/compatibility-renderer-traps/resource.yaml +28 -0
- package/library/skills/concept-art/SKILL.md +2 -2
- package/library/skills/export-and-ship/SKILL.md +4 -0
- package/library/skills/headless-scripting/resource.yaml +1 -0
- package/library/skills/in-game-purchases/SKILL.md +123 -118
- package/library/skills/in-game-purchases/resource.yaml +2 -2
- package/library/skills/multiplayer-publish/SKILL.md +5 -1
- package/library/skills/navigate-summer/SKILL.md +1 -1
- package/library/skills/web-compatibility-look/resource.yaml +1 -0
- package/library/tools/capture-gameplay/resource.yaml +73 -0
- package/library/tools/creator-publish/resource.yaml +4 -3
- package/library/tools/creator-releases/resource.yaml +1 -1
- package/library/tools/export-game/resource.yaml +72 -0
- package/library/tools/export-templates/resource.yaml +63 -0
- package/library/tools/generate-image/resource.yaml +15 -1
- package/library/tools/open/resource.yaml +1 -1
- package/library/tools/publish-build/resource.yaml +78 -0
- package/package.json +1 -1
- package/registry/generated/aliases.json +4 -0
- package/registry/generated/counts.json +3 -3
- package/registry/generated/gemini-extension.json +3 -1
- package/registry/generated/index.json +241 -19
- package/registry/generated/marketplace.claude.json +2 -2
- package/registry/generated/plugin.claude.json +4 -2
- package/registry/generated/plugin.codex.json +5 -3
- package/registry/generated/plugin.cursor.json +4 -2
- package/registry/generated/plugin.factory.json +4 -2
- package/registry/generated/skills-index.md +6 -4
- package/registry/generated/skills-registry.json +28 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
/** The part of an MCP client the mount and the CLI use (a fake in tests). */
|
|
3
|
+
export interface HostedClient {
|
|
4
|
+
listTools(params?: {
|
|
5
|
+
cursor?: string;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
tools: Tool[];
|
|
8
|
+
nextCursor?: string;
|
|
9
|
+
}>;
|
|
10
|
+
callTool(params: {
|
|
11
|
+
name: string;
|
|
12
|
+
arguments?: Record<string, unknown>;
|
|
13
|
+
}): Promise<Record<string, unknown>>;
|
|
14
|
+
listPrompts(params?: {
|
|
15
|
+
cursor?: string;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
prompts: Array<{
|
|
18
|
+
name: string;
|
|
19
|
+
title?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
arguments?: Array<{
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
}>;
|
|
27
|
+
nextCursor?: string;
|
|
28
|
+
}>;
|
|
29
|
+
getPrompt(params: {
|
|
30
|
+
name: string;
|
|
31
|
+
arguments?: Record<string, string>;
|
|
32
|
+
}): Promise<Record<string, unknown>>;
|
|
33
|
+
listResources(params?: {
|
|
34
|
+
cursor?: string;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
resources: Array<{
|
|
37
|
+
uri: string;
|
|
38
|
+
name: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
mimeType?: string;
|
|
42
|
+
}>;
|
|
43
|
+
nextCursor?: string;
|
|
44
|
+
}>;
|
|
45
|
+
readResource(params: {
|
|
46
|
+
uri: string;
|
|
47
|
+
}): Promise<Record<string, unknown>>;
|
|
48
|
+
close?(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
export interface HostedConnectDependencies {
|
|
51
|
+
/** The hosted Summer Engine MCP URL (the store sign-in's resource). */
|
|
52
|
+
url: () => string;
|
|
53
|
+
token: () => Promise<string>;
|
|
54
|
+
connect: (url: string, token: () => Promise<string>) => Promise<HostedClient>;
|
|
55
|
+
}
|
|
56
|
+
export declare function connectHostedMcp(url: string, token: () => Promise<string>): Promise<HostedClient>;
|
|
57
|
+
export declare const defaultHostedConnectDependencies: HostedConnectDependencies;
|
|
58
|
+
/** True when this machine has a store sign-in on disk (no network). */
|
|
59
|
+
export declare function hasStoreSignIn(): Promise<boolean>;
|
|
60
|
+
export declare function listAllHostedTools(client: HostedClient): Promise<Tool[]>;
|
|
61
|
+
/** Connect with the store sign-in, run fn, close. Throws OAuthError when not signed in. */
|
|
62
|
+
export declare function withHostedMcp<T>(fn: (client: HostedClient) => Promise<T>, deps?: HostedConnectDependencies): Promise<T>;
|
|
63
|
+
/** The text of a tool result, parsed as JSON when it is JSON. */
|
|
64
|
+
export declare function hostedResultPayload(result: Record<string, unknown>): {
|
|
65
|
+
isError: boolean;
|
|
66
|
+
text: string;
|
|
67
|
+
json: Record<string, unknown> | null;
|
|
68
|
+
};
|
|
69
|
+
export type StoreAccessResult = {
|
|
70
|
+
status: "not_signed_in";
|
|
71
|
+
message: string;
|
|
72
|
+
} | {
|
|
73
|
+
status: "ok";
|
|
74
|
+
games: number | null;
|
|
75
|
+
} | {
|
|
76
|
+
status: "refused";
|
|
77
|
+
code: string | null;
|
|
78
|
+
message: string;
|
|
79
|
+
requestId?: string;
|
|
80
|
+
} | {
|
|
81
|
+
status: "unreachable";
|
|
82
|
+
message: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Ask the store for the creator's games through the hosted MCP
|
|
86
|
+
* (summer_store_list_games): proves the store accepts this machine's sign-in.
|
|
87
|
+
*/
|
|
88
|
+
export declare function checkStoreAccess(timeoutMs?: number, deps?: HostedConnectDependencies): Promise<StoreAccessResult>;
|
|
89
|
+
/** The hosted tool a CLI name means: the exact name, or a slug ("store-list-games" -> summer_store_list_games). */
|
|
90
|
+
export declare function matchHostedTool(name: string, tools: readonly Tool[]): Tool | null;
|
|
91
|
+
export type HostedToolsListing = {
|
|
92
|
+
status: "listed";
|
|
93
|
+
tools: Tool[];
|
|
94
|
+
} | {
|
|
95
|
+
status: "not_signed_in";
|
|
96
|
+
} | {
|
|
97
|
+
status: "unavailable";
|
|
98
|
+
message: string;
|
|
99
|
+
};
|
|
100
|
+
/** The hosted store and publishing tools, when this machine has a store sign-in. */
|
|
101
|
+
export declare function listHostedToolsForCli(deps?: HostedConnectDependencies, signedIn?: () => Promise<boolean>): Promise<HostedToolsListing>;
|
|
102
|
+
export type HostedCallOutcome = {
|
|
103
|
+
status: "called";
|
|
104
|
+
tool: string;
|
|
105
|
+
result: Record<string, unknown>;
|
|
106
|
+
} | {
|
|
107
|
+
status: "not_found";
|
|
108
|
+
} | {
|
|
109
|
+
status: "not_signed_in";
|
|
110
|
+
} | {
|
|
111
|
+
status: "unavailable";
|
|
112
|
+
message: string;
|
|
113
|
+
};
|
|
114
|
+
/** Call a hosted tool by its name or slug with the store sign-in (one connection). */
|
|
115
|
+
export declare function callHostedToolForCli(name: string, args: Record<string, unknown>, deps?: HostedConnectDependencies, signedIn?: () => Promise<boolean>): Promise<HostedCallOutcome>;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
|
+
import { getStoreAccessToken, OAuthError, readStoredOAuthToken, resolveMcpResourceUrl } from "./oauth.js";
|
|
4
|
+
import { TOOLKIT_VERSION } from "./version.js";
|
|
5
|
+
/**
|
|
6
|
+
* A client for the hosted Summer Engine MCP (mcp.summerengine.com), signed in
|
|
7
|
+
* with the store sign-in ("summer login --store"). The local MCP mounts its
|
|
8
|
+
* tools (src/mcp/hosted-mount.ts); `summer tool` and `summer doctor` call it
|
|
9
|
+
* directly through the helpers below, so all three faces reach the same
|
|
10
|
+
* store and publishing tools.
|
|
11
|
+
*/
|
|
12
|
+
const CALL_TIMEOUT_MS = 120_000;
|
|
13
|
+
export async function connectHostedMcp(url, token) {
|
|
14
|
+
const transport = new StreamableHTTPClientTransport(new URL(url), {
|
|
15
|
+
// A fresh (refreshed when near expiry) token on every request.
|
|
16
|
+
fetch: async (input, init) => {
|
|
17
|
+
const headers = new Headers(init?.headers);
|
|
18
|
+
headers.set("authorization", `Bearer ${await token()}`);
|
|
19
|
+
return fetch(input, { ...init, headers });
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const client = new Client({ name: "summer-engine-local", version: TOOLKIT_VERSION });
|
|
23
|
+
await client.connect(transport);
|
|
24
|
+
const timeout = { timeout: CALL_TIMEOUT_MS };
|
|
25
|
+
return {
|
|
26
|
+
listTools: (params) => client.listTools(params),
|
|
27
|
+
callTool: (params) => client.callTool(params, undefined, timeout),
|
|
28
|
+
listPrompts: (params) => client.listPrompts(params),
|
|
29
|
+
getPrompt: (params) => client.getPrompt(params),
|
|
30
|
+
listResources: (params) => client.listResources(params),
|
|
31
|
+
readResource: (params) => client.readResource(params),
|
|
32
|
+
close: () => client.close(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export const defaultHostedConnectDependencies = {
|
|
36
|
+
url: () => resolveMcpResourceUrl(),
|
|
37
|
+
token: () => getStoreAccessToken(),
|
|
38
|
+
connect: connectHostedMcp,
|
|
39
|
+
};
|
|
40
|
+
/** True when this machine has a store sign-in on disk (no network). */
|
|
41
|
+
export async function hasStoreSignIn() {
|
|
42
|
+
return (await readStoredOAuthToken()) !== null;
|
|
43
|
+
}
|
|
44
|
+
export async function listAllHostedTools(client) {
|
|
45
|
+
const out = [];
|
|
46
|
+
let cursor;
|
|
47
|
+
for (let pages = 0; pages < 20; pages++) {
|
|
48
|
+
const result = await client.listTools(cursor ? { cursor } : undefined);
|
|
49
|
+
out.push(...(result.tools ?? []));
|
|
50
|
+
if (!result.nextCursor)
|
|
51
|
+
break;
|
|
52
|
+
cursor = result.nextCursor;
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/** Connect with the store sign-in, run fn, close. Throws OAuthError when not signed in. */
|
|
57
|
+
export async function withHostedMcp(fn, deps = defaultHostedConnectDependencies) {
|
|
58
|
+
const url = deps.url();
|
|
59
|
+
await deps.token();
|
|
60
|
+
const client = await deps.connect(url, deps.token);
|
|
61
|
+
try {
|
|
62
|
+
return await fn(client);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await client.close?.().catch(() => undefined);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** The text of a tool result, parsed as JSON when it is JSON. */
|
|
69
|
+
export function hostedResultPayload(result) {
|
|
70
|
+
const content = Array.isArray(result.content) ? result.content : [];
|
|
71
|
+
const text = content
|
|
72
|
+
.filter((part) => part.type === "text" && typeof part.text === "string")
|
|
73
|
+
.map((part) => part.text)
|
|
74
|
+
.join("\n");
|
|
75
|
+
let json = null;
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(text);
|
|
78
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
79
|
+
json = parsed;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
json = null;
|
|
83
|
+
}
|
|
84
|
+
if (!json && result.structuredContent && typeof result.structuredContent === "object") {
|
|
85
|
+
json = result.structuredContent;
|
|
86
|
+
}
|
|
87
|
+
return { isError: result.isError === true, text, json };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Ask the store for the creator's games through the hosted MCP
|
|
91
|
+
* (summer_store_list_games): proves the store accepts this machine's sign-in.
|
|
92
|
+
*/
|
|
93
|
+
export async function checkStoreAccess(timeoutMs = 8_000, deps = defaultHostedConnectDependencies) {
|
|
94
|
+
let timer;
|
|
95
|
+
const timeout = new Promise((resolve) => {
|
|
96
|
+
timer = setTimeout(() => resolve({ status: "unreachable", message: `no answer within ${Math.round(timeoutMs / 1000)} s` }), timeoutMs);
|
|
97
|
+
timer.unref?.();
|
|
98
|
+
});
|
|
99
|
+
const attempt = (async () => {
|
|
100
|
+
try {
|
|
101
|
+
const result = await withHostedMcp((client) => client.callTool({ name: "summer_store_list_games", arguments: {} }), deps);
|
|
102
|
+
const payload = hostedResultPayload(result);
|
|
103
|
+
if (payload.isError || payload.json?.ok === false) {
|
|
104
|
+
const code = typeof payload.json?.code === "string" ? payload.json.code : typeof payload.json?.error === "string" ? payload.json.error : null;
|
|
105
|
+
const message = typeof payload.json?.message === "string" ? payload.json.message : payload.text.slice(0, 300) || "the store refused the call";
|
|
106
|
+
const requestId = typeof payload.json?.requestId === "string" ? payload.json.requestId : undefined;
|
|
107
|
+
return { status: "refused", code, message, ...(requestId ? { requestId } : {}) };
|
|
108
|
+
}
|
|
109
|
+
const games = Array.isArray(payload.json?.games) ? payload.json.games.length : null;
|
|
110
|
+
return { status: "ok", games };
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (error instanceof OAuthError && error.code === "store_login_required") {
|
|
114
|
+
return { status: "not_signed_in", message: error.message.replace(` ${error.recovery}`, "") };
|
|
115
|
+
}
|
|
116
|
+
if (error instanceof OAuthError)
|
|
117
|
+
return { status: "refused", code: error.code, message: error.message };
|
|
118
|
+
return { status: "unreachable", message: error instanceof Error ? error.message : String(error) };
|
|
119
|
+
}
|
|
120
|
+
})();
|
|
121
|
+
try {
|
|
122
|
+
return await Promise.race([attempt, timeout]);
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
clearTimeout(timer);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** The hosted tool a CLI name means: the exact name, or a slug ("store-list-games" -> summer_store_list_games). */
|
|
129
|
+
export function matchHostedTool(name, tools) {
|
|
130
|
+
const needle = name.trim();
|
|
131
|
+
const asAlias = needle.startsWith("summer_") ? needle : `summer_${needle.replace(/-/g, "_")}`;
|
|
132
|
+
return tools.find((tool) => tool.name === needle) ?? tools.find((tool) => tool.name === asAlias) ?? null;
|
|
133
|
+
}
|
|
134
|
+
/** The hosted store and publishing tools, when this machine has a store sign-in. */
|
|
135
|
+
export async function listHostedToolsForCli(deps = defaultHostedConnectDependencies, signedIn = hasStoreSignIn) {
|
|
136
|
+
if (!(await signedIn()))
|
|
137
|
+
return { status: "not_signed_in" };
|
|
138
|
+
try {
|
|
139
|
+
return { status: "listed", tools: await withHostedMcp(listAllHostedTools, deps) };
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof OAuthError && error.code === "store_login_required")
|
|
143
|
+
return { status: "not_signed_in" };
|
|
144
|
+
return { status: "unavailable", message: error instanceof Error ? error.message : String(error) };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Call a hosted tool by its name or slug with the store sign-in (one connection). */
|
|
148
|
+
export async function callHostedToolForCli(name, args, deps = defaultHostedConnectDependencies, signedIn = hasStoreSignIn) {
|
|
149
|
+
if (!(await signedIn()))
|
|
150
|
+
return { status: "not_signed_in" };
|
|
151
|
+
try {
|
|
152
|
+
return await withHostedMcp(async (client) => {
|
|
153
|
+
const tool = matchHostedTool(name, await listAllHostedTools(client));
|
|
154
|
+
if (!tool)
|
|
155
|
+
return { status: "not_found" };
|
|
156
|
+
return { status: "called", tool: tool.name, result: await client.callTool({ name: tool.name, arguments: args }) };
|
|
157
|
+
}, deps);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (error instanceof OAuthError && error.code === "store_login_required")
|
|
161
|
+
return { status: "not_signed_in" };
|
|
162
|
+
return { status: "unavailable", message: error instanceof Error ? error.message : String(error) };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -96,6 +96,9 @@ export type BackgroundLaunchSupport = {
|
|
|
96
96
|
reason: "version_unknown";
|
|
97
97
|
version: null;
|
|
98
98
|
};
|
|
99
|
+
/** Whether `version` is `minimum` or newer; null when either is missing or
|
|
100
|
+
* not x.y.z (an unknown version is never "too old" and never "new enough"). */
|
|
101
|
+
export declare function isVersionAtLeast(version: string | null | undefined, minimum: string): boolean | null;
|
|
99
102
|
/**
|
|
100
103
|
* Whether the installed engine honours the background flag. The `--help`
|
|
101
104
|
* probe answer (true/false) is definitive when it ran; a probe that could not
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
* --help probe below runs against THAT binary (cache key: path + mtime + size).
|
|
62
62
|
*/
|
|
63
63
|
import { spawn } from "node:child_process";
|
|
64
|
-
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
64
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
65
65
|
import { basename, dirname, join } from "node:path";
|
|
66
66
|
import { platform } from "node:os";
|
|
67
67
|
import { getSummerDir } from "./auth.js";
|
|
@@ -100,6 +100,15 @@ function compareVersions(a, b) {
|
|
|
100
100
|
return a.minor - b.minor;
|
|
101
101
|
return a.patch - b.patch;
|
|
102
102
|
}
|
|
103
|
+
/** Whether `version` is `minimum` or newer; null when either is missing or
|
|
104
|
+
* not x.y.z (an unknown version is never "too old" and never "new enough"). */
|
|
105
|
+
export function isVersionAtLeast(version, minimum) {
|
|
106
|
+
const parsed = version ? parseVersion(version) : null;
|
|
107
|
+
const min = parseVersion(minimum);
|
|
108
|
+
if (!parsed || !min)
|
|
109
|
+
return null;
|
|
110
|
+
return compareVersions(parsed, min) >= 0;
|
|
111
|
+
}
|
|
103
112
|
/**
|
|
104
113
|
* Whether the installed engine honours the background flag. The `--help`
|
|
105
114
|
* probe answer (true/false) is definitive when it ran; a probe that could not
|
|
@@ -282,12 +291,16 @@ export function parseVelopackVersion(sqVersionText) {
|
|
|
282
291
|
const match = sqVersionText.match(/<version>\s*([^<\s]+)\s*<\/version>/i);
|
|
283
292
|
return match ? match[1].trim() : null;
|
|
284
293
|
}
|
|
285
|
-
/** Walk up from `.../Summer.app/Contents/MacOS/Summer` to the bundle.
|
|
294
|
+
/** Walk up from `.../Summer.app/Contents/MacOS/Summer` to the bundle. A
|
|
295
|
+
* bundle unpacked without its `.app` folder (`<dir>/Contents/MacOS/Summer`)
|
|
296
|
+
* reads as `<dir>`. */
|
|
286
297
|
function macBundlePathFor(binary) {
|
|
287
298
|
let current = dirname(binary);
|
|
288
299
|
for (let depth = 0; depth < 4; depth++) {
|
|
289
300
|
if (basename(current).endsWith(".app"))
|
|
290
301
|
return current;
|
|
302
|
+
if (basename(current) === "Contents" && existsSync(join(current, "Info.plist")))
|
|
303
|
+
return dirname(current);
|
|
291
304
|
const parent = dirname(current);
|
|
292
305
|
if (parent === current)
|
|
293
306
|
break;
|
|
@@ -19,10 +19,10 @@ export declare const readLibraryInputSchema: z.ZodObject<{
|
|
|
19
19
|
part: z.ZodOptional<z.ZodEnum<["skill", "resource", "all"]>>;
|
|
20
20
|
}, "strict", z.ZodTypeAny, {
|
|
21
21
|
id: string;
|
|
22
|
-
part?: "
|
|
22
|
+
part?: "resource" | "all" | "skill" | undefined;
|
|
23
23
|
}, {
|
|
24
24
|
id: string;
|
|
25
|
-
part?: "
|
|
25
|
+
part?: "resource" | "all" | "skill" | undefined;
|
|
26
26
|
}>;
|
|
27
27
|
export type ReadLibraryArgs = z.infer<typeof readLibraryInputSchema>;
|
|
28
28
|
export interface LibraryReadDeps extends LibrarySearchDeps {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Summer store sign-in for local tools (summer_publish_build): OAuth 2.1
|
|
3
|
+
* authorization code + PKCE against the same Supabase authorization server
|
|
4
|
+
* and resource the hosted MCP uses (mcp.summerengine.com/mcp), with a
|
|
5
|
+
* loopback redirect (RFC 8252). The access token's audience is the MCP
|
|
6
|
+
* resource, the one token the creator store accepts for agents (creator
|
|
7
|
+
* publishing spec, part C.3).
|
|
8
|
+
*
|
|
9
|
+
* The Summer CLI is one public client (no secret; PKCE proves each login).
|
|
10
|
+
* The authorization server matches redirect URIs exactly, so the CLI listens
|
|
11
|
+
* on one of a few fixed loopback ports and registers its client once per
|
|
12
|
+
* machine with exactly those redirect URIs. Later logins and refreshes reuse
|
|
13
|
+
* that client id (~/.summer/oauth-client); only --force registers anew.
|
|
14
|
+
*
|
|
15
|
+
* The token is stored in ~/.summer/oauth-token (0600) with its refresh token,
|
|
16
|
+
* separate from the CLI JWT in auth-token: the engine reads that file and
|
|
17
|
+
* expects the summer-cli contract.
|
|
18
|
+
*/
|
|
19
|
+
export declare const OAUTH_TOKEN_FILE = "oauth-token";
|
|
20
|
+
export declare const OAUTH_CLIENT_FILE = "oauth-client";
|
|
21
|
+
/** Loopback ports the Summer CLI client is registered for, tried in order. */
|
|
22
|
+
export declare const STORE_LOGIN_PORTS: readonly [47615, 47616, 47617];
|
|
23
|
+
export declare const DEFAULT_MCP_RESOURCE_URL = "https://mcp.summerengine.com/mcp";
|
|
24
|
+
export declare const MCP_RESOURCE_ENV = "SUMMER_MCP_RESOURCE_URL";
|
|
25
|
+
export declare class OAuthError extends Error {
|
|
26
|
+
readonly code: string;
|
|
27
|
+
readonly recovery: string;
|
|
28
|
+
constructor(code: string, message: string, recovery: string);
|
|
29
|
+
}
|
|
30
|
+
export interface StoredOAuthToken {
|
|
31
|
+
schemaVersion: 1;
|
|
32
|
+
resource: string;
|
|
33
|
+
issuer: string;
|
|
34
|
+
tokenEndpoint: string;
|
|
35
|
+
clientId: string;
|
|
36
|
+
accessToken: string;
|
|
37
|
+
refreshToken?: string;
|
|
38
|
+
expiresAt: string;
|
|
39
|
+
scope?: string;
|
|
40
|
+
}
|
|
41
|
+
/** The machine's registered Summer CLI client for one authorization server. */
|
|
42
|
+
export interface StoredOAuthClient {
|
|
43
|
+
schemaVersion: 1;
|
|
44
|
+
issuer: string;
|
|
45
|
+
clientId: string;
|
|
46
|
+
redirectUris: string[];
|
|
47
|
+
}
|
|
48
|
+
interface AuthorizationServer {
|
|
49
|
+
issuer: string;
|
|
50
|
+
authorizationEndpoint: string;
|
|
51
|
+
tokenEndpoint: string;
|
|
52
|
+
registrationEndpoint: string;
|
|
53
|
+
}
|
|
54
|
+
export interface OAuthDependencies {
|
|
55
|
+
fetch: typeof fetch;
|
|
56
|
+
now: () => number;
|
|
57
|
+
}
|
|
58
|
+
export declare function resolveMcpResourceUrl(env?: NodeJS.ProcessEnv): string;
|
|
59
|
+
/** RFC 9728 resource metadata, then RFC 8414 server metadata (path-aware first). */
|
|
60
|
+
export declare function discoverAuthorizationServer(resource: string, deps?: OAuthDependencies): Promise<AuthorizationServer>;
|
|
61
|
+
export interface StoreLoginDependencies extends OAuthDependencies {
|
|
62
|
+
openUrl: (url: string) => Promise<unknown>;
|
|
63
|
+
log: (message: string) => void;
|
|
64
|
+
timeoutMs?: number;
|
|
65
|
+
/** Register a new client instead of reusing this machine's ("summer login --store --force"). */
|
|
66
|
+
newClient?: boolean;
|
|
67
|
+
/** Tests only: other loopback ports. */
|
|
68
|
+
ports?: readonly number[];
|
|
69
|
+
}
|
|
70
|
+
/** Browser sign-in (authorization code + PKCE) that stores ~/.summer/oauth-token. */
|
|
71
|
+
export declare function runStoreLogin(deps: StoreLoginDependencies): Promise<StoredOAuthToken>;
|
|
72
|
+
export declare function readStoredOAuthToken(): Promise<StoredOAuthToken | null>;
|
|
73
|
+
/**
|
|
74
|
+
* A current store access token: the stored one, refreshed when it expires
|
|
75
|
+
* within a minute.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getStoreAccessToken(deps?: OAuthDependencies): Promise<string>;
|
|
78
|
+
export {};
|