gdharness 1.3.58 → 1.3.60
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 +351 -206
- package/build/godot/addons/gdharness_editor/property_values.gd +8 -1
- package/build/godot/addons/gdharness_editor/setting_reads.gd +58 -0
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +5 -2
- package/build/godot/operations/project_config.gd +21 -1
- package/build/godot/operations/property_values.gd +8 -1
- package/build/godot/operations/setting_reads.gd +58 -0
- package/build/godot/tests/listed.gd +19 -1
- package/build/keeper.js +5 -4
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -1717,6 +1717,7 @@ var init_whole_file = __esm(() => {
|
|
|
1717
1717
|
// src/engine-slots.ts
|
|
1718
1718
|
import {
|
|
1719
1719
|
closeSync as closeSync2,
|
|
1720
|
+
existsSync as existsSync2,
|
|
1720
1721
|
mkdirSync as mkdirSync2,
|
|
1721
1722
|
openSync as openSync2,
|
|
1722
1723
|
readdirSync,
|
|
@@ -1766,6 +1767,83 @@ function keptSlotsOf(count) {
|
|
|
1766
1767
|
function reservedSlotOf(count) {
|
|
1767
1768
|
return count - Math.max(1, count - keptSlotsOf(count)) >= 2 ? count - 1 : null;
|
|
1768
1769
|
}
|
|
1770
|
+
function slotWaiters(directory) {
|
|
1771
|
+
const marks = join5(directory, WAITING_FOLDER);
|
|
1772
|
+
let names;
|
|
1773
|
+
try {
|
|
1774
|
+
names = readdirSync(marks).filter((name) => name.endsWith(".json"));
|
|
1775
|
+
} catch {
|
|
1776
|
+
return [];
|
|
1777
|
+
}
|
|
1778
|
+
const found = [];
|
|
1779
|
+
for (const mark of names.sort()) {
|
|
1780
|
+
let content;
|
|
1781
|
+
let madeAt;
|
|
1782
|
+
try {
|
|
1783
|
+
content = readWhole(join5(marks, mark));
|
|
1784
|
+
madeAt = statSync3(join5(marks, mark)).mtimeMs;
|
|
1785
|
+
} catch {
|
|
1786
|
+
continue;
|
|
1787
|
+
}
|
|
1788
|
+
const holder = content === null ? null : holderOf(content);
|
|
1789
|
+
if (content === null || holder === null || !alive(holder.pid)) {
|
|
1790
|
+
continue;
|
|
1791
|
+
}
|
|
1792
|
+
const { taker, since } = JSON.parse(content);
|
|
1793
|
+
if (taker === MEMORY_TAKER) {
|
|
1794
|
+
continue;
|
|
1795
|
+
}
|
|
1796
|
+
found.push({
|
|
1797
|
+
mark,
|
|
1798
|
+
taker: taker === "gate" || taker === "timing" || taker === "tier" ? taker : "other",
|
|
1799
|
+
since: Math.floor(typeof since === "number" && Number.isFinite(since) ? since * 1000 : madeAt),
|
|
1800
|
+
game: holder.game === true
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
return found;
|
|
1804
|
+
}
|
|
1805
|
+
function slotsClaimed(ahead, open) {
|
|
1806
|
+
const left = new Set(open);
|
|
1807
|
+
const taken = new Map;
|
|
1808
|
+
for (const [at, numbers] of ahead.entries()) {
|
|
1809
|
+
const first = numbers.find((slot) => left.has(slot));
|
|
1810
|
+
if (first !== undefined) {
|
|
1811
|
+
left.delete(first);
|
|
1812
|
+
taken.set(first, at);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return taken;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
class SlotLine {
|
|
1819
|
+
since;
|
|
1820
|
+
mark;
|
|
1821
|
+
left = new Map;
|
|
1822
|
+
taker;
|
|
1823
|
+
game;
|
|
1824
|
+
clock;
|
|
1825
|
+
constructor(taker, game = false, clock = Date.now) {
|
|
1826
|
+
this.taker = taker;
|
|
1827
|
+
this.game = game;
|
|
1828
|
+
this.clock = clock;
|
|
1829
|
+
this.since = clock();
|
|
1830
|
+
}
|
|
1831
|
+
marked(holder) {
|
|
1832
|
+
return { ...holder, ...this.game ? { game: true } : {}, taker: this.taker, since: this.since / 1000 };
|
|
1833
|
+
}
|
|
1834
|
+
ahead(waiters) {
|
|
1835
|
+
const own = this.mark ?? "";
|
|
1836
|
+
return waiters.filter((one) => one.mark !== this.mark && (one.since < this.since || one.since === this.since && one.mark < own)).sort((a, b) => a.since - b.since || (a.mark < b.mark ? -1 : 1));
|
|
1837
|
+
}
|
|
1838
|
+
admitted(numbers, theirs) {
|
|
1839
|
+
const now = this.clock();
|
|
1840
|
+
this.left = new Map([...theirs].map((slot) => [slot, this.left.get(slot) ?? now]));
|
|
1841
|
+
return numbers.filter((slot) => !theirs.has(slot) || now - (this.left.get(slot) ?? now) >= SLOT_YIELD_MS);
|
|
1842
|
+
}
|
|
1843
|
+
leaves() {
|
|
1844
|
+
return [...this.left.keys()].sort((a, b) => a - b);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1769
1847
|
function gamesKeptOf(kept) {
|
|
1770
1848
|
return Math.max(0, Math.min(Math.floor(kept / 2), kept - GATE_KEPT - 1));
|
|
1771
1849
|
}
|
|
@@ -1905,6 +1983,7 @@ class EngineSlots {
|
|
|
1905
1983
|
starts = new Map;
|
|
1906
1984
|
held = new Set;
|
|
1907
1985
|
marks = new Set;
|
|
1986
|
+
passedOver = new Map;
|
|
1908
1987
|
inherited = null;
|
|
1909
1988
|
drawn = { numbers: [] };
|
|
1910
1989
|
saidAt = Number.NEGATIVE_INFINITY;
|
|
@@ -1923,19 +2002,20 @@ class EngineSlots {
|
|
|
1923
2002
|
}
|
|
1924
2003
|
async take(signal, waiting, blocked, game = false) {
|
|
1925
2004
|
mkdirSync2(this.directory, { recursive: true });
|
|
1926
|
-
const
|
|
2005
|
+
const line = new SlotLine(this.taker(), game);
|
|
2006
|
+
const began = line.since;
|
|
1927
2007
|
let said = Number.NEGATIVE_INFINITY;
|
|
1928
2008
|
let mark;
|
|
1929
2009
|
let changes;
|
|
1930
2010
|
try {
|
|
1931
2011
|
for (;; ) {
|
|
1932
2012
|
signal?.throwIfAborted();
|
|
1933
|
-
const lock = await this.takeFree(game, Date.now() - began);
|
|
2013
|
+
const lock = await this.takeFree(game, Date.now() - began, line);
|
|
1934
2014
|
if (lock !== null) {
|
|
1935
2015
|
return lock;
|
|
1936
2016
|
}
|
|
1937
2017
|
if (mark === undefined) {
|
|
1938
|
-
mark = this.waitMarked();
|
|
2018
|
+
mark = this.waitMarked(line);
|
|
1939
2019
|
blocked?.();
|
|
1940
2020
|
}
|
|
1941
2021
|
const now = Date.now();
|
|
@@ -1962,7 +2042,7 @@ class EngineSlots {
|
|
|
1962
2042
|
}
|
|
1963
2043
|
}
|
|
1964
2044
|
}
|
|
1965
|
-
async takeFree(game = false, waitedMs = 0) {
|
|
2045
|
+
async takeFree(game = false, waitedMs = 0, line) {
|
|
1966
2046
|
mkdirSync2(this.directory, { recursive: true });
|
|
1967
2047
|
await this.sweep();
|
|
1968
2048
|
const inherited = this.inherited === null ? await this.inheritedLock() : null;
|
|
@@ -1972,7 +2052,9 @@ class EngineSlots {
|
|
|
1972
2052
|
}
|
|
1973
2053
|
const taker = this.taker();
|
|
1974
2054
|
const aged = taker === "other" && !game && waitedMs >= ONE_OFF_AGED_MS;
|
|
1975
|
-
|
|
2055
|
+
let queue;
|
|
2056
|
+
const queued = async () => queue ??= await this.gateQueue();
|
|
2057
|
+
this.drawn = slotsDrawnOn(this.count, taker, taker === "gate" || taker === "timing" || aged ? "none" : await queued());
|
|
1976
2058
|
if (game && this.drawn.limit === "kept") {
|
|
1977
2059
|
const reserve = reservedSlotOf(this.count);
|
|
1978
2060
|
this.drawn = { ...this.drawn, numbers: this.drawn.numbers.filter((slot) => slot !== reserve) };
|
|
@@ -1983,8 +2065,31 @@ class EngineSlots {
|
|
|
1983
2065
|
return null;
|
|
1984
2066
|
}
|
|
1985
2067
|
}
|
|
2068
|
+
let tried = this.drawn.numbers;
|
|
2069
|
+
if (taker !== "timing") {
|
|
2070
|
+
const placed = line ?? new SlotLine(taker, game);
|
|
2071
|
+
const now = Date.now();
|
|
2072
|
+
const waiting = slotWaiters(this.directory);
|
|
2073
|
+
for (const mark of this.passedOver.keys()) {
|
|
2074
|
+
if (!waiting.some((one) => one.mark === mark)) {
|
|
2075
|
+
this.passedOver.delete(mark);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
const ahead = placed.ahead(waiting).filter((one) => now - (this.passedOver.get(one.mark) ?? now) < SLOT_YIELD_MS);
|
|
2079
|
+
const claims = await this.claimedAhead(ahead, queued);
|
|
2080
|
+
for (const mark of claims.values()) {
|
|
2081
|
+
if (!this.passedOver.has(mark)) {
|
|
2082
|
+
this.passedOver.set(mark, now);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
tried = placed.admitted(tried, new Set(claims.keys()));
|
|
2086
|
+
const left = placed.leaves().filter((slot) => this.drawn.numbers.includes(slot) && !tried.includes(slot));
|
|
2087
|
+
if (left.length > 0) {
|
|
2088
|
+
this.drawn = { ...this.drawn, left };
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
1986
2091
|
const holder = game ? { ...this.holder, game: true } : this.holder;
|
|
1987
|
-
for (const slot of
|
|
2092
|
+
for (const slot of tried) {
|
|
1988
2093
|
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
1989
2094
|
if (this.made(lock, holder) || await this.takenOver(lock, holder)) {
|
|
1990
2095
|
this.held.add(lock);
|
|
@@ -1993,6 +2098,30 @@ class EngineSlots {
|
|
|
1993
2098
|
}
|
|
1994
2099
|
return null;
|
|
1995
2100
|
}
|
|
2101
|
+
async claimedAhead(ahead, queued) {
|
|
2102
|
+
if (ahead.length === 0) {
|
|
2103
|
+
return new Map;
|
|
2104
|
+
}
|
|
2105
|
+
const open = [];
|
|
2106
|
+
for (let slot = 0;slot < this.count; slot += 1) {
|
|
2107
|
+
const lock = join5(this.directory, `${String(slot)}.lock`);
|
|
2108
|
+
if (!existsSync2(lock) || await this.free(lock)) {
|
|
2109
|
+
open.push(slot);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
if (open.length === 0) {
|
|
2113
|
+
return new Map;
|
|
2114
|
+
}
|
|
2115
|
+
const now = Date.now();
|
|
2116
|
+
const reserve = reservedSlotOf(this.count);
|
|
2117
|
+
const drawn = [];
|
|
2118
|
+
for (const one of ahead) {
|
|
2119
|
+
const aged = one.taker === "other" && !one.game && now - one.since >= ONE_OFF_AGED_MS;
|
|
2120
|
+
const theirs = slotsDrawnOn(this.count, one.taker, one.taker === "gate" || one.taker === "timing" || aged ? "none" : await queued());
|
|
2121
|
+
drawn.push(one.game && theirs.limit === "kept" ? theirs.numbers.filter((slot) => slot !== reserve) : theirs.numbers);
|
|
2122
|
+
}
|
|
2123
|
+
return new Map([...slotsClaimed(drawn, open)].map(([slot, at]) => [slot, ahead[at]?.mark ?? ""]));
|
|
2124
|
+
}
|
|
1996
2125
|
async inheritedLock() {
|
|
1997
2126
|
const lock = nonEmpty(process4.env[HELD_VARIABLE]);
|
|
1998
2127
|
const content = lock === undefined ? null : readWhole(lock);
|
|
@@ -2006,14 +2135,14 @@ class EngineSlots {
|
|
|
2006
2135
|
return tree !== undefined && inheritsSlot(tree, process4.pid, holder, basename3(process4.execPath), engineStarted) ? lock : null;
|
|
2007
2136
|
}
|
|
2008
2137
|
markWaiting() {
|
|
2009
|
-
const mark = this.waitMarked();
|
|
2138
|
+
const mark = this.waitMarked({ ...this.holder, taker: MEMORY_TAKER });
|
|
2010
2139
|
return () => {
|
|
2011
2140
|
if (mark !== undefined && this.marks.delete(mark)) {
|
|
2012
2141
|
removeWhole(mark);
|
|
2013
2142
|
}
|
|
2014
2143
|
};
|
|
2015
2144
|
}
|
|
2016
|
-
waitMarked() {
|
|
2145
|
+
waitMarked(line) {
|
|
2017
2146
|
const marks = join5(this.directory, WAITING_FOLDER);
|
|
2018
2147
|
waitsMarked += 1;
|
|
2019
2148
|
const mark = join5(marks, `${String(this.holder.pid)}-${String(waitsMarked)}.json`);
|
|
@@ -2022,9 +2151,12 @@ class EngineSlots {
|
|
|
2022
2151
|
} catch {
|
|
2023
2152
|
return;
|
|
2024
2153
|
}
|
|
2025
|
-
if (!this.made(mark)) {
|
|
2154
|
+
if (!this.made(mark, line instanceof SlotLine ? line.marked(this.holder) : line)) {
|
|
2026
2155
|
return;
|
|
2027
2156
|
}
|
|
2157
|
+
if (line instanceof SlotLine) {
|
|
2158
|
+
line.mark = basename3(mark);
|
|
2159
|
+
}
|
|
2028
2160
|
this.marks.add(mark);
|
|
2029
2161
|
return mark;
|
|
2030
2162
|
}
|
|
@@ -2283,13 +2415,16 @@ function slotWaitSaid(waitedMs, count, directory, holders = [], drawn = { number
|
|
|
2283
2415
|
const waiting = `${so}: ${slots}`;
|
|
2284
2416
|
const back = `the engine starts when ${taking === 1 ? "it" : "one"} is given back`;
|
|
2285
2417
|
const starts = drawn.limit === "kept" || drawn.limit === "tier" || drawn.limit === "games" ? `${back} or no gate is queued` : back;
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2418
|
+
const said = named.length === 0 ? `${waiting}, by a gate or another tool, and ${starts}.` : taking === 1 ? `${waiting}, by ${named.join(", ")}, and ${starts}.` : `${waiting}: ${listed(named)}. ${starts.charAt(0).toUpperCase()}${starts.slice(1)}.`;
|
|
2419
|
+
return `${said}${leftSaid(drawn)}`;
|
|
2420
|
+
}
|
|
2421
|
+
function leftSaid(drawn, past = false) {
|
|
2422
|
+
const left = drawn.left ?? [];
|
|
2423
|
+
if (left.length === 0) {
|
|
2424
|
+
return "";
|
|
2291
2425
|
}
|
|
2292
|
-
|
|
2426
|
+
const slots = left.length === 1 ? `slot ${String(left[0])}` : `slots ${listed(left.map(String))}`;
|
|
2427
|
+
return past ? ` It left free ${slots} to takers that had begun waiting before it, which go first.` : ` It leaves free ${slots} to takers that began waiting before it, which go first.`;
|
|
2293
2428
|
}
|
|
2294
2429
|
function slotsSaid(taking, count, directory, limit) {
|
|
2295
2430
|
const where = `on this machine (${directory})`;
|
|
@@ -2312,10 +2447,8 @@ function slotWaitedSaid(waitedMs, count, directory, holders, drawn = { numbers:
|
|
|
2312
2447
|
const taking = drawn.limit === undefined ? count : drawn.numbers.length;
|
|
2313
2448
|
const slots = `${slotsSaid(taking, count, directory, drawn.limit)} ${taking === 1 ? "was" : "were"} in use`;
|
|
2314
2449
|
const named = holdersNamed(taking, holders);
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
}
|
|
2318
|
-
return taking === 1 ? `${waited} When it first waited, ${slots}, by ${named.join(", ")}.` : `${waited} When it first waited, ${slots}: ${listed(named)}.`;
|
|
2450
|
+
const said = named.length === 0 ? `${waited} When it first waited, ${slots}, by a gate or another tool.` : taking === 1 ? `${waited} When it first waited, ${slots}, by ${named.join(", ")}.` : `${waited} When it first waited, ${slots}: ${listed(named)}.`;
|
|
2451
|
+
return `${said}${leftSaid(drawn, true)}`;
|
|
2319
2452
|
}
|
|
2320
2453
|
function holdersNamed(count, holders) {
|
|
2321
2454
|
const held = new Map;
|
|
@@ -2370,7 +2503,7 @@ async function inASlot(body) {
|
|
|
2370
2503
|
held.release();
|
|
2371
2504
|
}
|
|
2372
2505
|
}
|
|
2373
|
-
var HELD_VARIABLE = "GODOT_ENGINE_HELD", SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 2, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", QUEUED_FOLDER = "queued", SHARE_VARIABLE = "GODOT_ENGINE_SHARE", SHARE_COUNT_VARIABLE = "GODOT_ENGINE_SHARE_COUNT", GATE_KEPT = 1, ONE_OFF_AGED_MS = 120000, TIMED_VARIABLE = "GODOT_ENGINE_TIMED", TIER_VARIABLE = "GODOT_ENGINE_TIER", SEATED_SUFFIX = ".seated", waitsMarked = 0, ENGINE_PID_LOOK_MS = 100, ours, saidTo, takenBy;
|
|
2506
|
+
var HELD_VARIABLE = "GODOT_ENGINE_HELD", SLOTS_VARIABLE = "GODOT_ENGINE_SLOTS", SLOT_COUNT_VARIABLE = "GODOT_ENGINE_SLOT_COUNT", PROCESSORS_A_SLOT = 2, START_TOLERANCE_MS = 2000, UNWRITTEN_MS = 1e4, SLOT_LOOK_MS = 1000, SLOT_SETTLE_MS = 50, WAIT_SAID_MS = 20000, COMMAND_WAIT_SAID_MS = 2000, START_READ_MS = 1e4, WAITING_FOLDER = "waiting", QUEUED_FOLDER = "queued", SHARE_VARIABLE = "GODOT_ENGINE_SHARE", SHARE_COUNT_VARIABLE = "GODOT_ENGINE_SHARE_COUNT", GATE_KEPT = 1, ONE_OFF_AGED_MS = 120000, SLOT_YIELD_MS = 5000, MEMORY_TAKER = "memory", TIMED_VARIABLE = "GODOT_ENGINE_TIMED", TIER_VARIABLE = "GODOT_ENGINE_TIER", SEATED_SUFFIX = ".seated", waitsMarked = 0, ENGINE_PID_LOOK_MS = 100, ours, saidTo, takenBy;
|
|
2374
2507
|
var init_engine_slots = __esm(() => {
|
|
2375
2508
|
init_alive();
|
|
2376
2509
|
init_cache_home();
|
|
@@ -9645,7 +9778,7 @@ var init_config_formats = __esm(() => {
|
|
|
9645
9778
|
});
|
|
9646
9779
|
|
|
9647
9780
|
// src/runner.ts
|
|
9648
|
-
import { existsSync as
|
|
9781
|
+
import { existsSync as existsSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
9649
9782
|
import { delimiter, dirname as dirname3, extname, join as join6, resolve as resolve3 } from "node:path";
|
|
9650
9783
|
import process5 from "node:process";
|
|
9651
9784
|
function currentRunner() {
|
|
@@ -9689,12 +9822,12 @@ function realPath(path) {
|
|
|
9689
9822
|
}
|
|
9690
9823
|
function alongside(execPath, name) {
|
|
9691
9824
|
const runner = join6(dirname3(execPath), process5.platform === "win32" ? `${name}.cmd` : name);
|
|
9692
|
-
return
|
|
9825
|
+
return existsSync3(runner) ? runner : undefined;
|
|
9693
9826
|
}
|
|
9694
9827
|
var init_runner = () => {};
|
|
9695
9828
|
|
|
9696
9829
|
// src/harnesses.ts
|
|
9697
|
-
import { existsSync as
|
|
9830
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync8, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9698
9831
|
import { homedir as homedir3 } from "node:os";
|
|
9699
9832
|
import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute2, join as join7, relative as relative2, resolve as resolve4 } from "node:path";
|
|
9700
9833
|
import process6 from "node:process";
|
|
@@ -9785,15 +9918,15 @@ function harnessById(id) {
|
|
|
9785
9918
|
}
|
|
9786
9919
|
function present(harness, projectPath) {
|
|
9787
9920
|
const path = configPath(harness, projectPath);
|
|
9788
|
-
if (
|
|
9921
|
+
if (existsSync4(path)) {
|
|
9789
9922
|
return true;
|
|
9790
9923
|
}
|
|
9791
9924
|
const root = harness.scope === "project" ? projectPath : homedir3();
|
|
9792
9925
|
const own = dirname4(path);
|
|
9793
|
-
if (own !== root &&
|
|
9926
|
+
if (own !== root && existsSync4(own)) {
|
|
9794
9927
|
return true;
|
|
9795
9928
|
}
|
|
9796
|
-
return harness.marker !== undefined &&
|
|
9929
|
+
return harness.marker !== undefined && existsSync4(join7(root, harness.marker));
|
|
9797
9930
|
}
|
|
9798
9931
|
function candidates(projectPath) {
|
|
9799
9932
|
const found = [];
|
|
@@ -9806,7 +9939,7 @@ function candidates(projectPath) {
|
|
|
9806
9939
|
}
|
|
9807
9940
|
if (present(harness, projectPath)) {
|
|
9808
9941
|
found.push({ harness, reason: "configured" });
|
|
9809
|
-
} else if (harness.home !== undefined &&
|
|
9942
|
+
} else if (harness.home !== undefined && existsSync4(join7(homedir3(), harness.home))) {
|
|
9810
9943
|
found.push({ harness, reason: "installed" });
|
|
9811
9944
|
}
|
|
9812
9945
|
}
|
|
@@ -9828,7 +9961,7 @@ function groupByFile(harnesses, projectPath) {
|
|
|
9828
9961
|
}
|
|
9829
9962
|
function registered(harness, projectPath) {
|
|
9830
9963
|
const path = configPath(harness, projectPath);
|
|
9831
|
-
if (harness.snippet !== undefined || !
|
|
9964
|
+
if (harness.snippet !== undefined || !existsSync4(path)) {
|
|
9832
9965
|
return false;
|
|
9833
9966
|
}
|
|
9834
9967
|
const text = readFileSync8(path, "utf8");
|
|
@@ -9857,7 +9990,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9857
9990
|
}
|
|
9858
9991
|
const named = reach(entryEnvironment(harness, projectPath), "GODOT_PATH");
|
|
9859
9992
|
const path = typeof named !== "string" || named === "" ? null : isAbsolute2(named) ? named : resolve4(projectPath, named);
|
|
9860
|
-
if (path !== null &&
|
|
9993
|
+
if (path !== null && existsSync4(path)) {
|
|
9861
9994
|
return path;
|
|
9862
9995
|
}
|
|
9863
9996
|
}
|
|
@@ -9865,7 +9998,7 @@ function recordedEnginePath(projectPath) {
|
|
|
9865
9998
|
}
|
|
9866
9999
|
function mainCheckoutOf(projectPath) {
|
|
9867
10000
|
let top = resolve4(projectPath);
|
|
9868
|
-
while (!
|
|
10001
|
+
while (!existsSync4(join7(top, ".git"))) {
|
|
9869
10002
|
const up = dirname4(top);
|
|
9870
10003
|
if (up === top) {
|
|
9871
10004
|
return null;
|
|
@@ -9882,7 +10015,7 @@ function mainCheckoutOf(projectPath) {
|
|
|
9882
10015
|
}
|
|
9883
10016
|
const entry = resolve4(top, pointer);
|
|
9884
10017
|
const commonFile = join7(entry, "commondir");
|
|
9885
|
-
if (!
|
|
10018
|
+
if (!existsSync4(commonFile)) {
|
|
9886
10019
|
return null;
|
|
9887
10020
|
}
|
|
9888
10021
|
const common = resolve4(entry, readFileSync8(commonFile, "utf8").trim());
|
|
@@ -9890,11 +10023,11 @@ function mainCheckoutOf(projectPath) {
|
|
|
9890
10023
|
return null;
|
|
9891
10024
|
}
|
|
9892
10025
|
const main = join7(dirname4(common), relative2(top, resolve4(projectPath)));
|
|
9893
|
-
return isSameDirectory(main, projectPath) || !
|
|
10026
|
+
return isSameDirectory(main, projectPath) || !existsSync4(join7(main, "project.godot")) ? null : main;
|
|
9894
10027
|
}
|
|
9895
10028
|
function worktreeCheckoutsOf(projectPath) {
|
|
9896
10029
|
let top = resolve4(projectPath);
|
|
9897
|
-
while (!
|
|
10030
|
+
while (!existsSync4(join7(top, ".git"))) {
|
|
9898
10031
|
const up = dirname4(top);
|
|
9899
10032
|
if (up === top) {
|
|
9900
10033
|
return [];
|
|
@@ -9902,18 +10035,18 @@ function worktreeCheckoutsOf(projectPath) {
|
|
|
9902
10035
|
top = up;
|
|
9903
10036
|
}
|
|
9904
10037
|
const listed = join7(top, ".git", "worktrees");
|
|
9905
|
-
if (!statSync4(join7(top, ".git")).isDirectory() || !
|
|
10038
|
+
if (!statSync4(join7(top, ".git")).isDirectory() || !existsSync4(listed)) {
|
|
9906
10039
|
return [];
|
|
9907
10040
|
}
|
|
9908
10041
|
const below = relative2(top, resolve4(projectPath));
|
|
9909
10042
|
return readdirSync2(listed).flatMap((name) => {
|
|
9910
10043
|
const pointer = join7(listed, name, "gitdir");
|
|
9911
|
-
if (!
|
|
10044
|
+
if (!existsSync4(pointer)) {
|
|
9912
10045
|
return [];
|
|
9913
10046
|
}
|
|
9914
10047
|
const checkout = dirname4(resolve4(listed, name, readFileSync8(pointer, "utf8").trim()));
|
|
9915
10048
|
const project = join7(checkout, below);
|
|
9916
|
-
return
|
|
10049
|
+
return existsSync4(join7(project, "project.godot")) ? [project] : [];
|
|
9917
10050
|
});
|
|
9918
10051
|
}
|
|
9919
10052
|
function entryEnvironment(harness, projectPath) {
|
|
@@ -9921,7 +10054,7 @@ function entryEnvironment(harness, projectPath) {
|
|
|
9921
10054
|
return;
|
|
9922
10055
|
}
|
|
9923
10056
|
const path = configPath(harness, projectPath);
|
|
9924
|
-
if (!
|
|
10057
|
+
if (!existsSync4(path)) {
|
|
9925
10058
|
return;
|
|
9926
10059
|
}
|
|
9927
10060
|
let parsed;
|
|
@@ -9942,7 +10075,7 @@ function reach(held, key) {
|
|
|
9942
10075
|
}
|
|
9943
10076
|
function disconnect(harness, projectPath) {
|
|
9944
10077
|
const path = configPath(harness, projectPath);
|
|
9945
|
-
if (!
|
|
10078
|
+
if (!existsSync4(path)) {
|
|
9946
10079
|
return { harness, path, action: "absent" };
|
|
9947
10080
|
}
|
|
9948
10081
|
if (harness.snippet !== undefined) {
|
|
@@ -10029,7 +10162,7 @@ function connect(harness, projectPath, launch) {
|
|
|
10029
10162
|
if (harness.snippet !== undefined) {
|
|
10030
10163
|
return { harness, path, action: "snippet", snippet: harness.snippet(launch) };
|
|
10031
10164
|
}
|
|
10032
|
-
const held =
|
|
10165
|
+
const held = existsSync4(path) ? readFileSync8(path, "utf8") : "";
|
|
10033
10166
|
if (harness.toml !== undefined) {
|
|
10034
10167
|
const already = held.includes(harness.toml.identity ?? harness.toml.header);
|
|
10035
10168
|
return put(harness, path, writeToml(held, harness.toml, launch), already);
|
|
@@ -11195,7 +11328,7 @@ var init_gdscript_source = __esm(() => {
|
|
|
11195
11328
|
});
|
|
11196
11329
|
|
|
11197
11330
|
// src/class-cache.ts
|
|
11198
|
-
import { existsSync as
|
|
11331
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
|
|
11199
11332
|
import { join as join8, posix } from "node:path";
|
|
11200
11333
|
function isToolScript(source) {
|
|
11201
11334
|
return TOOL.test(codeOf(source));
|
|
@@ -11259,7 +11392,7 @@ function declaredClassOf(source) {
|
|
|
11259
11392
|
}
|
|
11260
11393
|
function eachScript(projectPath, each) {
|
|
11261
11394
|
const visit = (directory, prefix) => {
|
|
11262
|
-
if (
|
|
11395
|
+
if (existsSync5(join8(directory, ".gdignore"))) {
|
|
11263
11396
|
return;
|
|
11264
11397
|
}
|
|
11265
11398
|
for (const entry of readdirSync3(directory, { withFileTypes: true })) {
|
|
@@ -11655,7 +11788,7 @@ function uncachedForTheEngineNote(projectPath, types) {
|
|
|
11655
11788
|
}
|
|
11656
11789
|
const one = types.length === 1;
|
|
11657
11790
|
const named = types.map((type) => `${type.type} (${type.declaredIn})`).join(", ");
|
|
11658
|
-
const cacheExists =
|
|
11791
|
+
const cacheExists = existsSync5(join8(projectPath, ".godot", "global_script_class_cache.cfg"));
|
|
11659
11792
|
const state = cacheExists ? `missing from .godot/global_script_class_cache.cfg, which is where the engine that compiled these scripts resolves a class name from, so the error is the cache being behind the files rather than the script.` : `the engine that compiled these scripts resolves a class name from .godot/global_script_class_cache.cfg, which has not been written yet, as in a project no editor has opened, so the error is the missing cache rather than the script.`;
|
|
11660
11793
|
return `${named} ${one ? "is" : "are"} declared in this project${cacheExists ? " and" : ", but"} ${state} ` + "project_import refresh_classes writes the cache from the declarations on disk; editor_run start " + "writes it before a game, and an editor opening the project writes it when it scans.";
|
|
11661
11794
|
}
|
|
@@ -11681,7 +11814,7 @@ function declaredSince(projectPath, paths, names, since) {
|
|
|
11681
11814
|
});
|
|
11682
11815
|
}
|
|
11683
11816
|
function cachedAtMissingPaths(cached, projectPath) {
|
|
11684
|
-
return [...cached].filter(([, path]) => path.startsWith("res://") && !
|
|
11817
|
+
return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync5(join8(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
|
|
11685
11818
|
}
|
|
11686
11819
|
function staleAgainst(cached, projectPath) {
|
|
11687
11820
|
return [...declaredClasses(projectPath)].filter(([name, path]) => cached.get(name) !== path).map(([name]) => name);
|
|
@@ -13015,7 +13148,7 @@ var init_suite_judge = __esm(() => {
|
|
|
13015
13148
|
// src/engine-launch.ts
|
|
13016
13149
|
import {
|
|
13017
13150
|
closeSync as closeSync4,
|
|
13018
|
-
existsSync as
|
|
13151
|
+
existsSync as existsSync6,
|
|
13019
13152
|
fstatSync as fstatSync2,
|
|
13020
13153
|
openSync as openSync4,
|
|
13021
13154
|
readdirSync as readdirSync4,
|
|
@@ -13055,7 +13188,7 @@ function godotNamed(value, cwd) {
|
|
|
13055
13188
|
return null;
|
|
13056
13189
|
}
|
|
13057
13190
|
const path = resolve5(cwd, value);
|
|
13058
|
-
if (!
|
|
13191
|
+
if (!existsSync6(path) || statSync6(path).isDirectory()) {
|
|
13059
13192
|
throw new EngineUsageError(`--godot names ${path}, which is not an engine executable.`);
|
|
13060
13193
|
}
|
|
13061
13194
|
return path;
|
|
@@ -13086,7 +13219,7 @@ function resPathOf(entry, projectPath, cwd) {
|
|
|
13086
13219
|
const file = caseAt?.[1] ?? entry;
|
|
13087
13220
|
const fromProject = resolve5(projectPath, file);
|
|
13088
13221
|
const fromHere = resolve5(cwd, file);
|
|
13089
|
-
const absolute = isAbsolute3(file) || !
|
|
13222
|
+
const absolute = isAbsolute3(file) || !existsSync6(fromProject) && existsSync6(fromHere) ? fromHere : fromProject;
|
|
13090
13223
|
const inside = relative3(projectPath, absolute);
|
|
13091
13224
|
if (inside.startsWith("..") || isAbsolute3(inside)) {
|
|
13092
13225
|
throw new EngineUsageError(`${entry} is not inside the project at ${projectPath}.`);
|
|
@@ -13098,7 +13231,7 @@ function homeOf(projectPath) {
|
|
|
13098
13231
|
return mainCheckoutOf(projectPath) ?? projectPath;
|
|
13099
13232
|
}
|
|
13100
13233
|
function sweepRunDirectories(runs, kept = KEPT_RUN_DIRECTORIES) {
|
|
13101
|
-
if (!
|
|
13234
|
+
if (!existsSync6(runs)) {
|
|
13102
13235
|
return;
|
|
13103
13236
|
}
|
|
13104
13237
|
const ended = [];
|
|
@@ -13339,7 +13472,7 @@ async function watchedEngine(launch, lock, args, directory, log, silenceSeconds,
|
|
|
13339
13472
|
continue;
|
|
13340
13473
|
}
|
|
13341
13474
|
const { stoppedIn } = readRun(readLog(log));
|
|
13342
|
-
const unstarted = helper !== null && !
|
|
13475
|
+
const unstarted = helper !== null && !existsSync6(helper.pid) ? `, and it never started ${helper.how}: ${helperStep(helper.step)}` : "";
|
|
13343
13476
|
ended = `the engine printed nothing for ${String(allowed.seconds)} s${countedBy(quiet, silent, at)}${stoppedIn === null ? "" : ` while running ${stoppedIn}`}, so it was ended${unstarted}`;
|
|
13344
13477
|
stop();
|
|
13345
13478
|
}
|
|
@@ -13425,7 +13558,7 @@ var init_engine_launch = __esm(() => {
|
|
|
13425
13558
|
});
|
|
13426
13559
|
|
|
13427
13560
|
// src/detection.ts
|
|
13428
|
-
import { existsSync as
|
|
13561
|
+
import { existsSync as existsSync7, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
13429
13562
|
import { homedir as homedir4 } from "node:os";
|
|
13430
13563
|
import { join as join10 } from "node:path";
|
|
13431
13564
|
function resolveHomeDirectory() {
|
|
@@ -13436,7 +13569,7 @@ function resolveHomeDirectory() {
|
|
|
13436
13569
|
}
|
|
13437
13570
|
}
|
|
13438
13571
|
function scanDirectoryForGodotBinaries(directory, platform) {
|
|
13439
|
-
if (!directory || !
|
|
13572
|
+
if (!directory || !existsSync7(directory)) {
|
|
13440
13573
|
return [];
|
|
13441
13574
|
}
|
|
13442
13575
|
let entries;
|
|
@@ -13704,7 +13837,7 @@ var init_launch = __esm(() => {
|
|
|
13704
13837
|
});
|
|
13705
13838
|
|
|
13706
13839
|
// src/godot-path.ts
|
|
13707
|
-
import { existsSync as
|
|
13840
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
13708
13841
|
import { isAbsolute as isAbsolute4, normalize, resolve as resolve6 } from "node:path";
|
|
13709
13842
|
function versionStartOf(error) {
|
|
13710
13843
|
const failed = error ?? {};
|
|
@@ -13782,7 +13915,7 @@ class GodotLocator {
|
|
|
13782
13915
|
if (known !== undefined) {
|
|
13783
13916
|
return known;
|
|
13784
13917
|
}
|
|
13785
|
-
if (path !== "godot" && !
|
|
13918
|
+
if (path !== "godot" && !existsSync8(path)) {
|
|
13786
13919
|
this.answered.set(path, "does not exist");
|
|
13787
13920
|
return "does not exist";
|
|
13788
13921
|
}
|
|
@@ -14167,7 +14300,7 @@ var init_engine_run = __esm(() => {
|
|
|
14167
14300
|
});
|
|
14168
14301
|
|
|
14169
14302
|
// src/doc-cache.ts
|
|
14170
|
-
import { existsSync as
|
|
14303
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
14171
14304
|
import { homedir as homedir5 } from "node:os";
|
|
14172
14305
|
import { basename as basename5, dirname as dirname5, isAbsolute as isAbsolute5, join as join11 } from "node:path";
|
|
14173
14306
|
import process9 from "node:process";
|
|
@@ -14175,7 +14308,7 @@ function editorCacheDirectory(godotPath, platform = process9.platform, env = pro
|
|
|
14175
14308
|
const beside = dirname5(godotPath);
|
|
14176
14309
|
const bundle = platform === "darwin" && basename5(beside) === "MacOS" && basename5(dirname5(beside)) === "Contents" ? dirname5(dirname5(dirname5(beside))) : null;
|
|
14177
14310
|
for (const folder of bundle === null ? [beside] : [beside, bundle]) {
|
|
14178
|
-
if (
|
|
14311
|
+
if (existsSync9(join11(folder, "._sc_")) || existsSync9(join11(folder, "_sc_"))) {
|
|
14179
14312
|
return join11(folder, "editor_data", "cache");
|
|
14180
14313
|
}
|
|
14181
14314
|
}
|
|
@@ -14223,7 +14356,7 @@ var init_doc_cache = __esm(() => {
|
|
|
14223
14356
|
});
|
|
14224
14357
|
|
|
14225
14358
|
// src/project-scan.ts
|
|
14226
|
-
import { existsSync as
|
|
14359
|
+
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync12, statSync as statSync9 } from "node:fs";
|
|
14227
14360
|
import { basename as basename6, extname as extname2, join as join12, relative as relative4, sep as sep3 } from "node:path";
|
|
14228
14361
|
function skipped(name) {
|
|
14229
14362
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -14232,10 +14365,10 @@ function steppedOver(directory) {
|
|
|
14232
14365
|
return gdignored(directory) || installedByUs(directory);
|
|
14233
14366
|
}
|
|
14234
14367
|
function gdignored(directory) {
|
|
14235
|
-
return
|
|
14368
|
+
return existsSync10(join12(directory, ".gdignore"));
|
|
14236
14369
|
}
|
|
14237
14370
|
function installedByUs(directory) {
|
|
14238
|
-
return
|
|
14371
|
+
return existsSync10(join12(directory, VERSION_MARKER));
|
|
14239
14372
|
}
|
|
14240
14373
|
function projectStructure(projectPath) {
|
|
14241
14374
|
const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
|
|
@@ -14348,7 +14481,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
14348
14481
|
continue;
|
|
14349
14482
|
}
|
|
14350
14483
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
14351
|
-
if (CARRIES_A_UID.has(extension) && !
|
|
14484
|
+
if (CARRIES_A_UID.has(extension) && !existsSync10(join12(directory, `${entry.name}.uid`))) {
|
|
14352
14485
|
found.push(spelled);
|
|
14353
14486
|
}
|
|
14354
14487
|
}
|
|
@@ -14615,7 +14748,7 @@ var init_project_scan = __esm(() => {
|
|
|
14615
14748
|
|
|
14616
14749
|
// src/import-freshness.ts
|
|
14617
14750
|
import { createHash as createHash2 } from "node:crypto";
|
|
14618
|
-
import { existsSync as
|
|
14751
|
+
import { existsSync as existsSync11, readdirSync as readdirSync8, readFileSync as readFileSync13, statSync as statSync10 } from "node:fs";
|
|
14619
14752
|
import { join as join13 } from "node:path";
|
|
14620
14753
|
function md5Of(file) {
|
|
14621
14754
|
let stats;
|
|
@@ -14741,7 +14874,7 @@ function behind(projectPath, resPath, sidecarFile, sidecar, importedFrom) {
|
|
|
14741
14874
|
return "its import file names no imported output, as one written before the engine imports from it does";
|
|
14742
14875
|
}
|
|
14743
14876
|
}
|
|
14744
|
-
if (outputs.some((output) => !
|
|
14877
|
+
if (outputs.some((output) => !existsSync11(onDisk(projectPath, output)))) {
|
|
14745
14878
|
return "its imported output is not on disk";
|
|
14746
14879
|
}
|
|
14747
14880
|
const source = unquoted(deps.get("source_file"));
|
|
@@ -14766,7 +14899,7 @@ function staleImports(projectPath) {
|
|
|
14766
14899
|
const stale = [];
|
|
14767
14900
|
const importedFrom = importedSidecarMd5s(projectPath);
|
|
14768
14901
|
const visit = (directory, resDirectory) => {
|
|
14769
|
-
if (
|
|
14902
|
+
if (existsSync11(join13(directory, ".gdignore")) || existsSync11(join13(directory, VERSION_MARKER))) {
|
|
14770
14903
|
return;
|
|
14771
14904
|
}
|
|
14772
14905
|
let entries;
|
|
@@ -14857,7 +14990,7 @@ var init_import_freshness = __esm(() => {
|
|
|
14857
14990
|
|
|
14858
14991
|
// src/library-copies.ts
|
|
14859
14992
|
import {
|
|
14860
|
-
existsSync as
|
|
14993
|
+
existsSync as existsSync12,
|
|
14861
14994
|
mkdirSync as mkdirSync4,
|
|
14862
14995
|
readdirSync as readdirSync9,
|
|
14863
14996
|
readFileSync as readFileSync14,
|
|
@@ -14875,7 +15008,7 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14875
15008
|
for (const library of windowsLibraries(projectPath)) {
|
|
14876
15009
|
const folder = dirname6(library);
|
|
14877
15010
|
const copy = `~${basename7(library)}`;
|
|
14878
|
-
if (
|
|
15011
|
+
if (existsSync12(join14(folder, copy))) {
|
|
14879
15012
|
const aside = join14(folder, `${copy}.aside-${process.pid}-${Date.now()}`);
|
|
14880
15013
|
try {
|
|
14881
15014
|
renameSync3(join14(folder, copy), aside);
|
|
@@ -14901,7 +15034,7 @@ function freeLibraryCopies(projectPath, platform = process.platform) {
|
|
|
14901
15034
|
}
|
|
14902
15035
|
function seedExtensionList(projectPath) {
|
|
14903
15036
|
const list = join14(projectPath, ".godot", "extension_list.cfg");
|
|
14904
|
-
if (
|
|
15037
|
+
if (existsSync12(list)) {
|
|
14905
15038
|
return null;
|
|
14906
15039
|
}
|
|
14907
15040
|
const found = unlistedExtensions(projectPath);
|
|
@@ -14915,12 +15048,12 @@ function seedExtensionList(projectPath) {
|
|
|
14915
15048
|
return found;
|
|
14916
15049
|
}
|
|
14917
15050
|
function unlistedExtensions(projectPath) {
|
|
14918
|
-
if (
|
|
15051
|
+
if (existsSync12(join14(projectPath, ".godot", "extension_list.cfg"))) {
|
|
14919
15052
|
return [];
|
|
14920
15053
|
}
|
|
14921
15054
|
const found = [];
|
|
14922
15055
|
const visit = (directory, resDirectory) => {
|
|
14923
|
-
if (
|
|
15056
|
+
if (existsSync12(join14(directory, ".gdignore"))) {
|
|
14924
15057
|
return;
|
|
14925
15058
|
}
|
|
14926
15059
|
let entries;
|
|
@@ -14991,12 +15124,12 @@ var init_library_copies = () => {};
|
|
|
14991
15124
|
|
|
14992
15125
|
// src/reimport.ts
|
|
14993
15126
|
import { createHash as createHash3 } from "node:crypto";
|
|
14994
|
-
import { existsSync as
|
|
15127
|
+
import { existsSync as existsSync13, readFileSync as readFileSync15, rmSync as rmSync8, statSync as statSync11, utimesSync, writeFileSync as writeFileSync8 } from "node:fs";
|
|
14995
15128
|
import { basename as basename8, join as join15 } from "node:path";
|
|
14996
15129
|
function forceNextImport(projectPath, resourcePath) {
|
|
14997
15130
|
const relative = resourcePath.replace(/^res:\/\//, "");
|
|
14998
15131
|
const sidecar = join15(projectPath, `${relative}.import`);
|
|
14999
|
-
if (!
|
|
15132
|
+
if (!existsSync13(sidecar)) {
|
|
15000
15133
|
return;
|
|
15001
15134
|
}
|
|
15002
15135
|
const { atime, mtimeMs } = statSync11(sidecar);
|
|
@@ -15011,7 +15144,7 @@ function importRecord(projectPath, resourcePath) {
|
|
|
15011
15144
|
var init_reimport = () => {};
|
|
15012
15145
|
|
|
15013
15146
|
// src/scratch.ts
|
|
15014
|
-
import { existsSync as
|
|
15147
|
+
import { existsSync as existsSync14, mkdtempSync as mkdtempSync2, readdirSync as readdirSync10, rmSync as rmSync9 } from "node:fs";
|
|
15015
15148
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
15016
15149
|
import { join as join16 } from "node:path";
|
|
15017
15150
|
import process10 from "node:process";
|
|
@@ -15070,7 +15203,7 @@ function tryAgain(path, attempt) {
|
|
|
15070
15203
|
lastTryOnExit();
|
|
15071
15204
|
}
|
|
15072
15205
|
const after = AGAIN_AFTER_MS[attempt];
|
|
15073
|
-
if (after === undefined || !
|
|
15206
|
+
if (after === undefined || !existsSync14(path)) {
|
|
15074
15207
|
waiting.delete(path);
|
|
15075
15208
|
if (after === undefined) {
|
|
15076
15209
|
atExit.add(path);
|
|
@@ -15226,7 +15359,7 @@ var init_script_origins = __esm(() => {
|
|
|
15226
15359
|
});
|
|
15227
15360
|
|
|
15228
15361
|
// src/headless.ts
|
|
15229
|
-
import { existsSync as
|
|
15362
|
+
import { existsSync as existsSync15, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
15230
15363
|
import { dirname as dirname7, join as join18 } from "node:path";
|
|
15231
15364
|
function snakeCased(params) {
|
|
15232
15365
|
const result = emptyRecord();
|
|
@@ -15515,7 +15648,7 @@ async function operationOutcome(engine, operation, params, projectPath) {
|
|
|
15515
15648
|
};
|
|
15516
15649
|
}
|
|
15517
15650
|
function answerIn(file) {
|
|
15518
|
-
if (!
|
|
15651
|
+
if (!existsSync15(file)) {
|
|
15519
15652
|
return { kind: "none" };
|
|
15520
15653
|
}
|
|
15521
15654
|
const text = readFileSync16(file, "utf8");
|
|
@@ -15544,7 +15677,7 @@ var init_headless = __esm(() => {
|
|
|
15544
15677
|
});
|
|
15545
15678
|
|
|
15546
15679
|
// src/update-check.ts
|
|
15547
|
-
import { existsSync as
|
|
15680
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
15548
15681
|
import { homedir as homedir6, tmpdir as tmpdir6 } from "node:os";
|
|
15549
15682
|
import { join as join19 } from "node:path";
|
|
15550
15683
|
function packageUrl(root) {
|
|
@@ -15586,7 +15719,7 @@ function cacheFile(environment = process.env) {
|
|
|
15586
15719
|
}
|
|
15587
15720
|
function readCache(path) {
|
|
15588
15721
|
try {
|
|
15589
|
-
if (!
|
|
15722
|
+
if (!existsSync16(path)) {
|
|
15590
15723
|
return null;
|
|
15591
15724
|
}
|
|
15592
15725
|
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
@@ -16066,7 +16199,7 @@ var init_ports = __esm(() => {
|
|
|
16066
16199
|
});
|
|
16067
16200
|
|
|
16068
16201
|
// src/lsp_client.ts
|
|
16069
|
-
import { existsSync as
|
|
16202
|
+
import { existsSync as existsSync17, realpathSync as realpathSync3 } from "node:fs";
|
|
16070
16203
|
import { readFile, realpath } from "node:fs/promises";
|
|
16071
16204
|
import { createConnection } from "node:net";
|
|
16072
16205
|
import { dirname as dirname8, extname as extname3, join as join20, resolve as resolve7 } from "node:path";
|
|
@@ -16747,7 +16880,7 @@ async function resolveLSPPaths(projectPathValue, scriptPathValue) {
|
|
|
16747
16880
|
} catch {
|
|
16748
16881
|
throw new ArgumentRefusal(`Project path does not exist: ${requestedProjectPath}`);
|
|
16749
16882
|
}
|
|
16750
|
-
if (!
|
|
16883
|
+
if (!existsSync17(join20(projectPath, "project.godot"))) {
|
|
16751
16884
|
throw new ArgumentRefusal(`Not a Godot project: ${projectPath}. Point projectPath at the directory holding project.godot.`);
|
|
16752
16885
|
}
|
|
16753
16886
|
const contained = resolveWithinProject(projectPath, scriptPathValue);
|
|
@@ -17261,7 +17394,7 @@ function readParams(params, key) {
|
|
|
17261
17394
|
import { createHash as createHash5 } from "node:crypto";
|
|
17262
17395
|
import {
|
|
17263
17396
|
cpSync,
|
|
17264
|
-
existsSync as
|
|
17397
|
+
existsSync as existsSync19,
|
|
17265
17398
|
mkdirSync as mkdirSync6,
|
|
17266
17399
|
readdirSync as readdirSync12,
|
|
17267
17400
|
readFileSync as readFileSync21,
|
|
@@ -17344,7 +17477,7 @@ function installedRuntimeDigest(projectPath) {
|
|
|
17344
17477
|
}
|
|
17345
17478
|
function digestMarker(projectPath, addon) {
|
|
17346
17479
|
const marker = join22(projectPath, "addons", addon, DIGEST_MARKER);
|
|
17347
|
-
if (!
|
|
17480
|
+
if (!existsSync19(marker)) {
|
|
17348
17481
|
return null;
|
|
17349
17482
|
}
|
|
17350
17483
|
const said = readFileSync21(marker, "utf8").trim();
|
|
@@ -17361,7 +17494,7 @@ function shippedLoader() {
|
|
|
17361
17494
|
}
|
|
17362
17495
|
function loaderState(projectPath) {
|
|
17363
17496
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17364
|
-
if (!
|
|
17497
|
+
if (!existsSync19(copy)) {
|
|
17365
17498
|
return "missing";
|
|
17366
17499
|
}
|
|
17367
17500
|
const lines = (path) => readFileSync21(path, "utf8").replaceAll(`\r
|
|
@@ -17380,7 +17513,7 @@ function writeLoader(projectPath) {
|
|
|
17380
17513
|
}
|
|
17381
17514
|
function removeLoader(projectPath) {
|
|
17382
17515
|
const copy = join22(projectPath, ...RUNTIME_AUTOLOAD.path.split("/"));
|
|
17383
|
-
if (!
|
|
17516
|
+
if (!existsSync19(copy)) {
|
|
17384
17517
|
return false;
|
|
17385
17518
|
}
|
|
17386
17519
|
rmSync10(copy);
|
|
@@ -17396,10 +17529,10 @@ function shippedListedRunner() {
|
|
|
17396
17529
|
}
|
|
17397
17530
|
function gdUnit4Unusable(projectPath) {
|
|
17398
17531
|
const marker = "addons/gdUnit4/plugin.cfg";
|
|
17399
|
-
if (!
|
|
17532
|
+
if (!existsSync19(join22(projectPath, ...marker.split("/")))) {
|
|
17400
17533
|
return { missing: true, reason: `gdUnit4 is not installed in this project: no ${marker}` };
|
|
17401
17534
|
}
|
|
17402
|
-
if (!
|
|
17535
|
+
if (!existsSync19(join22(projectPath, ...GDUNIT4_CI_RUNNER.split("/")))) {
|
|
17403
17536
|
return {
|
|
17404
17537
|
missing: false,
|
|
17405
17538
|
reason: `gdUnit4 in this project is older than 6.0, which the shipped runner needs: no ${GDUNIT4_CI_RUNNER}`
|
|
@@ -17411,11 +17544,11 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17411
17544
|
const installed = [];
|
|
17412
17545
|
for (const name of ADDONS) {
|
|
17413
17546
|
const source = join22(from, name);
|
|
17414
|
-
if (!
|
|
17547
|
+
if (!existsSync19(join22(source, addonMarking(name)))) {
|
|
17415
17548
|
throw new Error(`The package holds no ${name} addon at ${source}.`);
|
|
17416
17549
|
}
|
|
17417
17550
|
const target = join22(projectPath, "addons", name);
|
|
17418
|
-
const replaced =
|
|
17551
|
+
const replaced = existsSync19(target);
|
|
17419
17552
|
rmSync10(target, { recursive: true, force: true });
|
|
17420
17553
|
mkdirSync6(dirname9(target), { recursive: true });
|
|
17421
17554
|
cpSync(source, target, { recursive: true });
|
|
@@ -17431,7 +17564,7 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
17431
17564
|
}
|
|
17432
17565
|
function installedAddonVersion(projectPath) {
|
|
17433
17566
|
const marker = join22(projectPath, "addons", ADDONS[0], VERSION_MARKER);
|
|
17434
|
-
if (!
|
|
17567
|
+
if (!existsSync19(marker)) {
|
|
17435
17568
|
return null;
|
|
17436
17569
|
}
|
|
17437
17570
|
const said = readFileSync21(marker, "utf8").trim();
|
|
@@ -17441,13 +17574,13 @@ function removeAddons(projectPath) {
|
|
|
17441
17574
|
const removed = [];
|
|
17442
17575
|
for (const name of ADDONS) {
|
|
17443
17576
|
const target = join22(projectPath, "addons", name);
|
|
17444
|
-
if (
|
|
17577
|
+
if (existsSync19(target)) {
|
|
17445
17578
|
rmSync10(target, { recursive: true, force: true });
|
|
17446
17579
|
removed.push(target);
|
|
17447
17580
|
}
|
|
17448
17581
|
}
|
|
17449
17582
|
const addons = join22(projectPath, "addons");
|
|
17450
|
-
if (removed.length > 0 &&
|
|
17583
|
+
if (removed.length > 0 && existsSync19(addons) && readdirSync12(addons).length === 0) {
|
|
17451
17584
|
rmdirSync(addons);
|
|
17452
17585
|
removed.push(addons);
|
|
17453
17586
|
}
|
|
@@ -17547,8 +17680,8 @@ function inspectProject(projectPath) {
|
|
|
17547
17680
|
const addons = ADDONS.map((name) => {
|
|
17548
17681
|
const directory = join22(projectPath, "addons", name);
|
|
17549
17682
|
const marker = join22(directory, VERSION_MARKER);
|
|
17550
|
-
const installed =
|
|
17551
|
-
const version =
|
|
17683
|
+
const installed = existsSync19(directory);
|
|
17684
|
+
const version = existsSync19(marker) ? readFileSync21(marker, "utf8").trim() : null;
|
|
17552
17685
|
const current = version === SERVER_VERSION;
|
|
17553
17686
|
if (!installed) {
|
|
17554
17687
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -17581,7 +17714,7 @@ function inspectProject(projectPath) {
|
|
|
17581
17714
|
const ignoredAutoloads = [];
|
|
17582
17715
|
const addonMissing = (path) => addons.some((addon) => !addon.installed && path.startsWith(`addons/${addon.name}/`));
|
|
17583
17716
|
for (const [name, path] of named) {
|
|
17584
|
-
if (!
|
|
17717
|
+
if (!existsSync19(join22(projectPath, path))) {
|
|
17585
17718
|
if (!addonMissing(path)) {
|
|
17586
17719
|
problems.push(`the ${name} autoload names res://${path}, which is not in this project, so it boots with a missing script; restore that file, or point the autoload at one that is here`);
|
|
17587
17720
|
}
|
|
@@ -17986,7 +18119,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
17986
18119
|
{
|
|
17987
18120
|
name: "project_settings",
|
|
17988
18121
|
title: "Project settings",
|
|
17989
|
-
description: "Reads or writes project.godot (settings, autoloads, the main scene, input actions and plugins) and the audio bus layout, default_bus_layout.tres unless audio/buses/default_bus_layout names another. project_info include lists the autoloads, input actions and audio buses as the project holds them. A write with an editor open on the project is handed to the editor, which takes the settings the write
|
|
18122
|
+
description: "Reads or writes project.godot (settings, autoloads, the main scene, input actions and plugins) and the audio bus layout, default_bus_layout.tres unless audio/buses/default_bus_layout names another. project_info include lists the autoloads, input actions and audio buses as the project holds them. A write with an editor open on the project is handed to the editor, which takes the settings the write names from the file (named under editorAdopted), even one the file already held, or reloads the bus layout, so it does not save the old values back over them. editorNote is an editor that could not take the write, or one on another release's addon that was not asked, which still holds the old values until editor_launch restart. An enabled plugin's code still loads on the editor's next start, and enable_plugin notes a script it would not load. set answers old_value and new_value, with was_new true when project.godot did not set the setting before, and was_default true when what it held was the engine's own default, which old_value then is, and overrides with overridesNote when a feature's override still replaces it. add_autoload refuses a name the editor's Autoload tab refuses: not an identifier, a keyword, a built-in type or an engine class. add_input_action on an existing action, a ui_ one included, replaces its events, and its deadzone when one is given, answering was_new false with old_events and old_deadzone. A set of the value the setting already holds, in the same type, writes nothing and answers unchanged true and saved false. unset takes a setting's line out of project.godot and answers removed, old_value and default_value, the value that holds now (null for a setting the engine does not declare; for an override, name.feature, holds is the base setting's value its builds read now); on one the file does not set it answers removed false and writes nothing, its note naming the nearest settings when the engine does not declare it either. Every write changes only the lines of the settings it names and keeps every other line as the file had it, in its place. get answers exists, true for any setting the engine knows, at_default, true when the value is the engine's own default and so has no line in project.godot, and overrides, the value each feature's override holds. An override answers override_of, its base setting, and one project.godot does not set answers exists false with holds, the base setting's value. Each setting under prefix carries at_default too; it is absent for a setting with no engine default, such as an input action the project added. A setting res://override.cfg or the project_settings_override file sets, which a run lays over project.godot and the editor does not, is answered with the project's value and overridden_in, the file and the value a run reads; a set adds overriddenNote.",
|
|
17990
18123
|
parameters: {
|
|
17991
18124
|
projectPath: PROJECT_PATH,
|
|
17992
18125
|
setting: {
|
|
@@ -19279,7 +19412,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
19279
19412
|
title: "Editor status",
|
|
19280
19413
|
effect: "read",
|
|
19281
19414
|
description: "Whether the editor addon is connected, which Godot answers, whether the editor is playing something, and which games with the runtime addon are reachable, of this project and of every other on the machine. Read connected with mayYetConnect: the editor dials this server and backs off between tries, so for the first half-minute after a server starts false means not reached yet as often as no editor; mayYetConnect true is worth waiting out, false is final, and editorCannotConnect, restartInterrupted, restartUnderway, closedHere and editorsNotYetConnected say why. An editor that has connected and not yet greeted reports nothing about itself, and every other call made in that window waits up to ten seconds for it to settle. playingInEditor null means unanswered rather than nothing playing: processActive and runtimes do not depend on the editor answering. game.run names the run editor_output and editor_run stop answer for, and stays named after it ends. addonIsStale, on a connected editor and on each running game (absent with neither), says it runs addon code other than what this server ships, and staleNote says which half moves: the project, by a gdharness upgrade it spells out to run in a shell, the editor by a restart, or this server by a reconnect. A false editor.lspListening or editor.dapListening comes with serversNote: editor_launch rebind binds the debug adapter again in place, and editor_launch restart the language server. editor.scan says whether the editor is scanning, which editor_run waits out before starting a game. A game announced in a protocol this server does not speak is listed under unreadable, during an upgrade that moves the protocol, until the halves match.",
|
|
19282
|
-
answer: "projectIs, when present, is the gdharness version of the addons in the project, which differs from this server's (project_info says which of the two to move), and configIs, when present, the version the project's MCP config starts, which differs from this server's, so the next connection runs that one. server names this server: its pid, its version, and lifecycleLog, the file every gdharness server of the user appends a line to when it starts, when its client first names itself, when it replaces another server of its project, and when it ends, with why it ended (the client closing its end as stdin:end, a signal by name, superseded with the successor's pid, an uncaught exception or rejection with its stack, or the exit code) and the calls it was answering then. The parent's command line follows on its own line a few seconds after the start. A server killed without warning writes no ended line, and on Windows every kill is that, so a started line with no ended line after it is a server something killed. " + "runtimeConnected counts the games of the project this server serves, and runtimes lists every game on the machine with ofThisProject saying which is which, since a game of another project is reached only by naming its projectPath, and userDir, the directory its user:// is, where its saves and settings are read. playingInEditor is null when the editor was not asked or did not answer, which is not the same as a no: with no editor connected there is nobody to ask, and an editor that does not serve the question is given a moment and then left. A game can be playing while this is null, so read it as unanswered rather than as nothing playing, and use processActive and runtimes, which come from elsewhere and do not depend on the editor answering. Its play says which play the editor is on: play.play counts the plays that editor has started since it opened, whoever started them, and play.editorPid is the editor, so two reads with different pairs are two plays even when both say playing. game.run names the run processActive is about, the one editor_output and editor_run stop answer for: its pid, its project, and adopted true when this server read it back from another server rather than starting it. It stays named after the run ends, beside processActive false, so editor_output can still read what that run printed; null when there is no run at all. startedAt says when it began, and endedAt when it ended, wherever something saw the end: a run adopted from a note another server wrote can have ended hours before this server started. editor.lspListening and editor.dapListening say whether anything accepts connections on the ports the editor names, lspPort and dapPort: Godot binds each once, as the editor starts, and reports a failure only in the log panel of the editor itself, so a false comes with serversNote: editor_launch rebind binds the debug adapter again in place, and editor_launch restart the language server. editor.scan says whether the editor is scanning or importing and how many milliseconds ago its last scan finished (finishedMsAgo), or is null when it did not answer: the editor rewrites the class cache just after a scan, and editor_run waits that out before starting a game, saying so under waitedForEditorScanMs. editor.openScenes lists the scenes open in the editor's tabs, leaving out a tab of a scene never saved, editor.editedScene the one it is showing (null when none is, or when that scene was never saved), and editor.unsavedScenes those with changes not yet written to disk, where an empty entry is a scene never saved; all three come with scan and are absent when it is null. Each game under runtimes is pinged with a short wait, so one held at a breakpoint is listed as unreachable rather than making this call wait out the runtime timeout; for the run this server is reporting on, heldAt says whether that is what it is, with the same three answers editor_output gives. A game the editor played announces the editor under editorPid, and so does whatever that game started for itself; a game some other server started announces none, which is how the two are told apart when both are running from one project. Each game also says which runtime addon it loaded, under addonVersion (null when it cannot say); addonIsStale is true when that code is not what this server ships, and staleNote says whether the project needs the gdharness upgrade command, spelled out to run in a shell, the game a restart, or this server a reconnect. A second checkout of a project, such as a git worktree, carries addons of its own and is where this shows. A runtime_* call to such a game is refused with the staleNote and not sent. When connected is false, mayYetConnect says whether that is final: the editor dials this server rather than the other way round and backs off between tries, so for the first half-minute after a server starts, false means \"not reached yet\" as often as it means \"no editor\". True is worth waiting out; false is an editor that is not there. False beside editorCannotConnect is a project without the gdharness editor addon installed or enabled, where no editor can ever dial in, however young the server or whichever editor is open; its remedies say how to install or enable it. False beside restartInterrupted is one that an editor_launch restart on a previous server asked to quit, where the launch half never ran because that server was ended in between, usually by the reconnect the restart was taken for; editor_launch open finishes it. True beside restartUnderway is a restart still in progress, its server alive and within the wait for the old editor to go: the editor is coming, and opening another would put two on one project. listeningSince is when this server took the bridge port, which is what that window is measured from and what a caller wanting its own window should read. An editor this server opened counts for as long as its process lives, however far past that window the import runs, and awaitingLaunchedEditor names its pid so the two reasons for true are told apart. Any editor of this project running and not yet connected, whoever opened it, makes it true as well and is named under editorsNotYetConnected with its pid and start time, so a restart a reconnect interrupted after its launch is not read as nothing being there. settingsDropped appears here once when the editor this server opened saved project.godot on its way in and took a key out of it, which is the same reading editor_launch restart makes in its own answer. A game that has announced itself in a protocol this server does not speak is listed under unreadable rather than left out, with the protocol it speaks and whether the server or the addon is the older half. This happens during an upgrade that moves the runtime protocol, which most do not: installing replaces the addon on disk as soon as the pin moves, while a server that is already running stays on the version it started with, so the two speak different protocols until the server is reconnected. Those games are real and running, but no tool here can reach them until the halves match, so runtimes stays empty and runtimeConnected stays false. An upgrade that leaves the protocol alone opens no such window and this list stays empty through it. addonIsStale is decided by the code of the editor addons rather than their version, so an editor started before an upgrade that left that code alone reports the older addonVersion, is not stale, and addonNote says so: it needs no restart. A stale editor is asked nothing but to quit: every other call to it is refused with staleNote, which names editor_launch restart, the upgrade command or a reconnect. port is the one the editor bridge is on; when that is not the one this server was configured with, portWanted names the configured one and portNote says why it moved and, when it was the server this one replaced, which pid kept it. A server replacing another of its project that holds the configured port waits for it to stand down and takes the port over, which takes a few seconds; bridgeHandover says so while it waits, and it moves only if that server has not let go within the wait. An editor that has connected and not yet greeted, which lasts a frame and longer while it imports, reports nothing about itself: greeting says so, addonIsStale is absent rather than guessed, and a restart asked then waits for the greeting to learn who opened it. startedByAnEditor is an editor another editor started, by Godot's own restart or the project manager, which has none of the arguments a server gave the one before it; startedByAnEditorNote says what that costs. An engine run that loads the editor addon to do one job and quit, such as a gate's godot --headless --import, an export or a script, is not taken as the editor: a process that greets without a server's mark has its command line read first, and from the socket opening until its greeting and that read are done, identifying is true and connected false; one started with such an option is turned away, and turnedAway names the last one, its pid and the option. Every other call made while an editor is arriving, before its greeting or while it is looked up, waits up to ten seconds for it to settle rather than acting on connected as it reads in that window. serverVersion is the gdharness version of this server. bridgeAvailable says the editor bridge is listening; when it failed to start, startupError gives the error, and retryingBridge is true while this server tries again. announcedAt is the file where this server told editors of its project which port to dial. connectedAt is when the editor connected, and lastPongAt when it last answered this server's keep-alive ping. addonDigest is a hash of the editor addon's code, which addonIsStale compares with what this server ships. debugPort is the port of the editor's remote debugger, the one games it plays connect to. openedByAServer says a gdharness server started this editor, syncsBreakpoints that it keeps its breakpoints when a debug session opens, which Godot otherwise clears, and hidden that it runs headless with no window anybody can see. pendingRequests counts the requests sent to the editor and not yet answered, and queuedResources the files with writes waiting behind another write to the same file.",
|
|
19415
|
+
answer: "projectIs, when present, is the gdharness version of the addons in the project, which differs from this server's (project_info says which of the two to move), and configIs, when present, the version the project's MCP config starts, which differs from this server's, so the next connection runs that one. server names this server: its pid, its version, and lifecycleLog, the file every gdharness server of the user appends a line to when it starts, when its client first names itself, when it replaces another server of its project, and when it ends, with why it ended (the client closing its end as stdin:end, a signal by name, superseded with the successor's pid, an uncaught exception or rejection with its stack, or the exit code) and the calls it was answering then. The parent's command line follows on its own line a few seconds after the start. A server killed without warning writes no ended line, and on Windows every kill is that, so a started line with no ended line after it is a server something killed. " + "runtimeConnected counts the games of the project this server serves on this release's runtime addon, and runtimes lists every game on the machine with ofThisProject saying which is which, since a game of another project is reached only by naming its projectPath, and userDir, the directory its user:// is, where its saves and settings are read. playingInEditor is null when the editor was not asked or did not answer, which is not the same as a no: with no editor connected there is nobody to ask, and an editor that does not serve the question is given a moment and then left. A game can be playing while this is null, so read it as unanswered rather than as nothing playing, and use processActive and runtimes, which come from elsewhere and do not depend on the editor answering. Its play says which play the editor is on: play.play counts the plays that editor has started since it opened, whoever started them, and play.editorPid is the editor, so two reads with different pairs are two plays even when both say playing. game.run names the run processActive is about, the one editor_output and editor_run stop answer for: its pid, its project, and adopted true when this server read it back from another server rather than starting it. It stays named after the run ends, beside processActive false, so editor_output can still read what that run printed; null when there is no run at all. startedAt says when it began, and endedAt when it ended, wherever something saw the end: a run adopted from a note another server wrote can have ended hours before this server started. editor.lspListening and editor.dapListening say whether anything accepts connections on the ports the editor names, lspPort and dapPort: Godot binds each once, as the editor starts, and reports a failure only in the log panel of the editor itself, so a false comes with serversNote: editor_launch rebind binds the debug adapter again in place, and editor_launch restart the language server. editor.scan says whether the editor is scanning or importing and how many milliseconds ago its last scan finished (finishedMsAgo), or is null when it did not answer: the editor rewrites the class cache just after a scan, and editor_run waits that out before starting a game, saying so under waitedForEditorScanMs. editor.openScenes lists the scenes open in the editor's tabs, leaving out a tab of a scene never saved, editor.editedScene the one it is showing (null when none is, or when that scene was never saved), and editor.unsavedScenes those with changes not yet written to disk, where an empty entry is a scene never saved; all three come with scan and are absent when it is null. Each game under runtimes is pinged with a short wait, so one held at a breakpoint is listed as unreachable rather than making this call wait out the runtime timeout; for the run this server is reporting on, heldAt says whether that is what it is, with the same three answers editor_output gives. A game the editor played announces the editor under editorPid, and so does whatever that game started for itself; a game some other server started announces none, which is how the two are told apart when both are running from one project. Each game also says which runtime addon it loaded, under addonVersion (null when it cannot say); addonIsStale is true when that code is not what this server ships, and staleNote says whether the project needs the gdharness upgrade command, spelled out to run in a shell, the game a restart, or this server a reconnect. A second checkout of a project, such as a git worktree, carries addons of its own and is where this shows. A runtime_* call to such a game is refused with the staleNote and not sent. When connected is false, mayYetConnect says whether that is final: the editor dials this server rather than the other way round and backs off between tries, so for the first half-minute after a server starts, false means \"not reached yet\" as often as it means \"no editor\". True is worth waiting out; false is an editor that is not there. False beside editorCannotConnect is a project without the gdharness editor addon installed or enabled, where no editor can ever dial in, however young the server or whichever editor is open; its remedies say how to install or enable it. False beside restartInterrupted is one that an editor_launch restart on a previous server asked to quit, where the launch half never ran because that server was ended in between, usually by the reconnect the restart was taken for; editor_launch open finishes it. True beside restartUnderway is a restart still in progress, its server alive and within the wait for the old editor to go: the editor is coming, and opening another would put two on one project. listeningSince is when this server took the bridge port, which is what that window is measured from and what a caller wanting its own window should read. An editor this server opened counts for as long as its process lives, however far past that window the import runs, and awaitingLaunchedEditor names its pid so the two reasons for true are told apart. Any editor of this project running and not yet connected, whoever opened it, makes it true as well and is named under editorsNotYetConnected with its pid and start time, so a restart a reconnect interrupted after its launch is not read as nothing being there. settingsDropped appears here once when the editor this server opened saved project.godot on its way in and took a key out of it, which is the same reading editor_launch restart makes in its own answer. A game that has announced itself in a protocol this server does not speak is listed under unreadable rather than left out, with the protocol it speaks and whether the server or the addon is the older half. This happens during an upgrade that moves the runtime protocol, which most do not: installing replaces the addon on disk as soon as the pin moves, while a server that is already running stays on the version it started with, so the two speak different protocols until the server is reconnected. Those games are real and running, but no tool here can reach them until the halves match, so runtimes stays empty and runtimeConnected stays false. An upgrade that leaves the protocol alone opens no such window and this list stays empty through it. addonIsStale is decided by the code of the editor addons rather than their version, so an editor started before an upgrade that left that code alone reports the older addonVersion, is not stale, and addonNote says so: it needs no restart. A stale editor is asked nothing but to quit: every other call to it is refused with staleNote, which names editor_launch restart, the upgrade command or a reconnect. port is the one the editor bridge is on; when that is not the one this server was configured with, portWanted names the configured one and portNote says why it moved and, when it was the server this one replaced, which pid kept it. A server replacing another of its project that holds the configured port waits for it to stand down and takes the port over, which takes a few seconds; bridgeHandover says so while it waits, and it moves only if that server has not let go within the wait. An editor that has connected and not yet greeted, which lasts a frame and longer while it imports, reports nothing about itself: greeting says so, addonIsStale is absent rather than guessed, and a restart asked then waits for the greeting to learn who opened it. startedByAnEditor is an editor another editor started, by Godot's own restart or the project manager, which has none of the arguments a server gave the one before it; startedByAnEditorNote says what that costs. An engine run that loads the editor addon to do one job and quit, such as a gate's godot --headless --import, an export or a script, is not taken as the editor: a process that greets without a server's mark has its command line read first, and from the socket opening until its greeting and that read are done, identifying is true and connected false; one started with such an option is turned away, and turnedAway names the last one, its pid and the option. Every other call made while an editor is arriving, before its greeting or while it is looked up, waits up to ten seconds for it to settle rather than acting on connected as it reads in that window. serverVersion is the gdharness version of this server. bridgeAvailable says the editor bridge is listening; when it failed to start, startupError gives the error, and retryingBridge is true while this server tries again. announcedAt is the file where this server told editors of its project which port to dial. connectedAt is when the editor connected, and lastPongAt when it last answered this server's keep-alive ping. addonDigest is a hash of the editor addon's code, which addonIsStale compares with what this server ships. debugPort is the port of the editor's remote debugger, the one games it plays connect to. openedByAServer says a gdharness server started this editor, syncsBreakpoints that it keeps its breakpoints when a debug session opens, which Godot otherwise clears, and hidden that it runs headless with no window anybody can see. pendingRequests counts the requests sent to the editor and not yet answered, and queuedResources the files with writes waiting behind another write to the same file.",
|
|
19283
19416
|
parameters: {},
|
|
19284
19417
|
requires: []
|
|
19285
19418
|
},
|
|
@@ -20152,7 +20285,7 @@ var init_tool_reference = __esm(() => {
|
|
|
20152
20285
|
});
|
|
20153
20286
|
|
|
20154
20287
|
// src/suite-plan.ts
|
|
20155
|
-
import { existsSync as
|
|
20288
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync9, readFileSync as readFileSync24 } from "node:fs";
|
|
20156
20289
|
import { dirname as dirname11, join as join26, posix as posix3 } from "node:path";
|
|
20157
20290
|
function within(path, folder) {
|
|
20158
20291
|
return path === folder || path.startsWith(`${folder}/`);
|
|
@@ -20564,7 +20697,7 @@ function windowNeedsOf(scripts, paths) {
|
|
|
20564
20697
|
}
|
|
20565
20698
|
function capsFrames(projectPath) {
|
|
20566
20699
|
const file = `${projectPath}/project.godot`;
|
|
20567
|
-
if (!
|
|
20700
|
+
if (!existsSync23(file)) {
|
|
20568
20701
|
return false;
|
|
20569
20702
|
}
|
|
20570
20703
|
const cap = parseProjectGodot(readFileSync24(file, "utf8"))["application"]?.["run/max_fps"];
|
|
@@ -20572,14 +20705,14 @@ function capsFrames(projectPath) {
|
|
|
20572
20705
|
}
|
|
20573
20706
|
function gdUnitFailsOnPushErrors(projectPath) {
|
|
20574
20707
|
const file = `${projectPath}/project.godot`;
|
|
20575
|
-
if (!
|
|
20708
|
+
if (!existsSync23(file)) {
|
|
20576
20709
|
return false;
|
|
20577
20710
|
}
|
|
20578
20711
|
return parseProjectGodot(readFileSync24(file, "utf8"))["gdunit4"]?.["report/godot/push_error"] === true;
|
|
20579
20712
|
}
|
|
20580
20713
|
function viewportOf(projectPath) {
|
|
20581
20714
|
const file = `${projectPath}/project.godot`;
|
|
20582
|
-
if (!
|
|
20715
|
+
if (!existsSync23(file)) {
|
|
20583
20716
|
return null;
|
|
20584
20717
|
}
|
|
20585
20718
|
const text = readFileSync24(file, "utf8");
|
|
@@ -42201,7 +42334,7 @@ var init_stdio = __esm(() => {
|
|
|
42201
42334
|
});
|
|
42202
42335
|
|
|
42203
42336
|
// src/autoload-failure.ts
|
|
42204
|
-
import { existsSync as
|
|
42337
|
+
import { existsSync as existsSync25, readFileSync as readFileSync27 } from "node:fs";
|
|
42205
42338
|
import { join as join29 } from "node:path";
|
|
42206
42339
|
function scriptsAutoloaded(projectPath) {
|
|
42207
42340
|
const scripts = new Map;
|
|
@@ -42217,7 +42350,7 @@ function scriptsAutoloaded(projectPath) {
|
|
|
42217
42350
|
continue;
|
|
42218
42351
|
}
|
|
42219
42352
|
const scene = join29(projectPath, path);
|
|
42220
|
-
if (!
|
|
42353
|
+
if (!existsSync25(scene)) {
|
|
42221
42354
|
continue;
|
|
42222
42355
|
}
|
|
42223
42356
|
try {
|
|
@@ -42240,7 +42373,7 @@ var init_autoload_failure = __esm(() => {
|
|
|
42240
42373
|
});
|
|
42241
42374
|
|
|
42242
42375
|
// src/runtime-client.ts
|
|
42243
|
-
import { existsSync as
|
|
42376
|
+
import { existsSync as existsSync26, readdirSync as readdirSync16, readFileSync as readFileSync28, statSync as statSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
42244
42377
|
import { createConnection as createConnection2 } from "node:net";
|
|
42245
42378
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
42246
42379
|
import { dirname as dirname14, join as join30, resolve as resolve12 } from "node:path";
|
|
@@ -42264,7 +42397,7 @@ function runtimeDirectories(variables = process.env) {
|
|
|
42264
42397
|
function errorReportOf(pid, directories = runtimeDirectories()) {
|
|
42265
42398
|
for (const directory of directories) {
|
|
42266
42399
|
const path = join30(directory, `runtime-${pid}.log`);
|
|
42267
|
-
if (
|
|
42400
|
+
if (existsSync26(path)) {
|
|
42268
42401
|
return path;
|
|
42269
42402
|
}
|
|
42270
42403
|
}
|
|
@@ -42410,7 +42543,7 @@ function strangersAmong(candidates, now, startTimes = startTimesOf) {
|
|
|
42410
42543
|
}).map((one) => one.file));
|
|
42411
42544
|
}
|
|
42412
42545
|
function announcedIn(directory) {
|
|
42413
|
-
if (!
|
|
42546
|
+
if (!existsSync26(directory)) {
|
|
42414
42547
|
return [];
|
|
42415
42548
|
}
|
|
42416
42549
|
const found = [];
|
|
@@ -42463,7 +42596,7 @@ function announcedIn(directory) {
|
|
|
42463
42596
|
return found;
|
|
42464
42597
|
}
|
|
42465
42598
|
async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
42466
|
-
const files = directories.map((directory) => join30(directory, `runtime-${pid}.json`)).filter((file) =>
|
|
42599
|
+
const files = directories.map((directory) => join30(directory, `runtime-${pid}.json`)).filter((file) => existsSync26(file));
|
|
42467
42600
|
const first = files[0];
|
|
42468
42601
|
if (first === undefined) {
|
|
42469
42602
|
return;
|
|
@@ -43042,11 +43175,11 @@ var init_class_note = __esm(() => {
|
|
|
43042
43175
|
});
|
|
43043
43176
|
|
|
43044
43177
|
// src/config-pin.ts
|
|
43045
|
-
import { existsSync as
|
|
43178
|
+
import { existsSync as existsSync27, readFileSync as readFileSync32 } from "node:fs";
|
|
43046
43179
|
import { join as join34 } from "node:path";
|
|
43047
43180
|
function versionsNamedInConfig(projectPath) {
|
|
43048
43181
|
const config = join34(projectPath, ".mcp.json");
|
|
43049
|
-
if (!
|
|
43182
|
+
if (!existsSync27(config)) {
|
|
43050
43183
|
return [];
|
|
43051
43184
|
}
|
|
43052
43185
|
let text;
|
|
@@ -43072,7 +43205,7 @@ var init_config_pin = __esm(() => {
|
|
|
43072
43205
|
});
|
|
43073
43206
|
|
|
43074
43207
|
// src/cut-test-run.ts
|
|
43075
|
-
import { existsSync as
|
|
43208
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync14, readFileSync as readFileSync33, rmSync as rmSync15, writeFileSync as writeFileSync16 } from "node:fs";
|
|
43076
43209
|
import { dirname as dirname18, join as join35 } from "node:path";
|
|
43077
43210
|
function keptAt(projectPath) {
|
|
43078
43211
|
return join35(projectPath, ".godot", "gdharness-reports", "cut-run.json");
|
|
@@ -43087,7 +43220,7 @@ function keepCutTestRun(projectPath, run) {
|
|
|
43087
43220
|
}
|
|
43088
43221
|
function takeCutTestRun(projectPath) {
|
|
43089
43222
|
const path = keptAt(projectPath);
|
|
43090
|
-
if (!
|
|
43223
|
+
if (!existsSync28(path)) {
|
|
43091
43224
|
return null;
|
|
43092
43225
|
}
|
|
43093
43226
|
try {
|
|
@@ -43855,7 +43988,7 @@ var init_dap_client = __esm(() => {
|
|
|
43855
43988
|
// src/editor-log.ts
|
|
43856
43989
|
import {
|
|
43857
43990
|
closeSync as closeSync5,
|
|
43858
|
-
existsSync as
|
|
43991
|
+
existsSync as existsSync29,
|
|
43859
43992
|
mkdirSync as mkdirSync15,
|
|
43860
43993
|
openSync as openSync5,
|
|
43861
43994
|
readFileSync as readFileSync34,
|
|
@@ -43919,7 +44052,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
|
|
|
43919
44052
|
return { kind: "another editor", notedPid: noted?.pid ?? null };
|
|
43920
44053
|
}
|
|
43921
44054
|
const path = editorLogPath(projectPath);
|
|
43922
|
-
if (!
|
|
44055
|
+
if (!existsSync29(path)) {
|
|
43923
44056
|
return { kind: "not written" };
|
|
43924
44057
|
}
|
|
43925
44058
|
const log = new GameLog;
|
|
@@ -44138,7 +44271,7 @@ var init_editor_log = __esm(() => {
|
|
|
44138
44271
|
});
|
|
44139
44272
|
|
|
44140
44273
|
// src/rename.ts
|
|
44141
|
-
import { existsSync as
|
|
44274
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync16, readFileSync as readFileSync35, renameSync as renameSync4, unlinkSync as unlinkSync4, writeFileSync as writeFileSync18 } from "node:fs";
|
|
44142
44275
|
import { dirname as dirname20, posix as posix4 } from "node:path";
|
|
44143
44276
|
|
|
44144
44277
|
class Script {
|
|
@@ -44863,7 +44996,7 @@ function applyRewrites(rewrites) {
|
|
|
44863
44996
|
if (now !== rewrite.before) {
|
|
44864
44997
|
throw new Error(`${rewrite.path} changed on disk while the rename was being worked out; nothing was written`);
|
|
44865
44998
|
}
|
|
44866
|
-
if (rewrite.writeTo !== rewrite.absolute &&
|
|
44999
|
+
if (rewrite.writeTo !== rewrite.absolute && existsSync30(rewrite.writeTo)) {
|
|
44867
45000
|
throw new Error(`${rewrite.writeTo} already exists; nothing was written`);
|
|
44868
45001
|
}
|
|
44869
45002
|
}
|
|
@@ -44877,7 +45010,7 @@ function applyRewrites(rewrites) {
|
|
|
44877
45010
|
let movedUid = false;
|
|
44878
45011
|
if (rewrite.writeTo !== rewrite.absolute) {
|
|
44879
45012
|
unlinkSync4(rewrite.absolute);
|
|
44880
|
-
if (
|
|
45013
|
+
if (existsSync30(`${rewrite.absolute}.uid`)) {
|
|
44881
45014
|
renameSync4(`${rewrite.absolute}.uid`, `${rewrite.writeTo}.uid`);
|
|
44882
45015
|
movedUid = true;
|
|
44883
45016
|
}
|
|
@@ -44923,7 +45056,7 @@ var init_rename = __esm(() => {
|
|
|
44923
45056
|
});
|
|
44924
45057
|
|
|
44925
45058
|
// src/rename-symbol.ts
|
|
44926
|
-
import { existsSync as
|
|
45059
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync17, readdirSync as readdirSync17, realpathSync as realpathSync6, rmSync as rmSync17, writeFileSync as writeFileSync19 } from "node:fs";
|
|
44927
45060
|
import { basename as basename10, dirname as dirname21, join as join37, relative as relative7, resolve as resolve13 } from "node:path";
|
|
44928
45061
|
function resourcePathOf(projectPath, absolute) {
|
|
44929
45062
|
const inside = relative7(onDiskSpelling(projectPath), onDiskSpelling(absolute));
|
|
@@ -44937,7 +45070,7 @@ function onDiskSpelling(path) {
|
|
|
44937
45070
|
let at = resolve13(path);
|
|
44938
45071
|
for (;; ) {
|
|
44939
45072
|
try {
|
|
44940
|
-
return join37(
|
|
45073
|
+
return join37(realpathSync6.native(at), ...missing.reverse());
|
|
44941
45074
|
} catch {
|
|
44942
45075
|
const parent = dirname21(at);
|
|
44943
45076
|
if (parent === at) {
|
|
@@ -44991,7 +45124,7 @@ async function renameSymbol(request, services) {
|
|
|
44991
45124
|
reason: `newScriptPath must be a .gd path inside the project, and ${request.newScriptPath} is not.`
|
|
44992
45125
|
};
|
|
44993
45126
|
}
|
|
44994
|
-
if (
|
|
45127
|
+
if (existsSync31(request.newScriptPath)) {
|
|
44995
45128
|
return { ok: false, reason: `${moveTo} already exists, so the script cannot be moved there.` };
|
|
44996
45129
|
}
|
|
44997
45130
|
}
|
|
@@ -45168,7 +45301,7 @@ async function renameSymbol(request, services) {
|
|
|
45168
45301
|
scripts,
|
|
45169
45302
|
moves: new Map([[declaringPath, moveTo]]),
|
|
45170
45303
|
named: [declaringPath],
|
|
45171
|
-
exists: (path) =>
|
|
45304
|
+
exists: (path) => existsSync31(`${projectPath}/${path.slice("res://".length)}`)
|
|
45172
45305
|
}, plan);
|
|
45173
45306
|
}
|
|
45174
45307
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), symbol, moveTo === null ? [] : [declaringPath]);
|
|
@@ -45443,7 +45576,7 @@ var init_rename_symbol = __esm(() => {
|
|
|
45443
45576
|
|
|
45444
45577
|
// src/file-move.ts
|
|
45445
45578
|
import {
|
|
45446
|
-
existsSync as
|
|
45579
|
+
existsSync as existsSync32,
|
|
45447
45580
|
mkdirSync as mkdirSync18,
|
|
45448
45581
|
readdirSync as readdirSync18,
|
|
45449
45582
|
readFileSync as readFileSync36,
|
|
@@ -45476,7 +45609,7 @@ function unseenByTheEngine(projectPath, path) {
|
|
|
45476
45609
|
}
|
|
45477
45610
|
if (at < steps.length - 1) {
|
|
45478
45611
|
directory = join38(directory, step);
|
|
45479
|
-
if (
|
|
45612
|
+
if (existsSync32(join38(directory, ".gdignore"))) {
|
|
45480
45613
|
return `${path} is under a directory holding a .gdignore, which the engine does not load`;
|
|
45481
45614
|
}
|
|
45482
45615
|
}
|
|
@@ -45488,12 +45621,12 @@ function installedAddonOf(projectPath, path) {
|
|
|
45488
45621
|
if (steps[0] !== "addons" || steps[1] === undefined) {
|
|
45489
45622
|
return null;
|
|
45490
45623
|
}
|
|
45491
|
-
return
|
|
45624
|
+
return existsSync32(join38(projectPath, "addons", steps[1], VERSION_MARKER)) ? `res://addons/${steps[1]}` : null;
|
|
45492
45625
|
}
|
|
45493
45626
|
function binaryResources(projectPath) {
|
|
45494
45627
|
const found = [];
|
|
45495
45628
|
const visit = (directory, prefix) => {
|
|
45496
|
-
if (
|
|
45629
|
+
if (existsSync32(join38(directory, ".gdignore"))) {
|
|
45497
45630
|
return;
|
|
45498
45631
|
}
|
|
45499
45632
|
for (const entry of readdirSync18(directory, { withFileTypes: true })) {
|
|
@@ -45530,7 +45663,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45530
45663
|
if (to === null) {
|
|
45531
45664
|
return { ok: false, reason: `newPath must be a path inside the project, and ${absoluteTo} is not.` };
|
|
45532
45665
|
}
|
|
45533
|
-
if (!
|
|
45666
|
+
if (!existsSync32(absoluteFrom)) {
|
|
45534
45667
|
return { ok: false, reason: `There is nothing at ${from} to move.` };
|
|
45535
45668
|
}
|
|
45536
45669
|
if (from === to) {
|
|
@@ -45559,7 +45692,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45559
45692
|
if (isDirectory && to.startsWith(`${from}/`)) {
|
|
45560
45693
|
return { ok: false, reason: `${from} cannot be moved into itself.` };
|
|
45561
45694
|
}
|
|
45562
|
-
if (
|
|
45695
|
+
if (existsSync32(absoluteTo) && !sameFile(absoluteFrom, absoluteTo)) {
|
|
45563
45696
|
return { ok: false, reason: `${to} already exists, so nothing was moved there.` };
|
|
45564
45697
|
}
|
|
45565
45698
|
const unseen = unseenByTheEngine(projectPath, to);
|
|
@@ -45567,7 +45700,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45567
45700
|
return { ok: false, reason: `${unseen}, so nothing there could load what was moved.` };
|
|
45568
45701
|
}
|
|
45569
45702
|
if (!isDirectory) {
|
|
45570
|
-
const owner = SIDECARS.map((sidecar) => from.endsWith(sidecar) ? from.slice(0, -sidecar.length) : null).find((path) => path !== null &&
|
|
45703
|
+
const owner = SIDECARS.map((sidecar) => from.endsWith(sidecar) ? from.slice(0, -sidecar.length) : null).find((path) => path !== null && existsSync32(join38(projectPath, path.slice("res://".length))));
|
|
45571
45704
|
if (owner !== undefined && owner !== null) {
|
|
45572
45705
|
return { ok: false, reason: `${from} belongs to ${owner} and moves with it: move ${owner} instead.` };
|
|
45573
45706
|
}
|
|
@@ -45589,7 +45722,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45589
45722
|
} else {
|
|
45590
45723
|
moves.set(from, to);
|
|
45591
45724
|
for (const sidecar of SIDECARS) {
|
|
45592
|
-
if (
|
|
45725
|
+
if (existsSync32(`${absoluteFrom}${sidecar}`)) {
|
|
45593
45726
|
moves.set(`${from}${sidecar}`, `${to}${sidecar}`);
|
|
45594
45727
|
}
|
|
45595
45728
|
}
|
|
@@ -45601,7 +45734,7 @@ function planFileMove(projectPath, absoluteFrom, absoluteTo) {
|
|
|
45601
45734
|
scripts,
|
|
45602
45735
|
moves,
|
|
45603
45736
|
named: [from],
|
|
45604
|
-
exists: (path) =>
|
|
45737
|
+
exists: (path) => existsSync32(join38(projectPath, path.slice("res://".length)))
|
|
45605
45738
|
}, { edits: [], mentions: [] });
|
|
45606
45739
|
plan = mentionIgnored(plan, ignoredTexts(projectPath), null, [from]);
|
|
45607
45740
|
const binaries = [];
|
|
@@ -45672,13 +45805,13 @@ function applyFileMove(outcome) {
|
|
|
45672
45805
|
}
|
|
45673
45806
|
}
|
|
45674
45807
|
for (const file of outcome.moved) {
|
|
45675
|
-
if (!
|
|
45808
|
+
if (!existsSync32(file.absoluteFrom)) {
|
|
45676
45809
|
throw new Error(`${file.from} is gone from disk; nothing was written`);
|
|
45677
45810
|
}
|
|
45678
45811
|
if (file.text !== null && readFileSync36(file.absoluteFrom, "utf8") !== file.text.before) {
|
|
45679
45812
|
throw new Error(`${file.from} changed on disk while the move was being worked out; nothing was written`);
|
|
45680
45813
|
}
|
|
45681
|
-
if (
|
|
45814
|
+
if (existsSync32(file.absoluteTo) && !sameFile(file.absoluteFrom, file.absoluteTo)) {
|
|
45682
45815
|
throw new Error(`${file.to} already exists; nothing was written`);
|
|
45683
45816
|
}
|
|
45684
45817
|
}
|
|
@@ -50404,10 +50537,10 @@ var init_server_instructions = __esm(() => {
|
|
|
50404
50537
|
});
|
|
50405
50538
|
|
|
50406
50539
|
// src/suites-scene.ts
|
|
50407
|
-
import { existsSync as
|
|
50540
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync22, writeFileSync as writeFileSync22 } from "node:fs";
|
|
50408
50541
|
import { join as join42, relative as relative9, sep as sep5 } from "node:path";
|
|
50409
50542
|
function hasSuitesScene(projectPath) {
|
|
50410
|
-
return
|
|
50543
|
+
return existsSync33(join42(projectPath, SUITES_SCENE));
|
|
50411
50544
|
}
|
|
50412
50545
|
function suitesSceneArgs(projectPath, suites) {
|
|
50413
50546
|
const runs = join42(projectPath, ".godot", "gdharness", "suite-scenes");
|
|
@@ -50442,7 +50575,7 @@ var init_suites_scene = __esm(() => {
|
|
|
50442
50575
|
});
|
|
50443
50576
|
|
|
50444
50577
|
// src/test-selection.ts
|
|
50445
|
-
import { existsSync as
|
|
50578
|
+
import { existsSync as existsSync34 } from "node:fs";
|
|
50446
50579
|
import { basename as basename13, join as join43 } from "node:path";
|
|
50447
50580
|
function casesOutOfPath(projectPath, given, tests) {
|
|
50448
50581
|
const entries = Array.isArray(given) ? given : [given];
|
|
@@ -50487,12 +50620,12 @@ function casesIn(scripts, suite) {
|
|
|
50487
50620
|
}
|
|
50488
50621
|
function scriptsWithoutCases(projectPath, asked) {
|
|
50489
50622
|
const scripts = new ProjectScripts(projectPath);
|
|
50490
|
-
return asked.filter((path) => path.endsWith(".gd") &&
|
|
50623
|
+
return asked.filter((path) => path.endsWith(".gd") && existsSync34(join43(projectPath, path.slice("res://".length))) && casesIn(scripts, path).length === 0);
|
|
50491
50624
|
}
|
|
50492
50625
|
function suitesUnder(projectPath, asked) {
|
|
50493
50626
|
const scripts = projectFiles(projectPath, [".gd"]).map((path) => `res://${path}`);
|
|
50494
50627
|
return [
|
|
50495
|
-
...new Set(asked.flatMap((path) => path.endsWith(".gd") ?
|
|
50628
|
+
...new Set(asked.flatMap((path) => path.endsWith(".gd") ? existsSync34(join43(projectPath, path.slice("res://".length))) ? [path] : [] : scripts.filter((script) => script.startsWith(`${path}/`))))
|
|
50496
50629
|
];
|
|
50497
50630
|
}
|
|
50498
50631
|
function selectTests(projectPath, asked, given) {
|
|
@@ -50558,14 +50691,14 @@ import {
|
|
|
50558
50691
|
closeSync as closeSync6,
|
|
50559
50692
|
constants,
|
|
50560
50693
|
copyFileSync as copyFileSync2,
|
|
50561
|
-
existsSync as
|
|
50694
|
+
existsSync as existsSync35,
|
|
50562
50695
|
fstatSync as fstatSync3,
|
|
50563
50696
|
mkdirSync as mkdirSync23,
|
|
50564
50697
|
openSync as openSync7,
|
|
50565
50698
|
readdirSync as readdirSync20,
|
|
50566
50699
|
readFileSync as readFileSync40,
|
|
50567
50700
|
readSync as readSync4,
|
|
50568
|
-
realpathSync as
|
|
50701
|
+
realpathSync as realpathSync7,
|
|
50569
50702
|
rmdirSync as rmdirSync2,
|
|
50570
50703
|
statSync as statSync20,
|
|
50571
50704
|
writeFileSync as writeFileSync23
|
|
@@ -50586,7 +50719,7 @@ function greetingWaitMs() {
|
|
|
50586
50719
|
function pictureToSend(pngPath, jpegPath) {
|
|
50587
50720
|
const png = readFileSync40(pngPath);
|
|
50588
50721
|
const beside = pngPath.replace(/\.png$/, ".jpg");
|
|
50589
|
-
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) &&
|
|
50722
|
+
const jpeg = jpegPath !== undefined && normalize2(jpegPath) === normalize2(beside) && existsSync35(beside) ? readFileSync40(beside) : null;
|
|
50590
50723
|
const sent = jpeg !== null && jpeg.length < png.length ? jpeg : png;
|
|
50591
50724
|
return {
|
|
50592
50725
|
data: sent.toString("base64"),
|
|
@@ -50626,7 +50759,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50626
50759
|
return `${named} ${path} does not end in ${rule.extensions.join(" or ")}, which is what ${what} is.`;
|
|
50627
50760
|
}
|
|
50628
50761
|
const directory = realAsFarAsItExists(dirname25(path));
|
|
50629
|
-
if (!
|
|
50762
|
+
if (!existsSync35(directory)) {
|
|
50630
50763
|
return `${named}'s directory ${dirname25(path)} does not exist; ${what} creates no directories.`;
|
|
50631
50764
|
}
|
|
50632
50765
|
const where = join44(directory, basename14(path));
|
|
@@ -50634,7 +50767,7 @@ function writtenFileRefusal(path, rule) {
|
|
|
50634
50767
|
if (inside !== undefined) {
|
|
50635
50768
|
return `${named} ${path} is inside the project at ${inside}; ${what} is saved outside it, so it never becomes part of the game.`;
|
|
50636
50769
|
}
|
|
50637
|
-
const taken = rule.writes(where).find((file) =>
|
|
50770
|
+
const taken = rule.writes(where).find((file) => existsSync35(file));
|
|
50638
50771
|
if (taken !== undefined) {
|
|
50639
50772
|
return taken === where ? `${named} ${path} already exists; ${what} is not written over a file. Name a new one.` : `${named} ${path} would write ${taken}, which already exists; ${what} is not written over a file. Name a new one.`;
|
|
50640
50773
|
}
|
|
@@ -51420,7 +51553,7 @@ function unsavedInEditorNote(scripts) {
|
|
|
51420
51553
|
return `${named} ${one ? "is" : "are"} open in the editor's script ${one ? "tab" : "tabs"} with unsaved edits, and saving ${one ? "that tab" : "them"} there writes ${one ? "its" : "their"} text over what was written here: close ${one ? "it" : "them"} without saving, or save first and edit again.`;
|
|
51421
51554
|
}
|
|
51422
51555
|
function editorAddonMissing(projectPath) {
|
|
51423
|
-
if (!
|
|
51556
|
+
if (!existsSync35(join44(projectPath, "project.godot"))) {
|
|
51424
51557
|
return null;
|
|
51425
51558
|
}
|
|
51426
51559
|
const report = inspectProject(projectPath);
|
|
@@ -51964,7 +52097,7 @@ function uncaughtNote(uncaught) {
|
|
|
51964
52097
|
}
|
|
51965
52098
|
function elsewhereIn(projectPath, asked) {
|
|
51966
52099
|
const wanted = asked.replace(/^res:\/\//, "").replace(/\/+$/, "");
|
|
51967
|
-
if (wanted === "" ||
|
|
52100
|
+
if (wanted === "" || existsSync35(join44(projectPath, wanted))) {
|
|
51968
52101
|
return "";
|
|
51969
52102
|
}
|
|
51970
52103
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
@@ -51987,7 +52120,7 @@ function windowNoteFor(needing, sharing) {
|
|
|
51987
52120
|
return `${named(needing)} ${one ? "needs" : "need"} a window, as gdharness test reads ${one ? "it" : "them"}, so the run had one: the engine ran without --headless, at the size project.godot gives its viewport, with no sound${process.platform === "win32" ? ", on a desktop of its own, where its window neither shows nor takes the keyboard" : ""}. ${why}${shared}`;
|
|
51988
52121
|
}
|
|
51989
52122
|
function testPathsIn(projectPath, given, named = "path") {
|
|
51990
|
-
const defaults = TEST_DIRECTORIES.filter((directory) =>
|
|
52123
|
+
const defaults = TEST_DIRECTORIES.filter((directory) => existsSync35(join44(projectPath, directory)));
|
|
51991
52124
|
const entries = given === undefined || given === null || given === "" ? defaults.length > 0 ? defaults : TEST_DIRECTORIES : given;
|
|
51992
52125
|
const listed = Array.isArray(entries) ? entries : [entries];
|
|
51993
52126
|
if (listed.length === 0) {
|
|
@@ -52412,7 +52545,7 @@ class GodotServer {
|
|
|
52412
52545
|
argv: process.argv.slice(1),
|
|
52413
52546
|
cwd,
|
|
52414
52547
|
project: this.ownProject,
|
|
52415
|
-
mcpJson:
|
|
52548
|
+
mcpJson: existsSync35(mcpJson) ? mcpJson : null
|
|
52416
52549
|
});
|
|
52417
52550
|
if (predecessor !== null) {
|
|
52418
52551
|
writeLifecycle("replaced", { project: this.ownProject, predecessor });
|
|
@@ -52554,7 +52687,7 @@ class GodotServer {
|
|
|
52554
52687
|
return checked.response;
|
|
52555
52688
|
}
|
|
52556
52689
|
const named = args["projectPath"];
|
|
52557
|
-
if (typeof named === "string" &&
|
|
52690
|
+
if (typeof named === "string" && existsSync35(join44(named, "project.godot"))) {
|
|
52558
52691
|
this.lastProjectPath = named;
|
|
52559
52692
|
}
|
|
52560
52693
|
this.updates.refresh();
|
|
@@ -53190,7 +53323,7 @@ class GodotServer {
|
|
|
53190
53323
|
return this.createErrorResponse("line is required: the one-based line to stop on.");
|
|
53191
53324
|
}
|
|
53192
53325
|
if (op === "set") {
|
|
53193
|
-
if (!
|
|
53326
|
+
if (!existsSync35(located.absolutePath)) {
|
|
53194
53327
|
return this.missingScript(project.value.path, located.relativePath);
|
|
53195
53328
|
}
|
|
53196
53329
|
const nothing = lineNothingStopsOn(located.absolutePath, located.relativePath, line);
|
|
@@ -53295,7 +53428,7 @@ class GodotServer {
|
|
|
53295
53428
|
return { ok: false, response: this.createErrorResponse("projectPath is required.") };
|
|
53296
53429
|
}
|
|
53297
53430
|
const file = join44(path, "project.godot");
|
|
53298
|
-
if (!
|
|
53431
|
+
if (!existsSync35(file)) {
|
|
53299
53432
|
return {
|
|
53300
53433
|
ok: false,
|
|
53301
53434
|
response: this.createErrorResponse(`Not a Godot project: ${path}`, [
|
|
@@ -54121,11 +54254,11 @@ class GodotServer {
|
|
|
54121
54254
|
if (place !== null && !place.ok) {
|
|
54122
54255
|
return this.createErrorResponse(place.reason);
|
|
54123
54256
|
}
|
|
54124
|
-
if (place !== null && !
|
|
54257
|
+
if (place !== null && !existsSync35(place.absolutePath)) {
|
|
54125
54258
|
const folders = readdirSync20(project.value.path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort();
|
|
54126
54259
|
return this.createErrorResponse(`There is nothing at res://${place.relativePath} to search.${folders.length === 0 ? "" : ` The project's folders are ${folders.join(", ")}.`}`);
|
|
54127
54260
|
}
|
|
54128
|
-
if (place !== null && !isWithinRoot(
|
|
54261
|
+
if (place !== null && !isWithinRoot(realpathSync7.native(project.value.path), realpathSync7.native(place.absolutePath))) {
|
|
54129
54262
|
return this.createErrorResponse(`res://${place.relativePath} leads outside the project through a link, so it is not searched.`);
|
|
54130
54263
|
}
|
|
54131
54264
|
try {
|
|
@@ -54312,7 +54445,7 @@ ${platform}`;
|
|
|
54312
54445
|
output.absolutePath
|
|
54313
54446
|
];
|
|
54314
54447
|
this.logDebug(`Exporting: ${engine.value} ${exportArgs.join(" ")}`);
|
|
54315
|
-
const writtenAt = () =>
|
|
54448
|
+
const writtenAt = () => existsSync35(output.absolutePath) ? statSync20(output.absolutePath).mtimeMs : null;
|
|
54316
54449
|
const caches = editorCacheDirectory(engine.value);
|
|
54317
54450
|
const exportOnce = async () => {
|
|
54318
54451
|
const before = writtenAt();
|
|
@@ -54342,7 +54475,7 @@ ${platform}`;
|
|
|
54342
54475
|
return this.createErrorResponse(`Export could not be run: ${ending.failure ?? "the engine gave no exit status"}`);
|
|
54343
54476
|
}
|
|
54344
54477
|
const beside = writtenBeside(listedBefore, filesIn(folder), basename14(output.absolutePath), dirname25(output.relativePath).replaceAll("\\", "/"));
|
|
54345
|
-
return exportAnswer(ending, { preset, outputPath: output.relativePath, debug, ...pack ? { pack } : {} }, before, writtenAt(), beside, docCacheNote,
|
|
54478
|
+
return exportAnswer(ending, { preset, outputPath: output.relativePath, debug, ...pack ? { pack } : {} }, before, writtenAt(), beside, docCacheNote, existsSync35(output.absolutePath) ? statSync20(output.absolutePath).size : null, importedFirstAnswer(imported));
|
|
54346
54479
|
}
|
|
54347
54480
|
reportTestProgress(log) {
|
|
54348
54481
|
const progress = callProgress();
|
|
@@ -54403,7 +54536,7 @@ ${platform}`;
|
|
|
54403
54536
|
if (movie !== null) {
|
|
54404
54537
|
return this.createErrorResponse(movie);
|
|
54405
54538
|
}
|
|
54406
|
-
const missing = paths.value.filter((path) => !
|
|
54539
|
+
const missing = paths.value.filter((path) => !existsSync35(join44(project.value.path, path.slice("res://".length))));
|
|
54407
54540
|
const projectScripts = new ProjectScripts(project.value.path);
|
|
54408
54541
|
const present = paths.value.filter((path) => !missing.includes(path));
|
|
54409
54542
|
const asked = projectScripts.searchedAsTold(present);
|
|
@@ -54595,7 +54728,7 @@ ${platform}`;
|
|
|
54595
54728
|
await untilGone([run.process.pid]);
|
|
54596
54729
|
}
|
|
54597
54730
|
await run.settled;
|
|
54598
|
-
const helperFailed = onDesktop ? helperFailure(helperFiles.error) ?? (
|
|
54731
|
+
const helperFailed = onDesktop ? helperFailure(helperFiles.error) ?? (existsSync35(helperFiles.pid) ? null : `it never started, and ${helperStep(helperFiles.step)}`) : null;
|
|
54599
54732
|
if (helperFailed !== null) {
|
|
54600
54733
|
discard(join44(project.value.path, ".godot", ...ours.split("/")), userData);
|
|
54601
54734
|
return this.createErrorResponse(`No tests ran: ${named(needing)} ${needing.length === 1 ? "needs" : "need"} a window, and the engine could not be started on a desktop of its own: ${helperFailed}`);
|
|
@@ -54611,10 +54744,10 @@ ${platform}`;
|
|
|
54611
54744
|
const reportsDir = join44(project.value.path, ".godot", ...ours.split("/"));
|
|
54612
54745
|
let report = null;
|
|
54613
54746
|
let reportProblem = null;
|
|
54614
|
-
const casePrinted = withNestedErrors(readRun(
|
|
54747
|
+
const casePrinted = withNestedErrors(readRun(existsSync35(engineLog) ? readFileSync40(engineLog, "utf8") : ""), run.log.all);
|
|
54615
54748
|
const declaredErrors = readExpected(expectedFile);
|
|
54616
54749
|
try {
|
|
54617
|
-
const written =
|
|
54750
|
+
const written = existsSync35(reportsDir) && notCompiled === null ? readdirSync20(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
54618
54751
|
const newest = written.at(-1);
|
|
54619
54752
|
if (newest !== undefined) {
|
|
54620
54753
|
report = parseJUnit(readFileSync40(join44(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -54941,7 +55074,7 @@ ${error.text}`;
|
|
|
54941
55074
|
if (!location.ok) {
|
|
54942
55075
|
return this.createErrorResponse(location.reason, PATH_SOLUTIONS);
|
|
54943
55076
|
}
|
|
54944
|
-
if (!
|
|
55077
|
+
if (!existsSync35(location.absolutePath)) {
|
|
54945
55078
|
return this.missingScript(project.value.path, location.relativePath);
|
|
54946
55079
|
}
|
|
54947
55080
|
ignored = scriptsUnderGdignore(project.value.path, [location.relativePath]);
|
|
@@ -55031,7 +55164,7 @@ ${error.text}`;
|
|
|
55031
55164
|
const wanted = `res://${relativePath}`;
|
|
55032
55165
|
const folder = dirname25(relativePath.replaceAll("\\", "/"));
|
|
55033
55166
|
const inFolder = join44(projectPath, folder);
|
|
55034
|
-
const beside =
|
|
55167
|
+
const beside = existsSync35(inFolder) ? readdirSync20(inFolder, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => `res://${folder === "." ? "" : `${folder}/`}${entry.name}`) : [];
|
|
55035
55168
|
return this.createErrorResponse(withNearestFiles(`Script file does not exist: ${wanted}`, wanted, scripts, beside));
|
|
55036
55169
|
}
|
|
55037
55170
|
async compileScripts(projectPath, paths) {
|
|
@@ -55159,7 +55292,7 @@ ${error.text}`;
|
|
|
55159
55292
|
const cached = cachedClasses(projectPath);
|
|
55160
55293
|
const sourceOf = (resourcePath) => {
|
|
55161
55294
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
55162
|
-
if (!contained.ok || !
|
|
55295
|
+
if (!contained.ok || !existsSync35(contained.absolutePath)) {
|
|
55163
55296
|
return null;
|
|
55164
55297
|
}
|
|
55165
55298
|
try {
|
|
@@ -55253,7 +55386,7 @@ ${error.text}`;
|
|
|
55253
55386
|
}
|
|
55254
55387
|
sourceOfClass(projectPath, resourcePath) {
|
|
55255
55388
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
55256
|
-
if (!contained.ok || !
|
|
55389
|
+
if (!contained.ok || !existsSync35(contained.absolutePath)) {
|
|
55257
55390
|
return null;
|
|
55258
55391
|
}
|
|
55259
55392
|
try {
|
|
@@ -55687,7 +55820,7 @@ ${error.text}`;
|
|
|
55687
55820
|
run,
|
|
55688
55821
|
playingInEditor: playing,
|
|
55689
55822
|
...hold,
|
|
55690
|
-
runtimeConnected: games.some((game) => game.reachable && game.ofThisProject !== false),
|
|
55823
|
+
runtimeConnected: games.some((game) => game.reachable && game.ofThisProject !== false && game.addonIsStale !== true),
|
|
55691
55824
|
runtimes: games,
|
|
55692
55825
|
unreadable: announced.unspoken.map((game) => ({
|
|
55693
55826
|
pid: game.pid,
|
|
@@ -56121,7 +56254,7 @@ ${error.text}`;
|
|
|
56121
56254
|
if (!paths.ok) {
|
|
56122
56255
|
return refused(paths.reason, PATH_SOLUTIONS);
|
|
56123
56256
|
}
|
|
56124
|
-
const missing = paths.value.filter((path) => !
|
|
56257
|
+
const missing = paths.value.filter((path) => !existsSync35(join44(projectPath, path.slice("res://".length))));
|
|
56125
56258
|
if (missing.length > 0) {
|
|
56126
56259
|
return refused(`Nothing at ${missing.join(" and ")} in the project at ${projectPath}.`, PATH_SOLUTIONS);
|
|
56127
56260
|
}
|
|
@@ -56166,7 +56299,7 @@ ${error.text}`;
|
|
|
56166
56299
|
return this.createErrorResponse(sceneToRun.reason, PATH_SOLUTIONS);
|
|
56167
56300
|
}
|
|
56168
56301
|
const build = readNonEmptyString(args, "executable");
|
|
56169
|
-
if (build === undefined && sceneToRun?.ok && !
|
|
56302
|
+
if (build === undefined && sceneToRun?.ok && !existsSync35(sceneToRun.absolutePath)) {
|
|
56170
56303
|
return this.createErrorResponse(`No scene at res://${sceneToRun.relativePath} in the project at ${project.value.path}.`, PATH_SOLUTIONS);
|
|
56171
56304
|
}
|
|
56172
56305
|
const exported = build === undefined ? null : exportedBuild(project.value.path, build);
|
|
@@ -56294,7 +56427,7 @@ ${error.text}`;
|
|
|
56294
56427
|
}
|
|
56295
56428
|
async runtimeUp(projectPath, before, budget, withArgs) {
|
|
56296
56429
|
const budgetMs = budget.ms;
|
|
56297
|
-
if (!
|
|
56430
|
+
if (!existsSync35(join44(projectPath, RUNTIME_SCRIPT))) {
|
|
56298
56431
|
return runtimeVerdict(null, {
|
|
56299
56432
|
addon: false,
|
|
56300
56433
|
budgetMs,
|
|
@@ -57370,7 +57503,7 @@ ${error.text}`;
|
|
|
57370
57503
|
};
|
|
57371
57504
|
const going = await this.runStillGoing(run);
|
|
57372
57505
|
const projectPath = run.projectPath;
|
|
57373
|
-
const projectGone = projectPath !== null && !
|
|
57506
|
+
const projectGone = projectPath !== null && !existsSync35(join44(projectPath, "project.godot"));
|
|
57374
57507
|
if (projectGone && callersName !== undefined) {
|
|
57375
57508
|
return this.createErrorResponse(`callersOf reads the project's scripts, and the run's project at ${projectPath} has no project.godot any more.`, ["editor_run profile without callersOf answers with the profile itself"]);
|
|
57376
57509
|
}
|
|
@@ -57777,7 +57910,7 @@ ${error.text}`;
|
|
|
57777
57910
|
notes.push(endedWithoutACode({
|
|
57778
57911
|
throughEditor: run.throughEditor,
|
|
57779
57912
|
announced: announced !== undefined || run.announcedPid !== undefined,
|
|
57780
|
-
couldAnnounce: run.projectPath !== null &&
|
|
57913
|
+
couldAnnounce: run.projectPath !== null && existsSync35(join44(run.projectPath, RUNTIME_SCRIPT)),
|
|
57781
57914
|
endedHere: typeof run.endedHere === "string",
|
|
57782
57915
|
pickedUp: run.pickedUp === true
|
|
57783
57916
|
}));
|
|
@@ -58573,11 +58706,18 @@ ${error.text}`;
|
|
|
58573
58706
|
return this.answer(created);
|
|
58574
58707
|
}
|
|
58575
58708
|
const rebuilt = await this.rebuildClassCache(project.value.path);
|
|
58576
|
-
const
|
|
58709
|
+
const fullPath = readString(created.payload, "full_path");
|
|
58710
|
+
const registered = cachedClasses(project.value.path)?.get(declared) === fullPath;
|
|
58711
|
+
const recompiled = registered && created.payload["parses"] === false && fullPath !== undefined ? await this.compileScripts(project.value.path, [fullPath]) : null;
|
|
58712
|
+
const parsesOnTheList = recompiled?.ok === true && recompiled.payload.failed.length === 0;
|
|
58577
58713
|
const answered = this.answer({
|
|
58578
58714
|
...created,
|
|
58579
58715
|
payload: {
|
|
58580
58716
|
...created.payload,
|
|
58717
|
+
...parsesOnTheList ? {
|
|
58718
|
+
parses: true,
|
|
58719
|
+
parsesNote: `The engine that wrote it compiled it against the class list from before, which did not hold ${declared}, so the errors it printed naming ${declared} are its own and not the script's. An engine started on the rebuilt list compiles it.`
|
|
58720
|
+
} : {},
|
|
58581
58721
|
registered,
|
|
58582
58722
|
...registered ? {} : {
|
|
58583
58723
|
registrationNote: rebuilt.ok ? `The class list was rebuilt and does not hold ${declared} at this script, so nothing started next resolves it by name. project_import refresh_classes says what the list holds and why.` : `The class list could not be rebuilt, so nothing started next resolves ${declared} by name: ${rebuilt.message}`
|
|
@@ -58659,7 +58799,7 @@ ${error.text}`;
|
|
|
58659
58799
|
if (!scriptPath.ok) {
|
|
58660
58800
|
return this.createErrorResponse(scriptPath.reason);
|
|
58661
58801
|
}
|
|
58662
|
-
if (!
|
|
58802
|
+
if (!existsSync35(scriptPath.absolutePath)) {
|
|
58663
58803
|
return this.missingScript(projectPath, scriptPath.relativePath);
|
|
58664
58804
|
}
|
|
58665
58805
|
const asked = readNonEmptyString(args, "newScriptPath");
|
|
@@ -59303,7 +59443,7 @@ ${error.text}`;
|
|
|
59303
59443
|
async ownRunOnItsWay(projectPath, budgetMs) {
|
|
59304
59444
|
const run = await this.currentRun();
|
|
59305
59445
|
const project = projectPath ?? run?.projectPath ?? null;
|
|
59306
|
-
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !
|
|
59446
|
+
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync35(join44(project, RUNTIME_SCRIPT)) || !await this.runStillGoing(run)) {
|
|
59307
59447
|
return null;
|
|
59308
59448
|
}
|
|
59309
59449
|
const already = runtimesAnnounced().running;
|
|
@@ -59756,7 +59896,7 @@ var init_server = __esm(() => {
|
|
|
59756
59896
|
init_bridge_announce();
|
|
59757
59897
|
init_engine_launch();
|
|
59758
59898
|
init_engine_slots();
|
|
59759
|
-
import { existsSync as
|
|
59899
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
59760
59900
|
import { dirname as dirname26, join as join45, resolve as resolve15 } from "node:path";
|
|
59761
59901
|
|
|
59762
59902
|
// src/error-mode.ts
|
|
@@ -59795,7 +59935,7 @@ init_alive();
|
|
|
59795
59935
|
init_engine_launch();
|
|
59796
59936
|
init_lsp_client();
|
|
59797
59937
|
init_process_children();
|
|
59798
|
-
import { existsSync as
|
|
59938
|
+
import { existsSync as existsSync18, readdirSync as readdirSync11, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "node:fs";
|
|
59799
59939
|
import { connect as connect2 } from "node:net";
|
|
59800
59940
|
import { join as join21, resolve as resolve8 } from "node:path";
|
|
59801
59941
|
var EDITOR_RECORD_PROTOCOL = 1;
|
|
@@ -59907,7 +60047,7 @@ function lspOptionsOf(args, cwd) {
|
|
|
59907
60047
|
}
|
|
59908
60048
|
}
|
|
59909
60049
|
const projectPath = resolve8(cwd, named ?? ".");
|
|
59910
|
-
if (!
|
|
60050
|
+
if (!existsSync18(join21(projectPath, "project.godot"))) {
|
|
59911
60051
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
59912
60052
|
}
|
|
59913
60053
|
return { projectPath, port, waitSeconds };
|
|
@@ -60014,7 +60154,7 @@ init_setup();
|
|
|
60014
60154
|
init_setup();
|
|
60015
60155
|
init_tool_definitions();
|
|
60016
60156
|
init_tool_reference();
|
|
60017
|
-
import { existsSync as
|
|
60157
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync7, readdirSync as readdirSync13, rmSync as rmSync11, writeFileSync as writeFileSync12 } from "node:fs";
|
|
60018
60158
|
import { basename as basename9, dirname as dirname10, join as join23 } from "node:path";
|
|
60019
60159
|
var SKILL_NAME = "gdharness";
|
|
60020
60160
|
var SHARED_SKILLS = join23(".agents", "skills");
|
|
@@ -60286,7 +60426,7 @@ function everySkillDirectory(projectPath, harnesses) {
|
|
|
60286
60426
|
function removeSkill(directories, projectPath) {
|
|
60287
60427
|
const removed = [];
|
|
60288
60428
|
for (const directory of directories) {
|
|
60289
|
-
if (
|
|
60429
|
+
if (existsSync20(directory)) {
|
|
60290
60430
|
rmSync11(directory, { recursive: true, force: true });
|
|
60291
60431
|
pruneEmpty(dirname10(directory), projectPath);
|
|
60292
60432
|
removed.push(directory);
|
|
@@ -60308,7 +60448,7 @@ function pruneEmpty(directory, projectPath) {
|
|
|
60308
60448
|
function writeSkill(directories, version) {
|
|
60309
60449
|
const files = skillFiles(version);
|
|
60310
60450
|
return directories.map((directory) => {
|
|
60311
|
-
const replaced =
|
|
60451
|
+
const replaced = existsSync20(directory);
|
|
60312
60452
|
rmSync11(directory, { recursive: true, force: true });
|
|
60313
60453
|
for (const [name, contents] of files) {
|
|
60314
60454
|
const path = join23(directory, name);
|
|
@@ -60325,7 +60465,7 @@ init_engine_slots();
|
|
|
60325
60465
|
init_log_read();
|
|
60326
60466
|
init_setup();
|
|
60327
60467
|
init_suite_judge();
|
|
60328
|
-
import { existsSync as
|
|
60468
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync8, readFileSync as readFileSync22, rmSync as rmSync12 } from "node:fs";
|
|
60329
60469
|
import { availableParallelism as availableParallelism4 } from "node:os";
|
|
60330
60470
|
import { join as join24, resolve as resolve10 } from "node:path";
|
|
60331
60471
|
import process13 from "node:process";
|
|
@@ -60367,9 +60507,9 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60367
60507
|
}
|
|
60368
60508
|
const first = positional[0];
|
|
60369
60509
|
const named = first === undefined ? null : resolve10(cwd, first);
|
|
60370
|
-
const projectNamed = named !== null &&
|
|
60510
|
+
const projectNamed = named !== null && existsSync21(join24(named, "project.godot"));
|
|
60371
60511
|
const projectPath = projectNamed ? named : resolve10(cwd);
|
|
60372
|
-
if (!
|
|
60512
|
+
if (!existsSync21(join24(projectPath, "project.godot"))) {
|
|
60373
60513
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
60374
60514
|
}
|
|
60375
60515
|
const scenes = positional.slice(projectNamed ? 1 : 0);
|
|
@@ -60377,7 +60517,7 @@ function spreadOptionsOf(args, cwd) {
|
|
|
60377
60517
|
throw new EngineUsageError(scenes.length === 0 ? "gdharness spread needs the scene of the bench to play." : `gdharness spread plays one scene, and was given ${String(scenes.length)}: ${scenes.join(", ")}.`);
|
|
60378
60518
|
}
|
|
60379
60519
|
const scene = resPathOf(scenes[0] ?? "", projectPath, cwd);
|
|
60380
|
-
if (!
|
|
60520
|
+
if (!existsSync21(join24(projectPath, scene.slice("res://".length)))) {
|
|
60381
60521
|
throw new EngineUsageError(`Nothing at ${scene} in the project at ${projectPath}.`);
|
|
60382
60522
|
}
|
|
60383
60523
|
const benchArguments = dashes === -1 ? [] : args.slice(dashes + 1);
|
|
@@ -60448,7 +60588,7 @@ function shareFaults(played) {
|
|
|
60448
60588
|
return faults;
|
|
60449
60589
|
}
|
|
60450
60590
|
async function runSpreadCommand(options, godotPath) {
|
|
60451
|
-
if (!
|
|
60591
|
+
if (!existsSync21(join24(options.projectPath, SHARE_SCRIPT))) {
|
|
60452
60592
|
throw new EngineUsageError(`res://${SHARE_SCRIPT} is not in the project, so its bench cannot ask GdhShare for outcomes. Run gdharness setup.`);
|
|
60453
60593
|
}
|
|
60454
60594
|
const startedAt = Date.now();
|
|
@@ -60513,7 +60653,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60513
60653
|
const faults = left.flatMap((worker) => engineFaults(worker, options.godotVersion));
|
|
60514
60654
|
const arms = left.map((_, index) => {
|
|
60515
60655
|
const file = join24(shareDirectory, `worker-${String(index)}.arms`);
|
|
60516
|
-
return
|
|
60656
|
+
return existsSync21(file) ? armsPlayed(readFileSync22(file, "utf8")) : [];
|
|
60517
60657
|
});
|
|
60518
60658
|
faults.push(...shareFaults(arms));
|
|
60519
60659
|
if (faults.length > 0) {
|
|
@@ -60523,7 +60663,7 @@ async function runSpreadCommand(options, godotPath) {
|
|
|
60523
60663
|
console.log(readLog(gather.log).replace(CONTROL_SEQUENCE, "").trimEnd());
|
|
60524
60664
|
const gatherFaults = engineFaults(gather, options.godotVersion);
|
|
60525
60665
|
const gatheredFile = join24(shareDirectory, "gathered.arms");
|
|
60526
|
-
const gathered = new Set((
|
|
60666
|
+
const gathered = new Set((existsSync21(gatheredFile) ? armsPlayed(readFileSync22(gatheredFile, "utf8")) ?? [] : []).map((arm) => arm.arm));
|
|
60527
60667
|
const ungathered = (arms[0] ?? []).filter((arm) => !gathered.has(arm.arm)).map((arm) => arm.arm);
|
|
60528
60668
|
if (ungathered.length > 0) {
|
|
60529
60669
|
gatherFaults.push(`the gathering run never asked for ${ungathered.join(", ")}, which the workers played: it went another way through the arms than they did`);
|
|
@@ -60574,7 +60714,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60574
60714
|
const said = code === null ? "without an exit code" : code >>> 0 >= WINDOWS_EXCEPTION2 ? exitNamed(code) : String(code);
|
|
60575
60715
|
faults.push(`${engine.name}: the engine exited ${said}`);
|
|
60576
60716
|
}
|
|
60577
|
-
if (!
|
|
60717
|
+
if (!existsSync21(engine.log)) {
|
|
60578
60718
|
return faults;
|
|
60579
60719
|
}
|
|
60580
60720
|
const printed = readRun(readLog(engine.log));
|
|
@@ -60590,7 +60730,7 @@ function engineFaults(engine, godotVersion) {
|
|
|
60590
60730
|
}
|
|
60591
60731
|
function progressOf(logs) {
|
|
60592
60732
|
const each = logs.map((log, index) => {
|
|
60593
|
-
const text =
|
|
60733
|
+
const text = existsSync21(log) ? readLog(log) : "";
|
|
60594
60734
|
const last = [...text.matchAll(PROGRESS)].at(-1);
|
|
60595
60735
|
return last === undefined ? `worker ${String(index)} has played no arm yet` : `worker ${String(index)} at ${last[1] ?? ""} ${last[2] ?? ""} of ${last[3] ?? ""}`;
|
|
60596
60736
|
});
|
|
@@ -60622,10 +60762,11 @@ init_reimport();
|
|
|
60622
60762
|
init_setup();
|
|
60623
60763
|
import {
|
|
60624
60764
|
copyFileSync,
|
|
60625
|
-
existsSync as
|
|
60765
|
+
existsSync as existsSync24,
|
|
60626
60766
|
mkdirSync as mkdirSync10,
|
|
60627
60767
|
readdirSync as readdirSync15,
|
|
60628
60768
|
readFileSync as readFileSync26,
|
|
60769
|
+
realpathSync as realpathSync5,
|
|
60629
60770
|
rmSync as rmSync13,
|
|
60630
60771
|
statSync as statSync14,
|
|
60631
60772
|
writeFileSync as writeFileSync13
|
|
@@ -60639,7 +60780,7 @@ import { setTimeout as delay5 } from "node:timers/promises";
|
|
|
60639
60780
|
init_class_cache();
|
|
60640
60781
|
init_gdscript_source();
|
|
60641
60782
|
import { createHash as createHash6 } from "node:crypto";
|
|
60642
|
-
import { existsSync as
|
|
60783
|
+
import { existsSync as existsSync22, readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync13 } from "node:fs";
|
|
60643
60784
|
import { join as join25, posix as posix2 } from "node:path";
|
|
60644
60785
|
var EVERY_FILE = "res://";
|
|
60645
60786
|
var CACHE_HELD = "cache:";
|
|
@@ -60657,7 +60798,7 @@ var ADDON = /^res:\/\/addons\/[^/]+\//;
|
|
|
60657
60798
|
var TEXT_RESOURCE = /\.(?:tscn|tres|gdextension)$/;
|
|
60658
60799
|
function reachedBySuite(file) {
|
|
60659
60800
|
const bySuite = new Map;
|
|
60660
|
-
if (!
|
|
60801
|
+
if (!existsSync22(file)) {
|
|
60661
60802
|
return bySuite;
|
|
60662
60803
|
}
|
|
60663
60804
|
const paths = (value) => Array.isArray(value) ? value.filter((path) => typeof path === "string") : [];
|
|
@@ -60767,7 +60908,7 @@ ${this.read(path).digest}
|
|
|
60767
60908
|
const hash = createHash6("sha256");
|
|
60768
60909
|
let modified = 0;
|
|
60769
60910
|
const directory = join25(this.scripts.projectPath, root.slice("res://".length));
|
|
60770
|
-
if (
|
|
60911
|
+
if (existsSync22(directory)) {
|
|
60771
60912
|
walkSeen(directory, (file, under, stat) => {
|
|
60772
60913
|
hash.update(`${under}
|
|
60773
60914
|
`).update(readFileSync23(file));
|
|
@@ -60778,7 +60919,7 @@ ${this.read(path).digest}
|
|
|
60778
60919
|
}
|
|
60779
60920
|
readAnew(path) {
|
|
60780
60921
|
const file = join25(this.scripts.projectPath, path.slice("res://".length));
|
|
60781
|
-
if (!
|
|
60922
|
+
if (!existsSync22(file)) {
|
|
60782
60923
|
return { digest: "missing", follows: [], also: [], modified: 0 };
|
|
60783
60924
|
}
|
|
60784
60925
|
const stat = statSync13(file);
|
|
@@ -60789,12 +60930,12 @@ ${this.read(path).digest}
|
|
|
60789
60930
|
}
|
|
60790
60931
|
const bytes = readFileSync23(file);
|
|
60791
60932
|
const digest = createHash6("sha256").update(bytes).digest("hex");
|
|
60792
|
-
const also = [`${path}.import`, `${path}.uid`].filter((beside) =>
|
|
60933
|
+
const also = [`${path}.import`, `${path}.uid`].filter((beside) => existsSync22(join25(this.scripts.projectPath, beside.slice("res://".length))));
|
|
60793
60934
|
const follows = [];
|
|
60794
60935
|
if (TEXT_RESOURCE.test(path)) {
|
|
60795
60936
|
for (const [named] of bytes.toString("latin1").matchAll(RES_LITERAL)) {
|
|
60796
60937
|
const target = join25(this.scripts.projectPath, named.slice("res://".length));
|
|
60797
|
-
(
|
|
60938
|
+
(existsSync22(target) && statSync13(target).isDirectory() ? also : follows).push(named);
|
|
60798
60939
|
}
|
|
60799
60940
|
} else if (path.endsWith(".gd")) {
|
|
60800
60941
|
const reaches = this.scriptReaches(path);
|
|
@@ -60981,7 +61122,7 @@ function joinedString(expression, named) {
|
|
|
60981
61122
|
}
|
|
60982
61123
|
function walkSeen(root, seen) {
|
|
60983
61124
|
const walk = (directory, under) => {
|
|
60984
|
-
if (
|
|
61125
|
+
if (existsSync22(join25(directory, ".gdignore"))) {
|
|
60985
61126
|
return;
|
|
60986
61127
|
}
|
|
60987
61128
|
for (const entry of readdirSync14(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -60999,7 +61140,7 @@ function walkSeen(root, seen) {
|
|
|
60999
61140
|
}
|
|
61000
61141
|
function extensionsOf(projectPath) {
|
|
61001
61142
|
const list = join25(projectPath, ".godot", "extension_list.cfg");
|
|
61002
|
-
return
|
|
61143
|
+
return existsSync22(list) ? readFileSync23(list, "utf8").split(`
|
|
61003
61144
|
`).map((line) => line.trim()).filter((line) => line.startsWith("res://")) : [];
|
|
61004
61145
|
}
|
|
61005
61146
|
|
|
@@ -61088,9 +61229,9 @@ function testOptionsOf(args, cwd) {
|
|
|
61088
61229
|
}
|
|
61089
61230
|
const first = positional[0];
|
|
61090
61231
|
const named = first === undefined ? null : resolve11(cwd, first);
|
|
61091
|
-
const projectNamed = named !== null &&
|
|
61232
|
+
const projectNamed = named !== null && existsSync24(join28(named, "project.godot"));
|
|
61092
61233
|
const projectPath = projectNamed ? named : resolve11(cwd);
|
|
61093
|
-
if (!
|
|
61234
|
+
if (!existsSync24(join28(projectPath, "project.godot"))) {
|
|
61094
61235
|
throw new EngineUsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
61095
61236
|
}
|
|
61096
61237
|
const last = (flag) => valued.get(flag)?.at(-1);
|
|
@@ -61125,12 +61266,12 @@ function seedOf(value) {
|
|
|
61125
61266
|
return seed;
|
|
61126
61267
|
}
|
|
61127
61268
|
function rootsOf(options) {
|
|
61128
|
-
return options.roots.length > 0 ? options.roots : TEST_DIRECTORIES.filter((root) =>
|
|
61269
|
+
return options.roots.length > 0 ? options.roots : TEST_DIRECTORIES.filter((root) => existsSync24(join28(options.projectPath, root))).map((root) => `res://${root}`);
|
|
61129
61270
|
}
|
|
61130
61271
|
function searchedRoots(options) {
|
|
61131
61272
|
return options.selected.length === 0 ? rootsOf(options) : options.selected.filter((entry) => {
|
|
61132
61273
|
const directory = join28(options.projectPath, entry.slice("res://".length));
|
|
61133
|
-
return
|
|
61274
|
+
return existsSync24(directory) && statSync14(directory).isDirectory();
|
|
61134
61275
|
});
|
|
61135
61276
|
}
|
|
61136
61277
|
function selectedSuites(scripts, options) {
|
|
@@ -61147,9 +61288,9 @@ function selectedSuites(scripts, options) {
|
|
|
61147
61288
|
const caseAt = /^(res:\/\/.*\.gd):(\w+)$/.exec(entry);
|
|
61148
61289
|
const path = caseAt?.[1] ?? entry;
|
|
61149
61290
|
const directory = join28(options.projectPath, path.slice(6));
|
|
61150
|
-
const suites =
|
|
61291
|
+
const suites = existsSync24(directory) && statSync14(directory).isDirectory() ? scripts.suitesUnder([path.replace(/\/$/, "")]) : [scripts.suite(path)].filter((suite) => suite !== null);
|
|
61151
61292
|
if (suites.length === 0) {
|
|
61152
|
-
throw new EngineUsageError(
|
|
61293
|
+
throw new EngineUsageError(existsSync24(directory) ? `${path} holds no gdUnit4 suite: nothing there extends GdUnitTestSuite and declares a test_ function.` : `Nothing at ${path} in the project at ${options.projectPath}.`);
|
|
61153
61294
|
}
|
|
61154
61295
|
for (const suite of suites) {
|
|
61155
61296
|
const picked = chosen.get(suite.path) ?? { suite, cases: new Set };
|
|
@@ -61291,8 +61432,7 @@ async function runTestCommand(options, godotPath) {
|
|
|
61291
61432
|
getLocalVersion(),
|
|
61292
61433
|
readFileSync26(shippedListedRunner(), "utf8"),
|
|
61293
61434
|
engineSaid(godotPath),
|
|
61294
|
-
...options.reachAlso
|
|
61295
|
-
${existsSync23(path) ? readFileSync26(path, "latin1") : "missing"}`)
|
|
61435
|
+
...reachedAlsoSaid(options.projectPath, options.reachAlso)
|
|
61296
61436
|
];
|
|
61297
61437
|
const everySuite = suites;
|
|
61298
61438
|
const compileKept = options.changedOnly ? { file: join28(state, COMPILED_FILE), scripts, always } : null;
|
|
@@ -61498,7 +61638,7 @@ function readPassed(file) {
|
|
|
61498
61638
|
function recordPassed(file, projectPath, ran, failedAcross, inputs, began) {
|
|
61499
61639
|
const passed = readPassed(file);
|
|
61500
61640
|
for (const path of Object.keys(passed)) {
|
|
61501
|
-
if (!
|
|
61641
|
+
if (!existsSync24(join28(projectPath, path.slice("res://".length)))) {
|
|
61502
61642
|
delete passed[path];
|
|
61503
61643
|
}
|
|
61504
61644
|
}
|
|
@@ -61532,11 +61672,16 @@ function recordPassed(file, projectPath, ran, failedAcross, inputs, began) {
|
|
|
61532
61672
|
writeJson(file, passed);
|
|
61533
61673
|
}
|
|
61534
61674
|
function engineSaid(godotPath) {
|
|
61535
|
-
const
|
|
61536
|
-
|
|
61675
|
+
const engine = realpathSync5.native(godotPath);
|
|
61676
|
+
const stat = statSync14(engine);
|
|
61677
|
+
return `${engine}
|
|
61537
61678
|
${String(stat.size)}
|
|
61538
61679
|
${String(stat.mtimeMs)}`;
|
|
61539
61680
|
}
|
|
61681
|
+
function reachedAlsoSaid(projectPath, paths) {
|
|
61682
|
+
return paths.map((path) => `${relative5(projectPath, path).split(sep4).join("/")}
|
|
61683
|
+
${existsSync24(path) ? readFileSync26(path, "latin1") : "missing"}`);
|
|
61684
|
+
}
|
|
61540
61685
|
var COMPILE_CHECK = "compiling every script together";
|
|
61541
61686
|
|
|
61542
61687
|
class HandedSlot {
|
|
@@ -61860,7 +62005,7 @@ async function runEngine2(launch, plan, index, times, again = "", slot = null) {
|
|
|
61860
62005
|
}
|
|
61861
62006
|
var REPORT_FILES_NAMED = 3;
|
|
61862
62007
|
function reportsFault(reports) {
|
|
61863
|
-
const files =
|
|
62008
|
+
const files = existsSync24(reports) ? readdirSync15(reports, { recursive: true, encoding: "utf8" }).filter((file) => statSync14(join28(reports, file)).isFile()).sort() : [];
|
|
61864
62009
|
if (files.length === 0) {
|
|
61865
62010
|
return null;
|
|
61866
62011
|
}
|
|
@@ -61873,7 +62018,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61873
62018
|
for (const engine of ran) {
|
|
61874
62019
|
console.log("");
|
|
61875
62020
|
console.log(`--- what engine ${String(engine.index)} printed, running ${named(engine.plan.suites.map((suite) => suite.path))}:`);
|
|
61876
|
-
console.log(
|
|
62021
|
+
console.log(existsSync24(engine.log) ? readLog(engine.log).replace(CONTROL_SEQUENCE, "").trimEnd() : "(no log was written)");
|
|
61877
62022
|
}
|
|
61878
62023
|
}
|
|
61879
62024
|
const failed = ran.filter((engine) => !engine.verdict.passed);
|
|
@@ -61884,7 +62029,7 @@ function report(ran, compiled, across, uncollected, startedAt, logs, printOutput
|
|
|
61884
62029
|
for (const fault of engine.verdict.faults) {
|
|
61885
62030
|
console.log(` ${fault}`);
|
|
61886
62031
|
}
|
|
61887
|
-
if (
|
|
62032
|
+
if (existsSync24(engine.log)) {
|
|
61888
62033
|
const verdict = [
|
|
61889
62034
|
`gdharness: ${heading.slice(4)}`,
|
|
61890
62035
|
...engine.verdict.faults.map((fault) => ` ${fault}`)
|
|
@@ -62023,7 +62168,7 @@ class UsageError extends Refusal {
|
|
|
62023
62168
|
function projectArgument(at) {
|
|
62024
62169
|
const named = args.slice(at).find((value) => !value.startsWith("--"));
|
|
62025
62170
|
const projectPath = resolve15(named ?? ".");
|
|
62026
|
-
if (!
|
|
62171
|
+
if (!existsSync36(join45(projectPath, "project.godot"))) {
|
|
62027
62172
|
throw new UsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
62028
62173
|
}
|
|
62029
62174
|
return projectPath;
|
|
@@ -62087,7 +62232,7 @@ async function registerRuntime(godot, projectPath) {
|
|
|
62087
62232
|
}
|
|
62088
62233
|
const path = (named ?? "").replace(/^res:\/\//, "");
|
|
62089
62234
|
console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
|
|
62090
|
-
if (!
|
|
62235
|
+
if (!existsSync36(join45(projectPath, path))) {
|
|
62091
62236
|
console.log(" that file is not in this project, so it boots with a missing script");
|
|
62092
62237
|
}
|
|
62093
62238
|
console.log(` ${useTheShippedLoader(RUNTIME_AUTOLOAD.name, path)}`);
|
|
@@ -62220,7 +62365,7 @@ async function setup() {
|
|
|
62220
62365
|
console.log("no harness configured; name one yourself, and gdharness harnesses lists them all");
|
|
62221
62366
|
}
|
|
62222
62367
|
if (!args.includes("--no-skill")) {
|
|
62223
|
-
const directories = skillDirectories(chosen.harnesses, projectPath,
|
|
62368
|
+
const directories = skillDirectories(chosen.harnesses, projectPath, existsSync36);
|
|
62224
62369
|
for (const written of writeSkill(directories, getLocalVersion())) {
|
|
62225
62370
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
62226
62371
|
}
|
|
@@ -62340,7 +62485,7 @@ async function upgrade() {
|
|
|
62340
62485
|
moved.push(took.from);
|
|
62341
62486
|
}
|
|
62342
62487
|
}
|
|
62343
|
-
for (const written of writeSkill(skillDirectories(already, projectPath,
|
|
62488
|
+
for (const written of writeSkill(skillDirectories(already, projectPath, existsSync36), version)) {
|
|
62344
62489
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
62345
62490
|
}
|
|
62346
62491
|
console.log(`
|