summer-engine 2.6.5 → 2.6.6
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/CHANGELOG.md +11 -0
- package/README.md +18 -16
- package/dist/lib/api-client.d.ts +11 -4
- package/dist/lib/api-client.js +51 -27
- package/dist/lib/cloud/engine-bridge.js +9 -1
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
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
|
+
## [2.6.6] — 2026-07-15 — "Project-bound engine requests"
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Every local engine request now carries the engine instance ID, stable project ID, project ID hash, and identity protocol version captured when the CLI connects. This lets compatible engine builds reject stale requests after a project or engine switch instead of acting on the wrong target.
|
|
9
|
+
- An explicit project rebind now refreshes the complete engine and project identity, while keeping the existing project-hash mutation guard and screenshot drift checks.
|
|
10
|
+
- Summer Cloud's engine bridge now binds its save, rescan, and scene reload requests to the project it verified on disk.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Summer Cloud is documented as an optional Research Preview instead of part of the core local CLI and MCP workflow.
|
|
14
|
+
- Release metadata and the manual npm runbook now pin the public registry and require a clean, reviewed public source checkout.
|
|
15
|
+
|
|
5
16
|
## [2.6.5] — 2026-07-04 — "Cloud tools don't need the engine"
|
|
6
17
|
|
|
7
18
|
### Fixed
|
package/README.md
CHANGED
|
@@ -23,22 +23,6 @@ Three names, one npm package (`summer-engine`):
|
|
|
23
23
|
|
|
24
24
|
All MIT, all free to use. One paste sets up all three.
|
|
25
25
|
|
|
26
|
-
## Summer Cloud (new in 2.6.0)
|
|
27
|
-
|
|
28
|
-
`summer cloud` syncs your whole game project across machines: scenes, scripts, settings, and the big binary assets that never fit in git. Files are stored by content hash, every push becomes a restorable version, and local checkpoints are taken before anything destructive touches your disk.
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
summer cloud init # bind this project to your account
|
|
32
|
-
summer cloud push # upload what changed (only missing bytes travel)
|
|
33
|
-
summer cloud pull # make this machine match the cloud, verified by hash
|
|
34
|
-
summer cloud status # what differs between here and the cloud
|
|
35
|
-
summer cloud restore # roll the project back to any version
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
The same operations are available to agents as MCP tools (`summer_cloud_push`, `summer_cloud_pull`, and friends). See [www.summerengine.com/cloud](https://www.summerengine.com/cloud).
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
26
|
## Get started: one prompt
|
|
43
27
|
|
|
44
28
|
Open your AI agent (Claude Code, Cursor, Codex, Copilot, Devin Desktop, etc.) and paste:
|
|
@@ -556,6 +540,24 @@ Skills evolve fast. Two ways to help:
|
|
|
556
540
|
|
|
557
541
|
---
|
|
558
542
|
|
|
543
|
+
## Research Preview: Summer Cloud
|
|
544
|
+
|
|
545
|
+
Summer Cloud is an experimental R&D preview. It is optional, it may change or break, and it is **not** the core Summer CLI or MCP workflow. You do not need it to install or run Summer Engine, work with local projects, or use the local MCP server. The stable workflow is the local engine, CLI, MCP bridge, and agent skills described above.
|
|
546
|
+
|
|
547
|
+
The preview explores content-addressed project sync across machines, including large assets that do not fit comfortably in git:
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
summer cloud init
|
|
551
|
+
summer cloud status
|
|
552
|
+
summer cloud push
|
|
553
|
+
summer cloud pull
|
|
554
|
+
summer cloud restore
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
Matching `summer_cloud_*` MCP tools are also experimental. Keep an independent backup and do not use this preview as the only recovery path for an important project. See [www.summerengine.com/cloud](https://www.summerengine.com/cloud).
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
559
561
|
## License
|
|
560
562
|
|
|
561
563
|
MIT for everything in this repo. Summer Engine itself is proprietary. See [What's open and what's not](#whats-open-and-whats-not).
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -33,11 +33,16 @@ export type EngineSnapshot = {
|
|
|
33
33
|
* (item 4, client-side drift check). */
|
|
34
34
|
projectMismatch?: boolean;
|
|
35
35
|
};
|
|
36
|
+
type EngineTargetIdentity = {
|
|
37
|
+
instanceId?: string;
|
|
38
|
+
projectId?: string;
|
|
39
|
+
projectIdHash?: string;
|
|
40
|
+
};
|
|
36
41
|
export declare class EngineApiClient {
|
|
37
42
|
private port;
|
|
38
43
|
private token;
|
|
39
|
-
private
|
|
40
|
-
constructor(port: number, token: string,
|
|
44
|
+
private targetIdentity;
|
|
45
|
+
constructor(port: number, token: string, targetIdentity?: EngineTargetIdentity | string);
|
|
41
46
|
static connect(): Promise<EngineApiClient>;
|
|
42
47
|
/** The projectIdHash this session is bound to (undefined if none was reported
|
|
43
48
|
* at connect — e.g. no project open yet). */
|
|
@@ -46,13 +51,14 @@ export declare class EngineApiClient {
|
|
|
46
51
|
* Re-read health and rebind to the currently-open project. Called by
|
|
47
52
|
* summer_get_project_context so the agent can INTENTIONALLY follow a project
|
|
48
53
|
* switch (the deliberate escape hatch after an identity_mismatch). Returns the
|
|
49
|
-
* new bound hash.
|
|
50
|
-
* even when
|
|
54
|
+
* new bound hash. The direct health probe is intentionally unscoped, so it can
|
|
55
|
+
* reach the current engine even when bound requests would be rejected.
|
|
51
56
|
*/
|
|
52
57
|
rebind(): Promise<string | undefined>;
|
|
53
58
|
/** Identity to attach to a MUTATING command's options so the engine can reject
|
|
54
59
|
* a wrong-project write. Empty when unbound (engine then skips the check). */
|
|
55
60
|
private identityOptions;
|
|
61
|
+
private targetUrl;
|
|
56
62
|
private request;
|
|
57
63
|
/** Raw fetch with auth + timeout — returns the Response so callers can inspect
|
|
58
64
|
* the status (202 queued vs 200 legacy). */
|
|
@@ -125,3 +131,4 @@ export declare class EngineApiClient {
|
|
|
125
131
|
*/
|
|
126
132
|
credentialsChanged(): Promise<boolean>;
|
|
127
133
|
}
|
|
134
|
+
export {};
|
package/dist/lib/api-client.js
CHANGED
|
@@ -67,17 +67,19 @@ function withoutImageData(payload) {
|
|
|
67
67
|
export class EngineApiClient {
|
|
68
68
|
port;
|
|
69
69
|
token;
|
|
70
|
-
// The project this session is
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
constructor(port, token, boundProjectIdHash) {
|
|
70
|
+
// The engine and project this session is bound to. Every request carries the
|
|
71
|
+
// identity captured from health so the engine can reject requests after an
|
|
72
|
+
// in-place project switch or an unexpected instance change. The string form
|
|
73
|
+
// preserves the pre-2.6.6 constructor contract for existing callers that only
|
|
74
|
+
// supplied a projectIdHash.
|
|
75
|
+
targetIdentity;
|
|
76
|
+
constructor(port, token, targetIdentity = {}) {
|
|
78
77
|
this.port = port;
|
|
79
78
|
this.token = token;
|
|
80
|
-
this.
|
|
79
|
+
this.targetIdentity =
|
|
80
|
+
typeof targetIdentity === "string"
|
|
81
|
+
? { projectIdHash: targetIdentity }
|
|
82
|
+
: { ...targetIdentity };
|
|
81
83
|
}
|
|
82
84
|
static async connect() {
|
|
83
85
|
const port = await getApiPort();
|
|
@@ -94,34 +96,57 @@ export class EngineApiClient {
|
|
|
94
96
|
// rebinds to the current project. An in-place project switch keeps the same
|
|
95
97
|
// token, so the cached client retains its original binding and the engine
|
|
96
98
|
// rejects mismatched mutations until the agent explicitly rebinds.
|
|
97
|
-
return new EngineApiClient(port, token,
|
|
99
|
+
return new EngineApiClient(port, token, {
|
|
100
|
+
instanceId: health.instanceId,
|
|
101
|
+
projectId: health.projectId,
|
|
102
|
+
projectIdHash: health.projectIdHash,
|
|
103
|
+
});
|
|
98
104
|
}
|
|
99
105
|
/** The projectIdHash this session is bound to (undefined if none was reported
|
|
100
106
|
* at connect — e.g. no project open yet). */
|
|
101
107
|
getBoundProjectIdHash() {
|
|
102
|
-
return this.
|
|
108
|
+
return this.targetIdentity.projectIdHash;
|
|
103
109
|
}
|
|
104
110
|
/**
|
|
105
111
|
* Re-read health and rebind to the currently-open project. Called by
|
|
106
112
|
* summer_get_project_context so the agent can INTENTIONALLY follow a project
|
|
107
113
|
* switch (the deliberate escape hatch after an identity_mismatch). Returns the
|
|
108
|
-
* new bound hash.
|
|
109
|
-
* even when
|
|
114
|
+
* new bound hash. The direct health probe is intentionally unscoped, so it can
|
|
115
|
+
* reach the current engine even when bound requests would be rejected.
|
|
110
116
|
*/
|
|
111
117
|
async rebind() {
|
|
112
118
|
const health = await checkEngineHealth(this.port);
|
|
113
119
|
if (health) {
|
|
114
|
-
this.
|
|
120
|
+
this.targetIdentity = {
|
|
121
|
+
instanceId: health.instanceId,
|
|
122
|
+
projectId: health.projectId,
|
|
123
|
+
projectIdHash: health.projectIdHash,
|
|
124
|
+
};
|
|
115
125
|
}
|
|
116
|
-
return this.
|
|
126
|
+
return this.targetIdentity.projectIdHash;
|
|
117
127
|
}
|
|
118
128
|
/** Identity to attach to a MUTATING command's options so the engine can reject
|
|
119
129
|
* a wrong-project write. Empty when unbound (engine then skips the check). */
|
|
120
130
|
identityOptions() {
|
|
121
|
-
|
|
131
|
+
const projectIdHash = this.targetIdentity.projectIdHash;
|
|
132
|
+
return projectIdHash ? { projectIdHash } : {};
|
|
133
|
+
}
|
|
134
|
+
targetUrl(path) {
|
|
135
|
+
const url = new URL(path, `http://127.0.0.1:${this.port}`);
|
|
136
|
+
const { instanceId, projectId, projectIdHash } = this.targetIdentity;
|
|
137
|
+
if (instanceId)
|
|
138
|
+
url.searchParams.set("instanceId", instanceId);
|
|
139
|
+
if (projectId)
|
|
140
|
+
url.searchParams.set("projectId", projectId);
|
|
141
|
+
if (projectIdHash)
|
|
142
|
+
url.searchParams.set("projectIdHash", projectIdHash);
|
|
143
|
+
if (instanceId && projectId && projectIdHash) {
|
|
144
|
+
url.searchParams.set("projectIdentityVersion", "1");
|
|
145
|
+
}
|
|
146
|
+
return url.toString();
|
|
122
147
|
}
|
|
123
148
|
async request(method, path, body) {
|
|
124
|
-
const url =
|
|
149
|
+
const url = this.targetUrl(path);
|
|
125
150
|
const headers = {
|
|
126
151
|
Authorization: `Bearer ${this.token}`,
|
|
127
152
|
"Content-Type": "application/json",
|
|
@@ -141,7 +166,7 @@ export class EngineApiClient {
|
|
|
141
166
|
/** Raw fetch with auth + timeout — returns the Response so callers can inspect
|
|
142
167
|
* the status (202 queued vs 200 legacy). */
|
|
143
168
|
async _fetchRaw(method, path, body, timeoutMs) {
|
|
144
|
-
return fetch(
|
|
169
|
+
return fetch(this.targetUrl(path), {
|
|
145
170
|
method,
|
|
146
171
|
headers: {
|
|
147
172
|
Authorization: `Bearer ${this.token}`,
|
|
@@ -305,18 +330,17 @@ export class EngineApiClient {
|
|
|
305
330
|
const { format, mime, ext } = snapshotFormat(payload);
|
|
306
331
|
const buffer = Buffer.from(base64, "base64");
|
|
307
332
|
const localPath = await this.writeSnapshotFile(kind, buffer, ext);
|
|
308
|
-
// Client-side identity drift check (item 4).
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
// project. Best-effort: a failed health read never blocks the (already
|
|
314
|
-
// captured) image.
|
|
333
|
+
// Client-side identity drift check (item 4). Current engines validate the
|
|
334
|
+
// identity query on snapshot reads, but older builds may ignore it. Re-read
|
|
335
|
+
// health and compare to the bound hash so a frame from a switched project is
|
|
336
|
+
// still marked as suspect. Best-effort: a failed health read never blocks the
|
|
337
|
+
// already captured image.
|
|
315
338
|
let projectMismatch;
|
|
316
|
-
|
|
339
|
+
const boundProjectIdHash = this.targetIdentity.projectIdHash;
|
|
340
|
+
if (boundProjectIdHash) {
|
|
317
341
|
try {
|
|
318
342
|
const health = await checkEngineHealth(this.port);
|
|
319
|
-
if (health?.projectIdHash && health.projectIdHash !==
|
|
343
|
+
if (health?.projectIdHash && health.projectIdHash !== boundProjectIdHash) {
|
|
320
344
|
projectMismatch = true;
|
|
321
345
|
}
|
|
322
346
|
}
|
|
@@ -50,7 +50,15 @@ async function connectForProject(projectRoot) {
|
|
|
50
50
|
// rescan; the executor rejects mismatches too, but skip the round trip.
|
|
51
51
|
if (health.projectIdHash && health.projectIdHash !== projectIdHash)
|
|
52
52
|
return null;
|
|
53
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
client: new EngineApiClient(port, token, {
|
|
55
|
+
instanceId: health.instanceId,
|
|
56
|
+
projectId: health.projectId,
|
|
57
|
+
projectIdHash,
|
|
58
|
+
}),
|
|
59
|
+
projectIdHash,
|
|
60
|
+
scene: health.scene,
|
|
61
|
+
};
|
|
54
62
|
}
|
|
55
63
|
catch {
|
|
56
64
|
return null;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "summer-engine",
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"description": "Summer CLI and MCP server for Summer Engine
|
|
3
|
+
"version": "2.6.6",
|
|
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",
|
|
7
7
|
"summer-cli",
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "git+https://github.com/SummerEngine/summer-engine-agent.git"
|
|
29
29
|
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public",
|
|
32
|
+
"registry": "https://registry.npmjs.org"
|
|
33
|
+
},
|
|
30
34
|
"license": "MIT",
|
|
31
35
|
"author": "Summer Engine <founders@summerengine.com>",
|
|
32
36
|
"type": "module",
|