gdharness 1.3.56 → 1.3.57

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
@@ -1784,12 +1784,16 @@ function slotsDrawnOn(count, taker, queue) {
1784
1784
  function inAGate(env = process4.env) {
1785
1785
  return nonEmpty(env[SHARE_VARIABLE]) !== undefined && nonEmpty(env[SHARE_COUNT_VARIABLE]) !== undefined;
1786
1786
  }
1787
- function inheritsSlot(tree, pid, holder, executable) {
1787
+ function inheritsSlot(tree, pid, holder, executable, engineStarted) {
1788
1788
  const program = (name) => name.toLowerCase().replace(/\.(?:exe|cmd|bat|com)$/, "");
1789
1789
  const own = program(executable);
1790
- for (const above of ancestorsIn(tree, pid, holder)) {
1790
+ for (const above of ancestorsIn(tree, pid, holder.pid)) {
1791
1791
  if (program(readCommandLine(tree.get(above)?.command ?? "").executable) !== own) {
1792
- return above === holder;
1792
+ if (above === holder.pid) {
1793
+ return true;
1794
+ }
1795
+ const started = tree.get(above)?.startedAt ?? engineStarted;
1796
+ return above === holder.engine?.pid && started !== undefined && Math.abs(started - holder.engine.started) <= START_TOLERANCE_MS;
1793
1797
  }
1794
1798
  }
1795
1799
  return false;
@@ -1854,20 +1858,29 @@ function holderOf(content) {
1854
1858
  if (typeof parsed !== "object" || parsed === null) {
1855
1859
  return null;
1856
1860
  }
1857
- const { pid, started, by, game } = parsed;
1858
- if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof started !== "number") {
1861
+ const { by, game, engine } = parsed;
1862
+ const named = namedProcess(parsed);
1863
+ if (named === null) {
1859
1864
  return null;
1860
1865
  }
1866
+ const runs = namedProcess(engine);
1861
1867
  return {
1862
- pid,
1863
- started,
1868
+ ...named,
1864
1869
  ...typeof by === "string" && by !== "" ? { by } : {},
1865
- ...game === true ? { game } : {}
1870
+ ...game === true ? { game } : {},
1871
+ ...runs === null ? {} : { engine: runs }
1866
1872
  };
1867
1873
  } catch {
1868
1874
  return null;
1869
1875
  }
1870
1876
  }
1877
+ function namedProcess(value) {
1878
+ if (typeof value !== "object" || value === null) {
1879
+ return null;
1880
+ }
1881
+ const { pid, started } = value;
1882
+ return typeof pid === "number" && Number.isInteger(pid) && pid > 0 && typeof started === "number" ? { pid, started } : null;
1883
+ }
1871
1884
  function lockIsFree(content, writtenAt, now, isAlive, startOf) {
1872
1885
  const holder = holderOf(content);
1873
1886
  if (holder === null) {
@@ -1981,7 +1994,9 @@ class EngineSlots {
1981
1994
  return null;
1982
1995
  }
1983
1996
  const tree = await processTree();
1984
- return tree !== undefined && inheritsSlot(tree, process4.pid, holder.pid, basename3(process4.execPath)) ? lock : null;
1997
+ const engine = holder.engine?.pid;
1998
+ const engineStarted = engine === undefined || tree?.get(engine)?.startedAt !== undefined ? undefined : (await startTimesOf([engine])).get(engine);
1999
+ return tree !== undefined && inheritsSlot(tree, process4.pid, holder, basename3(process4.execPath), engineStarted) ? lock : null;
1985
2000
  }
1986
2001
  markWaiting() {
1987
2002
  const mark = this.waitMarked();
@@ -2172,6 +2187,45 @@ function handSlot(lock, from, to) {
2172
2187
  const holder = content === null ? null : holderOf(content);
2173
2188
  return holder?.pid === from && writeWhole(lock, JSON.stringify(holder.game === true ? { ...to, game: true } : to));
2174
2189
  }
2190
+ function nameSlotEngine(lock, holder, engine) {
2191
+ let content;
2192
+ try {
2193
+ content = readWhole(lock);
2194
+ } catch {
2195
+ return false;
2196
+ }
2197
+ const named = content === null ? null : holderOf(content);
2198
+ return named?.pid === holder && writeWhole(lock, JSON.stringify({ ...named, engine }));
2199
+ }
2200
+ async function nameSlotEngineOf(lock, holder, pid) {
2201
+ const started = (await startTimesOf([pid])).get(pid);
2202
+ if (started !== undefined) {
2203
+ nameSlotEngine(lock, holder, { pid, started });
2204
+ }
2205
+ }
2206
+ async function slotEngineNamed(lock, run, pidFile) {
2207
+ if (pidFile === undefined) {
2208
+ if (run.pid !== null) {
2209
+ await nameSlotEngineOf(lock, process4.pid, run.pid);
2210
+ }
2211
+ return;
2212
+ }
2213
+ const state = { settled: false };
2214
+ run.settled.finally(() => {
2215
+ state.settled = true;
2216
+ });
2217
+ while (!state.settled) {
2218
+ let written = Number.NaN;
2219
+ try {
2220
+ written = Number(readFileSync6(pidFile, "utf8").trim());
2221
+ } catch {}
2222
+ if (Number.isInteger(written) && written > 0) {
2223
+ await nameSlotEngineOf(lock, process4.pid, written);
2224
+ return;
2225
+ }
2226
+ await delay2(ENGINE_PID_LOOK_MS);
2227
+ }
2228
+ }
2175
2229
  function giveBackSlot(lock, pid) {
2176
2230
  try {
2177
2231
  if (holderOf(readFileSync6(lock, "utf8"))?.pid === pid) {
@@ -2290,7 +2344,7 @@ async function inASlot(body) {
2290
2344
  held.release();
2291
2345
  }
2292
2346
  }
2293
- var HELD_VARIABLE = "GODOT_ENGINE_HELD", SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 2, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", QUEUED_FOLDER = "queued", SHARE_VARIABLE = "GODOT_ENGINE_SHARE", SHARE_COUNT_VARIABLE = "GODOT_ENGINE_SHARE_COUNT", GATE_KEPT = 1, TIMED_VARIABLE = "GODOT_ENGINE_TIMED", TIER_VARIABLE = "GODOT_ENGINE_TIER", SEATED_SUFFIX = ".seated", waitsMarked = 0, ours, saidTo, takenBy;
2347
+ var HELD_VARIABLE = "GODOT_ENGINE_HELD", SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 2, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", QUEUED_FOLDER = "queued", SHARE_VARIABLE = "GODOT_ENGINE_SHARE", SHARE_COUNT_VARIABLE = "GODOT_ENGINE_SHARE_COUNT", GATE_KEPT = 1, TIMED_VARIABLE = "GODOT_ENGINE_TIMED", TIER_VARIABLE = "GODOT_ENGINE_TIER", SEATED_SUFFIX = ".seated", waitsMarked = 0, ENGINE_PID_LOOK_MS = 100, ours, saidTo, takenBy;
2294
2348
  var init_engine_slots = __esm(() => {
2295
2349
  init_alive();
2296
2350
  init_cache_home();
@@ -13189,9 +13243,13 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
13189
13243
  return;
13190
13244
  }
13191
13245
  };
13246
+ const found = (engine) => {
13247
+ watching(engine, true);
13248
+ nameSlotEngineOf(lock, process7.pid, engine);
13249
+ };
13192
13250
  let pid = engineAt();
13193
13251
  if (pid !== undefined) {
13194
- watching(pid, true);
13252
+ found(pid);
13195
13253
  }
13196
13254
  try {
13197
13255
  let size = 0;
@@ -13206,7 +13264,7 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
13206
13264
  if (pid === undefined) {
13207
13265
  pid = engineAt();
13208
13266
  if (pid !== undefined) {
13209
- watching(pid, true);
13267
+ found(pid);
13210
13268
  }
13211
13269
  }
13212
13270
  const taken = await sample();
@@ -14023,6 +14081,9 @@ function runStarted(executable, args, lock, options, signal) {
14023
14081
  env: onTheSlot(process.env, lock),
14024
14082
  ...signal === undefined ? {} : { signal }
14025
14083
  });
14084
+ if (child.pid !== undefined) {
14085
+ nameSlotEngineOf(lock, process.pid, child.pid);
14086
+ }
14026
14087
  child.stdout.on("data", (chunk) => {
14027
14088
  log.append("stdout", chunk);
14028
14089
  });
@@ -19119,7 +19180,7 @@ var init_tool_definitions = __esm(() => {
19119
19180
  },
19120
19181
  wait: {
19121
19182
  effect: "read",
19122
- summary: "wait for the run to end, then answer as editor_output does",
19183
+ summary: "wait for the run to end, or to be held by its debugger at a breakpoint, a pause or a step, then answer as editor_output does",
19123
19184
  requires: []
19124
19185
  },
19125
19186
  profile: {
@@ -56713,6 +56774,7 @@ ${error.text}`;
56713
56774
  try {
56714
56775
  const run = this.spawnHeld(godotPath, cmdArgs, onTheSlot(env ?? process.env, held.lock), onDesktop);
56715
56776
  run.settled.finally(held.release);
56777
+ slotEngineNamed(held.lock, run, onDesktop?.files.pid);
56716
56778
  return run;
56717
56779
  } catch (error) {
56718
56780
  held.release();
@@ -57455,14 +57517,33 @@ ${error.text}`;
57455
57517
  return elsewhere;
57456
57518
  }
57457
57519
  const budgetMs = readPositiveNumber(args, "timeoutMs") ?? WAIT_FOR_RUN_MS;
57458
- const until = Date.now() + budgetMs;
57520
+ const began = Date.now();
57521
+ const until = began + budgetMs;
57459
57522
  const cancelled = callSignal();
57523
+ let held = false;
57524
+ let holdAsked = 0;
57460
57525
  while (cancelled?.aborted !== true && await this.runStillGoing(run) && Date.now() < until) {
57461
57526
  this.drainEditorOutput(run);
57462
57527
  this.drainTranscript(run);
57528
+ if (Date.now() - holdAsked >= HOLD_ASKED_EVERY_MS) {
57529
+ holdAsked = Date.now();
57530
+ if (await this.heldByItsDebugger(run)) {
57531
+ held = true;
57532
+ break;
57533
+ }
57534
+ }
57463
57535
  await delay8(RUN_POLL_MS);
57464
57536
  }
57465
- return await this.handleGetDebugOutput(args, await this.runStillGoing(run) ? budgetMs : undefined);
57537
+ if (!await this.runStillGoing(run)) {
57538
+ return await this.handleGetDebugOutput(args);
57539
+ }
57540
+ return await this.handleGetDebugOutput(args, held ? { heldAfterMs: Date.now() - began } : { ranOutMs: budgetMs });
57541
+ }
57542
+ async heldByItsDebugger(run) {
57543
+ if (!run.throughEditor) {
57544
+ return run.keeper !== undefined && await this.keptHold(run.keeper) !== null;
57545
+ }
57546
+ return this.dapClient?.holdIsKnown() === true && this.dapClient.whereItStopped() !== null;
57466
57547
  }
57467
57548
  async runStillGoing(run, editorSays) {
57468
57549
  if (!run.throughEditor) {
@@ -57611,7 +57692,7 @@ ${error.text}`;
57611
57692
  "editor_status names every game running on the machine under runtimes"
57612
57693
  ]);
57613
57694
  }
57614
- async handleGetDebugOutput(args, waitedMs) {
57695
+ async handleGetDebugOutput(args, waited) {
57615
57696
  if (readString(args, "op") === "editor") {
57616
57697
  return this.handleEditorConsole(args);
57617
57698
  }
@@ -57648,8 +57729,11 @@ ${error.text}`;
57648
57729
  if (wanted && cpuSeconds === undefined && stillRunning(run)) {
57649
57730
  notes.push(processToAsk === null ? "cpu was asked for and there is no process to ask: the editor is playing this run and holds it, and the game announced no runtime, so nothing here has its process id. A game with the runtime addon announces one; editor_run start without a connected editor, or with args, starts the game here instead and that run answers cpuSeconds either way." : "cpu was asked for and this platform would not say what the run has used.");
57650
57731
  }
57651
- if (waitedMs !== undefined) {
57652
- notes.push(`The wait of ${waitedMs}ms ran out and the run is still going, so this is what it had printed by then rather than everything it will print. editor_run wait again to keep waiting.`);
57732
+ if (waited !== undefined && "ranOutMs" in waited) {
57733
+ notes.push(`The wait of ${waited.ranOutMs}ms ran out and the run is still going, so this is what it had printed by then rather than everything it will print. editor_run wait again to keep waiting.`);
57734
+ }
57735
+ if (waited !== undefined && "heldAfterMs" in waited) {
57736
+ notes.push(`The wait answered after ${waited.heldAfterMs}ms because the game is held by its debugger, where heldAt says, and a held game does not end: debug_control continue lets it go, and editor_run wait then waits on.`);
57653
57737
  }
57654
57738
  const restarts = run.restartedFrom ?? [];
57655
57739
  if (restarts.length > 0) {
@@ -59507,7 +59591,7 @@ async function runGodotServer() {
59507
59591
  const server = new GodotServer;
59508
59592
  await server.run();
59509
59593
  }
59510
- var TYPE_ARGUMENTS, UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, SLOW_ANSWER_MS = 1000, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
59594
+ var TYPE_ARGUMENTS, UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, SLOW_ANSWER_MS = 1000, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, HOLD_ASKED_EVERY_MS = 1000, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
59511
59595
  var init_server = __esm(() => {
59512
59596
  init_dist2();
59513
59597
  init_stdio();
package/build/keeper.js CHANGED
@@ -8833,20 +8833,29 @@ function holderOf(content) {
8833
8833
  if (typeof parsed !== "object" || parsed === null) {
8834
8834
  return null;
8835
8835
  }
8836
- const { pid, started, by, game } = parsed;
8837
- if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof started !== "number") {
8836
+ const { by, game, engine } = parsed;
8837
+ const named = namedProcess(parsed);
8838
+ if (named === null) {
8838
8839
  return null;
8839
8840
  }
8841
+ const runs = namedProcess(engine);
8840
8842
  return {
8841
- pid,
8842
- started,
8843
+ ...named,
8843
8844
  ...typeof by === "string" && by !== "" ? { by } : {},
8844
- ...game === true ? { game } : {}
8845
+ ...game === true ? { game } : {},
8846
+ ...runs === null ? {} : { engine: runs }
8845
8847
  };
8846
8848
  } catch {
8847
8849
  return null;
8848
8850
  }
8849
8851
  }
8852
+ function namedProcess(value) {
8853
+ if (typeof value !== "object" || value === null) {
8854
+ return null;
8855
+ }
8856
+ const { pid, started } = value;
8857
+ return typeof pid === "number" && Number.isInteger(pid) && pid > 0 && typeof started === "number" ? { pid, started } : null;
8858
+ }
8850
8859
  async function ownStart() {
8851
8860
  const said = (await startTimesOf([process4.pid])).get(process4.pid);
8852
8861
  return said ?? Math.round(Date.now() - process4.uptime() * 1000);
@@ -8861,6 +8870,16 @@ function handSlot(lock, from, to) {
8861
8870
  const holder = content === null ? null : holderOf(content);
8862
8871
  return holder?.pid === from && writeWhole(lock, JSON.stringify(holder.game === true ? { ...to, game: true } : to));
8863
8872
  }
8873
+ function nameSlotEngine(lock, holder, engine) {
8874
+ let content;
8875
+ try {
8876
+ content = readWhole(lock);
8877
+ } catch {
8878
+ return false;
8879
+ }
8880
+ const named = content === null ? null : holderOf(content);
8881
+ return named?.pid === holder && writeWhole(lock, JSON.stringify({ ...named, engine }));
8882
+ }
8864
8883
  function giveBackSlot(lock, pid) {
8865
8884
  try {
8866
8885
  if (holderOf(readFileSync5(lock, "utf8"))?.pid === pid) {
@@ -11067,10 +11086,12 @@ async function keep() {
11067
11086
  });
11068
11087
  const slot = run?.slot;
11069
11088
  if (slot !== undefined && keeperStarted !== undefined) {
11089
+ const gameStarted = (await startTimesOf([pid])).get(pid);
11070
11090
  handSlot(slot.lock, slot.from, {
11071
11091
  pid: process.pid,
11072
11092
  started: await keeperStarted,
11073
- by: `${slot.by}, through the keeper process that runs it`
11093
+ by: `${slot.by}, through the keeper process that runs it`,
11094
+ ...gameStarted === undefined ? {} : { engine: { pid, started: gameStarted } }
11074
11095
  });
11075
11096
  }
11076
11097
  let { code, signal } = await exited;
@@ -11106,6 +11127,9 @@ async function keep() {
11106
11127
  restartedFrom: [...note.restartedFrom ?? [], before]
11107
11128
  };
11108
11129
  writeNoteIfItCan(note);
11130
+ if (slot !== undefined) {
11131
+ nameSlotEngine(slot.lock, process.pid, { pid: next.pid, started: next.startedAt });
11132
+ }
11109
11133
  end = () => {
11110
11134
  try {
11111
11135
  process.kill(next.pid);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdharness",
3
- "version": "1.3.56",
3
+ "version": "1.3.57",
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",