gdharness 1.1.33 → 1.1.34

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
@@ -17758,7 +17758,7 @@ var init_tool_definitions = __esm(() => {
17758
17758
  },
17759
17759
  {
17760
17760
  name: "script_edit",
17761
- description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none: changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a find_children string, a word in a comment, a node named like the class, a call on a value whose type the analyser could not tell. Read leftAlone before calling the rename done; nothing in it was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled.",
17761
+ description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none. A new name already taken is refused with nothing written, a member's included when a class inheriting it already uses the name in code, as a local or a parameter. changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a find_children string, a node named like the class, a call on a value whose type the analyser could not tell. A comment or a line of a text file with nothing more to say is given under leftAloneInProse by file and line instead. Read both before calling the rename done; nothing in them was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled. written is true once the files are written, and ok is false when what came after the write failed: the files are left changed, and note says so.",
17762
17762
  parameters: {
17763
17763
  projectPath: PROJECT_PATH,
17764
17764
  scriptPath: SCRIPT_PATH,
@@ -40684,6 +40684,20 @@ async function renameSymbol(request, services) {
40684
40684
  conflicts.push(`${newName} is already declared in ${id.endsWith("#") ? fileOf(id) : `${fileOf(id)}, class ${id.slice(id.lastIndexOf("#") + 1)}`}`);
40685
40685
  }
40686
40686
  }
40687
+ const heirs = graph.descendants(root);
40688
+ const inUse = [];
40689
+ for (const script of scripts.values()) {
40690
+ for (const occurrence of script.occurrences(newName)) {
40691
+ const body = graph.bodyAt(script.path, occurrence.offset);
40692
+ if (occurrence.kind === "code" && !occurrence.afterDot && heirs.has(body) && graph.declaration(body, newName)?.offset !== occurrence.offset) {
40693
+ inUse.push({ file: script.path, line: script.lines.positionOf(occurrence.offset).line + 1 });
40694
+ }
40695
+ }
40696
+ }
40697
+ if (inUse.length > 0) {
40698
+ const places = inUse.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line).slice(0, 10).map((place) => `${place.file}:${place.line}`);
40699
+ conflicts.push(`${newName} is already used in code where ${symbol} is inherited, as a local, a parameter or another name the renamed ${what} would shadow or be shadowed by, at ${places.join(", ")}${inUse.length > places.length ? ` and ${inUse.length - places.length} more` : ""}`);
40700
+ }
40687
40701
  if (conflicts.length > 0) {
40688
40702
  return {
40689
40703
  ok: false,
@@ -40755,7 +40769,7 @@ async function renameSymbol(request, services) {
40755
40769
  ...overrides.length > 0 ? { overridesRenamed: overrides } : {},
40756
40770
  ...moveTo === null ? {} : { moved: { from: declaringPath, to: moveTo } },
40757
40771
  changed: changedReport(plan.edits, rewrites),
40758
- leftAlone: plan.mentions,
40772
+ ...leftAloneReport(plan.mentions),
40759
40773
  summary: summaryOf(plan.edits, plan.mentions, rewrites)
40760
40774
  }
40761
40775
  };
@@ -40850,6 +40864,27 @@ function changedReport(edits, rewrites) {
40850
40864
  };
40851
40865
  });
40852
40866
  }
40867
+ function leftAloneReport(mentions) {
40868
+ const full = [];
40869
+ const prose = new Map;
40870
+ for (const mention of mentions) {
40871
+ if ((mention.kind === "comment" || mention.kind === "text") && mention.why === undefined) {
40872
+ const key = `${mention.file}
40873
+ ${mention.kind}`;
40874
+ const group = prose.get(key) ?? { file: mention.file, kind: mention.kind, lines: [] };
40875
+ if (!group.lines.includes(mention.line)) {
40876
+ group.lines.push(mention.line);
40877
+ }
40878
+ prose.set(key, group);
40879
+ } else {
40880
+ full.push(mention);
40881
+ }
40882
+ }
40883
+ return {
40884
+ leftAlone: full,
40885
+ ...prose.size > 0 ? { leftAloneInProse: [...prose.values()] } : {}
40886
+ };
40887
+ }
40853
40888
  function summaryOf(edits, mentions, rewrites) {
40854
40889
  const count = (values) => {
40855
40890
  const counted = {};
@@ -45995,7 +46030,18 @@ class GodotServer {
45995
46030
  rebuildCache: outcome.isClass || outcome.moved !== null,
45996
46031
  moved: outcome.moved !== null
45997
46032
  });
45998
- return this.jsonTextResponse({ ok: settled.ok, ...outcome.report, ...settled.report });
46033
+ const said = readString(settled.report, "note");
46034
+ const leftChanged = settled.ok ? said : [
46035
+ "The rename was written: every file under changed now reads as shown there and is left that way. ok is false for what came after the write, said under editor or compiled.",
46036
+ ...said === undefined ? [] : [said]
46037
+ ].join(" ");
46038
+ return this.jsonTextResponse({
46039
+ ok: settled.ok,
46040
+ written: true,
46041
+ ...outcome.report,
46042
+ ...settled.report,
46043
+ ...leftChanged === undefined ? {} : { note: leftChanged }
46044
+ });
45999
46045
  }
