gdharness 0.13.10 → 0.13.12

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
@@ -7281,6 +7281,32 @@ var init_game_log = __esm(() => {
7281
7281
  STREAMS = ["stdout", "stderr", "transcript"];
7282
7282
  });
7283
7283
 
7284
+ // src/scratch.ts
7285
+ import { rmSync as rmSync2 } from "node:fs";
7286
+ function discardWith(remove, paths) {
7287
+ const left = [];
7288
+ for (const path of paths) {
7289
+ if (!path) {
7290
+ continue;
7291
+ }
7292
+ try {
7293
+ remove(path);
7294
+ } catch (error) {
7295
+ left.push({ path, reason: error instanceof Error ? error.message : String(error) });
7296
+ }
7297
+ }
7298
+ return left;
7299
+ }
7300
+ function discard(...paths) {
7301
+ return discardWith((path) => {
7302
+ rmSync2(path, SWEPT);
7303
+ }, paths);
7304
+ }
7305
+ var SWEPT;
7306
+ var init_scratch = __esm(() => {
7307
+ SWEPT = { recursive: true, force: true, maxRetries: 20, retryDelay: 250 };
7308
+ });
7309
+
7284
7310
  // src/update-check.ts
7285
7311
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
7286
7312
  import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
@@ -7554,7 +7580,7 @@ var init_class_cache = () => {};
7554
7580
 
7555
7581
  // src/headless.ts
7556
7582
  import { execFile as execFile3 } from "node:child_process";
7557
- import { mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
7583
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync4 } from "node:fs";
7558
7584
  import { tmpdir as tmpdir3 } from "node:os";
7559
7585
  import { join as join7 } from "node:path";
7560
7586
  import { promisify as promisify3 } from "node:util";
@@ -7630,7 +7656,7 @@ async function runOperation2(engine, operation, params, projectPath) {
7630
7656
  messages: []
7631
7657
  };
7632
7658
  } finally {
7633
- rmSync3(paramsDir, { recursive: true, force: true });
7659
+ discard(paramsDir);
7634
7660
  }
7635
7661
  const payload = lastJsonObject2(stdout);
