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 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.port,
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
- stranger?.close(OTHER_PROJECT_CLOSE_CODE, said);
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
- await this.takeOverFromAPredecessor();
42908
- await this.godotBridge.start();
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: status.host,
42983
- port: status.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 && await this.launchedEditorIsUp();
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.port,
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
- stranger?.close(OTHER_PROJECT_CLOSE_CODE, said);
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
- await this.takeOverFromAPredecessor();
35395
- await this.godotBridge.start();
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: status.host,
35470
- port: status.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 && await this.launchedEditorIsUp();
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.52",
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",