gdharness 1.3.43 → 1.3.44
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 +321 -234
- package/build/godot/addons/gdharness_editor/reading.gd +14 -5
- package/build/godot/addons/gdharness_editor/scene_file.gd +18 -1
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +31 -12
- package/build/godot/addons/gdharness_runtime/reading.gd +14 -5
- package/build/godot/operations/dependencies.gd +51 -16
- package/build/godot/operations/editor_tools.gd +5 -4
- package/build/godot/operations/project_config.gd +8 -3
- package/build/godot/operations/reading.gd +14 -5
- package/build/keeper.js +43 -43
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -9723,8 +9723,71 @@ var init_gdscript_source = __esm(() => {
|
|
|
9723
9723
|
]);
|
|
9724
9724
|
});
|
|
9725
9725
|
|
|
9726
|
+
// src/whole-file.ts
|
|
9727
|
+
import { readFileSync as readFileSync5, renameSync, rmSync as rmSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
9728
|
+
function readWhole(path) {
|
|
9729
|
+
const until = Date.now() + HELD_FILE_MS;
|
|
9730
|
+
for (;; ) {
|
|
9731
|
+
try {
|
|
9732
|
+
return readFileSync5(path, "utf8");
|
|
9733
|
+
} catch (error) {
|
|
9734
|
+
const code = error.code ?? "";
|
|
9735
|
+
if (code === "ENOENT") {
|
|
9736
|
+
return null;
|
|
9737
|
+
}
|
|
9738
|
+
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
9739
|
+
throw error;
|
|
9740
|
+
}
|
|
9741
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
}
|
|
9745
|
+
function writeWhole(path, text) {
|
|
9746
|
+
const partial = `${path}.${process.pid}.partial`;
|
|
9747
|
+
try {
|
|
9748
|
+
writeFileSync4(partial, text, "utf8");
|
|
9749
|
+
} catch {
|
|
9750
|
+
return false;
|
|
9751
|
+
}
|
|
9752
|
+
const until = Date.now() + HELD_FILE_MS;
|
|
9753
|
+
for (;; ) {
|
|
9754
|
+
try {
|
|
9755
|
+
renameSync(partial, path);
|
|
9756
|
+
return true;
|
|
9757
|
+
} catch (error) {
|
|
9758
|
+
const code = error.code ?? "";
|
|
9759
|
+
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
9760
|
+
try {
|
|
9761
|
+
rmSync4(partial, { force: true });
|
|
9762
|
+
} catch {}
|
|
9763
|
+
return false;
|
|
9764
|
+
}
|
|
9765
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
function removeWhole(path) {
|
|
9770
|
+
const until = Date.now() + HELD_FILE_MS;
|
|
9771
|
+
for (;; ) {
|
|
9772
|
+
try {
|
|
9773
|
+
rmSync4(path, { force: true });
|
|
9774
|
+
return true;
|
|
9775
|
+
} catch (error) {
|
|
9776
|
+
const code = error.code ?? "";
|
|
9777
|
+
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
9778
|
+
return false;
|
|
9779
|
+
}
|
|
9780
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
9781
|
+
}
|
|
9782
|
+
}
|
|
9783
|
+
}
|
|
9784
|
+
var HELD_FILE_MS = 1000, HELD_FILE_RETRY_MS = 10, HELD_BY_A_READER;
|
|
9785
|
+
var init_whole_file = __esm(() => {
|
|
9786
|
+
HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
9787
|
+
});
|
|
9788
|
+
|
|
9726
9789
|
// src/class-cache.ts
|
|
9727
|
-
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as
|
|
9790
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
|
|
9728
9791
|
import { join as join6, posix } from "node:path";
|
|
9729
9792
|
function isToolScript(source) {
|
|
9730
9793
|
return TOOL.test(codeOf(source));
|
|
@@ -9799,7 +9862,7 @@ function eachScript(projectPath, each) {
|
|
|
9799
9862
|
if (entry.isDirectory()) {
|
|
9800
9863
|
visit(path, `${prefix}${entry.name}/`);
|
|
9801
9864
|
} else if (entry.isFile() && entry.name.endsWith(".gd")) {
|
|
9802
|
-
each(`res://${prefix}${entry.name}`,
|
|
9865
|
+
each(`res://${prefix}${entry.name}`, readFileSync6(path, "utf8"));
|
|
9803
9866
|
}
|
|
9804
9867
|
}
|
|
9805
9868
|
};
|
|
@@ -9832,12 +9895,11 @@ function scriptsDeclaring(projectPath, classes) {
|
|
|
9832
9895
|
return declaring.sort((a, b) => a.script.localeCompare(b.script));
|
|
9833
9896
|
}
|
|
9834
9897
|
function cachedClasses(projectPath) {
|
|
9835
|
-
const
|
|
9836
|
-
if (
|
|
9898
|
+
const text = readWhole(join6(projectPath, ".godot", "global_script_class_cache.cfg"));
|
|
9899
|
+
if (text === null) {
|
|
9837
9900
|
return null;
|
|
9838
9901
|
}
|
|
9839
9902
|
const listed = new Map;
|
|
9840
|
-
const text = readFileSync5(cache, "utf8");
|
|
9841
9903
|
for (const entry of text.matchAll(/"class":\s*&"([^"]+)"[\s\S]*?"path":\s*"([^"]+)"/g)) {
|
|
9842
9904
|
listed.set(entry[1] ?? "", entry[2] ?? "");
|
|
9843
9905
|
}
|
|
@@ -10126,7 +10188,8 @@ function failedReloadNote(failed) {
|
|
|
10126
10188
|
} else {
|
|
10127
10189
|
copy = `The copy the editor holds was compiled again from the text it was built from and changed even so${lost.length === 0 ? "" : `, and has lost ${lost.join(", ")}`}: anything diagnosed against it now is answered from what is left, and reloading it once it compiles rebuilds it.`;
|
|
10128
10190
|
}
|
|
10129
|
-
const
|
|
10191
|
+
const advice = failed.names.length === 0 ? "" : ` If they deny a member of ${failed.names.join(" or ")} that its file declares, the editor's copy of that class is behind: reload that class first with reloadScript and then this script, the order that cleared it in the one project that has met this.`;
|
|
10192
|
+
const order = failed.builtOn === undefined ? advice : ` ${failed.builtOn}${failed.builtOnUnchecked === true ? advice : ""}`;
|
|
10130
10193
|
return `${failed.script} did not compile: Godot answered ${answered}. ${copy} ` + `script_diagnostics on it gives the errors.${order}`;
|
|
10131
10194
|
}
|
|
10132
10195
|
function uncachedClassNote(types) {
|
|
@@ -10188,6 +10251,7 @@ function unseenByEditor(projectPath, editorHolds) {
|
|
|
10188
10251
|
var DECLARATION, TOOL, ABSTRACT_HEADER, UNKNOWN_CLASS;
|
|
10189
10252
|
var init_class_cache = __esm(() => {
|
|
10190
10253
|
init_gdscript_source();
|
|
10254
|
+
init_whole_file();
|
|
10191
10255
|
DECLARATION = /^(?:@[a-z_]+(?:\([^)\n]*\))?\s+)*class_name\s+([A-Za-z_][A-Za-z0-9_]*)/m;
|
|
10192
10256
|
TOOL = /^[ \t]*(?:@[a-z_]+(?:\([^)\n]*\))?[ \t]+)*@tool\b/m;
|
|
10193
10257
|
ABSTRACT_HEADER = /^((?:@[\p{L}_][\p{L}\p{N}_]*(?:\([^)]*\))?\s+)*)(?:class_name|extends)\s/mu;
|
|
@@ -10894,7 +10958,7 @@ var init_junit = __esm(() => {
|
|
|
10894
10958
|
});
|
|
10895
10959
|
|
|
10896
10960
|
// src/suite-judge.ts
|
|
10897
|
-
import { readFileSync as
|
|
10961
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
10898
10962
|
import { stripVTControlCharacters } from "node:util";
|
|
10899
10963
|
function secondsOf(time) {
|
|
10900
10964
|
let ms = 0;
|
|
@@ -11095,7 +11159,7 @@ function versionFault(said, wanted) {
|
|
|
11095
11159
|
function readExpected(file) {
|
|
11096
11160
|
const declared = (value) => typeof value === "object" && value !== null ? value : {};
|
|
11097
11161
|
try {
|
|
11098
|
-
const parsed = JSON.parse(
|
|
11162
|
+
const parsed = JSON.parse(readFileSync7(file, "utf8"));
|
|
11099
11163
|
const read = typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
11100
11164
|
return { errors: declared(read["errors"]), warnings: declared(read["warnings"]) };
|
|
11101
11165
|
} catch {
|
|
@@ -11417,9 +11481,9 @@ import {
|
|
|
11417
11481
|
openSync as openSync2,
|
|
11418
11482
|
readdirSync as readdirSync3,
|
|
11419
11483
|
readSync,
|
|
11420
|
-
rmSync as
|
|
11484
|
+
rmSync as rmSync5,
|
|
11421
11485
|
statSync as statSync5,
|
|
11422
|
-
writeFileSync as
|
|
11486
|
+
writeFileSync as writeFileSync5,
|
|
11423
11487
|
writeSync as writeSync2
|
|
11424
11488
|
} from "node:fs";
|
|
11425
11489
|
import { availableParallelism, freemem, totalmem } from "node:os";
|
|
@@ -11495,14 +11559,14 @@ function sweepRunDirectories(runs, kept = KEPT_RUN_DIRECTORIES) {
|
|
|
11495
11559
|
const named = /^(\d+)-(\d+)$/.exec(entry);
|
|
11496
11560
|
const pid = Number(named?.[2]);
|
|
11497
11561
|
if (!Number.isInteger(pid)) {
|
|
11498
|
-
|
|
11562
|
+
rmSync5(join7(runs, entry), { recursive: true, force: true });
|
|
11499
11563
|
} else if (!alive(pid)) {
|
|
11500
11564
|
ended.push({ entry, started: Number(named?.[1]) });
|
|
11501
11565
|
}
|
|
11502
11566
|
}
|
|
11503
11567
|
ended.sort((a, b) => b.started - a.started);
|
|
11504
11568
|
for (const { entry } of ended.slice(kept)) {
|
|
11505
|
-
|
|
11569
|
+
rmSync5(join7(runs, entry), { recursive: true, force: true });
|
|
11506
11570
|
}
|
|
11507
11571
|
}
|
|
11508
11572
|
function roomFor(most, processors, available, said = "of memory free", processorsSaid = `the machine has ${plural(processors, "processor")}`) {
|
|
@@ -11607,7 +11671,7 @@ async function watchedEngine(launch, args, directory, log, silenceSeconds, silen
|
|
|
11607
11671
|
piped = [helped.stdout, helped.stderr];
|
|
11608
11672
|
child = helped;
|
|
11609
11673
|
stop = () => {
|
|
11610
|
-
|
|
11674
|
+
writeFileSync5(stopFile, "");
|
|
11611
11675
|
};
|
|
11612
11676
|
} else {
|
|
11613
11677
|
const held = heldToCores(launch.cores, launch.godotPath, args);
|
|
@@ -11761,9 +11825,9 @@ function stillGoingSaid(tool, op, elapsedMs) {
|
|
|
11761
11825
|
const took = seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
11762
11826
|
return `${op === null || op === "" ? tool : `${tool} ${op}`} is still going; ${took} in.`;
|
|
11763
11827
|
}
|
|
11764
|
-
async function withCallSignal(signal, answer, progress, still) {
|
|
11828
|
+
async function withCallSignal(signal, answer, progress, still, slotWaits) {
|
|
11765
11829
|
if (progress === undefined) {
|
|
11766
|
-
return signal === undefined ? answer() : current.run({ signal, progress: undefined }, answer);
|
|
11830
|
+
return signal === undefined && slotWaits === undefined ? answer() : current.run({ signal, progress: undefined, slotWaits }, answer);
|
|
11767
11831
|
}
|
|
11768
11832
|
const began = Date.now();
|
|
11769
11833
|
const rising = risingOnly(progress);
|
|
@@ -11787,7 +11851,7 @@ async function withCallSignal(signal, answer, progress, still) {
|
|
|
11787
11851
|
};
|
|
11788
11852
|
rearm();
|
|
11789
11853
|
try {
|
|
11790
|
-
return await current.run({ signal, progress: told }, answer);
|
|
11854
|
+
return await current.run({ signal, progress: told, slotWaits }, answer);
|
|
11791
11855
|
} finally {
|
|
11792
11856
|
going = undefined;
|
|
11793
11857
|
clearTimeout(quiet);
|
|
@@ -11806,63 +11870,20 @@ function callSignal() {
|
|
|
11806
11870
|
function callProgress() {
|
|
11807
11871
|
return current.getStore()?.progress;
|
|
11808
11872
|
}
|
|
11873
|
+
function callSlotWaits() {
|
|
11874
|
+
return current.getStore()?.slotWaits;
|
|
11875
|
+
}
|
|
11809
11876
|
var current, CALL_HEARTBEAT_MS = 20000;
|
|
11810
11877
|
var init_call_signal = __esm(() => {
|
|
11811
11878
|
current = new AsyncLocalStorage;
|
|
11812
11879
|
});
|
|
11813
11880
|
|
|
11814
|
-
// src/whole-file.ts
|
|
11815
|
-
import { renameSync, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
11816
|
-
function writeWhole(path, text) {
|
|
11817
|
-
const partial = `${path}.${process.pid}.partial`;
|
|
11818
|
-
try {
|
|
11819
|
-
writeFileSync5(partial, text, "utf8");
|
|
11820
|
-
} catch {
|
|
11821
|
-
return false;
|
|
11822
|
-
}
|
|
11823
|
-
const until = Date.now() + HELD_FILE_MS;
|
|
11824
|
-
for (;; ) {
|
|
11825
|
-
try {
|
|
11826
|
-
renameSync(partial, path);
|
|
11827
|
-
return true;
|
|
11828
|
-
} catch (error) {
|
|
11829
|
-
const code = error.code ?? "";
|
|
11830
|
-
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
11831
|
-
try {
|
|
11832
|
-
rmSync5(partial, { force: true });
|
|
11833
|
-
} catch {}
|
|
11834
|
-
return false;
|
|
11835
|
-
}
|
|
11836
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
11837
|
-
}
|
|
11838
|
-
}
|
|
11839
|
-
}
|
|
11840
|
-
function removeWhole(path) {
|
|
11841
|
-
const until = Date.now() + HELD_FILE_MS;
|
|
11842
|
-
for (;; ) {
|
|
11843
|
-
try {
|
|
11844
|
-
rmSync5(path, { force: true });
|
|
11845
|
-
return true;
|
|
11846
|
-
} catch (error) {
|
|
11847
|
-
const code = error.code ?? "";
|
|
11848
|
-
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
11849
|
-
return false;
|
|
11850
|
-
}
|
|
11851
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
|
|
11852
|
-
}
|
|
11853
|
-
}
|
|
11854
|
-
}
|
|
11855
|
-
var HELD_FILE_MS = 1000, HELD_FILE_RETRY_MS = 10, HELD_BY_A_READER;
|
|
11856
|
-
var init_whole_file = __esm(() => {
|
|
11857
|
-
HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
11858
|
-
});
|
|
11859
|
-
|
|
11860
11881
|
// src/engine-slots.ts
|
|
11861
11882
|
import {
|
|
11862
11883
|
closeSync as closeSync3,
|
|
11863
11884
|
mkdirSync as mkdirSync3,
|
|
11864
11885
|
openSync as openSync3,
|
|
11865
|
-
readFileSync as
|
|
11886
|
+
readFileSync as readFileSync8,
|
|
11866
11887
|
rmSync as rmSync6,
|
|
11867
11888
|
statSync as statSync6,
|
|
11868
11889
|
watch,
|
|
@@ -11992,7 +12013,7 @@ class EngineSlots {
|
|
|
11992
12013
|
this.holder = holder;
|
|
11993
12014
|
this.say = say;
|
|
11994
12015
|
}
|
|
11995
|
-
async take(signal, waiting) {
|
|
12016
|
+
async take(signal, waiting, blocked) {
|
|
11996
12017
|
mkdirSync3(this.directory, { recursive: true });
|
|
11997
12018
|
const began = Date.now();
|
|
11998
12019
|
let said = Number.NEGATIVE_INFINITY;
|
|
@@ -12005,7 +12026,10 @@ class EngineSlots {
|
|
|
12005
12026
|
if (lock !== null) {
|
|
12006
12027
|
return lock;
|
|
12007
12028
|
}
|
|
12008
|
-
mark
|
|
12029
|
+
if (mark === undefined) {
|
|
12030
|
+
mark = this.waitMarked();
|
|
12031
|
+
blocked?.();
|
|
12032
|
+
}
|
|
12009
12033
|
const now = Date.now();
|
|
12010
12034
|
if (waiting !== undefined) {
|
|
12011
12035
|
if (now - said >= WAIT_SAID_MS) {
|
|
@@ -12059,7 +12083,7 @@ class EngineSlots {
|
|
|
12059
12083
|
const found = [];
|
|
12060
12084
|
for (let slot = 0;slot < this.count; slot += 1) {
|
|
12061
12085
|
try {
|
|
12062
|
-
const holder = holderOf(
|
|
12086
|
+
const holder = holderOf(readFileSync8(join8(this.directory, `${String(slot)}.lock`), "utf8"));
|
|
12063
12087
|
if (holder !== null) {
|
|
12064
12088
|
found.push(holder);
|
|
12065
12089
|
}
|
|
@@ -12079,7 +12103,7 @@ class EngineSlots {
|
|
|
12079
12103
|
release(lock) {
|
|
12080
12104
|
this.held.delete(lock);
|
|
12081
12105
|
try {
|
|
12082
|
-
if (holderOf(
|
|
12106
|
+
if (holderOf(readFileSync8(lock, "utf8"))?.pid === this.holder.pid) {
|
|
12083
12107
|
removeWhole(lock);
|
|
12084
12108
|
}
|
|
12085
12109
|
} catch {}
|
|
@@ -12129,7 +12153,7 @@ class EngineSlots {
|
|
|
12129
12153
|
let content;
|
|
12130
12154
|
let writtenAt;
|
|
12131
12155
|
try {
|
|
12132
|
-
content =
|
|
12156
|
+
content = readFileSync8(lock, "utf8");
|
|
12133
12157
|
writtenAt = statSync6(lock).mtimeMs;
|
|
12134
12158
|
} catch {
|
|
12135
12159
|
return false;
|
|
@@ -12167,31 +12191,55 @@ function nameSlotTaker(by) {
|
|
|
12167
12191
|
}
|
|
12168
12192
|
function slotWaitSaid(waitedMs, count, directory, holders = []) {
|
|
12169
12193
|
const slots = count === 1 ? `the one engine slot on this machine (${directory}) is in use` : `all ${String(count)} engine slots on this machine (${directory}) are in use`;
|
|
12194
|
+
const named = holdersNamed(count, holders);
|
|
12195
|
+
const waiting = `Waiting${waitedMs >= 1000 ? ` ${String(Math.round(waitedMs / 1000))} s so far` : ""} for an engine: ${slots}`;
|
|
12196
|
+
if (named.length === 0) {
|
|
12197
|
+
return `${waiting}, by a gate or another tool, and the engine starts when one is given back.`;
|
|
12198
|
+
}
|
|
12199
|
+
if (count === 1) {
|
|
12200
|
+
return `${waiting}, by ${named.join(", ")}, and the engine starts when it is given back.`;
|
|
12201
|
+
}
|
|
12202
|
+
return `${waiting}: ${listed(named)}. The engine starts when one is given back.`;
|
|
12203
|
+
}
|
|
12204
|
+
function slotWaitedSaid(waitedMs, count, directory, holders) {
|
|
12205
|
+
const waited = `This call waited ${String(Math.round(waitedMs / 1000))} s for an engine slot in all.`;
|
|
12206
|
+
const slots = count === 1 ? `the one engine slot on this machine (${directory}) was in use` : `all ${String(count)} engine slots on this machine (${directory}) were in use`;
|
|
12207
|
+
const named = holdersNamed(count, holders);
|
|
12208
|
+
if (named.length === 0) {
|
|
12209
|
+
return `${waited} When it first waited, ${slots}, by a gate or another tool.`;
|
|
12210
|
+
}
|
|
12211
|
+
return count === 1 ? `${waited} When it first waited, ${slots}, by ${named.join(", ")}.` : `${waited} When it first waited, ${slots}: ${listed(named)}.`;
|
|
12212
|
+
}
|
|
12213
|
+
function holdersNamed(count, holders) {
|
|
12170
12214
|
const held = new Map;
|
|
12171
12215
|
for (const holder of holders) {
|
|
12172
12216
|
const known = held.get(holder.pid);
|
|
12173
12217
|
held.set(holder.pid, { by: known?.by ?? holder.by, slots: (known?.slots ?? 0) + 1 });
|
|
12174
12218
|
}
|
|
12175
|
-
|
|
12219
|
+
return [...held].map(([pid, { by, slots: taken }]) => {
|
|
12176
12220
|
const who = pid === process7.pid ? `this process (pid ${String(pid)})` : by === undefined ? `pid ${String(pid)}` : `${by} (pid ${String(pid)})`;
|
|
12177
12221
|
return count === 1 ? who : `${String(taken)} by ${who}`;
|
|
12178
12222
|
});
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
}
|
|
12183
|
-
if (count === 1) {
|
|
12184
|
-
return `${waiting}, by ${named.join(", ")}, and the engine starts when it is given back.`;
|
|
12185
|
-
}
|
|
12186
|
-
const list = named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
12187
|
-
return `${waiting}: ${list}. The engine starts when one is given back.`;
|
|
12223
|
+
}
|
|
12224
|
+
function listed(named) {
|
|
12225
|
+
return named.length === 1 ? named.join("") : `${named.slice(0, -1).join(", ")} and ${named.at(-1) ?? ""}`;
|
|
12188
12226
|
}
|
|
12189
12227
|
async function slotForCall() {
|
|
12190
12228
|
const slots = await processSlots();
|
|
12191
12229
|
const progress = callProgress();
|
|
12230
|
+
const waits = callSlotWaits();
|
|
12231
|
+
const began = Date.now();
|
|
12232
|
+
let blockedBy;
|
|
12192
12233
|
const lock = await slots.take(callSignal(), progress === undefined ? undefined : (waitedMs) => {
|
|
12193
12234
|
progress(waitedMs / 1000, slotWaitSaid(waitedMs, slots.count, slots.directory, slots.holders()));
|
|
12235
|
+
}, () => {
|
|
12236
|
+
blockedBy = slots.holders();
|
|
12194
12237
|
});
|
|
12238
|
+
if (waits !== undefined && blockedBy !== undefined) {
|
|
12239
|
+
waits.ms += Date.now() - began;
|
|
12240
|
+
const heldBy = blockedBy;
|
|
12241
|
+
waits.said ??= (waitedMs) => slotWaitedSaid(waitedMs, slots.count, slots.directory, heldBy);
|
|
12242
|
+
}
|
|
12195
12243
|
return {
|
|
12196
12244
|
release: () => {
|
|
12197
12245
|
slots.release(lock);
|
|
@@ -12961,7 +13009,7 @@ var init_doc_cache = __esm(() => {
|
|
|
12961
13009
|
});
|
|
12962
13010
|
|
|
12963
13011
|
// src/project-scan.ts
|
|
12964
|
-
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as
|
|
13012
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync9, statSync as statSync9 } from "node:fs";
|
|
12965
13013
|
import { basename as basename5, extname, join as join11, relative as relative4, sep as sep3 } from "node:path";
|
|
12966
13014
|
function skipped(name) {
|
|
12967
13015
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -13097,7 +13145,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
13097
13145
|
function pathsInUidCache(projectPath) {
|
|
13098
13146
|
let data;
|
|
13099
13147
|
try {
|
|
13100
|
-
data =
|
|
13148
|
+
data = readFileSync9(join11(projectPath, ".godot", "uid_cache.bin"));
|
|
13101
13149
|
} catch {
|
|
13102
13150
|
return null;
|
|
13103
13151
|
}
|
|
@@ -13159,7 +13207,7 @@ function projectTexts(projectPath) {
|
|
|
13159
13207
|
if (!entry.isFile() || BINARY_EXTENSIONS.has(extension)) {
|
|
13160
13208
|
continue;
|
|
13161
13209
|
}
|
|
13162
|
-
const bytes =
|
|
13210
|
+
const bytes = readFileSync9(absolute);
|
|
13163
13211
|
if (!isBinary(bytes)) {
|
|
13164
13212
|
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
13165
13213
|
}
|
|
@@ -13189,7 +13237,7 @@ function ignoredTexts(projectPath) {
|
|
|
13189
13237
|
if (!under || !entry.isFile() || BINARY_EXTENSIONS.has(extension) || entry.name === ".gdignore") {
|
|
13190
13238
|
continue;
|
|
13191
13239
|
}
|
|
13192
|
-
const bytes =
|
|
13240
|
+
const bytes = readFileSync9(absolute);
|
|
13193
13241
|
if (!isBinary(bytes)) {
|
|
13194
13242
|
found.push({ path: `res://${spelled}`, absolute, text: bytes.toString("utf8") });
|
|
13195
13243
|
}
|
|
@@ -13226,7 +13274,7 @@ function searchProject(projectPath, options) {
|
|
|
13226
13274
|
};
|
|
13227
13275
|
const regex = options.regex ? compiledQuery(options.query, options.caseSensitive) : null;
|
|
13228
13276
|
const needle = options.caseSensitive ? options.query : options.query.toLowerCase();
|
|
13229
|
-
|
|
13277
|
+
let shown = 0;
|
|
13230
13278
|
const notSearched = [];
|
|
13231
13279
|
const met = new Set;
|
|
13232
13280
|
const searchFile = (entryPath, name) => {
|
|
@@ -13237,28 +13285,33 @@ function searchProject(projectPath, options) {
|
|
|
13237
13285
|
if (extensions !== null && !extensions.has(extension)) {
|
|
13238
13286
|
return;
|
|
13239
13287
|
}
|
|
13240
|
-
const bytes =
|
|
13288
|
+
const bytes = readFileSync9(entryPath);
|
|
13241
13289
|
if (extensions === null && isBinary(bytes)) {
|
|
13242
13290
|
return;
|
|
13243
13291
|
}
|
|
13244
13292
|
result.summary.files_searched += 1;
|
|
13245
13293
|
const matches = [];
|
|
13294
|
+
let matched = false;
|
|
13246
13295
|
for (const [index, line] of bytes.toString("utf8").split(/\r?\n/).entries()) {
|
|
13247
13296
|
const found = regex ? regex.exec(line) : plainMatch(line, needle, options.caseSensitive);
|
|
13248
13297
|
if (found === null) {
|
|
13249
13298
|
continue;
|
|
13250
13299
|
}
|
|
13251
|
-
|
|
13300
|
+
matched = true;
|
|
13301
|
+
result.summary.total_matches += 1;
|
|
13302
|
+
if (shown >= options.maxResults) {
|
|
13252
13303
|
result.summary.truncated = true;
|
|
13253
|
-
|
|
13304
|
+
continue;
|
|
13254
13305
|
}
|
|
13306
|
+
shown += 1;
|
|
13255
13307
|
matches.push({ line: index + 1, content: line.trim(), match: found[0] });
|
|
13256
|
-
|
|
13308
|
+
}
|
|
13309
|
+
if (matched) {
|
|
13310
|
+
result.summary.files_with_matches += 1;
|
|
13257
13311
|
}
|
|
13258
13312
|
if (matches.length > 0) {
|
|
13259
13313
|
const relativePath = entryPath.slice(projectPath.length + 1).replace(/\\/g, "/");
|
|
13260
13314
|
result.results.push({ file: `res://${relativePath}`, matches });
|
|
13261
|
-
result.summary.files_with_matches += 1;
|
|
13262
13315
|
}
|
|
13263
13316
|
};
|
|
13264
13317
|
const visit = (directory, named = false) => {
|
|
@@ -13269,9 +13322,6 @@ function searchProject(projectPath, options) {
|
|
|
13269
13322
|
return;
|
|
13270
13323
|
}
|
|
13271
13324
|
for (const entry of readdirSync6(directory, { withFileTypes: true })) {
|
|
13272
|
-
if (full()) {
|
|
13273
|
-
return;
|
|
13274
|
-
}
|
|
13275
13325
|
if (skipped(entry.name)) {
|
|
13276
13326
|
continue;
|
|
13277
13327
|
}
|
|
@@ -13351,7 +13401,7 @@ var init_project_scan = __esm(() => {
|
|
|
13351
13401
|
|
|
13352
13402
|
// src/import-freshness.ts
|
|
13353
13403
|
import { createHash as createHash2 } from "node:crypto";
|
|
13354
|
-
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as
|
|
13404
|
+
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync10 } from "node:fs";
|
|
13355
13405
|
import { join as join12 } from "node:path";
|
|
13356
13406
|
function md5Of(file) {
|
|
13357
13407
|
let stats;
|
|
@@ -13366,7 +13416,7 @@ function md5Of(file) {
|
|
|
13366
13416
|
}
|
|
13367
13417
|
let md5;
|
|
13368
13418
|
try {
|
|
13369
|
-
md5 = createHash2("md5").update(
|
|
13419
|
+
md5 = createHash2("md5").update(readFileSync10(file)).digest("hex");
|
|
13370
13420
|
} catch {
|
|
13371
13421
|
return null;
|
|
13372
13422
|
}
|
|
@@ -13392,7 +13442,7 @@ function sectionOf(text, section) {
|
|
|
13392
13442
|
function unquoted(value) {
|
|
13393
13443
|
return value === undefined ? "" : value.replace(/^"(.*)"$/, "$1");
|
|
13394
13444
|
}
|
|
13395
|
-
function
|
|
13445
|
+
function listed2(value) {
|
|
13396
13446
|
return [...(value ?? "").matchAll(/"((?:[^"\\]|\\.)*)"/g)].map((match) => match[1] ?? "");
|
|
13397
13447
|
}
|
|
13398
13448
|
function importedIntoTheProject(projectPath, resPaths) {
|
|
@@ -13400,11 +13450,11 @@ function importedIntoTheProject(projectPath, resPaths) {
|
|
|
13400
13450
|
for (const resPath of resPaths) {
|
|
13401
13451
|
let sidecar;
|
|
13402
13452
|
try {
|
|
13403
|
-
sidecar =
|
|
13453
|
+
sidecar = readFileSync10(`${onDisk(projectPath, resPath)}.import`, "utf8");
|
|
13404
13454
|
} catch {
|
|
13405
13455
|
continue;
|
|
13406
13456
|
}
|
|
13407
|
-
const outputs =
|
|
13457
|
+
const outputs = listed2(sectionOf(sidecar, "deps").get("dest_files")).filter((output) => output.startsWith("res://") && !output.startsWith("res://.godot/"));
|
|
13408
13458
|
if (outputs.length > 0) {
|
|
13409
13459
|
wrote[resPath] = outputs;
|
|
13410
13460
|
}
|
|
@@ -13420,7 +13470,7 @@ function behind(projectPath, resPath, sidecar) {
|
|
|
13420
13470
|
if (importer === "keep" || importer === "skip") {
|
|
13421
13471
|
return null;
|
|
13422
13472
|
}
|
|
13423
|
-
const outputs =
|
|
13473
|
+
const outputs = listed2(sectionOf(sidecar, "deps").get("dest_files"));
|
|
13424
13474
|
if (outputs.some((output) => !existsSync10(onDisk(projectPath, output)))) {
|
|
13425
13475
|
return "its imported output is not on disk";
|
|
13426
13476
|
}
|
|
@@ -13428,7 +13478,7 @@ function behind(projectPath, resPath, sidecar) {
|
|
|
13428
13478
|
const record = join12(projectPath, ".godot", "imported", `${name}-${createHash2("md5").update(resPath, "utf8").digest("hex")}.md5`);
|
|
13429
13479
|
let recorded = "";
|
|
13430
13480
|
try {
|
|
13431
|
-
recorded = /^source_md5="([0-9a-f]*)"/m.exec(
|
|
13481
|
+
recorded = /^source_md5="([0-9a-f]*)"/m.exec(readFileSync10(record, "utf8"))?.[1] ?? "";
|
|
13432
13482
|
} catch {
|
|
13433
13483
|
recorded = "";
|
|
13434
13484
|
}
|
|
@@ -13470,7 +13520,7 @@ function staleImports(projectPath) {
|
|
|
13470
13520
|
}
|
|
13471
13521
|
let sidecar;
|
|
13472
13522
|
try {
|
|
13473
|
-
sidecar =
|
|
13523
|
+
sidecar = readFileSync10(join12(directory, entry.name), "utf8");
|
|
13474
13524
|
} catch {
|
|
13475
13525
|
continue;
|
|
13476
13526
|
}
|
|
@@ -13534,7 +13584,7 @@ import {
|
|
|
13534
13584
|
existsSync as existsSync11,
|
|
13535
13585
|
mkdirSync as mkdirSync4,
|
|
13536
13586
|
readdirSync as readdirSync8,
|
|
13537
|
-
readFileSync as
|
|
13587
|
+
readFileSync as readFileSync11,
|
|
13538
13588
|
renameSync as renameSync2,
|
|
13539
13589
|
unlinkSync,
|
|
13540
13590
|
writeFileSync as writeFileSync6
|
|
@@ -13650,7 +13700,7 @@ function resolveResource(projectPath, relativeTo, path) {
|
|
|
13650
13700
|
}
|
|
13651
13701
|
function readOrNull(path) {
|
|
13652
13702
|
try {
|
|
13653
|
-
return
|
|
13703
|
+
return readFileSync11(path, "utf8");
|
|
13654
13704
|
} catch {
|
|
13655
13705
|
return null;
|
|
13656
13706
|
}
|
|
@@ -13659,7 +13709,7 @@ var init_library_copies = () => {};
|
|
|
13659
13709
|
|
|
13660
13710
|
// src/reimport.ts
|
|
13661
13711
|
import { createHash as createHash3 } from "node:crypto";
|
|
13662
|
-
import { existsSync as existsSync12, readFileSync as
|
|
13712
|
+
import { existsSync as existsSync12, readFileSync as readFileSync12, rmSync as rmSync7, statSync as statSync11, utimesSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
13663
13713
|
import { basename as basename7, join as join14 } from "node:path";
|
|
13664
13714
|
function forceNextImport(projectPath, resourcePath) {
|
|
13665
13715
|
const relative = resourcePath.replace(/^res:\/\//, "");
|
|
@@ -13668,7 +13718,7 @@ function forceNextImport(projectPath, resourcePath) {
|
|
|
13668
13718
|
return;
|
|
13669
13719
|
}
|
|
13670
13720
|
const { atime, mtimeMs } = statSync11(sidecar);
|
|
13671
|
-
writeFileSync7(sidecar,
|
|
13721
|
+
writeFileSync7(sidecar, readFileSync12(sidecar, "utf8").replace(/^valid=false\r?\n/m, ""));
|
|
13672
13722
|
utimesSync(sidecar, atime, new Date(mtimeMs + 2000));
|
|
13673
13723
|
rmSync7(importRecord(projectPath, resourcePath), { force: true });
|
|
13674
13724
|
}
|
|
@@ -13894,7 +13944,7 @@ var init_script_origins = __esm(() => {
|
|
|
13894
13944
|
});
|
|
13895
13945
|
|
|
13896
13946
|
// src/headless.ts
|
|
13897
|
-
import { existsSync as existsSync14, readFileSync as
|
|
13947
|
+
import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
|
|
13898
13948
|
import { dirname as dirname7, join as join17 } from "node:path";
|
|
13899
13949
|
function snakeCased(params) {
|
|
13900
13950
|
const result = emptyRecord();
|
|
@@ -14185,7 +14235,7 @@ function answerIn(file) {
|
|
|
14185
14235
|
if (!existsSync14(file)) {
|
|
14186
14236
|
return { kind: "none" };
|
|
14187
14237
|
}
|
|
14188
|
-
const text =
|
|
14238
|
+
const text = readFileSync13(file, "utf8");
|
|
14189
14239
|
try {
|
|
14190
14240
|
const parsed = JSON.parse(text);
|
|
14191
14241
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? { kind: "answer", payload: parsed } : { kind: "unreadable", why: `it is JSON but not an object: ${text.slice(0, 200)}` };
|
|
@@ -14210,7 +14260,7 @@ var init_headless = __esm(() => {
|
|
|
14210
14260
|
});
|
|
14211
14261
|
|
|
14212
14262
|
// src/update-check.ts
|
|
14213
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as
|
|
14263
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
|
|
14214
14264
|
import { homedir as homedir5, tmpdir as tmpdir4 } from "node:os";
|
|
14215
14265
|
import { join as join18 } from "node:path";
|
|
14216
14266
|
function packageUrl(root) {
|
|
@@ -14255,7 +14305,7 @@ function readCache(path) {
|
|
|
14255
14305
|
if (!existsSync15(path)) {
|
|
14256
14306
|
return null;
|
|
14257
14307
|
}
|
|
14258
|
-
const parsed = JSON.parse(
|
|
14308
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
14259
14309
|
if (typeof parsed !== "object" || parsed === null) {
|
|
14260
14310
|
return null;
|
|
14261
14311
|
}
|
|
@@ -14403,7 +14453,7 @@ var init_update_check = __esm(() => {
|
|
|
14403
14453
|
});
|
|
14404
14454
|
|
|
14405
14455
|
// src/server-version.ts
|
|
14406
|
-
import { readFileSync as
|
|
14456
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
14407
14457
|
function staleAddon(addonDigest, shippedDigest) {
|
|
14408
14458
|
return addonDigest !== shippedDigest;
|
|
14409
14459
|
}
|
|
@@ -14462,7 +14512,7 @@ var init_server_version = __esm(() => {
|
|
|
14462
14512
|
DEBUG_MODE = process.env["GDHARNESS_DEBUG"] === "1";
|
|
14463
14513
|
SERVER_VERSION = (() => {
|
|
14464
14514
|
try {
|
|
14465
|
-
const pkg = JSON.parse(
|
|
14515
|
+
const pkg = JSON.parse(readFileSync15(new URL("../package.json", import.meta.url), "utf8"));
|
|
14466
14516
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
14467
14517
|
} catch {
|
|
14468
14518
|
return "0.0.0";
|
|
@@ -15573,7 +15623,7 @@ var init_lsp_client = __esm(() => {
|
|
|
15573
15623
|
});
|
|
15574
15624
|
|
|
15575
15625
|
// src/resources.ts
|
|
15576
|
-
import { readFileSync as
|
|
15626
|
+
import { readFileSync as readFileSync17, realpathSync as realpathSync3 } from "node:fs";
|
|
15577
15627
|
import { extname as extname2, resolve as resolve8 } from "node:path";
|
|
15578
15628
|
function ensureProjectPath(getProjectPath) {
|
|
15579
15629
|
const projectPath = getProjectPath();
|
|
@@ -15769,7 +15819,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
15769
15819
|
const parsedUri = parseGodotUri(uri);
|
|
15770
15820
|
if (parsedUri.kind === "project-info") {
|
|
15771
15821
|
const projectFilePath = resolveProjectFile(projectPath, "project.godot");
|
|
15772
|
-
const rawProject =
|
|
15822
|
+
const rawProject = readFileSync17(projectFilePath, "utf-8");
|
|
15773
15823
|
const parsedProject = parseProjectGodot(rawProject);
|
|
15774
15824
|
return {
|
|
15775
15825
|
mimeType: "application/json",
|
|
@@ -15778,7 +15828,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
15778
15828
|
}
|
|
15779
15829
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
15780
15830
|
ensureAllowedExtension(parsedUri.kind, filePath);
|
|
15781
|
-
const text =
|
|
15831
|
+
const text = readFileSync17(filePath, "utf-8");
|
|
15782
15832
|
return {
|
|
15783
15833
|
mimeType: parsedUri.kind === "script" ? "text/x-gdscript" : "text/plain",
|
|
15784
15834
|
text
|
|
@@ -15925,7 +15975,7 @@ import {
|
|
|
15925
15975
|
existsSync as existsSync18,
|
|
15926
15976
|
mkdirSync as mkdirSync6,
|
|
15927
15977
|
readdirSync as readdirSync11,
|
|
15928
|
-
readFileSync as
|
|
15978
|
+
readFileSync as readFileSync18,
|
|
15929
15979
|
rmdirSync,
|
|
15930
15980
|
rmSync as rmSync9,
|
|
15931
15981
|
statSync as statSync12,
|
|
@@ -15959,7 +16009,7 @@ function addonsDigest(names, from) {
|
|
|
15959
16009
|
} else {
|
|
15960
16010
|
hash.update(`${inside}
|
|
15961
16011
|
`);
|
|
15962
|
-
hash.update(
|
|
16012
|
+
hash.update(readFileSync18(path));
|
|
15963
16013
|
hash.update(`
|
|
15964
16014
|
`);
|
|
15965
16015
|
}
|
|
@@ -15989,7 +16039,7 @@ function digestMarker(projectPath, addon) {
|
|
|
15989
16039
|
if (!existsSync18(marker)) {
|
|
15990
16040
|
return null;
|
|
15991
16041
|
}
|
|
15992
|
-
const said =
|
|
16042
|
+
const said = readFileSync18(marker, "utf8").trim();
|
|
15993
16043
|
return said === "" ? null : said;
|
|
15994
16044
|
}
|
|
15995
16045
|
function shippedAddonsDirectory() {
|
|
@@ -16006,7 +16056,7 @@ function loaderState(projectPath) {
|
|
|
16006
16056
|
if (!existsSync18(copy)) {
|
|
16007
16057
|
return "missing";
|
|
16008
16058
|
}
|
|
16009
|
-
const lines = (path) =>
|
|
16059
|
+
const lines = (path) => readFileSync18(path, "utf8").replaceAll(`\r
|
|
16010
16060
|
`, `
|
|
16011
16061
|
`);
|
|
16012
16062
|
return lines(copy) === lines(shippedLoader()) ? "current" : "differs";
|
|
@@ -16017,7 +16067,7 @@ function writeLoader(projectPath) {
|
|
|
16017
16067
|
}
|
|
16018
16068
|
const copy = join21(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
16019
16069
|
mkdirSync6(dirname9(copy), { recursive: true });
|
|
16020
|
-
writeFileSync10(copy,
|
|
16070
|
+
writeFileSync10(copy, readFileSync18(shippedLoader()));
|
|
16021
16071
|
return true;
|
|
16022
16072
|
}
|
|
16023
16073
|
function removeLoader(projectPath) {
|
|
@@ -16076,7 +16126,7 @@ function installedAddonVersion(projectPath) {
|
|
|
16076
16126
|
if (!existsSync18(marker)) {
|
|
16077
16127
|
return null;
|
|
16078
16128
|
}
|
|
16079
|
-
const said =
|
|
16129
|
+
const said = readFileSync18(marker, "utf8").trim();
|
|
16080
16130
|
return said === "" ? null : said;
|
|
16081
16131
|
}
|
|
16082
16132
|
function removeAddons(projectPath) {
|
|
@@ -16131,7 +16181,7 @@ function loaderAmong(projectPath, named) {
|
|
|
16131
16181
|
}
|
|
16132
16182
|
let source = null;
|
|
16133
16183
|
try {
|
|
16134
|
-
source =
|
|
16184
|
+
source = readFileSync18(join21(projectPath, path), "utf8");
|
|
16135
16185
|
} catch {}
|
|
16136
16186
|
if (source?.includes(RUNTIME_SCRIPT)) {
|
|
16137
16187
|
return { name: entry, path, exists: true };
|
|
@@ -16190,7 +16240,7 @@ function inspectProject(projectPath) {
|
|
|
16190
16240
|
const directory = join21(projectPath, "addons", name);
|
|
16191
16241
|
const marker = join21(directory, VERSION_MARKER);
|
|
16192
16242
|
const installed = existsSync18(directory);
|
|
16193
|
-
const version = existsSync18(marker) ?
|
|
16243
|
+
const version = existsSync18(marker) ? readFileSync18(marker, "utf8").trim() : null;
|
|
16194
16244
|
const current = version === SERVER_VERSION;
|
|
16195
16245
|
if (!installed) {
|
|
16196
16246
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -16199,7 +16249,7 @@ function inspectProject(projectPath) {
|
|
|
16199
16249
|
}
|
|
16200
16250
|
return { name, installed, version, current };
|
|
16201
16251
|
});
|
|
16202
|
-
const settings = parseProjectGodot(
|
|
16252
|
+
const settings = parseProjectGodot(readFileSync18(join21(projectPath, "project.godot"), "utf8"));
|
|
16203
16253
|
const pluginsEnabled = enabledPlugins(settings);
|
|
16204
16254
|
for (const name of EDITOR_PLUGINS) {
|
|
16205
16255
|
if (!pluginsEnabled.includes(name)) {
|
|
@@ -16630,7 +16680,11 @@ var init_tool_definitions = __esm(() => {
|
|
|
16630
16680
|
ops: ["set"],
|
|
16631
16681
|
description: 'The value to write, fitted to the type the setting is registered as, the way scene_node set fits a property. Engine types may be written as their fields, {"x": 1, "y": 2}, or tagged, {"_type": "Vector2", "x": 1, "y": 2}, and infinity as {"_type": "float", "value": "inf"}, the form a read answers with; one carrying a field its type has not is refused naming it, and a colour may also be its html code, "#ff8000". "" writes an empty string. A setting the engine does not declare is written as given, a whole number as an int and a plain list as an Array, so a packed array is tagged with its type, {"_type": "PackedStringArray", "value": ["res://a/"]}; a tag that cannot be read as its type is refused rather than written as a dictionary. When a setting in its section is named like an undeclared one, note names the nearest, as it may be a misspelt one. Every line of project.godot for another setting stays as it was, one holding a default value included.'
|
|
16632
16682
|
},
|
|
16633
|
-
name: {
|
|
16683
|
+
name: {
|
|
16684
|
+
type: "string",
|
|
16685
|
+
ops: ["add_autoload", "remove_autoload"],
|
|
16686
|
+
description: "Autoload name. add_autoload on a name already registered replaces its entry, as the editor's Add does, and answers action updated with old_path, the path it held, which no longer loads."
|
|
16687
|
+
},
|
|
16634
16688
|
path: {
|
|
16635
16689
|
type: "string",
|
|
16636
16690
|
ops: ["add_autoload"],
|
|
@@ -16784,7 +16838,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16784
16838
|
maxResults: {
|
|
16785
16839
|
type: "integer",
|
|
16786
16840
|
minimum: 1,
|
|
16787
|
-
description: "How many matching lines to answer. Default 100."
|
|
16841
|
+
description: "How many matching lines to answer. Default 100. Past it truncated is true, and the summary still counts the whole search."
|
|
16788
16842
|
}
|
|
16789
16843
|
},
|
|
16790
16844
|
requires: ["projectPath", "query"]
|
|
@@ -16823,7 +16877,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16823
16877
|
name: "project_import",
|
|
16824
16878
|
title: "Asset imports",
|
|
16825
16879
|
description: "The import pipeline: what needs importing, how a resource is imported, reimports, UIDs, and the global class list the editor and the engine read.",
|
|
16826
|
-
answer: "reimport is answered from a second status read: reimported lists what is current now, notReimported what is not, one entry per status and reason with the paths sharing them, and via says which of the two did the work. importedByTheScan names what the editor's scan imported first, and alsoImported, on a reimport of one resourcePath, the others it imported. wroteInProject names, by source, what an import wrote into the project itself rather than under .godot, such as the .translation a CSV gives each language, which version control sees and internationalization/locale/translations names. The import gives every script without a .uid sidecar one, as the editor's scan does, and uidsWritten names those scripts, counted per addon under uidsWrittenInAddons for the ones inside an addon. When nothing needed reimporting, the two lists are empty, a note says so, and there is no via. A whole-project reimport also answers missingSource, the .import files whose source is not beside them, empty when there are none, even when nothing needed reimporting; one resourcePath leaves it out. stillImporting is an editor that had not finished within timeoutMs.",
|
|
16880
|
+
answer: "options answers remap, deps and params as the .import file holds them, so an enum option such as compress/mode is its number: the engine gives scripts no list of a built-in importer's options or of what the numbers mean, so Godot's documentation of that importer is where a number is looked up. reimport is answered from a second status read: reimported lists what is current now, notReimported what is not, one entry per status and reason with the paths sharing them, and via says which of the two did the work. importedByTheScan names what the editor's scan imported first, and alsoImported, on a reimport of one resourcePath, the others it imported. wroteInProject names, by source, what an import wrote into the project itself rather than under .godot, such as the .translation a CSV gives each language, which version control sees and internationalization/locale/translations names. The import gives every script without a .uid sidecar one, as the editor's scan does, and uidsWritten names those scripts, counted per addon under uidsWrittenInAddons for the ones inside an addon. When nothing needed reimporting, the two lists are empty, a note says so, and there is no via. A whole-project reimport also answers missingSource, the .import files whose source is not beside them, empty when there are none, even when nothing needed reimporting; one resourcePath leaves it out. stillImporting is an editor that had not finished within timeoutMs.",
|
|
16827
16881
|
parameters: {
|
|
16828
16882
|
projectPath: PROJECT_PATH,
|
|
16829
16883
|
resourcePath: { ...RESOURCE_PATH, ops: ["status", "options", "set_options", "uid", "reimport"] },
|
|
@@ -16885,7 +16939,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16885
16939
|
},
|
|
16886
16940
|
refresh_classes: {
|
|
16887
16941
|
effect: "destructive",
|
|
16888
|
-
summary: 'rewrite .godot/global_script_class_cache.cfg from the class_name declarations on disk. That misses the list a running editor loaded, so "added: []" means the file was already right, not that nothing is wrong: unseenByEditor names a class the editor open on this project cannot resolve, and heldBehindInEditor one it holds compiled from an older text of its file. lostSinceLastRebuild names a class the cache held after the last rebuild and lost before this one: the editor wrote the file without it, on a save or a scan, and will again until restarted. staleInThisEngine names a class the rebuild added, unknown to the autoloads its own engine compiles afterwards, and autoloadsOnTheRebuiltList what a second engine on that list reports of them',
|
|
16942
|
+
summary: 'rewrite .godot/global_script_class_cache.cfg from the class_name declarations on disk. That misses the list a running editor loaded, so "added: []" means the file was already right, not that nothing is wrong: unseenByEditor names a class the editor open on this project cannot resolve, and heldBehindInEditor one it holds compiled from an older text of its file, with heldBehindUnchecked saying why when the editor did not say. lostSinceLastRebuild names a class the cache held after the last rebuild and lost before this one: the editor wrote the file without it, on a save or a scan, and will again until restarted. staleInThisEngine names a class the rebuild added, unknown to the autoloads its own engine compiles afterwards, and autoloadsOnTheRebuiltList what a second engine on that list reports of them',
|
|
16889
16943
|
requires: []
|
|
16890
16944
|
}
|
|
16891
16945
|
}
|
|
@@ -16893,7 +16947,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16893
16947
|
{
|
|
16894
16948
|
name: "project_export",
|
|
16895
16949
|
title: "Export",
|
|
16896
|
-
description: "Export presets and exports. add_preset writes a preset to export_presets.cfg with the keys the editor's Project > Export writes for a new one and every option a new preset of its platform shows, each at its default, and makes it the platform's runnable preset when the platform has none. set_preset changes a preset's export path, its resource filter and the files it lists, its include and exclude filters, its custom features and its platform's options, and answers under changed what each held before and holds now, and under unchanged what already held the value given; nothing is written when any of it is refused. The option names are the exporter's own, as the Export dialog's Options tab shows them by their paths, such as binary_format/embed_pck, and a name the platform does not have is refused with the nearest it has, or all of them when none is near. An option the dialog shows only while another is on, such as codesign/identity behind codesign/enable, is taken when the preset has that one on or the same call turns it on, and otherwise refused naming what shows it. A secret option, such as a signing password, is written to .godot/export_credentials.cfg, where the editor keeps secrets out of the committed file, and its value is never answered. A file an option names that is not there is written and listed under missing_files, or for a secret its option under secretsNamingNoFile. remove_preset takes a preset out, and when it was its platform's runnable preset the next of that platform becomes it, under runnableNow, which is null when the platform has no other; a secret it held is taken out with it. It answers where this engine's export templates belong and whether the preset's platform has them, since an export needs them; list says the same for every preset. An editor open on the project does not see a preset added this way until it restarts. run names, as alsoWritten, what else the export wrote beside its output, such as the .pck a Windows or Linux build cannot start without. Its entries are the errors and warnings the export printed, the newest two hundred distinct ones, one printed more than once carrying times, and errors and warnings count them; exported is true only when this run wrote the output and printed no error.",
|
|
16950
|
+
description: "Export presets and exports. add_preset writes a preset to export_presets.cfg with the keys the editor's Project > Export writes for a new one and every option a new preset of its platform shows, each at its default, and makes it the platform's runnable preset when the platform has none. set_preset changes a preset's export path, its resource filter and the files it lists, its include and exclude filters, its custom features and its platform's options, and answers under changed what each held before and holds now, and under unchanged what already held the value given, with saved false when that is all of it, since the file is then not written; nothing is written when any of it is refused. The option names are the exporter's own, as the Export dialog's Options tab shows them by their paths, such as binary_format/embed_pck, and a name the platform does not have is refused with the nearest it has, or all of them when none is near. An option the dialog shows only while another is on, such as codesign/identity behind codesign/enable, is taken when the preset has that one on or the same call turns it on, and otherwise refused naming what shows it. A secret option, such as a signing password, is written to .godot/export_credentials.cfg, where the editor keeps secrets out of the committed file, and its value is never answered. A file an option names that is not there is written and listed under missing_files, or for a secret its option under secretsNamingNoFile. remove_preset takes a preset out, and when it was its platform's runnable preset the next of that platform becomes it, under runnableNow, which is null when the platform has no other; a secret it held is taken out with it. It answers where this engine's export templates belong and whether the preset's platform has them, since an export needs them; list says the same for every preset. An editor open on the project does not see a preset added this way until it restarts. run names, as alsoWritten, what else the export wrote beside its output, such as the .pck a Windows or Linux build cannot start without. Its entries are the errors and warnings the export printed, the newest two hundred distinct ones, one printed more than once carrying times, and errors and warnings count them; exported is true only when this run wrote the output and printed no error.",
|
|
16897
16951
|
parameters: {
|
|
16898
16952
|
projectPath: PROJECT_PATH,
|
|
16899
16953
|
preset: {
|
|
@@ -16977,7 +17031,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
16977
17031
|
title: "Run tests",
|
|
16978
17032
|
effect: "additive",
|
|
16979
17033
|
description: "Runs the project's gdUnit4 tests and answers with every case that did not pass: where it is, and what the assertion said. Each entry under failed carries its first report as message and detail, and, when it has more than one, its reports under reports in the order the case met them: gdUnit4 goes on past a failed assertion, and a case can fail several and then stop on a runtime error, which makes its status error. Identical reports fold into one with times, at most twenty different ones are kept (reportsLeftOut counts the rest), and past about a megabyte the largest cases keep only their first message (failedWithoutDetail). failures counts the cases that failed an assertion and errors the cases that hit an error, so such a case counts in both. Suites where everything passed are counted, not listed, and an engine message keeps the frames above gdUnit4, not the twenty inside it; identical engine messages come back once under engineEntries, with times saying how often they were printed, and with script, line and function for the project script one points at, as editor_output's entries have. The class list is rebuilt first, so a suite written a moment ago is found, and the rebuild's answer is under classes. What changed on disk since it was imported is then imported before any suite runs, and named under importedFirst. A suite it ran with no .uid beside it is named under uidsMissing, with uidsNote. On Windows and Linux the run gets a user:// of its own, away from a player's saves; on macOS the engine reads user:// off HOME, so it writes where the player keeps theirs, and savesNote says so. The run is headless unless a suite in it needs a window as gdharness test reads it, and then has one, on a desktop of its own on Windows. A run that found nothing to run is never called a pass, and names the path it looked in. A script that does not load stops gdUnit4 before any suite runs: its errors come back in full under scriptErrors, and the scripts that failed only because one they depend on did are listed by path under failedThroughDependency. When they failed on a class whose own script has a parser error, which gdUnit4 never names, that script is checked by the engine and its error comes first under scriptErrors, with the class it declares under declares, and the errors a script has only because that class did not resolve, which the engine reads as Variant, are kept apart under followFromUnresolved. An autoload that does not compile stops the run at once, its errors listed the same way. A client sending a progress token is told as each suite finishes, and at least every twenty seconds. A run that ends without a report, at its timeout or otherwise, names the suites it finished under suitesFinished, the failing ones with their failed cases under suitesFailing, and the one it was in under suiteRunning. When a client cuts a run off, that is kept in the project and the next project_test there carries it under previousRunCut. A run where nothing failed but orphan nodes were left comes back under warnings, with the count per suite: gdUnit4 decides its verdict on those and keeps them out of its report, so they are read off what it printed. A run whose every case passed is still not called passed when it printed a script error that no case failed on: gdUnit4 fails a case on the script errors its logger sees, and it cannot see a stack overflow, so the cases pass on whatever the faulted calls returned. Those errors come back under uncaughtScriptErrors, and under engineEntries by index with detailUnder rather than with their backtrace a second time; a backtrace that repeats, as a recursion's does, has each repeated frame or cycle of frames written once with the frames it covers and how many times. One raised inside assert_error(...).is_runtime_error is the test's own and is not listed there, and none are when the project turns off gdUnit4's report/godot/script_error setting; a suite declares them all the same. Needs gdUnit4 under addons/gdUnit4.",
|
|
16980
|
-
answer: "passed is the verdict to read. exitCode is the engine's own exit, gdUnit4's code for what it saw (100 a case failed, 101 only warnings, 105 script errors it detected), and is 0 beside passed false when the run is failed for something gdUnit4 does not judge, such as an engine error no suite declared. time is gdUnit4's own sum of the seconds its cases took, from its report. tookMs is the whole call in milliseconds, from the class rebuild to the engine's exit, which is what a caller waits for, and tookMsBy splits it into the class rebuild (classes), the import after it (import) and the engine running the suites (engine), each with any wait for an engine slot or the editor's scan in it. The run is judged as gdharness test judges it: undeclaredErrors names each engine error that no suite declared in its GDHARNESS_EXPECTED_ERRORS constant, and each engine warning a suite printed and did not declare in its GDHARNESS_EXPECTED_WARNINGS, marked warning true, with the suite and the case that printed it, and declaredNotPrinted each declared error or warning its case did not print. gdUnit4 does not fail a case on push_error or push_warning, so a case that printed one undeclared is in neither failed nor errors: it is named here, and the run is failed for it. A declared text must be the whole line after ERROR: or WARNING: and its space, so a longer one its case printed holding the text is named under printedInstead. Either fails the run, and each suite holding one is listed with its count. leakedAtExit holds the engine's lines saying it exited still holding objects, resources, memory pages or a server's RIDs, which fail the run too, and the note names any script of the project Godot itself never frees and, on a run with engineArgs [\"--verbose\"], what the engine held. engineErrors counts every engine error the run printed but those a suite declared. orphans totals the orphan nodes gdUnit4 counted, and each suite that left some has its count, and a warning saying how to free them, under warnings, with left naming each case that left some (before or after for one of the suite's hooks, or the one value \"before or after\" where no case began and the two cannot be told apart) and the nodes, by class, name and script. suites lists only the suites with something to say (a case that failed, erred or was skipped, a hook that failed, orphans, or an error undeclared or declared and not printed), and suitesPassed counts the rest. A before() or after() that failed comes back under hookFailures with its suite, line and whole message; failures and errors count cases and leave it out, so the verdict names it as failed hooks, and the cases after a failed before() still run and are counted. Under classes, the classes each addon declares are counted under addedInAddons and changedInAddons rather than named, and a class the rebuild puts back that the cache had after the last rebuild is named under classes.lostSinceLastRebuild, which is the editor writing its shorter list over the file on every save until restarted. A suite needs a window when it declares const GDHARNESS_NEEDS_WINDOW: bool = true, or calls scene_runner and declares nothing; a run holding one has a window, at the size project.godot gives its viewport and with no sound, and windowed is true and windowNote names those suites and any saying it runs headless that shared the window. On a machine with no display such a run is headless, windowed is false, and windowNote says so. " + IMPORTED_FIRST,
|
|
17034
|
+
answer: "passed is the verdict to read. exitCode is the engine's own exit, gdUnit4's code for what it saw (100 a case failed, 101 only warnings, 105 script errors it detected), and is 0 beside passed false when the run is failed for something gdUnit4 does not judge, such as an engine error no suite declared. time is gdUnit4's own sum of the seconds its cases took, from its report. tookMs is the whole call in milliseconds, from the class rebuild to the engine's exit, which is what a caller waits for, and tookMsBy splits it into the class rebuild (classes), the import after it (import) and the engine running the suites (engine), each with any wait for an engine slot or the editor's scan in it; a call that waited a second or more for slots in all is answered with an engine_slot_wait block giving waitedMs and who held them. The run is judged as gdharness test judges it: undeclaredErrors names each engine error that no suite declared in its GDHARNESS_EXPECTED_ERRORS constant, and each engine warning a suite printed and did not declare in its GDHARNESS_EXPECTED_WARNINGS, marked warning true, with the suite and the case that printed it, and declaredNotPrinted each declared error or warning its case did not print. gdUnit4 does not fail a case on push_error or push_warning, so a case that printed one undeclared is in neither failed nor errors: it is named here, and the run is failed for it. A declared text must be the whole line after ERROR: or WARNING: and its space, so a longer one its case printed holding the text is named under printedInstead. Either fails the run, and each suite holding one is listed with its count. leakedAtExit holds the engine's lines saying it exited still holding objects, resources, memory pages or a server's RIDs, which fail the run too, and the note names any script of the project Godot itself never frees and, on a run with engineArgs [\"--verbose\"], what the engine held. engineErrors counts every engine error the run printed but those a suite declared. orphans totals the orphan nodes gdUnit4 counted, and each suite that left some has its count, and a warning saying how to free them, under warnings, with left naming each case that left some (before or after for one of the suite's hooks, or the one value \"before or after\" where no case began and the two cannot be told apart) and the nodes, by class, name and script. suites lists only the suites with something to say (a case that failed, erred or was skipped, a hook that failed, orphans, or an error undeclared or declared and not printed), and suitesPassed counts the rest. A before() or after() that failed comes back under hookFailures with its suite, line and whole message; failures and errors count cases and leave it out, so the verdict names it as failed hooks, and the cases after a failed before() still run and are counted. Under classes, the classes each addon declares are counted under addedInAddons and changedInAddons rather than named, and a class the rebuild puts back that the cache had after the last rebuild is named under classes.lostSinceLastRebuild, which is the editor writing its shorter list over the file on every save until restarted. A suite needs a window when it declares const GDHARNESS_NEEDS_WINDOW: bool = true, or calls scene_runner and declares nothing; a run holding one has a window, at the size project.godot gives its viewport and with no sound, and windowed is true and windowNote names those suites and any saying it runs headless that shared the window. On a machine with no display such a run is headless, windowed is false, and windowNote says so. " + IMPORTED_FIRST,
|
|
16981
17035
|
parameters: {
|
|
16982
17036
|
projectPath: PROJECT_PATH,
|
|
16983
17037
|
path: {
|
|
@@ -17512,7 +17566,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17512
17566
|
name: "script_diagnostics",
|
|
17513
17567
|
title: "Script diagnostics",
|
|
17514
17568
|
effect: "read",
|
|
17515
|
-
description: "Errors and warnings for a script, or for several, from the editor's language server, and whether each is clean. With no editor of this project open, so no language server of it to ask, a short headless engine compiles the scripts instead and the answer says checkedBy: engine rather than language server: every error that stops a script compiling, up to its first syntax error, with its line and no column (a
|
|
17569
|
+
description: "Errors and warnings for a script, or for several, from the editor's language server, and whether each is clean. With no editor of this project open, so no language server of it to ask, a short headless engine compiles the scripts instead and the answer says checkedBy: engine rather than language server: every error that stops a script compiling, up to its first syntax error, with its line and no column (a method or property another class lacks is not one, since GDScript checks a method only on self and a property only named bare: the object may be a subclass that has it, so it fails at run time instead), dependenciesWithErrors naming the other scripts that failed while it loaded, typesMissingFromTheClassCache naming a class the project declares that the engine could not resolve because the class cache lacks it, with staleAnalysis saying what rewrites the cache, and the warnings at the levels the project sets, which a second engine reports by raising each warning set to warn as an error for that run only, each at its line with no column, warnings being null when that engine could not answer; a script with a syntax error is checked for no warnings until it parses. Of several scripts, a language server that stops answering partway leaves the rest to the engine, and checkedBy then says language server, then engine, with checkedByLanguageServer counting the scripts it answered. Each diagnostic carries its severity (error or warning), its message, and where it is as the editor shows it: line and column counted from 1, and endLine and endColumn just past its end. Diagnostics are checked against the project's own files, and the two that the files disprove are named rather than passed on: a member the class cache's file declares, or a project class it extends does, a method, property, constant, static function or enum member, comes back under contradictedByTheFile with the script declaring it, and so does one a diagnostic names alone as an external class member, read against the class it is looked up on in the line it is on; and a class this project declares that the diagnostic could not resolve comes back under typesTheEditorHasNotLoaded, with inTheClassCache saying whether a launched game would resolve it. staleAnalysis then says what to do, and for both states it is editor_rescan first: it asks the editor already running, starts nothing, and has cleared each in every reproduction measured. Two exceptions are named when they apply. For an enum member, constant or static function of a global class the reload comes first: in the one project that has reproduced a stale enum member, editor_rescan with reloadScript on the declaring script cleared it and a plain rescan did not. And an editor whose last scan wrote the class cache shorter than the file holds a list behind the files and writes it on every scan, so on that editor the rescan loads nothing and staleAnalysis says editor_launch restart instead. What follows differs: for a stale analysed type, editor_rescan with reloadScript recompiles the held copy and editor_launch restart is the last resort that costs a window; for a class missing from the cache, project_import refresh_classes rewrites the cache from disk at the cost of a short headless engine, which matters beside a running bench.",
|
|
17516
17570
|
parameters: {
|
|
17517
17571
|
projectPath: PROJECT_PATH,
|
|
17518
17572
|
scriptPath: {
|
|
@@ -17899,7 +17953,8 @@ var init_tool_definitions = __esm(() => {
|
|
|
17899
17953
|
name: "editor_rescan",
|
|
17900
17954
|
title: "Rescan the project",
|
|
17901
17955
|
effect: "additive",
|
|
17902
|
-
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. A scan or an import the editor is already running is waited out first rather than scanned over, which would start a second import over it.
|
|
17956
|
+
description: "Makes the running editor scan the project filesystem, so files written outside it are picked up. A scan or an import the editor is already running is waited out first rather than scanned over, which would start a second import over it. 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. 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. The walk also passes over a file whose .uid alone changed, so the editor keeps the old UID and every engine reading its cache warns of a duplicate; before scanning, each file whose .uid names a UID the editor does not hold for it is read again and named under uidsReread, and files on disk naming one UID between them are named under uidsDuplicatedOnDisk, which reading again cannot settle. A class the scan brings in is named under broughtIn, and every script naming it is reloaded in the editor and named under dependentsReloaded: what the editor compiled from them while it could not see the class stays compiled that way after the scan, and a script extending a new base class went on reporting \"Could not find base class\" until reloaded. One that would not reload is named under dependentsNotReloaded and the call is not ok, as it is not when the script named in reloadScript was not reloaded. A script that fails to compile is tried again once the scripts it is compiled against that the editor holds behind their files are reloaded, which are named under reloadedFirst. An editor importing answers nothing until the import is over, and a hidden one imports on the thread that answers, so a large addon install can leave the rescan itself unanswered: that is waited for as any busy editor is, within timeoutMs, and when the wait runs out first the answer is stillWorking. The classes the editor could not see before that scan are then noted in the project, and the next editor_rescan of the same editor, from any server, names them under broughtIn and reloads what names them, which it could not otherwise know to do, since by then the editor sees them. 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. The other direction is guarded the same way: a class the editor still holds for a script that was renamed or deleted comes back into the cache at a path that is not there, and the next engine to read it fails on \"Could not parse global class\" in whichever correct script shares the bare name, so the cache is rebuilt without it and the answer names it under cacheDropped; the editor goes on holding it until it is restarted, and every scan until then ends in that rebuild. A script or shader written outside the editor has no .uid sidecar until something imports it, and the scan writes one beside it, which a project that commits sidecars needs before the commit. Needs the editor connected.",
|
|
17957
|
+
answer: "waitedMs is the whole call, and waitedForEditorScanMs, given only when a scan or an import was already running, the part spent waiting it out. waitedForEditorAnswerMs, given when an idle editor took a second or more to say so, is how long that took: such an editor is busy on the thread that answers with an earlier request rather than scanning, so the time is added to timeoutMs rather than taken from it, and the note says so. stillWorking is true when a scan was still running at the end of the wait; the scan the call started is looked at once even when the wait has run out, so stillWorking is never said of a scan nothing looked at.",
|
|
17903
17958
|
parameters: {
|
|
17904
17959
|
projectPath: PROJECT_PATH,
|
|
17905
17960
|
timeoutMs: {
|
|
@@ -18557,7 +18612,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18557
18612
|
{
|
|
18558
18613
|
name: "debug_state",
|
|
18559
18614
|
title: "Debugger state",
|
|
18560
|
-
description: "Where the debugged game is stopped: the stack trace, what is in scope at a frame with the values, or the debugger's console output so far, its last thousand lines, with any earlier ones counted under notShown. For a game this server started the output is what the game printed; the errors and warnings it reported, with where each happened, are in editor_output. For a game this server started, its keeper's debugger answers: each frame names its script as the project spells it under script and on this machine under path, and held says which thread stopped and why. For a game the editor plays, the editor's debug adapter answers. A stop is reported by the editor's adapter only to the sessions connected when it happened, so a server that connected afterwards, which is every server after a reconnect, is shown a thread and no frames about a game still sitting at its breakpoint. That server asks the runtime instead: a held game accepts a connection and never answers, and the refusal then says held rather than running, and that the stack cannot be read from here. debug_control continue lets it go, and the next stop is one this session is told about, with its stack. A function that awaited is resumed with no caller below it, since the call that started it returned at the await, so its frame is the only one. The variables give an object as its class and instance id only, and evaluate reads into it: an expression worked out by the game at a frame, with the frame's locals, the globals and every global class in scope and the frame's instance as self, such as wave.spawned or wave.spawned.size(). The game runs what the expression calls, so a call that changes something changes the game. A frame with no instance, a static function's called on its class, is refused, since the engine lets the game go on rather than evaluate there; the frame below it has one. The compiler's own locals, named with @ such as a for loop's @counter_pos, are left out.",
|
|
18615
|
+
description: "Where the debugged game is stopped: the stack trace, what is in scope at a frame with the values, or the debugger's console output so far, its last thousand lines, with any earlier ones counted under notShown. For a game this server started the output is what the game printed; the errors and warnings it reported, with where each happened, are in editor_output, which also has what it printed once it has ended, as its debugger ends with it. For a game this server started, its keeper's debugger answers: each frame names its script as the project spells it under script and on this machine under path, and held says which thread stopped and why. For a game the editor plays, the editor's debug adapter answers. A stop is reported by the editor's adapter only to the sessions connected when it happened, so a server that connected afterwards, which is every server after a reconnect, is shown a thread and no frames about a game still sitting at its breakpoint. That server asks the runtime instead: a held game accepts a connection and never answers, and the refusal then says held rather than running, and that the stack cannot be read from here. debug_control continue lets it go, and the next stop is one this session is told about, with its stack. A function that awaited is resumed with no caller below it, since the call that started it returned at the await, so its frame is the only one. The variables give an object as its class and instance id only, and evaluate reads into it: an expression worked out by the game at a frame, with the frame's locals, the globals and every global class in scope and the frame's instance as self, such as wave.spawned or wave.spawned.size(). The game runs what the expression calls, so a call that changes something changes the game. A frame with no instance, a static function's called on its class, is refused, since the engine lets the game go on rather than evaluate there; the frame below it has one. The compiler's own locals, named with @ such as a for loop's @counter_pos, are left out.",
|
|
18561
18616
|
parameters: {
|
|
18562
18617
|
frameId: {
|
|
18563
18618
|
type: "number",
|
|
@@ -18698,9 +18753,9 @@ function whatItCanChange(tool) {
|
|
|
18698
18753
|
if (destroying.length === 0) {
|
|
18699
18754
|
return "Adds or starts things, and overwrites and removes nothing itself.";
|
|
18700
18755
|
}
|
|
18701
|
-
return `Can overwrite, remove or end what is there, through ${
|
|
18756
|
+
return `Can overwrite, remove or end what is there, through ${listed3(destroying)}.`;
|
|
18702
18757
|
}
|
|
18703
|
-
function
|
|
18758
|
+
function listed3(items) {
|
|
18704
18759
|
const last = items.at(-1) ?? "";
|
|
18705
18760
|
return items.length === 1 ? last : `${items.slice(0, -1).join(", ")} and ${last}`;
|
|
18706
18761
|
}
|
|
@@ -18758,7 +18813,7 @@ var init_tool_reference = __esm(() => {
|
|
|
18758
18813
|
});
|
|
18759
18814
|
|
|
18760
18815
|
// src/suite-plan.ts
|
|
18761
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as
|
|
18816
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync21 } from "node:fs";
|
|
18762
18817
|
import { dirname as dirname11, join as join25, posix as posix3 } from "node:path";
|
|
18763
18818
|
function within(path, folder) {
|
|
18764
18819
|
return path === folder || path.startsWith(`${folder}/`);
|
|
@@ -18775,7 +18830,7 @@ class ProjectScripts {
|
|
|
18775
18830
|
this.projectPath = projectPath;
|
|
18776
18831
|
let settings = {};
|
|
18777
18832
|
try {
|
|
18778
|
-
settings = parseProjectGodot(
|
|
18833
|
+
settings = parseProjectGodot(readFileSync21(join25(projectPath, "project.godot"), "utf8"))["gdharness"] ?? {};
|
|
18779
18834
|
} catch {}
|
|
18780
18835
|
const [section, key] = [NOT_SEARCHED_SETTING, GUESS_WINDOW_SETTING].map((setting) => setting.slice("gdharness/".length));
|
|
18781
18836
|
const listed = settings[section ?? ""];
|
|
@@ -18890,7 +18945,7 @@ class ProjectScripts {
|
|
|
18890
18945
|
}
|
|
18891
18946
|
function readTimes(file) {
|
|
18892
18947
|
try {
|
|
18893
|
-
const parsed = JSON.parse(
|
|
18948
|
+
const parsed = JSON.parse(readFileSync21(file, "utf8"));
|
|
18894
18949
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
18895
18950
|
} catch {
|
|
18896
18951
|
return {};
|
|
@@ -19173,7 +19228,7 @@ function viewportOf(projectPath) {
|
|
|
19173
19228
|
if (!existsSync22(file)) {
|
|
19174
19229
|
return null;
|
|
19175
19230
|
}
|
|
19176
|
-
const text =
|
|
19231
|
+
const text = readFileSync21(file, "utf8");
|
|
19177
19232
|
const width = /^window\/size\/viewport_width\s*=\s*(\d+)/m.exec(text)?.[1];
|
|
19178
19233
|
const height = /^window\/size\/viewport_height\s*=\s*(\d+)/m.exec(text)?.[1];
|
|
19179
19234
|
return width === undefined || height === undefined ? null : { width: Number(width), height: Number(height) };
|
|
@@ -40792,13 +40847,13 @@ var init_stdio = __esm(() => {
|
|
|
40792
40847
|
});
|
|
40793
40848
|
|
|
40794
40849
|
// src/autoload-failure.ts
|
|
40795
|
-
import { existsSync as existsSync24, readFileSync as
|
|
40850
|
+
import { existsSync as existsSync24, readFileSync as readFileSync24 } from "node:fs";
|
|
40796
40851
|
import { join as join28 } from "node:path";
|
|
40797
40852
|
function scriptsAutoloaded(projectPath) {
|
|
40798
40853
|
const scripts = new Map;
|
|
40799
40854
|
let settings;
|
|
40800
40855
|
try {
|
|
40801
|
-
settings = parseProjectGodot(
|
|
40856
|
+
settings = parseProjectGodot(readFileSync24(join28(projectPath, "project.godot"), "utf8"));
|
|
40802
40857
|
} catch {
|
|
40803
40858
|
return scripts;
|
|
40804
40859
|
}
|
|
@@ -40812,7 +40867,7 @@ function scriptsAutoloaded(projectPath) {
|
|
|
40812
40867
|
continue;
|
|
40813
40868
|
}
|
|
40814
40869
|
try {
|
|
40815
|
-
for (const named of
|
|
40870
|
+
for (const named of readFileSync24(scene, "utf8").matchAll(/^\[ext_resource\b[^\]]*\btype="Script"[^\]]*\bpath="(res:\/\/[^"]+)"/gm)) {
|
|
40816
40871
|
scripts.set(named[1] ?? "", name);
|
|
40817
40872
|
}
|
|
40818
40873
|
} catch {}
|
|
@@ -40831,7 +40886,7 @@ var init_autoload_failure = __esm(() => {
|
|
|
40831
40886
|
});
|
|
40832
40887
|
|
|
40833
40888
|
// src/runtime-client.ts
|
|
40834
|
-
import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as
|
|
40889
|
+
import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as readFileSync25, statSync as statSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
40835
40890
|
import { createConnection as createConnection2 } from "node:net";
|
|
40836
40891
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
40837
40892
|
import { dirname as dirname14, join as join29, resolve as resolve11 } from "node:path";
|
|
@@ -40886,7 +40941,7 @@ function reportAlreadyInTranscript(transcript, report) {
|
|
|
40886
40941
|
function parseAnnouncement(file, pid) {
|
|
40887
40942
|
let fields;
|
|
40888
40943
|
try {
|
|
40889
|
-
fields = asParams(JSON.parse(
|
|
40944
|
+
fields = asParams(JSON.parse(readFileSync25(file, "utf8")));
|
|
40890
40945
|
} catch {
|
|
40891
40946
|
return { kind: "rubbish" };
|
|
40892
40947
|
}
|
|
@@ -40958,7 +41013,7 @@ function discoverRuntimes(directories = runtimeDirectories()) {
|
|
|
40958
41013
|
function wentAway(file, pid) {
|
|
40959
41014
|
let project = "";
|
|
40960
41015
|
try {
|
|
40961
|
-
const fields = asParams(JSON.parse(
|
|
41016
|
+
const fields = asParams(JSON.parse(readFileSync25(file, "utf8")));
|
|
40962
41017
|
project = readString(readParams(fields, "project") ?? {}, "path") ?? "";
|
|
40963
41018
|
} catch {
|
|
40964
41019
|
return;
|
|
@@ -41473,14 +41528,14 @@ var init_runtime_client = __esm(() => {
|
|
|
41473
41528
|
});
|
|
41474
41529
|
|
|
41475
41530
|
// src/boot-note.ts
|
|
41476
|
-
import { mkdirSync as mkdirSync11, readFileSync as
|
|
41531
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "node:fs";
|
|
41477
41532
|
import { dirname as dirname15, join as join30 } from "node:path";
|
|
41478
41533
|
function bootNotePath(projectPath) {
|
|
41479
41534
|
return join30(projectPath, ".godot", "gdharness-boot.json");
|
|
41480
41535
|
}
|
|
41481
41536
|
function readScenes(projectPath) {
|
|
41482
41537
|
try {
|
|
41483
|
-
return asParams(asParams(JSON.parse(
|
|
41538
|
+
return asParams(asParams(JSON.parse(readFileSync26(bootNotePath(projectPath), "utf8")))["scenes"]);
|
|
41484
41539
|
} catch {
|
|
41485
41540
|
return {};
|
|
41486
41541
|
}
|
|
@@ -41522,7 +41577,7 @@ var init_boot_note = __esm(() => {
|
|
|
41522
41577
|
});
|
|
41523
41578
|
|
|
41524
41579
|
// src/breakpoint-note.ts
|
|
41525
|
-
import { mkdirSync as mkdirSync12, readFileSync as
|
|
41580
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync27, rmSync as rmSync13, writeFileSync as writeFileSync14 } from "node:fs";
|
|
41526
41581
|
import { dirname as dirname16, isAbsolute as isAbsolute7, join as join31, relative as relative6 } from "node:path";
|
|
41527
41582
|
function breakpointNotePath(projectPath) {
|
|
41528
41583
|
return join31(projectPath, ".godot", "gdharness-breakpoints.json");
|
|
@@ -41551,7 +41606,7 @@ function writeBreakpointNote(projectPath, held) {
|
|
|
41551
41606
|
}
|
|
41552
41607
|
function readBreakpointNote(projectPath) {
|
|
41553
41608
|
try {
|
|
41554
|
-
const parsed = JSON.parse(
|
|
41609
|
+
const parsed = JSON.parse(readFileSync27(breakpointNotePath(projectPath), "utf8"));
|
|
41555
41610
|
if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.breakpoints)) {
|
|
41556
41611
|
return [];
|
|
41557
41612
|
}
|
|
@@ -41584,14 +41639,14 @@ var init_breakpoint_note = __esm(() => {
|
|
|
41584
41639
|
});
|
|
41585
41640
|
|
|
41586
41641
|
// src/class-note.ts
|
|
41587
|
-
import { mkdirSync as mkdirSync13, readFileSync as
|
|
41642
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync28 } from "node:fs";
|
|
41588
41643
|
import { dirname as dirname17, join as join32 } from "node:path";
|
|
41589
41644
|
function classNotePath(projectPath) {
|
|
41590
41645
|
return join32(projectPath, ".godot", "gdharness-classes.json");
|
|
41591
41646
|
}
|
|
41592
41647
|
function readClassNote(projectPath) {
|
|
41593
41648
|
try {
|
|
41594
|
-
const fields = asParams(JSON.parse(
|
|
41649
|
+
const fields = asParams(JSON.parse(readFileSync28(classNotePath(projectPath), "utf8")));
|
|
41595
41650
|
const rebuiltWith = readArray(fields, "rebuiltWith");
|
|
41596
41651
|
if (rebuiltWith === undefined || !rebuiltWith.every((name) => typeof name === "string")) {
|
|
41597
41652
|
return null;
|
|
@@ -41633,7 +41688,7 @@ var init_class_note = __esm(() => {
|
|
|
41633
41688
|
});
|
|
41634
41689
|
|
|
41635
41690
|
// src/config-pin.ts
|
|
41636
|
-
import { existsSync as existsSync26, readFileSync as
|
|
41691
|
+
import { existsSync as existsSync26, readFileSync as readFileSync29 } from "node:fs";
|
|
41637
41692
|
import { join as join33 } from "node:path";
|
|
41638
41693
|
function versionsNamedInConfig(projectPath) {
|
|
41639
41694
|
const config = join33(projectPath, ".mcp.json");
|
|
@@ -41642,7 +41697,7 @@ function versionsNamedInConfig(projectPath) {
|
|
|
41642
41697
|
}
|
|
41643
41698
|
let text;
|
|
41644
41699
|
try {
|
|
41645
|
-
text =
|
|
41700
|
+
text = readFileSync29(config, "utf8");
|
|
41646
41701
|
JSON.parse(text);
|
|
41647
41702
|
} catch {
|
|
41648
41703
|
return [];
|
|
@@ -41663,7 +41718,7 @@ var init_config_pin = __esm(() => {
|
|
|
41663
41718
|
});
|
|
41664
41719
|
|
|
41665
41720
|
// src/cut-test-run.ts
|
|
41666
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as
|
|
41721
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync30, rmSync as rmSync14, writeFileSync as writeFileSync15 } from "node:fs";
|
|
41667
41722
|
import { dirname as dirname18, join as join34 } from "node:path";
|
|
41668
41723
|
function keptAt(projectPath) {
|
|
41669
41724
|
return join34(projectPath, ".godot", "gdharness-reports", "cut-run.json");
|
|
@@ -41682,7 +41737,7 @@ function takeCutTestRun(projectPath) {
|
|
|
41682
41737
|
return null;
|
|
41683
41738
|
}
|
|
41684
41739
|
try {
|
|
41685
|
-
const run = JSON.parse(
|
|
41740
|
+
const run = JSON.parse(readFileSync30(path, "utf8"));
|
|
41686
41741
|
rmSync14(path, { force: true });
|
|
41687
41742
|
return typeof run.cutAt === "string" && Array.isArray(run.paths) && run.paths.every((path) => typeof path === "string") ? run : null;
|
|
41688
41743
|
} catch {
|
|
@@ -42418,7 +42473,7 @@ import {
|
|
|
42418
42473
|
existsSync as existsSync28,
|
|
42419
42474
|
mkdirSync as mkdirSync15,
|
|
42420
42475
|
openSync as openSync4,
|
|
42421
|
-
readFileSync as
|
|
42476
|
+
readFileSync as readFileSync31,
|
|
42422
42477
|
readSync as readSync2,
|
|
42423
42478
|
rmSync as rmSync15,
|
|
42424
42479
|
statSync as statSync16,
|
|
@@ -42433,7 +42488,7 @@ function editorLogNotePath(projectPath) {
|
|
|
42433
42488
|
}
|
|
42434
42489
|
function readEditorLogNote(projectPath) {
|
|
42435
42490
|
try {
|
|
42436
|
-
const fields = asParams(JSON.parse(
|
|
42491
|
+
const fields = asParams(JSON.parse(readFileSync31(editorLogNotePath(projectPath), "utf8")));
|
|
42437
42492
|
const pid = readNumber(fields, "pid");
|
|
42438
42493
|
const startedAt = readString(fields, "startedAt");
|
|
42439
42494
|
const processStartedAt = readNumber(fields, "processStartedAt");
|
|
@@ -42537,7 +42592,7 @@ function foldProgress(text) {
|
|
|
42537
42592
|
function theFirstOf(path) {
|
|
42538
42593
|
const whole = statSync16(path).size;
|
|
42539
42594
|
if (whole <= MOST_CONSOLE_BYTES) {
|
|
42540
|
-
return { text:
|
|
42595
|
+
return { text: readFileSync31(path, "utf8") };
|
|
42541
42596
|
}
|
|
42542
42597
|
const handle = openSync4(path, "r");
|
|
42543
42598
|
try {
|
|
@@ -42698,7 +42753,7 @@ var init_editor_log = __esm(() => {
|
|
|
42698
42753
|
});
|
|
42699
42754
|
|
|
42700
42755
|
// src/rename.ts
|
|
42701
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as
|
|
42756
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as readFileSync32, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync17 } from "node:fs";
|
|
42702
42757
|
import { dirname as dirname20, posix as posix4 } from "node:path";
|
|
42703
42758
|
|
|
42704
42759
|
class Script {
|
|
@@ -43403,7 +43458,7 @@ function rewritesOf(plan, texts, move) {
|
|
|
43403
43458
|
}
|
|
43404
43459
|
function applyRewrites(rewrites) {
|
|
43405
43460
|
for (const rewrite of rewrites) {
|
|
43406
|
-
const now =
|
|
43461
|
+
const now = readFileSync32(rewrite.absolute, "utf8");
|
|
43407
43462
|
if (now !== rewrite.before) {
|
|
43408
43463
|
throw new Error(`${rewrite.path} changed on disk while the rename was being worked out; nothing was written`);
|
|
43409
43464
|
}
|
|
@@ -43493,18 +43548,18 @@ function onDiskSpelling(path) {
|
|
|
43493
43548
|
}
|
|
43494
43549
|
}
|
|
43495
43550
|
function usedAsIdentifier(scripts, name, most) {
|
|
43496
|
-
const found =
|
|
43551
|
+
const found = new Set;
|
|
43497
43552
|
for (const script of scripts.values()) {
|
|
43498
43553
|
for (const occurrence of script.occurrences(name)) {
|
|
43499
43554
|
if (occurrence.kind === "code" && !occurrence.afterDot) {
|
|
43500
|
-
found.
|
|
43501
|
-
if (found.
|
|
43502
|
-
return found;
|
|
43555
|
+
found.add(`${script.path}:${script.lines.positionOf(occurrence.offset).line + 1}`);
|
|
43556
|
+
if (found.size >= most) {
|
|
43557
|
+
return [...found];
|
|
43503
43558
|
}
|
|
43504
43559
|
}
|
|
43505
43560
|
}
|
|
43506
43561
|
}
|
|
43507
|
-
return found;
|
|
43562
|
+
return [...found];
|
|
43508
43563
|
}
|
|
43509
43564
|
function autoloadNames(texts) {
|
|
43510
43565
|
const settings = texts.find((file) => file.path === "res://project.godot");
|
|
@@ -43568,7 +43623,7 @@ async function renameSymbol(request, services) {
|
|
|
43568
43623
|
conflicts.push(`${newName} is already an autoload in project.godot`);
|
|
43569
43624
|
}
|
|
43570
43625
|
for (const place of usedAsIdentifier(scripts, newName, 10)) {
|
|
43571
|
-
conflicts.push(`${newName} is already
|
|
43626
|
+
conflicts.push(`${newName} is already used in code at ${place}`);
|
|
43572
43627
|
}
|
|
43573
43628
|
const taken = (await services.namesTaken([newName], null))[newName];
|
|
43574
43629
|
if (taken !== undefined && taken.as.length > 0) {
|
|
@@ -43971,7 +44026,7 @@ import {
|
|
|
43971
44026
|
existsSync as existsSync31,
|
|
43972
44027
|
mkdirSync as mkdirSync18,
|
|
43973
44028
|
readdirSync as readdirSync17,
|
|
43974
|
-
readFileSync as
|
|
44029
|
+
readFileSync as readFileSync33,
|
|
43975
44030
|
renameSync as renameSync4,
|
|
43976
44031
|
statSync as statSync17,
|
|
43977
44032
|
writeFileSync as writeFileSync19
|
|
@@ -44131,7 +44186,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
44131
44186
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), null, [from]);
|
|
44132
44187
|
const binaries = [];
|
|
44133
44188
|
for (const path of binaryResources(projectPath)) {
|
|
44134
|
-
const bytes =
|
|
44189
|
+
const bytes = readFileSync33(join37(projectPath, path.slice("res://".length)));
|
|
44135
44190
|
const names = [...moves.keys()].find((moving) => bytes.includes(moving));
|
|
44136
44191
|
if (names !== undefined) {
|
|
44137
44192
|
binaries.push({
|
|
@@ -44192,7 +44247,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
44192
44247
|
}
|
|
44193
44248
|
function applyFileMove(outcome) {
|
|
44194
44249
|
for (const rewrite of outcome.inPlace) {
|
|
44195
|
-
if (
|
|
44250
|
+
if (readFileSync33(rewrite.absolute, "utf8") !== rewrite.before) {
|
|
44196
44251
|
throw new Error(`${rewrite.path} changed on disk while the move was being worked out; nothing was written`);
|
|
44197
44252
|
}
|
|
44198
44253
|
}
|
|
@@ -44200,7 +44255,7 @@ function applyFileMove(outcome) {
|
|
|
44200
44255
|
if (!existsSync31(file.absoluteFrom)) {
|
|
44201
44256
|
throw new Error(`${file.from} is gone from disk; nothing was written`);
|
|
44202
44257
|
}
|
|
44203
|
-
if (file.text !== null &&
|
|
44258
|
+
if (file.text !== null && readFileSync33(file.absoluteFrom, "utf8") !== file.text.before) {
|
|
44204
44259
|
throw new Error(`${file.from} changed on disk while the move was being worked out; nothing was written`);
|
|
44205
44260
|
}
|
|
44206
44261
|
if (existsSync31(file.absoluteTo) && !sameFile(file.absoluteFrom, file.absoluteTo)) {
|
|
@@ -48314,7 +48369,7 @@ var init_prompts = __esm(() => {
|
|
|
48314
48369
|
});
|
|
48315
48370
|
|
|
48316
48371
|
// src/restart-note.ts
|
|
48317
|
-
import { mkdirSync as mkdirSync20, readFileSync as
|
|
48372
|
+
import { mkdirSync as mkdirSync20, readFileSync as readFileSync34, rmSync as rmSync17, writeFileSync as writeFileSync20 } from "node:fs";
|
|
48318
48373
|
import { dirname as dirname24, join as join39 } from "node:path";
|
|
48319
48374
|
function restartNotePath(projectPath) {
|
|
48320
48375
|
return join39(projectPath, ".godot", "gdharness-restart.json");
|
|
@@ -48331,7 +48386,7 @@ function noteRestartBegun(note) {
|
|
|
48331
48386
|
}
|
|
48332
48387
|
function restartOwed(projectPath) {
|
|
48333
48388
|
try {
|
|
48334
|
-
const parsed = JSON.parse(
|
|
48389
|
+
const parsed = JSON.parse(readFileSync34(restartNotePath(projectPath), "utf8"));
|
|
48335
48390
|
if (typeof parsed !== "object" || parsed === null) {
|
|
48336
48391
|
return null;
|
|
48337
48392
|
}
|
|
@@ -48357,7 +48412,7 @@ var init_restart_note = __esm(() => {
|
|
|
48357
48412
|
|
|
48358
48413
|
// src/run-record.ts
|
|
48359
48414
|
import { createHash as createHash7 } from "node:crypto";
|
|
48360
|
-
import { mkdirSync as mkdirSync21, openSync as openSync5, readdirSync as readdirSync18, readFileSync as
|
|
48415
|
+
import { mkdirSync as mkdirSync21, openSync as openSync5, readdirSync as readdirSync18, readFileSync as readFileSync35, rmSync as rmSync18, statSync as statSync19 } from "node:fs";
|
|
48361
48416
|
import { basename as basename11, join as join40, resolve as resolve13 } from "node:path";
|
|
48362
48417
|
function runsDirectory() {
|
|
48363
48418
|
return join40(runtimeDirectory(), "runs");
|
|
@@ -48381,7 +48436,7 @@ function writeLatestRun(servedBy, latest) {
|
|
|
48381
48436
|
}
|
|
48382
48437
|
function readLatestRun(servedBy, directory = runtimeDirectory()) {
|
|
48383
48438
|
try {
|
|
48384
|
-
const fields = JSON.parse(
|
|
48439
|
+
const fields = JSON.parse(readFileSync35(latestRunPath(servedBy, directory), "utf8"));
|
|
48385
48440
|
if (typeof fields !== "object" || fields === null) {
|
|
48386
48441
|
return null;
|
|
48387
48442
|
}
|
|
@@ -48430,7 +48485,7 @@ function readEditorRunNote(projectPath) {
|
|
|
48430
48485
|
function editorNoteAt(path) {
|
|
48431
48486
|
let parsed;
|
|
48432
48487
|
try {
|
|
48433
|
-
parsed = JSON.parse(
|
|
48488
|
+
parsed = JSON.parse(readFileSync35(path, "utf8"));
|
|
48434
48489
|
} catch {
|
|
48435
48490
|
return null;
|
|
48436
48491
|
}
|
|
@@ -48480,7 +48535,7 @@ function everyRunRecord() {
|
|
|
48480
48535
|
function recordAt(path) {
|
|
48481
48536
|
let parsed;
|
|
48482
48537
|
try {
|
|
48483
|
-
parsed = JSON.parse(
|
|
48538
|
+
parsed = JSON.parse(readFileSync35(path, "utf8"));
|
|
48484
48539
|
} catch {
|
|
48485
48540
|
return null;
|
|
48486
48541
|
}
|
|
@@ -48561,7 +48616,7 @@ async function runningAs(pid) {
|
|
|
48561
48616
|
const began = await startedAt(pid, null);
|
|
48562
48617
|
const when = began === null ? {} : { startedAt: began };
|
|
48563
48618
|
if (process.platform === "linux") {
|
|
48564
|
-
const raw =
|
|
48619
|
+
const raw = readFileSync35(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
|
|
48565
48620
|
return raw === "" ? null : { kind: "commandLine", text: raw, ...when };
|
|
48566
48621
|
}
|
|
48567
48622
|
const args = (await runHidden("ps", ["-p", String(pid), "-o", "args="], { timeout: 15000 })).stdout.trim();
|
|
@@ -48757,10 +48812,10 @@ var init_run_record = __esm(() => {
|
|
|
48757
48812
|
});
|
|
48758
48813
|
|
|
48759
48814
|
// src/script-profile.ts
|
|
48760
|
-
import { readFileSync as
|
|
48815
|
+
import { readFileSync as readFileSync36 } from "node:fs";
|
|
48761
48816
|
function readProfileFile(path) {
|
|
48762
48817
|
try {
|
|
48763
|
-
const parsed = JSON.parse(
|
|
48818
|
+
const parsed = JSON.parse(readFileSync36(path, "utf8"));
|
|
48764
48819
|
return typeof parsed === "object" && typeof parsed.connected === "boolean" ? parsed : null;
|
|
48765
48820
|
} catch {
|
|
48766
48821
|
return null;
|
|
@@ -48818,7 +48873,7 @@ function writeProfileMark(path, mark) {
|
|
|
48818
48873
|
}
|
|
48819
48874
|
function readProfileMark(path) {
|
|
48820
48875
|
try {
|
|
48821
|
-
const parsed = JSON.parse(
|
|
48876
|
+
const parsed = JSON.parse(readFileSync36(path, "utf8"));
|
|
48822
48877
|
return typeof parsed === "object" && typeof parsed.totals === "object" ? parsed : null;
|
|
48823
48878
|
} catch {
|
|
48824
48879
|
return null;
|
|
@@ -49150,7 +49205,7 @@ import {
|
|
|
49150
49205
|
mkdirSync as mkdirSync23,
|
|
49151
49206
|
openSync as openSync6,
|
|
49152
49207
|
readdirSync as readdirSync19,
|
|
49153
|
-
readFileSync as
|
|
49208
|
+
readFileSync as readFileSync37,
|
|
49154
49209
|
readSync as readSync3,
|
|
49155
49210
|
realpathSync as realpathSync5,
|
|
49156
49211
|
rmdirSync as rmdirSync2,
|
|
@@ -49171,9 +49226,9 @@ function greetingWaitMs() {
|
|
|
49171
49226
|
return waitFromEnv("GDHARNESS_GREETING_WAIT_MS", 1e4);
|
|
49172
49227
|
}
|
|
49173
49228
|
function pictureToSend(pngPath, jpegPath) {
|
|
49174
|
-
const png =
|
|
49229
|
+
const png = readFileSync37(pngPath);
|
|
49175
49230
|
const beside = pngPath.replace(/\.png$/, ".jpg");
|
|
49176
|
-
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ?
|
|
49231
|
+
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync34(beside) ? readFileSync37(beside) : null;
|
|
49177
49232
|
const sent = jpeg !== null && jpeg.length < png.length ? jpeg : png;
|
|
49178
49233
|
return {
|
|
49179
49234
|
data: sent.toString("base64"),
|
|
@@ -49652,7 +49707,7 @@ function endedToStartThis(ended) {
|
|
|
49652
49707
|
return ` ${which} was ended to start this one; its output is no longer what editor_output answers about.`;
|
|
49653
49708
|
}
|
|
49654
49709
|
function lineNothingStopsOn(absolutePath, relativePath, line) {
|
|
49655
|
-
const text =
|
|
49710
|
+
const text = readFileSync37(absolutePath, "utf8");
|
|
49656
49711
|
const lines = text === "" ? 0 : text.split(`
|
|
49657
49712
|
`).length - (text.endsWith(`
|
|
49658
49713
|
`) ? 1 : 0);
|
|
@@ -49863,7 +49918,7 @@ function notRunNote(notRun, failFast) {
|
|
|
49863
49918
|
function presetsIn(projectPath) {
|
|
49864
49919
|
let text;
|
|
49865
49920
|
try {
|
|
49866
|
-
text =
|
|
49921
|
+
text = readFileSync37(join43(projectPath, "export_presets.cfg"), "utf8");
|
|
49867
49922
|
} catch {
|
|
49868
49923
|
return null;
|
|
49869
49924
|
}
|
|
@@ -50013,7 +50068,7 @@ function rewriteBusNamed(projectPath, from, to) {
|
|
|
50013
50068
|
const rewritten = [];
|
|
50014
50069
|
for (const file of projectFiles(projectPath, [".tscn", ".tres"])) {
|
|
50015
50070
|
const absolute = join43(projectPath, file);
|
|
50016
|
-
const lines =
|
|
50071
|
+
const lines = readFileSync37(absolute, "utf8").split(`
|
|
50017
50072
|
`);
|
|
50018
50073
|
const at = [];
|
|
50019
50074
|
const after = lines.map((line, index) => {
|
|
@@ -50032,7 +50087,7 @@ function rewriteBusNamed(projectPath, from, to) {
|
|
|
50032
50087
|
}
|
|
50033
50088
|
const namedInScripts = [];
|
|
50034
50089
|
for (const file of projectFiles(projectPath, [".gd"])) {
|
|
50035
|
-
|
|
50090
|
+
readFileSync37(join43(projectPath, file), "utf8").split(`
|
|
50036
50091
|
`).forEach((line, index) => {
|
|
50037
50092
|
if (line.includes(`"${from}"`)) {
|
|
50038
50093
|
namedInScripts.push({ file: `res://${file}`, line: index + 1, text: line.trim() });
|
|
@@ -50317,7 +50372,7 @@ function profileFrameFunctions(projectPath) {
|
|
|
50317
50372
|
let projectGodot = null;
|
|
50318
50373
|
if (projectPath !== null) {
|
|
50319
50374
|
try {
|
|
50320
|
-
projectGodot =
|
|
50375
|
+
projectGodot = readFileSync37(join43(projectPath, "project.godot"), "utf8");
|
|
50321
50376
|
} catch {}
|
|
50322
50377
|
}
|
|
50323
50378
|
return frameFunctionsFor(queuedMessagesOf(projectGodot));
|
|
@@ -50341,7 +50396,7 @@ function projectSourceOf(projectPath) {
|
|
|
50341
50396
|
let source = null;
|
|
50342
50397
|
if (inside.ok) {
|
|
50343
50398
|
try {
|
|
50344
|
-
source =
|
|
50399
|
+
source = readFileSync37(inside.absolutePath, "utf8");
|
|
50345
50400
|
} catch {}
|
|
50346
50401
|
}
|
|
50347
50402
|
read.set(script, source);
|
|
@@ -50513,7 +50568,7 @@ function foldedEntriesAnswer(log, floor = "warning") {
|
|
|
50513
50568
|
}
|
|
50514
50569
|
function gdUnitFailsOnScriptErrors(projectPath) {
|
|
50515
50570
|
try {
|
|
50516
|
-
return settingKeys(
|
|
50571
|
+
return settingKeys(readFileSync37(join43(projectPath, "project.godot"), "utf8")).get("gdunit4/report/godot/script_error") !== false;
|
|
50517
50572
|
} catch {
|
|
50518
50573
|
return true;
|
|
50519
50574
|
}
|
|
@@ -50645,7 +50700,7 @@ function engineChecked(why) {
|
|
|
50645
50700
|
return {
|
|
50646
50701
|
checkedBy: "engine",
|
|
50647
50702
|
languageServer: why,
|
|
50648
|
-
note: "No editor of this project is open to ask, so a headless engine compiled the scripts the way loading them does. It reports every error that stops a script compiling, at its line and without a column, but stops reading a script at its first syntax error, so an error after one shows once it is fixed. A second engine reports the warnings, at the levels the project sets, by raising each warning set to warn as an error for that run only, since the engine tells a warning as one only to an editor; each comes at its line without a column, and warnings is null when that engine could not answer. editor_launch with hidden: true opens this project's editor without a window, and its language server reports both with their columns."
|
|
50703
|
+
note: "No editor of this project is open to ask, so a headless engine compiled the scripts the way loading them does. It reports every error that stops a script compiling, at its line and without a column, but stops reading a script at its first syntax error, so an error after one shows once it is fixed, and so do its warnings, since a script that does not parse is not checked for any. A second engine reports the warnings, at the levels the project sets, by raising each warning set to warn as an error for that run only, since the engine tells a warning as one only to an editor; each comes at its line without a column, and warnings is null when that engine could not answer. editor_launch with hidden: true opens this project's editor without a window, and its language server reports both with their columns."
|
|
50649
50704
|
};
|
|
50650
50705
|
}
|
|
50651
50706
|
function asWarning(raised) {
|
|
@@ -50660,11 +50715,11 @@ function isDirectory(path) {
|
|
|
50660
50715
|
}
|
|
50661
50716
|
}
|
|
50662
50717
|
function mainSceneOf(projectFile) {
|
|
50663
|
-
const scene = parseProjectGodot(
|
|
50718
|
+
const scene = parseProjectGodot(readFileSync37(projectFile, "utf8"))["application"]?.["run/main_scene"];
|
|
50664
50719
|
return typeof scene === "string" && scene !== "" ? scene : null;
|
|
50665
50720
|
}
|
|
50666
50721
|
function editorPlaysHeadless(projectFile) {
|
|
50667
|
-
const runArgs = parseProjectGodot(
|
|
50722
|
+
const runArgs = parseProjectGodot(readFileSync37(projectFile, "utf8"))["editor"]?.["run/main_run_args"];
|
|
50668
50723
|
return typeof runArgs === "string" && /(?:^|\s)--headless(?:\s|$)/.test(runArgs);
|
|
50669
50724
|
}
|
|
50670
50725
|
function ownArguments(params) {
|
|
@@ -51117,12 +51172,16 @@ class GodotServer {
|
|
|
51117
51172
|
};
|
|
51118
51173
|
const call = this.callsTaken++;
|
|
51119
51174
|
this.inFlight.set(call, { tool: spec.name, op: checked.op ?? "", startedAt: Date.now() });
|
|
51175
|
+
const slotWaits = { ms: 0, said: undefined };
|
|
51120
51176
|
try {
|
|
51121
51177
|
const answer = await withCallSignal(ctx.mcpReq.signal, () => this.answered(spec.name, checked.op ?? "", args), progress, {
|
|
51122
51178
|
everyMs: CALL_HEARTBEAT_MS,
|
|
51123
51179
|
said: (elapsedMs) => stillGoingSaid(spec.name, checked.op, elapsedMs)
|
|
51180
|
+
}, slotWaits);
|
|
51181
|
+
const waited = slotWaits.said === undefined || slotWaits.ms < 1000 ? answer : this.saying(answer, {
|
|
51182
|
+
engine_slot_wait: { waitedMs: slotWaits.ms, note: slotWaits.said(slotWaits.ms) }
|
|
51124
51183
|
});
|
|
51125
|
-
return this.withinTheClientsLimit(spec.name, this.withFeedbackNotice(this.withUpdateNotice(
|
|
51184
|
+
return this.withinTheClientsLimit(spec.name, this.withFeedbackNotice(this.withUpdateNotice(waited)));
|
|
51126
51185
|
} finally {
|
|
51127
51186
|
this.inFlight.delete(call);
|
|
51128
51187
|
}
|
|
@@ -51801,6 +51860,10 @@ class GodotServer {
|
|
|
51801
51860
|
if (kept !== null) {
|
|
51802
51861
|
return await this.askTheKeptGame(kept.keeper, keptGameRequest(tool, op, args), kept.projectPath ?? "");
|
|
51803
51862
|
}
|
|
51863
|
+
const last = this.activeProcess;
|
|
51864
|
+
if (tool === "debug_state" && op === "output" && last !== null && !last.throughEditor && last.keeper !== undefined) {
|
|
51865
|
+
return this.createErrorResponse("The game this server started has ended, and its debugger, which held its console output, ended with it.", ["editor_output reads what the game printed, with the errors and warnings it reported"]);
|
|
51866
|
+
}
|
|
51804
51867
|
if (tool === "debug_state" && op === "output") {
|
|
51805
51868
|
return await this.handleDAP("dap_get_output", args);
|
|
51806
51869
|
}
|
|
@@ -52579,7 +52642,7 @@ class GodotServer {
|
|
|
52579
52642
|
if (!engine.ok) {
|
|
52580
52643
|
return engine.response;
|
|
52581
52644
|
}
|
|
52582
|
-
const application = parseProjectGodot(
|
|
52645
|
+
const application = parseProjectGodot(readFileSync37(project.value.file, "utf8"))["application"] ?? {};
|
|
52583
52646
|
const name = application["config/name"];
|
|
52584
52647
|
const mainScene = application["run/main_scene"];
|
|
52585
52648
|
const info = {
|
|
@@ -53130,13 +53193,13 @@ ${platform}`;
|
|
|
53130
53193
|
const reportsDir = join43(project.value.path, ".godot", ...ours.split("/"));
|
|
53131
53194
|
let report = null;
|
|
53132
53195
|
let reportProblem = null;
|
|
53133
|
-
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ?
|
|
53196
|
+
const casePrinted = withNestedErrors(readRun(existsSync34(engineLog) ? readFileSync37(engineLog, "utf8") : ""), run.log.all);
|
|
53134
53197
|
const declaredErrors = readExpected(expectedFile);
|
|
53135
53198
|
try {
|
|
53136
53199
|
const written = existsSync34(reportsDir) && notCompiled === null ? readdirSync19(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
53137
53200
|
const newest = written.at(-1);
|
|
53138
53201
|
if (newest !== undefined) {
|
|
53139
|
-
report = parseJUnit(
|
|
53202
|
+
report = parseJUnit(readFileSync37(join43(reportsDir, newest, "results.xml"), "utf8"));
|
|
53140
53203
|
}
|
|
53141
53204
|
} catch (error) {
|
|
53142
53205
|
reportProblem = errorMessage(error);
|
|
@@ -53674,7 +53737,7 @@ ${error.text}`;
|
|
|
53674
53737
|
return null;
|
|
53675
53738
|
}
|
|
53676
53739
|
try {
|
|
53677
|
-
return
|
|
53740
|
+
return readFileSync37(contained.absolutePath, "utf8");
|
|
53678
53741
|
} catch {
|
|
53679
53742
|
return null;
|
|
53680
53743
|
}
|
|
@@ -53768,7 +53831,7 @@ ${error.text}`;
|
|
|
53768
53831
|
return null;
|
|
53769
53832
|
}
|
|
53770
53833
|
try {
|
|
53771
|
-
return
|
|
53834
|
+
return readFileSync37(contained.absolutePath, "utf8");
|
|
53772
53835
|
} catch {
|
|
53773
53836
|
return null;
|
|
53774
53837
|
}
|
|
@@ -54287,7 +54350,7 @@ ${error.text}`;
|
|
|
54287
54350
|
return null;
|
|
54288
54351
|
}
|
|
54289
54352
|
try {
|
|
54290
|
-
return settingKeys(
|
|
54353
|
+
return settingKeys(readFileSync37(join43(projectPath, "project.godot"), "utf8"));
|
|
54291
54354
|
} catch {
|
|
54292
54355
|
return null;
|
|
54293
54356
|
}
|
|
@@ -55112,7 +55175,7 @@ ${error.text}`;
|
|
|
55112
55175
|
return 0;
|
|
55113
55176
|
}
|
|
55114
55177
|
try {
|
|
55115
|
-
return reportAlreadyInTranscript(
|
|
55178
|
+
return reportAlreadyInTranscript(readFileSync37(game.transcript), readFileSync37(report));
|
|
55116
55179
|
} catch (error) {
|
|
55117
55180
|
this.logDebug(`Could not compare a picked-up run's report with its transcript: ${errorMessage(error)}`);
|
|
55118
55181
|
return 0;
|
|
@@ -56496,6 +56559,8 @@ ${error.text}`;
|
|
|
56496
56559
|
let writtenBefore = null;
|
|
56497
56560
|
let blind = { unseen: [] };
|
|
56498
56561
|
let waitedForEditorMs = 0;
|
|
56562
|
+
let answerStalledMs = 0;
|
|
56563
|
+
const deadline = () => started + timeoutMs + answerStalledMs;
|
|
56499
56564
|
let startUnanswered = false;
|
|
56500
56565
|
let completedBefore;
|
|
56501
56566
|
let uidsReread = [];
|
|
@@ -56503,7 +56568,15 @@ ${error.text}`;
|
|
|
56503
56568
|
for (;; ) {
|
|
56504
56569
|
const busySince = Date.now();
|
|
56505
56570
|
let wasBusy = false;
|
|
56506
|
-
while (Date.now()
|
|
56571
|
+
while (Date.now() < deadline()) {
|
|
56572
|
+
const asked = Date.now();
|
|
56573
|
+
if (!await this.editorIsScanningOrImporting()) {
|
|
56574
|
+
const took = Date.now() - asked;
|
|
56575
|
+
if (took >= SLOW_ANSWER_MS) {
|
|
56576
|
+
answerStalledMs += took;
|
|
56577
|
+
}
|
|
56578
|
+
break;
|
|
56579
|
+
}
|
|
56507
56580
|
wasBusy = true;
|
|
56508
56581
|
await new Promise((settle) => setTimeout(settle, 100));
|
|
56509
56582
|
}
|
|
@@ -56528,7 +56601,7 @@ ${error.text}`;
|
|
|
56528
56601
|
if (duplicated !== undefined) {
|
|
56529
56602
|
uidsDuplicatedOnDisk = duplicated.map((group) => Array.isArray(group) ? group.map(String) : []);
|
|
56530
56603
|
}
|
|
56531
|
-
if (firstAnswer["started"] !== false || Date.now()
|
|
56604
|
+
if (firstAnswer["started"] !== false || Date.now() >= deadline()) {
|
|
56532
56605
|
break;
|
|
56533
56606
|
}
|
|
56534
56607
|
await new Promise((settle) => setTimeout(settle, 100));
|
|
@@ -56538,7 +56611,9 @@ ${error.text}`;
|
|
|
56538
56611
|
const ghosts = blind.stillHeld ?? [];
|
|
56539
56612
|
let busy = true;
|
|
56540
56613
|
let idleSince = null;
|
|
56541
|
-
|
|
56614
|
+
let looked = false;
|
|
56615
|
+
while (!looked || Date.now() < deadline()) {
|
|
56616
|
+
looked = true;
|
|
56542
56617
|
await new Promise((settle) => setTimeout(settle, 100));
|
|
56543
56618
|
let status;
|
|
56544
56619
|
try {
|
|
@@ -56584,6 +56659,7 @@ ${error.text}`;
|
|
|
56584
56659
|
let reloaded = {};
|
|
56585
56660
|
const reloadedFirst = [];
|
|
56586
56661
|
let builtOn;
|
|
56662
|
+
let builtOnUnchecked = false;
|
|
56587
56663
|
const reloadingSource = reloading === undefined || projectPath === "" ? null : this.sourceOfClass(projectPath, reloading);
|
|
56588
56664
|
if (reloading !== undefined && reloadingSource !== null && isToolScript(reloadingSource)) {
|
|
56589
56665
|
reloaded = {
|
|
@@ -56601,6 +56677,7 @@ ${error.text}`;
|
|
|
56601
56677
|
answer = await reloadAsked();
|
|
56602
56678
|
}
|
|
56603
56679
|
builtOn = first.said;
|
|
56680
|
+
builtOnUnchecked = first.unchecked === true;
|
|
56604
56681
|
}
|
|
56605
56682
|
const methods = readArray(answer, "methods");
|
|
56606
56683
|
const listed = (field) => {
|
|
@@ -56627,7 +56704,8 @@ ${error.text}`;
|
|
|
56627
56704
|
names: projectPath === "" ? [] : this.classesAScriptNames(projectPath, script),
|
|
56628
56705
|
restored: answer["restored"] === true,
|
|
56629
56706
|
restoredAs: readString(answer, "restoredAs") ?? "",
|
|
56630
|
-
...builtOn === undefined ? {} : { builtOn }
|
|
56707
|
+
...builtOn === undefined ? {} : { builtOn },
|
|
56708
|
+
...builtOnUnchecked ? { builtOnUnchecked } : {}
|
|
56631
56709
|
})
|
|
56632
56710
|
};
|
|
56633
56711
|
} else {
|
|
@@ -56655,6 +56733,9 @@ ${error.text}`;
|
|
|
56655
56733
|
const dependents = busy || projectPath === "" || broughtIn.length === 0 ? null : await this.reloadDependents(projectPath, broughtIn);
|
|
56656
56734
|
const stillGone = lost.filter((name) => !restored.includes(name));
|
|
56657
56735
|
const notes = [];
|
|
56736
|
+
if (answerStalledMs > 0) {
|
|
56737
|
+
notes.push(`The editor took ${(answerStalledMs / 1000).toFixed(1)} seconds to say it was idle, busy on the thread that answers with an earlier request, and that time was added to the wait rather than taken from it.`);
|
|
56738
|
+
}
|
|
56658
56739
|
if (busy) {
|
|
56659
56740
|
notes.push(startUnanswered ? "The editor took the rescan in and did not answer it before the wait ran out, which is an editor importing: a hidden editor imports on the thread that answers, and answers nothing until it is done. It carries the scan out once it is free, so new files may not be visible yet." : "The editor was still scanning or importing when the wait ran out, so new files may not be visible yet.");
|
|
56660
56741
|
if (unseenBefore.length > 0) {
|
|
@@ -56683,6 +56764,7 @@ ${error.text}`;
|
|
|
56683
56764
|
stillWorking: busy,
|
|
56684
56765
|
waitedMs: Date.now() - started,
|
|
56685
56766
|
waitedForEditorScanMs: waitedForEditorMs > 0 ? waitedForEditorMs : undefined,
|
|
56767
|
+
waitedForEditorAnswerMs: answerStalledMs > 0 ? answerStalledMs : undefined,
|
|
56686
56768
|
reloadedAs: reloaded.as,
|
|
56687
56769
|
...reloadDifference(reloaded),
|
|
56688
56770
|
...args["listMembers"] === true ? {
|
|
@@ -56800,17 +56882,20 @@ ${error.text}`;
|
|
|
56800
56882
|
try {
|
|
56801
56883
|
const answer = asParams(await this.godotBridge.invokeTool("scripts_behind", { scriptPaths }));
|
|
56802
56884
|
const behind = readArray(answer, "behind");
|
|
56803
|
-
return behind === undefined ?
|
|
56885
|
+
return behind === undefined ? { unchecked: "the editor answered without a list of them" } : { behind: behind.map(String), unsaved: (readArray(answer, "unsavedInEditor") ?? []).map(String) };
|
|
56804
56886
|
} catch (error) {
|
|
56805
|
-
|
|
56806
|
-
return null;
|
|
56887
|
+
return { unchecked: `the editor would not say: ${errorMessage(error)}` };
|
|
56807
56888
|
}
|
|
56808
56889
|
}
|
|
56809
56890
|
async reloadWhatItIsBuiltOn(projectPath, scriptPath) {
|
|
56810
56891
|
const against = this.scriptsCompiledAgainst(projectPath, scriptPath);
|
|
56811
56892
|
const held = await this.scriptsHeldBehind(against);
|
|
56812
|
-
if (
|
|
56813
|
-
return {
|
|
56893
|
+
if ("unchecked" in held) {
|
|
56894
|
+
return {
|
|
56895
|
+
reloaded: [],
|
|
56896
|
+
said: `Whether the editor holds the scripts it is compiled against behind their files could not be checked: ${held.unchecked}.`,
|
|
56897
|
+
unchecked: true
|
|
56898
|
+
};
|
|
56814
56899
|
}
|
|
56815
56900
|
const reloadedFor = scriptPath.startsWith("res://") ? scriptPath : `res://${scriptPath.replace(/^\/+/, "")}`;
|
|
56816
56901
|
const reloaded = [];
|
|
@@ -57460,10 +57545,11 @@ ${error.text}`;
|
|
|
57460
57545
|
const checked = await this.classesTheEditorCannotSee(args);
|
|
57461
57546
|
const stillHeld = checked.stillHeld ?? [];
|
|
57462
57547
|
const projectPath = typeof args["projectPath"] === "string" ? args["projectPath"] : "";
|
|
57463
|
-
const listed = projectPath === "" ? null : cachedClasses(projectPath);
|
|
57548
|
+
const listed = projectPath === "" || checked.unchecked !== undefined ? null : cachedClasses(projectPath);
|
|
57464
57549
|
const held = listed === null ? null : await this.scriptsHeldBehind([...new Set(listed.values())]);
|
|
57465
|
-
const
|
|
57466
|
-
|
|
57550
|
+
const behindUnchecked = held !== null && "unchecked" in held ? held.unchecked : undefined;
|
|
57551
|
+
const behind = listed === null || held === null || "unchecked" in held ? [] : [...listed].filter(([, path]) => held.behind.includes(path)).map(([className, scriptPath]) => ({ className, scriptPath }));
|
|
57552
|
+
if (checked.unseen.length === 0 && stillHeld.length === 0 && checked.unchecked === undefined && behindUnchecked === undefined && behind.length === 0) {
|
|
57467
57553
|
return answered;
|
|
57468
57554
|
}
|
|
57469
57555
|
const payload = asParams(JSON.parse(first.text));
|
|
@@ -57486,6 +57572,7 @@ ${error.text}`;
|
|
|
57486
57572
|
stillHeldByEditor: stillHeld.length > 0 ? stillHeld : undefined,
|
|
57487
57573
|
heldBehindInEditor: behind.length > 0 ? behind : undefined,
|
|
57488
57574
|
classesUnchecked: checked.unchecked,
|
|
57575
|
+
heldBehindUnchecked: behindUnchecked,
|
|
57489
57576
|
note: notes.length > 0 ? notes.join(" ") : undefined
|
|
57490
57577
|
});
|
|
57491
57578
|
}
|
|
@@ -57495,7 +57582,7 @@ ${error.text}`;
|
|
|
57495
57582
|
}
|
|
57496
57583
|
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
57497
57584
|
const declared = new RegExp(`^\\s*(?:@\\w+(?:\\([^)]*\\))?\\s+)*class_name\\s+${escaped}\\b`, "m");
|
|
57498
|
-
if (declared.test(
|
|
57585
|
+
if (declared.test(readFileSync37(scriptPath, "utf8"))) {
|
|
57499
57586
|
return null;
|
|
57500
57587
|
}
|
|
57501
57588
|
const checked = await this.classesTheEditorCannotSee(args);
|
|
@@ -58006,7 +58093,7 @@ async function runGodotServer() {
|
|
|
58006
58093
|
const server = new GodotServer;
|
|
58007
58094
|
await server.run();
|
|
58008
58095
|
}
|
|
58009
|
-
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
58096
|
+
var UPDATE_NOTICE_EVERY = 500, FEEDBACK_NOTICE_EVERY = 250, FAILED_BUDGET = 1e6, ANSWER_BUDGET = 4000000, __dirname2, PARENT_ASKED_AFTER_MS = 5000, EDITOR_SERVERS_START_MS = 20000, HOLD_PING_MS = 2000, SLOWEST_FRAME_RATE = 20, ALONGSIDE_NOTE = "Another call on this game was running while this one was: calls sent together run together and are answered as each finishes, so this answer is not from after the other. Send a call meant to come after another once that one has answered.", OWN_DEBUGGER = " Its debugger is the keeper holding it rather than the editor, so the debug_* tools answer for it all the same: breakpoints stop it, and debug_control pause breaks into it wherever it is, which the editor offers no way to do.", PLAY_STARTS_WITHIN_MS = 30000, KEEPER_ANSWER_MS = 15000, KEEPER_DEBUG_MS, EXIT_REPORTED_WITHIN_MS = 2000, SUCCESSOR_SOUGHT_WITHIN_MS = 20000, CLOSE_ASK_MS = 3000, CONSOLE_WRAPPER, LONGEST_BOOT_NOTED_MS, PROFILE_SEND_MS = 5000, MOST_GROUPS = 20, RUNTIME_LISTENING_LINE = "[gdharness] runtime listening on ", VALUE_NAMES, BRIDGE_RETRY_MS = 2000, SUCCESSOR_CHECK_MS = 1e4, CONSOLE_WATCH_MS = 250, BOUNDARY_WAIT_MS = 2000, HANDOVER_MS, HANDOVER_POLL_MS = 250, CACHE_WRITE_MS = 2000, STREAMS_GRACE_MS = 2000, PLAYING_STATUS_MS = 1000, SCAN_SETTLED_MS = 500, SLOW_ANSWER_MS = 1000, REIMPORT_TIMEOUT_MS = 300000, OPS_ELSEWHERE, AUDIO_BUS_OPS, STALLED_AFTER_MS = 30000, TEST_TIMEOUT_MS = 600000, TEST_HEARTBEAT_MS = 20000, DEPENDED_FAILED = "Failed to compile depended scripts", LOOPING_AFTER = 100, WAIT_FOR_RUN_MS = 600000, RUN_POLL_MS = 250, PATH_SOLUTIONS, DESTINATION_ARGUMENTS, OUTPUT_PATH_SOLUTIONS, PROJECT_FILE_ARGUMENTS, DEBUG_STATE_CALLS, PROJECT_INFO_SECTIONS2, RUNNER_DIRECTORY = "addons/gdUnit4/", PROFILE_FUNCTIONS = 30, PROFILER_ON_MS = 3000, PROPERTY_PLACES = "It is a property, so each place says whether it writes it (access write), which runs its set block, or reads it (access read), which runs its get block: withinCalls on a read says nothing of the set block, nor on a write of the get block unless the write is a compound one such as +=. Inside the property's own blocks its name is the value stored, which the engine reads and writes without running them, so those lines are not listed.", CALLERS_FOUND_BY_NAME = "Found by name in the project's scripts, since the engine's profiler counts calls and time per function and records nothing about who made them: a method of the same name on another class is listed too, unless one class was asked about and it is called through another class by name or through a variable declared as one. Each place carries the profile's numbers for the function it is written in.", MOST_ENGINE_ENTRIES = 200, MOST_PRINTED_LINES = 50, MOST_UNDECLARED_ERRORS = 20, ERROR_ASSERT = "GdUnitGodotErrorAssertImpl.gd", RAISED_WARNING = " (Warning treated as error.)", PARSE_ERROR2 = "Parse Error: ", EXTERNAL_MEMBER = 'Could not resolve external class member "', STATIC_LIST_HINT;
|
|
58010
58097
|
var init_server = __esm(() => {
|
|
58011
58098
|
init_dist2();
|
|
58012
58099
|
init_stdio();
|
|
@@ -58179,7 +58266,7 @@ init_alive();
|
|
|
58179
58266
|
init_engine_launch();
|
|
58180
58267
|
init_lsp_client();
|
|
58181
58268
|
init_process_children();
|
|
58182
|
-
import { existsSync as existsSync17, readdirSync as readdirSync10, readFileSync as
|
|
58269
|
+
import { existsSync as existsSync17, readdirSync as readdirSync10, readFileSync as readFileSync16, unlinkSync as unlinkSync2 } from "node:fs";
|
|
58183
58270
|
import { connect as connect2 } from "node:net";
|
|
58184
58271
|
import { join as join20, resolve as resolve7 } from "node:path";
|
|
58185
58272
|
var EDITOR_RECORD_PROTOCOL = 1;
|
|
@@ -58198,7 +58285,7 @@ function editorRecordsIn(projectPath) {
|
|
|
58198
58285
|
for (const name of names) {
|
|
58199
58286
|
const file = join20(directory, name);
|
|
58200
58287
|
try {
|
|
58201
|
-
const said = JSON.parse(
|
|
58288
|
+
const said = JSON.parse(readFileSync16(file, "utf8"));
|
|
58202
58289
|
const { protocol, pid, lsp_port: lspPort, written_at_ms: writtenAtMs } = said;
|
|
58203
58290
|
if (protocol === EDITOR_RECORD_PROTOCOL && typeof pid === "number" && typeof lspPort === "number" && lspPort > 0 && typeof writtenAtMs === "number") {
|
|
58204
58291
|
records.push({ file, pid, lspPort, writtenAtMs });
|
|
@@ -58707,7 +58794,7 @@ init_engine_launch();
|
|
|
58707
58794
|
init_engine_slots();
|
|
58708
58795
|
init_setup();
|
|
58709
58796
|
init_suite_judge();
|
|
58710
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as
|
|
58797
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, readFileSync as readFileSync19, rmSync as rmSync11 } from "node:fs";
|
|
58711
58798
|
import { availableParallelism as availableParallelism3 } from "node:os";
|
|
58712
58799
|
import { join as join23, resolve as resolve9 } from "node:path";
|
|
58713
58800
|
import process13 from "node:process";
|
|
@@ -58895,17 +58982,17 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
58895
58982
|
const faults = left.flatMap((worker) => engineFaults(worker, options.godotVersion));
|
|
58896
58983
|
const arms = left.map((_, index) => {
|
|
58897
58984
|
const file = join23(shareDirectory, `worker-${String(index)}.arms`);
|
|
58898
|
-
return existsSync20(file) ? armsPlayed(
|
|
58985
|
+
return existsSync20(file) ? armsPlayed(readFileSync19(file, "utf8")) : [];
|
|
58899
58986
|
});
|
|
58900
58987
|
faults.push(...shareFaults(arms));
|
|
58901
58988
|
if (faults.length > 0) {
|
|
58902
58989
|
return failed(faults, left, runDirectory, "so nothing was gathered");
|
|
58903
58990
|
}
|
|
58904
58991
|
const gather = await engine("gather", `${GATHER}${String(workers)}`);
|
|
58905
|
-
console.log(
|
|
58992
|
+
console.log(readFileSync19(gather.log, "utf8").replace(CONTROL_SEQUENCE, "").trimEnd());
|
|
58906
58993
|
const gatherFaults = engineFaults(gather, options.godotVersion);
|
|
58907
58994
|
const gatheredFile = join23(shareDirectory, "gathered.arms");
|
|
58908
|
-
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(
|
|
58995
|
+
const gathered = new Set((existsSync20(gatheredFile) ? armsPlayed(readFileSync19(gatheredFile, "utf8")) ?? [] : []).map((arm) => arm.arm));
|
|
58909
58996
|
const ungathered = (arms[0] ?? []).filter((arm) => !gathered.has(arm.arm)).map((arm) => arm.arm);
|
|
58910
58997
|
if (ungathered.length > 0) {
|
|
58911
58998
|
gatherFaults.push(`the gathering run never asked for ${ungathered.join(", ")}, which the workers played: it went another way through the arms than they did`);
|
|
@@ -58959,7 +59046,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
58959
59046
|
if (!existsSync20(engine.log)) {
|
|
58960
59047
|
return faults;
|
|
58961
59048
|
}
|
|
58962
|
-
const printed = readRun(
|
|
59049
|
+
const printed = readRun(readFileSync19(engine.log, "utf8"));
|
|
58963
59050
|
const wrongEngine = godotVersion === null ? null : versionFault(printed.engineVersion, godotVersion);
|
|
58964
59051
|
if (wrongEngine !== null) {
|
|
58965
59052
|
faults.push(`${engine.name}: ${wrongEngine}`);
|
|
@@ -58972,7 +59059,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
58972
59059
|
}
|
|
58973
59060
|
function progressOf(logs) {
|
|
58974
59061
|
const each = logs.map((log, index) => {
|
|
58975
|
-
const text = existsSync20(log) ?
|
|
59062
|
+
const text = existsSync20(log) ? readFileSync19(log, "utf8") : "";
|
|
58976
59063
|
const last = [...text.matchAll(PROGRESS)].at(-1);
|
|
58977
59064
|
return last === undefined ? `worker ${String(index)} has played no arm yet` : `worker ${String(index)} at ${last[1] ?? ""} ${last[2] ?? ""} of ${last[3] ?? ""}`;
|
|
58978
59065
|
});
|
|
@@ -59004,7 +59091,7 @@ import {
|
|
|
59004
59091
|
existsSync as existsSync23,
|
|
59005
59092
|
mkdirSync as mkdirSync10,
|
|
59006
59093
|
readdirSync as readdirSync14,
|
|
59007
|
-
readFileSync as
|
|
59094
|
+
readFileSync as readFileSync23,
|
|
59008
59095
|
rmSync as rmSync12,
|
|
59009
59096
|
statSync as statSync14,
|
|
59010
59097
|
writeFileSync as writeFileSync12
|
|
@@ -59016,7 +59103,7 @@ import process14 from "node:process";
|
|
|
59016
59103
|
// src/suite-fingerprint.ts
|
|
59017
59104
|
init_class_cache();
|
|
59018
59105
|
import { createHash as createHash6 } from "node:crypto";
|
|
59019
|
-
import { existsSync as existsSync21, readdirSync as readdirSync13, readFileSync as
|
|
59106
|
+
import { existsSync as existsSync21, readdirSync as readdirSync13, readFileSync as readFileSync20, statSync as statSync13 } from "node:fs";
|
|
59020
59107
|
import { join as join24, posix as posix2 } from "node:path";
|
|
59021
59108
|
var RES_LITERAL = /res:\/\/[^"'\s)\]<>]*/g;
|
|
59022
59109
|
var RELATIVE_LOAD = /\b(?:pre)?load\(\s*["']((?!res:\/\/|uid:\/\/)[^"']+)["']/g;
|
|
@@ -59081,7 +59168,7 @@ ${this.read(path).digest}
|
|
|
59081
59168
|
walk(file, `${under}${entry.name}/`);
|
|
59082
59169
|
} else if (entry.isFile()) {
|
|
59083
59170
|
hash.update(`${under}${entry.name}
|
|
59084
|
-
`).update(
|
|
59171
|
+
`).update(readFileSync20(file));
|
|
59085
59172
|
}
|
|
59086
59173
|
}
|
|
59087
59174
|
};
|
|
@@ -59107,7 +59194,7 @@ ${this.read(path).digest}
|
|
|
59107
59194
|
if (BINARY_RESOURCE.test(path)) {
|
|
59108
59195
|
return { digest: "", reaches: [], unreadable: `${path} is a binary resource` };
|
|
59109
59196
|
}
|
|
59110
|
-
const bytes =
|
|
59197
|
+
const bytes = readFileSync20(file);
|
|
59111
59198
|
const digest = createHash6("sha256").update(bytes).digest("hex");
|
|
59112
59199
|
const text = bytes.toString("latin1");
|
|
59113
59200
|
const reaches = new Set;
|
|
@@ -59145,7 +59232,7 @@ ${this.read(path).digest}
|
|
|
59145
59232
|
}
|
|
59146
59233
|
function extensionsOf(projectPath) {
|
|
59147
59234
|
const list = join24(projectPath, ".godot", "extension_list.cfg");
|
|
59148
|
-
return existsSync21(list) ?
|
|
59235
|
+
return existsSync21(list) ? readFileSync20(list, "utf8").split(`
|
|
59149
59236
|
`).map((line) => line.trim()).filter((line) => line.startsWith("res://")) : [];
|
|
59150
59237
|
}
|
|
59151
59238
|
|
|
@@ -59154,7 +59241,7 @@ init_suite_judge();
|
|
|
59154
59241
|
init_suite_plan();
|
|
59155
59242
|
|
|
59156
59243
|
// src/version.ts
|
|
59157
|
-
import { readFileSync as
|
|
59244
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
59158
59245
|
import { dirname as dirname12, join as join26 } from "node:path";
|
|
59159
59246
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
59160
59247
|
function getLocalVersion() {
|
|
@@ -59165,7 +59252,7 @@ function getLocalVersion() {
|
|
|
59165
59252
|
];
|
|
59166
59253
|
for (const packagePath of packageCandidates) {
|
|
59167
59254
|
try {
|
|
59168
|
-
const value = JSON.parse(
|
|
59255
|
+
const value = JSON.parse(readFileSync22(packagePath, "utf-8"));
|
|
59169
59256
|
if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
|
|
59170
59257
|
return value.version;
|
|
59171
59258
|
}
|
|
@@ -59426,9 +59513,9 @@ async function runTestCommand(options, godotPath) {
|
|
|
59426
59513
|
}
|
|
59427
59514
|
const fingerprints = new SuiteFingerprints(scripts, [
|
|
59428
59515
|
getLocalVersion(),
|
|
59429
|
-
|
|
59516
|
+
readFileSync23(shippedListedRunner(), "utf8"),
|
|
59430
59517
|
...options.reachAlso.map((path) => `${path}
|
|
59431
|
-
${existsSync23(path) ?
|
|
59518
|
+
${existsSync23(path) ? readFileSync23(path, "latin1") : "missing"}`)
|
|
59432
59519
|
]);
|
|
59433
59520
|
const printsOf = new Map(suites.map((suite) => [suite.path, fingerprints.of(suite)]));
|
|
59434
59521
|
if (options.changedOnly) {
|
|
@@ -59544,7 +59631,7 @@ function roomSaid(engines, lanes, unheld, held, asked) {
|
|
|
59544
59631
|
}
|
|
59545
59632
|
function readRecord(file) {
|
|
59546
59633
|
try {
|
|
59547
|
-
const parsed = JSON.parse(
|
|
59634
|
+
const parsed = JSON.parse(readFileSync23(file, "utf8"));
|
|
59548
59635
|
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
59549
59636
|
} catch {
|
|
59550
59637
|
return {};
|
|
@@ -59603,7 +59690,7 @@ async function importProject(launch) {
|
|
|
59603
59690
|
if (ended.ended !== null || ended.code !== 0) {
|
|
59604
59691
|
return `${ended.ended ?? `the engine exited ${exitNamed(ended.code ?? 0)}`}; everything it printed is in ${launch.logs.named(log)}`;
|
|
59605
59692
|
}
|
|
59606
|
-
const printed = readRun(
|
|
59693
|
+
const printed = readRun(readFileSync23(log, "utf8"));
|
|
59607
59694
|
const wrongEngine = launch.godotVersion === null ? null : versionFault(printed.engineVersion, launch.godotVersion);
|
|
59608
59695
|
if (wrongEngine !== null) {
|
|
59609
59696
|
return `${wrongEngine}; everything it printed is in ${launch.logs.named(log)}`;
|
|
@@ -59719,7 +59806,7 @@ async function runEngine2(launch, plan, index, times, again = "", slot = null) {
|
|
|
59719
59806
|
launch.slots.release(lock);
|
|
59720
59807
|
}
|
|
59721
59808
|
}
|
|
59722
|
-
const printed = readRun(
|
|
59809
|
+
const printed = readRun(readFileSync23(log, "utf8"));
|
|
59723
59810
|
const assignment = {
|
|
59724
59811
|
suites: plan.suites,
|
|
59725
59812
|
expected: readExpected(expectedFile),
|
|
@@ -59754,7 +59841,7 @@ function report(ran, across, uncollected, startedAt, logs, printOutput, targets)
|
|
|
59754
59841
|
for (const engine of ran) {
|
|
59755
59842
|
console.log("");
|
|
59756
59843
|
console.log(`--- what engine ${String(engine.index)} printed, running ${named(engine.plan.suites.map((suite) => suite.path))}:`);
|
|
59757
|
-
console.log(existsSync23(engine.log) ?
|
|
59844
|
+
console.log(existsSync23(engine.log) ? readFileSync23(engine.log, "utf8").replace(CONTROL_SEQUENCE, "").trimEnd() : "(no log was written)");
|
|
59758
59845
|
}
|
|
59759
59846
|
}
|
|
59760
59847
|
const failed = ran.filter((engine) => !engine.verdict.passed);
|
|
@@ -59773,7 +59860,7 @@ function report(ran, across, uncollected, startedAt, logs, printOutput, targets)
|
|
|
59773
59860
|
writeFileSync12(engine.log, `${verdict.join(`
|
|
59774
59861
|
`)}
|
|
59775
59862
|
---
|
|
59776
|
-
${
|
|
59863
|
+
${readFileSync23(engine.log, "utf8")}`);
|
|
59777
59864
|
}
|
|
59778
59865
|
if (engine.verdict.shown.length > 0) {
|
|
59779
59866
|
console.log("");
|