7636
7662
  if (payload === null) {
@@ -7645,6 +7671,7 @@ async function runOperation2(engine, operation, params, projectPath) {
7645
7671
  var run3;
7646
7672
  var init_headless = __esm(() => {
7647
7673
  init_game_log();
7674
+ init_scratch();
7648
7675
  run3 = promisify3(execFile3);
7649
7676
  });
7650
7677
 
@@ -14897,10 +14924,10 @@ function isValueComplete(value) {
14897
14924
  return depth <= 0 && !inString;
14898
14925
  }
14899
14926
  function settingKeys(content) {
14900
- const named = new Set;
14927
+ const named = new Map;
14901
14928
  for (const [section, entries] of Object.entries(parseProjectGodot(content))) {
14902
- for (const key of Object.keys(entries)) {
14903
- named.add(`${section}/${key}`);
14929
+ for (const [key, value] of Object.entries(entries)) {
14930
+ named.set(`${section}/${key}`, value);
14904
14931
  }
14905
14932
  }
14906
14933
  return named;
@@ -15787,7 +15814,10 @@ var init_tool_definitions = __esm(() => {
15787
15814
  summary: "run the project until it quits or is stopped",
15788
15815
  requires: ["projectPath"]
15789
15816
  },
15790
- stop: { summary: "end the run and answer with what it printed last", requires: [] },
15817
+ stop: {
15818
+ summary: "end the run and answer with what it printed last, naming the process ended under endedPid: a game that started processes of its own keeps them",
15819
+ requires: []
15820
+ },
15791
15821
  check: {
15792
15822
  summary: "boot headless, quit after a few frames, and report the verdict",
15793
15823
  requires: ["projectPath"]
@@ -30943,7 +30973,7 @@ var init_stdio2 = __esm(() => {
30943
30973
  });
30944
30974
 
30945
30975
  // src/bridge-announce.ts
30946
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync9, rmSync as rmSync6, writeFileSync as writeFileSync7 } from "node:fs";
30976
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync9, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
30947
30977
  import { dirname as dirname6, join as join11 } from "node:path";
30948
30978
  function announcementPath(projectPath) {
30949
30979
  return join11(projectPath, ".godot", "gdharness-bridge.json");
@@ -30991,7 +31021,7 @@ function withdrawBridge(path) {
30991
31021
  return;
30992
31022
  }
30993
31023
  try {
30994
- rmSync6(path, { force: true });
31024
+ rmSync5(path, { force: true });
30995
31025
  } catch (error) {
30996
31026
  console.error(`[SERVER] Could not withdraw the editor bridge announcement: ${errorMessage(error)}`);
30997
31027
  }
@@ -36327,7 +36357,7 @@ var init_runtime_client = __esm(() => {
36327
36357
 
36328
36358
  // src/run-record.ts
36329
36359
  import { execFileSync } from "node:child_process";
36330
- import { mkdirSync as mkdirSync6, openSync, readdirSync as readdirSync6, readFileSync as readFileSync13, rmSync as rmSync7, statSync as statSync3, writeFileSync as writeFileSync8 } from "node:fs";
36360
+ import { mkdirSync as mkdirSync6, openSync, readdirSync as readdirSync6, readFileSync as readFileSync13, rmSync as rmSync6, statSync as statSync3, writeFileSync as writeFileSync8 } from "node:fs";
36331
36361
  import { basename as basename2, join as join15 } from "node:path";
36332
36362
  function runsDirectory() {
36333
36363
  return join15(runtimeDirectory(), "runs");
@@ -36537,7 +36567,7 @@ function clearRunRecord(ours = () => true) {
36537
36567
  continue;
36538
36568
  }
36539
36569
  try {
36540
- rmSync7(path);
36570
+ rmSync6(path);
36541
36571
  } catch {}
36542
36572
  }
36543
36573
  }
@@ -36566,7 +36596,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
36566
36596
  continue;
36567
36597
  }
36568
36598
  try {
36569
- rmSync7(path);
36599
+ rmSync6(path);
36570
36600
  } catch {}
36571
36601
  }
36572
36602
  }
@@ -36575,7 +36605,7 @@ var init_run_record = __esm(() => {
36575
36605
  });
36576
36606
 
36577
36607
  // src/setup.ts
36578
- import { cpSync as cpSync2, existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync14, rmSync as rmSync8, writeFileSync as writeFileSync9 } from "node:fs";
36608
+ import { cpSync as cpSync2, existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync14, rmSync as rmSync7, writeFileSync as writeFileSync9 } from "node:fs";
36579
36609
  import { dirname as dirname8, join as join16 } from "node:path";
36580
36610
  function installedAddonVersion(projectPath) {
36581
36611
  const marker = join16(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
@@ -36611,8 +36641,7 @@ import {
36611
36641
  openSync as openSync2,
36612
36642
  readdirSync as readdirSync7,
36613
36643
  readFileSync as readFileSync15,
36614
- readSync,
36615
- rmSync as rmSync9
36644
+ readSync
36616
36645
  } from "node:fs";
36617
36646
  import { tmpdir as tmpdir5 } from "node:os";
36618
36647
  import { basename as basename3, dirname as dirname9, join as join17, normalize as normalize3 } from "node:path";
@@ -37689,7 +37718,7 @@ class GodotServer {
37689
37718
  log.append("stderr", failed.stderr);
37690
37719
  exitCode = typeof failed.code === "number" ? failed.code : -1;
37691
37720
  } finally {
37692
- rmSync9(exportLogs, { recursive: true, force: true });
37721
+ discard(exportLogs);
37693
37722
  }
37694
37723
  log.finish();
37695
37724
  const problems = log.select({ severity: "warning", sinceLastCall: false, limit: 200 });
@@ -37787,8 +37816,7 @@ class GodotServer {
37787
37816
  } catch (error) {
37788
37817
  reportProblem = errorMessage(error);
37789
37818
  } finally {
37790
- rmSync9(reportsDir, { recursive: true, force: true });
37791
- rmSync9(userData, { recursive: true, force: true });
37819
+ discard(reportsDir, userData);
37792
37820
  }
37793
37821
  const engineEntries = run.log.select({ severity: "warning", sinceLastCall: false, limit: 200 }).entries.map(aboveTheRunner);
37794
37822
  const verdicts = {
@@ -38030,12 +38058,12 @@ class GodotServer {
38030
38058
  }
38031
38059
  settingKeysOf(projectPath) {
38032
38060
  if (projectPath === undefined) {
38033
- return new Set;
38061
+ return new Map;
38034
38062
  }
38035
38063
  try {
38036
38064
  return settingKeys(readFileSync15(join17(projectPath, "project.godot"), "utf8"));
38037
38065
  } catch {
38038
- return new Set;
38066
+ return new Map;
38039
38067
  }
38040
38068
  }
38041
38069
  async handleRestartEditor() {
@@ -38067,7 +38095,7 @@ class GodotServer {
38067
38095
  }
38068
38096
  const now = this.godotBridge.getStatus();
38069
38097
  const after = this.settingKeysOf(before.projectPath);
38070
- const dropped = [...settingsBefore].filter((key) => !after.has(key));
38098
+ const dropped = [...settingsBefore].filter(([key]) => !after.has(key));
38071
38099
  return this.jsonTextResponse({
38072
38100
  restarted: true,
38073
38101
  editorPid: now.editorPid,
@@ -38075,8 +38103,8 @@ class GodotServer {
38075
38103
  serverVersion: SERVER_VERSION,
38076
38104
  addonIsStale: now.addonVersion !== SERVER_VERSION,
38077
38105
  staleNote: addonMismatch(now.addonVersion, SERVER_VERSION),
38078
- settingsDropped: dropped.length > 0 ? dropped : undefined,
38079
- settingsNote: dropped.length > 0 ? 'The editor saved project.godot on its way out and these keys are no longer in it. Godot writes only what differs from its own defaults, so a key named deliberately at its default value is redundant to the editor and is dropped on save. If any of them were pinned on purpose, to keep "set to this on purpose" and "not set" apart, put them back: nothing else will say they have gone until something depends on one.' : undefined,
38106
+ settingsDropped: dropped.length > 0 ? dropped.map(([setting, was]) => ({ setting, was })) : undefined,
38107
+ settingsNote: dropped.length > 0 ? `The editor saved project.godot on its way out and these keys are no longer in it, with the value each one held. Godot writes only what differs from its own defaults, so a key named deliberately at its default value is redundant to the editor and is dropped on save; it will be dropped again on the next restart. If any of them were pinned on purpose, to keep "set to this on purpose" and "not set" apart, project_settings set puts one back: ${dropped.map(([setting, was]) => `setting "${setting}" value ${JSON.stringify(was)}`).join(", ")}. Nothing else will say they have gone until something depends on one.` : undefined,
38080
38108
  tookMs: Date.now() - began
38081
38109
  });
38082
38110
  }
@@ -38701,11 +38729,13 @@ class GodotServer {
38701
38729
  return this.jsonTextResponse({
38702
38730
  stopped: true,
38703
38731
  through: stopped.throughEditor ? "editor" : "gdharness",
38732
+ endedPid: stopped.pid,
38704
38733
  exitedBeforeStop: stopped.exitCode !== null,
38705
38734
  exitCode: stopped.exitCode,
38706
38735
  errors: stopped.log.count("error"),
38707
38736
  warnings: stopped.log.count("warning"),
38708
38737
  clean: stopped.log.count("error") === 0,
38738
+ note: stopped.throughEditor ? "The editor was asked to stop the scene it is playing. Anything that game started for itself, with OS.create_process or otherwise, is not the editor's to stop and is still running." : "The process named under endedPid was ended. Anything that game started for itself, with OS.create_process or otherwise, is a separate process and is still running.",
38709
38739
  entries: forAnswer(stopped.log.select({ severity: "warning", sinceLastCall: false, limit: 200 }).entries)
38710
38740
  });
38711
38741
  }
@@ -38865,9 +38895,7 @@ class GodotServer {
38865
38895
  ]
38866
38896
  };
38867
38897
  } finally {
38868
- if (screenshotDir) {
38869
- rmSync9(screenshotDir, { recursive: true, force: true });
38870
- }
38898
+ discard(screenshotDir);
38871
38899
  }
38872
38900
  }
38873
38901
  async handleFindRuntimeNodes(args) {
@@ -38954,6 +38982,7 @@ var init_server3 = __esm(() => {
38954
38982
  init_resources();
38955
38983
  init_run_record();
38956
38984
  init_runtime_client();
38985
+ init_scratch();
38957
38986
  init_server_version();
38958
38987
  init_setup();
38959
38988
  init_tool_definitions();
@@ -39906,8 +39935,9 @@ function taken(harness, path, held, stripped) {
39906
39935
 
39907
39936
  // src/headless.ts
39908
39937
  init_game_log();
39938
+ init_scratch();
39909
39939
  import { execFile as execFile2 } from "node:child_process";
39910
- import { mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
39940
+ import { mkdtempSync, writeFileSync as writeFileSync2 } from "node:fs";
39911
39941
  import { tmpdir } from "node:os";
39912
39942
  import { join as join4 } from "node:path";
39913
39943
  import { promisify as promisify2 } from "node:util";
@@ -39984,7 +40014,7 @@ async function runOperation(engine, operation, params, projectPath) {
39984
40014
  messages: []
39985
40015
  };
39986
40016
  } finally {
39987
- rmSync2(paramsDir, { recursive: true, force: true });
40017
+ discard(paramsDir);
39988
40018
  }
39989
40019
  const payload = lastJsonObject(stdout);
39990
40020
  if (payload === null) {
@@ -40133,7 +40163,7 @@ init_headless();
40133
40163
  init_resources();
40134
40164
  init_server_version();
40135
40165
  import { spawnSync } from "node:child_process";
40136
- import { cpSync, existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "node:fs";
40166
+ import { cpSync, existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
40137
40167
  import { dirname as dirname3, join as join8 } from "node:path";
40138
40168
  import { fileURLToPath } from "node:url";
40139
40169
  var ADDONS = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
@@ -40158,7 +40188,7 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
40158
40188
  }
40159
40189
  const target = join8(projectPath, "addons", name);
40160
40190
  const replaced = existsSync7(target);
40161
- rmSync4(target, { recursive: true, force: true });
40191
+ rmSync3(target, { recursive: true, force: true });
40162
40192
  mkdirSync3(dirname3(target), { recursive: true });
40163
40193
  cpSync(source, target, { recursive: true });
40164
40194
  writeFileSync5(join8(target, VERSION_MARKER), `${SERVER_VERSION}
@@ -40172,7 +40202,7 @@ function removeAddons(projectPath) {
40172
40202
  for (const name of ADDONS) {
40173
40203
  const target = join8(projectPath, "addons", name);
40174
40204
  if (existsSync7(target)) {
40175
- rmSync4(target, { recursive: true, force: true });
40205
+ rmSync3(target, { recursive: true, force: true });
40176
40206
  removed.push(target);
40177
40207
  }
40178
40208
  }
@@ -40301,7 +40331,7 @@ function inspectProject(projectPath) {
40301
40331
 
40302
40332
  // src/skill.ts
40303
40333
  init_tool_definitions();
40304
- import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
40334
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
40305
40335
  import { basename, dirname as dirname4, join as join9 } from "node:path";
40306
40336
 
40307
40337
  // src/tool-reference.ts
@@ -40546,7 +40576,7 @@ function removeSkill(directories, projectPath) {
40546
40576
  const removed = [];
40547
40577
  for (const directory of directories) {
40548
40578
  if (existsSync8(directory)) {
40549
- rmSync5(directory, { recursive: true, force: true });
40579
+ rmSync4(directory, { recursive: true, force: true });
40550
40580
  pruneEmpty(dirname4(directory), projectPath);
40551
40581
  removed.push(directory);
40552
40582
  }
@@ -40560,7 +40590,7 @@ function pruneEmpty(directory, projectPath) {
40560
40590
  if (readdirSync3(path).length > 0) {
40561
40591
  return;
40562
40592
  }
40563
- rmSync5(path, { recursive: true, force: true });
40593
+ rmSync4(path, { recursive: true, force: true });
40564
40594
  path = dirname4(path);
40565
40595
  }
40566
40596
  }
@@ -40568,7 +40598,7 @@ function writeSkill(directories, version) {
40568
40598
  const files = skillFiles(version);
40569
40599
  return directories.map((directory) => {
40570
40600
  const replaced = existsSync8(directory);
40571
- rmSync5(directory, { recursive: true, force: true });
40601
+ rmSync4(directory, { recursive: true, force: true });
40572
40602
  for (const [name, contents] of files) {
40573
40603
  const path = join9(directory, name);
40574
40604
  mkdirSync4(dirname4(path), { recursive: true });
package/build/index.js CHANGED
@@ -10151,8 +10151,7 @@ import {
10151
10151
  openSync as openSync2,
10152
10152
  readdirSync as readdirSync6,
10153
10153
  readFileSync as readFileSync11,
10154
- readSync,
10155
- rmSync as rmSync5
10154
+ readSync
10156
10155
  } from "node:fs";
10157
10156
  import { tmpdir as tmpdir4 } from "node:os";
10158
10157
  import { basename as basename2, dirname as dirname4, join as join11, normalize as normalize2 } from "node:path";
@@ -26324,10 +26323,35 @@ class GodotLocator {
26324
26323
 
26325
26324
  // src/headless.ts
26326
26325
  import { execFile as execFile2 } from "node:child_process";
26327
- import { mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
26326
+ import { mkdtempSync, writeFileSync as writeFileSync3 } from "node:fs";
26328
26327
  import { tmpdir as tmpdir2 } from "node:os";
26329
26328
  import { join as join6 } from "node:path";
26330
26329
  import { promisify as promisify2 } from "node:util";
26330
+
26331
+ // src/scratch.ts
26332
+ import { rmSync as rmSync2 } from "node:fs";
26333
+ var SWEPT = { recursive: true, force: true, maxRetries: 20, retryDelay: 250 };
26334
+ function discardWith(remove, paths) {
26335
+ const left = [];
26336
+ for (const path of paths) {
26337
+ if (!path) {
26338
+ continue;
26339
+ }
26340
+ try {
26341
+ remove(path);
26342
+ } catch (error) {
26343
+ left.push({ path, reason: error instanceof Error ? error.message : String(error) });
26344
+ }
26345
+ }
26346
+ return left;
26347
+ }
26348
+ function discard(...paths) {
26349
+ return discardWith((path) => {
26350
+ rmSync2(path, SWEPT);
26351
+ }, paths);
26352
+ }
26353
+
26354
+ // src/headless.ts
26331
26355
  var run2 = promisify2(execFile2);
26332
26356
  function snakeCased(params) {
26333
26357
  const result = emptyRecord();
@@ -26401,7 +26425,7 @@ async function runOperation(engine, operation, params, projectPath) {
26401
26425
  messages: []
26402
26426
  };
26403
26427
  } finally {
26404
- rmSync2(paramsDir, { recursive: true, force: true });
26428
+ discard(paramsDir);
26405
26429
  }
26406
26430
  const payload = lastJsonObject(stdout);
26407
26431
  if (payload === null) {
@@ -27558,10 +27582,10 @@ function isValueComplete(value) {
27558
27582
  return depth <= 0 && !inString;
27559
27583
  }
27560
27584
  function settingKeys(content) {
27561
- const named = new Set;
27585
+ const named = new Map;
27562
27586
  for (const [section, entries] of Object.entries(parseProjectGodot(content))) {
27563
- for (const key of Object.keys(entries)) {
27564
- named.add(`${section}/${key}`);
27587
+ for (const [key, value] of Object.entries(entries)) {
27588
+ named.set(`${section}/${key}`, value);
27565
27589
  }
27566
27590
  }
27567
27591
  return named;
@@ -28877,7 +28901,10 @@ var TOOL_SPECS = [
28877
28901
  summary: "run the project until it quits or is stopped",
28878
28902
  requires: ["projectPath"]
28879
28903
  },
28880
- stop: { summary: "end the run and answer with what it printed last", requires: [] },
28904
+ stop: {
28905
+ summary: "end the run and answer with what it printed last, naming the process ended under endedPid: a game that started processes of its own keeps them",
28906
+ requires: []
28907
+ },
28881
28908
  check: {
28882
28909
  summary: "boot headless, quit after a few frames, and report the verdict",
28883
28910
  requires: ["projectPath"]
@@ -30443,7 +30470,7 @@ class GodotServer {
30443
30470
  log.append("stderr", failed.stderr);
30444
30471
  exitCode = typeof failed.code === "number" ? failed.code : -1;
30445
30472
  } finally {
30446
- rmSync5(exportLogs, { recursive: true, force: true });
30473
+ discard(exportLogs);
30447
30474
  }
30448
30475
  log.finish();
30449
30476
  const problems = log.select({ severity: "warning", sinceLastCall: false, limit: 200 });
@@ -30541,8 +30568,7 @@ class GodotServer {
30541
30568
  } catch (error) {
30542
30569
  reportProblem = errorMessage(error);
30543
30570
  } finally {
30544
- rmSync5(reportsDir, { recursive: true, force: true });
30545
- rmSync5(userData, { recursive: true, force: true });
30571
+ discard(reportsDir, userData);
30546
30572
  }
30547
30573
  const engineEntries = run.log.select({ severity: "warning", sinceLastCall: false, limit: 200 }).entries.map(aboveTheRunner);
30548
30574
  const verdicts = {
@@ -30784,12 +30810,12 @@ class GodotServer {
30784
30810
  }
30785
30811
  settingKeysOf(projectPath) {
30786
30812
  if (projectPath === undefined) {
30787
- return new Set;
30813
+ return new Map;
30788
30814
  }
30789
30815
  try {
30790
30816
  return settingKeys(readFileSync11(join11(projectPath, "project.godot"), "utf8"));
30791
30817
  } catch {
30792
- return new Set;
30818
+ return new Map;
30793
30819
  }
30794
30820
  }
30795
30821
  async handleRestartEditor() {
@@ -30821,7 +30847,7 @@ class GodotServer {
30821
30847
  }
30822
30848
  const now = this.godotBridge.getStatus();
30823
30849
  const after = this.settingKeysOf(before.projectPath);
30824
- const dropped = [...settingsBefore].filter((key) => !after.has(key));
30850
+ const dropped = [...settingsBefore].filter(([key]) => !after.has(key));
30825
30851
  return this.jsonTextResponse({
30826
30852
  restarted: true,
30827
30853
  editorPid: now.editorPid,
@@ -30829,8 +30855,8 @@ class GodotServer {
30829
30855
  serverVersion: SERVER_VERSION,
30830
30856
  addonIsStale: now.addonVersion !== SERVER_VERSION,
30831
30857
  staleNote: addonMismatch(now.addonVersion, SERVER_VERSION),
30832
- settingsDropped: dropped.length > 0 ? dropped : undefined,
30833
- settingsNote: dropped.length > 0 ? 'The editor saved project.godot on its way out and these keys are no longer in it. Godot writes only what differs from its own defaults, so a key named deliberately at its default value is redundant to the editor and is dropped on save. If any of them were pinned on purpose, to keep "set to this on purpose" and "not set" apart, put them back: nothing else will say they have gone until something depends on one.' : undefined,
30858
+ settingsDropped: dropped.length > 0 ? dropped.map(([setting, was]) => ({ setting, was })) : undefined,
30859
+ settingsNote: dropped.length > 0 ? `The editor saved project.godot on its way out and these keys are no longer in it, with the value each one held. Godot writes only what differs from its own defaults, so a key named deliberately at its default value is redundant to the editor and is dropped on save; it will be dropped again on the next restart. If any of them were pinned on purpose, to keep "set to this on purpose" and "not set" apart, project_settings set puts one back: ${dropped.map(([setting, was]) => `setting "${setting}" value ${JSON.stringify(was)}`).join(", ")}. Nothing else will say they have gone until something depends on one.` : undefined,
30834
30860
  tookMs: Date.now() - began
30835
30861
  });
30836
30862
  }
@@ -31455,11 +31481,13 @@ class GodotServer {
31455
31481
  return this.jsonTextResponse({
31456
31482
  stopped: true,
31457
31483
  through: stopped.throughEditor ? "editor" : "gdharness",
31484
+ endedPid: stopped.pid,
31458
31485
  exitedBeforeStop: stopped.exitCode !== null,
31459
31486
  exitCode: stopped.exitCode,
31460
31487
  errors: stopped.log.count("error"),
31461
31488
  warnings: stopped.log.count("warning"),
31462
31489
  clean: stopped.log.count("error") === 0,
31490
+ note: stopped.throughEditor ? "The editor was asked to stop the scene it is playing. Anything that game started for itself, with OS.create_process or otherwise, is not the editor's to stop and is still running." : "The process named under endedPid was ended. Anything that game started for itself, with OS.create_process or otherwise, is a separate process and is still running.",
31463
31491
  entries: forAnswer(stopped.log.select({ severity: "warning", sinceLastCall: false, limit: 200 }).entries)
31464
31492
  });
31465
31493
  }
@@ -31619,9 +31647,7 @@ class GodotServer {
31619
31647
  ]
31620
31648
  };
31621
31649
  } finally {
31622
- if (screenshotDir) {
31623
- rmSync5(screenshotDir, { recursive: true, force: true });
31624
- }
31650
+ discard(screenshotDir);
31625
31651
  }
31626
31652
  }
31627
31653
  async handleFindRuntimeNodes(args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdharness",
3
- "version": "0.13.10",
3
+ "version": "0.13.12",
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",