gdharness 0.13.23 → 0.13.25
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 +19 -9
- package/build/index.js +9 -4
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -7619,6 +7619,11 @@ function contradictedDiagnostics(messages, classes, sourceOf) {
|
|
|
7619
7619
|
}
|
|
7620
7620
|
return found;
|
|
7621
7621
|
}
|
|
7622
|
+
function staleAnalysisNote(contradicted, dependsOn) {
|
|
7623
|
+
const declaring = [...new Set(contradicted.map((one) => one.declaredIn))].sort();
|
|
7624
|
+
const lever = dependsOn.length === 0 ? ", and the named types depend on no other global class, so that lever is not available here. " + "That is the common case rather than the awkward one: an edit near a type that depends on " + "something refreshes it before the fault is noticed, which is why a type with no " + "dependencies is where this turns up" : `, so changing ${[...dependsOn].sort().join(", ")} and rescanning is worth a try`;
|
|
7625
|
+
return `The editor is reporting against an older copy of ${contradicted.length === 1 ? "a type" : "some types"} ` + "named under contradictedByTheFile. Each member listed is declared in the file the class cache " + "points at, so those diagnostics are wrong however the code is written. Run editor_rescan first: " + "it costs about half a second, it cleared this in one of five attempts in the project that " + "reported it, and it cleared both reproductions measured in a second project, the scan itself " + "returning in 243ms and 275ms. " + "The fault behind it is that a script the editor has loaded keeps the copy it built, and nothing " + `rebuilds that copy when the file changes; editor_rescan with reloadScript set to ${declaring.join(", ")} ` + `recompiles ${declaring.length === 1 ? "that copy" : "those copies"} from the file into the same ` + "object and answers with the members it has afterwards under reloadedMethods. Read that and the " + "next diagnostics as two readings rather than one: a built copy has been seen stale here while " + "the diagnostics on it read clean, so the reload is worth doing and is not known to be what " + "clears these. The other lever measured is that a held type is refreshed when something it " + `depends on changes rather than when it changes itself${lever}. editor_launch restart has always ` + "worked and costs a window. project_import refresh_classes does not, and answers added: [] while " + "this is happening.";
|
|
7626
|
+
}
|
|
7622
7627
|
function cacheWrittenAt(projectPath) {
|
|
7623
7628
|
const cache = join6(projectPath, ".godot", "global_script_class_cache.cfg");
|
|
7624
7629
|
try {
|
|
@@ -15231,6 +15236,9 @@ function opTakes(spec, op, name) {
|
|
|
15231
15236
|
function argumentsOf(spec, op) {
|
|
15232
15237
|
return Object.keys(spec.parameters).filter((name) => opTakes(spec, op, name));
|
|
15233
15238
|
}
|
|
15239
|
+
function toolsWithoutProjectPath() {
|
|
15240
|
+
return TOOL_SPECS.filter((spec) => !Object.hasOwn(spec.parameters, "projectPath")).map((spec) => spec.name).sort();
|
|
15241
|
+
}
|
|
15234
15242
|
function toolSpec(name) {
|
|
15235
15243
|
return SPECS_BY_NAME[name];
|
|
15236
15244
|
}
|
|
@@ -15961,13 +15969,13 @@ var init_tool_definitions = __esm(() => {
|
|
|
15961
15969
|
},
|
|
15962
15970
|
{
|
|
15963
15971
|
name: "editor_rescan",
|
|
15964
|
-
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. The scan is a change-detecting walk rather than an unconditional reparse, so a file another engine has already imported reads as settled and the walk does not look inside it: its class_name then stays out of the list the editor resolves against, however many times you scan. Any class in that state is named under unseenByEditor, which is what no check on disk can see, since the declaration and the cache are both correct there and only the editor disagrees. The cure
|
|
15972
|
+
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. The scan is a change-detecting walk rather than an unconditional reparse, so a file another engine has already imported reads as settled and the walk does not look inside it: its class_name then stays out of the list the editor resolves against, however many times you scan. Any class in that state is named under unseenByEditor, which is what no check on disk can see, since the declaration and the cache are both correct there and only the editor disagrees. The cure is this call on its own, with no change to the declaring script: measured against a real editor on three platforms, with idle waits of the same length ruled out so the scan is credited rather than the time it takes, and reproduced in a second project against its own reproduction in 203ms. editor_launch restart also does it and costs a window, and project_import refresh_classes does not: it rewrites the cache and does not touch what the editor is holding. A scan writes .godot/global_script_class_cache.cfg from the list the editor is holding, so a class the editor cannot resolve goes out of that file with it. That is not a reason to refuse the scan, because on a class the editor has merely not walked yet the scan is the cure; what the answer does instead is name the loss under cacheLost and rebuild the cache from the files, naming what came back under cacheRestored, so no fresh engine, CI run or clone inherits the short file. An editor that lost classes is still holding the short list, so the note says to restart it before scanning again. Needs the editor connected.",
|
|
15965
15973
|
parameters: {
|
|
15966
15974
|
projectPath: PROJECT_PATH,
|
|
15967
15975
|
timeoutMs: { type: "number", description: "How long to wait for the scan. Default 30000." },
|
|
15968
15976
|
reloadScript: {
|
|
15969
15977
|
type: "string",
|
|
15970
|
-
description: "A script to recompile in the editor after the scan, for the
|
|
15978
|
+
description: "A script to recompile in the editor after the scan, for the half a scan does not reach: a script the editor has loaded keeps the copy it built, that copy is refreshed when one of its dependencies changes rather than when it changes itself, and a scan leaves it alone. Measured here, a built copy comes back without a method added to it while script_diagnostics on the same script reads clean in the same window, so the copy the editor built and whatever the analyser resolves types against are not known to be one thing: reload for the copy, and read the diagnostics as a separate answer rather than as this one confirmed. This recompiles into the same object, so the holders that kept the stale copy alive see the new one. The methods it has afterwards come back under reloadedMethods, because a reload that compiled nothing and answered OK is the failure worth catching."
|
|
15971
15979
|
}
|
|
15972
15980
|
},
|
|
15973
15981
|
requires: ["projectPath"]
|
|
@@ -38130,7 +38138,7 @@ class GodotServer {
|
|
|
38130
38138
|
}
|
|
38131
38139
|
}
|
|
38132
38140
|
}
|
|
38133
|
-
notes.push(
|
|
38141
|
+
notes.push(staleAnalysisNote(contradicted, [...dependsOn]));
|
|
38134
38142
|
}
|
|
38135
38143
|
const uncached = unloaded.filter((type) => !type.inTheClassCache);
|
|
38136
38144
|
if (uncached.length > 0) {
|
|
@@ -39020,7 +39028,7 @@ class GodotServer {
|
|
|
39020
39028
|
cacheLost: lost.length > 0 ? lost : undefined,
|
|
39021
39029
|
cacheRestored: restored.length > 0 ? restored : undefined,
|
|
39022
39030
|
classesUnchecked: checked.unchecked,
|
|
39023
|
-
note: busy ? "The editor was still scanning or importing when the wait ran out, so new files may not be visible yet." : stillGone.length > 0 ? "The scan wrote the class cache from the list this editor is holding, that list is shorter than the file was, and rebuilding the cache from the files did not bring these back. Every engine that reads the cache next, including a test run, will report them as unknown identifiers. Restart the editor with editor_launch restart before scanning again." : lost.length > 0 ? "The scan wrote the class cache from the list this editor is holding, which is shorter than the file was, so the cache was rebuilt from the files and these classes are back in it. Nothing was lost, but this editor is still holding the short list: do not rescan again until it has been restarted with editor_launch restart, because it will write the same list over the file each time." : unseen.length > 0 ? "The scan finished and these classes are still not in the list the editor resolves against, so every use of them reads as an unknown identifier. Its walk skips a file another engine has already imported.
|
|
39031
|
+
note: busy ? "The editor was still scanning or importing when the wait ran out, so new files may not be visible yet." : stillGone.length > 0 ? "The scan wrote the class cache from the list this editor is holding, that list is shorter than the file was, and rebuilding the cache from the files did not bring these back. Every engine that reads the cache next, including a test run, will report them as unknown identifiers. Restart the editor with editor_launch restart before scanning again." : lost.length > 0 ? "The scan wrote the class cache from the list this editor is holding, which is shorter than the file was, so the cache was rebuilt from the files and these classes are back in it. Nothing was lost, but this editor is still holding the short list: do not rescan again until it has been restarted with editor_launch restart, because it will write the same list over the file each time." : unseen.length > 0 ? "The scan finished and these classes are still not in the list the editor resolves against, so every use of them reads as an unknown identifier. Its walk skips a file another engine has already imported. Rescan again on its own, which is the measured cure and needs no change to the declaring script, or restart the editor with editor_launch restart." : undefined
|
|
39024
39032
|
});
|
|
39025
39033
|
}
|
|
39026
39034
|
async rebuildCacheAfterLoss(projectPath, lost) {
|
|
@@ -40639,9 +40647,10 @@ function renderToolsMarkdown() {
|
|
|
40639
40647
|
`${TOOL_SPECS.length} tools, named \`domain_verb\`. A tool that does several related things takes an`,
|
|
40640
40648
|
"`op`. An unknown op or argument is refused with the valid set listed. Generated from the server.",
|
|
40641
40649
|
"",
|
|
40642
|
-
|
|
40643
|
-
"
|
|
40644
|
-
"
|
|
40650
|
+
`Every call takes \`projectPath\` except ${toolsWithoutProjectPath().map((name) => `\`${name}\``).join(", ")}, which take none: the \`runtime_*\` and \`debug_*\` ones pick between running games`,
|
|
40651
|
+
"instead, and the others answer about the editor on this server. An argument a tool does not",
|
|
40652
|
+
"declare is refused rather than ignored. Answers are read from the engine after the change, not",
|
|
40653
|
+
"echoed from the request. Engine stderr comes back under `engine_messages`.",
|
|
40645
40654
|
"",
|
|
40646
40655
|
...headlessSection()
|
|
40647
40656
|
];
|
|
@@ -40697,8 +40706,9 @@ that is running, and the project on disk. ${TOOL_SPECS.length} tools, named \`do
|
|
|
40697
40706
|
|
|
40698
40707
|
## Start here
|
|
40699
40708
|
|
|
40700
|
-
- Every call takes \`projectPath
|
|
40701
|
-
|
|
40709
|
+
- Every call takes \`projectPath\` except ${toolsWithoutProjectPath().map((name) => `\`${name}\``).join(", ")}, which take none. The \`runtime_*\` and \`debug_*\` ones pick between running
|
|
40710
|
+
games instead; the others answer about the editor this server is connected to. There is no
|
|
40711
|
+
ambient project, and an argument a tool does not declare is refused rather than ignored.
|
|
40702
40712
|
- \`editor_status\` says whether an editor is connected and whether its addon matches the server.
|
|
40703
40713
|
\`addonIsStale\` means they differ, and \`staleNote\` says which half is behind: an editor that
|
|
40704
40714
|
needs restarting, or a server that needs reconnecting in your harness. Every answer that came
|
package/build/index.js
CHANGED
|
@@ -24879,6 +24879,11 @@ function contradictedDiagnostics(messages, classes, sourceOf) {
|
|
|
24879
24879
|
}
|
|
24880
24880
|
return found;
|
|
24881
24881
|
}
|
|
24882
|
+
function staleAnalysisNote(contradicted, dependsOn) {
|
|
24883
|
+
const declaring = [...new Set(contradicted.map((one) => one.declaredIn))].sort();
|
|
24884
|
+
const lever = dependsOn.length === 0 ? ", and the named types depend on no other global class, so that lever is not available here. " + "That is the common case rather than the awkward one: an edit near a type that depends on " + "something refreshes it before the fault is noticed, which is why a type with no " + "dependencies is where this turns up" : `, so changing ${[...dependsOn].sort().join(", ")} and rescanning is worth a try`;
|
|
24885
|
+
return `The editor is reporting against an older copy of ${contradicted.length === 1 ? "a type" : "some types"} ` + "named under contradictedByTheFile. Each member listed is declared in the file the class cache " + "points at, so those diagnostics are wrong however the code is written. Run editor_rescan first: " + "it costs about half a second, it cleared this in one of five attempts in the project that " + "reported it, and it cleared both reproductions measured in a second project, the scan itself " + "returning in 243ms and 275ms. " + "The fault behind it is that a script the editor has loaded keeps the copy it built, and nothing " + `rebuilds that copy when the file changes; editor_rescan with reloadScript set to ${declaring.join(", ")} ` + `recompiles ${declaring.length === 1 ? "that copy" : "those copies"} from the file into the same ` + "object and answers with the members it has afterwards under reloadedMethods. Read that and the " + "next diagnostics as two readings rather than one: a built copy has been seen stale here while " + "the diagnostics on it read clean, so the reload is worth doing and is not known to be what " + "clears these. The other lever measured is that a held type is refreshed when something it " + `depends on changes rather than when it changes itself${lever}. editor_launch restart has always ` + "worked and costs a window. project_import refresh_classes does not, and answers added: [] while " + "this is happening.";
|
|
24886
|
+
}
|
|
24882
24887
|
function cacheWrittenAt(projectPath) {
|
|
24883
24888
|
const cache = join3(projectPath, ".godot", "global_script_class_cache.cfg");
|
|
24884
24889
|
try {
|
|
@@ -29078,13 +29083,13 @@ var TOOL_SPECS = [
|
|
|
29078
29083
|
},
|
|
29079
29084
|
{
|
|
29080
29085
|
name: "editor_rescan",
|
|
29081
|
-
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. The scan is a change-detecting walk rather than an unconditional reparse, so a file another engine has already imported reads as settled and the walk does not look inside it: its class_name then stays out of the list the editor resolves against, however many times you scan. Any class in that state is named under unseenByEditor, which is what no check on disk can see, since the declaration and the cache are both correct there and only the editor disagrees. The cure
|
|
29086
|
+
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. The scan is a change-detecting walk rather than an unconditional reparse, so a file another engine has already imported reads as settled and the walk does not look inside it: its class_name then stays out of the list the editor resolves against, however many times you scan. Any class in that state is named under unseenByEditor, which is what no check on disk can see, since the declaration and the cache are both correct there and only the editor disagrees. The cure is this call on its own, with no change to the declaring script: measured against a real editor on three platforms, with idle waits of the same length ruled out so the scan is credited rather than the time it takes, and reproduced in a second project against its own reproduction in 203ms. editor_launch restart also does it and costs a window, and project_import refresh_classes does not: it rewrites the cache and does not touch what the editor is holding. A scan writes .godot/global_script_class_cache.cfg from the list the editor is holding, so a class the editor cannot resolve goes out of that file with it. That is not a reason to refuse the scan, because on a class the editor has merely not walked yet the scan is the cure; what the answer does instead is name the loss under cacheLost and rebuild the cache from the files, naming what came back under cacheRestored, so no fresh engine, CI run or clone inherits the short file. An editor that lost classes is still holding the short list, so the note says to restart it before scanning again. Needs the editor connected.",
|
|
29082
29087
|
parameters: {
|
|
29083
29088
|
projectPath: PROJECT_PATH,
|
|
29084
29089
|
timeoutMs: { type: "number", description: "How long to wait for the scan. Default 30000." },
|
|
29085
29090
|
reloadScript: {
|
|
29086
29091
|
type: "string",
|
|
29087
|
-
description: "A script to recompile in the editor after the scan, for the
|
|
29092
|
+
description: "A script to recompile in the editor after the scan, for the half a scan does not reach: a script the editor has loaded keeps the copy it built, that copy is refreshed when one of its dependencies changes rather than when it changes itself, and a scan leaves it alone. Measured here, a built copy comes back without a method added to it while script_diagnostics on the same script reads clean in the same window, so the copy the editor built and whatever the analyser resolves types against are not known to be one thing: reload for the copy, and read the diagnostics as a separate answer rather than as this one confirmed. This recompiles into the same object, so the holders that kept the stale copy alive see the new one. The methods it has afterwards come back under reloadedMethods, because a reload that compiled nothing and answered OK is the failure worth catching."
|
|
29088
29093
|
}
|
|
29089
29094
|
},
|
|
29090
29095
|
requires: ["projectPath"]
|
|
@@ -30882,7 +30887,7 @@ class GodotServer {
|
|
|
30882
30887
|
}
|
|
30883
30888
|
}
|
|
30884
30889
|
}
|
|
30885
|
-
notes.push(
|
|
30890
|
+
notes.push(staleAnalysisNote(contradicted, [...dependsOn]));
|
|
30886
30891
|
}
|
|
30887
30892
|
const uncached = unloaded.filter((type) => !type.inTheClassCache);
|
|
30888
30893
|
if (uncached.length > 0) {
|
|
@@ -31772,7 +31777,7 @@ class GodotServer {
|
|
|
31772
31777
|
cacheLost: lost.length > 0 ? lost : undefined,
|
|
31773
31778
|
cacheRestored: restored.length > 0 ? restored : undefined,
|
|
31774
31779
|
classesUnchecked: checked.unchecked,
|
|
31775
|
-
note: busy ? "The editor was still scanning or importing when the wait ran out, so new files may not be visible yet." : stillGone.length > 0 ? "The scan wrote the class cache from the list this editor is holding, that list is shorter than the file was, and rebuilding the cache from the files did not bring these back. Every engine that reads the cache next, including a test run, will report them as unknown identifiers. Restart the editor with editor_launch restart before scanning again." : lost.length > 0 ? "The scan wrote the class cache from the list this editor is holding, which is shorter than the file was, so the cache was rebuilt from the files and these classes are back in it. Nothing was lost, but this editor is still holding the short list: do not rescan again until it has been restarted with editor_launch restart, because it will write the same list over the file each time." : unseen.length > 0 ? "The scan finished and these classes are still not in the list the editor resolves against, so every use of them reads as an unknown identifier. Its walk skips a file another engine has already imported.
|
|
31780
|
+
note: busy ? "The editor was still scanning or importing when the wait ran out, so new files may not be visible yet." : stillGone.length > 0 ? "The scan wrote the class cache from the list this editor is holding, that list is shorter than the file was, and rebuilding the cache from the files did not bring these back. Every engine that reads the cache next, including a test run, will report them as unknown identifiers. Restart the editor with editor_launch restart before scanning again." : lost.length > 0 ? "The scan wrote the class cache from the list this editor is holding, which is shorter than the file was, so the cache was rebuilt from the files and these classes are back in it. Nothing was lost, but this editor is still holding the short list: do not rescan again until it has been restarted with editor_launch restart, because it will write the same list over the file each time." : unseen.length > 0 ? "The scan finished and these classes are still not in the list the editor resolves against, so every use of them reads as an unknown identifier. Its walk skips a file another engine has already imported. Rescan again on its own, which is the measured cure and needs no change to the declaring script, or restart the editor with editor_launch restart." : undefined
|
|
31776
31781
|
});
|
|
31777
31782
|
}
|
|
31778
31783
|
async rebuildCacheAfterLoss(projectPath, lost) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.25",
|
|
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",
|