46000
46046
  async settleRenameInEditor(projectPath, changed, names) {
46001
46047
  const { gone, oldClass, newClass } = names;
@@ -47697,9 +47743,10 @@ that a setting nobody wrote down still answers with the default the engine regis
47697
47743
 
47698
47744
  To rename a class or a member across the project, use \`script_edit rename\` rather than a text
47699
47745
  replacement: it changes the uses the engine resolves, doc links and what scenes record, and lists
47700
- every other occurrence of the word under \`leftAlone\`, a \`find_children\` string, a word in a
47701
- comment or a file under a \`.gdignore\` directory, for you to read. Pass \`preview\` first on a
47702
- large rename.
47746
+ every other occurrence of the word for you to read: a \`find_children\` string or a file under a
47747
+ \`.gdignore\` directory under \`leftAlone\`, and a word in a comment or a text file by line under
47748
+ \`leftAloneInProse\`. Pass \`preview\` first on a large rename. If the answer has \`ok: false\`
47749
+ beside \`written: true\`, the files were changed and a script did not compile afterwards.
47703
47750
 
47704
47751
  Editing a file while a game is running does not change the running game. \`auto_reload\` is an
47705
47752
  editor plugin and reloads into the editor's own process; the game is a separate process holding
package/build/index.js CHANGED
@@ -31650,6 +31650,20 @@ async function renameSymbol(request, services) {
31650
31650
  conflicts.push(`${newName} is already declared in ${id.endsWith("#") ? fileOf(id) : `${fileOf(id)}, class ${id.slice(id.lastIndexOf("#") + 1)}`}`);
31651
31651
  }
31652
31652
  }
31653
+ const heirs = graph.descendants(root);
31654
+ const inUse = [];
31655
+ for (const script of scripts.values()) {
31656
+ for (const occurrence of script.occurrences(newName)) {
31657
+ const body = graph.bodyAt(script.path, occurrence.offset);
31658
+ if (occurrence.kind === "code" && !occurrence.afterDot && heirs.has(body) && graph.declaration(body, newName)?.offset !== occurrence.offset) {
31659
+ inUse.push({ file: script.path, line: script.lines.positionOf(occurrence.offset).line + 1 });
31660
+ }
31661
+ }
31662
+ }
31663
+ if (inUse.length > 0) {
31664
+ const places = inUse.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line).slice(0, 10).map((place) => `${place.file}:${place.line}`);
31665
+ conflicts.push(`${newName} is already used in code where ${symbol} is inherited, as a local, a parameter or another name the renamed ${what} would shadow or be shadowed by, at ${places.join(", ")}${inUse.length > places.length ? ` and ${inUse.length - places.length} more` : ""}`);
31666
+ }
31653
31667
  if (conflicts.length > 0) {
31654
31668
  return {
31655
31669
  ok: false,
@@ -31721,7 +31735,7 @@ async function renameSymbol(request, services) {
31721
31735
  ...overrides.length > 0 ? { overridesRenamed: overrides } : {},
31722
31736
  ...moveTo === null ? {} : { moved: { from: declaringPath, to: moveTo } },
31723
31737
  changed: changedReport(plan.edits, rewrites),
31724
- leftAlone: plan.mentions,
31738
+ ...leftAloneReport(plan.mentions),
31725
31739
  summary: summaryOf(plan.edits, plan.mentions, rewrites)
31726
31740
  }
31727
31741
  };
@@ -31816,6 +31830,27 @@ function changedReport(edits, rewrites) {
31816
31830
  };
31817
31831
  });
31818
31832
  }
31833
+ function leftAloneReport(mentions) {
31834
+ const full = [];
31835
+ const prose = new Map;
31836
+ for (const mention of mentions) {
31837
+ if ((mention.kind === "comment" || mention.kind === "text") && mention.why === undefined) {
31838
+ const key = `${mention.file}
31839
+ ${mention.kind}`;
31840
+ const group = prose.get(key) ?? { file: mention.file, kind: mention.kind, lines: [] };
31841
+ if (!group.lines.includes(mention.line)) {
31842
+ group.lines.push(mention.line);
31843
+ }
31844
+ prose.set(key, group);
31845
+ } else {
31846
+ full.push(mention);
31847
+ }
31848
+ }
31849
+ return {
31850
+ leftAlone: full,
31851
+ ...prose.size > 0 ? { leftAloneInProse: [...prose.values()] } : {}
31852
+ };
31853
+ }
31819
31854
  function summaryOf(edits, mentions, rewrites) {
31820
31855
  const count = (values) => {
31821
31856
  const counted = {};
@@ -33002,7 +33037,7 @@ var TOOL_SPECS = [
33002
33037
  },
33003
33038
  {
33004
33039
  name: "script_edit",
33005
- description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none: changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a find_children string, a word in a comment, a node named like the class, a call on a value whose type the analyser could not tell. Read leftAlone before calling the rename done; nothing in it was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled.",
33040
+ description: "Creates a GDScript file, or adds functions, variables and signals to one. Every declaration written carries a type. Both load what they wrote under the project's own warning settings and answer with parses; the engine's reasons for a refusal come back under engine_messages. create answers with the extends and class_name the engine read, and a script declaring a class_name is put in the project's class list, with registered saying whether it is there. modify makes every addition or none, and answers with the line each one is on in the file written. rename renames a class or a member wherever the engine uses it and writes every file or none. A new name already taken is refused with nothing written, a member's included when a class inheriting it already uses the name in code, as a local or a parameter. changed lists each file with its changed lines as they now read, and leftAlone lists every other whole-word occurrence of the old name with what the tokenizer makes of it (code, string, comment, doc, nodePath, scene, text, or ignored for a file under a .gdignore directory, which is never changed) and, where it is not plain, why: a find_children string, a node named like the class, a call on a value whose type the analyser could not tell. A comment or a line of a text file with nothing more to say is given under leftAloneInProse by file and line instead. Read both before calling the rename done; nothing in them was changed. Afterwards an open editor scans the changed files and reloads every changed script, which is also the compile check, and its answer comes back under editor; with no editor the class cache is rebuilt and the changed scripts are compiled in a fresh engine, under classCache and compiled. written is true once the files are written, and ok is false when what came after the write failed: the files are left changed, and note says so.",
33006
33041
  parameters: {
33007
33042
  projectPath: PROJECT_PATH,
33008
33043
  scriptPath: SCRIPT_PATH,
@@ -38567,7 +38602,18 @@ class GodotServer {
38567
38602
  rebuildCache: outcome.isClass || outcome.moved !== null,
38568
38603
  moved: outcome.moved !== null
38569
38604
  });
38570
- return this.jsonTextResponse({ ok: settled.ok, ...outcome.report, ...settled.report });
38605
+ const said = readString(settled.report, "note");
38606
+ const leftChanged = settled.ok ? said : [
38607
+ "The rename was written: every file under changed now reads as shown there and is left that way. ok is false for what came after the write, said under editor or compiled.",
38608
+ ...said === undefined ? [] : [said]
38609
+ ].join(" ");
38610
+ return this.jsonTextResponse({
38611
+ ok: settled.ok,
38612
+ written: true,
38613
+ ...outcome.report,
38614
+ ...settled.report,
38615
+ ...leftChanged === undefined ? {} : { note: leftChanged }
38616
+ });
38571
38617
  }
38572
38618
  async settleRenameInEditor(projectPath, changed, names) {
38573
38619
  const { gone, oldClass, newClass } = names;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdharness",
3
- "version": "1.1.33",
3
+ "version": "1.1.34",
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",