gdharness 1.1.38 → 1.1.40
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 +148 -49
- package/build/index.js +146 -52
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -16541,6 +16541,16 @@ var init_types = __esm(() => {
|
|
|
16541
16541
|
};
|
|
16542
16542
|
});
|
|
16543
16543
|
|
|
16544
|
+
// src/answer-json.ts
|
|
16545
|
+
function answerJson(value) {
|
|
16546
|
+
return JSON.stringify(value, null, 2).replace(SCALAR_ARRAY, (_whole, items) => `[${items.split(/,\n\s+/).join(", ")}]`);
|
|
16547
|
+
}
|
|
16548
|
+
var SCALAR, SCALAR_ARRAY;
|
|
16549
|
+
var init_answer_json = __esm(() => {
|
|
16550
|
+
SCALAR = String.raw`(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)`;
|
|
16551
|
+
SCALAR_ARRAY = new RegExp(String.raw`\[\n\s+(${SCALAR}(?:,\n\s+${SCALAR})*)\n\s*\]`, "g");
|
|
16552
|
+
});
|
|
16553
|
+
|
|
16544
16554
|
// src/resources.ts
|
|
16545
16555
|
import { readFileSync as readFileSync8, realpathSync as realpathSync3 } from "node:fs";
|
|
16546
16556
|
import { extname, resolve as resolve3 } from "node:path";
|
|
@@ -16727,7 +16737,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
16727
16737
|
const parsedProject = parseProjectGodot(rawProject);
|
|
16728
16738
|
return {
|
|
16729
16739
|
mimeType: "application/json",
|
|
16730
|
-
text:
|
|
16740
|
+
text: answerJson(parsedProject)
|
|
16731
16741
|
};
|
|
16732
16742
|
}
|
|
16733
16743
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
@@ -16770,6 +16780,7 @@ function setupResourceHandlers(mcp, getProjectPath) {
|
|
|
16770
16780
|
var STATIC_RESOURCES, RESOURCE_TEMPLATES, RESOURCE_COUNT;
|
|
16771
16781
|
var init_resources = __esm(() => {
|
|
16772
16782
|
init_types();
|
|
16783
|
+
init_answer_json();
|
|
16773
16784
|
init_errors();
|
|
16774
16785
|
init_paths();
|
|
16775
16786
|
STATIC_RESOURCES = [
|
|
@@ -17388,7 +17399,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17388
17399
|
},
|
|
17389
17400
|
{
|
|
17390
17401
|
name: "project_settings",
|
|
17391
|
-
description: "Reads or writes project.godot: settings, autoloads, the main scene, input actions, plugins and audio buses. A write with an editor open on the project is handed to the editor, which takes the settings the write changed from the file (named under editorAdopted), or reloads the bus layout, so it answers the new values and does not save the old ones back over them. editorNote is an editor that could not take the write, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
17402
|
+
description: "Reads or writes project.godot: settings, autoloads, the main scene, input actions, plugins and audio buses. A write with an editor open on the project is handed to the editor, which takes the settings the write changed or names from the file (named under editorAdopted), including a setting the file already held, since the editor can hold another value after the file was put back, or reloads the bus layout, so it answers the new values and does not save the old ones back over them. editorNote is an editor that could not take the write, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
17392
17403
|
parameters: {
|
|
17393
17404
|
projectPath: PROJECT_PATH,
|
|
17394
17405
|
setting: { type: "string", description: 'Setting path, such as "display/window/size/viewport_width".' },
|
|
@@ -17758,7 +17769,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17758
17769
|
},
|
|
17759
17770
|
{
|
|
17760
17771
|
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. 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 string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. 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.",
|
|
17772
|
+
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 string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. When those two grouped lists run past 300 lines, they are written with each line's text to a file under the project's .godot directory instead, of which the newest ten are kept, and leftAloneDetail names the file and counts what is in it. 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
17773
|
parameters: {
|
|
17763
17774
|
projectPath: PROJECT_PATH,
|
|
17764
17775
|
scriptPath: SCRIPT_PATH,
|
|
@@ -34666,7 +34677,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
34666
34677
|
}
|
|
34667
34678
|
const result = await client.setBreakpoint(safeArgs.scriptPath, safeArgs.line);
|
|
34668
34679
|
return {
|
|
34669
|
-
content: [{ type: "text", text:
|
|
34680
|
+
content: [{ type: "text", text: answerJson(result) }]
|
|
34670
34681
|
};
|
|
34671
34682
|
}
|
|
34672
34683
|
case "dap_remove_breakpoint": {
|
|
@@ -34675,7 +34686,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
34675
34686
|
}
|
|
34676
34687
|
const result = await client.removeBreakpoint(safeArgs.scriptPath, safeArgs.line);
|
|
34677
34688
|
return {
|
|
34678
|
-
content: [{ type: "text", text:
|
|
34689
|
+
content: [{ type: "text", text: answerJson(result) }]
|
|
34679
34690
|
};
|
|
34680
34691
|
}
|
|
34681
34692
|
case "dap_continue": {
|
|
@@ -34690,12 +34701,12 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
34690
34701
|
heldAgain,
|
|
34691
34702
|
note: `The game had not stopped again ${client.stepPatienceMs / 1000}s after the step: the step is still running, it went on without stopping anywhere, or the game was not held when it was asked. debug_state stack answers once it stops.`
|
|
34692
34703
|
};
|
|
34693
|
-
return { content: [{ type: "text", text:
|
|
34704
|
+
return { content: [{ type: "text", text: answerJson(answer) }] };
|
|
34694
34705
|
}
|
|
34695
34706
|
case "dap_get_stack_trace": {
|
|
34696
34707
|
const stack = await client.getStackTrace();
|
|
34697
34708
|
return {
|
|
34698
|
-
content: [{ type: "text", text:
|
|
34709
|
+
content: [{ type: "text", text: answerJson(stack) }]
|
|
34699
34710
|
};
|
|
34700
34711
|
}
|
|
34701
34712
|
case "dap_get_variables": {
|
|
@@ -34708,7 +34719,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
34708
34719
|
note: `The values of ${missing.join(", ")} did not arrive from the game within ${client.scopesPatienceMs / 1000}s, so they are unknown rather than empty. Ask again.`
|
|
34709
34720
|
};
|
|
34710
34721
|
return {
|
|
34711
|
-
content: [{ type: "text", text:
|
|
34722
|
+
content: [{ type: "text", text: answerJson(answer) }]
|
|
34712
34723
|
};
|
|
34713
34724
|
}
|
|
34714
34725
|
default:
|
|
@@ -34727,6 +34738,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
34727
34738
|
}
|
|
34728
34739
|
var DEFAULT_DAP_PORT = 6006, DAP_REQUEST_TIMEOUT_MS = 1e4, SCOPES_TIMEOUT_MS = 20000, STEP_LANDS_WITHIN_MS = 1e4, VARIABLES_POLL_TIMEOUT_MS = 2000, ReadRefusal;
|
|
34729
34740
|
var init_dap_client = __esm(() => {
|
|
34741
|
+
init_answer_json();
|
|
34730
34742
|
init_errors();
|
|
34731
34743
|
init_framing();
|
|
34732
34744
|
init_ports();
|
|
@@ -39341,7 +39353,7 @@ function asToolResponse(payload) {
|
|
|
39341
39353
|
content: [
|
|
39342
39354
|
{
|
|
39343
39355
|
type: "text",
|
|
39344
|
-
text:
|
|
39356
|
+
text: answerJson(payload)
|
|
39345
39357
|
}
|
|
39346
39358
|
]
|
|
39347
39359
|
};
|
|
@@ -39438,6 +39450,7 @@ async function handleLSPTool(client, toolName, args) {
|
|
|
39438
39450
|
}
|
|
39439
39451
|
var DEFAULT_LSP_PORT = 6005, DIAGNOSTICS_TIMEOUT_MS = 5000, REQUEST_TIMEOUT_MS2 = 1e4, REFERENCES_TIMEOUT_MS = 180000, LSPTimeout, ArgumentRefusal, AnotherProjectsServer;
|
|
39440
39452
|
var init_lsp_client = __esm(() => {
|
|
39453
|
+
init_answer_json();
|
|
39441
39454
|
init_errors();
|
|
39442
39455
|
init_framing();
|
|
39443
39456
|
init_paths();
|
|
@@ -40074,7 +40087,14 @@ class PlanBuilder {
|
|
|
40074
40087
|
}
|
|
40075
40088
|
function isWholeString(text, offset, name) {
|
|
40076
40089
|
const before = text[offset - 1];
|
|
40077
|
-
|
|
40090
|
+
if (before !== '"' && before !== "'" || text[offset + name.length] !== before) {
|
|
40091
|
+
return false;
|
|
40092
|
+
}
|
|
40093
|
+
let after = offset + name.length + 1;
|
|
40094
|
+
while (text[after] === " " || text[after] === "\t") {
|
|
40095
|
+
after += 1;
|
|
40096
|
+
}
|
|
40097
|
+
return text[after] !== ":";
|
|
40078
40098
|
}
|
|
40079
40099
|
function declaresItsOwn(script, name, except) {
|
|
40080
40100
|
return script.occurrences(name).some((occurrence) => occurrence.kind === "code" && occurrence.offset !== except && occurrence.declaredAs !== null && occurrence.declaredAs !== "class_name");
|
|
@@ -40158,7 +40178,7 @@ function planMemberRename(args) {
|
|
|
40158
40178
|
} else if (occurrence.kind === "doc" && docLinkAt(script.text, one.offset) !== null) {
|
|
40159
40179
|
plan.edit(one.file, one.offset, "doc link");
|
|
40160
40180
|
} else {
|
|
40161
|
-
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this to the ${kind === "func" ? "method" : "member"},
|
|
40181
|
+
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this word to the ${kind === "func" ? "method" : "member"}, but it is inside ${occurrence.kind === "string" ? "a string" : occurrence.kind === "nodePath" ? "a node path" : "a comment"}, which no rename changes: read it, and change the word by hand if it names the ${kind === "func" ? "method" : "member"}`);
|
|
40162
40182
|
}
|
|
40163
40183
|
}
|
|
40164
40184
|
for (const script of scripts.values()) {
|
|
@@ -40536,7 +40556,7 @@ function applyRewrites(rewrites) {
|
|
|
40536
40556
|
throw error;
|
|
40537
40557
|
}
|
|
40538
40558
|
}
|
|
40539
|
-
var DOC_LINK_KINDS, DOC_KIND, WHOLE_CLASS_NAME = "the whole string is the class's name, as find_children's type, a comparison with get_global_name() or a list of accepted type names takes it, and it was not changed: if it names this class, it no longer matches anything after the rename, and no compile says so", WHOLE_MEMBER_NAME = "the whole string is the member's name, as call, connect, has_method, get or
|
|
40559
|
+
var DOC_LINK_KINDS, DOC_KIND, WHOLE_CLASS_NAME = "the whole string is the class's name, as find_children's type, a comparison with get_global_name() or a list of accepted type names takes it, and it was not changed: if it names this class, it no longer matches anything after the rename, and no compile says so", WHOLE_MEMBER_NAME = "the whole string is the member's name, as call, connect, has_method, get, set or a subscript on an object take it, and it was not changed: if it names this member, it no longer finds it after the rename, and no compile says so", NOT_INHERITED = "no class in this file inherits the member, so a bare name here is that class's own local, parameter or member, or a global", RESOLVED_ELSEWHERE = "the language server resolved this to another declaration of the name";
|
|
40540
40560
|
var init_rename = __esm(() => {
|
|
40541
40561
|
init_gdscript_source();
|
|
40542
40562
|
DOC_LINK_KINDS = new Set([
|
|
@@ -40560,7 +40580,7 @@ var init_rename = __esm(() => {
|
|
|
40560
40580
|
});
|
|
40561
40581
|
|
|
40562
40582
|
// src/rename-symbol.ts
|
|
40563
|
-
import { existsSync as existsSync18, realpathSync as realpathSync5 } from "node:fs";
|
|
40583
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readdirSync as readdirSync8, realpathSync as realpathSync5, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
|
|
40564
40584
|
import { basename as basename5, dirname as dirname15, join as join21, relative as relative4, resolve as resolve6 } from "node:path";
|
|
40565
40585
|
function resourcePathOf(projectPath, absolute) {
|
|
40566
40586
|
const inside = relative4(onDiskSpelling(projectPath), onDiskSpelling(absolute));
|
|
@@ -40818,6 +40838,7 @@ async function renameSymbol(request, services) {
|
|
|
40818
40838
|
moved: moveTo === null ? null : { from: declaringPath, to: moveTo },
|
|
40819
40839
|
scriptsInOrder,
|
|
40820
40840
|
rewrites,
|
|
40841
|
+
detail: left.detail,
|
|
40821
40842
|
report: {
|
|
40822
40843
|
renamed: { what, from: symbol, to: newName, declaredIn: declaringPath, resolvedBy },
|
|
40823
40844
|
...took === null ? {} : { languageServer: took },
|
|
@@ -40930,6 +40951,10 @@ function leftAloneReport(mentions) {
|
|
|
40930
40951
|
lines.push(line);
|
|
40931
40952
|
}
|
|
40932
40953
|
};
|
|
40954
|
+
const textOf = new Map;
|
|
40955
|
+
for (const mention of mentions) {
|
|
40956
|
+
textOf.set(`${mention.file}:${String(mention.line)}`, mention.text);
|
|
40957
|
+
}
|
|
40933
40958
|
for (const mention of mentions) {
|
|
40934
40959
|
if (PROSE_KINDS.has(mention.kind) && mention.why === undefined) {
|
|
40935
40960
|
const key = `${mention.file}
|
|
@@ -40951,20 +40976,64 @@ ${mention.kind}`;
|
|
|
40951
40976
|
}
|
|
40952
40977
|
}
|
|
40953
40978
|
const loudFirst = (mention) => mention.kind === "string" && mention.why !== undefined ? 0 : 1;
|
|
40979
|
+
const leftAlone = full.sort((a, b) => loudFirst(a) - loudFirst(b));
|
|
40980
|
+
const inProse = [...prose.values()];
|
|
40981
|
+
const otherSymbols = [...others.entries()].map(([why, files]) => ({
|
|
40982
|
+
why,
|
|
40983
|
+
files: [...files.entries()].map(([file, lines]) => ({ file, lines }))
|
|
40984
|
+
}));
|
|
40985
|
+
const grouped = inProse.reduce((sum, group) => sum + group.lines.length, 0) + otherSymbols.reduce((sum, reason) => sum + reason.files.reduce((n, one) => n + one.lines.length, 0), 0);
|
|
40986
|
+
if (grouped <= LEFT_ALONE_ANSWER_LINES) {
|
|
40987
|
+
return {
|
|
40988
|
+
lists: {
|
|
40989
|
+
leftAlone,
|
|
40990
|
+
...inProse.length > 0 ? { leftAloneInProse: inProse } : {},
|
|
40991
|
+
...otherSymbols.length > 0 ? { leftAloneOtherSymbols: otherSymbols } : {}
|
|
40992
|
+
},
|
|
40993
|
+
counts,
|
|
40994
|
+
detail: null
|
|
40995
|
+
};
|
|
40996
|
+
}
|
|
40997
|
+
const withText = (file, lines) => lines.map((line) => ({ line, text: textOf.get(`${file}:${String(line)}`) ?? "" }));
|
|
40954
40998
|
return {
|
|
40955
40999
|
lists: {
|
|
40956
|
-
leftAlone
|
|
40957
|
-
|
|
40958
|
-
|
|
40959
|
-
|
|
40960
|
-
why,
|
|
40961
|
-
files:
|
|
41000
|
+
leftAlone,
|
|
41001
|
+
leftAloneDetail: {
|
|
41002
|
+
inProse: { files: new Set(inProse.map((group) => group.file)).size, occurrences: counts.inProse },
|
|
41003
|
+
otherSymbols: otherSymbols.map((reason) => ({
|
|
41004
|
+
why: reason.why,
|
|
41005
|
+
files: reason.files.length,
|
|
41006
|
+
occurrences: reason.files.reduce((n, one) => n + one.lines.length, 0)
|
|
40962
41007
|
}))
|
|
40963
|
-
}
|
|
41008
|
+
}
|
|
40964
41009
|
},
|
|
40965
|
-
counts
|
|
41010
|
+
counts,
|
|
41011
|
+
detail: {
|
|
41012
|
+
leftAloneInProse: inProse.map((group) => ({
|
|
41013
|
+
file: group.file,
|
|
41014
|
+
kind: group.kind,
|
|
41015
|
+
lines: withText(group.file, group.lines)
|
|
41016
|
+
})),
|
|
41017
|
+
leftAloneOtherSymbols: otherSymbols.map((reason) => ({
|
|
41018
|
+
why: reason.why,
|
|
41019
|
+
files: reason.files.map((one) => ({ file: one.file, lines: withText(one.file, one.lines) }))
|
|
41020
|
+
}))
|
|
41021
|
+
}
|
|
40966
41022
|
};
|
|
40967
41023
|
}
|
|
41024
|
+
function writeLeftAloneDetail(projectPath, symbol, detail) {
|
|
41025
|
+
const directory = join21(projectPath, ".godot", "gdharness-renames");
|
|
41026
|
+
mkdirSync11(directory, { recursive: true });
|
|
41027
|
+
detailWrites += 1;
|
|
41028
|
+
const path = join21(directory, `${String(Date.now())}-${String(detailWrites).padStart(6, "0")}-${String(process.pid)}-${symbol}.json`);
|
|
41029
|
+
writeFileSync13(path, `${JSON.stringify(detail, null, 2)}
|
|
41030
|
+
`, "utf8");
|
|
41031
|
+
const kept = readdirSync8(directory).filter((name) => name.endsWith(".json")).sort().reverse();
|
|
41032
|
+
for (const old of kept.slice(10)) {
|
|
41033
|
+
rmSync9(join21(directory, old), { force: true });
|
|
41034
|
+
}
|
|
41035
|
+
return path;
|
|
41036
|
+
}
|
|
40968
41037
|
function summaryOf(edits, mentions, rewrites, left) {
|
|
40969
41038
|
const count = (values) => {
|
|
40970
41039
|
const counted = {};
|
|
@@ -40981,7 +41050,7 @@ function summaryOf(edits, mentions, rewrites, left) {
|
|
|
40981
41050
|
leftAloneByKind: count(mentions.map((mention) => mention.kind))
|
|
40982
41051
|
};
|
|
40983
41052
|
}
|
|
40984
|
-
var WHAT, PROSE_KINDS;
|
|
41053
|
+
var WHAT, LEFT_ALONE_ANSWER_LINES = 300, detailWrites = 0, PROSE_KINDS;
|
|
40985
41054
|
var init_rename_symbol = __esm(() => {
|
|
40986
41055
|
init_gdscript_source();
|
|
40987
41056
|
init_lsp_client();
|
|
@@ -41001,7 +41070,7 @@ var init_rename_symbol = __esm(() => {
|
|
|
41001
41070
|
});
|
|
41002
41071
|
|
|
41003
41072
|
// src/restart-note.ts
|
|
41004
|
-
import { mkdirSync as
|
|
41073
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync19, rmSync as rmSync10, writeFileSync as writeFileSync14 } from "node:fs";
|
|
41005
41074
|
import { dirname as dirname16, join as join22 } from "node:path";
|
|
41006
41075
|
function restartNotePath(projectPath) {
|
|
41007
41076
|
return join22(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -41009,8 +41078,8 @@ function restartNotePath(projectPath) {
|
|
|
41009
41078
|
function noteRestartBegun(note) {
|
|
41010
41079
|
const path = restartNotePath(note.projectPath);
|
|
41011
41080
|
try {
|
|
41012
|
-
|
|
41013
|
-
|
|
41081
|
+
mkdirSync12(dirname16(path), { recursive: true });
|
|
41082
|
+
writeFileSync14(path, `${JSON.stringify(note, null, 2)}
|
|
41014
41083
|
`, "utf8");
|
|
41015
41084
|
} catch (error) {
|
|
41016
41085
|
console.error(`[SERVER] Could not record the restart at ${path}: ${errorMessage(error)}`);
|
|
@@ -41033,7 +41102,7 @@ function restartOwed(projectPath) {
|
|
|
41033
41102
|
}
|
|
41034
41103
|
function restartSettled(projectPath) {
|
|
41035
41104
|
try {
|
|
41036
|
-
|
|
41105
|
+
rmSync10(restartNotePath(projectPath), { force: true });
|
|
41037
41106
|
} catch (error) {
|
|
41038
41107
|
console.error(`[SERVER] Could not clear the restart note: ${errorMessage(error)}`);
|
|
41039
41108
|
}
|
|
@@ -41046,14 +41115,14 @@ var init_restart_note = __esm(() => {
|
|
|
41046
41115
|
import { execFile as execFile4 } from "node:child_process";
|
|
41047
41116
|
import { createHash as createHash4 } from "node:crypto";
|
|
41048
41117
|
import {
|
|
41049
|
-
mkdirSync as
|
|
41118
|
+
mkdirSync as mkdirSync13,
|
|
41050
41119
|
openSync as openSync2,
|
|
41051
|
-
readdirSync as
|
|
41120
|
+
readdirSync as readdirSync9,
|
|
41052
41121
|
readFileSync as readFileSync20,
|
|
41053
41122
|
realpathSync as realpathSync6,
|
|
41054
|
-
rmSync as
|
|
41123
|
+
rmSync as rmSync11,
|
|
41055
41124
|
statSync as statSync8,
|
|
41056
|
-
writeFileSync as
|
|
41125
|
+
writeFileSync as writeFileSync15
|
|
41057
41126
|
} from "node:fs";
|
|
41058
41127
|
import { basename as basename6, dirname as dirname17, join as join23, resolve as resolve7 } from "node:path";
|
|
41059
41128
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -41085,7 +41154,7 @@ function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
|
41085
41154
|
return join23(directory, "runs", `note-${projectKey(projectPath)}.json`);
|
|
41086
41155
|
}
|
|
41087
41156
|
function openTranscript(startedAt) {
|
|
41088
|
-
|
|
41157
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
41089
41158
|
const path = join23(runsDirectory(), `run-${startedAt}.log`);
|
|
41090
41159
|
return { path, fd: openSync2(path, "a") };
|
|
41091
41160
|
}
|
|
@@ -41096,8 +41165,8 @@ function editorNotePath(projectPath, directory = runtimeDirectory()) {
|
|
|
41096
41165
|
return join23(directory, "runs", `editor-${projectKey(projectPath)}.json`);
|
|
41097
41166
|
}
|
|
41098
41167
|
function writeEditorRunNote(note) {
|
|
41099
|
-
|
|
41100
|
-
|
|
41168
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
41169
|
+
writeFileSync15(editorNotePath(note.projectPath), JSON.stringify(note, null, 2), "utf8");
|
|
41101
41170
|
}
|
|
41102
41171
|
function readEditorRunNote(projectPath) {
|
|
41103
41172
|
for (const directory of runtimeDirectories()) {
|
|
@@ -41147,7 +41216,7 @@ function everyRunRecord() {
|
|
|
41147
41216
|
for (const directory of runtimeDirectories()) {
|
|
41148
41217
|
let entries;
|
|
41149
41218
|
try {
|
|
41150
|
-
entries =
|
|
41219
|
+
entries = readdirSync9(join23(directory, "runs"));
|
|
41151
41220
|
} catch {
|
|
41152
41221
|
continue;
|
|
41153
41222
|
}
|
|
@@ -41366,7 +41435,7 @@ function clearRunRecord(projectPath) {
|
|
|
41366
41435
|
const ours = sharedRecord !== null && sharedRecord.projectPath !== "" && isSameDirectory(sharedRecord.projectPath, projectPath);
|
|
41367
41436
|
for (const path of [runRecordPath(projectPath, directory), ...ours ? [shared] : []]) {
|
|
41368
41437
|
try {
|
|
41369
|
-
|
|
41438
|
+
rmSync11(path, { force: true });
|
|
41370
41439
|
} catch {}
|
|
41371
41440
|
}
|
|
41372
41441
|
}
|
|
@@ -41383,7 +41452,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
41383
41452
|
const kept = new Set(everyRunRecord().map((record) => record.transcript));
|
|
41384
41453
|
let entries;
|
|
41385
41454
|
try {
|
|
41386
|
-
entries =
|
|
41455
|
+
entries = readdirSync9(directory);
|
|
41387
41456
|
} catch {
|
|
41388
41457
|
return;
|
|
41389
41458
|
}
|
|
@@ -41396,7 +41465,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
41396
41465
|
continue;
|
|
41397
41466
|
}
|
|
41398
41467
|
try {
|
|
41399
|
-
|
|
41468
|
+
rmSync11(path);
|
|
41400
41469
|
} catch {}
|
|
41401
41470
|
}
|
|
41402
41471
|
}
|
|
@@ -41420,9 +41489,9 @@ import {
|
|
|
41420
41489
|
copyFileSync,
|
|
41421
41490
|
existsSync as existsSync19,
|
|
41422
41491
|
fstatSync,
|
|
41423
|
-
mkdirSync as
|
|
41492
|
+
mkdirSync as mkdirSync14,
|
|
41424
41493
|
openSync as openSync3,
|
|
41425
|
-
readdirSync as
|
|
41494
|
+
readdirSync as readdirSync10,
|
|
41426
41495
|
readFileSync as readFileSync21,
|
|
41427
41496
|
readSync as readSync2,
|
|
41428
41497
|
rmdirSync as rmdirSync2,
|
|
@@ -41876,7 +41945,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
41876
41945
|
...problems.omitted === 0 ? {} : { entriesOmitted: problems.omitted }
|
|
41877
41946
|
};
|
|
41878
41947
|
if (verdict.exported) {
|
|
41879
|
-
return { content: [{ type: "text", text:
|
|
41948
|
+
return { content: [{ type: "text", text: answerJson(verdict) }] };
|
|
41880
41949
|
}
|
|
41881
41950
|
const stale = !written && after !== null ? ` The ${asked.outputPath} there is from before this export, which did not write it.` : "";
|
|
41882
41951
|
const why = ending.exitSignal === null ? stale : ` The engine was ${howItEnded(ending)}, so it has no exit code.${stale}`;
|
|
@@ -41886,7 +41955,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
41886
41955
|
type: "text",
|
|
41887
41956
|
text: `Export with preset '${asked.preset}' did not produce ${asked.outputPath}.${why}`
|
|
41888
41957
|
},
|
|
41889
|
-
{ type: "text", text:
|
|
41958
|
+
{ type: "text", text: answerJson(verdict) }
|
|
41890
41959
|
],
|
|
41891
41960
|
isError: true
|
|
41892
41961
|
};
|
|
@@ -41908,6 +41977,25 @@ function changedSettings(before, after) {
|
|
|
41908
41977
|
const names = new Set([...before.keys(), ...after.keys()]);
|
|
41909
41978
|
return [...names].filter((name) => JSON.stringify(before.get(name)) !== JSON.stringify(after.get(name))).sort();
|
|
41910
41979
|
}
|
|
41980
|
+
function settingsNamedBy(op, args) {
|
|
41981
|
+
const text = (key) => readString(args, key) ?? "";
|
|
41982
|
+
switch (op) {
|
|
41983
|
+
case "set":
|
|
41984
|
+
return text("setting") === "" ? [] : [text("setting")];
|
|
41985
|
+
case "add_autoload":
|
|
41986
|
+
case "remove_autoload":
|
|
41987
|
+
return text("name") === "" ? [] : [`autoload/${text("name")}`];
|
|
41988
|
+
case "set_main_scene":
|
|
41989
|
+
return ["application/run/main_scene"];
|
|
41990
|
+
case "add_input_action":
|
|
41991
|
+
return text("actionName") === "" ? [] : [`input/${text("actionName")}`];
|
|
41992
|
+
case "enable_plugin":
|
|
41993
|
+
case "disable_plugin":
|
|
41994
|
+
return ["editor_plugins/enabled"];
|
|
41995
|
+
default:
|
|
41996
|
+
return [];
|
|
41997
|
+
}
|
|
41998
|
+
}
|
|
41911
41999
|
function scriptErrorsNote(errors) {
|
|
41912
42000
|
const causes = new Map;
|
|
41913
42001
|
for (const error of errors) {
|
|
@@ -41990,7 +42078,7 @@ function elsewhereIn(projectPath, asked) {
|
|
|
41990
42078
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
41991
42079
|
let near = [];
|
|
41992
42080
|
try {
|
|
41993
|
-
near =
|
|
42081
|
+
near = readdirSync10(projectPath, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.toLowerCase() !== root).map((entry) => entry.name).filter((name) => name.toLowerCase().startsWith("test") || root.startsWith(name.toLowerCase()));
|
|
41994
42082
|
} catch {
|
|
41995
42083
|
return "";
|
|
41996
42084
|
}
|
|
@@ -42092,7 +42180,7 @@ class GodotServer {
|
|
|
42092
42180
|
return response;
|
|
42093
42181
|
}
|
|
42094
42182
|
jsonTextResponse(payload) {
|
|
42095
|
-
return { content: [{ type: "text", text:
|
|
42183
|
+
return { content: [{ type: "text", text: answerJson(payload) }] };
|
|
42096
42184
|
}
|
|
42097
42185
|
async run() {
|
|
42098
42186
|
const located = await this.locator.find();
|
|
@@ -42425,7 +42513,7 @@ class GodotServer {
|
|
|
42425
42513
|
saying(answer, block) {
|
|
42426
42514
|
return {
|
|
42427
42515
|
...answer,
|
|
42428
|
-
content: [...answer.content, { type: "text", text:
|
|
42516
|
+
content: [...answer.content, { type: "text", text: answerJson(block) }]
|
|
42429
42517
|
};
|
|
42430
42518
|
}
|
|
42431
42519
|
projectHasMovedOn() {
|
|
@@ -43130,7 +43218,8 @@ class GodotServer {
|
|
|
43130
43218
|
if (AUDIO_BUS_OPS.has(op)) {
|
|
43131
43219
|
return this.jsonTextResponse({ ...answer, ...await this.editorTakes("adopt_audio_bus_layout", {}) });
|
|
43132
43220
|
}
|
|
43133
|
-
const
|
|
43221
|
+
const diffed = changedSettings(before, this.settingKeysOf(projectPath));
|
|
43222
|
+
const changed = diffed === null ? null : [...new Set([...diffed, ...settingsNamedBy(op, args)])].sort();
|
|
43134
43223
|
if (changed === null) {
|
|
43135
43224
|
return this.jsonTextResponse({
|
|
43136
43225
|
...answer,
|
|
@@ -43398,7 +43487,7 @@ class GodotServer {
|
|
|
43398
43487
|
if (!outcome.ok) {
|
|
43399
43488
|
const response = this.createErrorResponse(outcome.message);
|
|
43400
43489
|
if (Object.keys(extras).length > 0) {
|
|
43401
|
-
response.content.push({ type: "text", text:
|
|
43490
|
+
response.content.push({ type: "text", text: answerJson(extras) });
|
|
43402
43491
|
}
|
|
43403
43492
|
return response;
|
|
43404
43493
|
}
|
|
@@ -43476,7 +43565,7 @@ class GodotServer {
|
|
|
43476
43565
|
}
|
|
43477
43566
|
const folder = dirname18(output.absolutePath);
|
|
43478
43567
|
try {
|
|
43479
|
-
|
|
43568
|
+
mkdirSync14(folder, { recursive: true });
|
|
43480
43569
|
} catch (error) {
|
|
43481
43570
|
return this.createErrorResponse(`Cannot create ${dirname18(output.relativePath)} to export into: ${errorMessage(error)}`);
|
|
43482
43571
|
}
|
|
@@ -43587,7 +43676,7 @@ class GodotServer {
|
|
|
43587
43676
|
let report = null;
|
|
43588
43677
|
let reportProblem = null;
|
|
43589
43678
|
try {
|
|
43590
|
-
const written = existsSync19(reportsDir) ?
|
|
43679
|
+
const written = existsSync19(reportsDir) ? readdirSync10(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
43591
43680
|
const newest = written.at(-1);
|
|
43592
43681
|
if (newest !== undefined) {
|
|
43593
43682
|
report = parseJUnit(readFileSync21(join24(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -46098,6 +46187,15 @@ class GodotServer {
|
|
|
46098
46187
|
const said = outcome.conflicts === undefined ? "" : ` ${outcome.conflicts.join("; ")}.`;
|
|
46099
46188
|
return this.createErrorResponse(`${outcome.reason}${said}`, outcome.advice ?? []);
|
|
46100
46189
|
}
|
|
46190
|
+
if (outcome.detail !== null) {
|
|
46191
|
+
const file = writeLeftAloneDetail(projectPath, symbol, outcome.detail);
|
|
46192
|
+
const folded = asParams(outcome.report["leftAloneDetail"]);
|
|
46193
|
+
outcome.report["leftAloneDetail"] = {
|
|
46194
|
+
file,
|
|
46195
|
+
note: `Too many lines were left alone to list here, and none of them is a use: every comment, documentation line, string and text file line that only shares the word, and every other symbol of the same name, is in ${file} with its text. The newest ten of these files are kept and older ones removed as new ones are written.`,
|
|
46196
|
+
...folded
|
|
46197
|
+
};
|
|
46198
|
+
}
|
|
46101
46199
|
if (readBoolean(args, "preview") === true) {
|
|
46102
46200
|
return this.jsonTextResponse({ preview: true, ...outcome.report });
|
|
46103
46201
|
}
|
|
@@ -46561,6 +46659,7 @@ var init_server3 = __esm(() => {
|
|
|
46561
46659
|
init_stdio2();
|
|
46562
46660
|
init_types();
|
|
46563
46661
|
init_alive();
|
|
46662
|
+
init_answer_json();
|
|
46564
46663
|
init_boot_note();
|
|
46565
46664
|
init_breakpoint_note();
|
|
46566
46665
|
init_bridge_announce();
|
|
@@ -47831,7 +47930,7 @@ every other occurrence of the word for you to read: a string that is the name wh
|
|
|
47831
47930
|
\`find_children\` type, first under \`leftAlone\` since nothing compiles it, a file under a
|
|
47832
47931
|
\`.gdignore\` directory there too, a word in a comment, a doc line, a string or a text file by
|
|
47833
47932
|
line under \`leftAloneInProse\`, and a local or another class's member of the same name by line
|
|
47834
|
-
under \`leftAloneOtherSymbols
|
|
47933
|
+
under \`leftAloneOtherSymbols\`; a common name's lines go to the file \`leftAloneDetail\` names. Pass \`preview\` first on a large rename. If the answer has \`ok: false\`
|
|
47835
47934
|
beside \`written: true\`, the files were changed and a script did not compile afterwards.
|
|
47836
47935
|
|
|
47837
47936
|
Editing a file while a game is running does not change the running game. \`auto_reload\` is an
|
package/build/index.js
CHANGED
|
@@ -10238,9 +10238,9 @@ import {
|
|
|
10238
10238
|
copyFileSync,
|
|
10239
10239
|
existsSync as existsSync16,
|
|
10240
10240
|
fstatSync,
|
|
10241
|
-
mkdirSync as
|
|
10241
|
+
mkdirSync as mkdirSync12,
|
|
10242
10242
|
openSync as openSync3,
|
|
10243
|
-
readdirSync as
|
|
10243
|
+
readdirSync as readdirSync9,
|
|
10244
10244
|
readFileSync as readFileSync19,
|
|
10245
10245
|
readSync as readSync2,
|
|
10246
10246
|
rmdirSync as rmdirSync2,
|
|
@@ -24828,6 +24828,13 @@ function alive(pid) {
|
|
|
24828
24828
|
}
|
|
24829
24829
|
}
|
|
24830
24830
|
|
|
24831
|
+
// src/answer-json.ts
|
|
24832
|
+
var SCALAR = String.raw`(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)`;
|
|
24833
|
+
var SCALAR_ARRAY = new RegExp(String.raw`\[\n\s+(${SCALAR}(?:,\n\s+${SCALAR})*)\n\s*\]`, "g");
|
|
24834
|
+
function answerJson(value) {
|
|
24835
|
+
return JSON.stringify(value, null, 2).replace(SCALAR_ARRAY, (_whole, items) => `[${items.split(/,\n\s+/).join(", ")}]`);
|
|
24836
|
+
}
|
|
24837
|
+
|
|
24831
24838
|
// src/boot-note.ts
|
|
24832
24839
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
24833
24840
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
@@ -27580,7 +27587,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
27580
27587
|
}
|
|
27581
27588
|
const result = await client.setBreakpoint(safeArgs.scriptPath, safeArgs.line);
|
|
27582
27589
|
return {
|
|
27583
|
-
content: [{ type: "text", text:
|
|
27590
|
+
content: [{ type: "text", text: answerJson(result) }]
|
|
27584
27591
|
};
|
|
27585
27592
|
}
|
|
27586
27593
|
case "dap_remove_breakpoint": {
|
|
@@ -27589,7 +27596,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
27589
27596
|
}
|
|
27590
27597
|
const result = await client.removeBreakpoint(safeArgs.scriptPath, safeArgs.line);
|
|
27591
27598
|
return {
|
|
27592
|
-
content: [{ type: "text", text:
|
|
27599
|
+
content: [{ type: "text", text: answerJson(result) }]
|
|
27593
27600
|
};
|
|
27594
27601
|
}
|
|
27595
27602
|
case "dap_continue": {
|
|
@@ -27604,12 +27611,12 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
27604
27611
|
heldAgain,
|
|
27605
27612
|
note: `The game had not stopped again ${client.stepPatienceMs / 1000}s after the step: the step is still running, it went on without stopping anywhere, or the game was not held when it was asked. debug_state stack answers once it stops.`
|
|
27606
27613
|
};
|
|
27607
|
-
return { content: [{ type: "text", text:
|
|
27614
|
+
return { content: [{ type: "text", text: answerJson(answer) }] };
|
|
27608
27615
|
}
|
|
27609
27616
|
case "dap_get_stack_trace": {
|
|
27610
27617
|
const stack = await client.getStackTrace();
|
|
27611
27618
|
return {
|
|
27612
|
-
content: [{ type: "text", text:
|
|
27619
|
+
content: [{ type: "text", text: answerJson(stack) }]
|
|
27613
27620
|
};
|
|
27614
27621
|
}
|
|
27615
27622
|
case "dap_get_variables": {
|
|
@@ -27622,7 +27629,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
27622
27629
|
note: `The values of ${missing.join(", ")} did not arrive from the game within ${client.scopesPatienceMs / 1000}s, so they are unknown rather than empty. Ask again.`
|
|
27623
27630
|
};
|
|
27624
27631
|
return {
|
|
27625
|
-
content: [{ type: "text", text:
|
|
27632
|
+
content: [{ type: "text", text: answerJson(answer) }]
|
|
27626
27633
|
};
|
|
27627
27634
|
}
|
|
27628
27635
|
default:
|
|
@@ -30082,7 +30089,7 @@ function asToolResponse(payload) {
|
|
|
30082
30089
|
content: [
|
|
30083
30090
|
{
|
|
30084
30091
|
type: "text",
|
|
30085
|
-
text:
|
|
30092
|
+
text: answerJson(payload)
|
|
30086
30093
|
}
|
|
30087
30094
|
]
|
|
30088
30095
|
};
|
|
@@ -30798,10 +30805,17 @@ class PlanBuilder {
|
|
|
30798
30805
|
}
|
|
30799
30806
|
function isWholeString(text, offset, name) {
|
|
30800
30807
|
const before = text[offset - 1];
|
|
30801
|
-
|
|
30808
|
+
if (before !== '"' && before !== "'" || text[offset + name.length] !== before) {
|
|
30809
|
+
return false;
|
|
30810
|
+
}
|
|
30811
|
+
let after = offset + name.length + 1;
|
|
30812
|
+
while (text[after] === " " || text[after] === "\t") {
|
|
30813
|
+
after += 1;
|
|
30814
|
+
}
|
|
30815
|
+
return text[after] !== ":";
|
|
30802
30816
|
}
|
|
30803
30817
|
var WHOLE_CLASS_NAME = "the whole string is the class's name, as find_children's type, a comparison with get_global_name() or a list of accepted type names takes it, and it was not changed: if it names this class, it no longer matches anything after the rename, and no compile says so";
|
|
30804
|
-
var WHOLE_MEMBER_NAME = "the whole string is the member's name, as call, connect, has_method, get or
|
|
30818
|
+
var WHOLE_MEMBER_NAME = "the whole string is the member's name, as call, connect, has_method, get, set or a subscript on an object take it, and it was not changed: if it names this member, it no longer finds it after the rename, and no compile says so";
|
|
30805
30819
|
function declaresItsOwn(script, name, except) {
|
|
30806
30820
|
return script.occurrences(name).some((occurrence) => occurrence.kind === "code" && occurrence.offset !== except && occurrence.declaredAs !== null && occurrence.declaredAs !== "class_name");
|
|
30807
30821
|
}
|
|
@@ -30886,7 +30900,7 @@ function planMemberRename(args) {
|
|
|
30886
30900
|
} else if (occurrence.kind === "doc" && docLinkAt(script.text, one.offset) !== null) {
|
|
30887
30901
|
plan.edit(one.file, one.offset, "doc link");
|
|
30888
30902
|
} else {
|
|
30889
|
-
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this to the ${kind === "func" ? "method" : "member"},
|
|
30903
|
+
plan.mention(one.file, script.lines, one.offset, occurrence.kind, `the language server resolved this word to the ${kind === "func" ? "method" : "member"}, but it is inside ${occurrence.kind === "string" ? "a string" : occurrence.kind === "nodePath" ? "a node path" : "a comment"}, which no rename changes: read it, and change the word by hand if it names the ${kind === "func" ? "method" : "member"}`);
|
|
30890
30904
|
}
|
|
30891
30905
|
}
|
|
30892
30906
|
for (const script of scripts.values()) {
|
|
@@ -31266,7 +31280,7 @@ function applyRewrites(rewrites) {
|
|
|
31266
31280
|
}
|
|
31267
31281
|
|
|
31268
31282
|
// src/rename-symbol.ts
|
|
31269
|
-
import { existsSync as existsSync14, realpathSync as realpathSync5 } from "node:fs";
|
|
31283
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync8, readdirSync as readdirSync6, realpathSync as realpathSync5, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
|
|
31270
31284
|
import { basename as basename3, dirname as dirname10, join as join16, relative as relative3, resolve as resolve5 } from "node:path";
|
|
31271
31285
|
|
|
31272
31286
|
// src/resources.ts
|
|
@@ -31484,7 +31498,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
31484
31498
|
const parsedProject = parseProjectGodot(rawProject);
|
|
31485
31499
|
return {
|
|
31486
31500
|
mimeType: "application/json",
|
|
31487
|
-
text:
|
|
31501
|
+
text: answerJson(parsedProject)
|
|
31488
31502
|
};
|
|
31489
31503
|
}
|
|
31490
31504
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
@@ -31791,6 +31805,7 @@ async function renameSymbol(request, services) {
|
|
|
31791
31805
|
moved: moveTo === null ? null : { from: declaringPath, to: moveTo },
|
|
31792
31806
|
scriptsInOrder,
|
|
31793
31807
|
rewrites,
|
|
31808
|
+
detail: left.detail,
|
|
31794
31809
|
report: {
|
|
31795
31810
|
renamed: { what, from: symbol, to: newName, declaredIn: declaringPath, resolvedBy },
|
|
31796
31811
|
...took === null ? {} : { languageServer: took },
|
|
@@ -31903,6 +31918,10 @@ function leftAloneReport(mentions) {
|
|
|
31903
31918
|
lines.push(line);
|
|
31904
31919
|
}
|
|
31905
31920
|
};
|
|
31921
|
+
const textOf = new Map;
|
|
31922
|
+
for (const mention of mentions) {
|
|
31923
|
+
textOf.set(`${mention.file}:${String(mention.line)}`, mention.text);
|
|
31924
|
+
}
|
|
31906
31925
|
for (const mention of mentions) {
|
|
31907
31926
|
if (PROSE_KINDS.has(mention.kind) && mention.why === undefined) {
|
|
31908
31927
|
const key = `${mention.file}
|
|
@@ -31924,20 +31943,66 @@ ${mention.kind}`;
|
|
|
31924
31943
|
}
|
|
31925
31944
|
}
|
|
31926
31945
|
const loudFirst = (mention) => mention.kind === "string" && mention.why !== undefined ? 0 : 1;
|
|
31946
|
+
const leftAlone = full.sort((a, b) => loudFirst(a) - loudFirst(b));
|
|
31947
|
+
const inProse = [...prose.values()];
|
|
31948
|
+
const otherSymbols = [...others.entries()].map(([why, files]) => ({
|
|
31949
|
+
why,
|
|
31950
|
+
files: [...files.entries()].map(([file, lines]) => ({ file, lines }))
|
|
31951
|
+
}));
|
|
31952
|
+
const grouped = inProse.reduce((sum, group) => sum + group.lines.length, 0) + otherSymbols.reduce((sum, reason) => sum + reason.files.reduce((n, one) => n + one.lines.length, 0), 0);
|
|
31953
|
+
if (grouped <= LEFT_ALONE_ANSWER_LINES) {
|
|
31954
|
+
return {
|
|
31955
|
+
lists: {
|
|
31956
|
+
leftAlone,
|
|
31957
|
+
...inProse.length > 0 ? { leftAloneInProse: inProse } : {},
|
|
31958
|
+
...otherSymbols.length > 0 ? { leftAloneOtherSymbols: otherSymbols } : {}
|
|
31959
|
+
},
|
|
31960
|
+
counts,
|
|
31961
|
+
detail: null
|
|
31962
|
+
};
|
|
31963
|
+
}
|
|
31964
|
+
const withText = (file, lines) => lines.map((line) => ({ line, text: textOf.get(`${file}:${String(line)}`) ?? "" }));
|
|
31927
31965
|
return {
|
|
31928
31966
|
lists: {
|
|
31929
|
-
leftAlone
|
|
31930
|
-
|
|
31931
|
-
|
|
31932
|
-
|
|
31933
|
-
why,
|
|
31934
|
-
files:
|
|
31967
|
+
leftAlone,
|
|
31968
|
+
leftAloneDetail: {
|
|
31969
|
+
inProse: { files: new Set(inProse.map((group) => group.file)).size, occurrences: counts.inProse },
|
|
31970
|
+
otherSymbols: otherSymbols.map((reason) => ({
|
|
31971
|
+
why: reason.why,
|
|
31972
|
+
files: reason.files.length,
|
|
31973
|
+
occurrences: reason.files.reduce((n, one) => n + one.lines.length, 0)
|
|
31935
31974
|
}))
|
|
31936
|
-
}
|
|
31975
|
+
}
|
|
31937
31976
|
},
|
|
31938
|
-
counts
|
|
31977
|
+
counts,
|
|
31978
|
+
detail: {
|
|
31979
|
+
leftAloneInProse: inProse.map((group) => ({
|
|
31980
|
+
file: group.file,
|
|
31981
|
+
kind: group.kind,
|
|
31982
|
+
lines: withText(group.file, group.lines)
|
|
31983
|
+
})),
|
|
31984
|
+
leftAloneOtherSymbols: otherSymbols.map((reason) => ({
|
|
31985
|
+
why: reason.why,
|
|
31986
|
+
files: reason.files.map((one) => ({ file: one.file, lines: withText(one.file, one.lines) }))
|
|
31987
|
+
}))
|
|
31988
|
+
}
|
|
31939
31989
|
};
|
|
31940
31990
|
}
|
|
31991
|
+
var LEFT_ALONE_ANSWER_LINES = 300;
|
|
31992
|
+
var detailWrites = 0;
|
|
31993
|
+
function writeLeftAloneDetail(projectPath, symbol, detail) {
|
|
31994
|
+
const directory = join16(projectPath, ".godot", "gdharness-renames");
|
|
31995
|
+
mkdirSync8(directory, { recursive: true });
|
|
31996
|
+
detailWrites += 1;
|
|
31997
|
+
const path = join16(directory, `${String(Date.now())}-${String(detailWrites).padStart(6, "0")}-${String(process.pid)}-${symbol}.json`);
|
|
31998
|
+
writeFileSync10(path, `${JSON.stringify(detail, null, 2)}
|
|
31999
|
+
`, "utf8");
|
|
32000
|
+
const kept = readdirSync6(directory).filter((name) => name.endsWith(".json")).sort().reverse();
|
|
32001
|
+
for (const old of kept.slice(10)) {
|
|
32002
|
+
rmSync6(join16(directory, old), { force: true });
|
|
32003
|
+
}
|
|
32004
|
+
return path;
|
|
32005
|
+
}
|
|
31941
32006
|
var PROSE_KINDS = new Set(["comment", "doc", "string", "text"]);
|
|
31942
32007
|
function summaryOf(edits, mentions, rewrites, left) {
|
|
31943
32008
|
const count = (values) => {
|
|
@@ -31957,7 +32022,7 @@ function summaryOf(edits, mentions, rewrites, left) {
|
|
|
31957
32022
|
}
|
|
31958
32023
|
|
|
31959
32024
|
// src/restart-note.ts
|
|
31960
|
-
import { mkdirSync as
|
|
32025
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync16, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
31961
32026
|
import { dirname as dirname11, join as join17 } from "node:path";
|
|
31962
32027
|
function restartNotePath(projectPath) {
|
|
31963
32028
|
return join17(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -31965,8 +32030,8 @@ function restartNotePath(projectPath) {
|
|
|
31965
32030
|
function noteRestartBegun(note) {
|
|
31966
32031
|
const path = restartNotePath(note.projectPath);
|
|
31967
32032
|
try {
|
|
31968
|
-
|
|
31969
|
-
|
|
32033
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
32034
|
+
writeFileSync11(path, `${JSON.stringify(note, null, 2)}
|
|
31970
32035
|
`, "utf8");
|
|
31971
32036
|
} catch (error) {
|
|
31972
32037
|
console.error(`[SERVER] Could not record the restart at ${path}: ${errorMessage(error)}`);
|
|
@@ -31989,7 +32054,7 @@ function restartOwed(projectPath) {
|
|
|
31989
32054
|
}
|
|
31990
32055
|
function restartSettled(projectPath) {
|
|
31991
32056
|
try {
|
|
31992
|
-
|
|
32057
|
+
rmSync7(restartNotePath(projectPath), { force: true });
|
|
31993
32058
|
} catch (error) {
|
|
31994
32059
|
console.error(`[SERVER] Could not clear the restart note: ${errorMessage(error)}`);
|
|
31995
32060
|
}
|
|
@@ -31999,14 +32064,14 @@ function restartSettled(projectPath) {
|
|
|
31999
32064
|
import { execFile as execFile4 } from "node:child_process";
|
|
32000
32065
|
import { createHash as createHash3 } from "node:crypto";
|
|
32001
32066
|
import {
|
|
32002
|
-
mkdirSync as
|
|
32067
|
+
mkdirSync as mkdirSync10,
|
|
32003
32068
|
openSync as openSync2,
|
|
32004
|
-
readdirSync as
|
|
32069
|
+
readdirSync as readdirSync7,
|
|
32005
32070
|
readFileSync as readFileSync17,
|
|
32006
32071
|
realpathSync as realpathSync6,
|
|
32007
|
-
rmSync as
|
|
32072
|
+
rmSync as rmSync8,
|
|
32008
32073
|
statSync as statSync6,
|
|
32009
|
-
writeFileSync as
|
|
32074
|
+
writeFileSync as writeFileSync12
|
|
32010
32075
|
} from "node:fs";
|
|
32011
32076
|
import { basename as basename4, dirname as dirname12, join as join18, resolve as resolve6 } from "node:path";
|
|
32012
32077
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -32040,7 +32105,7 @@ function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
|
32040
32105
|
}
|
|
32041
32106
|
var SHARED_NOTE = "run.json";
|
|
32042
32107
|
function openTranscript(startedAt) {
|
|
32043
|
-
|
|
32108
|
+
mkdirSync10(runsDirectory(), { recursive: true });
|
|
32044
32109
|
const path = join18(runsDirectory(), `run-${startedAt}.log`);
|
|
32045
32110
|
return { path, fd: openSync2(path, "a") };
|
|
32046
32111
|
}
|
|
@@ -32051,8 +32116,8 @@ function editorNotePath(projectPath, directory = runtimeDirectory()) {
|
|
|
32051
32116
|
return join18(directory, "runs", `editor-${projectKey(projectPath)}.json`);
|
|
32052
32117
|
}
|
|
32053
32118
|
function writeEditorRunNote(note) {
|
|
32054
|
-
|
|
32055
|
-
|
|
32119
|
+
mkdirSync10(runsDirectory(), { recursive: true });
|
|
32120
|
+
writeFileSync12(editorNotePath(note.projectPath), JSON.stringify(note, null, 2), "utf8");
|
|
32056
32121
|
}
|
|
32057
32122
|
function readEditorRunNote(projectPath) {
|
|
32058
32123
|
for (const directory of runtimeDirectories()) {
|
|
@@ -32102,7 +32167,7 @@ function everyRunRecord() {
|
|
|
32102
32167
|
for (const directory of runtimeDirectories()) {
|
|
32103
32168
|
let entries;
|
|
32104
32169
|
try {
|
|
32105
|
-
entries =
|
|
32170
|
+
entries = readdirSync7(join18(directory, "runs"));
|
|
32106
32171
|
} catch {
|
|
32107
32172
|
continue;
|
|
32108
32173
|
}
|
|
@@ -32322,7 +32387,7 @@ function clearRunRecord(projectPath) {
|
|
|
32322
32387
|
const ours = sharedRecord !== null && sharedRecord.projectPath !== "" && isSameDirectory(sharedRecord.projectPath, projectPath);
|
|
32323
32388
|
for (const path of [runRecordPath(projectPath, directory), ...ours ? [shared] : []]) {
|
|
32324
32389
|
try {
|
|
32325
|
-
|
|
32390
|
+
rmSync8(path, { force: true });
|
|
32326
32391
|
} catch {}
|
|
32327
32392
|
}
|
|
32328
32393
|
}
|
|
@@ -32339,7 +32404,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
32339
32404
|
const kept = new Set(everyRunRecord().map((record) => record.transcript));
|
|
32340
32405
|
let entries;
|
|
32341
32406
|
try {
|
|
32342
|
-
entries =
|
|
32407
|
+
entries = readdirSync7(directory);
|
|
32343
32408
|
} catch {
|
|
32344
32409
|
return;
|
|
32345
32410
|
}
|
|
@@ -32352,7 +32417,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
32352
32417
|
continue;
|
|
32353
32418
|
}
|
|
32354
32419
|
try {
|
|
32355
|
-
|
|
32420
|
+
rmSync8(path);
|
|
32356
32421
|
} catch {}
|
|
32357
32422
|
}
|
|
32358
32423
|
}
|
|
@@ -32363,13 +32428,13 @@ import { createHash as createHash4 } from "node:crypto";
|
|
|
32363
32428
|
import {
|
|
32364
32429
|
cpSync,
|
|
32365
32430
|
existsSync as existsSync15,
|
|
32366
|
-
mkdirSync as
|
|
32367
|
-
readdirSync as
|
|
32431
|
+
mkdirSync as mkdirSync11,
|
|
32432
|
+
readdirSync as readdirSync8,
|
|
32368
32433
|
readFileSync as readFileSync18,
|
|
32369
32434
|
rmdirSync,
|
|
32370
|
-
rmSync as
|
|
32435
|
+
rmSync as rmSync9,
|
|
32371
32436
|
statSync as statSync7,
|
|
32372
|
-
writeFileSync as
|
|
32437
|
+
writeFileSync as writeFileSync13
|
|
32373
32438
|
} from "node:fs";
|
|
32374
32439
|
import { dirname as dirname13, join as join19 } from "node:path";
|
|
32375
32440
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -32391,7 +32456,7 @@ function runtimeAddonDigest(from = shippedAddonsDirectory()) {
|
|
|
32391
32456
|
function addonsDigest(names, from) {
|
|
32392
32457
|
const hash = createHash4("sha256");
|
|
32393
32458
|
const walk = (directory, relative) => {
|
|
32394
|
-
for (const name of
|
|
32459
|
+
for (const name of readdirSync8(directory).sort()) {
|
|
32395
32460
|
if (name === VERSION_MARKER || name === DIGEST_MARKER) {
|
|
32396
32461
|
continue;
|
|
32397
32462
|
}
|
|
@@ -32755,7 +32820,7 @@ var TOOL_SPECS = [
|
|
|
32755
32820
|
},
|
|
32756
32821
|
{
|
|
32757
32822
|
name: "project_settings",
|
|
32758
|
-
description: "Reads or writes project.godot: settings, autoloads, the main scene, input actions, plugins and audio buses. A write with an editor open on the project is handed to the editor, which takes the settings the write changed from the file (named under editorAdopted), or reloads the bus layout, so it answers the new values and does not save the old ones back over them. editorNote is an editor that could not take the write, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
32823
|
+
description: "Reads or writes project.godot: settings, autoloads, the main scene, input actions, plugins and audio buses. A write with an editor open on the project is handed to the editor, which takes the settings the write changed or names from the file (named under editorAdopted), including a setting the file already held, since the editor can hold another value after the file was put back, or reloads the bus layout, so it answers the new values and does not save the old ones back over them. editorNote is an editor that could not take the write, one on an addon from before this, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start.",
|
|
32759
32824
|
parameters: {
|
|
32760
32825
|
projectPath: PROJECT_PATH,
|
|
32761
32826
|
setting: { type: "string", description: 'Setting path, such as "display/window/size/viewport_width".' },
|
|
@@ -33125,7 +33190,7 @@ var TOOL_SPECS = [
|
|
|
33125
33190
|
},
|
|
33126
33191
|
{
|
|
33127
33192
|
name: "script_edit",
|
|
33128
|
-
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 string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. 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.",
|
|
33193
|
+
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 string that is the old name whole, such as find_children's type or a call's method name, which nothing renames or compiles and which is listed first; a node named like the class; a call on a value whose type the analyser could not tell. A member rename answers under languageServer how many requests it made and how long they took. A comment, documentation line, string or text file line with nothing more to say is given under leftAloneInProse by file, kind and line instead, and code that is certainly another symbol of the same name, a bare name in a file where nothing inherits the member or one the language server resolved to another declaration, under leftAloneOtherSymbols as each why with the files and lines it covers. summary.leftAlone counts each of the three lists beside the total. When those two grouped lists run past 300 lines, they are written with each line's text to a file under the project's .godot directory instead, of which the newest ten are kept, and leftAloneDetail names the file and counts what is in it. 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.",
|
|
33129
33194
|
parameters: {
|
|
33130
33195
|
projectPath: PROJECT_PATH,
|
|
33131
33196
|
scriptPath: SCRIPT_PATH,
|
|
@@ -34411,7 +34476,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
34411
34476
|
...problems.omitted === 0 ? {} : { entriesOmitted: problems.omitted }
|
|
34412
34477
|
};
|
|
34413
34478
|
if (verdict.exported) {
|
|
34414
|
-
return { content: [{ type: "text", text:
|
|
34479
|
+
return { content: [{ type: "text", text: answerJson(verdict) }] };
|
|
34415
34480
|
}
|
|
34416
34481
|
const stale = !written && after !== null ? ` The ${asked.outputPath} there is from before this export, which did not write it.` : "";
|
|
34417
34482
|
const why = ending.exitSignal === null ? stale : ` The engine was ${howItEnded(ending)}, so it has no exit code.${stale}`;
|
|
@@ -34421,7 +34486,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
34421
34486
|
type: "text",
|
|
34422
34487
|
text: `Export with preset '${asked.preset}' did not produce ${asked.outputPath}.${why}`
|
|
34423
34488
|
},
|
|
34424
|
-
{ type: "text", text:
|
|
34489
|
+
{ type: "text", text: answerJson(verdict) }
|
|
34425
34490
|
],
|
|
34426
34491
|
isError: true
|
|
34427
34492
|
};
|
|
@@ -34452,6 +34517,25 @@ function changedSettings(before, after) {
|
|
|
34452
34517
|
const names = new Set([...before.keys(), ...after.keys()]);
|
|
34453
34518
|
return [...names].filter((name) => JSON.stringify(before.get(name)) !== JSON.stringify(after.get(name))).sort();
|
|
34454
34519
|
}
|
|
34520
|
+
function settingsNamedBy(op, args) {
|
|
34521
|
+
const text = (key) => readString(args, key) ?? "";
|
|
34522
|
+
switch (op) {
|
|
34523
|
+
case "set":
|
|
34524
|
+
return text("setting") === "" ? [] : [text("setting")];
|
|
34525
|
+
case "add_autoload":
|
|
34526
|
+
case "remove_autoload":
|
|
34527
|
+
return text("name") === "" ? [] : [`autoload/${text("name")}`];
|
|
34528
|
+
case "set_main_scene":
|
|
34529
|
+
return ["application/run/main_scene"];
|
|
34530
|
+
case "add_input_action":
|
|
34531
|
+
return text("actionName") === "" ? [] : [`input/${text("actionName")}`];
|
|
34532
|
+
case "enable_plugin":
|
|
34533
|
+
case "disable_plugin":
|
|
34534
|
+
return ["editor_plugins/enabled"];
|
|
34535
|
+
default:
|
|
34536
|
+
return [];
|
|
34537
|
+
}
|
|
34538
|
+
}
|
|
34455
34539
|
var STALLED_AFTER_MS = 30000;
|
|
34456
34540
|
var DEPENDED_FAILED = "Failed to compile depended scripts";
|
|
34457
34541
|
function scriptErrorsNote(errors) {
|
|
@@ -34568,7 +34652,7 @@ function elsewhereIn(projectPath, asked) {
|
|
|
34568
34652
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
34569
34653
|
let near = [];
|
|
34570
34654
|
try {
|
|
34571
|
-
near =
|
|
34655
|
+
near = readdirSync9(projectPath, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.toLowerCase() !== root).map((entry) => entry.name).filter((name) => name.toLowerCase().startsWith("test") || root.startsWith(name.toLowerCase()));
|
|
34572
34656
|
} catch {
|
|
34573
34657
|
return "";
|
|
34574
34658
|
}
|
|
@@ -34670,7 +34754,7 @@ class GodotServer {
|
|
|
34670
34754
|
return response;
|
|
34671
34755
|
}
|
|
34672
34756
|
jsonTextResponse(payload) {
|
|
34673
|
-
return { content: [{ type: "text", text:
|
|
34757
|
+
return { content: [{ type: "text", text: answerJson(payload) }] };
|
|
34674
34758
|
}
|
|
34675
34759
|
async run() {
|
|
34676
34760
|
const located = await this.locator.find();
|
|
@@ -35003,7 +35087,7 @@ class GodotServer {
|
|
|
35003
35087
|
saying(answer, block) {
|
|
35004
35088
|
return {
|
|
35005
35089
|
...answer,
|
|
35006
|
-
content: [...answer.content, { type: "text", text:
|
|
35090
|
+
content: [...answer.content, { type: "text", text: answerJson(block) }]
|
|
35007
35091
|
};
|
|
35008
35092
|
}
|
|
35009
35093
|
projectHasMovedOn() {
|
|
@@ -35708,7 +35792,8 @@ class GodotServer {
|
|
|
35708
35792
|
if (AUDIO_BUS_OPS.has(op)) {
|
|
35709
35793
|
return this.jsonTextResponse({ ...answer, ...await this.editorTakes("adopt_audio_bus_layout", {}) });
|
|
35710
35794
|
}
|
|
35711
|
-
const
|
|
35795
|
+
const diffed = changedSettings(before, this.settingKeysOf(projectPath));
|
|
35796
|
+
const changed = diffed === null ? null : [...new Set([...diffed, ...settingsNamedBy(op, args)])].sort();
|
|
35712
35797
|
if (changed === null) {
|
|
35713
35798
|
return this.jsonTextResponse({
|
|
35714
35799
|
...answer,
|
|
@@ -35976,7 +36061,7 @@ class GodotServer {
|
|
|
35976
36061
|
if (!outcome.ok) {
|
|
35977
36062
|
const response = this.createErrorResponse(outcome.message);
|
|
35978
36063
|
if (Object.keys(extras).length > 0) {
|
|
35979
|
-
response.content.push({ type: "text", text:
|
|
36064
|
+
response.content.push({ type: "text", text: answerJson(extras) });
|
|
35980
36065
|
}
|
|
35981
36066
|
return response;
|
|
35982
36067
|
}
|
|
@@ -36054,7 +36139,7 @@ class GodotServer {
|
|
|
36054
36139
|
}
|
|
36055
36140
|
const folder = dirname14(output.absolutePath);
|
|
36056
36141
|
try {
|
|
36057
|
-
|
|
36142
|
+
mkdirSync12(folder, { recursive: true });
|
|
36058
36143
|
} catch (error) {
|
|
36059
36144
|
return this.createErrorResponse(`Cannot create ${dirname14(output.relativePath)} to export into: ${errorMessage(error)}`);
|
|
36060
36145
|
}
|
|
@@ -36165,7 +36250,7 @@ class GodotServer {
|
|
|
36165
36250
|
let report = null;
|
|
36166
36251
|
let reportProblem = null;
|
|
36167
36252
|
try {
|
|
36168
|
-
const written = existsSync16(reportsDir) ?
|
|
36253
|
+
const written = existsSync16(reportsDir) ? readdirSync9(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
36169
36254
|
const newest = written.at(-1);
|
|
36170
36255
|
if (newest !== undefined) {
|
|
36171
36256
|
report = parseJUnit(readFileSync19(join20(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -38676,6 +38761,15 @@ class GodotServer {
|
|
|
38676
38761
|
const said = outcome.conflicts === undefined ? "" : ` ${outcome.conflicts.join("; ")}.`;
|
|
38677
38762
|
return this.createErrorResponse(`${outcome.reason}${said}`, outcome.advice ?? []);
|
|
38678
38763
|
}
|
|
38764
|
+
if (outcome.detail !== null) {
|
|
38765
|
+
const file = writeLeftAloneDetail(projectPath, symbol, outcome.detail);
|
|
38766
|
+
const folded = asParams(outcome.report["leftAloneDetail"]);
|
|
38767
|
+
outcome.report["leftAloneDetail"] = {
|
|
38768
|
+
file,
|
|
38769
|
+
note: `Too many lines were left alone to list here, and none of them is a use: every comment, documentation line, string and text file line that only shares the word, and every other symbol of the same name, is in ${file} with its text. The newest ten of these files are kept and older ones removed as new ones are written.`,
|
|
38770
|
+
...folded
|
|
38771
|
+
};
|
|
38772
|
+
}
|
|
38679
38773
|
if (readBoolean(args, "preview") === true) {
|
|
38680
38774
|
return this.jsonTextResponse({ preview: true, ...outcome.report });
|
|
38681
38775
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.40",
|
|
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",
|