gdharness 0.13.30 → 0.13.32

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
@@ -7489,8 +7489,8 @@ function addonMismatch(addonVersion, serverVersion) {
7489
7489
  return;
7490
7490
  }
7491
7491
  const reported = addonVersion ?? "";
7492
- const editor = reported === "" ? UNVERSIONED : reported;
7493
- const both = `The editor is running the ${editor} addon while this server ships ${serverVersion}.`;
7492
+ const editor = reported === "" ? UNVERSIONED : `the ${reported} addon`;
7493
+ const both = `The editor is running ${editor} while this server ships ${serverVersion}.`;
7494
7494
  if (reported !== "" && isNewer(reported, serverVersion)) {
7495
7495
  return `${both} This server is the older half: reconnect it in your harness so it spawns ${reported}.`;
7496
7496
  }
@@ -7503,7 +7503,7 @@ function markIfStale(answer, addonVersion, serverVersion) {
7503
7503
  }
7504
7504
  return { ...answer, addonIsStale: true, staleNote };
7505
7505
  }
7506
- var DEBUG_MODE, GODOT_DEBUG_MODE_DEFAULT, SERVER_VERSION, UNVERSIONED = "addon from before versions were reported";
7506
+ var DEBUG_MODE, GODOT_DEBUG_MODE_DEFAULT, SERVER_VERSION, UNVERSIONED = "an addon from before versions were reported";
7507
7507
  var init_server_version = __esm(() => {
7508
7508
  init_update_check();
7509
7509
  DEBUG_MODE = process.env["DEBUG"] === "true";
@@ -7535,7 +7535,7 @@ function declaredClasses(projectPath) {
7535
7535
  if (entry.isDirectory()) {
7536
7536
  visit(path, `${prefix}${entry.name}/`);
7537
7537
  } else if (entry.isFile() && entry.name.endsWith(".gd")) {
7538
- const found = /^class_name\s+([A-Za-z_][A-Za-z0-9_]*)/m.exec(readFileSync5(path, "utf8"));
7538
+ const found = DECLARATION.exec(readFileSync5(path, "utf8"));
7539
7539
  if (found?.[1]) {
7540
7540
  declared.set(found[1], `res://${prefix}${entry.name}`);
7541
7541
  }
@@ -7656,9 +7656,12 @@ function heldButGone(projectPath, editorHolds) {
7656
7656
  }
7657
7657
  function unseenByEditor(projectPath, editorHolds) {
7658
7658
  const held = new Set(editorHolds);
7659
- return [...declaredClasses(projectPath)].filter(([name]) => !held.has(name)).map(([className, path]) => ({ className, path }));
7659
+ return [...declaredClasses(projectPath)].filter(([name]) => !held.has(name)).map(([className, path]) => ({ className, path })).sort((one, other) => one.className < other.className ? -1 : one.className > other.className ? 1 : 0);
7660
7660
  }
7661
- var init_class_cache = () => {};
7661
+ var DECLARATION;
7662
+ var init_class_cache = __esm(() => {
7663
+ DECLARATION = /^(?:@[a-z_]+(?:\([^)\n]*\))?\s+)*class_name\s+([A-Za-z_][A-Za-z0-9_]*)/m;
7664
+ });
7662
7665
 
7663
7666
  // src/headless.ts
7664
7667
  import { execFile as execFile3 } from "node:child_process";
@@ -15249,6 +15252,30 @@ function readParams(params, key) {
15249
15252
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
15250
15253
  }
15251
15254
 
15255
+ // src/setup.ts
15256
+ import { cpSync as cpSync2, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync8, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
15257
+ import { dirname as dirname4, join as join9 } from "node:path";
15258
+ function installedAddonVersion(projectPath) {
15259
+ const marker = join9(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
15260
+ if (!existsSync8(marker)) {
15261
+ return null;
15262
+ }
15263
+ const said = readFileSync8(marker, "utf8").trim();
15264
+ return said === "" ? null : said;
15265
+ }
15266
+ var ADDONS2, 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";
15267
+ var init_setup = __esm(() => {
15268
+ init_class_cache();
15269
+ init_headless();
15270
+ init_resources();
15271
+ init_server_version();
15272
+ ADDONS2 = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
15273
+ RUNTIME_AUTOLOAD2 = {
15274
+ name: "GdharnessRuntime",
15275
+ path: "addons/gdharness_runtime/runtime_autoload.gd"
15276
+ };
15277
+ });
15278
+
15252
15279
  // src/tool-definitions.ts
15253
15280
  function opTakes(spec, op, name) {
15254
15281
  const ops = spec.parameters[name]?.ops;
@@ -15566,7 +15593,7 @@ var init_tool_definitions = __esm(() => {
15566
15593
  direction: {
15567
15594
  type: "string",
15568
15595
  enum: ["forward", "reverse"],
15569
- description: "forward: what this resource loads, with cycles reported. reverse: every file that refers to it and how, a scene instancing it, a script extending, preloading or loading it, and for a script with a class_name every use of that name. Default forward."
15596
+ description: "forward: what this resource loads, with cycles reported. reverse: every file that refers to it and how, a scene instancing it, a script extending, preloading or loading it, and for a script with a class_name every use of that name. Each reference carries a kind, and two of them are mentions rather than uses: doc is a name inside a ## documentation comment, which renaming would break in the generated docs, and comment is one in ordinary prose, which it would only make stale. summary.in_code is the count with both of those left out, which is the number to read when the question is whether anything still uses this. Default forward."
15570
15597
  },
15571
15598
  depth: { type: "number", description: "forward: how many levels to follow. Default unlimited." },
15572
15599
  includeBuiltin: {
@@ -15836,7 +15863,7 @@ var init_tool_definitions = __esm(() => {
15836
15863
  scriptPath: SCRIPT_PATH,
15837
15864
  includeInherited: {
15838
15865
  type: "boolean",
15839
- description: "structure: include inherited members. Default false."
15866
+ description: "structure: also list what the script inherits, walking extends through the project's other scripts. Each such member carries inherited_from, the file declaring it, and the answer gains inherits_from, the chain that was walked. A name the script overrides is listed at both its lines rather than once. A native base is not walked, since it declares nothing in a file: editor_classes info answers for those. Default false."
15840
15867
  },
15841
15868
  line: { type: "number", description: "completion, hover: zero-based line." },
15842
15869
  character: { type: "number", description: "completion, hover: zero-based column." }
@@ -15934,7 +15961,7 @@ var init_tool_definitions = __esm(() => {
15934
15961
  runtimeWaitMs: {
15935
15962
  type: "number",
15936
15963
  ops: ["start"],
15937
- description: "start: how long to wait for the game to announce its runtime before answering. Default 5000. Worth raising for a project that takes longer than that to reach its first frame, which is what leaves runtime listening false on a game whose runtime arrives a moment later. 0 does not wait at all, which is the one to pass for a scene that announces nothing by construction, such as a bench that prints and quits."
15964
+ description: "start: how long to wait for the game to announce its runtime before answering. Default 5000. What it waits for is the first frame, so everything the game does before drawing one is inside it, including work the args just asked for: a flag that simulates six years of game time before anything is drawn makes the announcement that late, on a project that announces promptly without it. Raise it for such a run rather than reading runtime listening false as a fault. 0 does not wait at all, which is the one to pass for a scene that announces nothing by construction, such as a bench that prints and quits."
15938
15965
  },
15939
15966
  frames: {
15940
15967
  type: "number",
@@ -31118,14 +31145,14 @@ var init_stdio2 = __esm(() => {
31118
31145
  });
31119
31146
 
31120
31147
  // src/bridge-announce.ts
31121
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync9, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
31122
- import { dirname as dirname6, join as join11 } from "node:path";
31148
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync10, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "node:fs";
31149
+ import { dirname as dirname7, join as join12 } from "node:path";
31123
31150
  function announcementPath(projectPath) {
31124
- return join11(projectPath, ".godot", "gdharness-bridge.json");
31151
+ return join12(projectPath, ".godot", "gdharness-bridge.json");
31125
31152
  }
31126
31153
  function readAnnouncement(path) {
31127
31154
  try {
31128
- const parsed = JSON.parse(readFileSync9(path, "utf8"));
31155
+ const parsed = JSON.parse(readFileSync10(path, "utf8"));
31129
31156
  if (typeof parsed !== "object" || parsed === null) {
31130
31157
  return null;
31131
31158
  }
@@ -31144,7 +31171,7 @@ function announcementIsOurs(path) {
31144
31171
  function announceBridge(projectPath, bridge) {
31145
31172
  const path = announcementPath(projectPath);
31146
31173
  try {
31147
- mkdirSync5(dirname6(path), { recursive: true });
31174
+ mkdirSync6(dirname7(path), { recursive: true });
31148
31175
  const announcement = {
31149
31176
  protocol: BRIDGE_ANNOUNCE_PROTOCOL,
31150
31177
  host: bridge.host,
@@ -31153,7 +31180,7 @@ function announceBridge(projectPath, bridge) {
31153
31180
  version: bridge.version,
31154
31181
  startedAt: new Date().toISOString()
31155
31182
  };
31156
- writeFileSync7(path, `${JSON.stringify(announcement, null, 2)}
31183
+ writeFileSync8(path, `${JSON.stringify(announcement, null, 2)}
31157
31184
  `, "utf8");
31158
31185
  return path;
31159
31186
  } catch (error) {
@@ -31166,7 +31193,7 @@ function withdrawBridge(path) {
31166
31193
  return;
31167
31194
  }
31168
31195
  try {
31169
- rmSync5(path, { force: true });
31196
+ rmSync6(path, { force: true });
31170
31197
  } catch (error) {
31171
31198
  console.error(`[SERVER] Could not withdraw the editor bridge announcement: ${errorMessage(error)}`);
31172
31199
  }
@@ -31177,16 +31204,16 @@ var init_bridge_announce = __esm(() => {
31177
31204
  });
31178
31205
 
31179
31206
  // src/config-pin.ts
31180
- import { existsSync as existsSync9, readFileSync as readFileSync10 } from "node:fs";
31181
- import { join as join12 } from "node:path";
31207
+ import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
31208
+ import { join as join13 } from "node:path";
31182
31209
  function versionsNamedInConfig(projectPath) {
31183
- const config = join12(projectPath, ".mcp.json");
31184
- if (!existsSync9(config)) {
31210
+ const config = join13(projectPath, ".mcp.json");
31211
+ if (!existsSync10(config)) {
31185
31212
  return [];
31186
31213
  }
31187
31214
  let text;
31188
31215
  try {
31189
- text = readFileSync10(config, "utf8");
31216
+ text = readFileSync11(config, "utf8");
31190
31217
  JSON.parse(text);
31191
31218
  } catch {
31192
31219
  return [];
@@ -34727,6 +34754,9 @@ function servedPort(said) {
34727
34754
  function mayYetConnect(listeningSince, now = Date.now()) {
34728
34755
  return listeningSince === undefined || now - listeningSince.getTime() < CONNECT_WINDOW_MS;
34729
34756
  }
34757
+ function theEditorHasComeBack(status, startedAt) {
34758
+ return status.connected && (status.connectedAt?.getTime() ?? 0) > startedAt && status.addonVersion !== undefined;
34759
+ }
34730
34760
  function anEditorIsStillComing(listeningSince, launchedEditorIsAlive, now = Date.now()) {
34731
34761
  return mayYetConnect(listeningSince, now) || launchedEditorIsAlive;
34732
34762
  }
@@ -35192,7 +35222,7 @@ var init_godot_bridge = __esm(() => {
35192
35222
 
35193
35223
  // src/godot-path.ts
35194
35224
  import { execFile as execFile4 } from "node:child_process";
35195
- import { existsSync as existsSync10 } from "node:fs";
35225
+ import { existsSync as existsSync11 } from "node:fs";
35196
35226
  import { normalize as normalize2 } from "node:path";
35197
35227
  import { promisify as promisify4 } from "node:util";
35198
35228
  var run4, GodotLocator2;
@@ -35234,7 +35264,7 @@ var init_godot_path = __esm(() => {
35234
35264
  return known;
35235
35265
  }
35236
35266
  let ok = false;
35237
- if (path === "godot" || existsSync10(path)) {
35267
+ if (path === "godot" || existsSync11(path)) {
35238
35268
  try {
35239
35269
  await run4(path, ["--version"]);
35240
35270
  ok = true;
@@ -35582,7 +35612,7 @@ var init_junit = __esm(() => {
35582
35612
  import { realpathSync as realpathSync2 } from "node:fs";
35583
35613
  import { readFile, realpath } from "node:fs/promises";
35584
35614
  import { createConnection as createConnection2 } from "node:net";
35585
- import { dirname as dirname7, resolve as resolve3 } from "node:path";
35615
+ import { dirname as dirname8, resolve as resolve3 } from "node:path";
35586
35616
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
35587
35617
  function diagnosticsKey(uri) {
35588
35618
  let decoded;
@@ -35710,7 +35740,7 @@ class GodotLSPClient {
35710
35740
  if (this.initialized) {
35711
35741
  return;
35712
35742
  }
35713
- const rootPath = this.rootPath ?? dirname7(resolve3(filePath));
35743
+ const rootPath = this.rootPath ?? dirname8(resolve3(filePath));
35714
35744
  await this.initialize(rootPath);
35715
35745
  }
35716
35746
  async sendRequest(method, params) {
@@ -36155,13 +36185,13 @@ var init_process_time = __esm(() => {
36155
36185
  });
36156
36186
 
36157
36187
  // src/project-scan.ts
36158
- import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "node:fs";
36159
- import { join as join13 } from "node:path";
36188
+ import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "node:fs";
36189
+ import { join as join14 } from "node:path";
36160
36190
  function skipped(name) {
36161
36191
  return name.startsWith(".") || SKIPPED.has(name);
36162
36192
  }
36163
36193
  function steppedOver(directory) {
36164
- return existsSync11(join13(directory, ".gdignore"));
36194
+ return existsSync12(join14(directory, ".gdignore"));
36165
36195
  }
36166
36196
  function projectStructure(projectPath) {
36167
36197
  const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
@@ -36174,7 +36204,7 @@ function projectStructure(projectPath) {
36174
36204
  continue;
36175
36205
  }
36176
36206
  if (entry.isDirectory()) {
36177
- visit(join13(directory, entry.name));
36207
+ visit(join14(directory, entry.name));
36178
36208
  } else if (entry.isFile()) {
36179
36209
  const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
36180
36210
  if (extension === "tscn") {
@@ -36204,14 +36234,14 @@ function scriptsWithoutUid(projectPath) {
36204
36234
  }
36205
36235
  const spelled = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
36206
36236
  if (entry.isDirectory()) {
36207
- visit(join13(directory, entry.name), spelled);
36237
+ visit(join14(directory, entry.name), spelled);
36208
36238
  continue;
36209
36239
  }
36210
36240
  if (!entry.isFile()) {
36211
36241
  continue;
36212
36242
  }
36213
36243
  const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
36214
- if (CARRIES_A_UID.has(extension) && !existsSync11(join13(directory, `${entry.name}.uid`))) {
36244
+ if (CARRIES_A_UID.has(extension) && !existsSync12(join14(directory, `${entry.name}.uid`))) {
36215
36245
  found.push(spelled);
36216
36246
  }
36217
36247
  }
@@ -36246,7 +36276,7 @@ function searchProject(projectPath, options) {
36246
36276
  if (skipped(entry.name)) {
36247
36277
  continue;
36248
36278
  }
36249
- const entryPath = join13(directory, entry.name);
36279
+ const entryPath = join14(directory, entry.name);
36250
36280
  if (entry.isDirectory()) {
36251
36281
  visit(entryPath);
36252
36282
  continue;
@@ -36257,7 +36287,7 @@ function searchProject(projectPath, options) {
36257
36287
  }
36258
36288
  result.summary.files_searched += 1;
36259
36289
  const matches = [];
36260
- for (const [index, line] of readFileSync11(entryPath, "utf8").split(`
36290
+ for (const [index, line] of readFileSync12(entryPath, "utf8").split(`
36261
36291
  `).entries()) {
36262
36292
  if (full()) {
36263
36293
  break;
@@ -36286,10 +36316,10 @@ var init_project_scan = __esm(() => {
36286
36316
  });
36287
36317
 
36288
36318
  // src/runtime-client.ts
36289
- import { existsSync as existsSync12, readdirSync as readdirSync5, readFileSync as readFileSync12, unlinkSync } from "node:fs";
36319
+ import { existsSync as existsSync13, readdirSync as readdirSync5, readFileSync as readFileSync13, unlinkSync } from "node:fs";
36290
36320
  import { createConnection as createConnection3 } from "node:net";
36291
36321
  import { tmpdir as tmpdir4 } from "node:os";
36292
- import { join as join14, resolve as resolve4 } from "node:path";
36322
+ import { join as join15, resolve as resolve4 } from "node:path";
36293
36323
  import { setTimeout as delay2 } from "node:timers/promises";
36294
36324
  function runtimeDirectory(variables = process.env) {
36295
36325
  const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
@@ -36297,13 +36327,13 @@ function runtimeDirectory(variables = process.env) {
36297
36327
  return explicit;
36298
36328
  }
36299
36329
  const perUser = envValue("XDG_RUNTIME_DIR", variables);
36300
- return join14(perUser ?? tmpdir4(), "gdharness");
36330
+ return join15(perUser ?? tmpdir4(), "gdharness");
36301
36331
  }
36302
36332
  function runtimeDirectories(variables = process.env) {
36303
36333
  const candidates = [runtimeDirectory(variables)];
36304
36334
  const fallbacks = process.platform === "win32" ? [envValue("SystemRoot", variables) ?? envValue("windir", variables) ?? "C:\\Windows"] : ["/tmp", "/var/tmp"];
36305
36335
  for (const base of fallbacks) {
36306
- candidates.push(join14(base, process.platform === "win32" ? "Temp" : "", "gdharness"));
36336
+ candidates.push(join15(base, process.platform === "win32" ? "Temp" : "", "gdharness"));
36307
36337
  }
36308
36338
  return [...new Set(candidates.map((path) => resolve4(path)))];
36309
36339
  }
@@ -36318,7 +36348,7 @@ function processAlive(pid) {
36318
36348
  function parseAnnouncement(file, pid) {
36319
36349
  let fields;
36320
36350
  try {
36321
- fields = asParams(JSON.parse(readFileSync12(file, "utf8")));
36351
+ fields = asParams(JSON.parse(readFileSync13(file, "utf8")));
36322
36352
  } catch {
36323
36353
  return { kind: "rubbish" };
36324
36354
  }
@@ -36357,7 +36387,7 @@ function discoverRuntimes(directories = runtimeDirectories()) {
36357
36387
  return runtimesAnnounced(directories).running;
36358
36388
  }
36359
36389
  function announcedIn(directory) {
36360
- if (!existsSync12(directory)) {
36390
+ if (!existsSync13(directory)) {
36361
36391
  return [];
36362
36392
  }
36363
36393
  const found = [];
@@ -36366,7 +36396,7 @@ function announcedIn(directory) {
36366
36396
  if (!match) {
36367
36397
  continue;
36368
36398
  }
36369
- const file = join14(directory, entry);
36399
+ const file = join15(directory, entry);
36370
36400
  const pid = Number.parseInt(match[1] ?? "", 10);
36371
36401
  const announced = processAlive(pid) ? parseAnnouncement(file, pid) : { kind: "rubbish" };
36372
36402
  if (announced.kind === "rubbish") {
@@ -36528,36 +36558,36 @@ var init_runtime_client = __esm(() => {
36528
36558
 
36529
36559
  // src/run-record.ts
36530
36560
  import { execFileSync } from "node:child_process";
36531
- import { mkdirSync as mkdirSync6, openSync, readdirSync as readdirSync6, readFileSync as readFileSync13, rmSync as rmSync6, statSync as statSync3, writeFileSync as writeFileSync8 } from "node:fs";
36532
- import { basename as basename2, join as join15 } from "node:path";
36561
+ import { mkdirSync as mkdirSync7, openSync, readdirSync as readdirSync6, readFileSync as readFileSync14, rmSync as rmSync7, statSync as statSync3, writeFileSync as writeFileSync9 } from "node:fs";
36562
+ import { basename as basename2, join as join16 } from "node:path";
36533
36563
  function runsDirectory() {
36534
- return join15(runtimeDirectory(), "runs");
36564
+ return join16(runtimeDirectory(), "runs");
36535
36565
  }
36536
36566
  function recordPath() {
36537
- return join15(runsDirectory(), "run.json");
36567
+ return join16(runsDirectory(), "run.json");
36538
36568
  }
36539
36569
  function recordPaths() {
36540
- return runtimeDirectories().map((directory) => join15(directory, "runs", "run.json"));
36570
+ return runtimeDirectories().map((directory) => join16(directory, "runs", "run.json"));
36541
36571
  }
36542
36572
  function openTranscript(startedAt) {
36543
- mkdirSync6(runsDirectory(), { recursive: true });
36544
- const path = join15(runsDirectory(), `run-${startedAt}.log`);
36573
+ mkdirSync7(runsDirectory(), { recursive: true });
36574
+ const path = join16(runsDirectory(), `run-${startedAt}.log`);
36545
36575
  return { path, fd: openSync(path, "a") };
36546
36576
  }
36547
36577
  function writeRunRecord(record) {
36548
- mkdirSync6(runsDirectory(), { recursive: true });
36549
- writeFileSync8(recordPath(), JSON.stringify(record, null, 2), "utf8");
36578
+ mkdirSync7(runsDirectory(), { recursive: true });
36579
+ writeFileSync9(recordPath(), JSON.stringify(record, null, 2), "utf8");
36550
36580
  }
36551
36581
  function editorNotePath() {
36552
- return join15(runsDirectory(), "editor-run.json");
36582
+ return join16(runsDirectory(), "editor-run.json");
36553
36583
  }
36554
36584
  function writeEditorRunNote(note) {
36555
- mkdirSync6(runsDirectory(), { recursive: true });
36556
- writeFileSync8(editorNotePath(), JSON.stringify(note, null, 2), "utf8");
36585
+ mkdirSync7(runsDirectory(), { recursive: true });
36586
+ writeFileSync9(editorNotePath(), JSON.stringify(note, null, 2), "utf8");
36557
36587
  }
36558
36588
  function readEditorRunNote() {
36559
36589
  for (const directory of runtimeDirectories()) {
36560
- const note = editorNoteAt(join15(directory, "runs", "editor-run.json"));
36590
+ const note = editorNoteAt(join16(directory, "runs", "editor-run.json"));
36561
36591
  if (note !== null) {
36562
36592
  return note;
36563
36593
  }
@@ -36567,7 +36597,7 @@ function readEditorRunNote() {
36567
36597
  function editorNoteAt(path) {
36568
36598
  let parsed;
36569
36599
  try {
36570
- parsed = JSON.parse(readFileSync13(path, "utf8"));
36600
+ parsed = JSON.parse(readFileSync14(path, "utf8"));
36571
36601
  } catch {
36572
36602
  return null;
36573
36603
  }
@@ -36590,7 +36620,7 @@ function recordRunEnded(pid, exitCode) {
36590
36620
  return;
36591
36621
  }
36592
36622
  try {
36593
- writeFileSync8(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
36623
+ writeFileSync9(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
36594
36624
  } catch {}
36595
36625
  }
36596
36626
  function readRunRecord() {
@@ -36605,7 +36635,7 @@ function readRunRecord() {
36605
36635
  function recordAt(path) {
36606
36636
  let parsed;
36607
36637
  try {
36608
- parsed = JSON.parse(readFileSync13(path, "utf8"));
36638
+ parsed = JSON.parse(readFileSync14(path, "utf8"));
36609
36639
  } catch {
36610
36640
  return null;
36611
36641
  }
@@ -36641,7 +36671,7 @@ function runningAs(pid) {
36641
36671
  }
36642
36672
  try {
36643
36673
  if (process.platform === "linux") {
36644
- const raw = readFileSync13(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
36674
+ const raw = readFileSync14(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
36645
36675
  return raw === "" ? null : { kind: "commandLine", text: raw };
36646
36676
  }
36647
36677
  const args = execFileSync("ps", ["-p", String(pid), "-o", "args="], {
@@ -36738,7 +36768,7 @@ function clearRunRecord(ours = () => true) {
36738
36768
  continue;
36739
36769
  }
36740
36770
  try {
36741
- rmSync6(path);
36771
+ rmSync7(path);
36742
36772
  } catch {}
36743
36773
  }
36744
36774
  }
@@ -36762,12 +36792,12 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
36762
36792
  if (!entry.startsWith("run-") || !entry.endsWith(".log")) {
36763
36793
  continue;
36764
36794
  }
36765
- const path = join15(directory, entry);
36795
+ const path = join16(directory, entry);
36766
36796
  if (path === keep || ageMs(path, now) < keepMs) {
36767
36797
  continue;
36768
36798
  }
36769
36799
  try {
36770
- rmSync6(path);
36800
+ rmSync7(path);
36771
36801
  } catch {}
36772
36802
  }
36773
36803
  }
@@ -36775,30 +36805,6 @@ var init_run_record = __esm(() => {
36775
36805
  init_runtime_client();
36776
36806
  });
36777
36807
 
36778
- // src/setup.ts
36779
- import { cpSync as cpSync2, existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync14, rmSync as rmSync7, writeFileSync as writeFileSync9 } from "node:fs";
36780
- import { dirname as dirname8, join as join16 } from "node:path";
36781
- function installedAddonVersion(projectPath) {
36782
- const marker = join16(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
36783
- if (!existsSync13(marker)) {
36784
- return null;
36785
- }
36786
- const said = readFileSync14(marker, "utf8").trim();
36787
- return said === "" ? null : said;
36788
- }
36789
- var ADDONS2, RUNTIME_AUTOLOAD2, VERSION_MARKER2 = ".gdharness-version";
36790
- var init_setup = __esm(() => {
36791
- init_class_cache();
36792
- init_headless();
36793
- init_resources();
36794
- init_server_version();
36795
- ADDONS2 = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
36796
- RUNTIME_AUTOLOAD2 = {
36797
- name: "GdharnessRuntime",
36798
- path: "addons/gdharness_runtime/runtime_autoload.gd"
36799
- };
36800
- });
36801
-
36802
36808
  // src/server.ts
36803
36809
  import { execFile as execFile6, spawn } from "node:child_process";
36804
36810
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -36859,7 +36865,7 @@ function runtimeVerdict(endpoint, after) {
36859
36865
  return {
36860
36866
  listening: false,
36861
36867
  mayYetAnnounce: after.running,
36862
- note: after.running ? `nothing announced itself within ${after.budgetMs}ms and the game is still running, so it may announce a moment from now: editor_status says whether it has, and editor_run start takes runtimeWaitMs to wait longer than this` : `nothing announced itself within ${after.budgetMs}ms and the game is no longer running, so nothing is going to: editor_output has what it printed on the way down`,
36868
+ note: after.running ? `nothing announced itself within ${after.budgetMs}ms and the game is still running, so it may announce a moment from now: editor_status says whether it has, and editor_run start takes runtimeWaitMs to wait longer than this${after.withArgs ? ", which a run carrying its own arguments may well need, since whatever they ask the game to do before its first frame is inside this wait" : ""}` : `nothing announced itself within ${after.budgetMs}ms and the game is no longer running, so nothing is going to: editor_output has what it printed on the way down`,
36863
36869
  heldAt: null
36864
36870
  };
36865
36871
  }
@@ -38354,10 +38360,7 @@ class GodotServer {
38354
38360
  }
38355
38361
  const startedAt = before.connectedAt?.getTime() ?? 0;
38356
38362
  const began = Date.now();
38357
- const back = await this.waitForBridge(() => {
38358
- const status = this.godotBridge.getStatus();
38359
- return status.connected && (status.connectedAt?.getTime() ?? 0) > startedAt;
38360
- }, began + EDITOR_RESTART_TIMEOUT_MS);
38363
+ const back = await this.waitForBridge(() => theEditorHasComeBack(this.godotBridge.getStatus(), startedAt), began + EDITOR_RESTART_TIMEOUT_MS);
38361
38364
  if (!back) {
38362
38365
  return this.createErrorResponse(`The editor was asked to restart and has not come back within ${EDITOR_RESTART_TIMEOUT_MS / 1000}s.`, [
38363
38366
  "It may be asking what to do about an unsaved scene: look at the editor window",
@@ -38552,7 +38555,7 @@ class GodotServer {
38552
38555
  transcript: started.transcript,
38553
38556
  refreshedClasses: refreshed.value,
38554
38557
  endedPreviousRun: ended ?? undefined,
38555
- runtime: await this.runtimeUp(project.value.path, alreadyPlaying, runtimeWaitMs),
38558
+ runtime: await this.runtimeUp(project.value.path, alreadyPlaying, runtimeWaitMs, given.value.length > 0),
38556
38559
  message: `Use editor_output for what it prints and editor_run stop to end it.${spawnedInstead}${endedForThis}`
38557
38560
  });
38558
38561
  }
@@ -38561,9 +38564,9 @@ class GodotServer {
38561
38564
  const editorSays = run?.throughEditor === true ? (await this.editorPlayingState())?.playing ?? null : null;
38562
38565
  return runIsUp(run, editorSays);
38563
38566
  }
38564
- async runtimeUp(projectPath, before, budgetMs) {
38567
+ async runtimeUp(projectPath, before, budgetMs, withArgs) {
38565
38568
  if (!existsSync14(join17(projectPath, RUNTIME_AUTOLOAD2.path))) {
38566
- return runtimeVerdict(null, { addon: false, budgetMs, heldAt: null, running: false });
38569
+ return runtimeVerdict(null, { addon: false, budgetMs, heldAt: null, running: false, withArgs });
38567
38570
  }
38568
38571
  const endpoint = await announcedSince(projectPath, before, {
38569
38572
  budgetMs,
@@ -38573,7 +38576,8 @@ class GodotServer {
38573
38576
  addon: true,
38574
38577
  budgetMs,
38575
38578
  heldAt: this.dapClient?.whereItStopped() ?? null,
38576
- running: await this.gameIsUp()
38579
+ running: await this.gameIsUp(),
38580
+ withArgs
38577
38581
  });
38578
38582
  }
38579
38583
  async playThroughEditor(scene, refreshedClasses, projectPath, alreadyPlaying, runtimeWaitMs, ended) {
@@ -38624,7 +38628,7 @@ class GodotServer {
38624
38628
  refreshedClasses,
38625
38629
  debugPort: readNumber(asParams(JSON.parse(answer.content[0]?.text ?? "{}")), "debugPort"),
38626
38630
  endedPreviousRun: ended ?? undefined,
38627
- runtime: await this.runtimeUp(projectPath, alreadyPlaying, runtimeWaitMs),
38631
+ runtime: await this.runtimeUp(projectPath, alreadyPlaying, runtimeWaitMs, false),
38628
38632
  message: "The editor is playing it, so its debugger holds it: the debug_* tools can reach it, " + "editor_output reads its console through the debug adapter, and editor_run stop ends it." + (ended === null ? "" : ` The run that was going, pid ${ended}, was ended to start this one; its output is no longer what editor_output answers about.`)
38629
38633
  });
38630
38634
  }
@@ -40641,9 +40645,10 @@ function inspectProject(projectPath) {
40641
40645
  }
40642
40646
 
40643
40647
  // src/skill.ts
40648
+ init_setup();
40644
40649
  init_tool_definitions();
40645
- import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
40646
- import { basename, dirname as dirname4, join as join9 } from "node:path";
40650
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
40651
+ import { basename, dirname as dirname5, join as join10 } from "node:path";
40647
40652
 
40648
40653
  // src/tool-reference.ts
40649
40654
  init_headless_operations();
@@ -40738,7 +40743,7 @@ function renderToolsMarkdown() {
40738
40743
 
40739
40744
  // src/skill.ts
40740
40745
  var SKILL_NAME = "gdharness";
40741
- var SHARED_SKILLS = join9(".agents", "skills");
40746
+ var SHARED_SKILLS = join10(".agents", "skills");
40742
40747
  function skillMarkdown(version) {
40743
40748
  return `---
40744
40749
  name: ${SKILL_NAME}
@@ -40802,8 +40807,18 @@ that is running, and the project on disk. ${TOOL_SPECS.length} tools, named \`do
40802
40807
  These need the runtime autoload, which \`gdharness setup\` registers. \`runtime_capture\` needs a
40803
40808
  window and refuses headless rather than handing back the last frame anything drew.
40804
40809
 
40805
- A headless game answers; a \`godot -s\` script run does not. It has no game in it, so the autoload
40806
- stays quiet there rather than announcing a test tier as the project.
40810
+ The autoload reads these settings and no others. \`${BIND_ADDRESS_SETTING}\`
40811
+ is \`127.0.0.1\` and should stay there: the command set includes \`call_method\`, \`set_property\`
40812
+ and input injection, none of it authenticated, and Godot's own \`listen()\` defaults to every
40813
+ interface rather than to loopback, so this is named on purpose rather than left out.
40814
+ \`${PORT_SETTING}\` is 0, meaning the operating system picks one and the game announces it, which is
40815
+ what the server reads; fix it only for a client that cannot read the announcement.
40816
+
40817
+ A headless game answers; a \`godot -s\` script run does not, by default. It has no game in it, so the
40818
+ autoload stays quiet there rather than announcing a test tier as the project: a gate starting sixteen
40819
+ engines would otherwise announce sixteen games that are not games. Set \`${SCRIPT_RUNS_SETTING}\`
40820
+ true in \`project.godot\` to serve one anyway, which is for driving a \`-s\` script on purpose. Read
40821
+ that setting rather than assuming the quiet: it is a default and not a property of script runs.
40807
40822
 
40808
40823
  The autoload reaches an export. \`gdharness runtime off\` in the project before shipping.
40809
40824
 
@@ -40867,27 +40882,27 @@ whatever the engine said on stderr comes back under \`engine_messages\`.
40867
40882
  function skillFiles(version) {
40868
40883
  return new Map([
40869
40884
  ["SKILL.md", skillMarkdown(version)],
40870
- [join9("references", "tools.md"), renderToolsMarkdown()]
40885
+ [join10("references", "tools.md"), renderToolsMarkdown()]
40871
40886
  ]);
40872
40887
  }
40873
40888
  function skillDirectories(harnesses, projectPath, exists) {
40874
- const directories = [join9(projectPath, SHARED_SKILLS, SKILL_NAME)];
40889
+ const directories = [join10(projectPath, SHARED_SKILLS, SKILL_NAME)];
40875
40890
  for (const harness of harnesses) {
40876
40891
  if (harness.skills === undefined) {
40877
40892
  continue;
40878
40893
  }
40879
- const own = join9(projectPath, harness.skills.dir);
40880
- if ((!harness.skills.shared || exists(own)) && !directories.includes(join9(own, SKILL_NAME))) {
40881
- directories.push(join9(own, SKILL_NAME));
40894
+ const own = join10(projectPath, harness.skills.dir);
40895
+ if ((!harness.skills.shared || exists(own)) && !directories.includes(join10(own, SKILL_NAME))) {
40896
+ directories.push(join10(own, SKILL_NAME));
40882
40897
  }
40883
40898
  }
40884
40899
  return directories;
40885
40900
  }
40886
40901
  function everySkillDirectory(projectPath, harnesses) {
40887
- const directories = new Set([join9(projectPath, SHARED_SKILLS, SKILL_NAME)]);
40902
+ const directories = new Set([join10(projectPath, SHARED_SKILLS, SKILL_NAME)]);
40888
40903
  for (const harness of harnesses) {
40889
40904
  if (harness.skills !== undefined) {
40890
- directories.add(join9(projectPath, harness.skills.dir, SKILL_NAME));
40905
+ directories.add(join10(projectPath, harness.skills.dir, SKILL_NAME));
40891
40906
  }
40892
40907
  }
40893
40908
  return [...directories];
@@ -40895,52 +40910,52 @@ function everySkillDirectory(projectPath, harnesses) {
40895
40910
  function removeSkill(directories, projectPath) {
40896
40911
  const removed = [];
40897
40912
  for (const directory of directories) {
40898
- if (existsSync8(directory)) {
40899
- rmSync4(directory, { recursive: true, force: true });
40900
- pruneEmpty(dirname4(directory), projectPath);
40913
+ if (existsSync9(directory)) {
40914
+ rmSync5(directory, { recursive: true, force: true });
40915
+ pruneEmpty(dirname5(directory), projectPath);
40901
40916
  removed.push(directory);
40902
40917
  }
40903
40918
  }
40904
40919
  return removed;
40905
40920
  }
40906
40921
  function pruneEmpty(directory, projectPath) {
40907
- const shared = join9(projectPath, ".agents");
40922
+ const shared = join10(projectPath, ".agents");
40908
40923
  let path = directory;
40909
40924
  while (path !== projectPath && (basename(path) === "skills" || path === shared)) {
40910
40925
  if (readdirSync3(path).length > 0) {
40911
40926
  return;
40912
40927
  }
40913
- rmSync4(path, { recursive: true, force: true });
40914
- path = dirname4(path);
40928
+ rmSync5(path, { recursive: true, force: true });
40929
+ path = dirname5(path);
40915
40930
  }
40916
40931
  }
40917
40932
  function writeSkill(directories, version) {
40918
40933
  const files = skillFiles(version);
40919
40934
  return directories.map((directory) => {
40920
- const replaced = existsSync8(directory);
40921
- rmSync4(directory, { recursive: true, force: true });
40935
+ const replaced = existsSync9(directory);
40936
+ rmSync5(directory, { recursive: true, force: true });
40922
40937
  for (const [name, contents] of files) {
40923
- const path = join9(directory, name);
40924
- mkdirSync4(dirname4(path), { recursive: true });
40925
- writeFileSync6(path, contents, "utf8");
40938
+ const path = join10(directory, name);
40939
+ mkdirSync5(dirname5(path), { recursive: true });
40940
+ writeFileSync7(path, contents, "utf8");
40926
40941
  }
40927
40942
  return { path: directory, replaced };
40928
40943
  });
40929
40944
  }
40930
40945
 
40931
40946
  // src/version.ts
40932
- import { readFileSync as readFileSync8 } from "node:fs";
40933
- import { dirname as dirname5, join as join10 } from "node:path";
40947
+ import { readFileSync as readFileSync9 } from "node:fs";
40948
+ import { dirname as dirname6, join as join11 } from "node:path";
40934
40949
  import { fileURLToPath as fileURLToPath2 } from "node:url";
40935
40950
  function getLocalVersion() {
40936
- const currentDirectory = dirname5(fileURLToPath2(import.meta.url));
40951
+ const currentDirectory = dirname6(fileURLToPath2(import.meta.url));
40937
40952
  const packageCandidates = [
40938
- join10(currentDirectory, "..", "package.json"),
40939
- join10(currentDirectory, "..", "..", "package.json")
40953
+ join11(currentDirectory, "..", "package.json"),
40954
+ join11(currentDirectory, "..", "..", "package.json")
40940
40955
  ];
40941
40956
  for (const packagePath of packageCandidates) {
40942
40957
  try {
40943
- const value = JSON.parse(readFileSync8(packagePath, "utf-8"));
40958
+ const value = JSON.parse(readFileSync9(packagePath, "utf-8"));
40944
40959
  if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
40945
40960
  return value.version;
40946
40961
  }