gdharness 1.1.37 → 1.1.39
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 +150 -57
- package/build/index.js +146 -58
- 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 = [
|
|
@@ -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
|
|
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, 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");
|
|
@@ -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));
|
|
@@ -40807,6 +40827,7 @@ async function renameSymbol(request, services) {
|
|
|
40807
40827
|
}, plan);
|
|
40808
40828
|
}
|
|
40809
40829
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? null : declaringPath);
|
|
40830
|
+
const left = leftAloneReport(plan.mentions);
|
|
40810
40831
|
const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
|
|
40811
40832
|
const graph = new ClassGraph(scripts, declared);
|
|
40812
40833
|
const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
|
|
@@ -40817,14 +40838,15 @@ async function renameSymbol(request, services) {
|
|
|
40817
40838
|
moved: moveTo === null ? null : { from: declaringPath, to: moveTo },
|
|
40818
40839
|
scriptsInOrder,
|
|
40819
40840
|
rewrites,
|
|
40841
|
+
detail: left.detail,
|
|
40820
40842
|
report: {
|
|
40821
40843
|
renamed: { what, from: symbol, to: newName, declaredIn: declaringPath, resolvedBy },
|
|
40822
40844
|
...took === null ? {} : { languageServer: took },
|
|
40823
40845
|
...overrides.length > 0 ? { overridesRenamed: overrides } : {},
|
|
40824
40846
|
...moveTo === null ? {} : { moved: { from: declaringPath, to: moveTo } },
|
|
40825
40847
|
changed: changedReport(plan.edits, rewrites),
|
|
40826
|
-
...
|
|
40827
|
-
summary: summaryOf(plan.edits, plan.mentions, rewrites)
|
|
40848
|
+
...left.lists,
|
|
40849
|
+
summary: summaryOf(plan.edits, plan.mentions, rewrites, left.counts)
|
|
40828
40850
|
}
|
|
40829
40851
|
};
|
|
40830
40852
|
}
|
|
@@ -40923,36 +40945,96 @@ function leftAloneReport(mentions) {
|
|
|
40923
40945
|
const full = [];
|
|
40924
40946
|
const prose = new Map;
|
|
40925
40947
|
const others = new Map;
|
|
40926
|
-
const
|
|
40927
|
-
|
|
40928
|
-
|
|
40948
|
+
const counts = { quoted: 0, inProse: 0, otherSymbols: 0 };
|
|
40949
|
+
const add = (lines, line) => {
|
|
40950
|
+
if (!lines.includes(line)) {
|
|
40951
|
+
lines.push(line);
|
|
40929
40952
|
}
|
|
40930
40953
|
};
|
|
40954
|
+
const textOf = new Map;
|
|
40955
|
+
for (const mention of mentions) {
|
|
40956
|
+
textOf.set(`${mention.file}:${String(mention.line)}`, mention.text);
|
|
40957
|
+
}
|
|
40931
40958
|
for (const mention of mentions) {
|
|
40932
|
-
if ((mention.kind
|
|
40959
|
+
if (PROSE_KINDS.has(mention.kind) && mention.why === undefined) {
|
|
40933
40960
|
const key = `${mention.file}
|
|
40934
40961
|
${mention.kind}`;
|
|
40935
40962
|
const group = prose.get(key) ?? { file: mention.file, kind: mention.kind, lines: [] };
|
|
40936
|
-
add(group, mention.line);
|
|
40963
|
+
add(group.lines, mention.line);
|
|
40937
40964
|
prose.set(key, group);
|
|
40965
|
+
counts.inProse += 1;
|
|
40938
40966
|
} else if (mention.kind === "code" && (mention.why === NOT_INHERITED || mention.why === RESOLVED_ELSEWHERE)) {
|
|
40939
|
-
const
|
|
40940
|
-
|
|
40941
|
-
|
|
40942
|
-
|
|
40943
|
-
others.set(
|
|
40967
|
+
const files = others.get(mention.why) ?? new Map;
|
|
40968
|
+
const lines = files.get(mention.file) ?? [];
|
|
40969
|
+
add(lines, mention.line);
|
|
40970
|
+
files.set(mention.file, lines);
|
|
40971
|
+
others.set(mention.why, files);
|
|
40972
|
+
counts.otherSymbols += 1;
|
|
40944
40973
|
} else {
|
|
40945
40974
|
full.push(mention);
|
|
40975
|
+
counts.quoted += 1;
|
|
40946
40976
|
}
|
|
40947
40977
|
}
|
|
40948
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)}`) ?? "" }));
|
|
40949
40998
|
return {
|
|
40950
|
-
|
|
40951
|
-
|
|
40952
|
-
|
|
40999
|
+
lists: {
|
|
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)
|
|
41007
|
+
}))
|
|
41008
|
+
}
|
|
41009
|
+
},
|
|
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
|
+
}
|
|
40953
41022
|
};
|
|
40954
41023
|
}
|
|
40955
|
-
function
|
|
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
|
+
}
|
|
41037
|
+
function summaryOf(edits, mentions, rewrites, left) {
|
|
40956
41038
|
const count = (values) => {
|
|
40957
41039
|
const counted = {};
|
|
40958
41040
|
for (const value of values) {
|
|
@@ -40964,11 +41046,11 @@ function summaryOf(edits, mentions, rewrites) {
|
|
|
40964
41046
|
filesChanged: rewrites.length,
|
|
40965
41047
|
edits: edits.length,
|
|
40966
41048
|
editsByKind: count(edits.map((edit) => edit.kind)),
|
|
40967
|
-
leftAlone: mentions.length,
|
|
41049
|
+
leftAlone: { total: mentions.length, ...left },
|
|
40968
41050
|
leftAloneByKind: count(mentions.map((mention) => mention.kind))
|
|
40969
41051
|
};
|
|
40970
41052
|
}
|
|
40971
|
-
var WHAT;
|
|
41053
|
+
var WHAT, LEFT_ALONE_ANSWER_LINES = 300, detailWrites = 0, PROSE_KINDS;
|
|
40972
41054
|
var init_rename_symbol = __esm(() => {
|
|
40973
41055
|
init_gdscript_source();
|
|
40974
41056
|
init_lsp_client();
|
|
@@ -40984,10 +41066,11 @@ var init_rename_symbol = __esm(() => {
|
|
|
40984
41066
|
class: "inner class",
|
|
40985
41067
|
enumValue: "enum value"
|
|
40986
41068
|
};
|
|
41069
|
+
PROSE_KINDS = new Set(["comment", "doc", "string", "text"]);
|
|
40987
41070
|
});
|
|
40988
41071
|
|
|
40989
41072
|
// src/restart-note.ts
|
|
40990
|
-
import { mkdirSync as
|
|
41073
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync19, rmSync as rmSync10, writeFileSync as writeFileSync14 } from "node:fs";
|
|
40991
41074
|
import { dirname as dirname16, join as join22 } from "node:path";
|
|
40992
41075
|
function restartNotePath(projectPath) {
|
|
40993
41076
|
return join22(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -40995,8 +41078,8 @@ function restartNotePath(projectPath) {
|
|
|
40995
41078
|
function noteRestartBegun(note) {
|
|
40996
41079
|
const path = restartNotePath(note.projectPath);
|
|
40997
41080
|
try {
|
|
40998
|
-
|
|
40999
|
-
|
|
41081
|
+
mkdirSync12(dirname16(path), { recursive: true });
|
|
41082
|
+
writeFileSync14(path, `${JSON.stringify(note, null, 2)}
|
|
41000
41083
|
`, "utf8");
|
|
41001
41084
|
} catch (error) {
|
|
41002
41085
|
console.error(`[SERVER] Could not record the restart at ${path}: ${errorMessage(error)}`);
|
|
@@ -41019,7 +41102,7 @@ function restartOwed(projectPath) {
|
|
|
41019
41102
|
}
|
|
41020
41103
|
function restartSettled(projectPath) {
|
|
41021
41104
|
try {
|
|
41022
|
-
|
|
41105
|
+
rmSync10(restartNotePath(projectPath), { force: true });
|
|
41023
41106
|
} catch (error) {
|
|
41024
41107
|
console.error(`[SERVER] Could not clear the restart note: ${errorMessage(error)}`);
|
|
41025
41108
|
}
|
|
@@ -41032,14 +41115,14 @@ var init_restart_note = __esm(() => {
|
|
|
41032
41115
|
import { execFile as execFile4 } from "node:child_process";
|
|
41033
41116
|
import { createHash as createHash4 } from "node:crypto";
|
|
41034
41117
|
import {
|
|
41035
|
-
mkdirSync as
|
|
41118
|
+
mkdirSync as mkdirSync13,
|
|
41036
41119
|
openSync as openSync2,
|
|
41037
|
-
readdirSync as
|
|
41120
|
+
readdirSync as readdirSync9,
|
|
41038
41121
|
readFileSync as readFileSync20,
|
|
41039
41122
|
realpathSync as realpathSync6,
|
|
41040
|
-
rmSync as
|
|
41123
|
+
rmSync as rmSync11,
|
|
41041
41124
|
statSync as statSync8,
|
|
41042
|
-
writeFileSync as
|
|
41125
|
+
writeFileSync as writeFileSync15
|
|
41043
41126
|
} from "node:fs";
|
|
41044
41127
|
import { basename as basename6, dirname as dirname17, join as join23, resolve as resolve7 } from "node:path";
|
|
41045
41128
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -41071,7 +41154,7 @@ function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
|
41071
41154
|
return join23(directory, "runs", `note-${projectKey(projectPath)}.json`);
|
|
41072
41155
|
}
|
|
41073
41156
|
function openTranscript(startedAt) {
|
|
41074
|
-
|
|
41157
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
41075
41158
|
const path = join23(runsDirectory(), `run-${startedAt}.log`);
|
|
41076
41159
|
return { path, fd: openSync2(path, "a") };
|
|
41077
41160
|
}
|
|
@@ -41082,8 +41165,8 @@ function editorNotePath(projectPath, directory = runtimeDirectory()) {
|
|
|
41082
41165
|
return join23(directory, "runs", `editor-${projectKey(projectPath)}.json`);
|
|
41083
41166
|
}
|
|
41084
41167
|
function writeEditorRunNote(note) {
|
|
41085
|
-
|
|
41086
|
-
|
|
41168
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
41169
|
+
writeFileSync15(editorNotePath(note.projectPath), JSON.stringify(note, null, 2), "utf8");
|
|
41087
41170
|
}
|
|
41088
41171
|
function readEditorRunNote(projectPath) {
|
|
41089
41172
|
for (const directory of runtimeDirectories()) {
|
|
@@ -41133,7 +41216,7 @@ function everyRunRecord() {
|
|
|
41133
41216
|
for (const directory of runtimeDirectories()) {
|
|
41134
41217
|
let entries;
|
|
41135
41218
|
try {
|
|
41136
|
-
entries =
|
|
41219
|
+
entries = readdirSync9(join23(directory, "runs"));
|
|
41137
41220
|
} catch {
|
|
41138
41221
|
continue;
|
|
41139
41222
|
}
|
|
@@ -41352,7 +41435,7 @@ function clearRunRecord(projectPath) {
|
|
|
41352
41435
|
const ours = sharedRecord !== null && sharedRecord.projectPath !== "" && isSameDirectory(sharedRecord.projectPath, projectPath);
|
|
41353
41436
|
for (const path of [runRecordPath(projectPath, directory), ...ours ? [shared] : []]) {
|
|
41354
41437
|
try {
|
|
41355
|
-
|
|
41438
|
+
rmSync11(path, { force: true });
|
|
41356
41439
|
} catch {}
|
|
41357
41440
|
}
|
|
41358
41441
|
}
|
|
@@ -41369,7 +41452,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
41369
41452
|
const kept = new Set(everyRunRecord().map((record) => record.transcript));
|
|
41370
41453
|
let entries;
|
|
41371
41454
|
try {
|
|
41372
|
-
entries =
|
|
41455
|
+
entries = readdirSync9(directory);
|
|
41373
41456
|
} catch {
|
|
41374
41457
|
return;
|
|
41375
41458
|
}
|
|
@@ -41382,7 +41465,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
41382
41465
|
continue;
|
|
41383
41466
|
}
|
|
41384
41467
|
try {
|
|
41385
|
-
|
|
41468
|
+
rmSync11(path);
|
|
41386
41469
|
} catch {}
|
|
41387
41470
|
}
|
|
41388
41471
|
}
|
|
@@ -41406,9 +41489,9 @@ import {
|
|
|
41406
41489
|
copyFileSync,
|
|
41407
41490
|
existsSync as existsSync19,
|
|
41408
41491
|
fstatSync,
|
|
41409
|
-
mkdirSync as
|
|
41492
|
+
mkdirSync as mkdirSync14,
|
|
41410
41493
|
openSync as openSync3,
|
|
41411
|
-
readdirSync as
|
|
41494
|
+
readdirSync as readdirSync10,
|
|
41412
41495
|
readFileSync as readFileSync21,
|
|
41413
41496
|
readSync as readSync2,
|
|
41414
41497
|
rmdirSync as rmdirSync2,
|
|
@@ -41862,7 +41945,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
41862
41945
|
...problems.omitted === 0 ? {} : { entriesOmitted: problems.omitted }
|
|
41863
41946
|
};
|
|
41864
41947
|
if (verdict.exported) {
|
|
41865
|
-
return { content: [{ type: "text", text:
|
|
41948
|
+
return { content: [{ type: "text", text: answerJson(verdict) }] };
|
|
41866
41949
|
}
|
|
41867
41950
|
const stale = !written && after !== null ? ` The ${asked.outputPath} there is from before this export, which did not write it.` : "";
|
|
41868
41951
|
const why = ending.exitSignal === null ? stale : ` The engine was ${howItEnded(ending)}, so it has no exit code.${stale}`;
|
|
@@ -41872,7 +41955,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
41872
41955
|
type: "text",
|
|
41873
41956
|
text: `Export with preset '${asked.preset}' did not produce ${asked.outputPath}.${why}`
|
|
41874
41957
|
},
|
|
41875
|
-
{ type: "text", text:
|
|
41958
|
+
{ type: "text", text: answerJson(verdict) }
|
|
41876
41959
|
],
|
|
41877
41960
|
isError: true
|
|
41878
41961
|
};
|
|
@@ -41976,7 +42059,7 @@ function elsewhereIn(projectPath, asked) {
|
|
|
41976
42059
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
41977
42060
|
let near = [];
|
|
41978
42061
|
try {
|
|
41979
|
-
near =
|
|
42062
|
+
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()));
|
|
41980
42063
|
} catch {
|
|
41981
42064
|
return "";
|
|
41982
42065
|
}
|
|
@@ -42078,7 +42161,7 @@ class GodotServer {
|
|
|
42078
42161
|
return response;
|
|
42079
42162
|
}
|
|
42080
42163
|
jsonTextResponse(payload) {
|
|
42081
|
-
return { content: [{ type: "text", text:
|
|
42164
|
+
return { content: [{ type: "text", text: answerJson(payload) }] };
|
|
42082
42165
|
}
|
|
42083
42166
|
async run() {
|
|
42084
42167
|
const located = await this.locator.find();
|
|
@@ -42411,7 +42494,7 @@ class GodotServer {
|
|
|
42411
42494
|
saying(answer, block) {
|
|
42412
42495
|
return {
|
|
42413
42496
|
...answer,
|
|
42414
|
-
content: [...answer.content, { type: "text", text:
|
|
42497
|
+
content: [...answer.content, { type: "text", text: answerJson(block) }]
|
|
42415
42498
|
};
|
|
42416
42499
|
}
|
|
42417
42500
|
projectHasMovedOn() {
|
|
@@ -43384,7 +43467,7 @@ class GodotServer {
|
|
|
43384
43467
|
if (!outcome.ok) {
|
|
43385
43468
|
const response = this.createErrorResponse(outcome.message);
|
|
43386
43469
|
if (Object.keys(extras).length > 0) {
|
|
43387
|
-
response.content.push({ type: "text", text:
|
|
43470
|
+
response.content.push({ type: "text", text: answerJson(extras) });
|
|
43388
43471
|
}
|
|
43389
43472
|
return response;
|
|
43390
43473
|
}
|
|
@@ -43462,7 +43545,7 @@ class GodotServer {
|
|
|
43462
43545
|
}
|
|
43463
43546
|
const folder = dirname18(output.absolutePath);
|
|
43464
43547
|
try {
|
|
43465
|
-
|
|
43548
|
+
mkdirSync14(folder, { recursive: true });
|
|
43466
43549
|
} catch (error) {
|
|
43467
43550
|
return this.createErrorResponse(`Cannot create ${dirname18(output.relativePath)} to export into: ${errorMessage(error)}`);
|
|
43468
43551
|
}
|
|
@@ -43573,7 +43656,7 @@ class GodotServer {
|
|
|
43573
43656
|
let report = null;
|
|
43574
43657
|
let reportProblem = null;
|
|
43575
43658
|
try {
|
|
43576
|
-
const written = existsSync19(reportsDir) ?
|
|
43659
|
+
const written = existsSync19(reportsDir) ? readdirSync10(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
43577
43660
|
const newest = written.at(-1);
|
|
43578
43661
|
if (newest !== undefined) {
|
|
43579
43662
|
report = parseJUnit(readFileSync21(join24(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -46084,6 +46167,15 @@ class GodotServer {
|
|
|
46084
46167
|
const said = outcome.conflicts === undefined ? "" : ` ${outcome.conflicts.join("; ")}.`;
|
|
46085
46168
|
return this.createErrorResponse(`${outcome.reason}${said}`, outcome.advice ?? []);
|
|
46086
46169
|
}
|
|
46170
|
+
if (outcome.detail !== null) {
|
|
46171
|
+
const file = writeLeftAloneDetail(projectPath, symbol, outcome.detail);
|
|
46172
|
+
const folded = asParams(outcome.report["leftAloneDetail"]);
|
|
46173
|
+
outcome.report["leftAloneDetail"] = {
|
|
46174
|
+
file,
|
|
46175
|
+
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.`,
|
|
46176
|
+
...folded
|
|
46177
|
+
};
|
|
46178
|
+
}
|
|
46087
46179
|
if (readBoolean(args, "preview") === true) {
|
|
46088
46180
|
return this.jsonTextResponse({ preview: true, ...outcome.report });
|
|
46089
46181
|
}
|
|
@@ -46547,6 +46639,7 @@ var init_server3 = __esm(() => {
|
|
|
46547
46639
|
init_stdio2();
|
|
46548
46640
|
init_types();
|
|
46549
46641
|
init_alive();
|
|
46642
|
+
init_answer_json();
|
|
46550
46643
|
init_boot_note();
|
|
46551
46644
|
init_breakpoint_note();
|
|
46552
46645
|
init_bridge_announce();
|
|
@@ -47815,9 +47908,9 @@ To rename a class or a member across the project, use \`script_edit rename\` rat
|
|
|
47815
47908
|
replacement: it changes the uses the engine resolves, doc links and what scenes record, and lists
|
|
47816
47909
|
every other occurrence of the word for you to read: a string that is the name whole, such as a
|
|
47817
47910
|
\`find_children\` type, first under \`leftAlone\` since nothing compiles it, a file under a
|
|
47818
|
-
\`.gdignore\` directory there too, a word in a comment or a text file by
|
|
47819
|
-
\`leftAloneInProse\`, and a local or another class's member of the same name by line
|
|
47820
|
-
\`leftAloneOtherSymbols
|
|
47911
|
+
\`.gdignore\` directory there too, a word in a comment, a doc line, a string or a text file by
|
|
47912
|
+
line under \`leftAloneInProse\`, and a local or another class's member of the same name by line
|
|
47913
|
+
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\`
|
|
47821
47914
|
beside \`written: true\`, the files were changed and a script did not compile afterwards.
|
|
47822
47915
|
|
|
47823
47916
|
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
|
}
|
|
@@ -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);
|
|
@@ -31780,6 +31794,7 @@ async function renameSymbol(request, services) {
|
|
|
31780
31794
|
}, plan);
|
|
31781
31795
|
}
|
|
31782
31796
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? null : declaringPath);
|
|
31797
|
+
const left = leftAloneReport(plan.mentions);
|
|
31783
31798
|
const rewrites = rewritesOf(plan, texts, moveTo === null || request.newScriptPath === null ? null : { from: declaringPath, to: moveTo, absoluteTo: request.newScriptPath });
|
|
31784
31799
|
const graph = new ClassGraph(scripts, declared);
|
|
31785
31800
|
const rank = (path) => (declaringFiles.includes(path) ? 0 : 1000) + graph.ancestors(`${path}#`).length;
|
|
@@ -31790,14 +31805,15 @@ async function renameSymbol(request, services) {
|
|
|
31790
31805
|
moved: moveTo === null ? null : { from: declaringPath, to: moveTo },
|
|
31791
31806
|
scriptsInOrder,
|
|
31792
31807
|
rewrites,
|
|
31808
|
+
detail: left.detail,
|
|
31793
31809
|
report: {
|
|
31794
31810
|
renamed: { what, from: symbol, to: newName, declaredIn: declaringPath, resolvedBy },
|
|
31795
31811
|
...took === null ? {} : { languageServer: took },
|
|
31796
31812
|
...overrides.length > 0 ? { overridesRenamed: overrides } : {},
|
|
31797
31813
|
...moveTo === null ? {} : { moved: { from: declaringPath, to: moveTo } },
|
|
31798
31814
|
changed: changedReport(plan.edits, rewrites),
|
|
31799
|
-
...
|
|
31800
|
-
summary: summaryOf(plan.edits, plan.mentions, rewrites)
|
|
31815
|
+
...left.lists,
|
|
31816
|
+
summary: summaryOf(plan.edits, plan.mentions, rewrites, left.counts)
|
|
31801
31817
|
}
|
|
31802
31818
|
};
|
|
31803
31819
|
}
|
|
@@ -31896,36 +31912,99 @@ function leftAloneReport(mentions) {
|
|
|
31896
31912
|
const full = [];
|
|
31897
31913
|
const prose = new Map;
|
|
31898
31914
|
const others = new Map;
|
|
31899
|
-
const
|
|
31900
|
-
|
|
31901
|
-
|
|
31915
|
+
const counts = { quoted: 0, inProse: 0, otherSymbols: 0 };
|
|
31916
|
+
const add = (lines, line) => {
|
|
31917
|
+
if (!lines.includes(line)) {
|
|
31918
|
+
lines.push(line);
|
|
31902
31919
|
}
|
|
31903
31920
|
};
|
|
31921
|
+
const textOf = new Map;
|
|
31922
|
+
for (const mention of mentions) {
|
|
31923
|
+
textOf.set(`${mention.file}:${String(mention.line)}`, mention.text);
|
|
31924
|
+
}
|
|
31904
31925
|
for (const mention of mentions) {
|
|
31905
|
-
if ((mention.kind
|
|
31926
|
+
if (PROSE_KINDS.has(mention.kind) && mention.why === undefined) {
|
|
31906
31927
|
const key = `${mention.file}
|
|
31907
31928
|
${mention.kind}`;
|
|
31908
31929
|
const group = prose.get(key) ?? { file: mention.file, kind: mention.kind, lines: [] };
|
|
31909
|
-
add(group, mention.line);
|
|
31930
|
+
add(group.lines, mention.line);
|
|
31910
31931
|
prose.set(key, group);
|
|
31932
|
+
counts.inProse += 1;
|
|
31911
31933
|
} else if (mention.kind === "code" && (mention.why === NOT_INHERITED || mention.why === RESOLVED_ELSEWHERE)) {
|
|
31912
|
-
const
|
|
31913
|
-
|
|
31914
|
-
|
|
31915
|
-
|
|
31916
|
-
others.set(
|
|
31934
|
+
const files = others.get(mention.why) ?? new Map;
|
|
31935
|
+
const lines = files.get(mention.file) ?? [];
|
|
31936
|
+
add(lines, mention.line);
|
|
31937
|
+
files.set(mention.file, lines);
|
|
31938
|
+
others.set(mention.why, files);
|
|
31939
|
+
counts.otherSymbols += 1;
|
|
31917
31940
|
} else {
|
|
31918
31941
|
full.push(mention);
|
|
31942
|
+
counts.quoted += 1;
|
|
31919
31943
|
}
|
|
31920
31944
|
}
|
|
31921
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)}`) ?? "" }));
|
|
31922
31965
|
return {
|
|
31923
|
-
|
|
31924
|
-
|
|
31925
|
-
|
|
31966
|
+
lists: {
|
|
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)
|
|
31974
|
+
}))
|
|
31975
|
+
}
|
|
31976
|
+
},
|
|
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
|
+
}
|
|
31926
31989
|
};
|
|
31927
31990
|
}
|
|
31928
|
-
|
|
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
|
+
}
|
|
32006
|
+
var PROSE_KINDS = new Set(["comment", "doc", "string", "text"]);
|
|
32007
|
+
function summaryOf(edits, mentions, rewrites, left) {
|
|
31929
32008
|
const count = (values) => {
|
|
31930
32009
|
const counted = {};
|
|
31931
32010
|
for (const value of values) {
|
|
@@ -31937,13 +32016,13 @@ function summaryOf(edits, mentions, rewrites) {
|
|
|
31937
32016
|
filesChanged: rewrites.length,
|
|
31938
32017
|
edits: edits.length,
|
|
31939
32018
|
editsByKind: count(edits.map((edit) => edit.kind)),
|
|
31940
|
-
leftAlone: mentions.length,
|
|
32019
|
+
leftAlone: { total: mentions.length, ...left },
|
|
31941
32020
|
leftAloneByKind: count(mentions.map((mention) => mention.kind))
|
|
31942
32021
|
};
|
|
31943
32022
|
}
|
|
31944
32023
|
|
|
31945
32024
|
// src/restart-note.ts
|
|
31946
|
-
import { mkdirSync as
|
|
32025
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync16, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
31947
32026
|
import { dirname as dirname11, join as join17 } from "node:path";
|
|
31948
32027
|
function restartNotePath(projectPath) {
|
|
31949
32028
|
return join17(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -31951,8 +32030,8 @@ function restartNotePath(projectPath) {
|
|
|
31951
32030
|
function noteRestartBegun(note) {
|
|
31952
32031
|
const path = restartNotePath(note.projectPath);
|
|
31953
32032
|
try {
|
|
31954
|
-
|
|
31955
|
-
|
|
32033
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
32034
|
+
writeFileSync11(path, `${JSON.stringify(note, null, 2)}
|
|
31956
32035
|
`, "utf8");
|
|
31957
32036
|
} catch (error) {
|
|
31958
32037
|
console.error(`[SERVER] Could not record the restart at ${path}: ${errorMessage(error)}`);
|
|
@@ -31975,7 +32054,7 @@ function restartOwed(projectPath) {
|
|
|
31975
32054
|
}
|
|
31976
32055
|
function restartSettled(projectPath) {
|
|
31977
32056
|
try {
|
|
31978
|
-
|
|
32057
|
+
rmSync7(restartNotePath(projectPath), { force: true });
|
|
31979
32058
|
} catch (error) {
|
|
31980
32059
|
console.error(`[SERVER] Could not clear the restart note: ${errorMessage(error)}`);
|
|
31981
32060
|
}
|
|
@@ -31985,14 +32064,14 @@ function restartSettled(projectPath) {
|
|
|
31985
32064
|
import { execFile as execFile4 } from "node:child_process";
|
|
31986
32065
|
import { createHash as createHash3 } from "node:crypto";
|
|
31987
32066
|
import {
|
|
31988
|
-
mkdirSync as
|
|
32067
|
+
mkdirSync as mkdirSync10,
|
|
31989
32068
|
openSync as openSync2,
|
|
31990
|
-
readdirSync as
|
|
32069
|
+
readdirSync as readdirSync7,
|
|
31991
32070
|
readFileSync as readFileSync17,
|
|
31992
32071
|
realpathSync as realpathSync6,
|
|
31993
|
-
rmSync as
|
|
32072
|
+
rmSync as rmSync8,
|
|
31994
32073
|
statSync as statSync6,
|
|
31995
|
-
writeFileSync as
|
|
32074
|
+
writeFileSync as writeFileSync12
|
|
31996
32075
|
} from "node:fs";
|
|
31997
32076
|
import { basename as basename4, dirname as dirname12, join as join18, resolve as resolve6 } from "node:path";
|
|
31998
32077
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -32026,7 +32105,7 @@ function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
|
32026
32105
|
}
|
|
32027
32106
|
var SHARED_NOTE = "run.json";
|
|
32028
32107
|
function openTranscript(startedAt) {
|
|
32029
|
-
|
|
32108
|
+
mkdirSync10(runsDirectory(), { recursive: true });
|
|
32030
32109
|
const path = join18(runsDirectory(), `run-${startedAt}.log`);
|
|
32031
32110
|
return { path, fd: openSync2(path, "a") };
|
|
32032
32111
|
}
|
|
@@ -32037,8 +32116,8 @@ function editorNotePath(projectPath, directory = runtimeDirectory()) {
|
|
|
32037
32116
|
return join18(directory, "runs", `editor-${projectKey(projectPath)}.json`);
|
|
32038
32117
|
}
|
|
32039
32118
|
function writeEditorRunNote(note) {
|
|
32040
|
-
|
|
32041
|
-
|
|
32119
|
+
mkdirSync10(runsDirectory(), { recursive: true });
|
|
32120
|
+
writeFileSync12(editorNotePath(note.projectPath), JSON.stringify(note, null, 2), "utf8");
|
|
32042
32121
|
}
|
|
32043
32122
|
function readEditorRunNote(projectPath) {
|
|
32044
32123
|
for (const directory of runtimeDirectories()) {
|
|
@@ -32088,7 +32167,7 @@ function everyRunRecord() {
|
|
|
32088
32167
|
for (const directory of runtimeDirectories()) {
|
|
32089
32168
|
let entries;
|
|
32090
32169
|
try {
|
|
32091
|
-
entries =
|
|
32170
|
+
entries = readdirSync7(join18(directory, "runs"));
|
|
32092
32171
|
} catch {
|
|
32093
32172
|
continue;
|
|
32094
32173
|
}
|
|
@@ -32308,7 +32387,7 @@ function clearRunRecord(projectPath) {
|
|
|
32308
32387
|
const ours = sharedRecord !== null && sharedRecord.projectPath !== "" && isSameDirectory(sharedRecord.projectPath, projectPath);
|
|
32309
32388
|
for (const path of [runRecordPath(projectPath, directory), ...ours ? [shared] : []]) {
|
|
32310
32389
|
try {
|
|
32311
|
-
|
|
32390
|
+
rmSync8(path, { force: true });
|
|
32312
32391
|
} catch {}
|
|
32313
32392
|
}
|
|
32314
32393
|
}
|
|
@@ -32325,7 +32404,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
32325
32404
|
const kept = new Set(everyRunRecord().map((record) => record.transcript));
|
|
32326
32405
|
let entries;
|
|
32327
32406
|
try {
|
|
32328
|
-
entries =
|
|
32407
|
+
entries = readdirSync7(directory);
|
|
32329
32408
|
} catch {
|
|
32330
32409
|
return;
|
|
32331
32410
|
}
|
|
@@ -32338,7 +32417,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
32338
32417
|
continue;
|
|
32339
32418
|
}
|
|
32340
32419
|
try {
|
|
32341
|
-
|
|
32420
|
+
rmSync8(path);
|
|
32342
32421
|
} catch {}
|
|
32343
32422
|
}
|
|
32344
32423
|
}
|
|
@@ -32349,13 +32428,13 @@ import { createHash as createHash4 } from "node:crypto";
|
|
|
32349
32428
|
import {
|
|
32350
32429
|
cpSync,
|
|
32351
32430
|
existsSync as existsSync15,
|
|
32352
|
-
mkdirSync as
|
|
32353
|
-
readdirSync as
|
|
32431
|
+
mkdirSync as mkdirSync11,
|
|
32432
|
+
readdirSync as readdirSync8,
|
|
32354
32433
|
readFileSync as readFileSync18,
|
|
32355
32434
|
rmdirSync,
|
|
32356
|
-
rmSync as
|
|
32435
|
+
rmSync as rmSync9,
|
|
32357
32436
|
statSync as statSync7,
|
|
32358
|
-
writeFileSync as
|
|
32437
|
+
writeFileSync as writeFileSync13
|
|
32359
32438
|
} from "node:fs";
|
|
32360
32439
|
import { dirname as dirname13, join as join19 } from "node:path";
|
|
32361
32440
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -32377,7 +32456,7 @@ function runtimeAddonDigest(from = shippedAddonsDirectory()) {
|
|
|
32377
32456
|
function addonsDigest(names, from) {
|
|
32378
32457
|
const hash = createHash4("sha256");
|
|
32379
32458
|
const walk = (directory, relative) => {
|
|
32380
|
-
for (const name of
|
|
32459
|
+
for (const name of readdirSync8(directory).sort()) {
|
|
32381
32460
|
if (name === VERSION_MARKER || name === DIGEST_MARKER) {
|
|
32382
32461
|
continue;
|
|
32383
32462
|
}
|
|
@@ -33111,7 +33190,7 @@ var TOOL_SPECS = [
|
|
|
33111
33190
|
},
|
|
33112
33191
|
{
|
|
33113
33192
|
name: "script_edit",
|
|
33114
|
-
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
|
|
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, 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.",
|
|
33115
33194
|
parameters: {
|
|
33116
33195
|
projectPath: PROJECT_PATH,
|
|
33117
33196
|
scriptPath: SCRIPT_PATH,
|
|
@@ -34397,7 +34476,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
34397
34476
|
...problems.omitted === 0 ? {} : { entriesOmitted: problems.omitted }
|
|
34398
34477
|
};
|
|
34399
34478
|
if (verdict.exported) {
|
|
34400
|
-
return { content: [{ type: "text", text:
|
|
34479
|
+
return { content: [{ type: "text", text: answerJson(verdict) }] };
|
|
34401
34480
|
}
|
|
34402
34481
|
const stale = !written && after !== null ? ` The ${asked.outputPath} there is from before this export, which did not write it.` : "";
|
|
34403
34482
|
const why = ending.exitSignal === null ? stale : ` The engine was ${howItEnded(ending)}, so it has no exit code.${stale}`;
|
|
@@ -34407,7 +34486,7 @@ function exportAnswer(ending, asked, before, after) {
|
|
|
34407
34486
|
type: "text",
|
|
34408
34487
|
text: `Export with preset '${asked.preset}' did not produce ${asked.outputPath}.${why}`
|
|
34409
34488
|
},
|
|
34410
|
-
{ type: "text", text:
|
|
34489
|
+
{ type: "text", text: answerJson(verdict) }
|
|
34411
34490
|
],
|
|
34412
34491
|
isError: true
|
|
34413
34492
|
};
|
|
@@ -34554,7 +34633,7 @@ function elsewhereIn(projectPath, asked) {
|
|
|
34554
34633
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
34555
34634
|
let near = [];
|
|
34556
34635
|
try {
|
|
34557
|
-
near =
|
|
34636
|
+
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()));
|
|
34558
34637
|
} catch {
|
|
34559
34638
|
return "";
|
|
34560
34639
|
}
|
|
@@ -34656,7 +34735,7 @@ class GodotServer {
|
|
|
34656
34735
|
return response;
|
|
34657
34736
|
}
|
|
34658
34737
|
jsonTextResponse(payload) {
|
|
34659
|
-
return { content: [{ type: "text", text:
|
|
34738
|
+
return { content: [{ type: "text", text: answerJson(payload) }] };
|
|
34660
34739
|
}
|
|
34661
34740
|
async run() {
|
|
34662
34741
|
const located = await this.locator.find();
|
|
@@ -34989,7 +35068,7 @@ class GodotServer {
|
|
|
34989
35068
|
saying(answer, block) {
|
|
34990
35069
|
return {
|
|
34991
35070
|
...answer,
|
|
34992
|
-
content: [...answer.content, { type: "text", text:
|
|
35071
|
+
content: [...answer.content, { type: "text", text: answerJson(block) }]
|
|
34993
35072
|
};
|
|
34994
35073
|
}
|
|
34995
35074
|
projectHasMovedOn() {
|
|
@@ -35962,7 +36041,7 @@ class GodotServer {
|
|
|
35962
36041
|
if (!outcome.ok) {
|
|
35963
36042
|
const response = this.createErrorResponse(outcome.message);
|
|
35964
36043
|
if (Object.keys(extras).length > 0) {
|
|
35965
|
-
response.content.push({ type: "text", text:
|
|
36044
|
+
response.content.push({ type: "text", text: answerJson(extras) });
|
|
35966
36045
|
}
|
|
35967
36046
|
return response;
|
|
35968
36047
|
}
|
|
@@ -36040,7 +36119,7 @@ class GodotServer {
|
|
|
36040
36119
|
}
|
|
36041
36120
|
const folder = dirname14(output.absolutePath);
|
|
36042
36121
|
try {
|
|
36043
|
-
|
|
36122
|
+
mkdirSync12(folder, { recursive: true });
|
|
36044
36123
|
} catch (error) {
|
|
36045
36124
|
return this.createErrorResponse(`Cannot create ${dirname14(output.relativePath)} to export into: ${errorMessage(error)}`);
|
|
36046
36125
|
}
|
|
@@ -36151,7 +36230,7 @@ class GodotServer {
|
|
|
36151
36230
|
let report = null;
|
|
36152
36231
|
let reportProblem = null;
|
|
36153
36232
|
try {
|
|
36154
|
-
const written = existsSync16(reportsDir) ?
|
|
36233
|
+
const written = existsSync16(reportsDir) ? readdirSync9(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
36155
36234
|
const newest = written.at(-1);
|
|
36156
36235
|
if (newest !== undefined) {
|
|
36157
36236
|
report = parseJUnit(readFileSync19(join20(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -38662,6 +38741,15 @@ class GodotServer {
|
|
|
38662
38741
|
const said = outcome.conflicts === undefined ? "" : ` ${outcome.conflicts.join("; ")}.`;
|
|
38663
38742
|
return this.createErrorResponse(`${outcome.reason}${said}`, outcome.advice ?? []);
|
|
38664
38743
|
}
|
|
38744
|
+
if (outcome.detail !== null) {
|
|
38745
|
+
const file = writeLeftAloneDetail(projectPath, symbol, outcome.detail);
|
|
38746
|
+
const folded = asParams(outcome.report["leftAloneDetail"]);
|
|
38747
|
+
outcome.report["leftAloneDetail"] = {
|
|
38748
|
+
file,
|
|
38749
|
+
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.`,
|
|
38750
|
+
...folded
|
|
38751
|
+
};
|
|
38752
|
+
}
|
|
38665
38753
|
if (readBoolean(args, "preview") === true) {
|
|
38666
38754
|
return this.jsonTextResponse({ preview: true, ...outcome.report });
|
|
38667
38755
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.39",
|
|
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",
|