gdharness 1.0.12 → 1.0.14
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 +250 -57
- package/build/godot/addons/gdharness_editor/bridge_client.gd +18 -2
- package/build/index.js +238 -96
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -7531,11 +7531,20 @@ var init_update_check = __esm(() => {
|
|
|
7531
7531
|
|
|
7532
7532
|
// src/server-version.ts
|
|
7533
7533
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7534
|
-
function
|
|
7535
|
-
if (
|
|
7534
|
+
function editorIsStale(addonVersion, serverVersion, addonDigest, shippedDigest) {
|
|
7535
|
+
if (addonDigest !== undefined && addonDigest !== "" && shippedDigest !== undefined) {
|
|
7536
|
+
return addonDigest !== shippedDigest;
|
|
7537
|
+
}
|
|
7538
|
+
return addonVersion !== serverVersion;
|
|
7539
|
+
}
|
|
7540
|
+
function addonMismatch(addonVersion, serverVersion, addonDigest, shippedDigest) {
|
|
7541
|
+
if (!editorIsStale(addonVersion, serverVersion, addonDigest, shippedDigest)) {
|
|
7536
7542
|
return;
|
|
7537
7543
|
}
|
|
7538
7544
|
const reported = addonVersion ?? "";
|
|
7545
|
+
if (reported === serverVersion) {
|
|
7546
|
+
return `The editor is running a different build of the ${reported} addon from the one this server ships. Restart it with editor_launch restart to pick this one up.`;
|
|
7547
|
+
}
|
|
7539
7548
|
const editor = reported === "" ? UNVERSIONED : `the ${reported} addon`;
|
|
7540
7549
|
const both = `The editor is running ${editor} while this server ships ${serverVersion}.`;
|
|
7541
7550
|
if (reported !== "" && isNewer(reported, serverVersion)) {
|
|
@@ -7543,8 +7552,8 @@ function addonMismatch(addonVersion, serverVersion) {
|
|
|
7543
7552
|
}
|
|
7544
7553
|
return `${both} Restart it with editor_launch restart to pick the new one up.`;
|
|
7545
7554
|
}
|
|
7546
|
-
function markIfStale(answer, addonVersion, serverVersion) {
|
|
7547
|
-
const staleNote = addonMismatch(addonVersion, serverVersion);
|
|
7555
|
+
function markIfStale(answer, addonVersion, serverVersion, addonDigest, shippedDigest) {
|
|
7556
|
+
const staleNote = addonMismatch(addonVersion, serverVersion, addonDigest, shippedDigest);
|
|
7548
7557
|
if (staleNote === undefined || typeof answer !== "object" || answer === null || Array.isArray(answer)) {
|
|
7549
7558
|
return answer;
|
|
7550
7559
|
}
|
|
@@ -7690,6 +7699,19 @@ function cacheWrittenAt(projectPath) {
|
|
|
7690
7699
|
return null;
|
|
7691
7700
|
}
|
|
7692
7701
|
}
|
|
7702
|
+
function declaredSince(projectPath, paths, names, since) {
|
|
7703
|
+
return names.filter((name) => {
|
|
7704
|
+
const path = paths.get(name);
|
|
7705
|
+
if (path === undefined || !path.startsWith("res://")) {
|
|
7706
|
+
return false;
|
|
7707
|
+
}
|
|
7708
|
+
try {
|
|
7709
|
+
return statSync2(join6(projectPath, path.slice("res://".length))).mtimeMs > since;
|
|
7710
|
+
} catch {
|
|
7711
|
+
return false;
|
|
7712
|
+
}
|
|
7713
|
+
});
|
|
7714
|
+
}
|
|
7693
7715
|
function cachedAtMissingPaths(cached, projectPath) {
|
|
7694
7716
|
return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync6(join6(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
|
|
7695
7717
|
}
|
|
@@ -15308,8 +15330,57 @@ function readParams(params, key) {
|
|
|
15308
15330
|
}
|
|
15309
15331
|
|
|
15310
15332
|
// src/setup.ts
|
|
15311
|
-
import {
|
|
15333
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
15334
|
+
import {
|
|
15335
|
+
cpSync as cpSync2,
|
|
15336
|
+
existsSync as existsSync8,
|
|
15337
|
+
mkdirSync as mkdirSync4,
|
|
15338
|
+
readdirSync as readdirSync4,
|
|
15339
|
+
readFileSync as readFileSync8,
|
|
15340
|
+
rmSync as rmSync4,
|
|
15341
|
+
statSync as statSync4,
|
|
15342
|
+
writeFileSync as writeFileSync6
|
|
15343
|
+
} from "node:fs";
|
|
15312
15344
|
import { dirname as dirname4, join as join9 } from "node:path";
|
|
15345
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15346
|
+
function editorAddonDigest2(from = shippedAddonsDirectory2()) {
|
|
15347
|
+
const hash = createHash3("sha256");
|
|
15348
|
+
const walk = (directory, relative) => {
|
|
15349
|
+
for (const name of readdirSync4(directory).sort()) {
|
|
15350
|
+
if (name === VERSION_MARKER2 || name === DIGEST_MARKER2) {
|
|
15351
|
+
continue;
|
|
15352
|
+
}
|
|
15353
|
+
const path = join9(directory, name);
|
|
15354
|
+
const inside = `${relative}/${name}`;
|
|
15355
|
+
if (statSync4(path).isDirectory()) {
|
|
15356
|
+
walk(path, inside);
|
|
15357
|
+
} else {
|
|
15358
|
+
hash.update(`${inside}
|
|
15359
|
+
`);
|
|
15360
|
+
hash.update(readFileSync8(path));
|
|
15361
|
+
hash.update(`
|
|
15362
|
+
`);
|
|
15363
|
+
}
|
|
15364
|
+
}
|
|
15365
|
+
};
|
|
15366
|
+
for (const name of EDITOR_PLUGINS2) {
|
|
15367
|
+
walk(join9(from, name), name);
|
|
15368
|
+
}
|
|
15369
|
+
return hash.digest("hex");
|
|
15370
|
+
}
|
|
15371
|
+
function shippedEditorDigest() {
|
|
15372
|
+
if (shippedDigest === undefined) {
|
|
15373
|
+
try {
|
|
15374
|
+
shippedDigest = editorAddonDigest2();
|
|
15375
|
+
} catch {
|
|
15376
|
+
shippedDigest = null;
|
|
15377
|
+
}
|
|
15378
|
+
}
|
|
15379
|
+
return shippedDigest ?? undefined;
|
|
15380
|
+
}
|
|
15381
|
+
function shippedAddonsDirectory2() {
|
|
15382
|
+
return join9(dirname4(fileURLToPath2(import.meta.url)), "godot", "addons");
|
|
15383
|
+
}
|
|
15313
15384
|
function installedAddonVersion(projectPath) {
|
|
15314
15385
|
const marker = join9(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
|
|
15315
15386
|
if (!existsSync8(marker)) {
|
|
@@ -15318,13 +15389,14 @@ function installedAddonVersion(projectPath) {
|
|
|
15318
15389
|
const said = readFileSync8(marker, "utf8").trim();
|
|
15319
15390
|
return said === "" ? null : said;
|
|
15320
15391
|
}
|
|
15321
|
-
var ADDONS2, RUNTIME_AUTOLOAD2, SCRIPT_RUNS_SETTING = "gdharness/runtime/serve_script_runs", BIND_ADDRESS_SETTING = "gdharness/runtime/bind_address", PORT_SETTING = "gdharness/runtime/port", VERSION_MARKER2 = ".gdharness-version";
|
|
15392
|
+
var ADDONS2, EDITOR_PLUGINS2, RUNTIME_AUTOLOAD2, SCRIPT_RUNS_SETTING = "gdharness/runtime/serve_script_runs", BIND_ADDRESS_SETTING = "gdharness/runtime/bind_address", PORT_SETTING = "gdharness/runtime/port", VERSION_MARKER2 = ".gdharness-version", DIGEST_MARKER2 = ".gdharness-digest", shippedDigest;
|
|
15322
15393
|
var init_setup = __esm(() => {
|
|
15323
15394
|
init_class_cache();
|
|
15324
15395
|
init_headless();
|
|
15325
15396
|
init_resources();
|
|
15326
15397
|
init_server_version();
|
|
15327
15398
|
ADDONS2 = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
|
|
15399
|
+
EDITOR_PLUGINS2 = ["gdharness_editor", "auto_reload"];
|
|
15328
15400
|
RUNTIME_AUTOLOAD2 = {
|
|
15329
15401
|
name: "GdharnessRuntime",
|
|
15330
15402
|
path: "addons/gdharness_runtime/runtime_autoload.gd"
|
|
@@ -31490,7 +31562,7 @@ var init_process_children = __esm(() => {
|
|
|
31490
31562
|
});
|
|
31491
31563
|
|
|
31492
31564
|
// src/runtime-client.ts
|
|
31493
|
-
import { existsSync as existsSync10, readdirSync as
|
|
31565
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync10, statSync as statSync5, unlinkSync } from "node:fs";
|
|
31494
31566
|
import { createConnection } from "node:net";
|
|
31495
31567
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
31496
31568
|
import { dirname as dirname7, join as join12, resolve as resolve3 } from "node:path";
|
|
@@ -31599,8 +31671,7 @@ function announcedAndGone(projectPath) {
|
|
|
31599
31671
|
return [];
|
|
31600
31672
|
}
|
|
31601
31673
|
const since = Date.now() - GONE_WINDOW_MS;
|
|
31602
|
-
|
|
31603
|
-
return gone.filter((one) => one.noticedAt >= since && resolve3(one.project) === wanted);
|
|
31674
|
+
return gone.filter((one) => one.noticedAt >= since && isSameDirectory(one.project, projectPath));
|
|
31604
31675
|
}
|
|
31605
31676
|
function strangersAmong(candidates, now, startTimes = startTimesOf) {
|
|
31606
31677
|
const toJudge = candidates.filter((one) => {
|
|
@@ -31627,7 +31698,7 @@ function announcedIn(directory) {
|
|
|
31627
31698
|
const found = [];
|
|
31628
31699
|
const candidates = [];
|
|
31629
31700
|
const entries = [];
|
|
31630
|
-
for (const entry of
|
|
31701
|
+
for (const entry of readdirSync6(directory)) {
|
|
31631
31702
|
const report = ERROR_REPORT_PATTERN.exec(entry);
|
|
31632
31703
|
if (report) {
|
|
31633
31704
|
sweepErrorReport(join12(directory, entry), Number.parseInt(report[1] ?? "", 10));
|
|
@@ -31643,7 +31714,7 @@ function announcedIn(directory) {
|
|
|
31643
31714
|
entries.push({ file, pid, alive });
|
|
31644
31715
|
if (alive) {
|
|
31645
31716
|
try {
|
|
31646
|
-
candidates.push({ file, pid, writtenAt:
|
|
31717
|
+
candidates.push({ file, pid, writtenAt: statSync5(file).mtimeMs });
|
|
31647
31718
|
} catch {}
|
|
31648
31719
|
}
|
|
31649
31720
|
}
|
|
@@ -31700,17 +31771,16 @@ function sweepErrorReport(path, pid, now = Date.now()) {
|
|
|
31700
31771
|
return;
|
|
31701
31772
|
}
|
|
31702
31773
|
try {
|
|
31703
|
-
if (now -
|
|
31774
|
+
if (now - statSync5(path).mtimeMs >= ERROR_REPORT_KEEP_MS) {
|
|
31704
31775
|
unlinkSync(path);
|
|
31705
31776
|
}
|
|
31706
31777
|
} catch {}
|
|
31707
31778
|
}
|
|
31708
31779
|
async function announcedSince(projectPath, before, waiting = {}) {
|
|
31709
|
-
const wanted = resolve3(projectPath);
|
|
31710
31780
|
const directories = waiting.directories ?? runtimeDirectories();
|
|
31711
31781
|
const until = Date.now() + Math.max(waiting.budgetMs ?? ANNOUNCE_BUDGET_MS, 0);
|
|
31712
31782
|
for (;; ) {
|
|
31713
|
-
const fresh = discoverRuntimes(directories).find((endpoint) => !before.has(endpoint.pid) &&
|
|
31783
|
+
const fresh = discoverRuntimes(directories).find((endpoint) => !before.has(endpoint.pid) && isSameDirectory(endpoint.project.path, projectPath) && (waiting.accept?.(endpoint) ?? true));
|
|
31714
31784
|
if (fresh !== undefined) {
|
|
31715
31785
|
return fresh;
|
|
31716
31786
|
}
|
|
@@ -31731,7 +31801,7 @@ function theOneProject(endpoints) {
|
|
|
31731
31801
|
if (endpoints.some((endpoint) => endpoint.project.path === "")) {
|
|
31732
31802
|
return;
|
|
31733
31803
|
}
|
|
31734
|
-
const paths = new Set(endpoints.map((endpoint) => resolve3(endpoint.project.path)));
|
|
31804
|
+
const paths = new Set(endpoints.map((endpoint) => realPathOr(resolve3(endpoint.project.path))));
|
|
31735
31805
|
const only = [...paths][0];
|
|
31736
31806
|
return paths.size === 1 ? only : undefined;
|
|
31737
31807
|
}
|
|
@@ -31760,7 +31830,7 @@ function chooseRuntime(endpoints, projectPath, unspoken = [], pid) {
|
|
|
31760
31830
|
if (pid !== undefined) {
|
|
31761
31831
|
const named = endpoints.find((endpoint) => endpoint.pid === pid);
|
|
31762
31832
|
if (named !== undefined) {
|
|
31763
|
-
if (projectPath !== undefined &&
|
|
31833
|
+
if (projectPath !== undefined && !isSameDirectory(named.project.path, projectPath)) {
|
|
31764
31834
|
return {
|
|
31765
31835
|
problem: `The game with pid ${pid} is running ${named.project.path}, not ${resolve3(projectPath)}. Running: ${endpoints.map(describe2).join("; ")}.`
|
|
31766
31836
|
};
|
|
@@ -31803,7 +31873,7 @@ function chooseRuntime(endpoints, projectPath, unspoken = [], pid) {
|
|
|
31803
31873
|
}
|
|
31804
31874
|
if (projectPath !== undefined) {
|
|
31805
31875
|
const wanted = resolve3(projectPath);
|
|
31806
|
-
const matching = endpoints.filter((endpoint) =>
|
|
31876
|
+
const matching = endpoints.filter((endpoint) => isSameDirectory(endpoint.project.path, wanted));
|
|
31807
31877
|
if (matching.length === 0) {
|
|
31808
31878
|
return {
|
|
31809
31879
|
problem: `No running game is from ${wanted}. Running: ${endpoints.map(describe2).join("; ")}.`
|
|
@@ -31914,6 +31984,7 @@ function runtimeRequest(endpoint, command, params, timeoutMs) {
|
|
|
31914
31984
|
}
|
|
31915
31985
|
var RUNTIME_PROTOCOL = 2, ANNOUNCEMENT_PATTERN, ERROR_REPORT_PATTERN, ERROR_REPORT_KEEP_MS, GONE_WINDOW_MS = 120000, GONE_KEPT = 32, gone, STARTED_AFTER_ANNOUNCING_MS = 2000, CONFIRMED_FOR_MS = 60000, JUDGED_AFTER_MS = 60000, verdicts, ENDED_WITHIN_MS = 3000, LOOK_EVERY_MS = 50, ANNOUNCE_BUDGET_MS = 5000, nextRequestId = 1;
|
|
31916
31986
|
var init_runtime_client = __esm(() => {
|
|
31987
|
+
init_paths();
|
|
31917
31988
|
init_process_children();
|
|
31918
31989
|
ANNOUNCEMENT_PATTERN = /^runtime-(\d+)\.json$/;
|
|
31919
31990
|
ERROR_REPORT_PATTERN = /^runtime-(\d+)\.log$/;
|
|
@@ -32879,7 +32950,7 @@ import {
|
|
|
32879
32950
|
readFileSync as readFileSync16,
|
|
32880
32951
|
readSync,
|
|
32881
32952
|
rmSync as rmSync8,
|
|
32882
|
-
statSync as
|
|
32953
|
+
statSync as statSync6,
|
|
32883
32954
|
writeFileSync as writeFileSync12
|
|
32884
32955
|
} from "node:fs";
|
|
32885
32956
|
import { dirname as dirname12, join as join18 } from "node:path";
|
|
@@ -32942,7 +33013,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
|
|
|
32942
33013
|
return { log, path, ...of === undefined ? {} : { readBytes: text.length, of } };
|
|
32943
33014
|
}
|
|
32944
33015
|
function theFirstOf(path) {
|
|
32945
|
-
const whole =
|
|
33016
|
+
const whole = statSync6(path).size;
|
|
32946
33017
|
if (whole <= MOST_CONSOLE_BYTES) {
|
|
32947
33018
|
return { text: readFileSync16(path, "utf8") };
|
|
32948
33019
|
}
|
|
@@ -36160,6 +36231,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
36160
36231
|
connectedAt: this.connectionInfo?.connectedAt,
|
|
36161
36232
|
lastPongAt: this.connectionInfo?.lastPongAt,
|
|
36162
36233
|
addonVersion: this.connectionInfo?.addonVersion,
|
|
36234
|
+
addonDigest: this.connectionInfo?.addonDigest,
|
|
36163
36235
|
editorPid: this.connectionInfo?.editorPid,
|
|
36164
36236
|
lspPort: this.connectionInfo?.lspPort,
|
|
36165
36237
|
dapPort: this.connectionInfo?.dapPort,
|
|
@@ -36303,6 +36375,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
36303
36375
|
}
|
|
36304
36376
|
this.connectionInfo.projectPath = message.project_path;
|
|
36305
36377
|
this.connectionInfo.addonVersion = message.addon_version ?? "";
|
|
36378
|
+
this.connectionInfo.addonDigest = message.addon_digest;
|
|
36306
36379
|
this.connectionInfo.editorPid = message.editor_pid;
|
|
36307
36380
|
this.connectionInfo.lspPort = servedPort(message.lsp_port);
|
|
36308
36381
|
this.connectionInfo.dapPort = servedPort(message.dap_port);
|
|
@@ -36556,7 +36629,7 @@ var init_godot_path = __esm(() => {
|
|
|
36556
36629
|
});
|
|
36557
36630
|
|
|
36558
36631
|
// src/issues.ts
|
|
36559
|
-
import { createHash as
|
|
36632
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
36560
36633
|
import process7 from "node:process";
|
|
36561
36634
|
function feedbackNotice() {
|
|
36562
36635
|
return JSON.stringify({
|
|
@@ -36574,7 +36647,7 @@ function runtime2() {
|
|
|
36574
36647
|
function defectSignature2(where, message) {
|
|
36575
36648
|
const normalised = `${where}
|
|
36576
36649
|
${message}`.toLowerCase().replaceAll("\\", "/").replaceAll(/(?:[a-z]:)?(?:\/+[\w.-]+){2,}/gu, "<path>").replaceAll(/\d+/gu, "0");
|
|
36577
|
-
return
|
|
36650
|
+
return createHash4("sha256").update(normalised).digest("hex").slice(0, 8);
|
|
36578
36651
|
}
|
|
36579
36652
|
function facts2(where, message, godotVersion) {
|
|
36580
36653
|
return [
|
|
@@ -36911,7 +36984,7 @@ import { realpathSync as realpathSync2 } from "node:fs";
|
|
|
36911
36984
|
import { readFile, realpath } from "node:fs/promises";
|
|
36912
36985
|
import { createConnection as createConnection3 } from "node:net";
|
|
36913
36986
|
import { dirname as dirname13, resolve as resolve4 } from "node:path";
|
|
36914
|
-
import { fileURLToPath as
|
|
36987
|
+
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
|
|
36915
36988
|
function diagnosticsKey(uri) {
|
|
36916
36989
|
let decoded;
|
|
36917
36990
|
try {
|
|
@@ -36923,7 +36996,7 @@ function diagnosticsKey(uri) {
|
|
|
36923
36996
|
return decoded;
|
|
36924
36997
|
}
|
|
36925
36998
|
try {
|
|
36926
|
-
return realpathSync2.native(
|
|
36999
|
+
return realpathSync2.native(fileURLToPath4(decoded)).toLowerCase();
|
|
36927
37000
|
} catch {
|
|
36928
37001
|
return decoded.toLowerCase();
|
|
36929
37002
|
}
|
|
@@ -37483,7 +37556,7 @@ var init_process_time = __esm(() => {
|
|
|
37483
37556
|
});
|
|
37484
37557
|
|
|
37485
37558
|
// src/project-scan.ts
|
|
37486
|
-
import { existsSync as existsSync14, readdirSync as
|
|
37559
|
+
import { existsSync as existsSync14, readdirSync as readdirSync7, readFileSync as readFileSync17 } from "node:fs";
|
|
37487
37560
|
import { join as join19 } from "node:path";
|
|
37488
37561
|
function skipped(name) {
|
|
37489
37562
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
@@ -37497,7 +37570,7 @@ function projectStructure(projectPath) {
|
|
|
37497
37570
|
if (steppedOver(directory)) {
|
|
37498
37571
|
return;
|
|
37499
37572
|
}
|
|
37500
|
-
for (const entry of
|
|
37573
|
+
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
37501
37574
|
if (skipped(entry.name)) {
|
|
37502
37575
|
continue;
|
|
37503
37576
|
}
|
|
@@ -37526,7 +37599,7 @@ function scriptsWithoutUid(projectPath) {
|
|
|
37526
37599
|
if (steppedOver(directory)) {
|
|
37527
37600
|
return;
|
|
37528
37601
|
}
|
|
37529
|
-
for (const entry of
|
|
37602
|
+
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
37530
37603
|
if (skipped(entry.name)) {
|
|
37531
37604
|
continue;
|
|
37532
37605
|
}
|
|
@@ -37567,7 +37640,7 @@ function searchProject(projectPath, options) {
|
|
|
37567
37640
|
if (steppedOver(directory)) {
|
|
37568
37641
|
return;
|
|
37569
37642
|
}
|
|
37570
|
-
for (const entry of
|
|
37643
|
+
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
37571
37644
|
if (full()) {
|
|
37572
37645
|
return;
|
|
37573
37646
|
}
|
|
@@ -37657,7 +37730,7 @@ var init_restart_note = __esm(() => {
|
|
|
37657
37730
|
|
|
37658
37731
|
// src/run-record.ts
|
|
37659
37732
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
37660
|
-
import { mkdirSync as mkdirSync12, openSync as openSync2, readdirSync as
|
|
37733
|
+
import { mkdirSync as mkdirSync12, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync19, rmSync as rmSync10, statSync as statSync7, writeFileSync as writeFileSync14 } from "node:fs";
|
|
37661
37734
|
import { basename as basename3, join as join21 } from "node:path";
|
|
37662
37735
|
function runsDirectory() {
|
|
37663
37736
|
return join21(runtimeDirectory(), "runs");
|
|
@@ -37912,7 +37985,7 @@ function clearRunRecord(ours = () => true) {
|
|
|
37912
37985
|
}
|
|
37913
37986
|
function ageMs(path, now) {
|
|
37914
37987
|
try {
|
|
37915
|
-
return now -
|
|
37988
|
+
return now - statSync7(path).mtimeMs;
|
|
37916
37989
|
} catch {
|
|
37917
37990
|
return 0;
|
|
37918
37991
|
}
|
|
@@ -37922,7 +37995,7 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
37922
37995
|
const keep = readRunRecord()?.transcript;
|
|
37923
37996
|
let entries;
|
|
37924
37997
|
try {
|
|
37925
|
-
entries =
|
|
37998
|
+
entries = readdirSync8(directory);
|
|
37926
37999
|
} catch {
|
|
37927
38000
|
return;
|
|
37928
38001
|
}
|
|
@@ -37957,16 +38030,16 @@ import {
|
|
|
37957
38030
|
mkdirSync as mkdirSync13,
|
|
37958
38031
|
mkdtempSync as mkdtempSync3,
|
|
37959
38032
|
openSync as openSync3,
|
|
37960
|
-
readdirSync as
|
|
38033
|
+
readdirSync as readdirSync9,
|
|
37961
38034
|
readFileSync as readFileSync20,
|
|
37962
38035
|
readSync as readSync2,
|
|
37963
38036
|
rmdirSync,
|
|
37964
|
-
statSync as
|
|
38037
|
+
statSync as statSync8
|
|
37965
38038
|
} from "node:fs";
|
|
37966
38039
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
37967
38040
|
import { basename as basename4, dirname as dirname15, isAbsolute as isAbsolute3, join as join22, normalize as normalize3, relative as relative3 } from "node:path";
|
|
37968
38041
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
37969
|
-
import { fileURLToPath as
|
|
38042
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
37970
38043
|
import { promisify as promisify7 } from "node:util";
|
|
37971
38044
|
function patienceForFrames(frames, atLeast) {
|
|
37972
38045
|
return Math.max(atLeast, frames / SLOWEST_FRAME_RATE * 1000 + atLeast);
|
|
@@ -38212,7 +38285,7 @@ function elsewhereIn(projectPath, asked) {
|
|
|
38212
38285
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
38213
38286
|
let near = [];
|
|
38214
38287
|
try {
|
|
38215
|
-
near =
|
|
38288
|
+
near = readdirSync9(projectPath, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.toLowerCase() !== root).map((entry) => entry.name).filter((name) => name.toLowerCase().startsWith("test") || root.startsWith(name.toLowerCase()));
|
|
38216
38289
|
} catch {
|
|
38217
38290
|
return "";
|
|
38218
38291
|
}
|
|
@@ -39372,7 +39445,7 @@ class GodotServer {
|
|
|
39372
39445
|
let report = null;
|
|
39373
39446
|
let reportProblem = null;
|
|
39374
39447
|
try {
|
|
39375
|
-
const written = existsSync15(reportsDir) ?
|
|
39448
|
+
const written = existsSync15(reportsDir) ? readdirSync9(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
39376
39449
|
const newest = written.at(-1);
|
|
39377
39450
|
if (newest !== undefined) {
|
|
39378
39451
|
report = parseJUnit(readFileSync20(join22(reportsDir, newest, "results.xml"), "utf8"));
|
|
@@ -39501,7 +39574,7 @@ class GodotServer {
|
|
|
39501
39574
|
warnings: diagnostics.length - errors,
|
|
39502
39575
|
diagnostics,
|
|
39503
39576
|
...disagrees
|
|
39504
|
-
}, this.godotBridge.getStatus().addonVersion, SERVER_VERSION));
|
|
39577
|
+
}, this.godotBridge.getStatus().addonVersion, SERVER_VERSION, this.godotBridge.getStatus().addonDigest, shippedEditorDigest()));
|
|
39505
39578
|
}
|
|
39506
39579
|
whereTheFileDisagrees(diagnostics, args) {
|
|
39507
39580
|
const messages = diagnostics.map((entry) => asParams(entry)["message"]).filter((message) => typeof message === "string");
|
|
@@ -39688,7 +39761,7 @@ class GodotServer {
|
|
|
39688
39761
|
getEditorStatusPayload() {
|
|
39689
39762
|
const status = this.godotBridge.getStatus();
|
|
39690
39763
|
const isPortConflict = this.bridgeStartupError?.includes("EADDRINUSE") ?? false;
|
|
39691
|
-
const stale = status.connected && status.addonVersion
|
|
39764
|
+
const stale = status.connected && editorIsStale(status.addonVersion, SERVER_VERSION, status.addonDigest, shippedEditorDigest());
|
|
39692
39765
|
const unfinished = this.restartLeftUnfinished(status.connected);
|
|
39693
39766
|
return {
|
|
39694
39767
|
...status,
|
|
@@ -39705,7 +39778,7 @@ class GodotServer {
|
|
|
39705
39778
|
awaitingLaunchedEditor: status.connected || !this.launchedEditorIsUp() ? undefined : this.launchedEditor?.pid ?? undefined,
|
|
39706
39779
|
...status.connected ? this.whatTheLaunchedEditorDropped() : {},
|
|
39707
39780
|
startupError: this.bridgeStartupError,
|
|
39708
|
-
staleNote: stale ? addonMismatch(status.addonVersion, SERVER_VERSION) : undefined,
|
|
39781
|
+
staleNote: stale ? addonMismatch(status.addonVersion, SERVER_VERSION, status.addonDigest, shippedEditorDigest()) : undefined,
|
|
39709
39782
|
...this.breakpointsAtRisk(),
|
|
39710
39783
|
retryingBridge: this.bridgeRetry === null ? undefined : true,
|
|
39711
39784
|
announcedAt: this.announcedAt ?? undefined,
|
|
@@ -39837,8 +39910,8 @@ class GodotServer {
|
|
|
39837
39910
|
editorPid: now.editorPid,
|
|
39838
39911
|
addonVersion: now.addonVersion,
|
|
39839
39912
|
serverVersion: SERVER_VERSION,
|
|
39840
|
-
addonIsStale: now.addonVersion
|
|
39841
|
-
staleNote: addonMismatch(now.addonVersion, SERVER_VERSION),
|
|
39913
|
+
addonIsStale: editorIsStale(now.addonVersion, SERVER_VERSION, now.addonDigest, shippedEditorDigest()),
|
|
39914
|
+
staleNote: addonMismatch(now.addonVersion, SERVER_VERSION, now.addonDigest, shippedEditorDigest()),
|
|
39842
39915
|
...this.whatTheEditorDropped(settingsBefore, after),
|
|
39843
39916
|
tookMs: Date.now() - began
|
|
39844
39917
|
});
|
|
@@ -40115,7 +40188,7 @@ class GodotServer {
|
|
|
40115
40188
|
}
|
|
40116
40189
|
let announcedAt;
|
|
40117
40190
|
try {
|
|
40118
|
-
announcedAt =
|
|
40191
|
+
announcedAt = statSync8(endpoint.file).mtimeMs;
|
|
40119
40192
|
} catch {
|
|
40120
40193
|
return;
|
|
40121
40194
|
}
|
|
@@ -40725,7 +40798,15 @@ class GodotServer {
|
|
|
40725
40798
|
"editor_launch opens one, and an editor opened here has its console captured"
|
|
40726
40799
|
]);
|
|
40727
40800
|
}
|
|
40728
|
-
const
|
|
40801
|
+
const launched = status.connected ? null : this.launchedEditor?.pid ?? null;
|
|
40802
|
+
if (!status.connected && launched === null) {
|
|
40803
|
+
return this.createErrorResponse("No editor is connected, so there is no console to read.", [
|
|
40804
|
+
"editor_status says whether one is connected and whether it may yet be",
|
|
40805
|
+
"editor_launch opens one, and an editor opened here has its console captured"
|
|
40806
|
+
]);
|
|
40807
|
+
}
|
|
40808
|
+
const editorPid = status.connected ? status.editorPid ?? null : launched;
|
|
40809
|
+
const console2 = editorConsole(projectPath, editorPid, status.connected ? status.openedByAServer === true : true);
|
|
40729
40810
|
if ("kind" in console2) {
|
|
40730
40811
|
return this.createErrorResponse(theConsoleWasNotCaptured(console2, projectPath), [
|
|
40731
40812
|
"editor_launch restart replaces this editor with one whose console is captured",
|
|
@@ -40743,8 +40824,9 @@ class GodotServer {
|
|
|
40743
40824
|
const grouped = bursts(everything, readPositiveNumber(args, "before") ?? 3);
|
|
40744
40825
|
const shown = grouped.slice(0, MOST_GROUPS);
|
|
40745
40826
|
return this.jsonTextResponse({
|
|
40746
|
-
editorPid:
|
|
40827
|
+
editorPid: editorPid ?? undefined,
|
|
40747
40828
|
projectPath,
|
|
40829
|
+
...status.connected ? {} : this.launchedEditorIsUp() ? { stillConnecting: true } : { exitedBeforeConnecting: true },
|
|
40748
40830
|
capturedIn: console2.path,
|
|
40749
40831
|
...console2.of === undefined ? {} : {
|
|
40750
40832
|
readFromTheStart: console2.readBytes,
|
|
@@ -41043,6 +41125,7 @@ class GodotServer {
|
|
|
41043
41125
|
}
|
|
41044
41126
|
async rebuildClassCache(projectPath) {
|
|
41045
41127
|
const before = cachedClasses(projectPath);
|
|
41128
|
+
const writtenBefore = cacheWrittenAt(projectPath);
|
|
41046
41129
|
const noted = readClassNote(projectPath);
|
|
41047
41130
|
const rebuilt = await this.operation("refresh_class_cache", {}, projectPath);
|
|
41048
41131
|
if (!rebuilt.ok) {
|
|
@@ -41053,21 +41136,30 @@ class GodotServer {
|
|
|
41053
41136
|
return rebuilt;
|
|
41054
41137
|
}
|
|
41055
41138
|
const lost = noted === null || before === null ? [] : noted.rebuiltWith.filter((name) => !before.has(name) && after.has(name)).sort();
|
|
41056
|
-
const
|
|
41139
|
+
const cameBack = writtenBefore === null ? [] : declaredSince(projectPath, after, lost, writtenBefore);
|
|
41140
|
+
const droppedByTheEditor = lost.filter((name) => !cameBack.includes(name));
|
|
41141
|
+
const seenLosing = droppedByTheEditor.length > 0 && this.godotBridge.isConnected();
|
|
41057
41142
|
writeClassNote(projectPath, {
|
|
41058
41143
|
rebuiltWith: [...after.keys()].sort(),
|
|
41059
41144
|
...seenLosing ? { shortListEditorPid: this.godotBridge.getStatus().editorPid ?? null } : noted?.shortListEditorPid === undefined ? {} : { shortListEditorPid: noted.shortListEditorPid }
|
|
41060
41145
|
});
|
|
41061
|
-
|
|
41146
|
+
const notes = [];
|
|
41147
|
+
if (seenLosing) {
|
|
41148
|
+
const them = droppedByTheEditor.length === 1 ? "it" : "them";
|
|
41149
|
+
notes.push(`The cache held ${droppedByTheEditor.join(", ")} after the last rebuild and not when this one began, so the editor holding this project wrote it without ${them} in between: it holds a list shorter than the files and writes that list on every save and scan, and each rebuild puts ${them} back. editor_launch restart is what ends it.`);
|
|
41150
|
+
}
|
|
41151
|
+
if (cameBack.length > 0) {
|
|
41152
|
+
notes.push(`${cameBack.join(", ")} left the cache while ${cameBack.length === 1 ? "its script was" : "their scripts were"} gone: the script${cameBack.length === 1 ? " is" : "s are"} newer than the cache the editor last wrote, so it listed what was on disk then. editor_rescan picks ${cameBack.length === 1 ? "it" : "them"} up.`);
|
|
41153
|
+
}
|
|
41154
|
+
if (notes.length === 0) {
|
|
41062
41155
|
return rebuilt;
|
|
41063
41156
|
}
|
|
41064
|
-
const them = lost.length === 1 ? "it" : "them";
|
|
41065
41157
|
return {
|
|
41066
41158
|
...rebuilt,
|
|
41067
41159
|
payload: {
|
|
41068
41160
|
...rebuilt.payload,
|
|
41069
41161
|
lostSinceLastRebuild: lost,
|
|
41070
|
-
note:
|
|
41162
|
+
note: notes.join(" ")
|
|
41071
41163
|
}
|
|
41072
41164
|
};
|
|
41073
41165
|
}
|
|
@@ -41143,7 +41235,7 @@ class GodotServer {
|
|
|
41143
41235
|
]);
|
|
41144
41236
|
}
|
|
41145
41237
|
try {
|
|
41146
|
-
return this.jsonTextResponse(markIfStale(await this.godotBridge.invokeTool(toolName, args), this.godotBridge.getStatus().addonVersion, SERVER_VERSION));
|
|
41238
|
+
return this.jsonTextResponse(markIfStale(await this.godotBridge.invokeTool(toolName, args), this.godotBridge.getStatus().addonVersion, SERVER_VERSION, this.godotBridge.getStatus().addonDigest, shippedEditorDigest()));
|
|
41147
41239
|
} catch (error) {
|
|
41148
41240
|
return this.createErrorResponse(`The editor answered ${toolName} with an error: ${errorMessage(error)}`);
|
|
41149
41241
|
}
|
|
@@ -41196,8 +41288,59 @@ class GodotServer {
|
|
|
41196
41288
|
}
|
|
41197
41289
|
return { heldAt: undefined, heldUnknown: true, heldNote: reply.message };
|
|
41198
41290
|
}
|
|
41291
|
+
async ownRunOnItsWay(projectPath, budgetMs) {
|
|
41292
|
+
const run = this.currentRun();
|
|
41293
|
+
const project = projectPath ?? run?.projectPath ?? null;
|
|
41294
|
+
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync15(join22(project, RUNTIME_AUTOLOAD2.path)) || !await this.runStillGoing(run)) {
|
|
41295
|
+
return null;
|
|
41296
|
+
}
|
|
41297
|
+
const already = runtimesAnnounced().running;
|
|
41298
|
+
const announcedSinceTheStart = (one) => {
|
|
41299
|
+
if (run.announcedBefore !== undefined) {
|
|
41300
|
+
return !run.announcedBefore.has(one.pid);
|
|
41301
|
+
}
|
|
41302
|
+
try {
|
|
41303
|
+
return statSync8(one.file).mtimeMs >= run.startedAt;
|
|
41304
|
+
} catch {
|
|
41305
|
+
return false;
|
|
41306
|
+
}
|
|
41307
|
+
};
|
|
41308
|
+
if (already.some((one) => announcedSinceTheStart(one) && this.isTheGameOf(run, one, project))) {
|
|
41309
|
+
return null;
|
|
41310
|
+
}
|
|
41311
|
+
const which = run.throughEditor ? "the game the editor is playing for it" : `pid ${run.pid ?? "unknown"}`;
|
|
41312
|
+
const comingUpUntil = run.startedAt + waitSizedTo(readBootNote(project)) + budgetMs;
|
|
41313
|
+
const remaining = comingUpUntil - Date.now();
|
|
41314
|
+
if (remaining <= 0) {
|
|
41315
|
+
const seconds = Math.round((Date.now() - run.startedAt) / 1000);
|
|
41316
|
+
return `The game this server started (${which}) has been running for ${seconds}s and has not announced its runtime, so there is nothing to talk to. A game that keeps the runtime off, as a project's own loader can for some scenes, never announces; editor_output says what it has printed.`;
|
|
41317
|
+
}
|
|
41318
|
+
const endpoint = await announcedSince(project, new Set(already.map((one) => one.pid)), {
|
|
41319
|
+
budgetMs: Math.min(budgetMs, remaining),
|
|
41320
|
+
accept: (one) => this.isTheGameOf(this.currentRun(), one, project),
|
|
41321
|
+
giveUp: () => this.currentRun() !== run || this.dapClient?.isStopped() === true || !stillRunning(run)
|
|
41322
|
+
});
|
|
41323
|
+
if (endpoint !== null) {
|
|
41324
|
+
const tiedMeanwhile = () => run.announcedPid !== undefined;
|
|
41325
|
+
if (!tiedMeanwhile()) {
|
|
41326
|
+
this.tie(run, endpoint);
|
|
41327
|
+
}
|
|
41328
|
+
return null;
|
|
41329
|
+
}
|
|
41330
|
+
if (this.currentRun() !== run || !await this.runStillGoing(run)) {
|
|
41331
|
+
return null;
|
|
41332
|
+
}
|
|
41333
|
+
return `The game this server started (${which}) is still coming up and has not announced its runtime after a wait of ${Math.min(budgetMs, remaining)}ms, so there is nothing to talk to yet. It is still running: ask again in a moment rather than starting another.`;
|
|
41334
|
+
}
|
|
41199
41335
|
async handleRuntimeCommand(command, args, timeoutMs = this.runtimeTimeoutMs()) {
|
|
41200
41336
|
const { op: _op, projectPath, pid, ...params } = asParams(args);
|
|
41337
|
+
const waited = typeof pid === "number" ? null : await this.ownRunOnItsWay(typeof projectPath === "string" ? projectPath : this.ownProject, timeoutMs);
|
|
41338
|
+
if (waited !== null) {
|
|
41339
|
+
return this.createErrorResponse(waited, [
|
|
41340
|
+
"editor_status lists it under runtimes once it has announced",
|
|
41341
|
+
"editor_output says what it has printed so far"
|
|
41342
|
+
]);
|
|
41343
|
+
}
|
|
41201
41344
|
const announced = runtimesAnnounced();
|
|
41202
41345
|
const wanted = typeof projectPath === "string" ? projectPath : this.ownProject ?? undefined;
|
|
41203
41346
|
const own = typeof pid === "number" ? undefined : this.ownGameAmong(announced.running, wanted) ?? await this.ownGameThroughTheTree(announced.running, wanted);
|
|
@@ -41346,7 +41489,7 @@ var init_server3 = __esm(() => {
|
|
|
41346
41489
|
init_tool_definitions();
|
|
41347
41490
|
init_update_check();
|
|
41348
41491
|
run7 = promisify7(execFile7);
|
|
41349
|
-
__dirname2 = dirname15(
|
|
41492
|
+
__dirname2 = dirname15(fileURLToPath5(import.meta.url));
|
|
41350
41493
|
CONSOLE_WRAPPER = /_console(\.exe)?$/i;
|
|
41351
41494
|
LONGEST_BOOT_NOTED_MS = 5 * 60000;
|
|
41352
41495
|
VALUE_NAMES = {
|
|
@@ -42565,7 +42708,17 @@ init_headless();
|
|
|
42565
42708
|
init_resources();
|
|
42566
42709
|
init_server_version();
|
|
42567
42710
|
import { spawnSync } from "node:child_process";
|
|
42568
|
-
import {
|
|
42711
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
42712
|
+
import {
|
|
42713
|
+
cpSync,
|
|
42714
|
+
existsSync as existsSync7,
|
|
42715
|
+
mkdirSync as mkdirSync3,
|
|
42716
|
+
readdirSync as readdirSync3,
|
|
42717
|
+
readFileSync as readFileSync7,
|
|
42718
|
+
rmSync as rmSync3,
|
|
42719
|
+
statSync as statSync3,
|
|
42720
|
+
writeFileSync as writeFileSync5
|
|
42721
|
+
} from "node:fs";
|
|
42569
42722
|
import { dirname as dirname3, join as join8 } from "node:path";
|
|
42570
42723
|
import { fileURLToPath } from "node:url";
|
|
42571
42724
|
var ADDONS = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
|
|
@@ -42575,6 +42728,40 @@ var RUNTIME_AUTOLOAD = {
|
|
|
42575
42728
|
path: "addons/gdharness_runtime/runtime_autoload.gd"
|
|
42576
42729
|
};
|
|
42577
42730
|
var VERSION_MARKER = ".gdharness-version";
|
|
42731
|
+
var DIGEST_MARKER = ".gdharness-digest";
|
|
42732
|
+
function editorAddonDigest(from = shippedAddonsDirectory()) {
|
|
42733
|
+
const hash = createHash2("sha256");
|
|
42734
|
+
const walk = (directory, relative) => {
|
|
42735
|
+
for (const name of readdirSync3(directory).sort()) {
|
|
42736
|
+
if (name === VERSION_MARKER || name === DIGEST_MARKER) {
|
|
42737
|
+
continue;
|
|
42738
|
+
}
|
|
42739
|
+
const path = join8(directory, name);
|
|
42740
|
+
const inside = `${relative}/${name}`;
|
|
42741
|
+
if (statSync3(path).isDirectory()) {
|
|
42742
|
+
walk(path, inside);
|
|
42743
|
+
} else {
|
|
42744
|
+
hash.update(`${inside}
|
|
42745
|
+
`);
|
|
42746
|
+
hash.update(readFileSync7(path));
|
|
42747
|
+
hash.update(`
|
|
42748
|
+
`);
|
|
42749
|
+
}
|
|
42750
|
+
}
|
|
42751
|
+
};
|
|
42752
|
+
for (const name of EDITOR_PLUGINS) {
|
|
42753
|
+
walk(join8(from, name), name);
|
|
42754
|
+
}
|
|
42755
|
+
return hash.digest("hex");
|
|
42756
|
+
}
|
|
42757
|
+
function installedEditorDigest(projectPath) {
|
|
42758
|
+
const marker = join8(projectPath, "addons", ADDONS[0], DIGEST_MARKER);
|
|
42759
|
+
if (!existsSync7(marker)) {
|
|
42760
|
+
return null;
|
|
42761
|
+
}
|
|
42762
|
+
const said = readFileSync7(marker, "utf8").trim();
|
|
42763
|
+
return said === "" ? null : said;
|
|
42764
|
+
}
|
|
42578
42765
|
function shippedAddonsDirectory() {
|
|
42579
42766
|
return join8(dirname3(fileURLToPath(import.meta.url)), "godot", "addons");
|
|
42580
42767
|
}
|
|
@@ -42597,6 +42784,8 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
42597
42784
|
`);
|
|
42598
42785
|
installed.push({ name, path: target, replaced });
|
|
42599
42786
|
}
|
|
42787
|
+
writeFileSync5(join8(projectPath, "addons", ADDONS[0], DIGEST_MARKER), `${editorAddonDigest(from)}
|
|
42788
|
+
`);
|
|
42600
42789
|
return installed;
|
|
42601
42790
|
}
|
|
42602
42791
|
function removeAddons(projectPath) {
|
|
@@ -42741,7 +42930,7 @@ function inspectProject(projectPath) {
|
|
|
42741
42930
|
// src/skill.ts
|
|
42742
42931
|
init_setup();
|
|
42743
42932
|
init_tool_definitions();
|
|
42744
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as
|
|
42933
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync5, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
42745
42934
|
import { basename, dirname as dirname5, join as join10 } from "node:path";
|
|
42746
42935
|
|
|
42747
42936
|
// src/tool-reference.ts
|
|
@@ -42863,7 +43052,8 @@ that is running, and the project on disk. ${TOOL_SPECS.length} tools, named \`do
|
|
|
42863
43052
|
this server is connected to. There is no ambient project, and an argument a tool does not declare is refused
|
|
42864
43053
|
rather than ignored.
|
|
42865
43054
|
- \`editor_status\` says whether an editor is connected and whether its addon matches the server.
|
|
42866
|
-
\`addonIsStale\` means
|
|
43055
|
+
\`addonIsStale\` means the editor is running different addon code from what the server ships
|
|
43056
|
+
(an older \`addonVersion\` on the same code is not stale), and \`staleNote\` says which half is behind: an editor that
|
|
42867
43057
|
needs restarting, or a server that needs reconnecting in your harness. Every answer that came
|
|
42868
43058
|
from the editor carries the same two when they differ, so a stale addon cannot answer quietly:
|
|
42869
43059
|
believe a restart over a diagnostic that arrived with them.
|
|
@@ -43050,7 +43240,7 @@ function pruneEmpty(directory, projectPath) {
|
|
|
43050
43240
|
const shared = join10(projectPath, ".agents");
|
|
43051
43241
|
let path = directory;
|
|
43052
43242
|
while (path !== projectPath && (basename(path) === "skills" || path === shared)) {
|
|
43053
|
-
if (
|
|
43243
|
+
if (readdirSync5(path).length > 0) {
|
|
43054
43244
|
return;
|
|
43055
43245
|
}
|
|
43056
43246
|
rmSync5(path, { recursive: true, force: true });
|
|
@@ -43074,9 +43264,9 @@ function writeSkill(directories, version) {
|
|
|
43074
43264
|
// src/version.ts
|
|
43075
43265
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
43076
43266
|
import { dirname as dirname6, join as join11 } from "node:path";
|
|
43077
|
-
import { fileURLToPath as
|
|
43267
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
43078
43268
|
function getLocalVersion() {
|
|
43079
|
-
const currentDirectory = dirname6(
|
|
43269
|
+
const currentDirectory = dirname6(fileURLToPath3(import.meta.url));
|
|
43080
43270
|
const packageCandidates = [
|
|
43081
43271
|
join11(currentDirectory, "..", "package.json"),
|
|
43082
43272
|
join11(currentDirectory, "..", "..", "package.json")
|
|
@@ -43338,6 +43528,7 @@ async function upgrade() {
|
|
|
43338
43528
|
}
|
|
43339
43529
|
const godot = await engine(projectPath);
|
|
43340
43530
|
console.log(installed === version ? `already ${version}; reinstalling` : `${installed} -> ${version}`);
|
|
43531
|
+
const digestBefore = installedEditorDigest(projectPath);
|
|
43341
43532
|
for (const addon of installAddons(projectPath)) {
|
|
43342
43533
|
console.log(`${addon.replaced ? "replaced" : "installed"} ${addon.path}`);
|
|
43343
43534
|
}
|
|
@@ -43369,8 +43560,10 @@ async function upgrade() {
|
|
|
43369
43560
|
console.log(`skill: ${written.replaced ? "replaced" : "written"} ${written.path}`);
|
|
43370
43561
|
}
|
|
43371
43562
|
console.log(`
|
|
43372
|
-
On ${version}.
|
|
43373
|
-
console.log(` 1.
|
|
43563
|
+
On ${version}. What is left for you:`);
|
|
43564
|
+
console.log(digestBefore !== null && digestBefore === installedEditorDigest(projectPath) ? ` 1. Nothing for the editor: this upgrade left the editor addons the same code as before,
|
|
43565
|
+
` + ` so it gives an open editor nothing to restart for. editor_status says addonIsStale
|
|
43566
|
+
` + " if the editor is older than that." : ` 1. The open editor is still running the addons it loaded at startup. Restart it with the
|
|
43374
43567
|
` + " editor_launch restart tool, which closes and reopens the window.");
|
|
43375
43568
|
console.log(harnessNote({ moved, written, byHand }, [launch.command, ...launch.args].join(" ")));
|
|
43376
43569
|
}
|