gdharness 1.0.16 → 1.0.18

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
@@ -47,10 +47,233 @@ var __esm = (fn, res, err) => () => {
47
47
  };
48
48
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
49
49
 
50
+ // src/errors.ts
51
+ function errorMessage(error, fallback = "Unknown error") {
52
+ if (error instanceof Error) {
53
+ return error.message || fallback;
54
+ }
55
+ if (typeof error === "string") {
56
+ return error || fallback;
57
+ }
58
+ if (typeof error === "number" || typeof error === "boolean") {
59
+ return String(error);
60
+ }
61
+ return fallback;
62
+ }
63
+ function toError(error) {
64
+ return error instanceof Error ? error : new Error(errorMessage(error), { cause: error });
65
+ }
66
+ var Refusal;
67
+ var init_errors = __esm(() => {
68
+ Refusal = class Refusal extends Error {
69
+ };
70
+ });
71
+
72
+ // src/process-children.ts
73
+ import { execFile, execFileSync, spawnSync } from "node:child_process";
74
+ import { basename } from "node:path";
75
+ import { promisify } from "node:util";
76
+ function startTimesOf(pids) {
77
+ const began = new Map;
78
+ if (pids.length === 0) {
79
+ return began;
80
+ }
81
+ try {
82
+ if (process.platform === "win32") {
83
+ const filter = pids.map((pid) => `ProcessId=${pid}`).join(" OR ");
84
+ const said = execFileSync("powershell", [
85
+ "-NoProfile",
86
+ "-NonInteractive",
87
+ "-Command",
88
+ `Get-CimInstance Win32_Process -Filter "${filter}" | ForEach-Object { "$($_.ProcessId) $(([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds())" }`
89
+ ], { encoding: "utf8", timeout: ASK_TIMEOUT_MS, windowsHide: true });
90
+ for (const line of said.split(`
91
+ `)) {
92
+ const found = /^\s*(\d+)\s+(\d+)\s*$/.exec(line);
93
+ if (found?.[1] !== undefined && found[2] !== undefined) {
94
+ began.set(Number(found[1]), Number(found[2]));
95
+ }
96
+ }
97
+ return began;
98
+ }
99
+ const said = spawnSync("ps", ["-p", pids.join(","), "-o", "pid=,lstart="], {
100
+ encoding: "utf8",
101
+ timeout: ASK_TIMEOUT_MS,
102
+ env: { ...process.env, LC_ALL: "C" }
103
+ }).stdout;
104
+ for (const line of said.split(`
105
+ `)) {
106
+ const found = /^\s*(\d+)\s+(.+)$/.exec(line);
107
+ const at = Date.parse(found?.[2]?.trim() ?? "");
108
+ if (found?.[1] !== undefined && !Number.isNaN(at)) {
109
+ began.set(Number(found[1]), at);
110
+ }
111
+ }
112
+ } catch {}
113
+ return began;
114
+ }
115
+ async function processTree() {
116
+ try {
117
+ if (process.platform === "win32") {
118
+ return parseProcessTable(await askWindows(), true);
119
+ }
120
+ return parseProcessTable(await askPosix());
121
+ } catch {
122
+ return;
123
+ }
124
+ }
125
+ function parseProcessTable(printed, started = false) {
126
+ const tree = new Map;
127
+ for (const line of printed.split(/\r?\n/)) {
128
+ const fields = /^\s*(\d+)\s+(\d+)(?:\s+(.*))?$/.exec(line);
129
+ if (fields === null) {
130
+ continue;
131
+ }
132
+ const pid = Number(fields[1]);
133
+ const parent = Number(fields[2]);
134
+ const rest = (fields[3] ?? "").trim();
135
+ if (pid <= 0) {
136
+ continue;
137
+ }
138
+ if (!started) {
139
+ tree.set(pid, { parent, command: rest });
140
+ continue;
141
+ }
142
+ const timed = /^(\d+)(?:\s+(.*))?$/.exec(rest);
143
+ if (timed === null) {
144
+ continue;
145
+ }
146
+ const began = Number(timed[1]);
147
+ tree.set(pid, { parent, command: (timed[2] ?? "").trim(), ...began > 0 ? { startedAt: began } : {} });
148
+ }
149
+ return tree;
150
+ }
151
+ function linked(tree, child, parent) {
152
+ const from = tree.get(child);
153
+ const to = tree.get(parent);
154
+ if (from === undefined || from.parent !== parent) {
155
+ return false;
156
+ }
157
+ if (from.startedAt === undefined || to?.startedAt === undefined) {
158
+ return true;
159
+ }
160
+ return from.startedAt >= to.startedAt;
161
+ }
162
+ function childrenIn(tree, pid) {
163
+ const children = [];
164
+ for (const child of tree.keys()) {
165
+ if (linked(tree, child, pid)) {
166
+ children.push(child);
167
+ }
168
+ }
169
+ return children;
170
+ }
171
+ function descendantsIn(tree, pid) {
172
+ const found = [];
173
+ const queue = [pid];
174
+ const seen = new Set([pid]);
175
+ while (queue.length > 0) {
176
+ const next = queue.shift();
177
+ if (next === undefined) {
178
+ break;
179
+ }
180
+ for (const child of childrenIn(tree, next)) {
181
+ if (!seen.has(child)) {
182
+ seen.add(child);
183
+ found.push(child);
184
+ queue.push(child);
185
+ }
186
+ }
187
+ }
188
+ return found;
189
+ }
190
+ function ancestorsIn(tree, pid, root) {
191
+ const chain = [];
192
+ const seen = new Set([pid]);
193
+ let child = pid;
194
+ let parent = tree.get(pid)?.parent;
195
+ while (parent !== undefined && !seen.has(parent) && linked(tree, child, parent)) {
196
+ chain.push(parent);
197
+ if (parent === root) {
198
+ break;
199
+ }
200
+ seen.add(parent);
201
+ child = parent;
202
+ parent = tree.get(parent)?.parent;
203
+ }
204
+ return chain;
205
+ }
206
+ function readCommandLine(command) {
207
+ const words = commandWords(command);
208
+ const executable = words[0] === undefined ? "" : basename(words[0].replaceAll("\\", "/"));
209
+ const at = words.indexOf("--path");
210
+ let projectPath = null;
211
+ if (at !== -1 && at + 1 < words.length) {
212
+ const taken = [];
213
+ for (const word of words.slice(at + 1)) {
214
+ if (taken.length > 0 && (word.startsWith("-") || /^[a-z]+:\/\//.test(word))) {
215
+ break;
216
+ }
217
+ taken.push(word);
218
+ }
219
+ projectPath = taken.join(" ");
220
+ }
221
+ return {
222
+ executable,
223
+ projectPath,
224
+ editor: words.some((word) => word === "-e" || word === "--editor")
225
+ };
226
+ }
227
+ function commandWords(command) {
228
+ const words = [];
229
+ let word = "";
230
+ let quoted = false;
231
+ let started = false;
232
+ for (const char of command) {
233
+ if (char === '"') {
234
+ quoted = !quoted;
235
+ started = true;
236
+ } else if (!quoted && /\s/.test(char)) {
237
+ if (started) {
238
+ words.push(word);
239
+ word = "";
240
+ started = false;
241
+ }
242
+ } else {
243
+ word += char;
244
+ started = true;
245
+ }
246
+ }
247
+ if (started) {
248
+ words.push(word);
249
+ }
250
+ return words;
251
+ }
252
+ async function askWindows() {
253
+ const { stdout } = await run("powershell.exe", [
254
+ "-NoProfile",
255
+ "-NonInteractive",
256
+ "-Command",
257
+ `${POWERSHELL_UTF8}Get-CimInstance Win32_Process | ForEach-Object { $began = 0; if ($_.CreationDate) { $began = ([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds() }; "$($_.ProcessId) $($_.ParentProcessId) $began $($_.CommandLine)" }`
258
+ ], { timeout: ASK_TIMEOUT_MS, windowsHide: true, maxBuffer: 16 * 1024 * 1024 });
259
+ return stdout;
260
+ }
261
+ async function askPosix() {
262
+ const { stdout } = await run("ps", ["-e", "-o", "pid=,ppid=,args="], {
263
+ timeout: ASK_TIMEOUT_MS,
264
+ maxBuffer: 16 * 1024 * 1024
265
+ });
266
+ return stdout;
267
+ }
268
+ var run, POWERSHELL_UTF8 = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ", ASK_TIMEOUT_MS = 15000;
269
+ var init_process_children = __esm(() => {
270
+ run = promisify(execFile);
271
+ });
272
+
50
273
  // src/detection.ts
51
274
  import { existsSync, readdirSync, statSync } from "node:fs";
52
275
  import { homedir } from "node:os";
53
- import { join } from "node:path";
276
+ import { join as join2 } from "node:path";
54
277
  function resolveHomeDirectory() {
55
278
  try {
56
279
  return homedir();
@@ -74,7 +297,7 @@ function scanDirectoryForGodotBinaries(directory, platform) {
74
297
  if (!pattern.test(name)) {
75
298
  continue;
76
299
  }
77
- const fullPath = join(directory, name);
300
+ const fullPath = join2(directory, name);
78
301
  try {
79
302
  const stat = statSync(fullPath);
80
303
  if (stat.isFile()) {
@@ -83,7 +306,7 @@ function scanDirectoryForGodotBinaries(directory, platform) {
83
306
  } catch {}
84
307
  }
85
308
  matches.sort((a, b) => b.mtime - a.mtime);
86
- return matches.map((m) => join(directory, m.name));
309
+ return matches.map((m) => join2(directory, m.name));
87
310
  }
88
311
  function conventionalPaths(platform, home) {
89
312
  const paths = ["godot"];
@@ -133,28 +356,6 @@ function godotCandidates(platform, home) {
133
356
  }
134
357
  var init_detection = () => {};
135
358
 
136
- // src/errors.ts
137
- function errorMessage(error, fallback = "Unknown error") {
138
- if (error instanceof Error) {
139
- return error.message || fallback;
140
- }
141
- if (typeof error === "string") {
142
- return error || fallback;
143
- }
144
- if (typeof error === "number" || typeof error === "boolean") {
145
- return String(error);
146
- }
147
- return fallback;
148
- }
149
- function toError(error) {
150
- return error instanceof Error ? error : new Error(errorMessage(error), { cause: error });
151
- }
152
- var Refusal2;
153
- var init_errors = __esm(() => {
154
- Refusal2 = class Refusal2 extends Error {
155
- };
156
- });
157
-
158
359
  // src/launch.ts
159
360
  function envValue(name, variables = process.env) {
160
361
  const value = variables[name];
@@ -7161,7 +7362,7 @@ var require_public_api = __commonJS(function(exports) {
7161
7362
 
7162
7363
  // src/runner.ts
7163
7364
  import { existsSync as existsSync3 } from "node:fs";
7164
- import { dirname, join as join2 } from "node:path";
7365
+ import { dirname as dirname2, join as join3 } from "node:path";
7165
7366
  import process2 from "node:process";
7166
7367
  function currentRunner() {
7167
7368
  const versions = process2.versions;
@@ -7182,7 +7383,7 @@ function spawnFor(runner, version, execPath = process2.execPath) {
7182
7383
  return { command: alongside(execPath, "npx") ?? "npx", args: ["-y", spec] };
7183
7384
  }
7184
7385
  function alongside(execPath, name) {
7185
- const runner = join2(dirname(execPath), process2.platform === "win32" ? `${name}.cmd` : name);
7386
+ const runner = join3(dirname2(execPath), process2.platform === "win32" ? `${name}.cmd` : name);
7186
7387
  return existsSync3(runner) ? runner : undefined;
7187
7388
  }
7188
7389
  var init_runner = () => {};
@@ -7324,7 +7525,7 @@ var init_game_log = __esm(() => {
7324
7525
  });
7325
7526
 
7326
7527
  // src/scratch.ts
7327
- import { rmSync as rmSync2 } from "node:fs";
7528
+ import { rmSync as rmSync3 } from "node:fs";
7328
7529
  function discardWith(remove, paths) {
7329
7530
  const left = [];
7330
7531
  for (const path of paths) {
@@ -7341,7 +7542,7 @@ function discardWith(remove, paths) {
7341
7542
  }
7342
7543
  function discard(...paths) {
7343
7544
  return discardWith((path) => {
7344
- rmSync2(path, SWEPT);
7545
+ rmSync3(path, SWEPT);
7345
7546
  }, paths);
7346
7547
  }
7347
7548
  var SWEPT;
@@ -7350,9 +7551,9 @@ var init_scratch = __esm(() => {
7350
7551
  });
7351
7552
 
7352
7553
  // src/update-check.ts
7353
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
7554
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
7354
7555
  import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
7355
- import { join as join5 } from "node:path";
7556
+ import { join as join6 } from "node:path";
7356
7557
  function packageUrl(root) {
7357
7558
  return `${root.replace(/\/+$/, "")}/gdharness/latest`;
7358
7559
  }
@@ -7374,20 +7575,20 @@ function cacheDirectory(environment) {
7374
7575
  };
7375
7576
  const home = set("HOME") ?? homedir3();
7376
7577
  if (process.platform === "win32") {
7377
- return join5(set("LOCALAPPDATA") ?? home, "gdharness");
7578
+ return join6(set("LOCALAPPDATA") ?? home, "gdharness");
7378
7579
  }
7379
7580
  if (process.platform === "darwin") {
7380
- return join5(home, "Library", "Caches", "gdharness");
7581
+ return join6(home, "Library", "Caches", "gdharness");
7381
7582
  }
7382
- return join5(set("XDG_CACHE_HOME") ?? join5(home, ".cache"), "gdharness");
7583
+ return join6(set("XDG_CACHE_HOME") ?? join6(home, ".cache"), "gdharness");
7383
7584
  }
7384
7585
  function cacheFile(environment = process.env) {
7385
7586
  try {
7386
7587
  const directory = cacheDirectory(environment);
7387
- mkdirSync2(directory, { recursive: true, mode: 448 });
7388
- return join5(directory, "update-check.json");
7588
+ mkdirSync3(directory, { recursive: true, mode: 448 });
7589
+ return join6(directory, "update-check.json");
7389
7590
  } catch {
7390
- return join5(tmpdir2(), "gdharness-update-check.json");
7591
+ return join6(tmpdir2(), "gdharness-update-check.json");
7391
7592
  }
7392
7593
  }
7393
7594
  function readCache(path) {
@@ -7395,7 +7596,7 @@ function readCache(path) {
7395
7596
  if (!existsSync5(path)) {
7396
7597
  return null;
7397
7598
  }
7398
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
7599
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
7399
7600
  if (typeof parsed !== "object" || parsed === null) {
7400
7601
  return null;
7401
7602
  }
@@ -7412,7 +7613,7 @@ function readCache(path) {
7412
7613
  }
7413
7614
  function writeCache(path, entry) {
7414
7615
  try {
7415
- writeFileSync3(path, JSON.stringify(entry), { encoding: "utf8", mode: 384 });
7616
+ writeFileSync4(path, JSON.stringify(entry), { encoding: "utf8", mode: 384 });
7416
7617
  } catch {}
7417
7618
  }
7418
7619
  function parts(version) {
@@ -7543,7 +7744,7 @@ var init_update_check = __esm(() => {
7543
7744
  });
7544
7745
 
7545
7746
  // src/server-version.ts
7546
- import { readFileSync as readFileSync3 } from "node:fs";
7747
+ import { readFileSync as readFileSync4 } from "node:fs";
7547
7748
  function editorIsStale(addonVersion, serverVersion, addonDigest, shippedDigest) {
7548
7749
  if (addonDigest !== undefined && addonDigest !== "" && shippedDigest !== undefined) {
7549
7750
  return addonDigest !== shippedDigest;
@@ -7579,7 +7780,7 @@ var init_server_version = __esm(() => {
7579
7780
  GODOT_DEBUG_MODE_DEFAULT = process.env["GODOT_DEBUG"] === "true" || DEBUG_MODE;
7580
7781
  SERVER_VERSION = (() => {
7581
7782
  try {
7582
- const pkg = JSON.parse(readFileSync3(new URL("../package.json", import.meta.url), "utf8"));
7783
+ const pkg = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8"));
7583
7784
  return typeof pkg.version === "string" ? pkg.version : "0.0.0";
7584
7785
  } catch {
7585
7786
  return "0.0.0";
@@ -7588,23 +7789,23 @@ var init_server_version = __esm(() => {
7588
7789
  });
7589
7790
 
7590
7791
  // src/class-cache.ts
7591
- import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
7592
- import { join as join6 } from "node:path";
7792
+ import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2 } from "node:fs";
7793
+ import { join as join7 } from "node:path";
7593
7794
  function declaredClasses(projectPath) {
7594
7795
  const declared = new Map;
7595
7796
  const visit = (directory, prefix) => {
7596
- if (existsSync6(join6(directory, ".gdignore"))) {
7797
+ if (existsSync6(join7(directory, ".gdignore"))) {
7597
7798
  return;
7598
7799
  }
7599
7800
  for (const entry of readdirSync2(directory, { withFileTypes: true })) {
7600
7801
  if (entry.name.startsWith(".")) {
7601
7802
  continue;
7602
7803
  }
7603
- const path = join6(directory, entry.name);
7804
+ const path = join7(directory, entry.name);
7604
7805
  if (entry.isDirectory()) {
7605
7806
  visit(path, `${prefix}${entry.name}/`);
7606
7807
  } else if (entry.isFile() && entry.name.endsWith(".gd")) {
7607
- const found = DECLARATION.exec(readFileSync5(path, "utf8"));
7808
+ const found = DECLARATION.exec(readFileSync6(path, "utf8"));
7608
7809
  if (found?.[1]) {
7609
7810
  declared.set(found[1], `res://${prefix}${entry.name}`);
7610
7811
  }
@@ -7615,12 +7816,12 @@ function declaredClasses(projectPath) {
7615
7816
  return declared;
7616
7817
  }
7617
7818
  function cachedClasses(projectPath) {
7618
- const cache = join6(projectPath, ".godot", "global_script_class_cache.cfg");
7819
+ const cache = join7(projectPath, ".godot", "global_script_class_cache.cfg");
7619
7820
  if (!existsSync6(cache)) {
7620
7821
  return null;
7621
7822
  }
7622
7823
  const listed = new Map;
7623
- const text = readFileSync5(cache, "utf8");
7824
+ const text = readFileSync6(cache, "utf8");
7624
7825
  for (const entry of text.matchAll(/"class":\s*&"([^"]+)"[\s\S]*?"path":\s*"([^"]+)"/g)) {
7625
7826
  listed.set(entry[1] ?? "", entry[2] ?? "");
7626
7827
  }
@@ -7705,7 +7906,7 @@ function uncachedClassNote(types) {
7705
7906
  return `${types.join(", ")} ${one ? "is declared" : "are declared"} in this project and missing from ` + `.godot/global_script_class_cache.cfg, so a game launched now would not resolve ${one ? "it" : "them"} ` + "either. Try editor_rescan first: it asks the editor already running and starts nothing, and it " + "cleared this in 314ms in a second project with a 31-worker fan-out still importing. It is not " + "always enough, because a file another engine has already imported reads as settled and the " + "walk does not look inside it. project_import refresh_classes rewrites the cache from the " + "declarations on disk and does reach that case, at the cost of a short headless engine, which " + "is worth knowing when something else is already running against this project.";
7706
7907
  }
7707
7908
  function cacheWrittenAt(projectPath) {
7708
- const cache = join6(projectPath, ".godot", "global_script_class_cache.cfg");
7909
+ const cache = join7(projectPath, ".godot", "global_script_class_cache.cfg");
7709
7910
  try {
7710
7911
  return statSync2(cache).mtimeMs;
7711
7912
  } catch {
@@ -7719,14 +7920,14 @@ function declaredSince(projectPath, paths, names, since) {
7719
7920
  return false;
7720
7921
  }
7721
7922
  try {
7722
- return statSync2(join6(projectPath, path.slice("res://".length))).mtimeMs > since;
7923
+ return statSync2(join7(projectPath, path.slice("res://".length))).mtimeMs > since;
7723
7924
  } catch {
7724
7925
  return false;
7725
7926
  }
7726
7927
  });
7727
7928
  }
7728
7929
  function cachedAtMissingPaths(cached, projectPath) {
7729
- return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync6(join6(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
7930
+ return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync6(join7(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
7730
7931
  }
7731
7932
  function staleAgainst(cached, projectPath) {
7732
7933
  return [...declaredClasses(projectPath)].filter(([name, path]) => cached.get(name) !== path).map(([name]) => name);
@@ -7749,11 +7950,11 @@ var init_class_cache = __esm(() => {
7749
7950
  });
7750
7951
 
7751
7952
  // src/headless.ts
7752
- import { execFile as execFile3 } from "node:child_process";
7753
- import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync4 } from "node:fs";
7953
+ import { execFile as execFile4 } from "node:child_process";
7954
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync5 } from "node:fs";
7754
7955
  import { tmpdir as tmpdir3 } from "node:os";
7755
- import { join as join7 } from "node:path";
7756
- import { promisify as promisify3 } from "node:util";
7956
+ import { join as join8 } from "node:path";
7957
+ import { promisify as promisify4 } from "node:util";
7757
7958
  function snakeCased2(params) {
7758
7959
  const result = emptyRecord();
7759
7960
  for (const [key, value] of Object.entries(params)) {
@@ -7792,9 +7993,9 @@ function reason2(stdout, stderr) {
7792
7993
  return stdout.trim().split(/\r?\n/).at(-1) ?? "no output at all";
7793
7994
  }
7794
7995
  async function runImport(godotPath, projectPath) {
7795
- const logDir = mkdtempSync2(join7(tmpdir3(), "gdharness-import-"));
7996
+ const logDir = mkdtempSync2(join8(tmpdir3(), "gdharness-import-"));
7796
7997
  try {
7797
- const { stderr } = await run3(godotPath, ["--headless", "--log-file", join7(logDir, "engine.log"), "--path", projectPath, "--import"], { signal: callSignal() });
7998
+ const { stderr } = await run4(godotPath, ["--headless", "--log-file", join8(logDir, "engine.log"), "--path", projectPath, "--import"], { signal: callSignal() });
7798
7999
  return { ok: true, messages: problems2(stderr) };
7799
8000
  } catch (error) {
7800
8001
  if (error instanceof Error && "stdout" in error && "stderr" in error) {
@@ -7815,13 +8016,13 @@ async function runImport(godotPath, projectPath) {
7815
8016
  }
7816
8017
  }
7817
8018
  async function runOperation2(engine, operation, params, projectPath) {
7818
- const paramsDir = mkdtempSync2(join7(tmpdir3(), "gdharness-params-"));
7819
- const paramsFile = join7(paramsDir, `${operation}.json`);
7820
- writeFileSync4(paramsFile, JSON.stringify(snakeCased2(params)), "utf8");
8019
+ const paramsDir = mkdtempSync2(join8(tmpdir3(), "gdharness-params-"));
8020
+ const paramsFile = join8(paramsDir, `${operation}.json`);
8021
+ writeFileSync5(paramsFile, JSON.stringify(snakeCased2(params)), "utf8");
7821
8022
  const args = [
7822
8023
  "--headless",
7823
8024
  "--log-file",
7824
- join7(paramsDir, "engine.log"),
8025
+ join8(paramsDir, "engine.log"),
7825
8026
  "--path",
7826
8027
  projectPath,
7827
8028
  "--script",
@@ -7833,7 +8034,7 @@ async function runOperation2(engine, operation, params, projectPath) {
7833
8034
  let stdout;
7834
8035
  let stderr;
7835
8036
  try {
7836
- ({ stdout, stderr } = await run3(engine.godotPath, args, { signal: callSignal() }));
8037
+ ({ stdout, stderr } = await run4(engine.godotPath, args, { signal: callSignal() }));
7837
8038
  } catch (error) {
7838
8039
  if (error instanceof Error && "stdout" in error && "stderr" in error) {
7839
8040
  const failed = error;
@@ -7861,12 +8062,12 @@ async function runOperation2(engine, operation, params, projectPath) {
7861
8062
  }
7862
8063
  return { ok: true, payload, messages: problems2(stderr) };
7863
8064
  }
7864
- var run3;
8065
+ var run4;
7865
8066
  var init_headless = __esm(() => {
7866
8067
  init_call_signal();
7867
8068
  init_game_log();
7868
8069
  init_scratch();
7869
- run3 = promisify3(execFile3);
8070
+ run4 = promisify4(execFile4);
7870
8071
  });
7871
8072
 
7872
8073
  // node_modules/zod/v4/core/util.js
@@ -15034,26 +15235,26 @@ var init_paths = __esm(() => {
15034
15235
  });
15035
15236
 
15036
15237
  // src/resources.ts
15037
- import { readFileSync as readFileSync6 } from "node:fs";
15238
+ import { readFileSync as readFileSync7 } from "node:fs";
15038
15239
  import { extname, resolve as resolve2 } from "node:path";
15039
15240
  function ensureProjectPath(getProjectPath) {
15040
15241
  const projectPath = getProjectPath();
15041
15242
  if (!projectPath) {
15042
- throw new Refusal2("Project path is not set. Set a Godot project path first.");
15243
+ throw new Refusal("Project path is not set. Set a Godot project path first.");
15043
15244
  }
15044
15245
  return resolve2(projectPath);
15045
15246
  }
15046
15247
  function uriPathToProjectPath(inputPath) {
15047
15248
  const normalized = inputPath.replace(/\\/g, "/").trim();
15048
15249
  if (normalized.replace(/\//g, "") === "") {
15049
- throw new Refusal2("Resource path is empty.");
15250
+ throw new Refusal("Resource path is empty.");
15050
15251
  }
15051
15252
  return normalized.replace(/^\/+/, "");
15052
15253
  }
15053
15254
  function resolveProjectFile(projectPath, resourcePath) {
15054
15255
  const contained = resolveWithinProject(projectPath, resourcePath);
15055
15256
  if (!contained.ok) {
15056
- throw new Refusal2(contained.reason);
15257
+ throw new Refusal(contained.reason);
15057
15258
  }
15058
15259
  return contained.absolutePath;
15059
15260
  }
@@ -15065,14 +15266,14 @@ function parseGodotUri(uri) {
15065
15266
  try {
15066
15267
  parsed = new URL(uri);
15067
15268
  } catch {
15068
- throw new Refusal2(`Invalid URI: ${uri}`);
15269
+ throw new Refusal(`Invalid URI: ${uri}`);
15069
15270
  }
15070
15271
  if (parsed.protocol !== "godot:") {
15071
- throw new Refusal2(`Unsupported URI scheme: ${parsed.protocol}`);
15272
+ throw new Refusal(`Unsupported URI scheme: ${parsed.protocol}`);
15072
15273
  }
15073
15274
  const host = parsed.hostname;
15074
15275
  if (host !== "scene" && host !== "script" && host !== "resource") {
15075
- throw new Refusal2(`Unsupported Godot resource type: ${host}`);
15276
+ throw new Refusal(`Unsupported Godot resource type: ${host}`);
15076
15277
  }
15077
15278
  const resourcePath = uriPathToProjectPath(decodeURIComponent(parsed.pathname));
15078
15279
  return { kind: host, resourcePath };
@@ -15080,13 +15281,13 @@ function parseGodotUri(uri) {
15080
15281
  function ensureAllowedExtension(kind, filePath) {
15081
15282
  const extension = extname(filePath).toLowerCase();
15082
15283
  if (kind === "scene" && extension !== ".tscn") {
15083
- throw new Refusal2("Scene resources must use .tscn extension.");
15284
+ throw new Refusal("Scene resources must use .tscn extension.");
15084
15285
  }
15085
15286
  if (kind === "script" && extension !== ".gd") {
15086
- throw new Refusal2("Script resources must use .gd extension.");
15287
+ throw new Refusal("Script resources must use .gd extension.");
15087
15288
  }
15088
15289
  if (kind === "resource" && ![".tres", ".tscn", ".gd"].includes(extension)) {
15089
- throw new Refusal2("Resource URIs support only .tres, .tscn, and .gd files.");
15290
+ throw new Refusal("Resource URIs support only .tres, .tscn, and .gd files.");
15090
15291
  }
15091
15292
  }
15092
15293
  function isValueComplete(value) {
@@ -15200,7 +15401,7 @@ function readResourceText(uri, getProjectPath) {
15200
15401
  const parsedUri = parseGodotUri(uri);
15201
15402
  if (parsedUri.kind === "project-info") {
15202
15403
  const projectFilePath = resolveProjectFile(projectPath, "project.godot");
15203
- const rawProject = readFileSync6(projectFilePath, "utf-8");
15404
+ const rawProject = readFileSync7(projectFilePath, "utf-8");
15204
15405
  const parsedProject = parseProjectGodot(rawProject);
15205
15406
  return {
15206
15407
  mimeType: "application/json",
@@ -15209,7 +15410,7 @@ function readResourceText(uri, getProjectPath) {
15209
15410
  }
15210
15411
  const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
15211
15412
  ensureAllowedExtension(parsedUri.kind, filePath);
15212
- const text = readFileSync6(filePath, "utf-8");
15413
+ const text = readFileSync7(filePath, "utf-8");
15213
15414
  return {
15214
15415
  mimeType: parsedUri.kind === "script" ? "text/x-gdscript" : "text/plain",
15215
15416
  text
@@ -15238,9 +15439,9 @@ function setupResourceHandlers(mcp, getProjectPath) {
15238
15439
  };
15239
15440
  } catch (error) {
15240
15441
  if (error instanceof Error) {
15241
- throw new Refusal2(`Failed to read resource '${uri}': ${error.message}`, { cause: error });
15442
+ throw new Refusal(`Failed to read resource '${uri}': ${error.message}`, { cause: error });
15242
15443
  }
15243
- throw new Refusal2(`Failed to read resource '${uri}'.`, { cause: error });
15444
+ throw new Refusal(`Failed to read resource '${uri}'.`, { cause: error });
15244
15445
  }
15245
15446
  });
15246
15447
  }
@@ -15341,14 +15542,14 @@ import { createHash as createHash3 } from "node:crypto";
15341
15542
  import {
15342
15543
  cpSync as cpSync2,
15343
15544
  existsSync as existsSync8,
15344
- mkdirSync as mkdirSync4,
15545
+ mkdirSync as mkdirSync5,
15345
15546
  readdirSync as readdirSync4,
15346
- readFileSync as readFileSync8,
15347
- rmSync as rmSync4,
15547
+ readFileSync as readFileSync9,
15548
+ rmSync as rmSync5,
15348
15549
  statSync as statSync4,
15349
- writeFileSync as writeFileSync6
15550
+ writeFileSync as writeFileSync7
15350
15551
  } from "node:fs";
15351
- import { dirname as dirname4, join as join9 } from "node:path";
15552
+ import { dirname as dirname5, join as join10 } from "node:path";
15352
15553
  import { fileURLToPath as fileURLToPath2 } from "node:url";
15353
15554
  function editorAddonDigest2(from = shippedAddonsDirectory2()) {
15354
15555
  const hash = createHash3("sha256");
@@ -15357,21 +15558,21 @@ function editorAddonDigest2(from = shippedAddonsDirectory2()) {
15357
15558
  if (name === VERSION_MARKER2 || name === DIGEST_MARKER2) {
15358
15559
  continue;
15359
15560
  }
15360
- const path = join9(directory, name);
15561
+ const path = join10(directory, name);
15361
15562
  const inside = `${relative}/${name}`;
15362
15563
  if (statSync4(path).isDirectory()) {
15363
15564
  walk(path, inside);
15364
15565
  } else {
15365
15566
  hash.update(`${inside}
15366
15567
  `);
15367
- hash.update(readFileSync8(path));
15568
+ hash.update(readFileSync9(path));
15368
15569
  hash.update(`
15369
15570
  `);
15370
15571
  }
15371
15572
  }
15372
15573
  };
15373
15574
  for (const name of EDITOR_PLUGINS2) {
15374
- walk(join9(from, name), name);
15575
+ walk(join10(from, name), name);
15375
15576
  }
15376
15577
  return hash.digest("hex");
15377
15578
  }
@@ -15386,14 +15587,14 @@ function shippedEditorDigest() {
15386
15587
  return shippedDigest ?? undefined;
15387
15588
  }
15388
15589
  function shippedAddonsDirectory2() {
15389
- return join9(dirname4(fileURLToPath2(import.meta.url)), "godot", "addons");
15590
+ return join10(dirname5(fileURLToPath2(import.meta.url)), "godot", "addons");
15390
15591
  }
15391
15592
  function installedAddonVersion(projectPath) {
15392
- const marker = join9(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
15593
+ const marker = join10(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
15393
15594
  if (!existsSync8(marker)) {
15394
15595
  return null;
15395
15596
  }
15396
- const said = readFileSync8(marker, "utf8").trim();
15597
+ const said = readFileSync9(marker, "utf8").trim();
15397
15598
  return said === "" ? null : said;
15398
15599
  }
15399
15600
  var ADDONS2, EDITOR_PLUGINS2, RUNTIME_AUTOLOAD2, SCRIPT_RUNS_SETTING = "gdharness/runtime/serve_script_runs", BIND_ADDRESS_SETTING = "gdharness/runtime/bind_address", PORT_SETTING = "gdharness/runtime/port", VERSION_MARKER2 = ".gdharness-version", DIGEST_MARKER2 = ".gdharness-digest", shippedDigest;
@@ -31375,212 +31576,11 @@ var init_stdio2 = __esm(() => {
31375
31576
  init_stdio();
31376
31577
  });
31377
31578
 
31378
- // src/process-children.ts
31379
- import { execFile as execFile4, execFileSync, spawnSync as spawnSync2 } from "node:child_process";
31380
- import { basename as basename2 } from "node:path";
31381
- import { promisify as promisify4 } from "node:util";
31382
- function startTimesOf(pids) {
31383
- const began = new Map;
31384
- if (pids.length === 0) {
31385
- return began;
31386
- }
31387
- try {
31388
- if (process.platform === "win32") {
31389
- const filter = pids.map((pid) => `ProcessId=${pid}`).join(" OR ");
31390
- const said = execFileSync("powershell", [
31391
- "-NoProfile",
31392
- "-NonInteractive",
31393
- "-Command",
31394
- `Get-CimInstance Win32_Process -Filter "${filter}" | ForEach-Object { "$($_.ProcessId) $(([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds())" }`
31395
- ], { encoding: "utf8", timeout: ASK_TIMEOUT_MS, windowsHide: true });
31396
- for (const line of said.split(`
31397
- `)) {
31398
- const found = /^\s*(\d+)\s+(\d+)\s*$/.exec(line);
31399
- if (found?.[1] !== undefined && found[2] !== undefined) {
31400
- began.set(Number(found[1]), Number(found[2]));
31401
- }
31402
- }
31403
- return began;
31404
- }
31405
- const said = spawnSync2("ps", ["-p", pids.join(","), "-o", "pid=,lstart="], {
31406
- encoding: "utf8",
31407
- timeout: ASK_TIMEOUT_MS,
31408
- env: { ...process.env, LC_ALL: "C" }
31409
- }).stdout;
31410
- for (const line of said.split(`
31411
- `)) {
31412
- const found = /^\s*(\d+)\s+(.+)$/.exec(line);
31413
- const at = Date.parse(found?.[2]?.trim() ?? "");
31414
- if (found?.[1] !== undefined && !Number.isNaN(at)) {
31415
- began.set(Number(found[1]), at);
31416
- }
31417
- }
31418
- } catch {}
31419
- return began;
31420
- }
31421
- async function processTree() {
31422
- try {
31423
- if (process.platform === "win32") {
31424
- return parseProcessTable(await askWindows(), true);
31425
- }
31426
- return parseProcessTable(await askPosix());
31427
- } catch {
31428
- return;
31429
- }
31430
- }
31431
- function parseProcessTable(printed, started = false) {
31432
- const tree = new Map;
31433
- for (const line of printed.split(/\r?\n/)) {
31434
- const fields = /^\s*(\d+)\s+(\d+)(?:\s+(.*))?$/.exec(line);
31435
- if (fields === null) {
31436
- continue;
31437
- }
31438
- const pid = Number(fields[1]);
31439
- const parent = Number(fields[2]);
31440
- const rest = (fields[3] ?? "").trim();
31441
- if (pid <= 0) {
31442
- continue;
31443
- }
31444
- if (!started) {
31445
- tree.set(pid, { parent, command: rest });
31446
- continue;
31447
- }
31448
- const timed = /^(\d+)(?:\s+(.*))?$/.exec(rest);
31449
- if (timed === null) {
31450
- continue;
31451
- }
31452
- const began = Number(timed[1]);
31453
- tree.set(pid, { parent, command: (timed[2] ?? "").trim(), ...began > 0 ? { startedAt: began } : {} });
31454
- }
31455
- return tree;
31456
- }
31457
- function linked(tree, child, parent) {
31458
- const from = tree.get(child);
31459
- const to = tree.get(parent);
31460
- if (from === undefined || from.parent !== parent) {
31461
- return false;
31462
- }
31463
- if (from.startedAt === undefined || to?.startedAt === undefined) {
31464
- return true;
31465
- }
31466
- return from.startedAt >= to.startedAt;
31467
- }
31468
- function childrenIn(tree, pid) {
31469
- const children = [];
31470
- for (const child of tree.keys()) {
31471
- if (linked(tree, child, pid)) {
31472
- children.push(child);
31473
- }
31474
- }
31475
- return children;
31476
- }
31477
- function descendantsIn(tree, pid) {
31478
- const found = [];
31479
- const queue = [pid];
31480
- const seen = new Set([pid]);
31481
- while (queue.length > 0) {
31482
- const next = queue.shift();
31483
- if (next === undefined) {
31484
- break;
31485
- }
31486
- for (const child of childrenIn(tree, next)) {
31487
- if (!seen.has(child)) {
31488
- seen.add(child);
31489
- found.push(child);
31490
- queue.push(child);
31491
- }
31492
- }
31493
- }
31494
- return found;
31495
- }
31496
- function ancestorsIn(tree, pid, root) {
31497
- const chain = [];
31498
- const seen = new Set([pid]);
31499
- let child = pid;
31500
- let parent = tree.get(pid)?.parent;
31501
- while (parent !== undefined && !seen.has(parent) && linked(tree, child, parent)) {
31502
- chain.push(parent);
31503
- if (parent === root) {
31504
- break;
31505
- }
31506
- seen.add(parent);
31507
- child = parent;
31508
- parent = tree.get(parent)?.parent;
31509
- }
31510
- return chain;
31511
- }
31512
- function readCommandLine(command) {
31513
- const words = commandWords(command);
31514
- const executable = words[0] === undefined ? "" : basename2(words[0].replaceAll("\\", "/"));
31515
- const at = words.indexOf("--path");
31516
- let projectPath = null;
31517
- if (at !== -1 && at + 1 < words.length) {
31518
- const taken = [];
31519
- for (const word of words.slice(at + 1)) {
31520
- if (taken.length > 0 && (word.startsWith("-") || /^[a-z]+:\/\//.test(word))) {
31521
- break;
31522
- }
31523
- taken.push(word);
31524
- }
31525
- projectPath = taken.join(" ");
31526
- }
31527
- return {
31528
- executable,
31529
- projectPath,
31530
- editor: words.some((word) => word === "-e" || word === "--editor")
31531
- };
31532
- }
31533
- function commandWords(command) {
31534
- const words = [];
31535
- let word = "";
31536
- let quoted = false;
31537
- let started = false;
31538
- for (const char of command) {
31539
- if (char === '"') {
31540
- quoted = !quoted;
31541
- started = true;
31542
- } else if (!quoted && /\s/.test(char)) {
31543
- if (started) {
31544
- words.push(word);
31545
- word = "";
31546
- started = false;
31547
- }
31548
- } else {
31549
- word += char;
31550
- started = true;
31551
- }
31552
- }
31553
- if (started) {
31554
- words.push(word);
31555
- }
31556
- return words;
31557
- }
31558
- async function askWindows() {
31559
- const { stdout } = await run4("powershell.exe", [
31560
- "-NoProfile",
31561
- "-NonInteractive",
31562
- "-Command",
31563
- `${POWERSHELL_UTF8}Get-CimInstance Win32_Process | ForEach-Object { $began = 0; if ($_.CreationDate) { $began = ([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds() }; "$($_.ProcessId) $($_.ParentProcessId) $began $($_.CommandLine)" }`
31564
- ], { timeout: ASK_TIMEOUT_MS, windowsHide: true, maxBuffer: 16 * 1024 * 1024 });
31565
- return stdout;
31566
- }
31567
- async function askPosix() {
31568
- const { stdout } = await run4("ps", ["-e", "-o", "pid=,ppid=,args="], {
31569
- timeout: ASK_TIMEOUT_MS,
31570
- maxBuffer: 16 * 1024 * 1024
31571
- });
31572
- return stdout;
31573
- }
31574
- var run4, POWERSHELL_UTF8 = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ", ASK_TIMEOUT_MS = 15000;
31575
- var init_process_children = __esm(() => {
31576
- run4 = promisify4(execFile4);
31577
- });
31578
-
31579
31579
  // src/runtime-client.ts
31580
- import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync10, statSync as statSync5, unlinkSync } from "node:fs";
31580
+ import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync11, statSync as statSync5, unlinkSync } from "node:fs";
31581
31581
  import { createConnection } from "node:net";
31582
31582
  import { tmpdir as tmpdir4 } from "node:os";
31583
- import { dirname as dirname7, join as join12, resolve as resolve3 } from "node:path";
31583
+ import { dirname as dirname8, join as join13, resolve as resolve3 } from "node:path";
31584
31584
  import { setTimeout as delay } from "node:timers/promises";
31585
31585
  function runtimeDirectory(variables = process.env) {
31586
31586
  const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
@@ -31588,19 +31588,19 @@ function runtimeDirectory(variables = process.env) {
31588
31588
  return explicit;
31589
31589
  }
31590
31590
  const perUser = envValue("XDG_RUNTIME_DIR", variables);
31591
- return join12(perUser ?? tmpdir4(), "gdharness");
31591
+ return join13(perUser ?? tmpdir4(), "gdharness");
31592
31592
  }
31593
31593
  function runtimeDirectories(variables = process.env) {
31594
31594
  const candidates = [runtimeDirectory(variables)];
31595
31595
  const fallbacks = process.platform === "win32" ? [envValue("SystemRoot", variables) ?? envValue("windir", variables) ?? "C:\\Windows"] : ["/tmp", "/var/tmp"];
31596
31596
  for (const base of fallbacks) {
31597
- candidates.push(join12(base, process.platform === "win32" ? "Temp" : "", "gdharness"));
31597
+ candidates.push(join13(base, process.platform === "win32" ? "Temp" : "", "gdharness"));
31598
31598
  }
31599
31599
  return [...new Set(candidates.map((path) => resolve3(path)))];
31600
31600
  }
31601
31601
  function errorReportOf(pid, directories = runtimeDirectories()) {
31602
31602
  for (const directory of directories) {
31603
- const path = join12(directory, `runtime-${pid}.log`);
31603
+ const path = join13(directory, `runtime-${pid}.log`);
31604
31604
  if (existsSync10(path)) {
31605
31605
  return path;
31606
31606
  }
@@ -31618,7 +31618,7 @@ function processAlive(pid) {
31618
31618
  function parseAnnouncement(file, pid) {
31619
31619
  let fields;
31620
31620
  try {
31621
- fields = asParams(JSON.parse(readFileSync10(file, "utf8")));
31621
+ fields = asParams(JSON.parse(readFileSync11(file, "utf8")));
31622
31622
  } catch {
31623
31623
  return { kind: "rubbish" };
31624
31624
  }
@@ -31670,7 +31670,7 @@ function discoverRuntimes(directories = runtimeDirectories()) {
31670
31670
  function wentAway(file, pid) {
31671
31671
  let project = "";
31672
31672
  try {
31673
- const fields = asParams(JSON.parse(readFileSync10(file, "utf8")));
31673
+ const fields = asParams(JSON.parse(readFileSync11(file, "utf8")));
31674
31674
  project = readString(readParams(fields, "project") ?? {}, "path") ?? "";
31675
31675
  } catch {
31676
31676
  return;
@@ -31716,14 +31716,14 @@ function announcedIn(directory) {
31716
31716
  for (const entry of readdirSync6(directory)) {
31717
31717
  const report = ERROR_REPORT_PATTERN.exec(entry);
31718
31718
  if (report) {
31719
- sweepErrorReport(join12(directory, entry), Number.parseInt(report[1] ?? "", 10));
31719
+ sweepErrorReport(join13(directory, entry), Number.parseInt(report[1] ?? "", 10));
31720
31720
  continue;
31721
31721
  }
31722
31722
  const match = ANNOUNCEMENT_PATTERN.exec(entry);
31723
31723
  if (!match) {
31724
31724
  continue;
31725
31725
  }
31726
- const file = join12(directory, entry);
31726
+ const file = join13(directory, entry);
31727
31727
  const pid = Number.parseInt(match[1] ?? "", 10);
31728
31728
  const alive = processAlive(pid);
31729
31729
  entries.push({ file, pid, alive });
@@ -31751,16 +31751,16 @@ function announcedIn(directory) {
31751
31751
  found.push(announced);
31752
31752
  }
31753
31753
  const held = new Set(entries.map((one) => one.file));
31754
- const here = join12(directory, ".");
31754
+ const here = join13(directory, ".");
31755
31755
  for (const file of verdicts.keys()) {
31756
- if (dirname7(file) === here && !held.has(file)) {
31756
+ if (dirname8(file) === here && !held.has(file)) {
31757
31757
  verdicts.delete(file);
31758
31758
  }
31759
31759
  }
31760
31760
  return found;
31761
31761
  }
31762
31762
  async function announcementEnded(pid, directories = runtimeDirectories()) {
31763
- const files = directories.map((directory) => join12(directory, `runtime-${pid}.json`)).filter((file) => existsSync10(file));
31763
+ const files = directories.map((directory) => join13(directory, `runtime-${pid}.json`)).filter((file) => existsSync10(file));
31764
31764
  const first = files[0];
31765
31765
  if (first === undefined) {
31766
31766
  return;
@@ -32009,14 +32009,14 @@ var init_runtime_client = __esm(() => {
32009
32009
  });
32010
32010
 
32011
32011
  // src/boot-note.ts
32012
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "node:fs";
32013
- import { dirname as dirname8, join as join13 } from "node:path";
32012
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
32013
+ import { dirname as dirname9, join as join14 } from "node:path";
32014
32014
  function bootNotePath(projectPath) {
32015
- return join13(projectPath, ".godot", "gdharness-boot.json");
32015
+ return join14(projectPath, ".godot", "gdharness-boot.json");
32016
32016
  }
32017
32017
  function readBootNote(projectPath) {
32018
32018
  try {
32019
- const noted = readNumber(asParams(JSON.parse(readFileSync11(bootNotePath(projectPath), "utf8"))), "announcedAfterMs");
32019
+ const noted = readNumber(asParams(JSON.parse(readFileSync12(bootNotePath(projectPath), "utf8"))), "announcedAfterMs");
32020
32020
  return noted !== undefined && Number.isFinite(noted) && noted > 0 ? noted : null;
32021
32021
  } catch {
32022
32022
  return null;
@@ -32025,8 +32025,8 @@ function readBootNote(projectPath) {
32025
32025
  function writeBootNote(projectPath, announcedAfterMs) {
32026
32026
  try {
32027
32027
  const path = bootNotePath(projectPath);
32028
- mkdirSync6(dirname8(path), { recursive: true });
32029
- writeFileSync8(path, JSON.stringify({ announcedAfterMs: Math.round(announcedAfterMs), at: new Date().toISOString() }, null, 2), "utf8");
32028
+ mkdirSync7(dirname9(path), { recursive: true });
32029
+ writeFileSync9(path, JSON.stringify({ announcedAfterMs: Math.round(announcedAfterMs), at: new Date().toISOString() }, null, 2), "utf8");
32030
32030
  } catch {}
32031
32031
  }
32032
32032
  function halfAsLongAgain(lastBootMs) {
@@ -32044,10 +32044,10 @@ var init_boot_note = __esm(() => {
32044
32044
  });
32045
32045
 
32046
32046
  // src/breakpoint-note.ts
32047
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync12, rmSync as rmSync6, writeFileSync as writeFileSync9 } from "node:fs";
32048
- import { dirname as dirname9, isAbsolute as isAbsolute2, join as join14, relative as relative2 } from "node:path";
32047
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
32048
+ import { dirname as dirname10, isAbsolute as isAbsolute2, join as join15, relative as relative2 } from "node:path";
32049
32049
  function breakpointNotePath(projectPath) {
32050
- return join14(projectPath, ".godot", "gdharness-breakpoints.json");
32050
+ return join15(projectPath, ".godot", "gdharness-breakpoints.json");
32051
32051
  }
32052
32052
  function writeBreakpointNote(projectPath, held) {
32053
32053
  const path = breakpointNotePath(projectPath);
@@ -32055,7 +32055,7 @@ function writeBreakpointNote(projectPath, held) {
32055
32055
  const inside = held.map((one) => ({ scriptPath: realPathOr(one.scriptPath), lines: one.lines })).filter((one) => one.lines.length > 0 && withinProject(root, one.scriptPath));
32056
32056
  try {
32057
32057
  if (inside.length === 0) {
32058
- rmSync6(path, { force: true });
32058
+ rmSync7(path, { force: true });
32059
32059
  return;
32060
32060
  }
32061
32061
  const note = {
@@ -32064,8 +32064,8 @@ function writeBreakpointNote(projectPath, held) {
32064
32064
  lines: [...one.lines]
32065
32065
  }))
32066
32066
  };
32067
- mkdirSync7(dirname9(path), { recursive: true });
32068
- writeFileSync9(path, `${JSON.stringify(note, null, 2)}
32067
+ mkdirSync8(dirname10(path), { recursive: true });
32068
+ writeFileSync10(path, `${JSON.stringify(note, null, 2)}
32069
32069
  `, "utf8");
32070
32070
  } catch (error) {
32071
32071
  console.error(`[SERVER] Could not record the breakpoints at ${path}: ${errorMessage(error)}`);
@@ -32073,7 +32073,7 @@ function writeBreakpointNote(projectPath, held) {
32073
32073
  }
32074
32074
  function readBreakpointNote(projectPath) {
32075
32075
  try {
32076
- const parsed = JSON.parse(readFileSync12(breakpointNotePath(projectPath), "utf8"));
32076
+ const parsed = JSON.parse(readFileSync13(breakpointNotePath(projectPath), "utf8"));
32077
32077
  if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.breakpoints)) {
32078
32078
  return [];
32079
32079
  }
@@ -32088,7 +32088,7 @@ function readBreakpointNote(projectPath) {
32088
32088
  }
32089
32089
  const lines = Array.isArray(listed) ? listed.filter((line) => Number.isInteger(line) && line > 0) : [];
32090
32090
  if (lines.length > 0) {
32091
- held.push({ scriptPath: realPathOr(join14(projectPath, script)), lines });
32091
+ held.push({ scriptPath: realPathOr(join15(projectPath, script)), lines });
32092
32092
  }
32093
32093
  }
32094
32094
  return held;
@@ -32106,14 +32106,14 @@ var init_breakpoint_note = __esm(() => {
32106
32106
  });
32107
32107
 
32108
32108
  // src/bridge-announce.ts
32109
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
32110
- import { dirname as dirname10, join as join15 } from "node:path";
32111
- function announcementPath(projectPath) {
32112
- return join15(projectPath, ".godot", "gdharness-bridge.json");
32109
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, rmSync as rmSync8, writeFileSync as writeFileSync11 } from "node:fs";
32110
+ import { dirname as dirname11, join as join16 } from "node:path";
32111
+ function announcementPath2(projectPath) {
32112
+ return join16(projectPath, ".godot", "gdharness-bridge.json");
32113
32113
  }
32114
- function readAnnouncement(path) {
32114
+ function readAnnouncement2(path) {
32115
32115
  try {
32116
- const parsed = JSON.parse(readFileSync13(path, "utf8"));
32116
+ const parsed = JSON.parse(readFileSync14(path, "utf8"));
32117
32117
  if (typeof parsed !== "object" || parsed === null) {
32118
32118
  return null;
32119
32119
  }
@@ -32127,12 +32127,12 @@ function readAnnouncement(path) {
32127
32127
  }
32128
32128
  }
32129
32129
  function announcementIsOurs(path) {
32130
- return readAnnouncement(path)?.pid === process.pid;
32130
+ return readAnnouncement2(path)?.pid === process.pid;
32131
32131
  }
32132
32132
  function announceBridge(projectPath, bridge) {
32133
- const path = announcementPath(projectPath);
32133
+ const path = announcementPath2(projectPath);
32134
32134
  try {
32135
- mkdirSync8(dirname10(path), { recursive: true });
32135
+ mkdirSync9(dirname11(path), { recursive: true });
32136
32136
  const announcement = {
32137
32137
  protocol: BRIDGE_ANNOUNCE_PROTOCOL,
32138
32138
  host: bridge.host,
@@ -32141,7 +32141,7 @@ function announceBridge(projectPath, bridge) {
32141
32141
  version: bridge.version,
32142
32142
  startedAt: new Date().toISOString()
32143
32143
  };
32144
- writeFileSync10(path, `${JSON.stringify(announcement, null, 2)}
32144
+ writeFileSync11(path, `${JSON.stringify(announcement, null, 2)}
32145
32145
  `, "utf8");
32146
32146
  return path;
32147
32147
  } catch (error) {
@@ -32154,7 +32154,7 @@ function withdrawBridge(path) {
32154
32154
  return;
32155
32155
  }
32156
32156
  try {
32157
- rmSync7(path, { force: true });
32157
+ rmSync8(path, { force: true });
32158
32158
  } catch (error) {
32159
32159
  console.error(`[SERVER] Could not withdraw the editor bridge announcement: ${errorMessage(error)}`);
32160
32160
  }
@@ -32162,17 +32162,18 @@ function withdrawBridge(path) {
32162
32162
  var BRIDGE_ANNOUNCE_PROTOCOL = 1;
32163
32163
  var init_bridge_announce = __esm(() => {
32164
32164
  init_errors();
32165
+ init_process_children();
32165
32166
  });
32166
32167
 
32167
32168
  // src/class-note.ts
32168
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "node:fs";
32169
- import { dirname as dirname11, join as join16 } from "node:path";
32169
+ import { mkdirSync as mkdirSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "node:fs";
32170
+ import { dirname as dirname12, join as join17 } from "node:path";
32170
32171
  function classNotePath(projectPath) {
32171
- return join16(projectPath, ".godot", "gdharness-classes.json");
32172
+ return join17(projectPath, ".godot", "gdharness-classes.json");
32172
32173
  }
32173
32174
  function readClassNote(projectPath) {
32174
32175
  try {
32175
- const fields = asParams(JSON.parse(readFileSync14(classNotePath(projectPath), "utf8")));
32176
+ const fields = asParams(JSON.parse(readFileSync15(classNotePath(projectPath), "utf8")));
32176
32177
  const rebuiltWith = readArray(fields, "rebuiltWith");
32177
32178
  if (rebuiltWith === undefined || !rebuiltWith.every((name) => typeof name === "string")) {
32178
32179
  return null;
@@ -32189,24 +32190,24 @@ function readClassNote(projectPath) {
32189
32190
  function writeClassNote(projectPath, note) {
32190
32191
  try {
32191
32192
  const path = classNotePath(projectPath);
32192
- mkdirSync9(dirname11(path), { recursive: true });
32193
- writeFileSync11(path, `${JSON.stringify(note, null, 2)}
32193
+ mkdirSync10(dirname12(path), { recursive: true });
32194
+ writeFileSync12(path, `${JSON.stringify(note, null, 2)}
32194
32195
  `, "utf8");
32195
32196
  } catch {}
32196
32197
  }
32197
32198
  var init_class_note = () => {};
32198
32199
 
32199
32200
  // src/config-pin.ts
32200
- import { existsSync as existsSync11, readFileSync as readFileSync15 } from "node:fs";
32201
- import { join as join17 } from "node:path";
32201
+ import { existsSync as existsSync11, readFileSync as readFileSync16 } from "node:fs";
32202
+ import { join as join18 } from "node:path";
32202
32203
  function versionsNamedInConfig(projectPath) {
32203
- const config = join17(projectPath, ".mcp.json");
32204
+ const config = join18(projectPath, ".mcp.json");
32204
32205
  if (!existsSync11(config)) {
32205
32206
  return [];
32206
32207
  }
32207
32208
  let text;
32208
32209
  try {
32209
- text = readFileSync15(config, "utf8");
32210
+ text = readFileSync16(config, "utf8");
32210
32211
  JSON.parse(text);
32211
32212
  } catch {
32212
32213
  return [];
@@ -32314,7 +32315,7 @@ function portFromEnvOrNull(variable) {
32314
32315
  }
32315
32316
  const parsed = Number.parseInt(raw, 10);
32316
32317
  if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535 || String(parsed) !== raw) {
32317
- throw new Refusal2(`${variable} is "${raw}", not a port between 1 and 65535.`);
32318
+ throw new Refusal(`${variable} is "${raw}", not a port between 1 and 65535.`);
32318
32319
  }
32319
32320
  return parsed;
32320
32321
  }
@@ -32328,7 +32329,7 @@ async function freePort(preferred, host = "127.0.0.1") {
32328
32329
  }
32329
32330
  const spare = await bindable(0, host);
32330
32331
  if (spare === null) {
32331
- throw new Refusal2(`No port could be bound on ${host}.`);
32332
+ throw new Refusal(`No port could be bound on ${host}.`);
32332
32333
  }
32333
32334
  return spare;
32334
32335
  }
@@ -32478,7 +32479,7 @@ class GodotDAPClient {
32478
32479
  async sendRequest(command, args, timeoutMs = DAP_REQUEST_TIMEOUT_MS) {
32479
32480
  await this.ensureConnected();
32480
32481
  if (!this.socket) {
32481
- throw new Refusal2("DAP socket is not available");
32482
+ throw new Refusal("DAP socket is not available");
32482
32483
  }
32483
32484
  const requestSeq = this.seq++;
32484
32485
  const request = {
@@ -32888,7 +32889,7 @@ async function handleDAPTool(client, toolName, args) {
32888
32889
  }
32889
32890
  case "dap_set_breakpoint": {
32890
32891
  if (typeof safeArgs.scriptPath !== "string" || typeof safeArgs.line !== "number") {
32891
- throw new Refusal2("dap_set_breakpoint requires { scriptPath: string, line: number }");
32892
+ throw new Refusal("dap_set_breakpoint requires { scriptPath: string, line: number }");
32892
32893
  }
32893
32894
  const result = await client.setBreakpoint(safeArgs.scriptPath, safeArgs.line);
32894
32895
  return {
@@ -32897,7 +32898,7 @@ async function handleDAPTool(client, toolName, args) {
32897
32898
  }
32898
32899
  case "dap_remove_breakpoint": {
32899
32900
  if (typeof safeArgs.scriptPath !== "string" || typeof safeArgs.line !== "number") {
32900
- throw new Refusal2("dap_remove_breakpoint requires { scriptPath: string, line: number }");
32901
+ throw new Refusal("dap_remove_breakpoint requires { scriptPath: string, line: number }");
32901
32902
  }
32902
32903
  const result = await client.removeBreakpoint(safeArgs.scriptPath, safeArgs.line);
32903
32904
  return {
@@ -32960,24 +32961,24 @@ var init_dap_client = __esm(() => {
32960
32961
  import {
32961
32962
  closeSync,
32962
32963
  existsSync as existsSync12,
32963
- mkdirSync as mkdirSync10,
32964
+ mkdirSync as mkdirSync11,
32964
32965
  openSync,
32965
- readFileSync as readFileSync16,
32966
+ readFileSync as readFileSync17,
32966
32967
  readSync,
32967
- rmSync as rmSync8,
32968
+ rmSync as rmSync9,
32968
32969
  statSync as statSync6,
32969
- writeFileSync as writeFileSync12
32970
+ writeFileSync as writeFileSync13
32970
32971
  } from "node:fs";
32971
- import { dirname as dirname12, join as join18 } from "node:path";
32972
+ import { dirname as dirname13, join as join19 } from "node:path";
32972
32973
  function editorLogPath(projectPath) {
32973
- return join18(projectPath, ".godot", "gdharness-editor.log");
32974
+ return join19(projectPath, ".godot", "gdharness-editor.log");
32974
32975
  }
32975
32976
  function editorLogNotePath(projectPath) {
32976
- return join18(projectPath, ".godot", "gdharness-editor.json");
32977
+ return join19(projectPath, ".godot", "gdharness-editor.json");
32977
32978
  }
32978
32979
  function readEditorLogNote(projectPath) {
32979
32980
  try {
32980
- const fields = asParams(JSON.parse(readFileSync16(editorLogNotePath(projectPath), "utf8")));
32981
+ const fields = asParams(JSON.parse(readFileSync17(editorLogNotePath(projectPath), "utf8")));
32981
32982
  const pid = readNumber(fields, "pid");
32982
32983
  const startedAt = readString(fields, "startedAt");
32983
32984
  return pid !== undefined && Number.isInteger(pid) && pid > 0 && startedAt !== undefined ? { pid, startedAt } : null;
@@ -32988,16 +32989,16 @@ function readEditorLogNote(projectPath) {
32988
32989
  function clearEditorLog(projectPath) {
32989
32990
  try {
32990
32991
  const path = editorLogPath(projectPath);
32991
- mkdirSync10(dirname12(path), { recursive: true });
32992
- rmSync8(path, { force: true });
32993
- rmSync8(editorLogNotePath(projectPath), { force: true });
32992
+ mkdirSync11(dirname13(path), { recursive: true });
32993
+ rmSync9(path, { force: true });
32994
+ rmSync9(editorLogNotePath(projectPath), { force: true });
32994
32995
  } catch {}
32995
32996
  }
32996
32997
  function writeEditorLogNote(projectPath, pid) {
32997
32998
  try {
32998
32999
  const path = editorLogNotePath(projectPath);
32999
- mkdirSync10(dirname12(path), { recursive: true });
33000
- writeFileSync12(path, JSON.stringify({ pid, startedAt: new Date().toISOString() }, null, 2), "utf8");
33000
+ mkdirSync11(dirname13(path), { recursive: true });
33001
+ writeFileSync13(path, JSON.stringify({ pid, startedAt: new Date().toISOString() }, null, 2), "utf8");
33001
33002
  } catch {}
33002
33003
  }
33003
33004
  function theConsoleWasNotCaptured(why, projectPath) {
@@ -33030,7 +33031,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
33030
33031
  function theFirstOf(path) {
33031
33032
  const whole = statSync6(path).size;
33032
33033
  if (whole <= MOST_CONSOLE_BYTES) {
33033
- return { text: readFileSync16(path, "utf8") };
33034
+ return { text: readFileSync17(path, "utf8") };
33034
33035
  }
33035
33036
  const handle = openSync(path, "r");
33036
33037
  try {
@@ -36448,7 +36449,7 @@ var init_godot_bridge = __esm(() => {
36448
36449
  }
36449
36450
  sendMessage(message) {
36450
36451
  if (this.socket?.readyState !== import_websocket.default.OPEN) {
36451
- throw new Refusal2("Godot is not connected");
36452
+ throw new Refusal("Godot is not connected");
36452
36453
  }
36453
36454
  this.socket.send(JSON.stringify(message));
36454
36455
  }
@@ -36998,7 +36999,7 @@ var init_junit = __esm(() => {
36998
36999
  import { realpathSync as realpathSync2 } from "node:fs";
36999
37000
  import { readFile, realpath } from "node:fs/promises";
37000
37001
  import { createConnection as createConnection3 } from "node:net";
37001
- import { dirname as dirname13, resolve as resolve4 } from "node:path";
37002
+ import { dirname as dirname14, resolve as resolve4 } from "node:path";
37002
37003
  import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
37003
37004
  function diagnosticsKey(uri) {
37004
37005
  let decoded;
@@ -37126,13 +37127,13 @@ class GodotLSPClient {
37126
37127
  if (this.initialized) {
37127
37128
  return;
37128
37129
  }
37129
- const rootPath = this.rootPath ?? dirname13(resolve4(filePath));
37130
+ const rootPath = this.rootPath ?? dirname14(resolve4(filePath));
37130
37131
  await this.initialize(rootPath);
37131
37132
  }
37132
37133
  async sendRequest(method, params) {
37133
37134
  await this.ensureConnected();
37134
37135
  if (!this.socket) {
37135
- throw new Refusal2("Not connected to Godot LSP");
37136
+ throw new Refusal("Not connected to Godot LSP");
37136
37137
  }
37137
37138
  this.requestId += 1;
37138
37139
  const id = this.requestId;
@@ -37171,7 +37172,7 @@ class GodotLSPClient {
37171
37172
  }
37172
37173
  sendNotification(method, params) {
37173
37174
  if (!this.connected || !this.socket) {
37174
- throw new Refusal2("Not connected to Godot LSP");
37175
+ throw new Refusal("Not connected to Godot LSP");
37175
37176
  }
37176
37177
  const payload = {
37177
37178
  jsonrpc: "2.0",
@@ -37453,36 +37454,36 @@ async function resolveLSPPaths(projectPathValue, scriptPathValue) {
37453
37454
  try {
37454
37455
  projectPath = await realpath(requestedProjectPath);
37455
37456
  } catch {
37456
- throw new Refusal2(`Project path does not exist: ${requestedProjectPath}`);
37457
+ throw new Refusal(`Project path does not exist: ${requestedProjectPath}`);
37457
37458
  }
37458
37459
  const contained = resolveWithinProject(projectPath, scriptPathValue);
37459
37460
  if (!contained.ok) {
37460
- throw new Refusal2(contained.reason);
37461
+ throw new Refusal(contained.reason);
37461
37462
  }
37462
37463
  let scriptPath;
37463
37464
  try {
37464
37465
  scriptPath = await realpath(contained.absolutePath);
37465
37466
  } catch {
37466
- throw new Refusal2(`Script file does not exist: ${contained.absolutePath}`);
37467
+ throw new Refusal(`Script file does not exist: ${contained.absolutePath}`);
37467
37468
  }
37468
37469
  if (!isWithinRoot(projectPath, scriptPath)) {
37469
- throw new Refusal2("scriptPath resolves outside the project root boundary.");
37470
+ throw new Refusal("scriptPath resolves outside the project root boundary.");
37470
37471
  }
37471
37472
  return { projectPath, scriptPath };
37472
37473
  }
37473
37474
  async function handleLSPTool(client, toolName, args) {
37474
37475
  try {
37475
37476
  if (!args || typeof args !== "object") {
37476
- throw new Refusal2("Tool arguments must be an object.");
37477
+ throw new Refusal("Tool arguments must be an object.");
37477
37478
  }
37478
37479
  const parsedArgs = args;
37479
37480
  const projectPathValue = parsedArgs["projectPath"];
37480
37481
  const scriptPathValue = parsedArgs["scriptPath"];
37481
37482
  if (typeof projectPathValue !== "string" || projectPathValue.length === 0) {
37482
- throw new Refusal2("Missing required argument: projectPath");
37483
+ throw new Refusal("Missing required argument: projectPath");
37483
37484
  }
37484
37485
  if (typeof scriptPathValue !== "string" || scriptPathValue.length === 0) {
37485
- throw new Refusal2("Missing required argument: scriptPath");
37486
+ throw new Refusal("Missing required argument: scriptPath");
37486
37487
  }
37487
37488
  const { projectPath, scriptPath } = await resolveLSPPaths(projectPathValue, scriptPathValue);
37488
37489
  const content = await readFile(scriptPath, "utf8");
@@ -37496,7 +37497,7 @@ async function handleLSPTool(client, toolName, args) {
37496
37497
  const line = Number(parsedArgs["line"]);
37497
37498
  const character = Number(parsedArgs["character"]);
37498
37499
  if (!Number.isFinite(line) || !Number.isFinite(character)) {
37499
- throw new Refusal2("Arguments line and character must be numbers.");
37500
+ throw new Refusal("Arguments line and character must be numbers.");
37500
37501
  }
37501
37502
  const completions = await client.getCompletions(scriptPath, content, line, character);
37502
37503
  return asToolResponse({ completions });
@@ -37505,7 +37506,7 @@ async function handleLSPTool(client, toolName, args) {
37505
37506
  const line = Number(parsedArgs["line"]);
37506
37507
  const character = Number(parsedArgs["character"]);
37507
37508
  if (!Number.isFinite(line) || !Number.isFinite(character)) {
37508
- throw new Refusal2("Arguments line and character must be numbers.");
37509
+ throw new Refusal("Arguments line and character must be numbers.");
37509
37510
  }
37510
37511
  const hover = await client.getHover(scriptPath, content, line, character);
37511
37512
  return asToolResponse({ hover });
@@ -37571,13 +37572,13 @@ var init_process_time = __esm(() => {
37571
37572
  });
37572
37573
 
37573
37574
  // src/project-scan.ts
37574
- import { existsSync as existsSync14, readdirSync as readdirSync7, readFileSync as readFileSync17 } from "node:fs";
37575
- import { join as join19 } from "node:path";
37575
+ import { existsSync as existsSync14, readdirSync as readdirSync7, readFileSync as readFileSync18 } from "node:fs";
37576
+ import { join as join20 } from "node:path";
37576
37577
  function skipped(name) {
37577
37578
  return name.startsWith(".") || SKIPPED.has(name);
37578
37579
  }
37579
37580
  function steppedOver(directory) {
37580
- return existsSync14(join19(directory, ".gdignore"));
37581
+ return existsSync14(join20(directory, ".gdignore"));
37581
37582
  }
37582
37583
  function projectStructure(projectPath) {
37583
37584
  const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
@@ -37590,7 +37591,7 @@ function projectStructure(projectPath) {
37590
37591
  continue;
37591
37592
  }
37592
37593
  if (entry.isDirectory()) {
37593
- visit(join19(directory, entry.name));
37594
+ visit(join20(directory, entry.name));
37594
37595
  } else if (entry.isFile()) {
37595
37596
  const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
37596
37597
  if (extension === "tscn") {
@@ -37620,14 +37621,14 @@ function scriptsWithoutUid(projectPath) {
37620
37621
  }
37621
37622
  const spelled = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
37622
37623
  if (entry.isDirectory()) {
37623
- visit(join19(directory, entry.name), spelled);
37624
+ visit(join20(directory, entry.name), spelled);
37624
37625
  continue;
37625
37626
  }
37626
37627
  if (!entry.isFile()) {
37627
37628
  continue;
37628
37629
  }
37629
37630
  const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
37630
- if (CARRIES_A_UID.has(extension) && !existsSync14(join19(directory, `${entry.name}.uid`))) {
37631
+ if (CARRIES_A_UID.has(extension) && !existsSync14(join20(directory, `${entry.name}.uid`))) {
37631
37632
  found.push(spelled);
37632
37633
  }
37633
37634
  }
@@ -37662,7 +37663,7 @@ function searchProject(projectPath, options) {
37662
37663
  if (skipped(entry.name)) {
37663
37664
  continue;
37664
37665
  }
37665
- const entryPath = join19(directory, entry.name);
37666
+ const entryPath = join20(directory, entry.name);
37666
37667
  if (entry.isDirectory()) {
37667
37668
  visit(entryPath);
37668
37669
  continue;
@@ -37673,7 +37674,7 @@ function searchProject(projectPath, options) {
37673
37674
  }
37674
37675
  result.summary.files_searched += 1;
37675
37676
  const matches = [];
37676
- for (const [index, line] of readFileSync17(entryPath, "utf8").split(`
37677
+ for (const [index, line] of readFileSync18(entryPath, "utf8").split(`
37677
37678
  `).entries()) {
37678
37679
  if (full()) {
37679
37680
  break;
@@ -37702,16 +37703,16 @@ var init_project_scan = __esm(() => {
37702
37703
  });
37703
37704
 
37704
37705
  // src/restart-note.ts
37705
- import { mkdirSync as mkdirSync11, readFileSync as readFileSync18, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
37706
- import { dirname as dirname14, join as join20 } from "node:path";
37706
+ import { mkdirSync as mkdirSync12, readFileSync as readFileSync19, rmSync as rmSync10, writeFileSync as writeFileSync14 } from "node:fs";
37707
+ import { dirname as dirname15, join as join21 } from "node:path";
37707
37708
  function restartNotePath(projectPath) {
37708
- return join20(projectPath, ".godot", "gdharness-restart.json");
37709
+ return join21(projectPath, ".godot", "gdharness-restart.json");
37709
37710
  }
37710
37711
  function noteRestartBegun(note) {
37711
37712
  const path = restartNotePath(note.projectPath);
37712
37713
  try {
37713
- mkdirSync11(dirname14(path), { recursive: true });
37714
- writeFileSync13(path, `${JSON.stringify(note, null, 2)}
37714
+ mkdirSync12(dirname15(path), { recursive: true });
37715
+ writeFileSync14(path, `${JSON.stringify(note, null, 2)}
37715
37716
  `, "utf8");
37716
37717
  } catch (error) {
37717
37718
  console.error(`[SERVER] Could not record the restart at ${path}: ${errorMessage(error)}`);
@@ -37719,7 +37720,7 @@ function noteRestartBegun(note) {
37719
37720
  }
37720
37721
  function restartOwed(projectPath) {
37721
37722
  try {
37722
- const parsed = JSON.parse(readFileSync18(restartNotePath(projectPath), "utf8"));
37723
+ const parsed = JSON.parse(readFileSync19(restartNotePath(projectPath), "utf8"));
37723
37724
  if (typeof parsed !== "object" || parsed === null) {
37724
37725
  return null;
37725
37726
  }
@@ -37734,7 +37735,7 @@ function restartOwed(projectPath) {
37734
37735
  }
37735
37736
  function restartSettled(projectPath) {
37736
37737
  try {
37737
- rmSync9(restartNotePath(projectPath), { force: true });
37738
+ rmSync10(restartNotePath(projectPath), { force: true });
37738
37739
  } catch (error) {
37739
37740
  console.error(`[SERVER] Could not clear the restart note: ${errorMessage(error)}`);
37740
37741
  }
@@ -37745,36 +37746,36 @@ var init_restart_note = __esm(() => {
37745
37746
 
37746
37747
  // src/run-record.ts
37747
37748
  import { execFileSync as execFileSync2 } from "node:child_process";
37748
- import { mkdirSync as mkdirSync12, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync19, rmSync as rmSync10, statSync as statSync7, writeFileSync as writeFileSync14 } from "node:fs";
37749
- import { basename as basename3, join as join21 } from "node:path";
37749
+ import { mkdirSync as mkdirSync13, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync20, rmSync as rmSync11, statSync as statSync7, writeFileSync as writeFileSync15 } from "node:fs";
37750
+ import { basename as basename3, join as join22 } from "node:path";
37750
37751
  function runsDirectory() {
37751
- return join21(runtimeDirectory(), "runs");
37752
+ return join22(runtimeDirectory(), "runs");
37752
37753
  }
37753
37754
  function recordPath() {
37754
- return join21(runsDirectory(), "run.json");
37755
+ return join22(runsDirectory(), "run.json");
37755
37756
  }
37756
37757
  function recordPaths() {
37757
- return runtimeDirectories().map((directory) => join21(directory, "runs", "run.json"));
37758
+ return runtimeDirectories().map((directory) => join22(directory, "runs", "run.json"));
37758
37759
  }
37759
37760
  function openTranscript(startedAt) {
37760
- mkdirSync12(runsDirectory(), { recursive: true });
37761
- const path = join21(runsDirectory(), `run-${startedAt}.log`);
37761
+ mkdirSync13(runsDirectory(), { recursive: true });
37762
+ const path = join22(runsDirectory(), `run-${startedAt}.log`);
37762
37763
  return { path, fd: openSync2(path, "a") };
37763
37764
  }
37764
37765
  function writeRunRecord(record) {
37765
- mkdirSync12(runsDirectory(), { recursive: true });
37766
- writeFileSync14(recordPath(), JSON.stringify(record, null, 2), "utf8");
37766
+ mkdirSync13(runsDirectory(), { recursive: true });
37767
+ writeFileSync15(recordPath(), JSON.stringify(record, null, 2), "utf8");
37767
37768
  }
37768
37769
  function editorNotePath() {
37769
- return join21(runsDirectory(), "editor-run.json");
37770
+ return join22(runsDirectory(), "editor-run.json");
37770
37771
  }
37771
37772
  function writeEditorRunNote(note) {
37772
- mkdirSync12(runsDirectory(), { recursive: true });
37773
- writeFileSync14(editorNotePath(), JSON.stringify(note, null, 2), "utf8");
37773
+ mkdirSync13(runsDirectory(), { recursive: true });
37774
+ writeFileSync15(editorNotePath(), JSON.stringify(note, null, 2), "utf8");
37774
37775
  }
37775
37776
  function readEditorRunNote() {
37776
37777
  for (const directory of runtimeDirectories()) {
37777
- const note = editorNoteAt(join21(directory, "runs", "editor-run.json"));
37778
+ const note = editorNoteAt(join22(directory, "runs", "editor-run.json"));
37778
37779
  if (note !== null) {
37779
37780
  return note;
37780
37781
  }
@@ -37784,7 +37785,7 @@ function readEditorRunNote() {
37784
37785
  function editorNoteAt(path) {
37785
37786
  let parsed;
37786
37787
  try {
37787
- parsed = JSON.parse(readFileSync19(path, "utf8"));
37788
+ parsed = JSON.parse(readFileSync20(path, "utf8"));
37788
37789
  } catch {
37789
37790
  return null;
37790
37791
  }
@@ -37807,7 +37808,7 @@ function recordRunEnded(pid, exitCode) {
37807
37808
  return;
37808
37809
  }
37809
37810
  try {
37810
- writeFileSync14(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
37811
+ writeFileSync15(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
37811
37812
  } catch {}
37812
37813
  }
37813
37814
  function readRunRecord() {
@@ -37822,7 +37823,7 @@ function readRunRecord() {
37822
37823
  function recordAt(path) {
37823
37824
  let parsed;
37824
37825
  try {
37825
- parsed = JSON.parse(readFileSync19(path, "utf8"));
37826
+ parsed = JSON.parse(readFileSync20(path, "utf8"));
37826
37827
  } catch {
37827
37828
  return null;
37828
37829
  }
@@ -37867,7 +37868,7 @@ function runningAs(pid) {
37867
37868
  const began = startedAt(pid, null);
37868
37869
  const when = began === null ? {} : { startedAt: began };
37869
37870
  if (process.platform === "linux") {
37870
- const raw = readFileSync19(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
37871
+ const raw = readFileSync20(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
37871
37872
  return raw === "" ? null : { kind: "commandLine", text: raw, ...when };
37872
37873
  }
37873
37874
  const args = execFileSync2("ps", ["-p", String(pid), "-o", "args="], {
@@ -37994,7 +37995,7 @@ function clearRunRecord(ours = () => true) {
37994
37995
  continue;
37995
37996
  }
37996
37997
  try {
37997
- rmSync10(path);
37998
+ rmSync11(path);
37998
37999
  } catch {}
37999
38000
  }
38000
38001
  }
@@ -38018,12 +38019,12 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
38018
38019
  if (!entry.startsWith("run-") || !entry.endsWith(".log")) {
38019
38020
  continue;
38020
38021
  }
38021
- const path = join21(directory, entry);
38022
+ const path = join22(directory, entry);
38022
38023
  if (path === keep || ageMs(path, now) < keepMs) {
38023
38024
  continue;
38024
38025
  }
38025
38026
  try {
38026
- rmSync10(path);
38027
+ rmSync11(path);
38027
38028
  } catch {}
38028
38029
  }
38029
38030
  }
@@ -38044,17 +38045,17 @@ import {
38044
38045
  copyFileSync,
38045
38046
  existsSync as existsSync15,
38046
38047
  fstatSync,
38047
- mkdirSync as mkdirSync13,
38048
+ mkdirSync as mkdirSync14,
38048
38049
  mkdtempSync as mkdtempSync3,
38049
38050
  openSync as openSync3,
38050
38051
  readdirSync as readdirSync9,
38051
- readFileSync as readFileSync20,
38052
+ readFileSync as readFileSync21,
38052
38053
  readSync as readSync2,
38053
38054
  rmdirSync,
38054
38055
  statSync as statSync8
38055
38056
  } from "node:fs";
38056
38057
  import { tmpdir as tmpdir5 } from "node:os";
38057
- import { basename as basename4, dirname as dirname15, extname as extname2, isAbsolute as isAbsolute3, join as join22, normalize as normalize3, relative as relative3 } from "node:path";
38058
+ import { basename as basename4, dirname as dirname16, extname as extname2, isAbsolute as isAbsolute3, join as join23, normalize as normalize3, relative as relative3 } from "node:path";
38058
38059
  import { setTimeout as delay3 } from "node:timers/promises";
38059
38060
  import { fileURLToPath as fileURLToPath5 } from "node:url";
38060
38061
  import { promisify as promisify7 } from "node:util";
@@ -38068,11 +38069,11 @@ function captureDestinationRefusal(outputPath, projects) {
38068
38069
  if (extname2(outputPath).toLowerCase() !== ".png") {
38069
38070
  return `outputPath ${outputPath} does not end in .png, which is what a capture is.`;
38070
38071
  }
38071
- const directory = realPathOr(dirname15(outputPath));
38072
+ const directory = realPathOr(dirname16(outputPath));
38072
38073
  if (!existsSync15(directory)) {
38073
- return `outputPath's directory ${dirname15(outputPath)} does not exist; a capture creates no directories.`;
38074
+ return `outputPath's directory ${dirname16(outputPath)} does not exist; a capture creates no directories.`;
38074
38075
  }
38075
- const where = join22(directory, basename4(outputPath));
38076
+ const where = join23(directory, basename4(outputPath));
38076
38077
  const inside = projects.find((project) => project !== "" && isWithinRoot(realPathOr(project), where));
38077
38078
  if (inside !== undefined) {
38078
38079
  return `outputPath ${outputPath} is inside the project at ${inside}; a capture is saved outside it, so it never becomes part of the game.`;
@@ -38320,7 +38321,7 @@ function aboveTheRunner(entry) {
38320
38321
  }
38321
38322
  function elsewhereIn(projectPath, asked) {
38322
38323
  const wanted = asked.replace(/^res:\/\//, "").replace(/\/+$/, "");
38323
- if (wanted === "" || existsSync15(join22(projectPath, wanted))) {
38324
+ if (wanted === "" || existsSync15(join23(projectPath, wanted))) {
38324
38325
  return "";
38325
38326
  }
38326
38327
  const root = (wanted.split("/")[0] ?? "").toLowerCase();
@@ -38334,7 +38335,7 @@ function elsewhereIn(projectPath, asked) {
38334
38335
  return near.length === 0 ? "" : ` The project does have ${there}.`;
38335
38336
  }
38336
38337
  function hasMainScene(projectFile) {
38337
- const scene = parseProjectGodot(readFileSync20(projectFile, "utf8"))["application"]?.["run/main_scene"];
38338
+ const scene = parseProjectGodot(readFileSync21(projectFile, "utf8"))["application"]?.["run/main_scene"];
38338
38339
  return typeof scene === "string" && scene !== "";
38339
38340
  }
38340
38341
  function runtimeAddonAnnouncesEditors(projectPath) {
@@ -38342,13 +38343,13 @@ function runtimeAddonAnnouncesEditors(projectPath) {
38342
38343
  return false;
38343
38344
  }
38344
38345
  try {
38345
- return readFileSync20(join22(projectPath, RUNTIME_AUTOLOAD2.path), "utf8").includes('"editor_pid"');
38346
+ return readFileSync21(join23(projectPath, RUNTIME_AUTOLOAD2.path), "utf8").includes('"editor_pid"');
38346
38347
  } catch {
38347
38348
  return false;
38348
38349
  }
38349
38350
  }
38350
38351
  function editorPlaysHeadless(projectFile) {
38351
- const runArgs = parseProjectGodot(readFileSync20(projectFile, "utf8"))["editor"]?.["run/main_run_args"];
38352
+ const runArgs = parseProjectGodot(readFileSync21(projectFile, "utf8"))["editor"]?.["run/main_run_args"];
38352
38353
  return typeof runArgs === "string" && /(?:^|\s)--headless(?:\s|$)/.test(runArgs);
38353
38354
  }
38354
38355
  function camelCased(params) {
@@ -38367,7 +38368,7 @@ function needsItsOwnProcess(asked) {
38367
38368
  class GodotServer {
38368
38369
  mcp;
38369
38370
  locator = new GodotLocator2;
38370
- operationsScript = join22(__dirname2, "godot", "operations", "godot_operations.gd");
38371
+ operationsScript = join23(__dirname2, "godot", "operations", "godot_operations.gd");
38371
38372
  godotBridge;
38372
38373
  tools = buildToolDefinitions();
38373
38374
  activeProcess = null;
@@ -38511,7 +38512,7 @@ class GodotServer {
38511
38512
  if (this.ownProject === null) {
38512
38513
  return null;
38513
38514
  }
38514
- const announced = readAnnouncement(announcementPath(this.ownProject));
38515
+ const announced = readAnnouncement2(announcementPath2(this.ownProject));
38515
38516
  if (announced === null || announced.pid === process.pid) {
38516
38517
  return null;
38517
38518
  }
@@ -38621,7 +38622,7 @@ class GodotServer {
38621
38622
  try {
38622
38623
  return await this.dispatch(tool, op, args);
38623
38624
  } catch (error) {
38624
- if (error instanceof McpError || error instanceof Refusal2) {
38625
+ if (error instanceof McpError || error instanceof Refusal) {
38625
38626
  throw error;
38626
38627
  }
38627
38628
  const where = op === "" ? tool : `${tool} op=${op}`;
@@ -39032,7 +39033,7 @@ class GodotServer {
39032
39033
  if (path === undefined) {
39033
39034
  return { ok: false, response: this.createErrorResponse("projectPath is required.") };
39034
39035
  }
39035
- const file = join22(path, "project.godot");
39036
+ const file = join23(path, "project.godot");
39036
39037
  if (!existsSync15(file)) {
39037
39038
  return {
39038
39039
  ok: false,
@@ -39301,7 +39302,7 @@ class GodotServer {
39301
39302
  if (!engine.ok) {
39302
39303
  return engine.response;
39303
39304
  }
39304
- const application = parseProjectGodot(readFileSync20(project.value.file, "utf8"))["application"] ?? {};
39305
+ const application = parseProjectGodot(readFileSync21(project.value.file, "utf8"))["application"] ?? {};
39305
39306
  const name = application["config/name"];
39306
39307
  const mainScene = application["run/main_scene"];
39307
39308
  const info = {
@@ -39362,18 +39363,18 @@ class GodotServer {
39362
39363
  if (!engine.ok) {
39363
39364
  return engine.response;
39364
39365
  }
39365
- const folder = dirname15(output.absolutePath);
39366
+ const folder = dirname16(output.absolutePath);
39366
39367
  try {
39367
- mkdirSync13(folder, { recursive: true });
39368
+ mkdirSync14(folder, { recursive: true });
39368
39369
  } catch (error) {
39369
- return this.createErrorResponse(`Cannot create ${dirname15(output.relativePath)} to export into: ${errorMessage(error)}`);
39370
+ return this.createErrorResponse(`Cannot create ${dirname16(output.relativePath)} to export into: ${errorMessage(error)}`);
39370
39371
  }
39371
39372
  const debug = readBoolean(args, "debug") ?? false;
39372
- const exportLogs = mkdtempSync3(join22(tmpdir5(), "gdharness-export-"));
39373
+ const exportLogs = mkdtempSync3(join23(tmpdir5(), "gdharness-export-"));
39373
39374
  const exportArgs = [
39374
39375
  "--headless",
39375
39376
  "--log-file",
39376
- join22(exportLogs, "engine.log"),
39377
+ join23(exportLogs, "engine.log"),
39377
39378
  "--path",
39378
39379
  project.value.path,
39379
39380
  debug ? "--export-debug" : "--export-release",
@@ -39434,7 +39435,7 @@ class GodotServer {
39434
39435
  return contained.response;
39435
39436
  }
39436
39437
  const runner = "addons/gdUnit4/bin/GdUnitCmdTool.gd";
39437
- if (!existsSync15(join22(project.value.path, runner))) {
39438
+ if (!existsSync15(join23(project.value.path, runner))) {
39438
39439
  return this.createErrorResponse(`gdUnit4 is not installed in this project: no ${runner}.`, [
39439
39440
  "Install gdUnit4 under addons/gdUnit4, from https://github.com/godot-gdunit-labs/gdUnit4"
39440
39441
  ]);
@@ -39469,7 +39470,7 @@ class GodotServer {
39469
39470
  ];
39470
39471
  const timeoutMs = readPositiveNumber(args, "timeoutMs") ?? 600000;
39471
39472
  this.logDebug(`Running tests: ${engine.value} ${cmdArgs.join(" ")}`);
39472
- const userData = mkdtempSync3(join22(tmpdir5(), "gdharness-tests-"));
39473
+ const userData = mkdtempSync3(join23(tmpdir5(), "gdharness-tests-"));
39473
39474
  const run = this.spawnGame(engine.value, cmdArgs, userDataIn(userData));
39474
39475
  const hung = await new Promise((resolve) => {
39475
39476
  const timer = setTimeout(() => {
@@ -39485,21 +39486,21 @@ class GodotServer {
39485
39486
  resolve(false);
39486
39487
  });
39487
39488
  });
39488
- const reportsDir = join22(project.value.path, ".godot", ...ours.split("/"));
39489
+ const reportsDir = join23(project.value.path, ".godot", ...ours.split("/"));
39489
39490
  let report = null;
39490
39491
  let reportProblem = null;
39491
39492
  try {
39492
39493
  const written = existsSync15(reportsDir) ? readdirSync9(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
39493
39494
  const newest = written.at(-1);
39494
39495
  if (newest !== undefined) {
39495
- report = parseJUnit(readFileSync20(join22(reportsDir, newest, "results.xml"), "utf8"));
39496
+ report = parseJUnit(readFileSync21(join23(reportsDir, newest, "results.xml"), "utf8"));
39496
39497
  }
39497
39498
  } catch (error) {
39498
39499
  reportProblem = errorMessage(error);
39499
39500
  } finally {
39500
39501
  discard(reportsDir, userData);
39501
39502
  try {
39502
- rmdirSync(dirname15(reportsDir));
39503
+ rmdirSync(dirname16(reportsDir));
39503
39504
  } catch {}
39504
39505
  }
39505
39506
  const engineEntries = run.log.select({ severity: "warning", sinceLastCall: false, limit: 200 }).entries.map(aboveTheRunner);
@@ -39635,7 +39636,7 @@ class GodotServer {
39635
39636
  return null;
39636
39637
  }
39637
39638
  try {
39638
- return readFileSync20(contained.absolutePath, "utf8");
39639
+ return readFileSync21(contained.absolutePath, "utf8");
39639
39640
  } catch {
39640
39641
  return null;
39641
39642
  }
@@ -39689,7 +39690,7 @@ class GodotServer {
39689
39690
  return null;
39690
39691
  }
39691
39692
  try {
39692
- return readFileSync20(contained.absolutePath, "utf8");
39693
+ return readFileSync21(contained.absolutePath, "utf8");
39693
39694
  } catch {
39694
39695
  return null;
39695
39696
  }
@@ -39918,7 +39919,7 @@ class GodotServer {
39918
39919
  return null;
39919
39920
  }
39920
39921
  try {
39921
- return settingKeys(readFileSync20(join22(projectPath, "project.godot"), "utf8"));
39922
+ return settingKeys(readFileSync21(join23(projectPath, "project.godot"), "utf8"));
39922
39923
  } catch {
39923
39924
  return null;
39924
39925
  }
@@ -40169,7 +40170,7 @@ class GodotServer {
40169
40170
  }
40170
40171
  async runtimeUp(projectPath, before, budget, withArgs) {
40171
40172
  const budgetMs = budget.ms;
40172
- if (!existsSync15(join22(projectPath, RUNTIME_AUTOLOAD2.path))) {
40173
+ if (!existsSync15(join23(projectPath, RUNTIME_AUTOLOAD2.path))) {
40173
40174
  return runtimeVerdict(null, { addon: false, budgetMs, heldAt: null, running: false, withArgs });
40174
40175
  }
40175
40176
  let asking = null;
@@ -40826,7 +40827,8 @@ class GodotServer {
40826
40827
  }
40827
40828
  const budgetMs = readPositiveNumber(args, "timeoutMs") ?? WAIT_FOR_RUN_MS;
40828
40829
  const until = Date.now() + budgetMs;
40829
- while (await this.runStillGoing(run) && Date.now() < until) {
40830
+ const cancelled = callSignal();
40831
+ while (cancelled?.aborted !== true && await this.runStillGoing(run) && Date.now() < until) {
40830
40832
  this.drainEditorOutput(run);
40831
40833
  this.drainTranscript(run);
40832
40834
  await delay3(RUN_POLL_MS);
@@ -41352,7 +41354,7 @@ class GodotServer {
41352
41354
  async ownRunOnItsWay(projectPath, budgetMs) {
41353
41355
  const run = this.currentRun();
41354
41356
  const project = projectPath ?? run?.projectPath ?? null;
41355
- if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync15(join22(project, RUNTIME_AUTOLOAD2.path)) || !await this.runStillGoing(run)) {
41357
+ if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync15(join23(project, RUNTIME_AUTOLOAD2.path)) || !await this.runStillGoing(run)) {
41356
41358
  return null;
41357
41359
  }
41358
41360
  const already = runtimesAnnounced().running;
@@ -41431,8 +41433,8 @@ class GodotServer {
41431
41433
  return this.createErrorResponse(refusal);
41432
41434
  }
41433
41435
  }
41434
- const screenshotDir = expectsScreenshot ? mkdtempSync3(join22(tmpdir5(), "gdharness-runtime-screenshot-")) : null;
41435
- const screenshotPath = screenshotDir ? join22(screenshotDir, "capture.png") : null;
41436
+ const screenshotDir = expectsScreenshot ? mkdtempSync3(join23(tmpdir5(), "gdharness-runtime-screenshot-")) : null;
41437
+ const screenshotPath = screenshotDir ? join23(screenshotDir, "capture.png") : null;
41436
41438
  try {
41437
41439
  const reply = await runtimeRequest(choice.endpoint, command, screenshotPath ? { ...params, output_path: screenshotPath } : params, timeoutMs);
41438
41440
  if (!reply.ok) {
@@ -41463,7 +41465,7 @@ class GodotServer {
41463
41465
  type: "text",
41464
41466
  text: `Screenshot captured: ${dimensions}${chosenAmongSeveral ? ` from pid ${own}, the game this server holds` : ""}${saveTo === null ? "" : `. Saved to ${saveTo}`}`
41465
41467
  },
41466
- { type: "image", data: readFileSync20(screenshotPath).toString("base64"), mimeType: "image/png" }
41468
+ { type: "image", data: readFileSync21(screenshotPath).toString("base64"), mimeType: "image/png" }
41467
41469
  ]
41468
41470
  };
41469
41471
  } finally {
@@ -41572,7 +41574,7 @@ var init_server3 = __esm(() => {
41572
41574
  init_tool_definitions();
41573
41575
  init_update_check();
41574
41576
  run7 = promisify7(execFile7);
41575
- __dirname2 = dirname15(fileURLToPath5(import.meta.url));
41577
+ __dirname2 = dirname16(fileURLToPath5(import.meta.url));
41576
41578
  CONSOLE_WRAPPER = /_console(\.exe)?$/i;
41577
41579
  LONGEST_BOOT_NOTED_MS = 5 * 60000;
41578
41580
  VALUE_NAMES = {
@@ -41613,20 +41615,61 @@ var init_server3 = __esm(() => {
41613
41615
 
41614
41616
  // src/cli.ts
41615
41617
  import { existsSync as existsSync16 } from "fs";
41616
- import { join as join23, resolve as resolve5 } from "path";
41618
+ import { join as join24, resolve as resolve5 } from "path";
41619
+
41620
+ // src/bridge-announce.ts
41621
+ init_errors();
41622
+ init_process_children();
41623
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
41624
+ import { dirname, join } from "node:path";
41625
+ function announcementPath(projectPath) {
41626
+ return join(projectPath, ".godot", "gdharness-bridge.json");
41627
+ }
41628
+ function readAnnouncement(path) {
41629
+ try {
41630
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
41631
+ if (typeof parsed !== "object" || parsed === null) {
41632
+ return null;
41633
+ }
41634
+ const said = parsed;
41635
+ if (typeof said.port !== "number" || typeof said.pid !== "number") {
41636
+ return null;
41637
+ }
41638
+ return said;
41639
+ } catch {
41640
+ return null;
41641
+ }
41642
+ }
41643
+ function serverBehind(announcement, startedAt) {
41644
+ if (announcement === null || typeof announcement.version !== "string" || startedAt === undefined) {
41645
+ return null;
41646
+ }
41647
+ const announcedAt = Date.parse(announcement.startedAt);
41648
+ if (Number.isNaN(announcedAt) || startedAt > announcedAt + 1000) {
41649
+ return null;
41650
+ }
41651
+ return { version: announcement.version, pid: announcement.pid };
41652
+ }
41653
+ function serverServing(projectPath) {
41654
+ const announcement = readAnnouncement(announcementPath(projectPath));
41655
+ if (announcement === null) {
41656
+ return null;
41657
+ }
41658
+ return serverBehind(announcement, startTimesOf([announcement.pid]).get(announcement.pid));
41659
+ }
41617
41660
 
41618
41661
  // src/errors.ts
41619
- class Refusal extends Error {
41662
+ class Refusal2 extends Error {
41620
41663
  }
41621
41664
 
41622
41665
  // src/godot-path.ts
41623
41666
  init_detection();
41624
41667
  init_errors();
41625
- import { execFile } from "node:child_process";
41668
+ import { execFile as execFile2 } from "node:child_process";
41626
41669
  import { existsSync as existsSync2 } from "node:fs";
41627
41670
  import { normalize } from "node:path";
41628
- import { promisify } from "node:util";
41629
- var run = promisify(execFile);
41671
+ import { promisify as promisify2 } from "node:util";
41672
+ var run2 = promisify2(execFile2);
41630
41673
 
41631
41674
  class GodotLocator {
41632
41675
  answered = new Map;
@@ -41683,7 +41726,7 @@ class GodotLocator {
41683
41726
  reason = "does not exist";
41684
41727
  } else {
41685
41728
  try {
41686
- await run(path, ["--version"]);
41729
+ await run2(path, ["--version"]);
41687
41730
  reason = null;
41688
41731
  } catch (error) {
41689
41732
  reason = `does not answer --version: ${errorMessage(error)}`;
@@ -41695,9 +41738,9 @@ class GodotLocator {
41695
41738
  }
41696
41739
 
41697
41740
  // src/harnesses.ts
41698
- import { existsSync as existsSync4, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
41741
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
41699
41742
  import { homedir as homedir2 } from "node:os";
41700
- import { dirname as dirname2, join as join3 } from "node:path";
41743
+ import { dirname as dirname3, join as join4 } from "node:path";
41701
41744
  import process3 from "node:process";
41702
41745
 
41703
41746
  // node_modules/yaml/dist/index.js
@@ -41870,7 +41913,7 @@ var HARNESSES = [
41870
41913
  shape: "plain",
41871
41914
  home: ".claude",
41872
41915
  marker: ".claude",
41873
- skills: { dir: join3(".claude", "skills"), shared: false }
41916
+ skills: { dir: join4(".claude", "skills"), shared: false }
41874
41917
  },
41875
41918
  {
41876
41919
  id: "copilot-cli",
@@ -41880,7 +41923,7 @@ var HARNESSES = [
41880
41923
  container: "mcpServers",
41881
41924
  shape: "plain",
41882
41925
  home: ".copilot",
41883
- skills: { dir: join3(".github", "skills"), shared: true },
41926
+ skills: { dir: join4(".github", "skills"), shared: true },
41884
41927
  manual: "Trust the folder when Copilot CLI first asks, or it reads no config here."
41885
41928
  },
41886
41929
  {
@@ -41906,22 +41949,22 @@ var HARNESSES = [
41906
41949
  id: "cursor",
41907
41950
  name: "Cursor",
41908
41951
  scope: "project",
41909
- file: join3(".cursor", "mcp.json"),
41952
+ file: join4(".cursor", "mcp.json"),
41910
41953
  container: "mcpServers",
41911
41954
  shape: "plain",
41912
41955
  home: ".cursor",
41913
- skills: { dir: join3(".cursor", "skills"), shared: true },
41956
+ skills: { dir: join4(".cursor", "skills"), shared: true },
41914
41957
  manual: "Cursor asks before each tool call by default, and the server can be toggled off."
41915
41958
  },
41916
41959
  {
41917
41960
  id: "vscode",
41918
41961
  name: "VS Code",
41919
41962
  scope: "project",
41920
- file: join3(".vscode", "mcp.json"),
41963
+ file: join4(".vscode", "mcp.json"),
41921
41964
  container: "servers",
41922
41965
  shape: "typed",
41923
41966
  home: ".vscode",
41924
- skills: { dir: join3(".github", "skills"), shared: true },
41967
+ skills: { dir: join4(".github", "skills"), shared: true },
41925
41968
  manual: "VS Code asks you to trust a server the first time it starts one."
41926
41969
  },
41927
41970
  {
@@ -41931,45 +41974,45 @@ var HARNESSES = [
41931
41974
  file: "opencode.json",
41932
41975
  container: "mcp",
41933
41976
  shape: "opencode",
41934
- home: join3(".config", "opencode"),
41977
+ home: join4(".config", "opencode"),
41935
41978
  marker: ".opencode",
41936
- skills: { dir: join3(".opencode", "skills"), shared: true }
41979
+ skills: { dir: join4(".opencode", "skills"), shared: true }
41937
41980
  },
41938
41981
  {
41939
41982
  id: "junie",
41940
41983
  name: "Junie",
41941
41984
  scope: "project",
41942
- file: join3(".junie", "mcp", "mcp.json"),
41985
+ file: join4(".junie", "mcp", "mcp.json"),
41943
41986
  container: "mcpServers",
41944
41987
  shape: "plain",
41945
41988
  home: ".junie",
41946
- skills: { dir: join3(".junie", "skills"), shared: true }
41989
+ skills: { dir: join4(".junie", "skills"), shared: true }
41947
41990
  },
41948
41991
  {
41949
41992
  id: "kiro",
41950
41993
  name: "Kiro",
41951
41994
  scope: "project",
41952
- file: join3(".kiro", "settings", "mcp.json"),
41995
+ file: join4(".kiro", "settings", "mcp.json"),
41953
41996
  container: "mcpServers",
41954
41997
  shape: "plain",
41955
41998
  home: ".kiro",
41956
- skills: { dir: join3(".kiro", "skills"), shared: false }
41999
+ skills: { dir: join4(".kiro", "skills"), shared: false }
41957
42000
  },
41958
42001
  {
41959
42002
  id: "gemini",
41960
42003
  name: "Gemini CLI",
41961
42004
  scope: "project",
41962
- file: join3(".gemini", "settings.json"),
42005
+ file: join4(".gemini", "settings.json"),
41963
42006
  container: "mcpServers",
41964
42007
  shape: "plain",
41965
42008
  home: ".gemini",
41966
- skills: { dir: join3(".gemini", "skills"), shared: true }
42009
+ skills: { dir: join4(".gemini", "skills"), shared: true }
41967
42010
  },
41968
42011
  {
41969
42012
  id: "roo",
41970
42013
  name: "Roo Code",
41971
42014
  scope: "project",
41972
- file: join3(".roo", "mcp.json"),
42015
+ file: join4(".roo", "mcp.json"),
41973
42016
  container: "mcpServers",
41974
42017
  shape: "plain"
41975
42018
  },
@@ -41977,7 +42020,7 @@ var HARNESSES = [
41977
42020
  id: "kilo",
41978
42021
  name: "Kilo Code",
41979
42022
  scope: "project",
41980
- file: join3(".kilocode", "mcp.json"),
42023
+ file: join4(".kilocode", "mcp.json"),
41981
42024
  container: "mcpServers",
41982
42025
  shape: "plain"
41983
42026
  },
@@ -41985,16 +42028,16 @@ var HARNESSES = [
41985
42028
  id: "amazon-q",
41986
42029
  name: "Amazon Q Developer CLI",
41987
42030
  scope: "project",
41988
- file: join3(".amazonq", "mcp.json"),
42031
+ file: join4(".amazonq", "mcp.json"),
41989
42032
  container: "mcpServers",
41990
42033
  shape: "plain",
41991
- home: join3(".aws", "amazonq")
42034
+ home: join4(".aws", "amazonq")
41992
42035
  },
41993
42036
  {
41994
42037
  id: "zed",
41995
42038
  name: "Zed",
41996
42039
  scope: "project",
41997
- file: join3(".zed", "settings.json"),
42040
+ file: join4(".zed", "settings.json"),
41998
42041
  container: "context_servers",
41999
42042
  shape: "plain"
42000
42043
  },
@@ -42002,16 +42045,16 @@ var HARNESSES = [
42002
42045
  id: "amp",
42003
42046
  name: "Amp",
42004
42047
  scope: "project",
42005
- file: join3(".amp", "settings.json"),
42048
+ file: join4(".amp", "settings.json"),
42006
42049
  container: "amp.mcpServers",
42007
42050
  shape: "plain",
42008
- home: join3(".config", "amp")
42051
+ home: join4(".config", "amp")
42009
42052
  },
42010
42053
  {
42011
42054
  id: "warp",
42012
42055
  name: "Warp",
42013
42056
  scope: "project",
42014
- file: join3(".warp", ".mcp.json"),
42057
+ file: join4(".warp", ".mcp.json"),
42015
42058
  container: "mcpServers",
42016
42059
  shape: "plain",
42017
42060
  home: ".warp",
@@ -42021,7 +42064,7 @@ var HARNESSES = [
42021
42064
  id: "trae",
42022
42065
  name: "Trae",
42023
42066
  scope: "project",
42024
- file: join3(".trae", "mcp.json"),
42067
+ file: join4(".trae", "mcp.json"),
42025
42068
  container: "mcpServers",
42026
42069
  shape: "plain",
42027
42070
  home: ".trae"
@@ -42030,7 +42073,7 @@ var HARNESSES = [
42030
42073
  id: "factory",
42031
42074
  name: "Factory Droid",
42032
42075
  scope: "project",
42033
- file: join3(".factory", "mcp.json"),
42076
+ file: join4(".factory", "mcp.json"),
42034
42077
  container: "mcpServers",
42035
42078
  shape: "typed",
42036
42079
  home: ".factory"
@@ -42039,7 +42082,7 @@ var HARNESSES = [
42039
42082
  id: "tabnine",
42040
42083
  name: "Tabnine",
42041
42084
  scope: "project",
42042
- file: join3(".tabnine", "mcp_servers.json"),
42085
+ file: join4(".tabnine", "mcp_servers.json"),
42043
42086
  container: "mcpServers",
42044
42087
  shape: "plain",
42045
42088
  home: ".tabnine"
@@ -42056,7 +42099,7 @@ var HARNESSES = [
42056
42099
  id: "pi",
42057
42100
  name: "pi",
42058
42101
  scope: "project",
42059
- file: join3(".pi", "mcp.json"),
42102
+ file: join4(".pi", "mcp.json"),
42060
42103
  container: "mcpServers",
42061
42104
  shape: "plain",
42062
42105
  home: ".pi"
@@ -42065,7 +42108,7 @@ var HARNESSES = [
42065
42108
  id: "mistral-vibe",
42066
42109
  name: "Mistral Vibe",
42067
42110
  scope: "project",
42068
- file: join3(".vibe", "config.toml"),
42111
+ file: join4(".vibe", "config.toml"),
42069
42112
  container: "mcp_servers",
42070
42113
  shape: "plain",
42071
42114
  toml: {
@@ -42121,7 +42164,7 @@ var HARNESSES = [
42121
42164
  id: "codex",
42122
42165
  name: "Codex CLI",
42123
42166
  scope: "home",
42124
- file: join3(".codex", "config.toml"),
42167
+ file: join4(".codex", "config.toml"),
42125
42168
  container: "mcp_servers",
42126
42169
  shape: "plain",
42127
42170
  manual: "Codex reads its config at startup, so restart it.",
@@ -42140,20 +42183,20 @@ var HARNESSES = [
42140
42183
  id: "cline",
42141
42184
  name: "Cline",
42142
42185
  scope: "home",
42143
- file: join3(".cline", "data", "settings", "cline_mcp_settings.json"),
42186
+ file: join4(".cline", "data", "settings", "cline_mcp_settings.json"),
42144
42187
  container: "mcpServers",
42145
42188
  shape: "plain",
42146
42189
  marker: ".cline",
42147
- skills: { dir: join3(".cline", "skills"), shared: false }
42190
+ skills: { dir: join4(".cline", "skills"), shared: false }
42148
42191
  },
42149
42192
  {
42150
42193
  id: "goose",
42151
42194
  name: "Goose",
42152
42195
  scope: "home",
42153
42196
  file: {
42154
- win32: { appData: join3("Block", "goose", "config", "config.yaml") },
42155
- darwin: join3(".config", "goose", "config.yaml"),
42156
- linux: join3(".config", "goose", "config.yaml")
42197
+ win32: { appData: join4("Block", "goose", "config", "config.yaml") },
42198
+ darwin: join4(".config", "goose", "config.yaml"),
42199
+ linux: join4(".config", "goose", "config.yaml")
42157
42200
  },
42158
42201
  container: "extensions",
42159
42202
  shape: "plain",
@@ -42174,19 +42217,19 @@ var HARNESSES = [
42174
42217
  id: "windsurf",
42175
42218
  name: "Windsurf",
42176
42219
  scope: "home",
42177
- file: join3(".codeium", "windsurf", "mcp_config.json"),
42220
+ file: join4(".codeium", "windsurf", "mcp_config.json"),
42178
42221
  container: "mcpServers",
42179
42222
  shape: "plain",
42180
- skills: { dir: join3(".windsurf", "skills"), shared: true }
42223
+ skills: { dir: join4(".windsurf", "skills"), shared: true }
42181
42224
  },
42182
42225
  {
42183
42226
  id: "hermes",
42184
42227
  name: "Hermes",
42185
42228
  scope: "home",
42186
- file: join3(".hermes", "config.yaml"),
42229
+ file: join4(".hermes", "config.yaml"),
42187
42230
  container: "mcp_servers",
42188
42231
  shape: "plain",
42189
- skills: { dir: join3(".hermes", "skills"), shared: true },
42232
+ skills: { dir: join4(".hermes", "skills"), shared: true },
42190
42233
  yaml: {
42191
42234
  path: ["mcp_servers", SERVER_KEY],
42192
42235
  entry: (launch) => ({
@@ -42201,7 +42244,7 @@ var HARNESSES = [
42201
42244
  id: "openclaw",
42202
42245
  name: "OpenClaw",
42203
42246
  scope: "home",
42204
- file: join3(".openclaw", "openclaw.json"),
42247
+ file: join4(".openclaw", "openclaw.json"),
42205
42248
  container: "mcpServers",
42206
42249
  shape: "plain"
42207
42250
  },
@@ -42210,9 +42253,9 @@ var HARNESSES = [
42210
42253
  name: "Claude Desktop",
42211
42254
  scope: "home",
42212
42255
  file: {
42213
- win32: { appData: join3("Claude", "claude_desktop_config.json") },
42214
- darwin: join3("Library", "Application Support", "Claude", "claude_desktop_config.json"),
42215
- linux: join3(".config", "Claude", "claude_desktop_config.json")
42256
+ win32: { appData: join4("Claude", "claude_desktop_config.json") },
42257
+ darwin: join4("Library", "Application Support", "Claude", "claude_desktop_config.json"),
42258
+ linux: join4(".config", "Claude", "claude_desktop_config.json")
42216
42259
  },
42217
42260
  container: "mcpServers",
42218
42261
  shape: "plain"
@@ -42221,7 +42264,7 @@ var HARNESSES = [
42221
42264
  id: "zeroclaw",
42222
42265
  name: "ZeroClaw",
42223
42266
  scope: "home",
42224
- file: join3(".zeroclaw", "config.toml"),
42267
+ file: join4(".zeroclaw", "config.toml"),
42225
42268
  container: "mcp.servers",
42226
42269
  shape: "plain",
42227
42270
  toml: {
@@ -42242,7 +42285,7 @@ var HARNESSES = [
42242
42285
  id: "deepcode",
42243
42286
  name: "Deep Code",
42244
42287
  scope: "home",
42245
- file: join3(".deepcode", "settings.json"),
42288
+ file: join4(".deepcode", "settings.json"),
42246
42289
  container: "mcpServers",
42247
42290
  shape: "plain"
42248
42291
  },
@@ -42250,7 +42293,7 @@ var HARNESSES = [
42250
42293
  id: "nanobot",
42251
42294
  name: "nanobot",
42252
42295
  scope: "home",
42253
- file: join3(".nanobot", "config.json"),
42296
+ file: join4(".nanobot", "config.json"),
42254
42297
  container: "mcpServers",
42255
42298
  shape: "plain",
42256
42299
  snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
@@ -42259,17 +42302,17 @@ var HARNESSES = [
42259
42302
  id: "autohand",
42260
42303
  name: "Autohand",
42261
42304
  scope: "home",
42262
- file: join3(".autohand", "config.json"),
42305
+ file: join4(".autohand", "config.json"),
42263
42306
  container: "mcpServers",
42264
42307
  shape: "plain",
42265
42308
  snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
42266
42309
  }
42267
42310
  ];
42268
42311
  function appDataRoot() {
42269
- return process3.env["APPDATA"] ?? join3(homedir2(), "AppData", "Roaming");
42312
+ return process3.env["APPDATA"] ?? join4(homedir2(), "AppData", "Roaming");
42270
42313
  }
42271
42314
  function homePath(path) {
42272
- return typeof path === "string" ? join3(homedir2(), path) : join3(appDataRoot(), path.appData);
42315
+ return typeof path === "string" ? join4(homedir2(), path) : join4(appDataRoot(), path.appData);
42273
42316
  }
42274
42317
  function fileFor(harness, platform = process3.platform) {
42275
42318
  if (typeof harness.file === "string") {
@@ -42280,7 +42323,7 @@ function fileFor(harness, platform = process3.platform) {
42280
42323
  function configPath(harness, projectPath) {
42281
42324
  const file = fileFor(harness);
42282
42325
  if (harness.scope === "project") {
42283
- return join3(projectPath, file);
42326
+ return join4(projectPath, file);
42284
42327
  }
42285
42328
  return homePath(file);
42286
42329
  }
@@ -42339,11 +42382,11 @@ function present(harness, projectPath) {
42339
42382
  return true;
42340
42383
  }
42341
42384
  const root = harness.scope === "project" ? projectPath : homedir2();
42342
- const own = dirname2(path);
42385
+ const own = dirname3(path);
42343
42386
  if (own !== root && existsSync4(own)) {
42344
42387
  return true;
42345
42388
  }
42346
- return harness.marker !== undefined && existsSync4(join3(root, harness.marker));
42389
+ return harness.marker !== undefined && existsSync4(join4(root, harness.marker));
42347
42390
  }
42348
42391
  function candidates(projectPath) {
42349
42392
  const found = [];
@@ -42356,7 +42399,7 @@ function candidates(projectPath) {
42356
42399
  }
42357
42400
  if (present(harness, projectPath)) {
42358
42401
  found.push({ harness, reason: "configured" });
42359
- } else if (harness.home !== undefined && existsSync4(join3(homedir2(), harness.home))) {
42402
+ } else if (harness.home !== undefined && existsSync4(join4(homedir2(), harness.home))) {
42360
42403
  found.push({ harness, reason: "installed" });
42361
42404
  }
42362
42405
  }
@@ -42381,7 +42424,7 @@ function registered(harness, projectPath) {
42381
42424
  if (harness.snippet !== undefined || !existsSync4(path)) {
42382
42425
  return false;
42383
42426
  }
42384
- const text = readFileSync(path, "utf8");
42427
+ const text = readFileSync2(path, "utf8");
42385
42428
  if (harness.toml !== undefined) {
42386
42429
  return text.includes(harness.toml.identity ?? harness.toml.header);
42387
42430
  }
@@ -42411,7 +42454,7 @@ function recordedEnginePath(projectPath) {
42411
42454
  }
42412
42455
  let parsed;
42413
42456
  try {
42414
- parsed = JSON.parse(readFileSync(path, "utf8"));
42457
+ parsed = JSON.parse(readFileSync2(path, "utf8"));
42415
42458
  } catch {
42416
42459
  continue;
42417
42460
  }
@@ -42434,7 +42477,7 @@ function disconnect(harness, projectPath) {
42434
42477
  if (harness.snippet !== undefined) {
42435
42478
  return { harness, path, action: "manual" };
42436
42479
  }
42437
- const text = readFileSync(path, "utf8");
42480
+ const text = readFileSync2(path, "utf8");
42438
42481
  if (harness.toml !== undefined) {
42439
42482
  return taken(harness, path, text, removeToml(text, harness.toml));
42440
42483
  }
@@ -42443,7 +42486,7 @@ function disconnect(harness, projectPath) {
42443
42486
  }
42444
42487
  let existing;
42445
42488
  try {
42446
- existing = JSON.parse(readFileSync(path, "utf8"));
42489
+ existing = JSON.parse(readFileSync2(path, "utf8"));
42447
42490
  } catch {
42448
42491
  return { harness, path, action: "absent" };
42449
42492
  }
@@ -42463,25 +42506,32 @@ function disconnect(harness, projectPath) {
42463
42506
  root[harness.container] = servers;
42464
42507
  }
42465
42508
  if (Object.keys(root).length === 0) {
42466
- rmSync(path, { force: true });
42509
+ rmSync2(path, { force: true });
42467
42510
  return { harness, path, action: "deleted" };
42468
42511
  }
42469
- writeFileSync(path, `${JSON.stringify(root, null, 2)}
42512
+ writeFileSync2(path, `${JSON.stringify(root, null, 2)}
42470
42513
  `, "utf8");
42471
42514
  return { harness, path, action: "removed" };
42472
42515
  }
42473
- function harnessNote(repinned, now) {
42516
+ function harnessNote(repinned, now, running = null) {
42474
42517
  const alsoByHand = repinned.byHand === 0 ? "" : `
42475
42518
  ${repinned.byHand === 1 ? "One harness above was" : `${repinned.byHand} harnesses above were`} handed a command to run instead; run it too.`;
42519
+ const serving = running === null ? ` No gdharness server is announcing itself for this project, so which one your harness
42520
+ ` + ` is running cannot be read from here.
42521
+ ` : ` The server serving this project is gdharness ${running.server.version} (pid ${running.server.pid})${running.isThisVersion ? ", which is already this version." : "."}
42522
+ `;
42523
+ if (running?.isThisVersion === true && repinned.byHand === 0 && (repinned.moved.length > 0 || repinned.written > 0)) {
42524
+ return ` 2. Nothing for the harness: the server serving this project is gdharness ${running.server.version}
42525
+ (pid ${running.server.pid}), which is already this version.`;
42526
+ }
42476
42527
  if (repinned.moved.length > 0) {
42477
- return ` 2. Your harness is still running the server it spawned from ${repinned.moved.join(", ")}.
42478
- ` + ` Its config names ${now} now.
42479
- ` + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
42528
+ return ` 2. Your harness config held ${repinned.moved.join(", ")} before this upgrade.
42529
+ ` + ` It names ${now} now.
42530
+ ` + serving + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
42480
42531
  }
42481
42532
  if (repinned.written > 0) {
42482
- return ` 2. Your harness config already named this version, but the server it is running is
42483
- ` + ` whichever one it spawned when the session started, which this cannot see from here.
42484
- ` + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
42533
+ return ` 2. Your harness config already named this version.
42534
+ ` + serving + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
42485
42535
  }
42486
42536
  if (repinned.byHand > 0) {
42487
42537
  return ` 2. None of the harness configs found here can be written for you, so nothing was
@@ -42508,7 +42558,7 @@ function connect(harness, projectPath, launch) {
42508
42558
  if (harness.snippet !== undefined) {
42509
42559
  return { harness, path, action: "snippet", snippet: harness.snippet(launch) };
42510
42560
  }
42511
- const held = existsSync4(path) ? readFileSync(path, "utf8") : "";
42561
+ const held = existsSync4(path) ? readFileSync2(path, "utf8") : "";
42512
42562
  if (harness.toml !== undefined) {
42513
42563
  const already = held.includes(harness.toml.identity ?? harness.toml.header);
42514
42564
  return put(harness, path, writeToml(held, harness.toml, launch), already);
@@ -42522,7 +42572,7 @@ function connect(harness, projectPath, launch) {
42522
42572
  try {
42523
42573
  existing = JSON.parse(held);
42524
42574
  } catch (cause) {
42525
- throw new Refusal2(`${path} is not valid JSON, so gdharness was not added to it.`, { cause });
42575
+ throw new Refusal(`${path} is not valid JSON, so gdharness was not added to it.`, { cause });
42526
42576
  }
42527
42577
  }
42528
42578
  const container = typeof existing === "object" && existing !== null && !Array.isArray(existing) ? existing[harness.container] : undefined;
@@ -42534,8 +42584,8 @@ function connect(harness, projectPath, launch) {
42534
42584
  return was === undefined || was === now ? written : { ...written, wasLaunchedBy: was };
42535
42585
  }
42536
42586
  function put(harness, path, contents, already) {
42537
- mkdirSync(dirname2(path), { recursive: true });
42538
- writeFileSync(path, contents, "utf8");
42587
+ mkdirSync2(dirname3(path), { recursive: true });
42588
+ writeFileSync2(path, contents, "utf8");
42539
42589
  return { harness, path, action: already ? "replaced" : "written" };
42540
42590
  }
42541
42591
  function taken(harness, path, held, stripped) {
@@ -42543,10 +42593,10 @@ function taken(harness, path, held, stripped) {
42543
42593
  return { harness, path, action: "absent" };
42544
42594
  }
42545
42595
  if (stripped.trim() === "" || stripped.trim() === "{}") {
42546
- rmSync(path, { force: true });
42596
+ rmSync2(path, { force: true });
42547
42597
  return { harness, path, action: "deleted" };
42548
42598
  }
42549
- writeFileSync(path, stripped, "utf8");
42599
+ writeFileSync2(path, stripped, "utf8");
42550
42600
  return { harness, path, action: "removed" };
42551
42601
  }
42552
42602
 
@@ -42554,12 +42604,12 @@ function taken(harness, path, held, stripped) {
42554
42604
  init_call_signal();
42555
42605
  init_game_log();
42556
42606
  init_scratch();
42557
- import { execFile as execFile2 } from "node:child_process";
42558
- import { mkdtempSync, writeFileSync as writeFileSync2 } from "node:fs";
42607
+ import { execFile as execFile3 } from "node:child_process";
42608
+ import { mkdtempSync, writeFileSync as writeFileSync3 } from "node:fs";
42559
42609
  import { tmpdir } from "node:os";
42560
- import { join as join4 } from "node:path";
42561
- import { promisify as promisify2 } from "node:util";
42562
- var run2 = promisify2(execFile2);
42610
+ import { join as join5 } from "node:path";
42611
+ import { promisify as promisify3 } from "node:util";
42612
+ var run3 = promisify3(execFile3);
42563
42613
  function snakeCased(params) {
42564
42614
  const result = emptyRecord();
42565
42615
  for (const [key, value] of Object.entries(params)) {
@@ -42598,13 +42648,13 @@ function reason(stdout, stderr) {
42598
42648
  return stdout.trim().split(/\r?\n/).at(-1) ?? "no output at all";
42599
42649
  }
42600
42650
  async function runOperation(engine, operation, params, projectPath) {
42601
- const paramsDir = mkdtempSync(join4(tmpdir(), "gdharness-params-"));
42602
- const paramsFile = join4(paramsDir, `${operation}.json`);
42603
- writeFileSync2(paramsFile, JSON.stringify(snakeCased(params)), "utf8");
42651
+ const paramsDir = mkdtempSync(join5(tmpdir(), "gdharness-params-"));
42652
+ const paramsFile = join5(paramsDir, `${operation}.json`);
42653
+ writeFileSync3(paramsFile, JSON.stringify(snakeCased(params)), "utf8");
42604
42654
  const args = [
42605
42655
  "--headless",
42606
42656
  "--log-file",
42607
- join4(paramsDir, "engine.log"),
42657
+ join5(paramsDir, "engine.log"),
42608
42658
  "--path",
42609
42659
  projectPath,
42610
42660
  "--script",
@@ -42616,7 +42666,7 @@ async function runOperation(engine, operation, params, projectPath) {
42616
42666
  let stdout;
42617
42667
  let stderr;
42618
42668
  try {
42619
- ({ stdout, stderr } = await run2(engine.godotPath, args, { signal: callSignal() }));
42669
+ ({ stdout, stderr } = await run3(engine.godotPath, args, { signal: callSignal() }));
42620
42670
  } catch (error) {
42621
42671
  if (error instanceof Error && "stdout" in error && "stderr" in error) {
42622
42672
  const failed = error;
@@ -42774,12 +42824,12 @@ class Ask {
42774
42824
 
42775
42825
  // src/server-version.ts
42776
42826
  init_update_check();
42777
- import { readFileSync as readFileSync4 } from "node:fs";
42827
+ import { readFileSync as readFileSync5 } from "node:fs";
42778
42828
  var DEBUG_MODE2 = process.env["DEBUG"] === "true";
42779
42829
  var GODOT_DEBUG_MODE_DEFAULT2 = process.env["GODOT_DEBUG"] === "true" || DEBUG_MODE2;
42780
42830
  var SERVER_VERSION2 = (() => {
42781
42831
  try {
42782
- const pkg = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8"));
42832
+ const pkg = JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf8"));
42783
42833
  return typeof pkg.version === "string" ? pkg.version : "0.0.0";
42784
42834
  } catch {
42785
42835
  return "0.0.0";
@@ -42791,19 +42841,19 @@ init_class_cache();
42791
42841
  init_headless();
42792
42842
  init_resources();
42793
42843
  init_server_version();
42794
- import { spawnSync } from "node:child_process";
42844
+ import { spawnSync as spawnSync2 } from "node:child_process";
42795
42845
  import { createHash as createHash2 } from "node:crypto";
42796
42846
  import {
42797
42847
  cpSync,
42798
42848
  existsSync as existsSync7,
42799
- mkdirSync as mkdirSync3,
42849
+ mkdirSync as mkdirSync4,
42800
42850
  readdirSync as readdirSync3,
42801
- readFileSync as readFileSync7,
42802
- rmSync as rmSync3,
42851
+ readFileSync as readFileSync8,
42852
+ rmSync as rmSync4,
42803
42853
  statSync as statSync3,
42804
- writeFileSync as writeFileSync5
42854
+ writeFileSync as writeFileSync6
42805
42855
  } from "node:fs";
42806
- import { dirname as dirname3, join as join8 } from "node:path";
42856
+ import { dirname as dirname4, join as join9 } from "node:path";
42807
42857
  import { fileURLToPath } from "node:url";
42808
42858
  var ADDONS = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
42809
42859
  var EDITOR_PLUGINS = ["gdharness_editor", "auto_reload"];
@@ -42820,64 +42870,64 @@ function editorAddonDigest(from = shippedAddonsDirectory()) {
42820
42870
  if (name === VERSION_MARKER || name === DIGEST_MARKER) {
42821
42871
  continue;
42822
42872
  }
42823
- const path = join8(directory, name);
42873
+ const path = join9(directory, name);
42824
42874
  const inside = `${relative}/${name}`;
42825
42875
  if (statSync3(path).isDirectory()) {
42826
42876
  walk(path, inside);
42827
42877
  } else {
42828
42878
  hash.update(`${inside}
42829
42879
  `);
42830
- hash.update(readFileSync7(path));
42880
+ hash.update(readFileSync8(path));
42831
42881
  hash.update(`
42832
42882
  `);
42833
42883
  }
42834
42884
  }
42835
42885
  };
42836
42886
  for (const name of EDITOR_PLUGINS) {
42837
- walk(join8(from, name), name);
42887
+ walk(join9(from, name), name);
42838
42888
  }
42839
42889
  return hash.digest("hex");
42840
42890
  }
42841
42891
  function installedEditorDigest(projectPath) {
42842
- const marker = join8(projectPath, "addons", ADDONS[0], DIGEST_MARKER);
42892
+ const marker = join9(projectPath, "addons", ADDONS[0], DIGEST_MARKER);
42843
42893
  if (!existsSync7(marker)) {
42844
42894
  return null;
42845
42895
  }
42846
- const said = readFileSync7(marker, "utf8").trim();
42896
+ const said = readFileSync8(marker, "utf8").trim();
42847
42897
  return said === "" ? null : said;
42848
42898
  }
42849
42899
  function shippedAddonsDirectory() {
42850
- return join8(dirname3(fileURLToPath(import.meta.url)), "godot", "addons");
42900
+ return join9(dirname4(fileURLToPath(import.meta.url)), "godot", "addons");
42851
42901
  }
42852
42902
  function shippedOperationsScript() {
42853
- return join8(dirname3(fileURLToPath(import.meta.url)), "godot", "operations", "godot_operations.gd");
42903
+ return join9(dirname4(fileURLToPath(import.meta.url)), "godot", "operations", "godot_operations.gd");
42854
42904
  }
42855
42905
  function installAddons(projectPath, from = shippedAddonsDirectory()) {
42856
42906
  const installed = [];
42857
42907
  for (const name of ADDONS) {
42858
- const source = join8(from, name);
42859
- if (!existsSync7(join8(source, name === "gdharness_runtime" ? "runtime_autoload.gd" : "plugin.cfg"))) {
42908
+ const source = join9(from, name);
42909
+ if (!existsSync7(join9(source, name === "gdharness_runtime" ? "runtime_autoload.gd" : "plugin.cfg"))) {
42860
42910
  throw new Error(`The package holds no ${name} addon at ${source}.`);
42861
42911
  }
42862
- const target = join8(projectPath, "addons", name);
42912
+ const target = join9(projectPath, "addons", name);
42863
42913
  const replaced = existsSync7(target);
42864
- rmSync3(target, { recursive: true, force: true });
42865
- mkdirSync3(dirname3(target), { recursive: true });
42914
+ rmSync4(target, { recursive: true, force: true });
42915
+ mkdirSync4(dirname4(target), { recursive: true });
42866
42916
  cpSync(source, target, { recursive: true });
42867
- writeFileSync5(join8(target, VERSION_MARKER), `${SERVER_VERSION}
42917
+ writeFileSync6(join9(target, VERSION_MARKER), `${SERVER_VERSION}
42868
42918
  `);
42869
42919
  installed.push({ name, path: target, replaced });
42870
42920
  }
42871
- writeFileSync5(join8(projectPath, "addons", ADDONS[0], DIGEST_MARKER), `${editorAddonDigest(from)}
42921
+ writeFileSync6(join9(projectPath, "addons", ADDONS[0], DIGEST_MARKER), `${editorAddonDigest(from)}
42872
42922
  `);
42873
42923
  return installed;
42874
42924
  }
42875
42925
  function removeAddons(projectPath) {
42876
42926
  const removed = [];
42877
42927
  for (const name of ADDONS) {
42878
- const target = join8(projectPath, "addons", name);
42928
+ const target = join9(projectPath, "addons", name);
42879
42929
  if (existsSync7(target)) {
42880
- rmSync3(target, { recursive: true, force: true });
42930
+ rmSync4(target, { recursive: true, force: true });
42881
42931
  removed.push(target);
42882
42932
  }
42883
42933
  }
@@ -42911,7 +42961,7 @@ function loaderAmong(projectPath, named) {
42911
42961
  }
42912
42962
  let source = null;
42913
42963
  try {
42914
- source = readFileSync7(join8(projectPath, path), "utf8");
42964
+ source = readFileSync8(join9(projectPath, path), "utf8");
42915
42965
  } catch {}
42916
42966
  if (source?.includes(RUNTIME_AUTOLOAD.path)) {
42917
42967
  return { name: entry, path, exists: true };
@@ -42934,7 +42984,7 @@ function trackedByGit(projectPath, wanted) {
42934
42984
  if (wanted.length === 0) {
42935
42985
  return new Set;
42936
42986
  }
42937
- const asked = spawnSync("git", ["ls-files", "-z", "--", ...wanted], {
42987
+ const asked = spawnSync2("git", ["ls-files", "-z", "--", ...wanted], {
42938
42988
  cwd: projectPath,
42939
42989
  encoding: "utf8"
42940
42990
  });
@@ -42953,10 +43003,10 @@ function enabledPlugins(settings) {
42953
43003
  function inspectProject(projectPath) {
42954
43004
  const problems = [];
42955
43005
  const addons = ADDONS.map((name) => {
42956
- const directory = join8(projectPath, "addons", name);
42957
- const marker = join8(directory, VERSION_MARKER);
43006
+ const directory = join9(projectPath, "addons", name);
43007
+ const marker = join9(directory, VERSION_MARKER);
42958
43008
  const installed = existsSync7(directory);
42959
- const version = existsSync7(marker) ? readFileSync7(marker, "utf8").trim() : null;
43009
+ const version = existsSync7(marker) ? readFileSync8(marker, "utf8").trim() : null;
42960
43010
  const current = version === SERVER_VERSION;
42961
43011
  if (!installed) {
42962
43012
  problems.push(`addons/${name} is not installed; run gdharness setup`);
@@ -42965,7 +43015,7 @@ function inspectProject(projectPath) {
42965
43015
  }
42966
43016
  return { name, installed, version, current };
42967
43017
  });
42968
- const settings = parseProjectGodot(readFileSync7(join8(projectPath, "project.godot"), "utf8"));
43018
+ const settings = parseProjectGodot(readFileSync8(join9(projectPath, "project.godot"), "utf8"));
42969
43019
  const pluginsEnabled = enabledPlugins(settings);
42970
43020
  for (const name of EDITOR_PLUGINS) {
42971
43021
  if (!pluginsEnabled.includes(name)) {
@@ -42981,7 +43031,7 @@ function inspectProject(projectPath) {
42981
43031
  const tracked = trackedByGit(projectPath, [...named.values()]);
42982
43032
  const addonMissing = (path) => addons.some((addon) => !addon.installed && path.startsWith(`addons/${addon.name}/`));
42983
43033
  for (const [name, path] of named) {
42984
- if (!existsSync7(join8(projectPath, path))) {
43034
+ if (!existsSync7(join9(projectPath, path))) {
42985
43035
  if (!addonMissing(path)) {
42986
43036
  problems.push(`the ${name} autoload names res://${path}, which is not in this project, so it boots with a missing script; restore that file, or point the autoload at one that is here`);
42987
43037
  }
@@ -43014,8 +43064,8 @@ function inspectProject(projectPath) {
43014
43064
  // src/skill.ts
43015
43065
  init_setup();
43016
43066
  init_tool_definitions();
43017
- import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
43018
- import { basename, dirname as dirname5, join as join10 } from "node:path";
43067
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6, readdirSync as readdirSync5, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "node:fs";
43068
+ import { basename as basename2, dirname as dirname6, join as join11 } from "node:path";
43019
43069
 
43020
43070
  // src/tool-reference.ts
43021
43071
  init_headless_operations();
@@ -43111,7 +43161,7 @@ function renderToolsMarkdown() {
43111
43161
 
43112
43162
  // src/skill.ts
43113
43163
  var SKILL_NAME = "gdharness";
43114
- var SHARED_SKILLS = join10(".agents", "skills");
43164
+ var SHARED_SKILLS = join11(".agents", "skills");
43115
43165
  function skillMarkdown(version) {
43116
43166
  return `---
43117
43167
  name: ${SKILL_NAME}
@@ -43284,27 +43334,27 @@ whatever the engine said on stderr comes back under \`engine_messages\`.
43284
43334
  function skillFiles(version) {
43285
43335
  return new Map([
43286
43336
  ["SKILL.md", skillMarkdown(version)],
43287
- [join10("references", "tools.md"), renderToolsMarkdown()]
43337
+ [join11("references", "tools.md"), renderToolsMarkdown()]
43288
43338
  ]);
43289
43339
  }
43290
43340
  function skillDirectories(harnesses, projectPath, exists) {
43291
- const directories = [join10(projectPath, SHARED_SKILLS, SKILL_NAME)];
43341
+ const directories = [join11(projectPath, SHARED_SKILLS, SKILL_NAME)];
43292
43342
  for (const harness of harnesses) {
43293
43343
  if (harness.skills === undefined) {
43294
43344
  continue;
43295
43345
  }
43296
- const own = join10(projectPath, harness.skills.dir);
43297
- if ((!harness.skills.shared || exists(own)) && !directories.includes(join10(own, SKILL_NAME))) {
43298
- directories.push(join10(own, SKILL_NAME));
43346
+ const own = join11(projectPath, harness.skills.dir);
43347
+ if ((!harness.skills.shared || exists(own)) && !directories.includes(join11(own, SKILL_NAME))) {
43348
+ directories.push(join11(own, SKILL_NAME));
43299
43349
  }
43300
43350
  }
43301
43351
  return directories;
43302
43352
  }
43303
43353
  function everySkillDirectory(projectPath, harnesses) {
43304
- const directories = new Set([join10(projectPath, SHARED_SKILLS, SKILL_NAME)]);
43354
+ const directories = new Set([join11(projectPath, SHARED_SKILLS, SKILL_NAME)]);
43305
43355
  for (const harness of harnesses) {
43306
43356
  if (harness.skills !== undefined) {
43307
- directories.add(join10(projectPath, harness.skills.dir, SKILL_NAME));
43357
+ directories.add(join11(projectPath, harness.skills.dir, SKILL_NAME));
43308
43358
  }
43309
43359
  }
43310
43360
  return [...directories];
@@ -43313,51 +43363,51 @@ function removeSkill(directories, projectPath) {
43313
43363
  const removed = [];
43314
43364
  for (const directory of directories) {
43315
43365
  if (existsSync9(directory)) {
43316
- rmSync5(directory, { recursive: true, force: true });
43317
- pruneEmpty(dirname5(directory), projectPath);
43366
+ rmSync6(directory, { recursive: true, force: true });
43367
+ pruneEmpty(dirname6(directory), projectPath);
43318
43368
  removed.push(directory);
43319
43369
  }
43320
43370
  }
43321
43371
  return removed;
43322
43372
  }
43323
43373
  function pruneEmpty(directory, projectPath) {
43324
- const shared = join10(projectPath, ".agents");
43374
+ const shared = join11(projectPath, ".agents");
43325
43375
  let path = directory;
43326
- while (path !== projectPath && (basename(path) === "skills" || path === shared)) {
43376
+ while (path !== projectPath && (basename2(path) === "skills" || path === shared)) {
43327
43377
  if (readdirSync5(path).length > 0) {
43328
43378
  return;
43329
43379
  }
43330
- rmSync5(path, { recursive: true, force: true });
43331
- path = dirname5(path);
43380
+ rmSync6(path, { recursive: true, force: true });
43381
+ path = dirname6(path);
43332
43382
  }
43333
43383
  }
43334
43384
  function writeSkill(directories, version) {
43335
43385
  const files = skillFiles(version);
43336
43386
  return directories.map((directory) => {
43337
43387
  const replaced = existsSync9(directory);
43338
- rmSync5(directory, { recursive: true, force: true });
43388
+ rmSync6(directory, { recursive: true, force: true });
43339
43389
  for (const [name, contents] of files) {
43340
- const path = join10(directory, name);
43341
- mkdirSync5(dirname5(path), { recursive: true });
43342
- writeFileSync7(path, contents, "utf8");
43390
+ const path = join11(directory, name);
43391
+ mkdirSync6(dirname6(path), { recursive: true });
43392
+ writeFileSync8(path, contents, "utf8");
43343
43393
  }
43344
43394
  return { path: directory, replaced };
43345
43395
  });
43346
43396
  }
43347
43397
 
43348
43398
  // src/version.ts
43349
- import { readFileSync as readFileSync9 } from "node:fs";
43350
- import { dirname as dirname6, join as join11 } from "node:path";
43399
+ import { readFileSync as readFileSync10 } from "node:fs";
43400
+ import { dirname as dirname7, join as join12 } from "node:path";
43351
43401
  import { fileURLToPath as fileURLToPath3 } from "node:url";
43352
43402
  function getLocalVersion() {
43353
- const currentDirectory = dirname6(fileURLToPath3(import.meta.url));
43403
+ const currentDirectory = dirname7(fileURLToPath3(import.meta.url));
43354
43404
  const packageCandidates = [
43355
- join11(currentDirectory, "..", "package.json"),
43356
- join11(currentDirectory, "..", "..", "package.json")
43405
+ join12(currentDirectory, "..", "package.json"),
43406
+ join12(currentDirectory, "..", "..", "package.json")
43357
43407
  ];
43358
43408
  for (const packagePath of packageCandidates) {
43359
43409
  try {
43360
- const value = JSON.parse(readFileSync9(packagePath, "utf-8"));
43410
+ const value = JSON.parse(readFileSync10(packagePath, "utf-8"));
43361
43411
  if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
43362
43412
  return value.version;
43363
43413
  }
@@ -43370,12 +43420,12 @@ function getLocalVersion() {
43370
43420
  var args = process.argv.slice(2);
43371
43421
  var command = args[0];
43372
43422
 
43373
- class UsageError extends Refusal {
43423
+ class UsageError extends Refusal2 {
43374
43424
  }
43375
43425
  function projectArgument(at) {
43376
43426
  const named = args.slice(at).find((value) => !value.startsWith("--"));
43377
43427
  const projectPath = resolve5(named ?? ".");
43378
- if (!existsSync16(join23(projectPath, "project.godot"))) {
43428
+ if (!existsSync16(join24(projectPath, "project.godot"))) {
43379
43429
  throw new UsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
43380
43430
  }
43381
43431
  return projectPath;
@@ -43394,7 +43444,7 @@ async function engine(projectPath) {
43394
43444
  }
43395
43445
  function said2(outcome, what) {
43396
43446
  if (!outcome.ok) {
43397
- throw new Refusal(`${what}: ${outcome.message}`);
43447
+ throw new Refusal2(`${what}: ${outcome.message}`);
43398
43448
  }
43399
43449
  for (const entry of outcome.messages) {
43400
43450
  console.error(` engine ${entry.severity}: ${entry.text}`);
@@ -43414,7 +43464,7 @@ async function registerRuntime(godot, projectPath) {
43414
43464
  return;
43415
43465
  }
43416
43466
  console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
43417
- if (!existsSync16(join23(projectPath, (named ?? "").replace(/^res:\/\//, "")))) {
43467
+ if (!existsSync16(join24(projectPath, (named ?? "").replace(/^res:\/\//, "")))) {
43418
43468
  console.log(` that file is not in this project, so it boots with a missing script: restore it, or point the entry at res://${RUNTIME_AUTOLOAD.path}`);
43419
43469
  }
43420
43470
  }
@@ -43649,7 +43699,8 @@ On ${version}. What is left for you:`);
43649
43699
  ` + ` so it gives an open editor nothing to restart for. editor_status says addonIsStale
43650
43700
  ` + " if the editor is older than that." : ` 1. The open editor is still running the addons it loaded at startup. Restart it with the
43651
43701
  ` + " editor_launch restart tool, which closes and reopens the window.");
43652
- console.log(harnessNote({ moved, written, byHand }, [launch.command, ...launch.args].join(" ")));
43702
+ const serving = serverServing(projectPath);
43703
+ console.log(harnessNote({ moved, written, byHand }, [launch.command, ...launch.args].join(" "), serving === null ? null : { server: serving, isThisVersion: serving.version === version }));
43653
43704
  }
43654
43705
  function doctorReport(projectPath) {
43655
43706
  const report = inspectProject(projectPath);
@@ -43809,7 +43860,7 @@ async function main() {
43809
43860
  }
43810
43861
  }
43811
43862
  await main().catch((error) => {
43812
- if (error instanceof Refusal) {
43863
+ if (error instanceof Refusal2) {
43813
43864
  console.error("gdharness:", error.message);
43814
43865
  process.exit(error instanceof UsageError ? 2 : 1);
43815
43866
  }