gdharness 0.12.15 → 0.12.17

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
@@ -7467,6 +7467,13 @@ function addonMismatch(addonVersion, serverVersion) {
7467
7467
  }
7468
7468
  return `${both} Restart it with editor_launch restart to pick the new one up.`;
7469
7469
  }
7470
+ function markIfStale(answer, addonVersion, serverVersion) {
7471
+ const staleNote = addonMismatch(addonVersion, serverVersion);
7472
+ if (staleNote === undefined || typeof answer !== "object" || answer === null || Array.isArray(answer)) {
7473
+ return answer;
7474
+ }
7475
+ return { ...answer, addonIsStale: true, staleNote };
7476
+ }
7470
7477
  var DEBUG_MODE, GODOT_DEBUG_MODE_DEFAULT, SERVER_VERSION, UNVERSIONED = "addon from before versions were reported";
7471
7478
  var init_server_version = __esm(() => {
7472
7479
  init_update_check();
@@ -36159,6 +36166,16 @@ function writeRunRecord(record) {
36159
36166
  mkdirSync6(runsDirectory(), { recursive: true });
36160
36167
  writeFileSync8(recordPath(), JSON.stringify(record, null, 2), "utf8");
36161
36168
  }
36169
+ function recordRunEnded(pid, exitCode) {
36170
+ const path = recordPath();
36171
+ const record = recordAt(path);
36172
+ if (record === null || record.pid !== pid) {
36173
+ return;
36174
+ }
36175
+ try {
36176
+ writeFileSync8(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
36177
+ } catch {}
36178
+ }
36162
36179
  function readRunRecord() {
36163
36180
  for (const path of recordPaths()) {
36164
36181
  const record = recordAt(path);
@@ -36192,7 +36209,8 @@ function recordAt(path) {
36192
36209
  startedAt,
36193
36210
  projectPath: typeof fields["projectPath"] === "string" ? fields["projectPath"] : "",
36194
36211
  arguments: Array.isArray(args) ? args.filter((value) => typeof value === "string") : [],
36195
- ...typeof fields["command"] === "string" ? { command: fields["command"] } : {}
36212
+ ...typeof fields["command"] === "string" ? { command: fields["command"] } : {},
36213
+ ...typeof fields["exitCode"] === "number" ? { exitCode: fields["exitCode"] } : {}
36196
36214
  };
36197
36215
  }
36198
36216
  function runningAs(pid) {
@@ -38006,6 +38024,9 @@ class GodotServer {
38006
38024
  this.logDebug(`Godot process exited with code ${code ?? "none"}`);
38007
38025
  log.finish();
38008
38026
  started.exitCode = code ?? -1;
38027
+ if (started.pid !== null) {
38028
+ recordRunEnded(started.pid, started.exitCode);
38029
+ }
38009
38030
  });
38010
38031
  child.on("error", (err) => {
38011
38032
  console.error("Failed to start Godot process:", err);
@@ -38110,8 +38131,8 @@ class GodotServer {
38110
38131
  this.drainTranscript(adopted);
38111
38132
  if (!alive(record.pid) || !couldStillBeTheRecordedRun(record)) {
38112
38133
  adopted.log.finish();
38113
- adopted.exitCode = null;
38114
- adopted.endedUnwatched = true;
38134
+ adopted.exitCode = record.exitCode ?? null;
38135
+ adopted.endedUnwatched = record.exitCode === undefined;
38115
38136
  }
38116
38137
  this.activeProcess = adopted;
38117
38138
  return adopted;
@@ -38314,7 +38335,7 @@ class GodotServer {
38314
38335
  ]);
38315
38336
  }
38316
38337
  try {
38317
- return this.jsonTextResponse(await this.godotBridge.invokeTool(toolName, args));
38338
+ return this.jsonTextResponse(markIfStale(await this.godotBridge.invokeTool(toolName, args), this.godotBridge.getStatus().addonVersion, SERVER_VERSION));
38318
38339
  } catch (error) {
38319
38340
  return this.createErrorResponse(`The editor answered ${toolName} with an error: ${errorMessage(error)}`);
38320
38341
  }
@@ -39897,7 +39918,9 @@ that is running, and the project on disk. ${TOOL_SPECS.length} tools, named \`do
39897
39918
  running games. There is no ambient project.
39898
39919
  - \`editor_status\` says whether an editor is connected and whether its addon matches the server.
39899
39920
  \`addonIsStale\` means they differ, and \`staleNote\` says which half is behind: an editor that
39900
- needs restarting, or a server that needs reconnecting in your harness.
39921
+ needs restarting, or a server that needs reconnecting in your harness. Every answer that came
39922
+ from the editor carries the same two when they differ, so a stale addon cannot answer quietly:
39923
+ believe a restart over a diagnostic that arrived with them.
39901
39924
  - Start the game with \`editor_run start\`, never by spawning an engine. The editor plays it, so
39902
39925
  its debugger holds it, which is what gives the \`debug_*\` tools something to talk to. Its answer
39903
39926
  says under \`runtime\` whether the game can be talked to yet; when it cannot, \`mayYetAnnounce\`
package/build/index.js CHANGED
@@ -10040,6 +10040,13 @@ function addonMismatch(addonVersion, serverVersion) {
10040
10040
  }
10041
10041
  return `${both} Restart it with editor_launch restart to pick the new one up.`;
10042
10042
  }
10043
+ function markIfStale(answer, addonVersion, serverVersion) {
10044
+ const staleNote = addonMismatch(addonVersion, serverVersion);
10045
+ if (staleNote === undefined || typeof answer !== "object" || answer === null || Array.isArray(answer)) {
10046
+ return answer;
10047
+ }
10048
+ return { ...answer, addonIsStale: true, staleNote };
10049
+ }
10043
10050
 
10044
10051
  // src/issues.ts
10045
10052
  var NEW_ISSUE = "https://github.com/Aureliolo/gdharness/issues/new";
@@ -27841,6 +27848,16 @@ function writeRunRecord(record) {
27841
27848
  mkdirSync3(runsDirectory(), { recursive: true });
27842
27849
  writeFileSync4(recordPath(), JSON.stringify(record, null, 2), "utf8");
27843
27850
  }
27851
+ function recordRunEnded(pid, exitCode) {
27852
+ const path = recordPath();
27853
+ const record = recordAt(path);
27854
+ if (record === null || record.pid !== pid) {
27855
+ return;
27856
+ }
27857
+ try {
27858
+ writeFileSync4(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
27859
+ } catch {}
27860
+ }
27844
27861
  function readRunRecord() {
27845
27862
  for (const path of recordPaths()) {
27846
27863
  const record = recordAt(path);
@@ -27874,7 +27891,8 @@ function recordAt(path) {
27874
27891
  startedAt,
27875
27892
  projectPath: typeof fields["projectPath"] === "string" ? fields["projectPath"] : "",
27876
27893
  arguments: Array.isArray(args) ? args.filter((value) => typeof value === "string") : [],
27877
- ...typeof fields["command"] === "string" ? { command: fields["command"] } : {}
27894
+ ...typeof fields["command"] === "string" ? { command: fields["command"] } : {},
27895
+ ...typeof fields["exitCode"] === "number" ? { exitCode: fields["exitCode"] } : {}
27878
27896
  };
27879
27897
  }
27880
27898
  function runningAs(pid) {
@@ -30789,6 +30807,9 @@ class GodotServer {
30789
30807
  this.logDebug(`Godot process exited with code ${code ?? "none"}`);
30790
30808
  log.finish();
30791
30809
  started.exitCode = code ?? -1;
30810
+ if (started.pid !== null) {
30811
+ recordRunEnded(started.pid, started.exitCode);
30812
+ }
30792
30813
  });
30793
30814
  child.on("error", (err) => {
30794
30815
  console.error("Failed to start Godot process:", err);
@@ -30893,8 +30914,8 @@ class GodotServer {
30893
30914
  this.drainTranscript(adopted);
30894
30915
  if (!alive(record.pid) || !couldStillBeTheRecordedRun(record)) {
30895
30916
  adopted.log.finish();
30896
- adopted.exitCode = null;
30897
- adopted.endedUnwatched = true;
30917
+ adopted.exitCode = record.exitCode ?? null;
30918
+ adopted.endedUnwatched = record.exitCode === undefined;
30898
30919
  }
30899
30920
  this.activeProcess = adopted;
30900
30921
  return adopted;
@@ -31097,7 +31118,7 @@ class GodotServer {
31097
31118
  ]);
31098
31119
  }
31099
31120
  try {
31100
- return this.jsonTextResponse(await this.godotBridge.invokeTool(toolName, args));
31121
+ return this.jsonTextResponse(markIfStale(await this.godotBridge.invokeTool(toolName, args), this.godotBridge.getStatus().addonVersion, SERVER_VERSION));
31101
31122
  } catch (error) {
31102
31123
  return this.createErrorResponse(`The editor answered ${toolName} with an error: ${errorMessage(error)}`);
31103
31124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdharness",
3
- "version": "0.12.15",
3
+ "version": "0.12.17",
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",