gdharness 0.12.0 → 0.12.2

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/README.md CHANGED
@@ -73,11 +73,12 @@ and integration suites run against a real engine on all three before anything is
73
73
 
74
74
  What each kind of release means here:
75
75
 
76
- - **Patch**: an answer that was wrong is now right. The output can change, because a wrong answer
77
- corrected is a fix rather than a feature, and leaving one wrong to protect whoever parsed it is
78
- how a tool stops being worth asking.
79
- - **Minor**: a tool, an op, an argument or a field was added, or behaviour a caller can see
80
- changed.
76
+ - **Patch**: nearly everything. An answer that was wrong is now right, and the output may change
77
+ shape for it, because a wrong answer corrected is a fix rather than a feature and leaving one
78
+ wrong to protect whoever parsed it is how a tool stops being worth asking. An addition nothing
79
+ has to adapt to is a patch too: a new argument, a new field, an argument reaching further than it
80
+ did. Ignore all of it and your calls still work.
81
+ - **Minor**: a new tool or a new op, meaning this does something it could not do before.
81
82
  - **Major**: a tool, an op, an argument or a field was renamed or taken away. Nothing else earns
82
83
  one.
83
84
 
package/build/cli.js CHANGED
@@ -15714,7 +15714,7 @@ var init_tool_definitions = __esm(() => {
15714
15714
  },
15715
15715
  {
15716
15716
  name: "editor_output",
15717
- description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries. A run that has quit still answers here, with running false and its exit code, until the next one starts.",
15717
+ description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries. A run that has quit still answers here, with running false and its exit code, until the next one starts. A run this server started also answers with transcript, the file both its streams are written to: uncapped, written while the run is going, and the thing to read or tail for a long run rather than the engine's own log, which every engine start rotates away.",
15718
15718
  parameters: {
15719
15719
  severity: {
15720
15720
  type: "string",
@@ -38002,6 +38002,13 @@ class GodotServer {
38002
38002
  limit: readPositiveNumber(args, "limit") ?? 200
38003
38003
  });
38004
38004
  const halt = run.throughEditor ? this.dapClient?.whereItStopped() ?? null : null;
38005
+ const notes = [];
38006
+ if (run.endedUnwatched === true) {
38007
+ notes.push("This run outlived the server that started it and is over now, so its exit code was never collected. Everything it printed is below, read back from its transcript.");
38008
+ }
38009
+ if (run.transcript !== null && selected.omitted > 0) {
38010
+ notes.push(`Everything this run has printed is in ${run.transcript}, uncapped and still being written.`);
38011
+ }
38005
38012
  return this.jsonTextResponse({
38006
38013
  running: stillRunning(run),
38007
38014
  exitCode: run.exitCode,
@@ -38013,7 +38020,8 @@ class GodotServer {
38013
38020
  heldAt: halt,
38014
38021
  endedUnwatched: run.endedUnwatched === true ? true : undefined,
38015
38022
  project: !run.throughEditor && run.process === null ? run.projectPath ?? undefined : undefined,
38016
- note: run.endedUnwatched === true ? "This run outlived the server that started it and is over now, so its exit code was never collected. Everything it printed is below, read back from its transcript." : undefined,
38023
+ transcript: run.transcript ?? undefined,
38024
+ note: notes.length > 0 ? notes.join(" ") : undefined,
38017
38025
  omitted: selected.omitted,
38018
38026
  entries: selected.entries
38019
38027
  });
@@ -39477,6 +39485,9 @@ async function enablePlugins(engine, projectPath, names) {
39477
39485
  }
39478
39486
  return outcomes;
39479
39487
  }
39488
+ function autoloadIsOurs(named) {
39489
+ return named === null || named === `res://${RUNTIME_AUTOLOAD.path}`;
39490
+ }
39480
39491
  async function setRuntime(engine, projectPath, on) {
39481
39492
  return on ? await runOperation2(engine, "add_autoload", { name: RUNTIME_AUTOLOAD.name, path: `res://${RUNTIME_AUTOLOAD.path}`, enabled: true }, projectPath) : await runOperation2(engine, "remove_autoload", { name: RUNTIME_AUTOLOAD.name }, projectPath);
39482
39493
  }
@@ -39533,8 +39544,12 @@ function inspectProject(projectPath) {
39533
39544
  }
39534
39545
  }
39535
39546
  const autoload = settings["autoload"];
39536
- const runtimeAutoload = autoload !== undefined && typeof readString(autoload, RUNTIME_AUTOLOAD.name) === "string";
39547
+ const registered = autoload === undefined ? undefined : readString(autoload, RUNTIME_AUTOLOAD.name);
39548
+ const runtimeAutoload = typeof registered === "string";
39549
+ const runtimeAutoloadPath = typeof registered === "string" ? registered.replace(/^\*/, "") : null;
39537
39550
  const named = autoloadPaths(settings);
39551
+ const loaderEntry = [...named].find(([entry, path]) => entry !== RUNTIME_AUTOLOAD.name && path !== RUNTIME_AUTOLOAD.path && path.toLowerCase().includes("gdharness")) ?? null;
39552
+ const runtimeLoaderAutoload = loaderEntry === null ? null : { name: loaderEntry[0], path: loaderEntry[1] };
39538
39553
  const tracked = trackedByGit(projectPath, [...named.values()]);
39539
39554
  for (const [name, path] of named) {
39540
39555
  if (tracked !== null && !tracked.has(path) && existsSync7(join8(projectPath, path))) {
@@ -39553,6 +39568,8 @@ function inspectProject(projectPath) {
39553
39568
  addons,
39554
39569
  pluginsEnabled,
39555
39570
  runtimeAutoload,
39571
+ runtimeAutoloadPath,
39572
+ runtimeLoaderAutoload,
39556
39573
  staleClasses,
39557
39574
  classCacheExists: cached !== null,
39558
39575
  problems
@@ -39839,6 +39856,24 @@ function said2(outcome, what) {
39839
39856
  console.error(` engine ${entry.severity}: ${entry.text}`);
39840
39857
  }
39841
39858
  }
39859
+ async function registerRuntime(godot, projectPath) {
39860
+ const report = inspectProject(projectPath);
39861
+ const named = report.runtimeAutoloadPath;
39862
+ const loader = report.runtimeLoaderAutoload;
39863
+ if (named === null && loader !== null) {
39864
+ console.log(`${loader.name} autoload already names res://${loader.path}, which is this project bringing the runtime up its own way, so ${RUNTIME_AUTOLOAD.name} was not added: a second entry would come up beside it without whatever that file refuses. If it is not a loader, add ${RUNTIME_AUTOLOAD.name} yourself.`);
39865
+ return;
39866
+ }
39867
+ if (autoloadIsOurs(named)) {
39868
+ said2(await setRuntime(godot, projectPath, true), "registering the runtime autoload");
39869
+ console.log(`${RUNTIME_AUTOLOAD.name} autoload registered at res://${RUNTIME_AUTOLOAD.path}`);
39870
+ return;
39871
+ }
39872
+ console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
39873
+ if (!existsSync13(join17(projectPath, (named ?? "").replace(/^res:\/\//, "")))) {
39874
+ 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}`);
39875
+ }
39876
+ }
39842
39877
  var SETUP_FLAGS = new Set(["--runtime", "--no-runtime", "--no-connect", "--no-skill", "--json", "--yes"]);
39843
39878
  function namedHarnesses() {
39844
39879
  const flags = args.filter((arg) => arg.startsWith("--") && !SETUP_FLAGS.has(arg));
@@ -39941,8 +39976,7 @@ async function setup() {
39941
39976
  console.log(`${name}: ${outcome.ok ? String(outcome.payload["action"]) : "failed"}`);
39942
39977
  }
39943
39978
  if (runtime) {
39944
- said2(await setRuntime(godot, projectPath, true), "registering the runtime autoload");
39945
- console.log(`${RUNTIME_AUTOLOAD.name} autoload registered`);
39979
+ await registerRuntime(godot, projectPath);
39946
39980
  }
39947
39981
  const classes = await runOperation(godot, "refresh_class_cache", {}, projectPath);
39948
39982
  said2(classes, "rebuilding the class list");
@@ -40042,7 +40076,7 @@ async function upgrade() {
40042
40076
  said2(outcome, `enabling ${EDITOR_PLUGINS[index] ?? ""}`);
40043
40077
  }
40044
40078
  if (before.runtimeAutoload) {
40045
- said2(await setRuntime(godot, projectPath, true), "registering the runtime autoload");
40079
+ await registerRuntime(godot, projectPath);
40046
40080
  }
40047
40081
  said2(await runOperation(godot, "refresh_class_cache", {}, projectPath), "rebuilding the class list");
40048
40082
  const launch = launchFor(version, godot.godotPath, projectPath);
@@ -40092,8 +40126,12 @@ async function runtime3() {
40092
40126
  }
40093
40127
  const projectPath = projectArgument(2);
40094
40128
  const godot = await engine();
40095
- said2(await setRuntime(godot, projectPath, state === "on"), `turning the runtime ${state}`);
40096
- console.log(`${RUNTIME_AUTOLOAD.name} autoload ${state === "on" ? "registered" : "removed"}`);
40129
+ if (state === "on") {
40130
+ await registerRuntime(godot, projectPath);
40131
+ return;
40132
+ }
40133
+ said2(await setRuntime(godot, projectPath, false), "turning the runtime off");
40134
+ console.log(`${RUNTIME_AUTOLOAD.name} autoload removed`);
40097
40135
  }
40098
40136
  async function classes() {
40099
40137
  const projectPath = projectArgument(1);
package/build/index.js CHANGED
@@ -28518,7 +28518,7 @@ var TOOL_SPECS = [
28518
28518
  },
28519
28519
  {
28520
28520
  name: "editor_output",
28521
- description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries. A run that has quit still answers here, with running false and its exit code, until the next one starts.",
28521
+ description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries. A run that has quit still answers here, with running false and its exit code, until the next one starts. A run this server started also answers with transcript, the file both its streams are written to: uncapped, written while the run is going, and the thing to read or tail for a long run rather than the engine's own log, which every engine start rotates away.",
28522
28522
  parameters: {
28523
28523
  severity: {
28524
28524
  type: "string",
@@ -30784,6 +30784,13 @@ class GodotServer {
30784
30784
  limit: readPositiveNumber(args, "limit") ?? 200
30785
30785
  });
30786
30786
  const halt = run.throughEditor ? this.dapClient?.whereItStopped() ?? null : null;
30787
+ const notes = [];
30788
+ if (run.endedUnwatched === true) {
30789
+ notes.push("This run outlived the server that started it and is over now, so its exit code was never collected. Everything it printed is below, read back from its transcript.");
30790
+ }
30791
+ if (run.transcript !== null && selected.omitted > 0) {
30792
+ notes.push(`Everything this run has printed is in ${run.transcript}, uncapped and still being written.`);
30793
+ }
30787
30794
  return this.jsonTextResponse({
30788
30795
  running: stillRunning(run),
30789
30796
  exitCode: run.exitCode,
@@ -30795,7 +30802,8 @@ class GodotServer {
30795
30802
  heldAt: halt,
30796
30803
  endedUnwatched: run.endedUnwatched === true ? true : undefined,
30797
30804
  project: !run.throughEditor && run.process === null ? run.projectPath ?? undefined : undefined,
30798
- note: run.endedUnwatched === true ? "This run outlived the server that started it and is over now, so its exit code was never collected. Everything it printed is below, read back from its transcript." : undefined,
30805
+ transcript: run.transcript ?? undefined,
30806
+ note: notes.length > 0 ? notes.join(" ") : undefined,
30799
30807
  omitted: selected.omitted,
30800
30808
  entries: selected.entries
30801
30809
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdharness",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "mcpName": "io.github.Aureliolo/gdharness",
5
5
  "description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
6
6
  "type": "module",