gdharness 1.1.32 → 1.1.33

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.
Files changed (3) hide show
  1. package/build/cli.js +129 -25
  2. package/build/index.js +123 -20
  3. package/package.json +1 -1
package/build/cli.js CHANGED
@@ -8892,6 +8892,7 @@ function wholeWord(name, flags = "gu") {
8892
8892
  function occurrencesOf(source, name, regions = regionsOf(source)) {
8893
8893
  const found = [];
8894
8894
  let index = 0;
8895
+ let code = null;
8895
8896
  for (const match of source.matchAll(wholeWord(name))) {
8896
8897
  const offset = match.index;
8897
8898
  while (index < regions.length - 1 && (regions[index]?.end ?? 0) <= offset) {
@@ -8901,16 +8902,17 @@ function occurrencesOf(source, name, regions = regionsOf(source)) {
8901
8902
  let afterDot = false;
8902
8903
  let declaredAs = null;
8903
8904
  if (kind === "code") {
8905
+ code ??= codeOf(source, regions);
8904
8906
  let back = offset - 1;
8905
- while (back >= 0 && /[\s\\]/.test(source[back] ?? "")) {
8907
+ while (back >= 0 && /[\s\\]/.test(code[back] ?? "")) {
8906
8908
  back -= 1;
8907
8909
  }
8908
- afterDot = source[back] === "." && source[back - 1] !== ".";
8910
+ afterDot = code[back] === "." && code[back - 1] !== ".";
8909
8911
  let wordStart = back + 1;
8910
- while (wordStart > 0 && isIdentifierPart(source[wordStart - 1])) {
8912
+ while (wordStart > 0 && isIdentifierPart(code[wordStart - 1])) {
8911
8913
  wordStart -= 1;
8912
8914
  }
8913
- const word = source.slice(wordStart, back + 1);
8915
+ const word = code.slice(wordStart, back + 1);
8914
8916
  declaredAs = DECLARING.has(word) ? word : null;
8915
8917
  }
8916
8918
  found.push({ offset, kind, afterDot, declaredAs });
@@ -17756,7 +17758,7 @@ var init_tool_definitions = __esm(() => {
17756
17758
  },
17757
17759
  {
17758
17760
  name: "script_edit",
17759
- 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 or text) 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: 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.",
17760
17762
  parameters: {
17761
17763
  projectPath: PROJECT_PATH,
17762
17764
  scriptPath: SCRIPT_PATH,
@@ -39654,6 +39656,33 @@ function projectTexts(projectPath) {
39654
39656
  visit(projectPath, "");
39655
39657
  return found;
39656
39658
  }
39659
+ function ignoredTexts(projectPath) {
39660
+ const found = [];
39661
+ const visit = (directory, prefix, ignored) => {
39662
+ const under = ignored || steppedOver(directory);
39663
+ for (const entry of readdirSync7(directory, { withFileTypes: true })) {
39664
+ if (skipped(entry.name)) {
39665
+ continue;
39666
+ }
39667
+ const absolute = join20(directory, entry.name);
39668
+ const spelled = `${prefix}${entry.name}`;
39669
+ if (entry.isDirectory()) {
39670
+ visit(absolute, `${spelled}/`, under);
39671
+ continue;
39672
+ }
39673
+ const extension = entry.name.includes(".") ? entry.name.split(".").pop()?.toLowerCase() ?? "" : "";
39674
+ if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
39675
+ continue;
39676
+ }
39677
+ const bytes = readFileSync17(absolute);
39678
+ if (!isBinary(bytes)) {
39679
+ found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
39680
+ }
39681
+ }
39682
+ };
39683
+ visit(projectPath, "", false);
39684
+ return found;
39685
+ }
39657
39686
  function searchProject(projectPath, options) {
39658
39687
  const extensions = options.fileTypes === undefined ? null : new Set(options.fileTypes.map((ext) => ext.replace(/^\./, "").toLowerCase()).filter(Boolean));
39659
39688
  const result = {
@@ -39901,33 +39930,79 @@ function declaredIn(scripts) {
39901
39930
  }
39902
39931
  return declared;
39903
39932
  }
39933
+ function docBlockAt(text, offset) {
39934
+ const lineStartOf = (at) => text.lastIndexOf(`
39935
+ `, at - 1) + 1;
39936
+ const contentOf = (lineStart) => {
39937
+ let at = lineStart;
39938
+ while (text[at] === " " || text[at] === "\t") {
39939
+ at += 1;
39940
+ }
39941
+ return text.startsWith("##", at) ? at + 2 : null;
39942
+ };
39943
+ let top = lineStartOf(offset);
39944
+ if (contentOf(top) === null) {
39945
+ return null;
39946
+ }
39947
+ while (top > 0 && contentOf(lineStartOf(top - 1)) !== null) {
39948
+ top = lineStartOf(top - 1);
39949
+ }
39950
+ let joined = "";
39951
+ const from = [];
39952
+ for (let line = top;; ) {
39953
+ const content = contentOf(line);
39954
+ if (content === null) {
39955
+ break;
39956
+ }
39957
+ const nextBreak = text.indexOf(`
39958
+ `, line);
39959
+ let end = nextBreak < 0 ? text.length : nextBreak;
39960
+ if (text[end - 1] === "\r") {
39961
+ end -= 1;
39962
+ }
39963
+ if (joined.length > 0) {
39964
+ joined += " ";
39965
+ from.push(-1);
39966
+ }
39967
+ for (let at = content;at < end; at += 1) {
39968
+ joined += text[at];
39969
+ from.push(at);
39970
+ }
39971
+ if (nextBreak < 0) {
39972
+ break;
39973
+ }
39974
+ line = nextBreak + 1;
39975
+ }
39976
+ return { joined, from };
39977
+ }
39904
39978
  function docLinkAt(text, offset) {
39905
- const lineStart = text.lastIndexOf(`
39906
- `, offset - 1) + 1;
39907
- const nextBreak = text.indexOf(`
39908
- `, offset);
39909
- const lineEnd = nextBreak < 0 ? text.length : nextBreak;
39910
- const open = text.lastIndexOf("[", offset);
39911
- const close = text.indexOf("]", offset);
39912
- if (open < lineStart || close === -1 || close > lineEnd) {
39979
+ const block = docBlockAt(text, offset);
39980
+ const at = block?.from.indexOf(offset) ?? -1;
39981
+ if (block === null || at < 0) {
39913
39982
  return null;
39914
39983
  }
39915
- const inside = text.slice(open + 1, close);
39984
+ const { joined } = block;
39985
+ const open = joined.lastIndexOf("[", at);
39986
+ const close = joined.indexOf("]", at);
39987
+ if (open < 0 || close < 0) {
39988
+ return null;
39989
+ }
39990
+ const inside = joined.slice(open + 1, close);
39916
39991
  if (inside.includes("[") || inside.includes("]")) {
39917
39992
  return null;
39918
39993
  }
39919
- const match = /^(?:([a-z_]+)\s+)?([\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)*)$/u.exec(inside);
39994
+ const match = /^\s*(?:([a-z_]+)\s+)?([\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)*)\s*$/u.exec(inside);
39920
39995
  if (match === null || match[1] !== undefined && !DOC_LINK_KINDS.has(match[1])) {
39921
39996
  return null;
39922
39997
  }
39923
- const parts = (match[2] ?? "").split(".");
39924
- const pathStart = open + 1 + inside.length - (match[2] ?? "").length;
39925
- let at = pathStart;
39998
+ const path = match[2] ?? "";
39999
+ const parts = path.split(".");
40000
+ let partAt = open + 1 + inside.trimEnd().length - path.length;
39926
40001
  for (const [index, part] of parts.entries()) {
39927
- if (at === offset) {
40002
+ if (partAt === at) {
39928
40003
  return { kind: match[1] ?? null, parts, index };
39929
40004
  }
39930
- at += part.length + 1;
40005
+ partAt += part.length + 1;
39931
40006
  }
39932
40007
  return null;
39933
40008
  }
@@ -40325,6 +40400,33 @@ function planMove(args, plan) {
40325
40400
  mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
40326
40401
  };
40327
40402
  }
40403
+ function mentionIgnored(plan, ignored, name, movedFrom) {
40404
+ const mentions = [...plan.mentions];
40405
+ const why = "under a directory holding a .gdignore, which the engine does not load, so it was not changed";
40406
+ for (const file of ignored) {
40407
+ const lines = new Lines(file.text);
40408
+ const offsets = occurrencesOf(file.text, name, [{ kind: "code", start: 0, end: file.text.length }]).map((one) => one.offset);
40409
+ if (movedFrom !== null) {
40410
+ let at = file.text.indexOf(movedFrom);
40411
+ while (at >= 0) {
40412
+ offsets.push(at);
40413
+ at = file.text.indexOf(movedFrom, at + movedFrom.length);
40414
+ }
40415
+ }
40416
+ const seen = new Set;
40417
+ for (const offset of offsets) {
40418
+ const line = lines.positionOf(offset).line + 1;
40419
+ if (!seen.has(line)) {
40420
+ seen.add(line);
40421
+ mentions.push({ file: file.path, line, kind: "ignored", text: lines.lineAt(offset).trim(), why });
40422
+ }
40423
+ }
40424
+ }
40425
+ return {
40426
+ edits: plan.edits,
40427
+ mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
40428
+ };
40429
+ }
40328
40430
  function rewritesOf(plan, texts, move) {
40329
40431
  const byPath = new Map(texts.map((file) => [file.path, file]));
40330
40432
  const byFile = new Map;
@@ -40637,6 +40739,7 @@ async function renameSymbol(request, services) {
40637
40739
  exists: (path) => existsSync18(`${projectPath}/${path.slice("res://".length)}`)
40638
40740
  }, plan);
40639
40741
  }
40742
+ plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? null : declaringPath);
40640
40743
  const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
40641
40744
  const graph = new ClassGraph(scripts, declared);
40642
40745
  const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
@@ -47588,14 +47691,15 @@ formatting. \`script_diagnostics\` and \`script_info\` come from the editor's ow
47588
47691
  \`project_export\`, \`project_test\`, \`script_edit\`, \`script_info structure\` and
47589
47692
  \`editor_classes\` need nothing open: they run a short headless engine and are gone before the
47590
47693
  answer is printed. The exception is \`script_edit rename\` of a method, variable, signal or other
47591
- member, which asks the editor's language server which uses are that class's.
47694
+ member, which asks the editor's language server which uses are that class's. \`project_settings
47695
+ get\` is on that list too, reading as it does like a look at a config file: it starts an engine so
47696
+ that a setting nobody wrote down still answers with the default the engine registers for it.
47592
47697
 
47593
47698
  To rename a class or a member across the project, use \`script_edit rename\` rather than a text
47594
47699
  replacement: it changes the uses the engine resolves, doc links and what scenes record, and lists
47595
- every other occurrence of the word under \`leftAlone\`, a \`find_children\` string or a word in a
47596
- comment, for you to read. Pass \`preview\` first on a large rename. \`project_settings get\` is on that list too, reading as it does like a look at
47597
- a config file: it starts an engine so that a setting nobody wrote down still answers with the
47598
- default the engine registers for it.
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.
47599
47703
 
47600
47704
  Editing a file while a game is running does not change the running game. \`auto_reload\` is an
47601
47705
  editor plugin and reloads into the editor's own process; the game is a separate process holding
package/build/index.js CHANGED
@@ -26268,6 +26268,7 @@ function wholeWord(name, flags = "gu") {
26268
26268
  function occurrencesOf(source, name, regions = regionsOf(source)) {
26269
26269
  const found = [];
26270
26270
  let index = 0;
26271
+ let code = null;
26271
26272
  for (const match of source.matchAll(wholeWord(name))) {
26272
26273
  const offset = match.index;
26273
26274
  while (index < regions.length - 1 && (regions[index]?.end ?? 0) <= offset) {
@@ -26277,16 +26278,17 @@ function occurrencesOf(source, name, regions = regionsOf(source)) {
26277
26278
  let afterDot = false;
26278
26279
  let declaredAs = null;
26279
26280
  if (kind === "code") {
26281
+ code ??= codeOf(source, regions);
26280
26282
  let back = offset - 1;
26281
- while (back >= 0 && /[\s\\]/.test(source[back] ?? "")) {
26283
+ while (back >= 0 && /[\s\\]/.test(code[back] ?? "")) {
26282
26284
  back -= 1;
26283
26285
  }
26284
- afterDot = source[back] === "." && source[back - 1] !== ".";
26286
+ afterDot = code[back] === "." && code[back - 1] !== ".";
26285
26287
  let wordStart = back + 1;
26286
- while (wordStart > 0 && isIdentifierPart(source[wordStart - 1])) {
26288
+ while (wordStart > 0 && isIdentifierPart(code[wordStart - 1])) {
26287
26289
  wordStart -= 1;
26288
26290
  }
26289
- const word = source.slice(wordStart, back + 1);
26291
+ const word = code.slice(wordStart, back + 1);
26290
26292
  declaredAs = DECLARING.has(word) ? word : null;
26291
26293
  }
26292
26294
  found.push({ offset, kind, afterDot, declaredAs });
@@ -30405,6 +30407,33 @@ function projectTexts(projectPath) {
30405
30407
  visit(projectPath, "");
30406
30408
  return found;
30407
30409
  }
30410
+ function ignoredTexts(projectPath) {
30411
+ const found = [];
30412
+ const visit = (directory, prefix, ignored) => {
30413
+ const under = ignored || steppedOver(directory);
30414
+ for (const entry of readdirSync5(directory, { withFileTypes: true })) {
30415
+ if (skipped(entry.name)) {
30416
+ continue;
30417
+ }
30418
+ const absolute = join15(directory, entry.name);
30419
+ const spelled = `${prefix}${entry.name}`;
30420
+ if (entry.isDirectory()) {
30421
+ visit(absolute, `${spelled}/`, under);
30422
+ continue;
30423
+ }
30424
+ const extension = entry.name.includes(".") ? entry.name.split(".").pop()?.toLowerCase() ?? "" : "";
30425
+ if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
30426
+ continue;
30427
+ }
30428
+ const bytes = readFileSync13(absolute);
30429
+ if (!isBinary(bytes)) {
30430
+ found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
30431
+ }
30432
+ }
30433
+ };
30434
+ visit(projectPath, "", false);
30435
+ return found;
30436
+ }
30408
30437
  function searchProject(projectPath, options) {
30409
30438
  const extensions = options.fileTypes === undefined ? null : new Set(options.fileTypes.map((ext) => ext.replace(/^\./, "").toLowerCase()).filter(Boolean));
30410
30439
  const result = {
@@ -30613,33 +30642,79 @@ var DOC_LINK_KINDS = new Set([
30613
30642
  "annotation",
30614
30643
  "theme_item"
30615
30644
  ]);
30645
+ function docBlockAt(text, offset) {
30646
+ const lineStartOf = (at) => text.lastIndexOf(`
30647
+ `, at - 1) + 1;
30648
+ const contentOf = (lineStart) => {
30649
+ let at = lineStart;
30650
+ while (text[at] === " " || text[at] === "\t") {
30651
+ at += 1;
30652
+ }
30653
+ return text.startsWith("##", at) ? at + 2 : null;
30654
+ };
30655
+ let top = lineStartOf(offset);
30656
+ if (contentOf(top) === null) {
30657
+ return null;
30658
+ }
30659
+ while (top > 0 && contentOf(lineStartOf(top - 1)) !== null) {
30660
+ top = lineStartOf(top - 1);
30661
+ }
30662
+ let joined = "";
30663
+ const from = [];
30664
+ for (let line = top;; ) {
30665
+ const content = contentOf(line);
30666
+ if (content === null) {
30667
+ break;
30668
+ }
30669
+ const nextBreak = text.indexOf(`
30670
+ `, line);
30671
+ let end = nextBreak < 0 ? text.length : nextBreak;
30672
+ if (text[end - 1] === "\r") {
30673
+ end -= 1;
30674
+ }
30675
+ if (joined.length > 0) {
30676
+ joined += " ";
30677
+ from.push(-1);
30678
+ }
30679
+ for (let at = content;at < end; at += 1) {
30680
+ joined += text[at];
30681
+ from.push(at);
30682
+ }
30683
+ if (nextBreak < 0) {
30684
+ break;
30685
+ }
30686
+ line = nextBreak + 1;
30687
+ }
30688
+ return { joined, from };
30689
+ }
30616
30690
  function docLinkAt(text, offset) {
30617
- const lineStart = text.lastIndexOf(`
30618
- `, offset - 1) + 1;
30619
- const nextBreak = text.indexOf(`
30620
- `, offset);
30621
- const lineEnd = nextBreak < 0 ? text.length : nextBreak;
30622
- const open = text.lastIndexOf("[", offset);
30623
- const close = text.indexOf("]", offset);
30624
- if (open < lineStart || close === -1 || close > lineEnd) {
30691
+ const block = docBlockAt(text, offset);
30692
+ const at = block?.from.indexOf(offset) ?? -1;
30693
+ if (block === null || at < 0) {
30625
30694
  return null;
30626
30695
  }
30627
- const inside = text.slice(open + 1, close);
30696
+ const { joined } = block;
30697
+ const open = joined.lastIndexOf("[", at);
30698
+ const close = joined.indexOf("]", at);
30699
+ if (open < 0 || close < 0) {
30700
+ return null;
30701
+ }
30702
+ const inside = joined.slice(open + 1, close);
30628
30703
  if (inside.includes("[") || inside.includes("]")) {
30629
30704
  return null;
30630
30705
  }
30631
- const match = /^(?:([a-z_]+)\s+)?([\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)*)$/u.exec(inside);
30706
+ const match = /^\s*(?:([a-z_]+)\s+)?([\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)*)\s*$/u.exec(inside);
30632
30707
  if (match === null || match[1] !== undefined && !DOC_LINK_KINDS.has(match[1])) {
30633
30708
  return null;
30634
30709
  }
30635
- const parts = (match[2] ?? "").split(".");
30636
- const pathStart = open + 1 + inside.length - (match[2] ?? "").length;
30637
- let at = pathStart;
30710
+ const path = match[2] ?? "";
30711
+ const parts = path.split(".");
30712
+ let partAt = open + 1 + inside.trimEnd().length - path.length;
30638
30713
  for (const [index, part] of parts.entries()) {
30639
- if (at === offset) {
30714
+ if (partAt === at) {
30640
30715
  return { kind: match[1] ?? null, parts, index };
30641
30716
  }
30642
- at += part.length + 1;
30717
+ partAt += part.length + 1;
30643
30718
  }
30644
30719
  return null;
30645
30720
  }
@@ -31046,6 +31121,33 @@ function planMove(args, plan) {
31046
31121
  mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
31047
31122
  };
31048
31123
  }
31124
+ function mentionIgnored(plan, ignored, name, movedFrom) {
31125
+ const mentions = [...plan.mentions];
31126
+ const why = "under a directory holding a .gdignore, which the engine does not load, so it was not changed";
31127
+ for (const file of ignored) {
31128
+ const lines = new Lines(file.text);
31129
+ const offsets = occurrencesOf(file.text, name, [{ kind: "code", start: 0, end: file.text.length }]).map((one) => one.offset);
31130
+ if (movedFrom !== null) {
31131
+ let at = file.text.indexOf(movedFrom);
31132
+ while (at >= 0) {
31133
+ offsets.push(at);
31134
+ at = file.text.indexOf(movedFrom, at + movedFrom.length);
31135
+ }
31136
+ }
31137
+ const seen = new Set;
31138
+ for (const offset of offsets) {
31139
+ const line = lines.positionOf(offset).line + 1;
31140
+ if (!seen.has(line)) {
31141
+ seen.add(line);
31142
+ mentions.push({ file: file.path, line, kind: "ignored", text: lines.lineAt(offset).trim(), why });
31143
+ }
31144
+ }
31145
+ }
31146
+ return {
31147
+ edits: plan.edits,
31148
+ mentions: mentions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
31149
+ };
31150
+ }
31049
31151
  function rewritesOf(plan, texts, move) {
31050
31152
  const byPath = new Map(texts.map((file) => [file.path, file]));
31051
31153
  const byFile = new Map;
@@ -31603,6 +31705,7 @@ async function renameSymbol(request, services) {
31603
31705
  exists: (path) => existsSync14(`${projectPath}/${path.slice("res://".length)}`)
31604
31706
  }, plan);
31605
31707
  }
31708
+ plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? null : declaringPath);
31606
31709
  const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
31607
31710
  const graph = new ClassGraph(scripts, declared);
31608
31711
  const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
@@ -32899,7 +33002,7 @@ var TOOL_SPECS = [
32899
33002
  },
32900
33003
  {
32901
33004
  name: "script_edit",
32902
- 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 or text) 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.",
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.",
32903
33006
  parameters: {
32904
33007
  projectPath: PROJECT_PATH,
32905
33008
  scriptPath: SCRIPT_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdharness",
3
- "version": "1.1.32",
3
+ "version": "1.1.33",
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",