gdharness 1.1.52 → 1.1.53
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/build/cli.js +34 -13
- package/build/index.js +34 -12
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -38117,6 +38117,21 @@ var init_wrapper = __esm(() => {
|
|
|
38117
38117
|
import { randomUUID } from "node:crypto";
|
|
38118
38118
|
import { EventEmitter } from "node:events";
|
|
38119
38119
|
import http from "node:http";
|
|
38120
|
+
function closeReason(text, keep) {
|
|
38121
|
+
if (Buffer.byteLength(text) <= MOST_CLOSE_REASON_BYTES) {
|
|
38122
|
+
return text;
|
|
38123
|
+
}
|
|
38124
|
+
const characters = Array.from(text);
|
|
38125
|
+
const marker = "...";
|
|
38126
|
+
while (Buffer.byteLength(characters.join("")) + marker.length > MOST_CLOSE_REASON_BYTES) {
|
|
38127
|
+
if (keep === "end") {
|
|
38128
|
+
characters.shift();
|
|
38129
|
+
} else {
|
|
38130
|
+
characters.pop();
|
|
38131
|
+
}
|
|
38132
|
+
}
|
|
38133
|
+
return keep === "end" ? `${marker}${characters.join("")}` : `${characters.join("")}${marker}`;
|
|
38134
|
+
}
|
|
38120
38135
|
function resolveDefaultBridgePort() {
|
|
38121
38136
|
return portFromEnv("GDHARNESS_BRIDGE_PORT", DEFAULT_PORT);
|
|
38122
38137
|
}
|
|
@@ -38143,7 +38158,7 @@ function getDefaultBridge(ownProject = null) {
|
|
|
38143
38158
|
defaultBridge ??= new GodotBridge(resolveDefaultBridgePort(), resolveDefaultBridgeHost(), DEFAULT_TIMEOUT_MS, ownProject);
|
|
38144
38159
|
return defaultBridge;
|
|
38145
38160
|
}
|
|
38146
|
-
var DEFAULT_PORT = 6505, DEFAULT_HOST = "127.0.0.1", DEFAULT_TIMEOUT_MS = 30000, KEEPALIVE_INTERVAL_MS = 1e4, SECOND_CONNECTION_CLOSE_CODE = 4000, OTHER_PROJECT_CLOSE_CODE = 4001, ONE_SHOT_CLOSE_CODE = 4002, CONNECT_WINDOW_MS = 35000, GodotBridge, defaultBridge = null;
|
|
38161
|
+
var DEFAULT_PORT = 6505, DEFAULT_HOST = "127.0.0.1", DEFAULT_TIMEOUT_MS = 30000, KEEPALIVE_INTERVAL_MS = 1e4, SECOND_CONNECTION_CLOSE_CODE = 4000, MOST_CLOSE_REASON_BYTES = 123, OTHER_PROJECT_CLOSE_CODE = 4001, ONE_SHOT_CLOSE_CODE = 4002, CONNECT_WINDOW_MS = 35000, GodotBridge, defaultBridge = null;
|
|
38147
38162
|
var init_godot_bridge = __esm(() => {
|
|
38148
38163
|
init_wrapper();
|
|
38149
38164
|
init_errors();
|
|
@@ -38293,7 +38308,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
38293
38308
|
const editor = identifying ? null : this.connectionInfo;
|
|
38294
38309
|
return {
|
|
38295
38310
|
host: this.host,
|
|
38296
|
-
port: this.
|
|
38311
|
+
port: this.boundPort,
|
|
38297
38312
|
connected: this.isConnected(),
|
|
38298
38313
|
projectPath: editor?.projectPath,
|
|
38299
38314
|
connectedAt: editor?.connectedAt,
|
|
@@ -38550,7 +38565,8 @@ var init_godot_bridge = __esm(() => {
|
|
|
38550
38565
|
this.socket = null;
|
|
38551
38566
|
this.connectionInfo = null;
|
|
38552
38567
|
this.stopKeepalive();
|
|
38553
|
-
|
|
38568
|
+
const fits = closeReason(said, "start") === said;
|
|
38569
|
+
stranger?.close(OTHER_PROJECT_CLOSE_CODE, fits ? said : closeReason(`this server serves ${this.ownProject ?? ""}`, "end"));
|
|
38554
38570
|
}
|
|
38555
38571
|
identify(pid) {
|
|
38556
38572
|
const known = this.oneShots.get(pid);
|
|
@@ -38589,7 +38605,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
38589
38605
|
this.socket = null;
|
|
38590
38606
|
this.connectionInfo = null;
|
|
38591
38607
|
this.stopKeepalive();
|
|
38592
|
-
run?.close(ONE_SHOT_CLOSE_CODE, said);
|
|
38608
|
+
run?.close(ONE_SHOT_CLOSE_CODE, closeReason(said, "start"));
|
|
38593
38609
|
}
|
|
38594
38610
|
handleDisconnect(disconnectedSocket, reason) {
|
|
38595
38611
|
if (disconnectedSocket && this.socket && disconnectedSocket !== this.socket) {
|
|
@@ -42904,8 +42920,12 @@ class GodotServer {
|
|
|
42904
42920
|
console.error("gdharness running on stdio");
|
|
42905
42921
|
sweepAbandonedScratch();
|
|
42906
42922
|
try {
|
|
42907
|
-
|
|
42908
|
-
|
|
42923
|
+
try {
|
|
42924
|
+
await this.takeOverFromAPredecessor();
|
|
42925
|
+
await this.godotBridge.start();
|
|
42926
|
+
} finally {
|
|
42927
|
+
this.handingOverFrom = null;
|
|
42928
|
+
}
|
|
42909
42929
|
this.bridgeStartupError = null;
|
|
42910
42930
|
const bridgeStatus = this.godotBridge.getStatus();
|
|
42911
42931
|
console.error(`[SERVER] Godot Editor Bridge started on ${bridgeStatus.host}:${bridgeStatus.port}`);
|
|
@@ -42945,7 +42965,6 @@ class GodotServer {
|
|
|
42945
42965
|
await delay3(HANDOVER_POLL_MS);
|
|
42946
42966
|
}
|
|
42947
42967
|
}
|
|
42948
|
-
this.handingOverFrom = null;
|
|
42949
42968
|
this.notHandedOverBy = taken ? null : announced.pid;
|
|
42950
42969
|
}
|
|
42951
42970
|
keepTryingTheBridge() {
|
|
@@ -42977,10 +42996,9 @@ class GodotServer {
|
|
|
42977
42996
|
if (this.ownProject === null) {
|
|
42978
42997
|
return;
|
|
42979
42998
|
}
|
|
42980
|
-
const status = this.godotBridge.getStatus();
|
|
42981
42999
|
this.announcedAt = announceBridge(this.ownProject, {
|
|
42982
|
-
host:
|
|
42983
|
-
port:
|
|
43000
|
+
host: this.godotBridge.getStatus().host,
|
|
43001
|
+
port: this.godotBridge.port,
|
|
42984
43002
|
version: SERVER_VERSION
|
|
42985
43003
|
});
|
|
42986
43004
|
this.watchForASuccessor();
|
|
@@ -44923,19 +44941,22 @@ class GodotServer {
|
|
|
44923
44941
|
return { note: owed, underway: restartUnderway(owed) };
|
|
44924
44942
|
}
|
|
44925
44943
|
async getEditorStatusPayload() {
|
|
44944
|
+
const wasConnected = this.godotBridge.getStatus().connected;
|
|
44945
|
+
const launchedWasUp = !wasConnected && await this.launchedEditorIsUp();
|
|
44946
|
+
const arrivingFound = wasConnected || this.ownProject === null ? [] : await this.editorsNotYetConnected(this.ownProject) ?? [];
|
|
44926
44947
|
const status = this.godotBridge.getStatus();
|
|
44927
|
-
const launchedIsUp = !status.connected &&
|
|
44948
|
+
const launchedIsUp = !status.connected && launchedWasUp;
|
|
44949
|
+
const arriving = status.connected ? [] : arrivingFound;
|
|
44928
44950
|
const isPortConflict = this.bridgeStartupError?.includes("EADDRINUSE") ?? false;
|
|
44929
44951
|
const greeted = hasSaidWhoItIs(status);
|
|
44930
44952
|
const stale = greeted && editorIsStale(status.addonVersion, SERVER_VERSION, status.addonDigest, shippedEditorDigest());
|
|
44931
44953
|
const unfinished = this.restartLeftUnfinished(status.connected);
|
|
44932
|
-
const arriving = status.connected || this.ownProject === null ? [] : await this.editorsNotYetConnected(this.ownProject) ?? [];
|
|
44933
44954
|
return {
|
|
44934
44955
|
...status,
|
|
44935
44956
|
serverVersion: SERVER_VERSION,
|
|
44936
44957
|
addonIsStale: greeted ? stale : undefined,
|
|
44937
44958
|
greeting: status.connected && !greeted ? "The editor has connected and has not yet said who it is: its project, pid, addon version and ports arrive with its greeting a moment after the socket opens, later while it imports. Ask again for them." : undefined,
|
|
44938
|
-
bridgeAvailable: this.bridgeStartupError === null,
|
|
44959
|
+
bridgeAvailable: this.bridgeStartupError === null && status.port !== null,
|
|
44939
44960
|
mayYetConnect: status.connected ? undefined : arriving.length > 0 ? true : unfinished !== null ? unfinished.underway : anEditorIsStillComing(status.listeningSince, launchedIsUp),
|
|
44940
44961
|
editorsNotYetConnected: arriving.length > 0 ? arriving : undefined,
|
|
44941
44962
|
restartInterrupted: unfinished === null || unfinished.underway || arriving.length > 0 ? undefined : {
|
package/build/index.js
CHANGED
|
@@ -28181,6 +28181,22 @@ var DEFAULT_HOST = "127.0.0.1";
|
|
|
28181
28181
|
var DEFAULT_TIMEOUT_MS = 30000;
|
|
28182
28182
|
var KEEPALIVE_INTERVAL_MS = 1e4;
|
|
28183
28183
|
var SECOND_CONNECTION_CLOSE_CODE = 4000;
|
|
28184
|
+
var MOST_CLOSE_REASON_BYTES = 123;
|
|
28185
|
+
function closeReason(text, keep) {
|
|
28186
|
+
if (Buffer.byteLength(text) <= MOST_CLOSE_REASON_BYTES) {
|
|
28187
|
+
return text;
|
|
28188
|
+
}
|
|
28189
|
+
const characters = Array.from(text);
|
|
28190
|
+
const marker = "...";
|
|
28191
|
+
while (Buffer.byteLength(characters.join("")) + marker.length > MOST_CLOSE_REASON_BYTES) {
|
|
28192
|
+
if (keep === "end") {
|
|
28193
|
+
characters.shift();
|
|
28194
|
+
} else {
|
|
28195
|
+
characters.pop();
|
|
28196
|
+
}
|
|
28197
|
+
}
|
|
28198
|
+
return keep === "end" ? `${marker}${characters.join("")}` : `${characters.join("")}${marker}`;
|
|
28199
|
+
}
|
|
28184
28200
|
var OTHER_PROJECT_CLOSE_CODE = 4001;
|
|
28185
28201
|
var ONE_SHOT_CLOSE_CODE = 4002;
|
|
28186
28202
|
function resolveDefaultBridgePort() {
|
|
@@ -28351,7 +28367,7 @@ class GodotBridge extends EventEmitter {
|
|
|
28351
28367
|
const editor = identifying ? null : this.connectionInfo;
|
|
28352
28368
|
return {
|
|
28353
28369
|
host: this.host,
|
|
28354
|
-
port: this.
|
|
28370
|
+
port: this.boundPort,
|
|
28355
28371
|
connected: this.isConnected(),
|
|
28356
28372
|
projectPath: editor?.projectPath,
|
|
28357
28373
|
connectedAt: editor?.connectedAt,
|
|
@@ -28608,7 +28624,8 @@ class GodotBridge extends EventEmitter {
|
|
|
28608
28624
|
this.socket = null;
|
|
28609
28625
|
this.connectionInfo = null;
|
|
28610
28626
|
this.stopKeepalive();
|
|
28611
|
-
|
|
28627
|
+
const fits = closeReason(said, "start") === said;
|
|
28628
|
+
stranger?.close(OTHER_PROJECT_CLOSE_CODE, fits ? said : closeReason(`this server serves ${this.ownProject ?? ""}`, "end"));
|
|
28612
28629
|
}
|
|
28613
28630
|
identify(pid) {
|
|
28614
28631
|
const known = this.oneShots.get(pid);
|
|
@@ -28647,7 +28664,7 @@ class GodotBridge extends EventEmitter {
|
|
|
28647
28664
|
this.socket = null;
|
|
28648
28665
|
this.connectionInfo = null;
|
|
28649
28666
|
this.stopKeepalive();
|
|
28650
|
-
run?.close(ONE_SHOT_CLOSE_CODE, said);
|
|
28667
|
+
run?.close(ONE_SHOT_CLOSE_CODE, closeReason(said, "start"));
|
|
28651
28668
|
}
|
|
28652
28669
|
handleDisconnect(disconnectedSocket, reason) {
|
|
28653
28670
|
if (disconnectedSocket && this.socket && disconnectedSocket !== this.socket) {
|
|
@@ -35391,8 +35408,12 @@ class GodotServer {
|
|
|
35391
35408
|
console.error("gdharness running on stdio");
|
|
35392
35409
|
sweepAbandonedScratch();
|
|
35393
35410
|
try {
|
|
35394
|
-
|
|
35395
|
-
|
|
35411
|
+
try {
|
|
35412
|
+
await this.takeOverFromAPredecessor();
|
|
35413
|
+
await this.godotBridge.start();
|
|
35414
|
+
} finally {
|
|
35415
|
+
this.handingOverFrom = null;
|
|
35416
|
+
}
|
|
35396
35417
|
this.bridgeStartupError = null;
|
|
35397
35418
|
const bridgeStatus = this.godotBridge.getStatus();
|
|
35398
35419
|
console.error(`[SERVER] Godot Editor Bridge started on ${bridgeStatus.host}:${bridgeStatus.port}`);
|
|
@@ -35432,7 +35453,6 @@ class GodotServer {
|
|
|
35432
35453
|
await delay3(HANDOVER_POLL_MS);
|
|
35433
35454
|
}
|
|
35434
35455
|
}
|
|
35435
|
-
this.handingOverFrom = null;
|
|
35436
35456
|
this.notHandedOverBy = taken ? null : announced.pid;
|
|
35437
35457
|
}
|
|
35438
35458
|
keepTryingTheBridge() {
|
|
@@ -35464,10 +35484,9 @@ class GodotServer {
|
|
|
35464
35484
|
if (this.ownProject === null) {
|
|
35465
35485
|
return;
|
|
35466
35486
|
}
|
|
35467
|
-
const status = this.godotBridge.getStatus();
|
|
35468
35487
|
this.announcedAt = announceBridge(this.ownProject, {
|
|
35469
|
-
host:
|
|
35470
|
-
port:
|
|
35488
|
+
host: this.godotBridge.getStatus().host,
|
|
35489
|
+
port: this.godotBridge.port,
|
|
35471
35490
|
version: SERVER_VERSION
|
|
35472
35491
|
});
|
|
35473
35492
|
this.watchForASuccessor();
|
|
@@ -37410,19 +37429,22 @@ class GodotServer {
|
|
|
37410
37429
|
return { note: owed, underway: restartUnderway(owed) };
|
|
37411
37430
|
}
|
|
37412
37431
|
async getEditorStatusPayload() {
|
|
37432
|
+
const wasConnected = this.godotBridge.getStatus().connected;
|
|
37433
|
+
const launchedWasUp = !wasConnected && await this.launchedEditorIsUp();
|
|
37434
|
+
const arrivingFound = wasConnected || this.ownProject === null ? [] : await this.editorsNotYetConnected(this.ownProject) ?? [];
|
|
37413
37435
|
const status = this.godotBridge.getStatus();
|
|
37414
|
-
const launchedIsUp = !status.connected &&
|
|
37436
|
+
const launchedIsUp = !status.connected && launchedWasUp;
|
|
37437
|
+
const arriving = status.connected ? [] : arrivingFound;
|
|
37415
37438
|
const isPortConflict = this.bridgeStartupError?.includes("EADDRINUSE") ?? false;
|
|
37416
37439
|
const greeted = hasSaidWhoItIs(status);
|
|
37417
37440
|
const stale = greeted && editorIsStale(status.addonVersion, SERVER_VERSION, status.addonDigest, shippedEditorDigest());
|
|
37418
37441
|
const unfinished = this.restartLeftUnfinished(status.connected);
|
|
37419
|
-
const arriving = status.connected || this.ownProject === null ? [] : await this.editorsNotYetConnected(this.ownProject) ?? [];
|
|
37420
37442
|
return {
|
|
37421
37443
|
...status,
|
|
37422
37444
|
serverVersion: SERVER_VERSION,
|
|
37423
37445
|
addonIsStale: greeted ? stale : undefined,
|
|
37424
37446
|
greeting: status.connected && !greeted ? "The editor has connected and has not yet said who it is: its project, pid, addon version and ports arrive with its greeting a moment after the socket opens, later while it imports. Ask again for them." : undefined,
|
|
37425
|
-
bridgeAvailable: this.bridgeStartupError === null,
|
|
37447
|
+
bridgeAvailable: this.bridgeStartupError === null && status.port !== null,
|
|
37426
37448
|
mayYetConnect: status.connected ? undefined : arriving.length > 0 ? true : unfinished !== null ? unfinished.underway : anEditorIsStillComing(status.listeningSince, launchedIsUp),
|
|
37427
37449
|
editorsNotYetConnected: arriving.length > 0 ? arriving : undefined,
|
|
37428
37450
|
restartInterrupted: unfinished === null || unfinished.underway || arriving.length > 0 ? undefined : {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.53",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|