gdharness 1.0.15 → 1.0.17
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 +679 -600
- package/build/index.js +35 -12
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -47,10 +47,233 @@ var __esm = (fn, res, err) => () => {
|
|
|
47
47
|
};
|
|
48
48
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
49
49
|
|
|
50
|
+
// src/errors.ts
|
|
51
|
+
function errorMessage(error, fallback = "Unknown error") {
|
|
52
|
+
if (error instanceof Error) {
|
|
53
|
+
return error.message || fallback;
|
|
54
|
+
}
|
|
55
|
+
if (typeof error === "string") {
|
|
56
|
+
return error || fallback;
|
|
57
|
+
}
|
|
58
|
+
if (typeof error === "number" || typeof error === "boolean") {
|
|
59
|
+
return String(error);
|
|
60
|
+
}
|
|
61
|
+
return fallback;
|
|
62
|
+
}
|
|
63
|
+
function toError(error) {
|
|
64
|
+
return error instanceof Error ? error : new Error(errorMessage(error), { cause: error });
|
|
65
|
+
}
|
|
66
|
+
var Refusal;
|
|
67
|
+
var init_errors = __esm(() => {
|
|
68
|
+
Refusal = class Refusal extends Error {
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// src/process-children.ts
|
|
73
|
+
import { execFile, execFileSync, spawnSync } from "node:child_process";
|
|
74
|
+
import { basename } from "node:path";
|
|
75
|
+
import { promisify } from "node:util";
|
|
76
|
+
function startTimesOf(pids) {
|
|
77
|
+
const began = new Map;
|
|
78
|
+
if (pids.length === 0) {
|
|
79
|
+
return began;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
if (process.platform === "win32") {
|
|
83
|
+
const filter = pids.map((pid) => `ProcessId=${pid}`).join(" OR ");
|
|
84
|
+
const said = execFileSync("powershell", [
|
|
85
|
+
"-NoProfile",
|
|
86
|
+
"-NonInteractive",
|
|
87
|
+
"-Command",
|
|
88
|
+
`Get-CimInstance Win32_Process -Filter "${filter}" | ForEach-Object { "$($_.ProcessId) $(([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds())" }`
|
|
89
|
+
], { encoding: "utf8", timeout: ASK_TIMEOUT_MS, windowsHide: true });
|
|
90
|
+
for (const line of said.split(`
|
|
91
|
+
`)) {
|
|
92
|
+
const found = /^\s*(\d+)\s+(\d+)\s*$/.exec(line);
|
|
93
|
+
if (found?.[1] !== undefined && found[2] !== undefined) {
|
|
94
|
+
began.set(Number(found[1]), Number(found[2]));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return began;
|
|
98
|
+
}
|
|
99
|
+
const said = spawnSync("ps", ["-p", pids.join(","), "-o", "pid=,lstart="], {
|
|
100
|
+
encoding: "utf8",
|
|
101
|
+
timeout: ASK_TIMEOUT_MS,
|
|
102
|
+
env: { ...process.env, LC_ALL: "C" }
|
|
103
|
+
}).stdout;
|
|
104
|
+
for (const line of said.split(`
|
|
105
|
+
`)) {
|
|
106
|
+
const found = /^\s*(\d+)\s+(.+)$/.exec(line);
|
|
107
|
+
const at = Date.parse(found?.[2]?.trim() ?? "");
|
|
108
|
+
if (found?.[1] !== undefined && !Number.isNaN(at)) {
|
|
109
|
+
began.set(Number(found[1]), at);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} catch {}
|
|
113
|
+
return began;
|
|
114
|
+
}
|
|
115
|
+
async function processTree() {
|
|
116
|
+
try {
|
|
117
|
+
if (process.platform === "win32") {
|
|
118
|
+
return parseProcessTable(await askWindows(), true);
|
|
119
|
+
}
|
|
120
|
+
return parseProcessTable(await askPosix());
|
|
121
|
+
} catch {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function parseProcessTable(printed, started = false) {
|
|
126
|
+
const tree = new Map;
|
|
127
|
+
for (const line of printed.split(/\r?\n/)) {
|
|
128
|
+
const fields = /^\s*(\d+)\s+(\d+)(?:\s+(.*))?$/.exec(line);
|
|
129
|
+
if (fields === null) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const pid = Number(fields[1]);
|
|
133
|
+
const parent = Number(fields[2]);
|
|
134
|
+
const rest = (fields[3] ?? "").trim();
|
|
135
|
+
if (pid <= 0) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (!started) {
|
|
139
|
+
tree.set(pid, { parent, command: rest });
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const timed = /^(\d+)(?:\s+(.*))?$/.exec(rest);
|
|
143
|
+
if (timed === null) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const began = Number(timed[1]);
|
|
147
|
+
tree.set(pid, { parent, command: (timed[2] ?? "").trim(), ...began > 0 ? { startedAt: began } : {} });
|
|
148
|
+
}
|
|
149
|
+
return tree;
|
|
150
|
+
}
|
|
151
|
+
function linked(tree, child, parent) {
|
|
152
|
+
const from = tree.get(child);
|
|
153
|
+
const to = tree.get(parent);
|
|
154
|
+
if (from === undefined || from.parent !== parent) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if (from.startedAt === undefined || to?.startedAt === undefined) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
return from.startedAt >= to.startedAt;
|
|
161
|
+
}
|
|
162
|
+
function childrenIn(tree, pid) {
|
|
163
|
+
const children = [];
|
|
164
|
+
for (const child of tree.keys()) {
|
|
165
|
+
if (linked(tree, child, pid)) {
|
|
166
|
+
children.push(child);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return children;
|
|
170
|
+
}
|
|
171
|
+
function descendantsIn(tree, pid) {
|
|
172
|
+
const found = [];
|
|
173
|
+
const queue = [pid];
|
|
174
|
+
const seen = new Set([pid]);
|
|
175
|
+
while (queue.length > 0) {
|
|
176
|
+
const next = queue.shift();
|
|
177
|
+
if (next === undefined) {
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
for (const child of childrenIn(tree, next)) {
|
|
181
|
+
if (!seen.has(child)) {
|
|
182
|
+
seen.add(child);
|
|
183
|
+
found.push(child);
|
|
184
|
+
queue.push(child);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return found;
|
|
189
|
+
}
|
|
190
|
+
function ancestorsIn(tree, pid, root) {
|
|
191
|
+
const chain = [];
|
|
192
|
+
const seen = new Set([pid]);
|
|
193
|
+
let child = pid;
|
|
194
|
+
let parent = tree.get(pid)?.parent;
|
|
195
|
+
while (parent !== undefined && !seen.has(parent) && linked(tree, child, parent)) {
|
|
196
|
+
chain.push(parent);
|
|
197
|
+
if (parent === root) {
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
seen.add(parent);
|
|
201
|
+
child = parent;
|
|
202
|
+
parent = tree.get(parent)?.parent;
|
|
203
|
+
}
|
|
204
|
+
return chain;
|
|
205
|
+
}
|
|
206
|
+
function readCommandLine(command) {
|
|
207
|
+
const words = commandWords(command);
|
|
208
|
+
const executable = words[0] === undefined ? "" : basename(words[0].replaceAll("\\", "/"));
|
|
209
|
+
const at = words.indexOf("--path");
|
|
210
|
+
let projectPath = null;
|
|
211
|
+
if (at !== -1 && at + 1 < words.length) {
|
|
212
|
+
const taken = [];
|
|
213
|
+
for (const word of words.slice(at + 1)) {
|
|
214
|
+
if (taken.length > 0 && (word.startsWith("-") || /^[a-z]+:\/\//.test(word))) {
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
taken.push(word);
|
|
218
|
+
}
|
|
219
|
+
projectPath = taken.join(" ");
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
executable,
|
|
223
|
+
projectPath,
|
|
224
|
+
editor: words.some((word) => word === "-e" || word === "--editor")
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function commandWords(command) {
|
|
228
|
+
const words = [];
|
|
229
|
+
let word = "";
|
|
230
|
+
let quoted = false;
|
|
231
|
+
let started = false;
|
|
232
|
+
for (const char of command) {
|
|
233
|
+
if (char === '"') {
|
|
234
|
+
quoted = !quoted;
|
|
235
|
+
started = true;
|
|
236
|
+
} else if (!quoted && /\s/.test(char)) {
|
|
237
|
+
if (started) {
|
|
238
|
+
words.push(word);
|
|
239
|
+
word = "";
|
|
240
|
+
started = false;
|
|
241
|
+
}
|
|
242
|
+
} else {
|
|
243
|
+
word += char;
|
|
244
|
+
started = true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (started) {
|
|
248
|
+
words.push(word);
|
|
249
|
+
}
|
|
250
|
+
return words;
|
|
251
|
+
}
|
|
252
|
+
async function askWindows() {
|
|
253
|
+
const { stdout } = await run("powershell.exe", [
|
|
254
|
+
"-NoProfile",
|
|
255
|
+
"-NonInteractive",
|
|
256
|
+
"-Command",
|
|
257
|
+
`${POWERSHELL_UTF8}Get-CimInstance Win32_Process | ForEach-Object { $began = 0; if ($_.CreationDate) { $began = ([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds() }; "$($_.ProcessId) $($_.ParentProcessId) $began $($_.CommandLine)" }`
|
|
258
|
+
], { timeout: ASK_TIMEOUT_MS, windowsHide: true, maxBuffer: 16 * 1024 * 1024 });
|
|
259
|
+
return stdout;
|
|
260
|
+
}
|
|
261
|
+
async function askPosix() {
|
|
262
|
+
const { stdout } = await run("ps", ["-e", "-o", "pid=,ppid=,args="], {
|
|
263
|
+
timeout: ASK_TIMEOUT_MS,
|
|
264
|
+
maxBuffer: 16 * 1024 * 1024
|
|
265
|
+
});
|
|
266
|
+
return stdout;
|
|
267
|
+
}
|
|
268
|
+
var run, POWERSHELL_UTF8 = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ", ASK_TIMEOUT_MS = 15000;
|
|
269
|
+
var init_process_children = __esm(() => {
|
|
270
|
+
run = promisify(execFile);
|
|
271
|
+
});
|
|
272
|
+
|
|
50
273
|
// src/detection.ts
|
|
51
274
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
52
275
|
import { homedir } from "node:os";
|
|
53
|
-
import { join } from "node:path";
|
|
276
|
+
import { join as join2 } from "node:path";
|
|
54
277
|
function resolveHomeDirectory() {
|
|
55
278
|
try {
|
|
56
279
|
return homedir();
|
|
@@ -74,7 +297,7 @@ function scanDirectoryForGodotBinaries(directory, platform) {
|
|
|
74
297
|
if (!pattern.test(name)) {
|
|
75
298
|
continue;
|
|
76
299
|
}
|
|
77
|
-
const fullPath =
|
|
300
|
+
const fullPath = join2(directory, name);
|
|
78
301
|
try {
|
|
79
302
|
const stat = statSync(fullPath);
|
|
80
303
|
if (stat.isFile()) {
|
|
@@ -83,7 +306,7 @@ function scanDirectoryForGodotBinaries(directory, platform) {
|
|
|
83
306
|
} catch {}
|
|
84
307
|
}
|
|
85
308
|
matches.sort((a, b) => b.mtime - a.mtime);
|
|
86
|
-
return matches.map((m) =>
|
|
309
|
+
return matches.map((m) => join2(directory, m.name));
|
|
87
310
|
}
|
|
88
311
|
function conventionalPaths(platform, home) {
|
|
89
312
|
const paths = ["godot"];
|
|
@@ -133,28 +356,6 @@ function godotCandidates(platform, home) {
|
|
|
133
356
|
}
|
|
134
357
|
var init_detection = () => {};
|
|
135
358
|
|
|
136
|
-
// src/errors.ts
|
|
137
|
-
function errorMessage(error, fallback = "Unknown error") {
|
|
138
|
-
if (error instanceof Error) {
|
|
139
|
-
return error.message || fallback;
|
|
140
|
-
}
|
|
141
|
-
if (typeof error === "string") {
|
|
142
|
-
return error || fallback;
|
|
143
|
-
}
|
|
144
|
-
if (typeof error === "number" || typeof error === "boolean") {
|
|
145
|
-
return String(error);
|
|
146
|
-
}
|
|
147
|
-
return fallback;
|
|
148
|
-
}
|
|
149
|
-
function toError(error) {
|
|
150
|
-
return error instanceof Error ? error : new Error(errorMessage(error), { cause: error });
|
|
151
|
-
}
|
|
152
|
-
var Refusal2;
|
|
153
|
-
var init_errors = __esm(() => {
|
|
154
|
-
Refusal2 = class Refusal2 extends Error {
|
|
155
|
-
};
|
|
156
|
-
});
|
|
157
|
-
|
|
158
359
|
// src/launch.ts
|
|
159
360
|
function envValue(name, variables = process.env) {
|
|
160
361
|
const value = variables[name];
|
|
@@ -7161,7 +7362,7 @@ var require_public_api = __commonJS(function(exports) {
|
|
|
7161
7362
|
|
|
7162
7363
|
// src/runner.ts
|
|
7163
7364
|
import { existsSync as existsSync3 } from "node:fs";
|
|
7164
|
-
import { dirname, join as
|
|
7365
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
7165
7366
|
import process2 from "node:process";
|
|
7166
7367
|
function currentRunner() {
|
|
7167
7368
|
const versions = process2.versions;
|
|
@@ -7182,11 +7383,24 @@ function spawnFor(runner, version, execPath = process2.execPath) {
|
|
|
7182
7383
|
return { command: alongside(execPath, "npx") ?? "npx", args: ["-y", spec] };
|
|
7183
7384
|
}
|
|
7184
7385
|
function alongside(execPath, name) {
|
|
7185
|
-
const runner =
|
|
7386
|
+
const runner = join3(dirname2(execPath), process2.platform === "win32" ? `${name}.cmd` : name);
|
|
7186
7387
|
return existsSync3(runner) ? runner : undefined;
|
|
7187
7388
|
}
|
|
7188
7389
|
var init_runner = () => {};
|
|
7189
7390
|
|
|
7391
|
+
// src/call-signal.ts
|
|
7392
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7393
|
+
function withCallSignal(signal, answer) {
|
|
7394
|
+
return signal === undefined ? answer() : current.run(signal, answer);
|
|
7395
|
+
}
|
|
7396
|
+
function callSignal() {
|
|
7397
|
+
return current.getStore();
|
|
7398
|
+
}
|
|
7399
|
+
var current;
|
|
7400
|
+
var init_call_signal = __esm(() => {
|
|
7401
|
+
current = new AsyncLocalStorage;
|
|
7402
|
+
});
|
|
7403
|
+
|
|
7190
7404
|
// src/dictionary.ts
|
|
7191
7405
|
function emptyRecord() {
|
|
7192
7406
|
return Object.create(null);
|
|
@@ -7311,7 +7525,7 @@ var init_game_log = __esm(() => {
|
|
|
7311
7525
|
});
|
|
7312
7526
|
|
|
7313
7527
|
// src/scratch.ts
|
|
7314
|
-
import { rmSync as
|
|
7528
|
+
import { rmSync as rmSync3 } from "node:fs";
|
|
7315
7529
|
function discardWith(remove, paths) {
|
|
7316
7530
|
const left = [];
|
|
7317
7531
|
for (const path of paths) {
|
|
@@ -7328,7 +7542,7 @@ function discardWith(remove, paths) {
|
|
|
7328
7542
|
}
|
|
7329
7543
|
function discard(...paths) {
|
|
7330
7544
|
return discardWith((path) => {
|
|
7331
|
-
|
|
7545
|
+
rmSync3(path, SWEPT);
|
|
7332
7546
|
}, paths);
|
|
7333
7547
|
}
|
|
7334
7548
|
var SWEPT;
|
|
@@ -7337,9 +7551,9 @@ var init_scratch = __esm(() => {
|
|
|
7337
7551
|
});
|
|
7338
7552
|
|
|
7339
7553
|
// src/update-check.ts
|
|
7340
|
-
import { existsSync as existsSync5, mkdirSync as
|
|
7554
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
7341
7555
|
import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
|
|
7342
|
-
import { join as
|
|
7556
|
+
import { join as join6 } from "node:path";
|
|
7343
7557
|
function packageUrl(root) {
|
|
7344
7558
|
return `${root.replace(/\/+$/, "")}/gdharness/latest`;
|
|
7345
7559
|
}
|
|
@@ -7361,20 +7575,20 @@ function cacheDirectory(environment) {
|
|
|
7361
7575
|
};
|
|
7362
7576
|
const home = set("HOME") ?? homedir3();
|
|
7363
7577
|
if (process.platform === "win32") {
|
|
7364
|
-
return
|
|
7578
|
+
return join6(set("LOCALAPPDATA") ?? home, "gdharness");
|
|
7365
7579
|
}
|
|
7366
7580
|
if (process.platform === "darwin") {
|
|
7367
|
-
return
|
|
7581
|
+
return join6(home, "Library", "Caches", "gdharness");
|
|
7368
7582
|
}
|
|
7369
|
-
return
|
|
7583
|
+
return join6(set("XDG_CACHE_HOME") ?? join6(home, ".cache"), "gdharness");
|
|
7370
7584
|
}
|
|
7371
7585
|
function cacheFile(environment = process.env) {
|
|
7372
7586
|
try {
|
|
7373
7587
|
const directory = cacheDirectory(environment);
|
|
7374
|
-
|
|
7375
|
-
return
|
|
7588
|
+
mkdirSync3(directory, { recursive: true, mode: 448 });
|
|
7589
|
+
return join6(directory, "update-check.json");
|
|
7376
7590
|
} catch {
|
|
7377
|
-
return
|
|
7591
|
+
return join6(tmpdir2(), "gdharness-update-check.json");
|
|
7378
7592
|
}
|
|
7379
7593
|
}
|
|
7380
7594
|
function readCache(path) {
|
|
@@ -7382,7 +7596,7 @@ function readCache(path) {
|
|
|
7382
7596
|
if (!existsSync5(path)) {
|
|
7383
7597
|
return null;
|
|
7384
7598
|
}
|
|
7385
|
-
const parsed = JSON.parse(
|
|
7599
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
7386
7600
|
if (typeof parsed !== "object" || parsed === null) {
|
|
7387
7601
|
return null;
|
|
7388
7602
|
}
|
|
@@ -7399,7 +7613,7 @@ function readCache(path) {
|
|
|
7399
7613
|
}
|
|
7400
7614
|
function writeCache(path, entry) {
|
|
7401
7615
|
try {
|
|
7402
|
-
|
|
7616
|
+
writeFileSync4(path, JSON.stringify(entry), { encoding: "utf8", mode: 384 });
|
|
7403
7617
|
} catch {}
|
|
7404
7618
|
}
|
|
7405
7619
|
function parts(version) {
|
|
@@ -7530,7 +7744,7 @@ var init_update_check = __esm(() => {
|
|
|
7530
7744
|
});
|
|
7531
7745
|
|
|
7532
7746
|
// src/server-version.ts
|
|
7533
|
-
import { readFileSync as
|
|
7747
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
7534
7748
|
function editorIsStale(addonVersion, serverVersion, addonDigest, shippedDigest) {
|
|
7535
7749
|
if (addonDigest !== undefined && addonDigest !== "" && shippedDigest !== undefined) {
|
|
7536
7750
|
return addonDigest !== shippedDigest;
|
|
@@ -7566,7 +7780,7 @@ var init_server_version = __esm(() => {
|
|
|
7566
7780
|
GODOT_DEBUG_MODE_DEFAULT = process.env["GODOT_DEBUG"] === "true" || DEBUG_MODE;
|
|
7567
7781
|
SERVER_VERSION = (() => {
|
|
7568
7782
|
try {
|
|
7569
|
-
const pkg = JSON.parse(
|
|
7783
|
+
const pkg = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8"));
|
|
7570
7784
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
7571
7785
|
} catch {
|
|
7572
7786
|
return "0.0.0";
|
|
@@ -7575,23 +7789,23 @@ var init_server_version = __esm(() => {
|
|
|
7575
7789
|
});
|
|
7576
7790
|
|
|
7577
7791
|
// src/class-cache.ts
|
|
7578
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as
|
|
7579
|
-
import { join as
|
|
7792
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2 } from "node:fs";
|
|
7793
|
+
import { join as join7 } from "node:path";
|
|
7580
7794
|
function declaredClasses(projectPath) {
|
|
7581
7795
|
const declared = new Map;
|
|
7582
7796
|
const visit = (directory, prefix) => {
|
|
7583
|
-
if (existsSync6(
|
|
7797
|
+
if (existsSync6(join7(directory, ".gdignore"))) {
|
|
7584
7798
|
return;
|
|
7585
7799
|
}
|
|
7586
7800
|
for (const entry of readdirSync2(directory, { withFileTypes: true })) {
|
|
7587
7801
|
if (entry.name.startsWith(".")) {
|
|
7588
7802
|
continue;
|
|
7589
7803
|
}
|
|
7590
|
-
const path =
|
|
7804
|
+
const path = join7(directory, entry.name);
|
|
7591
7805
|
if (entry.isDirectory()) {
|
|
7592
7806
|
visit(path, `${prefix}${entry.name}/`);
|
|
7593
7807
|
} else if (entry.isFile() && entry.name.endsWith(".gd")) {
|
|
7594
|
-
const found = DECLARATION.exec(
|
|
7808
|
+
const found = DECLARATION.exec(readFileSync6(path, "utf8"));
|
|
7595
7809
|
if (found?.[1]) {
|
|
7596
7810
|
declared.set(found[1], `res://${prefix}${entry.name}`);
|
|
7597
7811
|
}
|
|
@@ -7602,12 +7816,12 @@ function declaredClasses(projectPath) {
|
|
|
7602
7816
|
return declared;
|
|
7603
7817
|
}
|
|
7604
7818
|
function cachedClasses(projectPath) {
|
|
7605
|
-
const cache =
|
|
7819
|
+
const cache = join7(projectPath, ".godot", "global_script_class_cache.cfg");
|
|
7606
7820
|
if (!existsSync6(cache)) {
|
|
7607
7821
|
return null;
|
|
7608
7822
|
}
|
|
7609
7823
|
const listed = new Map;
|
|
7610
|
-
const text =
|
|
7824
|
+
const text = readFileSync6(cache, "utf8");
|
|
7611
7825
|
for (const entry of text.matchAll(/"class":\s*&"([^"]+)"[\s\S]*?"path":\s*"([^"]+)"/g)) {
|
|
7612
7826
|
listed.set(entry[1] ?? "", entry[2] ?? "");
|
|
7613
7827
|
}
|
|
@@ -7692,7 +7906,7 @@ function uncachedClassNote(types) {
|
|
|
7692
7906
|
return `${types.join(", ")} ${one ? "is declared" : "are declared"} in this project and missing from ` + `.godot/global_script_class_cache.cfg, so a game launched now would not resolve ${one ? "it" : "them"} ` + "either. Try editor_rescan first: it asks the editor already running and starts nothing, and it " + "cleared this in 314ms in a second project with a 31-worker fan-out still importing. It is not " + "always enough, because a file another engine has already imported reads as settled and the " + "walk does not look inside it. project_import refresh_classes rewrites the cache from the " + "declarations on disk and does reach that case, at the cost of a short headless engine, which " + "is worth knowing when something else is already running against this project.";
|
|
7693
7907
|
}
|
|
7694
7908
|
function cacheWrittenAt(projectPath) {
|
|
7695
|
-
const cache =
|
|
7909
|
+
const cache = join7(projectPath, ".godot", "global_script_class_cache.cfg");
|
|
7696
7910
|
try {
|
|
7697
7911
|
return statSync2(cache).mtimeMs;
|
|
7698
7912
|
} catch {
|
|
@@ -7706,14 +7920,14 @@ function declaredSince(projectPath, paths, names, since) {
|
|
|
7706
7920
|
return false;
|
|
7707
7921
|
}
|
|
7708
7922
|
try {
|
|
7709
|
-
return statSync2(
|
|
7923
|
+
return statSync2(join7(projectPath, path.slice("res://".length))).mtimeMs > since;
|
|
7710
7924
|
} catch {
|
|
7711
7925
|
return false;
|
|
7712
7926
|
}
|
|
7713
7927
|
});
|
|
7714
7928
|
}
|
|
7715
7929
|
function cachedAtMissingPaths(cached, projectPath) {
|
|
7716
|
-
return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync6(
|
|
7930
|
+
return [...cached].filter(([, path]) => path.startsWith("res://") && !existsSync6(join7(projectPath, path.slice("res://".length)))).map(([name]) => name).sort();
|
|
7717
7931
|
}
|
|
7718
7932
|
function staleAgainst(cached, projectPath) {
|
|
7719
7933
|
return [...declaredClasses(projectPath)].filter(([name, path]) => cached.get(name) !== path).map(([name]) => name);
|
|
@@ -7736,11 +7950,11 @@ var init_class_cache = __esm(() => {
|
|
|
7736
7950
|
});
|
|
7737
7951
|
|
|
7738
7952
|
// src/headless.ts
|
|
7739
|
-
import { execFile as
|
|
7740
|
-
import { mkdtempSync as mkdtempSync2, writeFileSync as
|
|
7953
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
7954
|
+
import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
7741
7955
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
7742
|
-
import { join as
|
|
7743
|
-
import { promisify as
|
|
7956
|
+
import { join as join8 } from "node:path";
|
|
7957
|
+
import { promisify as promisify4 } from "node:util";
|
|
7744
7958
|
function snakeCased2(params) {
|
|
7745
7959
|
const result = emptyRecord();
|
|
7746
7960
|
for (const [key, value] of Object.entries(params)) {
|
|
@@ -7779,16 +7993,9 @@ function reason2(stdout, stderr) {
|
|
|
7779
7993
|
return stdout.trim().split(/\r?\n/).at(-1) ?? "no output at all";
|
|
7780
7994
|
}
|
|
7781
7995
|
async function runImport(godotPath, projectPath) {
|
|
7782
|
-
const logDir = mkdtempSync2(
|
|
7996
|
+
const logDir = mkdtempSync2(join8(tmpdir3(), "gdharness-import-"));
|
|
7783
7997
|
try {
|
|
7784
|
-
const { stderr } = await
|
|
7785
|
-
"--headless",
|
|
7786
|
-
"--log-file",
|
|
7787
|
-
join7(logDir, "engine.log"),
|
|
7788
|
-
"--path",
|
|
7789
|
-
projectPath,
|
|
7790
|
-
"--import"
|
|
7791
|
-
]);
|
|
7998
|
+
const { stderr } = await run4(godotPath, ["--headless", "--log-file", join8(logDir, "engine.log"), "--path", projectPath, "--import"], { signal: callSignal() });
|
|
7792
7999
|
return { ok: true, messages: problems2(stderr) };
|
|
7793
8000
|
} catch (error) {
|
|
7794
8001
|
if (error instanceof Error && "stdout" in error && "stderr" in error) {
|
|
@@ -7809,13 +8016,13 @@ async function runImport(godotPath, projectPath) {
|
|
|
7809
8016
|
}
|
|
7810
8017
|
}
|
|
7811
8018
|
async function runOperation2(engine, operation, params, projectPath) {
|
|
7812
|
-
const paramsDir = mkdtempSync2(
|
|
7813
|
-
const paramsFile =
|
|
7814
|
-
|
|
8019
|
+
const paramsDir = mkdtempSync2(join8(tmpdir3(), "gdharness-params-"));
|
|
8020
|
+
const paramsFile = join8(paramsDir, `${operation}.json`);
|
|
8021
|
+
writeFileSync5(paramsFile, JSON.stringify(snakeCased2(params)), "utf8");
|
|
7815
8022
|
const args = [
|
|
7816
8023
|
"--headless",
|
|
7817
8024
|
"--log-file",
|
|
7818
|
-
|
|
8025
|
+
join8(paramsDir, "engine.log"),
|
|
7819
8026
|
"--path",
|
|
7820
8027
|
projectPath,
|
|
7821
8028
|
"--script",
|
|
@@ -7827,7 +8034,7 @@ async function runOperation2(engine, operation, params, projectPath) {
|
|
|
7827
8034
|
let stdout;
|
|
7828
8035
|
let stderr;
|
|
7829
8036
|
try {
|
|
7830
|
-
({ stdout, stderr } = await
|
|
8037
|
+
({ stdout, stderr } = await run4(engine.godotPath, args, { signal: callSignal() }));
|
|
7831
8038
|
} catch (error) {
|
|
7832
8039
|
if (error instanceof Error && "stdout" in error && "stderr" in error) {
|
|
7833
8040
|
const failed = error;
|
|
@@ -7855,11 +8062,12 @@ async function runOperation2(engine, operation, params, projectPath) {
|
|
|
7855
8062
|
}
|
|
7856
8063
|
return { ok: true, payload, messages: problems2(stderr) };
|
|
7857
8064
|
}
|
|
7858
|
-
var
|
|
8065
|
+
var run4;
|
|
7859
8066
|
var init_headless = __esm(() => {
|
|
8067
|
+
init_call_signal();
|
|
7860
8068
|
init_game_log();
|
|
7861
8069
|
init_scratch();
|
|
7862
|
-
|
|
8070
|
+
run4 = promisify4(execFile4);
|
|
7863
8071
|
});
|
|
7864
8072
|
|
|
7865
8073
|
// node_modules/zod/v4/core/util.js
|
|
@@ -15027,26 +15235,26 @@ var init_paths = __esm(() => {
|
|
|
15027
15235
|
});
|
|
15028
15236
|
|
|
15029
15237
|
// src/resources.ts
|
|
15030
|
-
import { readFileSync as
|
|
15238
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
15031
15239
|
import { extname, resolve as resolve2 } from "node:path";
|
|
15032
15240
|
function ensureProjectPath(getProjectPath) {
|
|
15033
15241
|
const projectPath = getProjectPath();
|
|
15034
15242
|
if (!projectPath) {
|
|
15035
|
-
throw new
|
|
15243
|
+
throw new Refusal("Project path is not set. Set a Godot project path first.");
|
|
15036
15244
|
}
|
|
15037
15245
|
return resolve2(projectPath);
|
|
15038
15246
|
}
|
|
15039
15247
|
function uriPathToProjectPath(inputPath) {
|
|
15040
15248
|
const normalized = inputPath.replace(/\\/g, "/").trim();
|
|
15041
15249
|
if (normalized.replace(/\//g, "") === "") {
|
|
15042
|
-
throw new
|
|
15250
|
+
throw new Refusal("Resource path is empty.");
|
|
15043
15251
|
}
|
|
15044
15252
|
return normalized.replace(/^\/+/, "");
|
|
15045
15253
|
}
|
|
15046
15254
|
function resolveProjectFile(projectPath, resourcePath) {
|
|
15047
15255
|
const contained = resolveWithinProject(projectPath, resourcePath);
|
|
15048
15256
|
if (!contained.ok) {
|
|
15049
|
-
throw new
|
|
15257
|
+
throw new Refusal(contained.reason);
|
|
15050
15258
|
}
|
|
15051
15259
|
return contained.absolutePath;
|
|
15052
15260
|
}
|
|
@@ -15058,14 +15266,14 @@ function parseGodotUri(uri) {
|
|
|
15058
15266
|
try {
|
|
15059
15267
|
parsed = new URL(uri);
|
|
15060
15268
|
} catch {
|
|
15061
|
-
throw new
|
|
15269
|
+
throw new Refusal(`Invalid URI: ${uri}`);
|
|
15062
15270
|
}
|
|
15063
15271
|
if (parsed.protocol !== "godot:") {
|
|
15064
|
-
throw new
|
|
15272
|
+
throw new Refusal(`Unsupported URI scheme: ${parsed.protocol}`);
|
|
15065
15273
|
}
|
|
15066
15274
|
const host = parsed.hostname;
|
|
15067
15275
|
if (host !== "scene" && host !== "script" && host !== "resource") {
|
|
15068
|
-
throw new
|
|
15276
|
+
throw new Refusal(`Unsupported Godot resource type: ${host}`);
|
|
15069
15277
|
}
|
|
15070
15278
|
const resourcePath = uriPathToProjectPath(decodeURIComponent(parsed.pathname));
|
|
15071
15279
|
return { kind: host, resourcePath };
|
|
@@ -15073,13 +15281,13 @@ function parseGodotUri(uri) {
|
|
|
15073
15281
|
function ensureAllowedExtension(kind, filePath) {
|
|
15074
15282
|
const extension = extname(filePath).toLowerCase();
|
|
15075
15283
|
if (kind === "scene" && extension !== ".tscn") {
|
|
15076
|
-
throw new
|
|
15284
|
+
throw new Refusal("Scene resources must use .tscn extension.");
|
|
15077
15285
|
}
|
|
15078
15286
|
if (kind === "script" && extension !== ".gd") {
|
|
15079
|
-
throw new
|
|
15287
|
+
throw new Refusal("Script resources must use .gd extension.");
|
|
15080
15288
|
}
|
|
15081
15289
|
if (kind === "resource" && ![".tres", ".tscn", ".gd"].includes(extension)) {
|
|
15082
|
-
throw new
|
|
15290
|
+
throw new Refusal("Resource URIs support only .tres, .tscn, and .gd files.");
|
|
15083
15291
|
}
|
|
15084
15292
|
}
|
|
15085
15293
|
function isValueComplete(value) {
|
|
@@ -15193,7 +15401,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
15193
15401
|
const parsedUri = parseGodotUri(uri);
|
|
15194
15402
|
if (parsedUri.kind === "project-info") {
|
|
15195
15403
|
const projectFilePath = resolveProjectFile(projectPath, "project.godot");
|
|
15196
|
-
const rawProject =
|
|
15404
|
+
const rawProject = readFileSync7(projectFilePath, "utf-8");
|
|
15197
15405
|
const parsedProject = parseProjectGodot(rawProject);
|
|
15198
15406
|
return {
|
|
15199
15407
|
mimeType: "application/json",
|
|
@@ -15202,7 +15410,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
15202
15410
|
}
|
|
15203
15411
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
15204
15412
|
ensureAllowedExtension(parsedUri.kind, filePath);
|
|
15205
|
-
const text =
|
|
15413
|
+
const text = readFileSync7(filePath, "utf-8");
|
|
15206
15414
|
return {
|
|
15207
15415
|
mimeType: parsedUri.kind === "script" ? "text/x-gdscript" : "text/plain",
|
|
15208
15416
|
text
|
|
@@ -15231,9 +15439,9 @@ function setupResourceHandlers(mcp, getProjectPath) {
|
|
|
15231
15439
|
};
|
|
15232
15440
|
} catch (error) {
|
|
15233
15441
|
if (error instanceof Error) {
|
|
15234
|
-
throw new
|
|
15442
|
+
throw new Refusal(`Failed to read resource '${uri}': ${error.message}`, { cause: error });
|
|
15235
15443
|
}
|
|
15236
|
-
throw new
|
|
15444
|
+
throw new Refusal(`Failed to read resource '${uri}'.`, { cause: error });
|
|
15237
15445
|
}
|
|
15238
15446
|
});
|
|
15239
15447
|
}
|
|
@@ -15334,14 +15542,14 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
15334
15542
|
import {
|
|
15335
15543
|
cpSync as cpSync2,
|
|
15336
15544
|
existsSync as existsSync8,
|
|
15337
|
-
mkdirSync as
|
|
15545
|
+
mkdirSync as mkdirSync5,
|
|
15338
15546
|
readdirSync as readdirSync4,
|
|
15339
|
-
readFileSync as
|
|
15340
|
-
rmSync as
|
|
15547
|
+
readFileSync as readFileSync9,
|
|
15548
|
+
rmSync as rmSync5,
|
|
15341
15549
|
statSync as statSync4,
|
|
15342
|
-
writeFileSync as
|
|
15550
|
+
writeFileSync as writeFileSync7
|
|
15343
15551
|
} from "node:fs";
|
|
15344
|
-
import { dirname as
|
|
15552
|
+
import { dirname as dirname5, join as join10 } from "node:path";
|
|
15345
15553
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15346
15554
|
function editorAddonDigest2(from = shippedAddonsDirectory2()) {
|
|
15347
15555
|
const hash = createHash3("sha256");
|
|
@@ -15350,21 +15558,21 @@ function editorAddonDigest2(from = shippedAddonsDirectory2()) {
|
|
|
15350
15558
|
if (name === VERSION_MARKER2 || name === DIGEST_MARKER2) {
|
|
15351
15559
|
continue;
|
|
15352
15560
|
}
|
|
15353
|
-
const path =
|
|
15561
|
+
const path = join10(directory, name);
|
|
15354
15562
|
const inside = `${relative}/${name}`;
|
|
15355
15563
|
if (statSync4(path).isDirectory()) {
|
|
15356
15564
|
walk(path, inside);
|
|
15357
15565
|
} else {
|
|
15358
15566
|
hash.update(`${inside}
|
|
15359
15567
|
`);
|
|
15360
|
-
hash.update(
|
|
15568
|
+
hash.update(readFileSync9(path));
|
|
15361
15569
|
hash.update(`
|
|
15362
15570
|
`);
|
|
15363
15571
|
}
|
|
15364
15572
|
}
|
|
15365
15573
|
};
|
|
15366
15574
|
for (const name of EDITOR_PLUGINS2) {
|
|
15367
|
-
walk(
|
|
15575
|
+
walk(join10(from, name), name);
|
|
15368
15576
|
}
|
|
15369
15577
|
return hash.digest("hex");
|
|
15370
15578
|
}
|
|
@@ -15379,14 +15587,14 @@ function shippedEditorDigest() {
|
|
|
15379
15587
|
return shippedDigest ?? undefined;
|
|
15380
15588
|
}
|
|
15381
15589
|
function shippedAddonsDirectory2() {
|
|
15382
|
-
return
|
|
15590
|
+
return join10(dirname5(fileURLToPath2(import.meta.url)), "godot", "addons");
|
|
15383
15591
|
}
|
|
15384
15592
|
function installedAddonVersion(projectPath) {
|
|
15385
|
-
const marker =
|
|
15593
|
+
const marker = join10(projectPath, "addons", ADDONS2[0], VERSION_MARKER2);
|
|
15386
15594
|
if (!existsSync8(marker)) {
|
|
15387
15595
|
return null;
|
|
15388
15596
|
}
|
|
15389
|
-
const said =
|
|
15597
|
+
const said = readFileSync9(marker, "utf8").trim();
|
|
15390
15598
|
return said === "" ? null : said;
|
|
15391
15599
|
}
|
|
15392
15600
|
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;
|
|
@@ -31368,212 +31576,11 @@ var init_stdio2 = __esm(() => {
|
|
|
31368
31576
|
init_stdio();
|
|
31369
31577
|
});
|
|
31370
31578
|
|
|
31371
|
-
// src/process-children.ts
|
|
31372
|
-
import { execFile as execFile4, execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
31373
|
-
import { basename as basename2 } from "node:path";
|
|
31374
|
-
import { promisify as promisify4 } from "node:util";
|
|
31375
|
-
function startTimesOf(pids) {
|
|
31376
|
-
const began = new Map;
|
|
31377
|
-
if (pids.length === 0) {
|
|
31378
|
-
return began;
|
|
31379
|
-
}
|
|
31380
|
-
try {
|
|
31381
|
-
if (process.platform === "win32") {
|
|
31382
|
-
const filter = pids.map((pid) => `ProcessId=${pid}`).join(" OR ");
|
|
31383
|
-
const said = execFileSync("powershell", [
|
|
31384
|
-
"-NoProfile",
|
|
31385
|
-
"-NonInteractive",
|
|
31386
|
-
"-Command",
|
|
31387
|
-
`Get-CimInstance Win32_Process -Filter "${filter}" | ForEach-Object { "$($_.ProcessId) $(([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds())" }`
|
|
31388
|
-
], { encoding: "utf8", timeout: ASK_TIMEOUT_MS, windowsHide: true });
|
|
31389
|
-
for (const line of said.split(`
|
|
31390
|
-
`)) {
|
|
31391
|
-
const found = /^\s*(\d+)\s+(\d+)\s*$/.exec(line);
|
|
31392
|
-
if (found?.[1] !== undefined && found[2] !== undefined) {
|
|
31393
|
-
began.set(Number(found[1]), Number(found[2]));
|
|
31394
|
-
}
|
|
31395
|
-
}
|
|
31396
|
-
return began;
|
|
31397
|
-
}
|
|
31398
|
-
const said = spawnSync2("ps", ["-p", pids.join(","), "-o", "pid=,lstart="], {
|
|
31399
|
-
encoding: "utf8",
|
|
31400
|
-
timeout: ASK_TIMEOUT_MS,
|
|
31401
|
-
env: { ...process.env, LC_ALL: "C" }
|
|
31402
|
-
}).stdout;
|
|
31403
|
-
for (const line of said.split(`
|
|
31404
|
-
`)) {
|
|
31405
|
-
const found = /^\s*(\d+)\s+(.+)$/.exec(line);
|
|
31406
|
-
const at = Date.parse(found?.[2]?.trim() ?? "");
|
|
31407
|
-
if (found?.[1] !== undefined && !Number.isNaN(at)) {
|
|
31408
|
-
began.set(Number(found[1]), at);
|
|
31409
|
-
}
|
|
31410
|
-
}
|
|
31411
|
-
} catch {}
|
|
31412
|
-
return began;
|
|
31413
|
-
}
|
|
31414
|
-
async function processTree() {
|
|
31415
|
-
try {
|
|
31416
|
-
if (process.platform === "win32") {
|
|
31417
|
-
return parseProcessTable(await askWindows(), true);
|
|
31418
|
-
}
|
|
31419
|
-
return parseProcessTable(await askPosix());
|
|
31420
|
-
} catch {
|
|
31421
|
-
return;
|
|
31422
|
-
}
|
|
31423
|
-
}
|
|
31424
|
-
function parseProcessTable(printed, started = false) {
|
|
31425
|
-
const tree = new Map;
|
|
31426
|
-
for (const line of printed.split(/\r?\n/)) {
|
|
31427
|
-
const fields = /^\s*(\d+)\s+(\d+)(?:\s+(.*))?$/.exec(line);
|
|
31428
|
-
if (fields === null) {
|
|
31429
|
-
continue;
|
|
31430
|
-
}
|
|
31431
|
-
const pid = Number(fields[1]);
|
|
31432
|
-
const parent = Number(fields[2]);
|
|
31433
|
-
const rest = (fields[3] ?? "").trim();
|
|
31434
|
-
if (pid <= 0) {
|
|
31435
|
-
continue;
|
|
31436
|
-
}
|
|
31437
|
-
if (!started) {
|
|
31438
|
-
tree.set(pid, { parent, command: rest });
|
|
31439
|
-
continue;
|
|
31440
|
-
}
|
|
31441
|
-
const timed = /^(\d+)(?:\s+(.*))?$/.exec(rest);
|
|
31442
|
-
if (timed === null) {
|
|
31443
|
-
continue;
|
|
31444
|
-
}
|
|
31445
|
-
const began = Number(timed[1]);
|
|
31446
|
-
tree.set(pid, { parent, command: (timed[2] ?? "").trim(), ...began > 0 ? { startedAt: began } : {} });
|
|
31447
|
-
}
|
|
31448
|
-
return tree;
|
|
31449
|
-
}
|
|
31450
|
-
function linked(tree, child, parent) {
|
|
31451
|
-
const from = tree.get(child);
|
|
31452
|
-
const to = tree.get(parent);
|
|
31453
|
-
if (from === undefined || from.parent !== parent) {
|
|
31454
|
-
return false;
|
|
31455
|
-
}
|
|
31456
|
-
if (from.startedAt === undefined || to?.startedAt === undefined) {
|
|
31457
|
-
return true;
|
|
31458
|
-
}
|
|
31459
|
-
return from.startedAt >= to.startedAt;
|
|
31460
|
-
}
|
|
31461
|
-
function childrenIn(tree, pid) {
|
|
31462
|
-
const children = [];
|
|
31463
|
-
for (const child of tree.keys()) {
|
|
31464
|
-
if (linked(tree, child, pid)) {
|
|
31465
|
-
children.push(child);
|
|
31466
|
-
}
|
|
31467
|
-
}
|
|
31468
|
-
return children;
|
|
31469
|
-
}
|
|
31470
|
-
function descendantsIn(tree, pid) {
|
|
31471
|
-
const found = [];
|
|
31472
|
-
const queue = [pid];
|
|
31473
|
-
const seen = new Set([pid]);
|
|
31474
|
-
while (queue.length > 0) {
|
|
31475
|
-
const next = queue.shift();
|
|
31476
|
-
if (next === undefined) {
|
|
31477
|
-
break;
|
|
31478
|
-
}
|
|
31479
|
-
for (const child of childrenIn(tree, next)) {
|
|
31480
|
-
if (!seen.has(child)) {
|
|
31481
|
-
seen.add(child);
|
|
31482
|
-
found.push(child);
|
|
31483
|
-
queue.push(child);
|
|
31484
|
-
}
|
|
31485
|
-
}
|
|
31486
|
-
}
|
|
31487
|
-
return found;
|
|
31488
|
-
}
|
|
31489
|
-
function ancestorsIn(tree, pid, root) {
|
|
31490
|
-
const chain = [];
|
|
31491
|
-
const seen = new Set([pid]);
|
|
31492
|
-
let child = pid;
|
|
31493
|
-
let parent = tree.get(pid)?.parent;
|
|
31494
|
-
while (parent !== undefined && !seen.has(parent) && linked(tree, child, parent)) {
|
|
31495
|
-
chain.push(parent);
|
|
31496
|
-
if (parent === root) {
|
|
31497
|
-
break;
|
|
31498
|
-
}
|
|
31499
|
-
seen.add(parent);
|
|
31500
|
-
child = parent;
|
|
31501
|
-
parent = tree.get(parent)?.parent;
|
|
31502
|
-
}
|
|
31503
|
-
return chain;
|
|
31504
|
-
}
|
|
31505
|
-
function readCommandLine(command) {
|
|
31506
|
-
const words = commandWords(command);
|
|
31507
|
-
const executable = words[0] === undefined ? "" : basename2(words[0].replaceAll("\\", "/"));
|
|
31508
|
-
const at = words.indexOf("--path");
|
|
31509
|
-
let projectPath = null;
|
|
31510
|
-
if (at !== -1 && at + 1 < words.length) {
|
|
31511
|
-
const taken = [];
|
|
31512
|
-
for (const word of words.slice(at + 1)) {
|
|
31513
|
-
if (taken.length > 0 && (word.startsWith("-") || /^[a-z]+:\/\//.test(word))) {
|
|
31514
|
-
break;
|
|
31515
|
-
}
|
|
31516
|
-
taken.push(word);
|
|
31517
|
-
}
|
|
31518
|
-
projectPath = taken.join(" ");
|
|
31519
|
-
}
|
|
31520
|
-
return {
|
|
31521
|
-
executable,
|
|
31522
|
-
projectPath,
|
|
31523
|
-
editor: words.some((word) => word === "-e" || word === "--editor")
|
|
31524
|
-
};
|
|
31525
|
-
}
|
|
31526
|
-
function commandWords(command) {
|
|
31527
|
-
const words = [];
|
|
31528
|
-
let word = "";
|
|
31529
|
-
let quoted = false;
|
|
31530
|
-
let started = false;
|
|
31531
|
-
for (const char of command) {
|
|
31532
|
-
if (char === '"') {
|
|
31533
|
-
quoted = !quoted;
|
|
31534
|
-
started = true;
|
|
31535
|
-
} else if (!quoted && /\s/.test(char)) {
|
|
31536
|
-
if (started) {
|
|
31537
|
-
words.push(word);
|
|
31538
|
-
word = "";
|
|
31539
|
-
started = false;
|
|
31540
|
-
}
|
|
31541
|
-
} else {
|
|
31542
|
-
word += char;
|
|
31543
|
-
started = true;
|
|
31544
|
-
}
|
|
31545
|
-
}
|
|
31546
|
-
if (started) {
|
|
31547
|
-
words.push(word);
|
|
31548
|
-
}
|
|
31549
|
-
return words;
|
|
31550
|
-
}
|
|
31551
|
-
async function askWindows() {
|
|
31552
|
-
const { stdout } = await run4("powershell.exe", [
|
|
31553
|
-
"-NoProfile",
|
|
31554
|
-
"-NonInteractive",
|
|
31555
|
-
"-Command",
|
|
31556
|
-
`${POWERSHELL_UTF8}Get-CimInstance Win32_Process | ForEach-Object { $began = 0; if ($_.CreationDate) { $began = ([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds() }; "$($_.ProcessId) $($_.ParentProcessId) $began $($_.CommandLine)" }`
|
|
31557
|
-
], { timeout: ASK_TIMEOUT_MS, windowsHide: true, maxBuffer: 16 * 1024 * 1024 });
|
|
31558
|
-
return stdout;
|
|
31559
|
-
}
|
|
31560
|
-
async function askPosix() {
|
|
31561
|
-
const { stdout } = await run4("ps", ["-e", "-o", "pid=,ppid=,args="], {
|
|
31562
|
-
timeout: ASK_TIMEOUT_MS,
|
|
31563
|
-
maxBuffer: 16 * 1024 * 1024
|
|
31564
|
-
});
|
|
31565
|
-
return stdout;
|
|
31566
|
-
}
|
|
31567
|
-
var run4, POWERSHELL_UTF8 = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ", ASK_TIMEOUT_MS = 15000;
|
|
31568
|
-
var init_process_children = __esm(() => {
|
|
31569
|
-
run4 = promisify4(execFile4);
|
|
31570
|
-
});
|
|
31571
|
-
|
|
31572
31579
|
// src/runtime-client.ts
|
|
31573
|
-
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as
|
|
31580
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync11, statSync as statSync5, unlinkSync } from "node:fs";
|
|
31574
31581
|
import { createConnection } from "node:net";
|
|
31575
31582
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
31576
|
-
import { dirname as
|
|
31583
|
+
import { dirname as dirname8, join as join13, resolve as resolve3 } from "node:path";
|
|
31577
31584
|
import { setTimeout as delay } from "node:timers/promises";
|
|
31578
31585
|
function runtimeDirectory(variables = process.env) {
|
|
31579
31586
|
const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
|
|
@@ -31581,19 +31588,19 @@ function runtimeDirectory(variables = process.env) {
|
|
|
31581
31588
|
return explicit;
|
|
31582
31589
|
}
|
|
31583
31590
|
const perUser = envValue("XDG_RUNTIME_DIR", variables);
|
|
31584
|
-
return
|
|
31591
|
+
return join13(perUser ?? tmpdir4(), "gdharness");
|
|
31585
31592
|
}
|
|
31586
31593
|
function runtimeDirectories(variables = process.env) {
|
|
31587
31594
|
const candidates = [runtimeDirectory(variables)];
|
|
31588
31595
|
const fallbacks = process.platform === "win32" ? [envValue("SystemRoot", variables) ?? envValue("windir", variables) ?? "C:\\Windows"] : ["/tmp", "/var/tmp"];
|
|
31589
31596
|
for (const base of fallbacks) {
|
|
31590
|
-
candidates.push(
|
|
31597
|
+
candidates.push(join13(base, process.platform === "win32" ? "Temp" : "", "gdharness"));
|
|
31591
31598
|
}
|
|
31592
31599
|
return [...new Set(candidates.map((path) => resolve3(path)))];
|
|
31593
31600
|
}
|
|
31594
31601
|
function errorReportOf(pid, directories = runtimeDirectories()) {
|
|
31595
31602
|
for (const directory of directories) {
|
|
31596
|
-
const path =
|
|
31603
|
+
const path = join13(directory, `runtime-${pid}.log`);
|
|
31597
31604
|
if (existsSync10(path)) {
|
|
31598
31605
|
return path;
|
|
31599
31606
|
}
|
|
@@ -31611,7 +31618,7 @@ function processAlive(pid) {
|
|
|
31611
31618
|
function parseAnnouncement(file, pid) {
|
|
31612
31619
|
let fields;
|
|
31613
31620
|
try {
|
|
31614
|
-
fields = asParams(JSON.parse(
|
|
31621
|
+
fields = asParams(JSON.parse(readFileSync11(file, "utf8")));
|
|
31615
31622
|
} catch {
|
|
31616
31623
|
return { kind: "rubbish" };
|
|
31617
31624
|
}
|
|
@@ -31663,7 +31670,7 @@ function discoverRuntimes(directories = runtimeDirectories()) {
|
|
|
31663
31670
|
function wentAway(file, pid) {
|
|
31664
31671
|
let project = "";
|
|
31665
31672
|
try {
|
|
31666
|
-
const fields = asParams(JSON.parse(
|
|
31673
|
+
const fields = asParams(JSON.parse(readFileSync11(file, "utf8")));
|
|
31667
31674
|
project = readString(readParams(fields, "project") ?? {}, "path") ?? "";
|
|
31668
31675
|
} catch {
|
|
31669
31676
|
return;
|
|
@@ -31709,14 +31716,14 @@ function announcedIn(directory) {
|
|
|
31709
31716
|
for (const entry of readdirSync6(directory)) {
|
|
31710
31717
|
const report = ERROR_REPORT_PATTERN.exec(entry);
|
|
31711
31718
|
if (report) {
|
|
31712
|
-
sweepErrorReport(
|
|
31719
|
+
sweepErrorReport(join13(directory, entry), Number.parseInt(report[1] ?? "", 10));
|
|
31713
31720
|
continue;
|
|
31714
31721
|
}
|
|
31715
31722
|
const match = ANNOUNCEMENT_PATTERN.exec(entry);
|
|
31716
31723
|
if (!match) {
|
|
31717
31724
|
continue;
|
|
31718
31725
|
}
|
|
31719
|
-
const file =
|
|
31726
|
+
const file = join13(directory, entry);
|
|
31720
31727
|
const pid = Number.parseInt(match[1] ?? "", 10);
|
|
31721
31728
|
const alive = processAlive(pid);
|
|
31722
31729
|
entries.push({ file, pid, alive });
|
|
@@ -31744,16 +31751,16 @@ function announcedIn(directory) {
|
|
|
31744
31751
|
found.push(announced);
|
|
31745
31752
|
}
|
|
31746
31753
|
const held = new Set(entries.map((one) => one.file));
|
|
31747
|
-
const here =
|
|
31754
|
+
const here = join13(directory, ".");
|
|
31748
31755
|
for (const file of verdicts.keys()) {
|
|
31749
|
-
if (
|
|
31756
|
+
if (dirname8(file) === here && !held.has(file)) {
|
|
31750
31757
|
verdicts.delete(file);
|
|
31751
31758
|
}
|
|
31752
31759
|
}
|
|
31753
31760
|
return found;
|
|
31754
31761
|
}
|
|
31755
31762
|
async function announcementEnded(pid, directories = runtimeDirectories()) {
|
|
31756
|
-
const files = directories.map((directory) =>
|
|
31763
|
+
const files = directories.map((directory) => join13(directory, `runtime-${pid}.json`)).filter((file) => existsSync10(file));
|
|
31757
31764
|
const first = files[0];
|
|
31758
31765
|
if (first === undefined) {
|
|
31759
31766
|
return;
|
|
@@ -32002,14 +32009,14 @@ var init_runtime_client = __esm(() => {
|
|
|
32002
32009
|
});
|
|
32003
32010
|
|
|
32004
32011
|
// src/boot-note.ts
|
|
32005
|
-
import { mkdirSync as
|
|
32006
|
-
import { dirname as
|
|
32012
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
|
|
32013
|
+
import { dirname as dirname9, join as join14 } from "node:path";
|
|
32007
32014
|
function bootNotePath(projectPath) {
|
|
32008
|
-
return
|
|
32015
|
+
return join14(projectPath, ".godot", "gdharness-boot.json");
|
|
32009
32016
|
}
|
|
32010
32017
|
function readBootNote(projectPath) {
|
|
32011
32018
|
try {
|
|
32012
|
-
const noted = readNumber(asParams(JSON.parse(
|
|
32019
|
+
const noted = readNumber(asParams(JSON.parse(readFileSync12(bootNotePath(projectPath), "utf8"))), "announcedAfterMs");
|
|
32013
32020
|
return noted !== undefined && Number.isFinite(noted) && noted > 0 ? noted : null;
|
|
32014
32021
|
} catch {
|
|
32015
32022
|
return null;
|
|
@@ -32018,8 +32025,8 @@ function readBootNote(projectPath) {
|
|
|
32018
32025
|
function writeBootNote(projectPath, announcedAfterMs) {
|
|
32019
32026
|
try {
|
|
32020
32027
|
const path = bootNotePath(projectPath);
|
|
32021
|
-
|
|
32022
|
-
|
|
32028
|
+
mkdirSync7(dirname9(path), { recursive: true });
|
|
32029
|
+
writeFileSync9(path, JSON.stringify({ announcedAfterMs: Math.round(announcedAfterMs), at: new Date().toISOString() }, null, 2), "utf8");
|
|
32023
32030
|
} catch {}
|
|
32024
32031
|
}
|
|
32025
32032
|
function halfAsLongAgain(lastBootMs) {
|
|
@@ -32037,10 +32044,10 @@ var init_boot_note = __esm(() => {
|
|
|
32037
32044
|
});
|
|
32038
32045
|
|
|
32039
32046
|
// src/breakpoint-note.ts
|
|
32040
|
-
import { mkdirSync as
|
|
32041
|
-
import { dirname as
|
|
32047
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, rmSync as rmSync7, writeFileSync as writeFileSync10 } from "node:fs";
|
|
32048
|
+
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join15, relative as relative2 } from "node:path";
|
|
32042
32049
|
function breakpointNotePath(projectPath) {
|
|
32043
|
-
return
|
|
32050
|
+
return join15(projectPath, ".godot", "gdharness-breakpoints.json");
|
|
32044
32051
|
}
|
|
32045
32052
|
function writeBreakpointNote(projectPath, held) {
|
|
32046
32053
|
const path = breakpointNotePath(projectPath);
|
|
@@ -32048,7 +32055,7 @@ function writeBreakpointNote(projectPath, held) {
|
|
|
32048
32055
|
const inside = held.map((one) => ({ scriptPath: realPathOr(one.scriptPath), lines: one.lines })).filter((one) => one.lines.length > 0 && withinProject(root, one.scriptPath));
|
|
32049
32056
|
try {
|
|
32050
32057
|
if (inside.length === 0) {
|
|
32051
|
-
|
|
32058
|
+
rmSync7(path, { force: true });
|
|
32052
32059
|
return;
|
|
32053
32060
|
}
|
|
32054
32061
|
const note = {
|
|
@@ -32057,8 +32064,8 @@ function writeBreakpointNote(projectPath, held) {
|
|
|
32057
32064
|
lines: [...one.lines]
|
|
32058
32065
|
}))
|
|
32059
32066
|
};
|
|
32060
|
-
|
|
32061
|
-
|
|
32067
|
+
mkdirSync8(dirname10(path), { recursive: true });
|
|
32068
|
+
writeFileSync10(path, `${JSON.stringify(note, null, 2)}
|
|
32062
32069
|
`, "utf8");
|
|
32063
32070
|
} catch (error) {
|
|
32064
32071
|
console.error(`[SERVER] Could not record the breakpoints at ${path}: ${errorMessage(error)}`);
|
|
@@ -32066,7 +32073,7 @@ function writeBreakpointNote(projectPath, held) {
|
|
|
32066
32073
|
}
|
|
32067
32074
|
function readBreakpointNote(projectPath) {
|
|
32068
32075
|
try {
|
|
32069
|
-
const parsed = JSON.parse(
|
|
32076
|
+
const parsed = JSON.parse(readFileSync13(breakpointNotePath(projectPath), "utf8"));
|
|
32070
32077
|
if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.breakpoints)) {
|
|
32071
32078
|
return [];
|
|
32072
32079
|
}
|
|
@@ -32081,7 +32088,7 @@ function readBreakpointNote(projectPath) {
|
|
|
32081
32088
|
}
|
|
32082
32089
|
const lines = Array.isArray(listed) ? listed.filter((line) => Number.isInteger(line) && line > 0) : [];
|
|
32083
32090
|
if (lines.length > 0) {
|
|
32084
|
-
held.push({ scriptPath: realPathOr(
|
|
32091
|
+
held.push({ scriptPath: realPathOr(join15(projectPath, script)), lines });
|
|
32085
32092
|
}
|
|
32086
32093
|
}
|
|
32087
32094
|
return held;
|
|
@@ -32099,14 +32106,14 @@ var init_breakpoint_note = __esm(() => {
|
|
|
32099
32106
|
});
|
|
32100
32107
|
|
|
32101
32108
|
// src/bridge-announce.ts
|
|
32102
|
-
import { mkdirSync as
|
|
32103
|
-
import { dirname as
|
|
32104
|
-
function
|
|
32105
|
-
return
|
|
32109
|
+
import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, rmSync as rmSync8, writeFileSync as writeFileSync11 } from "node:fs";
|
|
32110
|
+
import { dirname as dirname11, join as join16 } from "node:path";
|
|
32111
|
+
function announcementPath2(projectPath) {
|
|
32112
|
+
return join16(projectPath, ".godot", "gdharness-bridge.json");
|
|
32106
32113
|
}
|
|
32107
|
-
function
|
|
32114
|
+
function readAnnouncement2(path) {
|
|
32108
32115
|
try {
|
|
32109
|
-
const parsed = JSON.parse(
|
|
32116
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
32110
32117
|
if (typeof parsed !== "object" || parsed === null) {
|
|
32111
32118
|
return null;
|
|
32112
32119
|
}
|
|
@@ -32120,12 +32127,12 @@ function readAnnouncement(path) {
|
|
|
32120
32127
|
}
|
|
32121
32128
|
}
|
|
32122
32129
|
function announcementIsOurs(path) {
|
|
32123
|
-
return
|
|
32130
|
+
return readAnnouncement2(path)?.pid === process.pid;
|
|
32124
32131
|
}
|
|
32125
32132
|
function announceBridge(projectPath, bridge) {
|
|
32126
|
-
const path =
|
|
32133
|
+
const path = announcementPath2(projectPath);
|
|
32127
32134
|
try {
|
|
32128
|
-
|
|
32135
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
32129
32136
|
const announcement = {
|
|
32130
32137
|
protocol: BRIDGE_ANNOUNCE_PROTOCOL,
|
|
32131
32138
|
host: bridge.host,
|
|
@@ -32134,7 +32141,7 @@ function announceBridge(projectPath, bridge) {
|
|
|
32134
32141
|
version: bridge.version,
|
|
32135
32142
|
startedAt: new Date().toISOString()
|
|
32136
32143
|
};
|
|
32137
|
-
|
|
32144
|
+
writeFileSync11(path, `${JSON.stringify(announcement, null, 2)}
|
|
32138
32145
|
`, "utf8");
|
|
32139
32146
|
return path;
|
|
32140
32147
|
} catch (error) {
|
|
@@ -32147,7 +32154,7 @@ function withdrawBridge(path) {
|
|
|
32147
32154
|
return;
|
|
32148
32155
|
}
|
|
32149
32156
|
try {
|
|
32150
|
-
|
|
32157
|
+
rmSync8(path, { force: true });
|
|
32151
32158
|
} catch (error) {
|
|
32152
32159
|
console.error(`[SERVER] Could not withdraw the editor bridge announcement: ${errorMessage(error)}`);
|
|
32153
32160
|
}
|
|
@@ -32155,17 +32162,18 @@ function withdrawBridge(path) {
|
|
|
32155
32162
|
var BRIDGE_ANNOUNCE_PROTOCOL = 1;
|
|
32156
32163
|
var init_bridge_announce = __esm(() => {
|
|
32157
32164
|
init_errors();
|
|
32165
|
+
init_process_children();
|
|
32158
32166
|
});
|
|
32159
32167
|
|
|
32160
32168
|
// src/class-note.ts
|
|
32161
|
-
import { mkdirSync as
|
|
32162
|
-
import { dirname as
|
|
32169
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "node:fs";
|
|
32170
|
+
import { dirname as dirname12, join as join17 } from "node:path";
|
|
32163
32171
|
function classNotePath(projectPath) {
|
|
32164
|
-
return
|
|
32172
|
+
return join17(projectPath, ".godot", "gdharness-classes.json");
|
|
32165
32173
|
}
|
|
32166
32174
|
function readClassNote(projectPath) {
|
|
32167
32175
|
try {
|
|
32168
|
-
const fields = asParams(JSON.parse(
|
|
32176
|
+
const fields = asParams(JSON.parse(readFileSync15(classNotePath(projectPath), "utf8")));
|
|
32169
32177
|
const rebuiltWith = readArray(fields, "rebuiltWith");
|
|
32170
32178
|
if (rebuiltWith === undefined || !rebuiltWith.every((name) => typeof name === "string")) {
|
|
32171
32179
|
return null;
|
|
@@ -32182,24 +32190,24 @@ function readClassNote(projectPath) {
|
|
|
32182
32190
|
function writeClassNote(projectPath, note) {
|
|
32183
32191
|
try {
|
|
32184
32192
|
const path = classNotePath(projectPath);
|
|
32185
|
-
|
|
32186
|
-
|
|
32193
|
+
mkdirSync10(dirname12(path), { recursive: true });
|
|
32194
|
+
writeFileSync12(path, `${JSON.stringify(note, null, 2)}
|
|
32187
32195
|
`, "utf8");
|
|
32188
32196
|
} catch {}
|
|
32189
32197
|
}
|
|
32190
32198
|
var init_class_note = () => {};
|
|
32191
32199
|
|
|
32192
32200
|
// src/config-pin.ts
|
|
32193
|
-
import { existsSync as existsSync11, readFileSync as
|
|
32194
|
-
import { join as
|
|
32201
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16 } from "node:fs";
|
|
32202
|
+
import { join as join18 } from "node:path";
|
|
32195
32203
|
function versionsNamedInConfig(projectPath) {
|
|
32196
|
-
const config =
|
|
32204
|
+
const config = join18(projectPath, ".mcp.json");
|
|
32197
32205
|
if (!existsSync11(config)) {
|
|
32198
32206
|
return [];
|
|
32199
32207
|
}
|
|
32200
32208
|
let text;
|
|
32201
32209
|
try {
|
|
32202
|
-
text =
|
|
32210
|
+
text = readFileSync16(config, "utf8");
|
|
32203
32211
|
JSON.parse(text);
|
|
32204
32212
|
} catch {
|
|
32205
32213
|
return [];
|
|
@@ -32307,7 +32315,7 @@ function portFromEnvOrNull(variable) {
|
|
|
32307
32315
|
}
|
|
32308
32316
|
const parsed = Number.parseInt(raw, 10);
|
|
32309
32317
|
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535 || String(parsed) !== raw) {
|
|
32310
|
-
throw new
|
|
32318
|
+
throw new Refusal(`${variable} is "${raw}", not a port between 1 and 65535.`);
|
|
32311
32319
|
}
|
|
32312
32320
|
return parsed;
|
|
32313
32321
|
}
|
|
@@ -32321,7 +32329,7 @@ async function freePort(preferred, host = "127.0.0.1") {
|
|
|
32321
32329
|
}
|
|
32322
32330
|
const spare = await bindable(0, host);
|
|
32323
32331
|
if (spare === null) {
|
|
32324
|
-
throw new
|
|
32332
|
+
throw new Refusal(`No port could be bound on ${host}.`);
|
|
32325
32333
|
}
|
|
32326
32334
|
return spare;
|
|
32327
32335
|
}
|
|
@@ -32471,7 +32479,7 @@ class GodotDAPClient {
|
|
|
32471
32479
|
async sendRequest(command, args, timeoutMs = DAP_REQUEST_TIMEOUT_MS) {
|
|
32472
32480
|
await this.ensureConnected();
|
|
32473
32481
|
if (!this.socket) {
|
|
32474
|
-
throw new
|
|
32482
|
+
throw new Refusal("DAP socket is not available");
|
|
32475
32483
|
}
|
|
32476
32484
|
const requestSeq = this.seq++;
|
|
32477
32485
|
const request = {
|
|
@@ -32881,7 +32889,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
32881
32889
|
}
|
|
32882
32890
|
case "dap_set_breakpoint": {
|
|
32883
32891
|
if (typeof safeArgs.scriptPath !== "string" || typeof safeArgs.line !== "number") {
|
|
32884
|
-
throw new
|
|
32892
|
+
throw new Refusal("dap_set_breakpoint requires { scriptPath: string, line: number }");
|
|
32885
32893
|
}
|
|
32886
32894
|
const result = await client.setBreakpoint(safeArgs.scriptPath, safeArgs.line);
|
|
32887
32895
|
return {
|
|
@@ -32890,7 +32898,7 @@ async function handleDAPTool(client, toolName, args) {
|
|
|
32890
32898
|
}
|
|
32891
32899
|
case "dap_remove_breakpoint": {
|
|
32892
32900
|
if (typeof safeArgs.scriptPath !== "string" || typeof safeArgs.line !== "number") {
|
|
32893
|
-
throw new
|
|
32901
|
+
throw new Refusal("dap_remove_breakpoint requires { scriptPath: string, line: number }");
|
|
32894
32902
|
}
|
|
32895
32903
|
const result = await client.removeBreakpoint(safeArgs.scriptPath, safeArgs.line);
|
|
32896
32904
|
return {
|
|
@@ -32953,24 +32961,24 @@ var init_dap_client = __esm(() => {
|
|
|
32953
32961
|
import {
|
|
32954
32962
|
closeSync,
|
|
32955
32963
|
existsSync as existsSync12,
|
|
32956
|
-
mkdirSync as
|
|
32964
|
+
mkdirSync as mkdirSync11,
|
|
32957
32965
|
openSync,
|
|
32958
|
-
readFileSync as
|
|
32966
|
+
readFileSync as readFileSync17,
|
|
32959
32967
|
readSync,
|
|
32960
|
-
rmSync as
|
|
32968
|
+
rmSync as rmSync9,
|
|
32961
32969
|
statSync as statSync6,
|
|
32962
|
-
writeFileSync as
|
|
32970
|
+
writeFileSync as writeFileSync13
|
|
32963
32971
|
} from "node:fs";
|
|
32964
|
-
import { dirname as
|
|
32972
|
+
import { dirname as dirname13, join as join19 } from "node:path";
|
|
32965
32973
|
function editorLogPath(projectPath) {
|
|
32966
|
-
return
|
|
32974
|
+
return join19(projectPath, ".godot", "gdharness-editor.log");
|
|
32967
32975
|
}
|
|
32968
32976
|
function editorLogNotePath(projectPath) {
|
|
32969
|
-
return
|
|
32977
|
+
return join19(projectPath, ".godot", "gdharness-editor.json");
|
|
32970
32978
|
}
|
|
32971
32979
|
function readEditorLogNote(projectPath) {
|
|
32972
32980
|
try {
|
|
32973
|
-
const fields = asParams(JSON.parse(
|
|
32981
|
+
const fields = asParams(JSON.parse(readFileSync17(editorLogNotePath(projectPath), "utf8")));
|
|
32974
32982
|
const pid = readNumber(fields, "pid");
|
|
32975
32983
|
const startedAt = readString(fields, "startedAt");
|
|
32976
32984
|
return pid !== undefined && Number.isInteger(pid) && pid > 0 && startedAt !== undefined ? { pid, startedAt } : null;
|
|
@@ -32981,16 +32989,16 @@ function readEditorLogNote(projectPath) {
|
|
|
32981
32989
|
function clearEditorLog(projectPath) {
|
|
32982
32990
|
try {
|
|
32983
32991
|
const path = editorLogPath(projectPath);
|
|
32984
|
-
|
|
32985
|
-
|
|
32986
|
-
|
|
32992
|
+
mkdirSync11(dirname13(path), { recursive: true });
|
|
32993
|
+
rmSync9(path, { force: true });
|
|
32994
|
+
rmSync9(editorLogNotePath(projectPath), { force: true });
|
|
32987
32995
|
} catch {}
|
|
32988
32996
|
}
|
|
32989
32997
|
function writeEditorLogNote(projectPath, pid) {
|
|
32990
32998
|
try {
|
|
32991
32999
|
const path = editorLogNotePath(projectPath);
|
|
32992
|
-
|
|
32993
|
-
|
|
33000
|
+
mkdirSync11(dirname13(path), { recursive: true });
|
|
33001
|
+
writeFileSync13(path, JSON.stringify({ pid, startedAt: new Date().toISOString() }, null, 2), "utf8");
|
|
32994
33002
|
} catch {}
|
|
32995
33003
|
}
|
|
32996
33004
|
function theConsoleWasNotCaptured(why, projectPath) {
|
|
@@ -33023,7 +33031,7 @@ function editorConsole(projectPath, editorPid, openedByAServer) {
|
|
|
33023
33031
|
function theFirstOf(path) {
|
|
33024
33032
|
const whole = statSync6(path).size;
|
|
33025
33033
|
if (whole <= MOST_CONSOLE_BYTES) {
|
|
33026
|
-
return { text:
|
|
33034
|
+
return { text: readFileSync17(path, "utf8") };
|
|
33027
33035
|
}
|
|
33028
33036
|
const handle = openSync(path, "r");
|
|
33029
33037
|
try {
|
|
@@ -36441,7 +36449,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
36441
36449
|
}
|
|
36442
36450
|
sendMessage(message) {
|
|
36443
36451
|
if (this.socket?.readyState !== import_websocket.default.OPEN) {
|
|
36444
|
-
throw new
|
|
36452
|
+
throw new Refusal("Godot is not connected");
|
|
36445
36453
|
}
|
|
36446
36454
|
this.socket.send(JSON.stringify(message));
|
|
36447
36455
|
}
|
|
@@ -36991,7 +36999,7 @@ var init_junit = __esm(() => {
|
|
|
36991
36999
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
36992
37000
|
import { readFile, realpath } from "node:fs/promises";
|
|
36993
37001
|
import { createConnection as createConnection3 } from "node:net";
|
|
36994
|
-
import { dirname as
|
|
37002
|
+
import { dirname as dirname14, resolve as resolve4 } from "node:path";
|
|
36995
37003
|
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
|
|
36996
37004
|
function diagnosticsKey(uri) {
|
|
36997
37005
|
let decoded;
|
|
@@ -37119,13 +37127,13 @@ class GodotLSPClient {
|
|
|
37119
37127
|
if (this.initialized) {
|
|
37120
37128
|
return;
|
|
37121
37129
|
}
|
|
37122
|
-
const rootPath = this.rootPath ??
|
|
37130
|
+
const rootPath = this.rootPath ?? dirname14(resolve4(filePath));
|
|
37123
37131
|
await this.initialize(rootPath);
|
|
37124
37132
|
}
|
|
37125
37133
|
async sendRequest(method, params) {
|
|
37126
37134
|
await this.ensureConnected();
|
|
37127
37135
|
if (!this.socket) {
|
|
37128
|
-
throw new
|
|
37136
|
+
throw new Refusal("Not connected to Godot LSP");
|
|
37129
37137
|
}
|
|
37130
37138
|
this.requestId += 1;
|
|
37131
37139
|
const id = this.requestId;
|
|
@@ -37164,7 +37172,7 @@ class GodotLSPClient {
|
|
|
37164
37172
|
}
|
|
37165
37173
|
sendNotification(method, params) {
|
|
37166
37174
|
if (!this.connected || !this.socket) {
|
|
37167
|
-
throw new
|
|
37175
|
+
throw new Refusal("Not connected to Godot LSP");
|
|
37168
37176
|
}
|
|
37169
37177
|
const payload = {
|
|
37170
37178
|
jsonrpc: "2.0",
|
|
@@ -37446,36 +37454,36 @@ async function resolveLSPPaths(projectPathValue, scriptPathValue) {
|
|
|
37446
37454
|
try {
|
|
37447
37455
|
projectPath = await realpath(requestedProjectPath);
|
|
37448
37456
|
} catch {
|
|
37449
|
-
throw new
|
|
37457
|
+
throw new Refusal(`Project path does not exist: ${requestedProjectPath}`);
|
|
37450
37458
|
}
|
|
37451
37459
|
const contained = resolveWithinProject(projectPath, scriptPathValue);
|
|
37452
37460
|
if (!contained.ok) {
|
|
37453
|
-
throw new
|
|
37461
|
+
throw new Refusal(contained.reason);
|
|
37454
37462
|
}
|
|
37455
37463
|
let scriptPath;
|
|
37456
37464
|
try {
|
|
37457
37465
|
scriptPath = await realpath(contained.absolutePath);
|
|
37458
37466
|
} catch {
|
|
37459
|
-
throw new
|
|
37467
|
+
throw new Refusal(`Script file does not exist: ${contained.absolutePath}`);
|
|
37460
37468
|
}
|
|
37461
37469
|
if (!isWithinRoot(projectPath, scriptPath)) {
|
|
37462
|
-
throw new
|
|
37470
|
+
throw new Refusal("scriptPath resolves outside the project root boundary.");
|
|
37463
37471
|
}
|
|
37464
37472
|
return { projectPath, scriptPath };
|
|
37465
37473
|
}
|
|
37466
37474
|
async function handleLSPTool(client, toolName, args) {
|
|
37467
37475
|
try {
|
|
37468
37476
|
if (!args || typeof args !== "object") {
|
|
37469
|
-
throw new
|
|
37477
|
+
throw new Refusal("Tool arguments must be an object.");
|
|
37470
37478
|
}
|
|
37471
37479
|
const parsedArgs = args;
|
|
37472
37480
|
const projectPathValue = parsedArgs["projectPath"];
|
|
37473
37481
|
const scriptPathValue = parsedArgs["scriptPath"];
|
|
37474
37482
|
if (typeof projectPathValue !== "string" || projectPathValue.length === 0) {
|
|
37475
|
-
throw new
|
|
37483
|
+
throw new Refusal("Missing required argument: projectPath");
|
|
37476
37484
|
}
|
|
37477
37485
|
if (typeof scriptPathValue !== "string" || scriptPathValue.length === 0) {
|
|
37478
|
-
throw new
|
|
37486
|
+
throw new Refusal("Missing required argument: scriptPath");
|
|
37479
37487
|
}
|
|
37480
37488
|
const { projectPath, scriptPath } = await resolveLSPPaths(projectPathValue, scriptPathValue);
|
|
37481
37489
|
const content = await readFile(scriptPath, "utf8");
|
|
@@ -37489,7 +37497,7 @@ async function handleLSPTool(client, toolName, args) {
|
|
|
37489
37497
|
const line = Number(parsedArgs["line"]);
|
|
37490
37498
|
const character = Number(parsedArgs["character"]);
|
|
37491
37499
|
if (!Number.isFinite(line) || !Number.isFinite(character)) {
|
|
37492
|
-
throw new
|
|
37500
|
+
throw new Refusal("Arguments line and character must be numbers.");
|
|
37493
37501
|
}
|
|
37494
37502
|
const completions = await client.getCompletions(scriptPath, content, line, character);
|
|
37495
37503
|
return asToolResponse({ completions });
|
|
@@ -37498,7 +37506,7 @@ async function handleLSPTool(client, toolName, args) {
|
|
|
37498
37506
|
const line = Number(parsedArgs["line"]);
|
|
37499
37507
|
const character = Number(parsedArgs["character"]);
|
|
37500
37508
|
if (!Number.isFinite(line) || !Number.isFinite(character)) {
|
|
37501
|
-
throw new
|
|
37509
|
+
throw new Refusal("Arguments line and character must be numbers.");
|
|
37502
37510
|
}
|
|
37503
37511
|
const hover = await client.getHover(scriptPath, content, line, character);
|
|
37504
37512
|
return asToolResponse({ hover });
|
|
@@ -37564,13 +37572,13 @@ var init_process_time = __esm(() => {
|
|
|
37564
37572
|
});
|
|
37565
37573
|
|
|
37566
37574
|
// src/project-scan.ts
|
|
37567
|
-
import { existsSync as existsSync14, readdirSync as readdirSync7, readFileSync as
|
|
37568
|
-
import { join as
|
|
37575
|
+
import { existsSync as existsSync14, readdirSync as readdirSync7, readFileSync as readFileSync18 } from "node:fs";
|
|
37576
|
+
import { join as join20 } from "node:path";
|
|
37569
37577
|
function skipped(name) {
|
|
37570
37578
|
return name.startsWith(".") || SKIPPED.has(name);
|
|
37571
37579
|
}
|
|
37572
37580
|
function steppedOver(directory) {
|
|
37573
|
-
return existsSync14(
|
|
37581
|
+
return existsSync14(join20(directory, ".gdignore"));
|
|
37574
37582
|
}
|
|
37575
37583
|
function projectStructure(projectPath) {
|
|
37576
37584
|
const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
|
|
@@ -37583,7 +37591,7 @@ function projectStructure(projectPath) {
|
|
|
37583
37591
|
continue;
|
|
37584
37592
|
}
|
|
37585
37593
|
if (entry.isDirectory()) {
|
|
37586
|
-
visit(
|
|
37594
|
+
visit(join20(directory, entry.name));
|
|
37587
37595
|
} else if (entry.isFile()) {
|
|
37588
37596
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
37589
37597
|
if (extension === "tscn") {
|
|
@@ -37613,14 +37621,14 @@ function scriptsWithoutUid(projectPath) {
|
|
|
37613
37621
|
}
|
|
37614
37622
|
const spelled = prefix === "" ? entry.name : `${prefix}/${entry.name}`;
|
|
37615
37623
|
if (entry.isDirectory()) {
|
|
37616
|
-
visit(
|
|
37624
|
+
visit(join20(directory, entry.name), spelled);
|
|
37617
37625
|
continue;
|
|
37618
37626
|
}
|
|
37619
37627
|
if (!entry.isFile()) {
|
|
37620
37628
|
continue;
|
|
37621
37629
|
}
|
|
37622
37630
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
37623
|
-
if (CARRIES_A_UID.has(extension) && !existsSync14(
|
|
37631
|
+
if (CARRIES_A_UID.has(extension) && !existsSync14(join20(directory, `${entry.name}.uid`))) {
|
|
37624
37632
|
found.push(spelled);
|
|
37625
37633
|
}
|
|
37626
37634
|
}
|
|
@@ -37655,7 +37663,7 @@ function searchProject(projectPath, options) {
|
|
|
37655
37663
|
if (skipped(entry.name)) {
|
|
37656
37664
|
continue;
|
|
37657
37665
|
}
|
|
37658
|
-
const entryPath =
|
|
37666
|
+
const entryPath = join20(directory, entry.name);
|
|
37659
37667
|
if (entry.isDirectory()) {
|
|
37660
37668
|
visit(entryPath);
|
|
37661
37669
|
continue;
|
|
@@ -37666,7 +37674,7 @@ function searchProject(projectPath, options) {
|
|
|
37666
37674
|
}
|
|
37667
37675
|
result.summary.files_searched += 1;
|
|
37668
37676
|
const matches = [];
|
|
37669
|
-
for (const [index, line] of
|
|
37677
|
+
for (const [index, line] of readFileSync18(entryPath, "utf8").split(`
|
|
37670
37678
|
`).entries()) {
|
|
37671
37679
|
if (full()) {
|
|
37672
37680
|
break;
|
|
@@ -37695,16 +37703,16 @@ var init_project_scan = __esm(() => {
|
|
|
37695
37703
|
});
|
|
37696
37704
|
|
|
37697
37705
|
// src/restart-note.ts
|
|
37698
|
-
import { mkdirSync as
|
|
37699
|
-
import { dirname as
|
|
37706
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync19, rmSync as rmSync10, writeFileSync as writeFileSync14 } from "node:fs";
|
|
37707
|
+
import { dirname as dirname15, join as join21 } from "node:path";
|
|
37700
37708
|
function restartNotePath(projectPath) {
|
|
37701
|
-
return
|
|
37709
|
+
return join21(projectPath, ".godot", "gdharness-restart.json");
|
|
37702
37710
|
}
|
|
37703
37711
|
function noteRestartBegun(note) {
|
|
37704
37712
|
const path = restartNotePath(note.projectPath);
|
|
37705
37713
|
try {
|
|
37706
|
-
|
|
37707
|
-
|
|
37714
|
+
mkdirSync12(dirname15(path), { recursive: true });
|
|
37715
|
+
writeFileSync14(path, `${JSON.stringify(note, null, 2)}
|
|
37708
37716
|
`, "utf8");
|
|
37709
37717
|
} catch (error) {
|
|
37710
37718
|
console.error(`[SERVER] Could not record the restart at ${path}: ${errorMessage(error)}`);
|
|
@@ -37712,7 +37720,7 @@ function noteRestartBegun(note) {
|
|
|
37712
37720
|
}
|
|
37713
37721
|
function restartOwed(projectPath) {
|
|
37714
37722
|
try {
|
|
37715
|
-
const parsed = JSON.parse(
|
|
37723
|
+
const parsed = JSON.parse(readFileSync19(restartNotePath(projectPath), "utf8"));
|
|
37716
37724
|
if (typeof parsed !== "object" || parsed === null) {
|
|
37717
37725
|
return null;
|
|
37718
37726
|
}
|
|
@@ -37727,7 +37735,7 @@ function restartOwed(projectPath) {
|
|
|
37727
37735
|
}
|
|
37728
37736
|
function restartSettled(projectPath) {
|
|
37729
37737
|
try {
|
|
37730
|
-
|
|
37738
|
+
rmSync10(restartNotePath(projectPath), { force: true });
|
|
37731
37739
|
} catch (error) {
|
|
37732
37740
|
console.error(`[SERVER] Could not clear the restart note: ${errorMessage(error)}`);
|
|
37733
37741
|
}
|
|
@@ -37738,36 +37746,36 @@ var init_restart_note = __esm(() => {
|
|
|
37738
37746
|
|
|
37739
37747
|
// src/run-record.ts
|
|
37740
37748
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
37741
|
-
import { mkdirSync as
|
|
37742
|
-
import { basename as basename3, join as
|
|
37749
|
+
import { mkdirSync as mkdirSync13, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync20, rmSync as rmSync11, statSync as statSync7, writeFileSync as writeFileSync15 } from "node:fs";
|
|
37750
|
+
import { basename as basename3, join as join22 } from "node:path";
|
|
37743
37751
|
function runsDirectory() {
|
|
37744
|
-
return
|
|
37752
|
+
return join22(runtimeDirectory(), "runs");
|
|
37745
37753
|
}
|
|
37746
37754
|
function recordPath() {
|
|
37747
|
-
return
|
|
37755
|
+
return join22(runsDirectory(), "run.json");
|
|
37748
37756
|
}
|
|
37749
37757
|
function recordPaths() {
|
|
37750
|
-
return runtimeDirectories().map((directory) =>
|
|
37758
|
+
return runtimeDirectories().map((directory) => join22(directory, "runs", "run.json"));
|
|
37751
37759
|
}
|
|
37752
37760
|
function openTranscript(startedAt) {
|
|
37753
|
-
|
|
37754
|
-
const path =
|
|
37761
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
37762
|
+
const path = join22(runsDirectory(), `run-${startedAt}.log`);
|
|
37755
37763
|
return { path, fd: openSync2(path, "a") };
|
|
37756
37764
|
}
|
|
37757
37765
|
function writeRunRecord(record) {
|
|
37758
|
-
|
|
37759
|
-
|
|
37766
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
37767
|
+
writeFileSync15(recordPath(), JSON.stringify(record, null, 2), "utf8");
|
|
37760
37768
|
}
|
|
37761
37769
|
function editorNotePath() {
|
|
37762
|
-
return
|
|
37770
|
+
return join22(runsDirectory(), "editor-run.json");
|
|
37763
37771
|
}
|
|
37764
37772
|
function writeEditorRunNote(note) {
|
|
37765
|
-
|
|
37766
|
-
|
|
37773
|
+
mkdirSync13(runsDirectory(), { recursive: true });
|
|
37774
|
+
writeFileSync15(editorNotePath(), JSON.stringify(note, null, 2), "utf8");
|
|
37767
37775
|
}
|
|
37768
37776
|
function readEditorRunNote() {
|
|
37769
37777
|
for (const directory of runtimeDirectories()) {
|
|
37770
|
-
const note = editorNoteAt(
|
|
37778
|
+
const note = editorNoteAt(join22(directory, "runs", "editor-run.json"));
|
|
37771
37779
|
if (note !== null) {
|
|
37772
37780
|
return note;
|
|
37773
37781
|
}
|
|
@@ -37777,7 +37785,7 @@ function readEditorRunNote() {
|
|
|
37777
37785
|
function editorNoteAt(path) {
|
|
37778
37786
|
let parsed;
|
|
37779
37787
|
try {
|
|
37780
|
-
parsed = JSON.parse(
|
|
37788
|
+
parsed = JSON.parse(readFileSync20(path, "utf8"));
|
|
37781
37789
|
} catch {
|
|
37782
37790
|
return null;
|
|
37783
37791
|
}
|
|
@@ -37800,7 +37808,7 @@ function recordRunEnded(pid, exitCode) {
|
|
|
37800
37808
|
return;
|
|
37801
37809
|
}
|
|
37802
37810
|
try {
|
|
37803
|
-
|
|
37811
|
+
writeFileSync15(path, JSON.stringify({ ...record, exitCode }, null, 2), "utf8");
|
|
37804
37812
|
} catch {}
|
|
37805
37813
|
}
|
|
37806
37814
|
function readRunRecord() {
|
|
@@ -37815,7 +37823,7 @@ function readRunRecord() {
|
|
|
37815
37823
|
function recordAt(path) {
|
|
37816
37824
|
let parsed;
|
|
37817
37825
|
try {
|
|
37818
|
-
parsed = JSON.parse(
|
|
37826
|
+
parsed = JSON.parse(readFileSync20(path, "utf8"));
|
|
37819
37827
|
} catch {
|
|
37820
37828
|
return null;
|
|
37821
37829
|
}
|
|
@@ -37860,7 +37868,7 @@ function runningAs(pid) {
|
|
|
37860
37868
|
const began = startedAt(pid, null);
|
|
37861
37869
|
const when = began === null ? {} : { startedAt: began };
|
|
37862
37870
|
if (process.platform === "linux") {
|
|
37863
|
-
const raw =
|
|
37871
|
+
const raw = readFileSync20(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ").trim();
|
|
37864
37872
|
return raw === "" ? null : { kind: "commandLine", text: raw, ...when };
|
|
37865
37873
|
}
|
|
37866
37874
|
const args = execFileSync2("ps", ["-p", String(pid), "-o", "args="], {
|
|
@@ -37987,7 +37995,7 @@ function clearRunRecord(ours = () => true) {
|
|
|
37987
37995
|
continue;
|
|
37988
37996
|
}
|
|
37989
37997
|
try {
|
|
37990
|
-
|
|
37998
|
+
rmSync11(path);
|
|
37991
37999
|
} catch {}
|
|
37992
38000
|
}
|
|
37993
38001
|
}
|
|
@@ -38011,12 +38019,12 @@ function sweepTranscripts(keepMs = 24 * 60 * 60 * 1000, now = Date.now()) {
|
|
|
38011
38019
|
if (!entry.startsWith("run-") || !entry.endsWith(".log")) {
|
|
38012
38020
|
continue;
|
|
38013
38021
|
}
|
|
38014
|
-
const path =
|
|
38022
|
+
const path = join22(directory, entry);
|
|
38015
38023
|
if (path === keep || ageMs(path, now) < keepMs) {
|
|
38016
38024
|
continue;
|
|
38017
38025
|
}
|
|
38018
38026
|
try {
|
|
38019
|
-
|
|
38027
|
+
rmSync11(path);
|
|
38020
38028
|
} catch {}
|
|
38021
38029
|
}
|
|
38022
38030
|
}
|
|
@@ -38037,17 +38045,17 @@ import {
|
|
|
38037
38045
|
copyFileSync,
|
|
38038
38046
|
existsSync as existsSync15,
|
|
38039
38047
|
fstatSync,
|
|
38040
|
-
mkdirSync as
|
|
38048
|
+
mkdirSync as mkdirSync14,
|
|
38041
38049
|
mkdtempSync as mkdtempSync3,
|
|
38042
38050
|
openSync as openSync3,
|
|
38043
38051
|
readdirSync as readdirSync9,
|
|
38044
|
-
readFileSync as
|
|
38052
|
+
readFileSync as readFileSync21,
|
|
38045
38053
|
readSync as readSync2,
|
|
38046
38054
|
rmdirSync,
|
|
38047
38055
|
statSync as statSync8
|
|
38048
38056
|
} from "node:fs";
|
|
38049
38057
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
38050
|
-
import { basename as basename4, dirname as
|
|
38058
|
+
import { basename as basename4, dirname as dirname16, extname as extname2, isAbsolute as isAbsolute3, join as join23, normalize as normalize3, relative as relative3 } from "node:path";
|
|
38051
38059
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
38052
38060
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
38053
38061
|
import { promisify as promisify7 } from "node:util";
|
|
@@ -38061,11 +38069,11 @@ function captureDestinationRefusal(outputPath, projects) {
|
|
|
38061
38069
|
if (extname2(outputPath).toLowerCase() !== ".png") {
|
|
38062
38070
|
return `outputPath ${outputPath} does not end in .png, which is what a capture is.`;
|
|
38063
38071
|
}
|
|
38064
|
-
const directory = realPathOr(
|
|
38072
|
+
const directory = realPathOr(dirname16(outputPath));
|
|
38065
38073
|
if (!existsSync15(directory)) {
|
|
38066
|
-
return `outputPath's directory ${
|
|
38074
|
+
return `outputPath's directory ${dirname16(outputPath)} does not exist; a capture creates no directories.`;
|
|
38067
38075
|
}
|
|
38068
|
-
const where =
|
|
38076
|
+
const where = join23(directory, basename4(outputPath));
|
|
38069
38077
|
const inside = projects.find((project) => project !== "" && isWithinRoot(realPathOr(project), where));
|
|
38070
38078
|
if (inside !== undefined) {
|
|
38071
38079
|
return `outputPath ${outputPath} is inside the project at ${inside}; a capture is saved outside it, so it never becomes part of the game.`;
|
|
@@ -38313,7 +38321,7 @@ function aboveTheRunner(entry) {
|
|
|
38313
38321
|
}
|
|
38314
38322
|
function elsewhereIn(projectPath, asked) {
|
|
38315
38323
|
const wanted = asked.replace(/^res:\/\//, "").replace(/\/+$/, "");
|
|
38316
|
-
if (wanted === "" || existsSync15(
|
|
38324
|
+
if (wanted === "" || existsSync15(join23(projectPath, wanted))) {
|
|
38317
38325
|
return "";
|
|
38318
38326
|
}
|
|
38319
38327
|
const root = (wanted.split("/")[0] ?? "").toLowerCase();
|
|
@@ -38327,7 +38335,7 @@ function elsewhereIn(projectPath, asked) {
|
|
|
38327
38335
|
return near.length === 0 ? "" : ` The project does have ${there}.`;
|
|
38328
38336
|
}
|
|
38329
38337
|
function hasMainScene(projectFile) {
|
|
38330
|
-
const scene = parseProjectGodot(
|
|
38338
|
+
const scene = parseProjectGodot(readFileSync21(projectFile, "utf8"))["application"]?.["run/main_scene"];
|
|
38331
38339
|
return typeof scene === "string" && scene !== "";
|
|
38332
38340
|
}
|
|
38333
38341
|
function runtimeAddonAnnouncesEditors(projectPath) {
|
|
@@ -38335,13 +38343,13 @@ function runtimeAddonAnnouncesEditors(projectPath) {
|
|
|
38335
38343
|
return false;
|
|
38336
38344
|
}
|
|
38337
38345
|
try {
|
|
38338
|
-
return
|
|
38346
|
+
return readFileSync21(join23(projectPath, RUNTIME_AUTOLOAD2.path), "utf8").includes('"editor_pid"');
|
|
38339
38347
|
} catch {
|
|
38340
38348
|
return false;
|
|
38341
38349
|
}
|
|
38342
38350
|
}
|
|
38343
38351
|
function editorPlaysHeadless(projectFile) {
|
|
38344
|
-
const runArgs = parseProjectGodot(
|
|
38352
|
+
const runArgs = parseProjectGodot(readFileSync21(projectFile, "utf8"))["editor"]?.["run/main_run_args"];
|
|
38345
38353
|
return typeof runArgs === "string" && /(?:^|\s)--headless(?:\s|$)/.test(runArgs);
|
|
38346
38354
|
}
|
|
38347
38355
|
function camelCased(params) {
|
|
@@ -38360,7 +38368,7 @@ function needsItsOwnProcess(asked) {
|
|
|
38360
38368
|
class GodotServer {
|
|
38361
38369
|
mcp;
|
|
38362
38370
|
locator = new GodotLocator2;
|
|
38363
|
-
operationsScript =
|
|
38371
|
+
operationsScript = join23(__dirname2, "godot", "operations", "godot_operations.gd");
|
|
38364
38372
|
godotBridge;
|
|
38365
38373
|
tools = buildToolDefinitions();
|
|
38366
38374
|
activeProcess = null;
|
|
@@ -38504,7 +38512,7 @@ class GodotServer {
|
|
|
38504
38512
|
if (this.ownProject === null) {
|
|
38505
38513
|
return null;
|
|
38506
38514
|
}
|
|
38507
|
-
const announced =
|
|
38515
|
+
const announced = readAnnouncement2(announcementPath2(this.ownProject));
|
|
38508
38516
|
if (announced === null || announced.pid === process.pid) {
|
|
38509
38517
|
return null;
|
|
38510
38518
|
}
|
|
@@ -38591,7 +38599,7 @@ class GodotServer {
|
|
|
38591
38599
|
}
|
|
38592
38600
|
setupToolHandlers() {
|
|
38593
38601
|
this.mcp.server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: this.tools }));
|
|
38594
|
-
this.mcp.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
38602
|
+
this.mcp.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
38595
38603
|
this.logDebug(`Handling tool request: ${request.params.name}`);
|
|
38596
38604
|
const spec = toolSpec(request.params.name);
|
|
38597
38605
|
if (!spec) {
|
|
@@ -38606,7 +38614,7 @@ class GodotServer {
|
|
|
38606
38614
|
this.lastProjectPath = args["projectPath"];
|
|
38607
38615
|
}
|
|
38608
38616
|
this.updates.refresh();
|
|
38609
|
-
const answer = await this.answered(spec.name, checked.op ?? "", args);
|
|
38617
|
+
const answer = await withCallSignal(extra.signal, () => this.answered(spec.name, checked.op ?? "", args));
|
|
38610
38618
|
return this.withFeedbackNotice(this.withUpdateNotice(answer));
|
|
38611
38619
|
});
|
|
38612
38620
|
}
|
|
@@ -38614,7 +38622,7 @@ class GodotServer {
|
|
|
38614
38622
|
try {
|
|
38615
38623
|
return await this.dispatch(tool, op, args);
|
|
38616
38624
|
} catch (error) {
|
|
38617
|
-
if (error instanceof McpError || error instanceof
|
|
38625
|
+
if (error instanceof McpError || error instanceof Refusal) {
|
|
38618
38626
|
throw error;
|
|
38619
38627
|
}
|
|
38620
38628
|
const where = op === "" ? tool : `${tool} op=${op}`;
|
|
@@ -39025,7 +39033,7 @@ class GodotServer {
|
|
|
39025
39033
|
if (path === undefined) {
|
|
39026
39034
|
return { ok: false, response: this.createErrorResponse("projectPath is required.") };
|
|
39027
39035
|
}
|
|
39028
|
-
const file =
|
|
39036
|
+
const file = join23(path, "project.godot");
|
|
39029
39037
|
if (!existsSync15(file)) {
|
|
39030
39038
|
return {
|
|
39031
39039
|
ok: false,
|
|
@@ -39294,7 +39302,7 @@ class GodotServer {
|
|
|
39294
39302
|
if (!engine.ok) {
|
|
39295
39303
|
return engine.response;
|
|
39296
39304
|
}
|
|
39297
|
-
const application = parseProjectGodot(
|
|
39305
|
+
const application = parseProjectGodot(readFileSync21(project.value.file, "utf8"))["application"] ?? {};
|
|
39298
39306
|
const name = application["config/name"];
|
|
39299
39307
|
const mainScene = application["run/main_scene"];
|
|
39300
39308
|
const info = {
|
|
@@ -39355,18 +39363,18 @@ class GodotServer {
|
|
|
39355
39363
|
if (!engine.ok) {
|
|
39356
39364
|
return engine.response;
|
|
39357
39365
|
}
|
|
39358
|
-
const folder =
|
|
39366
|
+
const folder = dirname16(output.absolutePath);
|
|
39359
39367
|
try {
|
|
39360
|
-
|
|
39368
|
+
mkdirSync14(folder, { recursive: true });
|
|
39361
39369
|
} catch (error) {
|
|
39362
|
-
return this.createErrorResponse(`Cannot create ${
|
|
39370
|
+
return this.createErrorResponse(`Cannot create ${dirname16(output.relativePath)} to export into: ${errorMessage(error)}`);
|
|
39363
39371
|
}
|
|
39364
39372
|
const debug = readBoolean(args, "debug") ?? false;
|
|
39365
|
-
const exportLogs = mkdtempSync3(
|
|
39373
|
+
const exportLogs = mkdtempSync3(join23(tmpdir5(), "gdharness-export-"));
|
|
39366
39374
|
const exportArgs = [
|
|
39367
39375
|
"--headless",
|
|
39368
39376
|
"--log-file",
|
|
39369
|
-
|
|
39377
|
+
join23(exportLogs, "engine.log"),
|
|
39370
39378
|
"--path",
|
|
39371
39379
|
project.value.path,
|
|
39372
39380
|
debug ? "--export-debug" : "--export-release",
|
|
@@ -39377,7 +39385,10 @@ class GodotServer {
|
|
|
39377
39385
|
const log = new GameLog;
|
|
39378
39386
|
let exitCode = 0;
|
|
39379
39387
|
try {
|
|
39380
|
-
const { stdout, stderr } = await run7(engine.value, exportArgs, {
|
|
39388
|
+
const { stdout, stderr } = await run7(engine.value, exportArgs, {
|
|
39389
|
+
timeout: 300000,
|
|
39390
|
+
signal: callSignal()
|
|
39391
|
+
});
|
|
39381
39392
|
log.append("stdout", stdout);
|
|
39382
39393
|
log.append("stderr", stderr);
|
|
39383
39394
|
} catch (error) {
|
|
@@ -39424,7 +39435,7 @@ class GodotServer {
|
|
|
39424
39435
|
return contained.response;
|
|
39425
39436
|
}
|
|
39426
39437
|
const runner = "addons/gdUnit4/bin/GdUnitCmdTool.gd";
|
|
39427
|
-
if (!existsSync15(
|
|
39438
|
+
if (!existsSync15(join23(project.value.path, runner))) {
|
|
39428
39439
|
return this.createErrorResponse(`gdUnit4 is not installed in this project: no ${runner}.`, [
|
|
39429
39440
|
"Install gdUnit4 under addons/gdUnit4, from https://github.com/godot-gdunit-labs/gdUnit4"
|
|
39430
39441
|
]);
|
|
@@ -39459,7 +39470,7 @@ class GodotServer {
|
|
|
39459
39470
|
];
|
|
39460
39471
|
const timeoutMs = readPositiveNumber(args, "timeoutMs") ?? 600000;
|
|
39461
39472
|
this.logDebug(`Running tests: ${engine.value} ${cmdArgs.join(" ")}`);
|
|
39462
|
-
const userData = mkdtempSync3(
|
|
39473
|
+
const userData = mkdtempSync3(join23(tmpdir5(), "gdharness-tests-"));
|
|
39463
39474
|
const run = this.spawnGame(engine.value, cmdArgs, userDataIn(userData));
|
|
39464
39475
|
const hung = await new Promise((resolve) => {
|
|
39465
39476
|
const timer = setTimeout(() => {
|
|
@@ -39475,21 +39486,21 @@ class GodotServer {
|
|
|
39475
39486
|
resolve(false);
|
|
39476
39487
|
});
|
|
39477
39488
|
});
|
|
39478
|
-
const reportsDir =
|
|
39489
|
+
const reportsDir = join23(project.value.path, ".godot", ...ours.split("/"));
|
|
39479
39490
|
let report = null;
|
|
39480
39491
|
let reportProblem = null;
|
|
39481
39492
|
try {
|
|
39482
39493
|
const written = existsSync15(reportsDir) ? readdirSync9(reportsDir).filter((name) => name.startsWith("report_")).sort((a, b) => Number(a.slice("report_".length)) - Number(b.slice("report_".length))) : [];
|
|
39483
39494
|
const newest = written.at(-1);
|
|
39484
39495
|
if (newest !== undefined) {
|
|
39485
|
-
report = parseJUnit(
|
|
39496
|
+
report = parseJUnit(readFileSync21(join23(reportsDir, newest, "results.xml"), "utf8"));
|
|
39486
39497
|
}
|
|
39487
39498
|
} catch (error) {
|
|
39488
39499
|
reportProblem = errorMessage(error);
|
|
39489
39500
|
} finally {
|
|
39490
39501
|
discard(reportsDir, userData);
|
|
39491
39502
|
try {
|
|
39492
|
-
rmdirSync(
|
|
39503
|
+
rmdirSync(dirname16(reportsDir));
|
|
39493
39504
|
} catch {}
|
|
39494
39505
|
}
|
|
39495
39506
|
const engineEntries = run.log.select({ severity: "warning", sinceLastCall: false, limit: 200 }).entries.map(aboveTheRunner);
|
|
@@ -39625,7 +39636,7 @@ class GodotServer {
|
|
|
39625
39636
|
return null;
|
|
39626
39637
|
}
|
|
39627
39638
|
try {
|
|
39628
|
-
return
|
|
39639
|
+
return readFileSync21(contained.absolutePath, "utf8");
|
|
39629
39640
|
} catch {
|
|
39630
39641
|
return null;
|
|
39631
39642
|
}
|
|
@@ -39679,7 +39690,7 @@ class GodotServer {
|
|
|
39679
39690
|
return null;
|
|
39680
39691
|
}
|
|
39681
39692
|
try {
|
|
39682
|
-
return
|
|
39693
|
+
return readFileSync21(contained.absolutePath, "utf8");
|
|
39683
39694
|
} catch {
|
|
39684
39695
|
return null;
|
|
39685
39696
|
}
|
|
@@ -39908,7 +39919,7 @@ class GodotServer {
|
|
|
39908
39919
|
return null;
|
|
39909
39920
|
}
|
|
39910
39921
|
try {
|
|
39911
|
-
return settingKeys(
|
|
39922
|
+
return settingKeys(readFileSync21(join23(projectPath, "project.godot"), "utf8"));
|
|
39912
39923
|
} catch {
|
|
39913
39924
|
return null;
|
|
39914
39925
|
}
|
|
@@ -40159,7 +40170,7 @@ class GodotServer {
|
|
|
40159
40170
|
}
|
|
40160
40171
|
async runtimeUp(projectPath, before, budget, withArgs) {
|
|
40161
40172
|
const budgetMs = budget.ms;
|
|
40162
|
-
if (!existsSync15(
|
|
40173
|
+
if (!existsSync15(join23(projectPath, RUNTIME_AUTOLOAD2.path))) {
|
|
40163
40174
|
return runtimeVerdict(null, { addon: false, budgetMs, heldAt: null, running: false, withArgs });
|
|
40164
40175
|
}
|
|
40165
40176
|
let asking = null;
|
|
@@ -40393,6 +40404,23 @@ class GodotServer {
|
|
|
40393
40404
|
}
|
|
40394
40405
|
spawnGame(godotPath, cmdArgs, env) {
|
|
40395
40406
|
const child = spawn(godotPath, cmdArgs, { stdio: ["ignore", "pipe", "pipe"], ...env ? { env } : {} });
|
|
40407
|
+
const cancelled = callSignal();
|
|
40408
|
+
if (cancelled !== undefined) {
|
|
40409
|
+
const end = () => {
|
|
40410
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
40411
|
+
this.logDebug(`The call waiting on pid ${child.pid ?? "unknown"} was cancelled; ending it.`);
|
|
40412
|
+
child.kill();
|
|
40413
|
+
}
|
|
40414
|
+
};
|
|
40415
|
+
if (cancelled.aborted) {
|
|
40416
|
+
end();
|
|
40417
|
+
} else {
|
|
40418
|
+
cancelled.addEventListener("abort", end, { once: true });
|
|
40419
|
+
child.once("exit", () => {
|
|
40420
|
+
cancelled.removeEventListener("abort", end);
|
|
40421
|
+
});
|
|
40422
|
+
}
|
|
40423
|
+
}
|
|
40396
40424
|
const log = new GameLog;
|
|
40397
40425
|
const started = {
|
|
40398
40426
|
process: child,
|
|
@@ -41325,7 +41353,7 @@ class GodotServer {
|
|
|
41325
41353
|
async ownRunOnItsWay(projectPath, budgetMs) {
|
|
41326
41354
|
const run = this.currentRun();
|
|
41327
41355
|
const project = projectPath ?? run?.projectPath ?? null;
|
|
41328
|
-
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync15(
|
|
41356
|
+
if (run === null || project === null || run.announcedPid !== undefined || run.projectPath !== null && !isSameDirectory(run.projectPath, project) || !existsSync15(join23(project, RUNTIME_AUTOLOAD2.path)) || !await this.runStillGoing(run)) {
|
|
41329
41357
|
return null;
|
|
41330
41358
|
}
|
|
41331
41359
|
const already = runtimesAnnounced().running;
|
|
@@ -41404,8 +41432,8 @@ class GodotServer {
|
|
|
41404
41432
|
return this.createErrorResponse(refusal);
|
|
41405
41433
|
}
|
|
41406
41434
|
}
|
|
41407
|
-
const screenshotDir = expectsScreenshot ? mkdtempSync3(
|
|
41408
|
-
const screenshotPath = screenshotDir ?
|
|
41435
|
+
const screenshotDir = expectsScreenshot ? mkdtempSync3(join23(tmpdir5(), "gdharness-runtime-screenshot-")) : null;
|
|
41436
|
+
const screenshotPath = screenshotDir ? join23(screenshotDir, "capture.png") : null;
|
|
41409
41437
|
try {
|
|
41410
41438
|
const reply = await runtimeRequest(choice.endpoint, command, screenshotPath ? { ...params, output_path: screenshotPath } : params, timeoutMs);
|
|
41411
41439
|
if (!reply.ok) {
|
|
@@ -41436,7 +41464,7 @@ class GodotServer {
|
|
|
41436
41464
|
type: "text",
|
|
41437
41465
|
text: `Screenshot captured: ${dimensions}${chosenAmongSeveral ? ` from pid ${own}, the game this server holds` : ""}${saveTo === null ? "" : `. Saved to ${saveTo}`}`
|
|
41438
41466
|
},
|
|
41439
|
-
{ type: "image", data:
|
|
41467
|
+
{ type: "image", data: readFileSync21(screenshotPath).toString("base64"), mimeType: "image/png" }
|
|
41440
41468
|
]
|
|
41441
41469
|
};
|
|
41442
41470
|
} finally {
|
|
@@ -41515,6 +41543,7 @@ var init_server3 = __esm(() => {
|
|
|
41515
41543
|
init_boot_note();
|
|
41516
41544
|
init_breakpoint_note();
|
|
41517
41545
|
init_bridge_announce();
|
|
41546
|
+
init_call_signal();
|
|
41518
41547
|
init_class_cache();
|
|
41519
41548
|
init_class_note();
|
|
41520
41549
|
init_config_pin();
|
|
@@ -41544,7 +41573,7 @@ var init_server3 = __esm(() => {
|
|
|
41544
41573
|
init_tool_definitions();
|
|
41545
41574
|
init_update_check();
|
|
41546
41575
|
run7 = promisify7(execFile7);
|
|
41547
|
-
__dirname2 =
|
|
41576
|
+
__dirname2 = dirname16(fileURLToPath5(import.meta.url));
|
|
41548
41577
|
CONSOLE_WRAPPER = /_console(\.exe)?$/i;
|
|
41549
41578
|
LONGEST_BOOT_NOTED_MS = 5 * 60000;
|
|
41550
41579
|
VALUE_NAMES = {
|
|
@@ -41585,20 +41614,61 @@ var init_server3 = __esm(() => {
|
|
|
41585
41614
|
|
|
41586
41615
|
// src/cli.ts
|
|
41587
41616
|
import { existsSync as existsSync16 } from "fs";
|
|
41588
|
-
import { join as
|
|
41617
|
+
import { join as join24, resolve as resolve5 } from "path";
|
|
41618
|
+
|
|
41619
|
+
// src/bridge-announce.ts
|
|
41620
|
+
init_errors();
|
|
41621
|
+
init_process_children();
|
|
41622
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
41623
|
+
import { dirname, join } from "node:path";
|
|
41624
|
+
function announcementPath(projectPath) {
|
|
41625
|
+
return join(projectPath, ".godot", "gdharness-bridge.json");
|
|
41626
|
+
}
|
|
41627
|
+
function readAnnouncement(path) {
|
|
41628
|
+
try {
|
|
41629
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
41630
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
41631
|
+
return null;
|
|
41632
|
+
}
|
|
41633
|
+
const said = parsed;
|
|
41634
|
+
if (typeof said.port !== "number" || typeof said.pid !== "number") {
|
|
41635
|
+
return null;
|
|
41636
|
+
}
|
|
41637
|
+
return said;
|
|
41638
|
+
} catch {
|
|
41639
|
+
return null;
|
|
41640
|
+
}
|
|
41641
|
+
}
|
|
41642
|
+
function serverBehind(announcement, startedAt) {
|
|
41643
|
+
if (announcement === null || typeof announcement.version !== "string" || startedAt === undefined) {
|
|
41644
|
+
return null;
|
|
41645
|
+
}
|
|
41646
|
+
const announcedAt = Date.parse(announcement.startedAt);
|
|
41647
|
+
if (Number.isNaN(announcedAt) || startedAt > announcedAt + 1000) {
|
|
41648
|
+
return null;
|
|
41649
|
+
}
|
|
41650
|
+
return { version: announcement.version, pid: announcement.pid };
|
|
41651
|
+
}
|
|
41652
|
+
function serverServing(projectPath) {
|
|
41653
|
+
const announcement = readAnnouncement(announcementPath(projectPath));
|
|
41654
|
+
if (announcement === null) {
|
|
41655
|
+
return null;
|
|
41656
|
+
}
|
|
41657
|
+
return serverBehind(announcement, startTimesOf([announcement.pid]).get(announcement.pid));
|
|
41658
|
+
}
|
|
41589
41659
|
|
|
41590
41660
|
// src/errors.ts
|
|
41591
|
-
class
|
|
41661
|
+
class Refusal2 extends Error {
|
|
41592
41662
|
}
|
|
41593
41663
|
|
|
41594
41664
|
// src/godot-path.ts
|
|
41595
41665
|
init_detection();
|
|
41596
41666
|
init_errors();
|
|
41597
|
-
import { execFile } from "node:child_process";
|
|
41667
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
41598
41668
|
import { existsSync as existsSync2 } from "node:fs";
|
|
41599
41669
|
import { normalize } from "node:path";
|
|
41600
|
-
import { promisify } from "node:util";
|
|
41601
|
-
var
|
|
41670
|
+
import { promisify as promisify2 } from "node:util";
|
|
41671
|
+
var run2 = promisify2(execFile2);
|
|
41602
41672
|
|
|
41603
41673
|
class GodotLocator {
|
|
41604
41674
|
answered = new Map;
|
|
@@ -41655,7 +41725,7 @@ class GodotLocator {
|
|
|
41655
41725
|
reason = "does not exist";
|
|
41656
41726
|
} else {
|
|
41657
41727
|
try {
|
|
41658
|
-
await
|
|
41728
|
+
await run2(path, ["--version"]);
|
|
41659
41729
|
reason = null;
|
|
41660
41730
|
} catch (error) {
|
|
41661
41731
|
reason = `does not answer --version: ${errorMessage(error)}`;
|
|
@@ -41667,9 +41737,9 @@ class GodotLocator {
|
|
|
41667
41737
|
}
|
|
41668
41738
|
|
|
41669
41739
|
// src/harnesses.ts
|
|
41670
|
-
import { existsSync as existsSync4, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
41740
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
41671
41741
|
import { homedir as homedir2 } from "node:os";
|
|
41672
|
-
import { dirname as
|
|
41742
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
41673
41743
|
import process3 from "node:process";
|
|
41674
41744
|
|
|
41675
41745
|
// node_modules/yaml/dist/index.js
|
|
@@ -41842,7 +41912,7 @@ var HARNESSES = [
|
|
|
41842
41912
|
shape: "plain",
|
|
41843
41913
|
home: ".claude",
|
|
41844
41914
|
marker: ".claude",
|
|
41845
|
-
skills: { dir:
|
|
41915
|
+
skills: { dir: join4(".claude", "skills"), shared: false }
|
|
41846
41916
|
},
|
|
41847
41917
|
{
|
|
41848
41918
|
id: "copilot-cli",
|
|
@@ -41852,7 +41922,7 @@ var HARNESSES = [
|
|
|
41852
41922
|
container: "mcpServers",
|
|
41853
41923
|
shape: "plain",
|
|
41854
41924
|
home: ".copilot",
|
|
41855
|
-
skills: { dir:
|
|
41925
|
+
skills: { dir: join4(".github", "skills"), shared: true },
|
|
41856
41926
|
manual: "Trust the folder when Copilot CLI first asks, or it reads no config here."
|
|
41857
41927
|
},
|
|
41858
41928
|
{
|
|
@@ -41878,22 +41948,22 @@ var HARNESSES = [
|
|
|
41878
41948
|
id: "cursor",
|
|
41879
41949
|
name: "Cursor",
|
|
41880
41950
|
scope: "project",
|
|
41881
|
-
file:
|
|
41951
|
+
file: join4(".cursor", "mcp.json"),
|
|
41882
41952
|
container: "mcpServers",
|
|
41883
41953
|
shape: "plain",
|
|
41884
41954
|
home: ".cursor",
|
|
41885
|
-
skills: { dir:
|
|
41955
|
+
skills: { dir: join4(".cursor", "skills"), shared: true },
|
|
41886
41956
|
manual: "Cursor asks before each tool call by default, and the server can be toggled off."
|
|
41887
41957
|
},
|
|
41888
41958
|
{
|
|
41889
41959
|
id: "vscode",
|
|
41890
41960
|
name: "VS Code",
|
|
41891
41961
|
scope: "project",
|
|
41892
|
-
file:
|
|
41962
|
+
file: join4(".vscode", "mcp.json"),
|
|
41893
41963
|
container: "servers",
|
|
41894
41964
|
shape: "typed",
|
|
41895
41965
|
home: ".vscode",
|
|
41896
|
-
skills: { dir:
|
|
41966
|
+
skills: { dir: join4(".github", "skills"), shared: true },
|
|
41897
41967
|
manual: "VS Code asks you to trust a server the first time it starts one."
|
|
41898
41968
|
},
|
|
41899
41969
|
{
|
|
@@ -41903,45 +41973,45 @@ var HARNESSES = [
|
|
|
41903
41973
|
file: "opencode.json",
|
|
41904
41974
|
container: "mcp",
|
|
41905
41975
|
shape: "opencode",
|
|
41906
|
-
home:
|
|
41976
|
+
home: join4(".config", "opencode"),
|
|
41907
41977
|
marker: ".opencode",
|
|
41908
|
-
skills: { dir:
|
|
41978
|
+
skills: { dir: join4(".opencode", "skills"), shared: true }
|
|
41909
41979
|
},
|
|
41910
41980
|
{
|
|
41911
41981
|
id: "junie",
|
|
41912
41982
|
name: "Junie",
|
|
41913
41983
|
scope: "project",
|
|
41914
|
-
file:
|
|
41984
|
+
file: join4(".junie", "mcp", "mcp.json"),
|
|
41915
41985
|
container: "mcpServers",
|
|
41916
41986
|
shape: "plain",
|
|
41917
41987
|
home: ".junie",
|
|
41918
|
-
skills: { dir:
|
|
41988
|
+
skills: { dir: join4(".junie", "skills"), shared: true }
|
|
41919
41989
|
},
|
|
41920
41990
|
{
|
|
41921
41991
|
id: "kiro",
|
|
41922
41992
|
name: "Kiro",
|
|
41923
41993
|
scope: "project",
|
|
41924
|
-
file:
|
|
41994
|
+
file: join4(".kiro", "settings", "mcp.json"),
|
|
41925
41995
|
container: "mcpServers",
|
|
41926
41996
|
shape: "plain",
|
|
41927
41997
|
home: ".kiro",
|
|
41928
|
-
skills: { dir:
|
|
41998
|
+
skills: { dir: join4(".kiro", "skills"), shared: false }
|
|
41929
41999
|
},
|
|
41930
42000
|
{
|
|
41931
42001
|
id: "gemini",
|
|
41932
42002
|
name: "Gemini CLI",
|
|
41933
42003
|
scope: "project",
|
|
41934
|
-
file:
|
|
42004
|
+
file: join4(".gemini", "settings.json"),
|
|
41935
42005
|
container: "mcpServers",
|
|
41936
42006
|
shape: "plain",
|
|
41937
42007
|
home: ".gemini",
|
|
41938
|
-
skills: { dir:
|
|
42008
|
+
skills: { dir: join4(".gemini", "skills"), shared: true }
|
|
41939
42009
|
},
|
|
41940
42010
|
{
|
|
41941
42011
|
id: "roo",
|
|
41942
42012
|
name: "Roo Code",
|
|
41943
42013
|
scope: "project",
|
|
41944
|
-
file:
|
|
42014
|
+
file: join4(".roo", "mcp.json"),
|
|
41945
42015
|
container: "mcpServers",
|
|
41946
42016
|
shape: "plain"
|
|
41947
42017
|
},
|
|
@@ -41949,7 +42019,7 @@ var HARNESSES = [
|
|
|
41949
42019
|
id: "kilo",
|
|
41950
42020
|
name: "Kilo Code",
|
|
41951
42021
|
scope: "project",
|
|
41952
|
-
file:
|
|
42022
|
+
file: join4(".kilocode", "mcp.json"),
|
|
41953
42023
|
container: "mcpServers",
|
|
41954
42024
|
shape: "plain"
|
|
41955
42025
|
},
|
|
@@ -41957,16 +42027,16 @@ var HARNESSES = [
|
|
|
41957
42027
|
id: "amazon-q",
|
|
41958
42028
|
name: "Amazon Q Developer CLI",
|
|
41959
42029
|
scope: "project",
|
|
41960
|
-
file:
|
|
42030
|
+
file: join4(".amazonq", "mcp.json"),
|
|
41961
42031
|
container: "mcpServers",
|
|
41962
42032
|
shape: "plain",
|
|
41963
|
-
home:
|
|
42033
|
+
home: join4(".aws", "amazonq")
|
|
41964
42034
|
},
|
|
41965
42035
|
{
|
|
41966
42036
|
id: "zed",
|
|
41967
42037
|
name: "Zed",
|
|
41968
42038
|
scope: "project",
|
|
41969
|
-
file:
|
|
42039
|
+
file: join4(".zed", "settings.json"),
|
|
41970
42040
|
container: "context_servers",
|
|
41971
42041
|
shape: "plain"
|
|
41972
42042
|
},
|
|
@@ -41974,16 +42044,16 @@ var HARNESSES = [
|
|
|
41974
42044
|
id: "amp",
|
|
41975
42045
|
name: "Amp",
|
|
41976
42046
|
scope: "project",
|
|
41977
|
-
file:
|
|
42047
|
+
file: join4(".amp", "settings.json"),
|
|
41978
42048
|
container: "amp.mcpServers",
|
|
41979
42049
|
shape: "plain",
|
|
41980
|
-
home:
|
|
42050
|
+
home: join4(".config", "amp")
|
|
41981
42051
|
},
|
|
41982
42052
|
{
|
|
41983
42053
|
id: "warp",
|
|
41984
42054
|
name: "Warp",
|
|
41985
42055
|
scope: "project",
|
|
41986
|
-
file:
|
|
42056
|
+
file: join4(".warp", ".mcp.json"),
|
|
41987
42057
|
container: "mcpServers",
|
|
41988
42058
|
shape: "plain",
|
|
41989
42059
|
home: ".warp",
|
|
@@ -41993,7 +42063,7 @@ var HARNESSES = [
|
|
|
41993
42063
|
id: "trae",
|
|
41994
42064
|
name: "Trae",
|
|
41995
42065
|
scope: "project",
|
|
41996
|
-
file:
|
|
42066
|
+
file: join4(".trae", "mcp.json"),
|
|
41997
42067
|
container: "mcpServers",
|
|
41998
42068
|
shape: "plain",
|
|
41999
42069
|
home: ".trae"
|
|
@@ -42002,7 +42072,7 @@ var HARNESSES = [
|
|
|
42002
42072
|
id: "factory",
|
|
42003
42073
|
name: "Factory Droid",
|
|
42004
42074
|
scope: "project",
|
|
42005
|
-
file:
|
|
42075
|
+
file: join4(".factory", "mcp.json"),
|
|
42006
42076
|
container: "mcpServers",
|
|
42007
42077
|
shape: "typed",
|
|
42008
42078
|
home: ".factory"
|
|
@@ -42011,7 +42081,7 @@ var HARNESSES = [
|
|
|
42011
42081
|
id: "tabnine",
|
|
42012
42082
|
name: "Tabnine",
|
|
42013
42083
|
scope: "project",
|
|
42014
|
-
file:
|
|
42084
|
+
file: join4(".tabnine", "mcp_servers.json"),
|
|
42015
42085
|
container: "mcpServers",
|
|
42016
42086
|
shape: "plain",
|
|
42017
42087
|
home: ".tabnine"
|
|
@@ -42028,7 +42098,7 @@ var HARNESSES = [
|
|
|
42028
42098
|
id: "pi",
|
|
42029
42099
|
name: "pi",
|
|
42030
42100
|
scope: "project",
|
|
42031
|
-
file:
|
|
42101
|
+
file: join4(".pi", "mcp.json"),
|
|
42032
42102
|
container: "mcpServers",
|
|
42033
42103
|
shape: "plain",
|
|
42034
42104
|
home: ".pi"
|
|
@@ -42037,7 +42107,7 @@ var HARNESSES = [
|
|
|
42037
42107
|
id: "mistral-vibe",
|
|
42038
42108
|
name: "Mistral Vibe",
|
|
42039
42109
|
scope: "project",
|
|
42040
|
-
file:
|
|
42110
|
+
file: join4(".vibe", "config.toml"),
|
|
42041
42111
|
container: "mcp_servers",
|
|
42042
42112
|
shape: "plain",
|
|
42043
42113
|
toml: {
|
|
@@ -42093,7 +42163,7 @@ var HARNESSES = [
|
|
|
42093
42163
|
id: "codex",
|
|
42094
42164
|
name: "Codex CLI",
|
|
42095
42165
|
scope: "home",
|
|
42096
|
-
file:
|
|
42166
|
+
file: join4(".codex", "config.toml"),
|
|
42097
42167
|
container: "mcp_servers",
|
|
42098
42168
|
shape: "plain",
|
|
42099
42169
|
manual: "Codex reads its config at startup, so restart it.",
|
|
@@ -42112,20 +42182,20 @@ var HARNESSES = [
|
|
|
42112
42182
|
id: "cline",
|
|
42113
42183
|
name: "Cline",
|
|
42114
42184
|
scope: "home",
|
|
42115
|
-
file:
|
|
42185
|
+
file: join4(".cline", "data", "settings", "cline_mcp_settings.json"),
|
|
42116
42186
|
container: "mcpServers",
|
|
42117
42187
|
shape: "plain",
|
|
42118
42188
|
marker: ".cline",
|
|
42119
|
-
skills: { dir:
|
|
42189
|
+
skills: { dir: join4(".cline", "skills"), shared: false }
|
|
42120
42190
|
},
|
|
42121
42191
|
{
|
|
42122
42192
|
id: "goose",
|
|
42123
42193
|
name: "Goose",
|
|
42124
42194
|
scope: "home",
|
|
42125
42195
|
file: {
|
|
42126
|
-
win32: { appData:
|
|
42127
|
-
darwin:
|
|
42128
|
-
linux:
|
|
42196
|
+
win32: { appData: join4("Block", "goose", "config", "config.yaml") },
|
|
42197
|
+
darwin: join4(".config", "goose", "config.yaml"),
|
|
42198
|
+
linux: join4(".config", "goose", "config.yaml")
|
|
42129
42199
|
},
|
|
42130
42200
|
container: "extensions",
|
|
42131
42201
|
shape: "plain",
|
|
@@ -42146,19 +42216,19 @@ var HARNESSES = [
|
|
|
42146
42216
|
id: "windsurf",
|
|
42147
42217
|
name: "Windsurf",
|
|
42148
42218
|
scope: "home",
|
|
42149
|
-
file:
|
|
42219
|
+
file: join4(".codeium", "windsurf", "mcp_config.json"),
|
|
42150
42220
|
container: "mcpServers",
|
|
42151
42221
|
shape: "plain",
|
|
42152
|
-
skills: { dir:
|
|
42222
|
+
skills: { dir: join4(".windsurf", "skills"), shared: true }
|
|
42153
42223
|
},
|
|
42154
42224
|
{
|
|
42155
42225
|
id: "hermes",
|
|
42156
42226
|
name: "Hermes",
|
|
42157
42227
|
scope: "home",
|
|
42158
|
-
file:
|
|
42228
|
+
file: join4(".hermes", "config.yaml"),
|
|
42159
42229
|
container: "mcp_servers",
|
|
42160
42230
|
shape: "plain",
|
|
42161
|
-
skills: { dir:
|
|
42231
|
+
skills: { dir: join4(".hermes", "skills"), shared: true },
|
|
42162
42232
|
yaml: {
|
|
42163
42233
|
path: ["mcp_servers", SERVER_KEY],
|
|
42164
42234
|
entry: (launch) => ({
|
|
@@ -42173,7 +42243,7 @@ var HARNESSES = [
|
|
|
42173
42243
|
id: "openclaw",
|
|
42174
42244
|
name: "OpenClaw",
|
|
42175
42245
|
scope: "home",
|
|
42176
|
-
file:
|
|
42246
|
+
file: join4(".openclaw", "openclaw.json"),
|
|
42177
42247
|
container: "mcpServers",
|
|
42178
42248
|
shape: "plain"
|
|
42179
42249
|
},
|
|
@@ -42182,9 +42252,9 @@ var HARNESSES = [
|
|
|
42182
42252
|
name: "Claude Desktop",
|
|
42183
42253
|
scope: "home",
|
|
42184
42254
|
file: {
|
|
42185
|
-
win32: { appData:
|
|
42186
|
-
darwin:
|
|
42187
|
-
linux:
|
|
42255
|
+
win32: { appData: join4("Claude", "claude_desktop_config.json") },
|
|
42256
|
+
darwin: join4("Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
42257
|
+
linux: join4(".config", "Claude", "claude_desktop_config.json")
|
|
42188
42258
|
},
|
|
42189
42259
|
container: "mcpServers",
|
|
42190
42260
|
shape: "plain"
|
|
@@ -42193,7 +42263,7 @@ var HARNESSES = [
|
|
|
42193
42263
|
id: "zeroclaw",
|
|
42194
42264
|
name: "ZeroClaw",
|
|
42195
42265
|
scope: "home",
|
|
42196
|
-
file:
|
|
42266
|
+
file: join4(".zeroclaw", "config.toml"),
|
|
42197
42267
|
container: "mcp.servers",
|
|
42198
42268
|
shape: "plain",
|
|
42199
42269
|
toml: {
|
|
@@ -42214,7 +42284,7 @@ var HARNESSES = [
|
|
|
42214
42284
|
id: "deepcode",
|
|
42215
42285
|
name: "Deep Code",
|
|
42216
42286
|
scope: "home",
|
|
42217
|
-
file:
|
|
42287
|
+
file: join4(".deepcode", "settings.json"),
|
|
42218
42288
|
container: "mcpServers",
|
|
42219
42289
|
shape: "plain"
|
|
42220
42290
|
},
|
|
@@ -42222,7 +42292,7 @@ var HARNESSES = [
|
|
|
42222
42292
|
id: "nanobot",
|
|
42223
42293
|
name: "nanobot",
|
|
42224
42294
|
scope: "home",
|
|
42225
|
-
file:
|
|
42295
|
+
file: join4(".nanobot", "config.json"),
|
|
42226
42296
|
container: "mcpServers",
|
|
42227
42297
|
shape: "plain",
|
|
42228
42298
|
snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
|
|
@@ -42231,17 +42301,17 @@ var HARNESSES = [
|
|
|
42231
42301
|
id: "autohand",
|
|
42232
42302
|
name: "Autohand",
|
|
42233
42303
|
scope: "home",
|
|
42234
|
-
file:
|
|
42304
|
+
file: join4(".autohand", "config.json"),
|
|
42235
42305
|
container: "mcpServers",
|
|
42236
42306
|
shape: "plain",
|
|
42237
42307
|
snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
|
|
42238
42308
|
}
|
|
42239
42309
|
];
|
|
42240
42310
|
function appDataRoot() {
|
|
42241
|
-
return process3.env["APPDATA"] ??
|
|
42311
|
+
return process3.env["APPDATA"] ?? join4(homedir2(), "AppData", "Roaming");
|
|
42242
42312
|
}
|
|
42243
42313
|
function homePath(path) {
|
|
42244
|
-
return typeof path === "string" ?
|
|
42314
|
+
return typeof path === "string" ? join4(homedir2(), path) : join4(appDataRoot(), path.appData);
|
|
42245
42315
|
}
|
|
42246
42316
|
function fileFor(harness, platform = process3.platform) {
|
|
42247
42317
|
if (typeof harness.file === "string") {
|
|
@@ -42252,7 +42322,7 @@ function fileFor(harness, platform = process3.platform) {
|
|
|
42252
42322
|
function configPath(harness, projectPath) {
|
|
42253
42323
|
const file = fileFor(harness);
|
|
42254
42324
|
if (harness.scope === "project") {
|
|
42255
|
-
return
|
|
42325
|
+
return join4(projectPath, file);
|
|
42256
42326
|
}
|
|
42257
42327
|
return homePath(file);
|
|
42258
42328
|
}
|
|
@@ -42311,11 +42381,11 @@ function present(harness, projectPath) {
|
|
|
42311
42381
|
return true;
|
|
42312
42382
|
}
|
|
42313
42383
|
const root = harness.scope === "project" ? projectPath : homedir2();
|
|
42314
|
-
const own =
|
|
42384
|
+
const own = dirname3(path);
|
|
42315
42385
|
if (own !== root && existsSync4(own)) {
|
|
42316
42386
|
return true;
|
|
42317
42387
|
}
|
|
42318
|
-
return harness.marker !== undefined && existsSync4(
|
|
42388
|
+
return harness.marker !== undefined && existsSync4(join4(root, harness.marker));
|
|
42319
42389
|
}
|
|
42320
42390
|
function candidates(projectPath) {
|
|
42321
42391
|
const found = [];
|
|
@@ -42328,7 +42398,7 @@ function candidates(projectPath) {
|
|
|
42328
42398
|
}
|
|
42329
42399
|
if (present(harness, projectPath)) {
|
|
42330
42400
|
found.push({ harness, reason: "configured" });
|
|
42331
|
-
} else if (harness.home !== undefined && existsSync4(
|
|
42401
|
+
} else if (harness.home !== undefined && existsSync4(join4(homedir2(), harness.home))) {
|
|
42332
42402
|
found.push({ harness, reason: "installed" });
|
|
42333
42403
|
}
|
|
42334
42404
|
}
|
|
@@ -42353,7 +42423,7 @@ function registered(harness, projectPath) {
|
|
|
42353
42423
|
if (harness.snippet !== undefined || !existsSync4(path)) {
|
|
42354
42424
|
return false;
|
|
42355
42425
|
}
|
|
42356
|
-
const text =
|
|
42426
|
+
const text = readFileSync2(path, "utf8");
|
|
42357
42427
|
if (harness.toml !== undefined) {
|
|
42358
42428
|
return text.includes(harness.toml.identity ?? harness.toml.header);
|
|
42359
42429
|
}
|
|
@@ -42383,7 +42453,7 @@ function recordedEnginePath(projectPath) {
|
|
|
42383
42453
|
}
|
|
42384
42454
|
let parsed;
|
|
42385
42455
|
try {
|
|
42386
|
-
parsed = JSON.parse(
|
|
42456
|
+
parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
42387
42457
|
} catch {
|
|
42388
42458
|
continue;
|
|
42389
42459
|
}
|
|
@@ -42406,7 +42476,7 @@ function disconnect(harness, projectPath) {
|
|
|
42406
42476
|
if (harness.snippet !== undefined) {
|
|
42407
42477
|
return { harness, path, action: "manual" };
|
|
42408
42478
|
}
|
|
42409
|
-
const text =
|
|
42479
|
+
const text = readFileSync2(path, "utf8");
|
|
42410
42480
|
if (harness.toml !== undefined) {
|
|
42411
42481
|
return taken(harness, path, text, removeToml(text, harness.toml));
|
|
42412
42482
|
}
|
|
@@ -42415,7 +42485,7 @@ function disconnect(harness, projectPath) {
|
|
|
42415
42485
|
}
|
|
42416
42486
|
let existing;
|
|
42417
42487
|
try {
|
|
42418
|
-
existing = JSON.parse(
|
|
42488
|
+
existing = JSON.parse(readFileSync2(path, "utf8"));
|
|
42419
42489
|
} catch {
|
|
42420
42490
|
return { harness, path, action: "absent" };
|
|
42421
42491
|
}
|
|
@@ -42435,25 +42505,32 @@ function disconnect(harness, projectPath) {
|
|
|
42435
42505
|
root[harness.container] = servers;
|
|
42436
42506
|
}
|
|
42437
42507
|
if (Object.keys(root).length === 0) {
|
|
42438
|
-
|
|
42508
|
+
rmSync2(path, { force: true });
|
|
42439
42509
|
return { harness, path, action: "deleted" };
|
|
42440
42510
|
}
|
|
42441
|
-
|
|
42511
|
+
writeFileSync2(path, `${JSON.stringify(root, null, 2)}
|
|
42442
42512
|
`, "utf8");
|
|
42443
42513
|
return { harness, path, action: "removed" };
|
|
42444
42514
|
}
|
|
42445
|
-
function harnessNote(repinned, now) {
|
|
42515
|
+
function harnessNote(repinned, now, running = null) {
|
|
42446
42516
|
const alsoByHand = repinned.byHand === 0 ? "" : `
|
|
42447
42517
|
${repinned.byHand === 1 ? "One harness above was" : `${repinned.byHand} harnesses above were`} handed a command to run instead; run it too.`;
|
|
42518
|
+
const serving = running === null ? ` No gdharness server is announcing itself for this project, so which one your harness
|
|
42519
|
+
` + ` is running cannot be read from here.
|
|
42520
|
+
` : ` The server serving this project is gdharness ${running.server.version} (pid ${running.server.pid})${running.isThisVersion ? ", which is already this version." : "."}
|
|
42521
|
+
`;
|
|
42522
|
+
if (running?.isThisVersion === true && repinned.byHand === 0 && (repinned.moved.length > 0 || repinned.written > 0)) {
|
|
42523
|
+
return ` 2. Nothing for the harness: the server serving this project is gdharness ${running.server.version}
|
|
42524
|
+
(pid ${running.server.pid}), which is already this version.`;
|
|
42525
|
+
}
|
|
42448
42526
|
if (repinned.moved.length > 0) {
|
|
42449
|
-
return ` 2. Your harness
|
|
42450
|
-
` + `
|
|
42451
|
-
` + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
|
|
42527
|
+
return ` 2. Your harness config held ${repinned.moved.join(", ")} before this upgrade.
|
|
42528
|
+
` + ` It names ${now} now.
|
|
42529
|
+
` + serving + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
|
|
42452
42530
|
}
|
|
42453
42531
|
if (repinned.written > 0) {
|
|
42454
|
-
return ` 2. Your harness config already named this version
|
|
42455
|
-
` + `
|
|
42456
|
-
` + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
|
|
42532
|
+
return ` 2. Your harness config already named this version.
|
|
42533
|
+
` + serving + ` Reconnect the MCP server, or restart the harness.${alsoByHand}`;
|
|
42457
42534
|
}
|
|
42458
42535
|
if (repinned.byHand > 0) {
|
|
42459
42536
|
return ` 2. None of the harness configs found here can be written for you, so nothing was
|
|
@@ -42480,7 +42557,7 @@ function connect(harness, projectPath, launch) {
|
|
|
42480
42557
|
if (harness.snippet !== undefined) {
|
|
42481
42558
|
return { harness, path, action: "snippet", snippet: harness.snippet(launch) };
|
|
42482
42559
|
}
|
|
42483
|
-
const held = existsSync4(path) ?
|
|
42560
|
+
const held = existsSync4(path) ? readFileSync2(path, "utf8") : "";
|
|
42484
42561
|
if (harness.toml !== undefined) {
|
|
42485
42562
|
const already = held.includes(harness.toml.identity ?? harness.toml.header);
|
|
42486
42563
|
return put(harness, path, writeToml(held, harness.toml, launch), already);
|
|
@@ -42494,7 +42571,7 @@ function connect(harness, projectPath, launch) {
|
|
|
42494
42571
|
try {
|
|
42495
42572
|
existing = JSON.parse(held);
|
|
42496
42573
|
} catch (cause) {
|
|
42497
|
-
throw new
|
|
42574
|
+
throw new Refusal(`${path} is not valid JSON, so gdharness was not added to it.`, { cause });
|
|
42498
42575
|
}
|
|
42499
42576
|
}
|
|
42500
42577
|
const container = typeof existing === "object" && existing !== null && !Array.isArray(existing) ? existing[harness.container] : undefined;
|
|
@@ -42506,8 +42583,8 @@ function connect(harness, projectPath, launch) {
|
|
|
42506
42583
|
return was === undefined || was === now ? written : { ...written, wasLaunchedBy: was };
|
|
42507
42584
|
}
|
|
42508
42585
|
function put(harness, path, contents, already) {
|
|
42509
|
-
|
|
42510
|
-
|
|
42586
|
+
mkdirSync2(dirname3(path), { recursive: true });
|
|
42587
|
+
writeFileSync2(path, contents, "utf8");
|
|
42511
42588
|
return { harness, path, action: already ? "replaced" : "written" };
|
|
42512
42589
|
}
|
|
42513
42590
|
function taken(harness, path, held, stripped) {
|
|
@@ -42515,22 +42592,23 @@ function taken(harness, path, held, stripped) {
|
|
|
42515
42592
|
return { harness, path, action: "absent" };
|
|
42516
42593
|
}
|
|
42517
42594
|
if (stripped.trim() === "" || stripped.trim() === "{}") {
|
|
42518
|
-
|
|
42595
|
+
rmSync2(path, { force: true });
|
|
42519
42596
|
return { harness, path, action: "deleted" };
|
|
42520
42597
|
}
|
|
42521
|
-
|
|
42598
|
+
writeFileSync2(path, stripped, "utf8");
|
|
42522
42599
|
return { harness, path, action: "removed" };
|
|
42523
42600
|
}
|
|
42524
42601
|
|
|
42525
42602
|
// src/headless.ts
|
|
42603
|
+
init_call_signal();
|
|
42526
42604
|
init_game_log();
|
|
42527
42605
|
init_scratch();
|
|
42528
|
-
import { execFile as
|
|
42529
|
-
import { mkdtempSync, writeFileSync as
|
|
42606
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
42607
|
+
import { mkdtempSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
42530
42608
|
import { tmpdir } from "node:os";
|
|
42531
|
-
import { join as
|
|
42532
|
-
import { promisify as
|
|
42533
|
-
var
|
|
42609
|
+
import { join as join5 } from "node:path";
|
|
42610
|
+
import { promisify as promisify3 } from "node:util";
|
|
42611
|
+
var run3 = promisify3(execFile3);
|
|
42534
42612
|
function snakeCased(params) {
|
|
42535
42613
|
const result = emptyRecord();
|
|
42536
42614
|
for (const [key, value] of Object.entries(params)) {
|
|
@@ -42569,13 +42647,13 @@ function reason(stdout, stderr) {
|
|
|
42569
42647
|
return stdout.trim().split(/\r?\n/).at(-1) ?? "no output at all";
|
|
42570
42648
|
}
|
|
42571
42649
|
async function runOperation(engine, operation, params, projectPath) {
|
|
42572
|
-
const paramsDir = mkdtempSync(
|
|
42573
|
-
const paramsFile =
|
|
42574
|
-
|
|
42650
|
+
const paramsDir = mkdtempSync(join5(tmpdir(), "gdharness-params-"));
|
|
42651
|
+
const paramsFile = join5(paramsDir, `${operation}.json`);
|
|
42652
|
+
writeFileSync3(paramsFile, JSON.stringify(snakeCased(params)), "utf8");
|
|
42575
42653
|
const args = [
|
|
42576
42654
|
"--headless",
|
|
42577
42655
|
"--log-file",
|
|
42578
|
-
|
|
42656
|
+
join5(paramsDir, "engine.log"),
|
|
42579
42657
|
"--path",
|
|
42580
42658
|
projectPath,
|
|
42581
42659
|
"--script",
|
|
@@ -42587,7 +42665,7 @@ async function runOperation(engine, operation, params, projectPath) {
|
|
|
42587
42665
|
let stdout;
|
|
42588
42666
|
let stderr;
|
|
42589
42667
|
try {
|
|
42590
|
-
({ stdout, stderr } = await
|
|
42668
|
+
({ stdout, stderr } = await run3(engine.godotPath, args, { signal: callSignal() }));
|
|
42591
42669
|
} catch (error) {
|
|
42592
42670
|
if (error instanceof Error && "stdout" in error && "stderr" in error) {
|
|
42593
42671
|
const failed = error;
|
|
@@ -42745,12 +42823,12 @@ class Ask {
|
|
|
42745
42823
|
|
|
42746
42824
|
// src/server-version.ts
|
|
42747
42825
|
init_update_check();
|
|
42748
|
-
import { readFileSync as
|
|
42826
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
42749
42827
|
var DEBUG_MODE2 = process.env["DEBUG"] === "true";
|
|
42750
42828
|
var GODOT_DEBUG_MODE_DEFAULT2 = process.env["GODOT_DEBUG"] === "true" || DEBUG_MODE2;
|
|
42751
42829
|
var SERVER_VERSION2 = (() => {
|
|
42752
42830
|
try {
|
|
42753
|
-
const pkg = JSON.parse(
|
|
42831
|
+
const pkg = JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf8"));
|
|
42754
42832
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
42755
42833
|
} catch {
|
|
42756
42834
|
return "0.0.0";
|
|
@@ -42762,19 +42840,19 @@ init_class_cache();
|
|
|
42762
42840
|
init_headless();
|
|
42763
42841
|
init_resources();
|
|
42764
42842
|
init_server_version();
|
|
42765
|
-
import { spawnSync } from "node:child_process";
|
|
42843
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
42766
42844
|
import { createHash as createHash2 } from "node:crypto";
|
|
42767
42845
|
import {
|
|
42768
42846
|
cpSync,
|
|
42769
42847
|
existsSync as existsSync7,
|
|
42770
|
-
mkdirSync as
|
|
42848
|
+
mkdirSync as mkdirSync4,
|
|
42771
42849
|
readdirSync as readdirSync3,
|
|
42772
|
-
readFileSync as
|
|
42773
|
-
rmSync as
|
|
42850
|
+
readFileSync as readFileSync8,
|
|
42851
|
+
rmSync as rmSync4,
|
|
42774
42852
|
statSync as statSync3,
|
|
42775
|
-
writeFileSync as
|
|
42853
|
+
writeFileSync as writeFileSync6
|
|
42776
42854
|
} from "node:fs";
|
|
42777
|
-
import { dirname as
|
|
42855
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
42778
42856
|
import { fileURLToPath } from "node:url";
|
|
42779
42857
|
var ADDONS = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
|
|
42780
42858
|
var EDITOR_PLUGINS = ["gdharness_editor", "auto_reload"];
|
|
@@ -42791,64 +42869,64 @@ function editorAddonDigest(from = shippedAddonsDirectory()) {
|
|
|
42791
42869
|
if (name === VERSION_MARKER || name === DIGEST_MARKER) {
|
|
42792
42870
|
continue;
|
|
42793
42871
|
}
|
|
42794
|
-
const path =
|
|
42872
|
+
const path = join9(directory, name);
|
|
42795
42873
|
const inside = `${relative}/${name}`;
|
|
42796
42874
|
if (statSync3(path).isDirectory()) {
|
|
42797
42875
|
walk(path, inside);
|
|
42798
42876
|
} else {
|
|
42799
42877
|
hash.update(`${inside}
|
|
42800
42878
|
`);
|
|
42801
|
-
hash.update(
|
|
42879
|
+
hash.update(readFileSync8(path));
|
|
42802
42880
|
hash.update(`
|
|
42803
42881
|
`);
|
|
42804
42882
|
}
|
|
42805
42883
|
}
|
|
42806
42884
|
};
|
|
42807
42885
|
for (const name of EDITOR_PLUGINS) {
|
|
42808
|
-
walk(
|
|
42886
|
+
walk(join9(from, name), name);
|
|
42809
42887
|
}
|
|
42810
42888
|
return hash.digest("hex");
|
|
42811
42889
|
}
|
|
42812
42890
|
function installedEditorDigest(projectPath) {
|
|
42813
|
-
const marker =
|
|
42891
|
+
const marker = join9(projectPath, "addons", ADDONS[0], DIGEST_MARKER);
|
|
42814
42892
|
if (!existsSync7(marker)) {
|
|
42815
42893
|
return null;
|
|
42816
42894
|
}
|
|
42817
|
-
const said =
|
|
42895
|
+
const said = readFileSync8(marker, "utf8").trim();
|
|
42818
42896
|
return said === "" ? null : said;
|
|
42819
42897
|
}
|
|
42820
42898
|
function shippedAddonsDirectory() {
|
|
42821
|
-
return
|
|
42899
|
+
return join9(dirname4(fileURLToPath(import.meta.url)), "godot", "addons");
|
|
42822
42900
|
}
|
|
42823
42901
|
function shippedOperationsScript() {
|
|
42824
|
-
return
|
|
42902
|
+
return join9(dirname4(fileURLToPath(import.meta.url)), "godot", "operations", "godot_operations.gd");
|
|
42825
42903
|
}
|
|
42826
42904
|
function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
42827
42905
|
const installed = [];
|
|
42828
42906
|
for (const name of ADDONS) {
|
|
42829
|
-
const source =
|
|
42830
|
-
if (!existsSync7(
|
|
42907
|
+
const source = join9(from, name);
|
|
42908
|
+
if (!existsSync7(join9(source, name === "gdharness_runtime" ? "runtime_autoload.gd" : "plugin.cfg"))) {
|
|
42831
42909
|
throw new Error(`The package holds no ${name} addon at ${source}.`);
|
|
42832
42910
|
}
|
|
42833
|
-
const target =
|
|
42911
|
+
const target = join9(projectPath, "addons", name);
|
|
42834
42912
|
const replaced = existsSync7(target);
|
|
42835
|
-
|
|
42836
|
-
|
|
42913
|
+
rmSync4(target, { recursive: true, force: true });
|
|
42914
|
+
mkdirSync4(dirname4(target), { recursive: true });
|
|
42837
42915
|
cpSync(source, target, { recursive: true });
|
|
42838
|
-
|
|
42916
|
+
writeFileSync6(join9(target, VERSION_MARKER), `${SERVER_VERSION}
|
|
42839
42917
|
`);
|
|
42840
42918
|
installed.push({ name, path: target, replaced });
|
|
42841
42919
|
}
|
|
42842
|
-
|
|
42920
|
+
writeFileSync6(join9(projectPath, "addons", ADDONS[0], DIGEST_MARKER), `${editorAddonDigest(from)}
|
|
42843
42921
|
`);
|
|
42844
42922
|
return installed;
|
|
42845
42923
|
}
|
|
42846
42924
|
function removeAddons(projectPath) {
|
|
42847
42925
|
const removed = [];
|
|
42848
42926
|
for (const name of ADDONS) {
|
|
42849
|
-
const target =
|
|
42927
|
+
const target = join9(projectPath, "addons", name);
|
|
42850
42928
|
if (existsSync7(target)) {
|
|
42851
|
-
|
|
42929
|
+
rmSync4(target, { recursive: true, force: true });
|
|
42852
42930
|
removed.push(target);
|
|
42853
42931
|
}
|
|
42854
42932
|
}
|
|
@@ -42882,7 +42960,7 @@ function loaderAmong(projectPath, named) {
|
|
|
42882
42960
|
}
|
|
42883
42961
|
let source = null;
|
|
42884
42962
|
try {
|
|
42885
|
-
source =
|
|
42963
|
+
source = readFileSync8(join9(projectPath, path), "utf8");
|
|
42886
42964
|
} catch {}
|
|
42887
42965
|
if (source?.includes(RUNTIME_AUTOLOAD.path)) {
|
|
42888
42966
|
return { name: entry, path, exists: true };
|
|
@@ -42905,7 +42983,7 @@ function trackedByGit(projectPath, wanted) {
|
|
|
42905
42983
|
if (wanted.length === 0) {
|
|
42906
42984
|
return new Set;
|
|
42907
42985
|
}
|
|
42908
|
-
const asked =
|
|
42986
|
+
const asked = spawnSync2("git", ["ls-files", "-z", "--", ...wanted], {
|
|
42909
42987
|
cwd: projectPath,
|
|
42910
42988
|
encoding: "utf8"
|
|
42911
42989
|
});
|
|
@@ -42924,10 +43002,10 @@ function enabledPlugins(settings) {
|
|
|
42924
43002
|
function inspectProject(projectPath) {
|
|
42925
43003
|
const problems = [];
|
|
42926
43004
|
const addons = ADDONS.map((name) => {
|
|
42927
|
-
const directory =
|
|
42928
|
-
const marker =
|
|
43005
|
+
const directory = join9(projectPath, "addons", name);
|
|
43006
|
+
const marker = join9(directory, VERSION_MARKER);
|
|
42929
43007
|
const installed = existsSync7(directory);
|
|
42930
|
-
const version = existsSync7(marker) ?
|
|
43008
|
+
const version = existsSync7(marker) ? readFileSync8(marker, "utf8").trim() : null;
|
|
42931
43009
|
const current = version === SERVER_VERSION;
|
|
42932
43010
|
if (!installed) {
|
|
42933
43011
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -42936,7 +43014,7 @@ function inspectProject(projectPath) {
|
|
|
42936
43014
|
}
|
|
42937
43015
|
return { name, installed, version, current };
|
|
42938
43016
|
});
|
|
42939
|
-
const settings = parseProjectGodot(
|
|
43017
|
+
const settings = parseProjectGodot(readFileSync8(join9(projectPath, "project.godot"), "utf8"));
|
|
42940
43018
|
const pluginsEnabled = enabledPlugins(settings);
|
|
42941
43019
|
for (const name of EDITOR_PLUGINS) {
|
|
42942
43020
|
if (!pluginsEnabled.includes(name)) {
|
|
@@ -42952,7 +43030,7 @@ function inspectProject(projectPath) {
|
|
|
42952
43030
|
const tracked = trackedByGit(projectPath, [...named.values()]);
|
|
42953
43031
|
const addonMissing = (path) => addons.some((addon) => !addon.installed && path.startsWith(`addons/${addon.name}/`));
|
|
42954
43032
|
for (const [name, path] of named) {
|
|
42955
|
-
if (!existsSync7(
|
|
43033
|
+
if (!existsSync7(join9(projectPath, path))) {
|
|
42956
43034
|
if (!addonMissing(path)) {
|
|
42957
43035
|
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`);
|
|
42958
43036
|
}
|
|
@@ -42985,8 +43063,8 @@ function inspectProject(projectPath) {
|
|
|
42985
43063
|
// src/skill.ts
|
|
42986
43064
|
init_setup();
|
|
42987
43065
|
init_tool_definitions();
|
|
42988
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
42989
|
-
import { basename, dirname as
|
|
43066
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, readdirSync as readdirSync5, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "node:fs";
|
|
43067
|
+
import { basename as basename2, dirname as dirname6, join as join11 } from "node:path";
|
|
42990
43068
|
|
|
42991
43069
|
// src/tool-reference.ts
|
|
42992
43070
|
init_headless_operations();
|
|
@@ -43082,7 +43160,7 @@ function renderToolsMarkdown() {
|
|
|
43082
43160
|
|
|
43083
43161
|
// src/skill.ts
|
|
43084
43162
|
var SKILL_NAME = "gdharness";
|
|
43085
|
-
var SHARED_SKILLS =
|
|
43163
|
+
var SHARED_SKILLS = join11(".agents", "skills");
|
|
43086
43164
|
function skillMarkdown(version) {
|
|
43087
43165
|
return `---
|
|
43088
43166
|
name: ${SKILL_NAME}
|
|
@@ -43255,27 +43333,27 @@ whatever the engine said on stderr comes back under \`engine_messages\`.
|
|
|
43255
43333
|
function skillFiles(version) {
|
|
43256
43334
|
return new Map([
|
|
43257
43335
|
["SKILL.md", skillMarkdown(version)],
|
|
43258
|
-
[
|
|
43336
|
+
[join11("references", "tools.md"), renderToolsMarkdown()]
|
|
43259
43337
|
]);
|
|
43260
43338
|
}
|
|
43261
43339
|
function skillDirectories(harnesses, projectPath, exists) {
|
|
43262
|
-
const directories = [
|
|
43340
|
+
const directories = [join11(projectPath, SHARED_SKILLS, SKILL_NAME)];
|
|
43263
43341
|
for (const harness of harnesses) {
|
|
43264
43342
|
if (harness.skills === undefined) {
|
|
43265
43343
|
continue;
|
|
43266
43344
|
}
|
|
43267
|
-
const own =
|
|
43268
|
-
if ((!harness.skills.shared || exists(own)) && !directories.includes(
|
|
43269
|
-
directories.push(
|
|
43345
|
+
const own = join11(projectPath, harness.skills.dir);
|
|
43346
|
+
if ((!harness.skills.shared || exists(own)) && !directories.includes(join11(own, SKILL_NAME))) {
|
|
43347
|
+
directories.push(join11(own, SKILL_NAME));
|
|
43270
43348
|
}
|
|
43271
43349
|
}
|
|
43272
43350
|
return directories;
|
|
43273
43351
|
}
|
|
43274
43352
|
function everySkillDirectory(projectPath, harnesses) {
|
|
43275
|
-
const directories = new Set([
|
|
43353
|
+
const directories = new Set([join11(projectPath, SHARED_SKILLS, SKILL_NAME)]);
|
|
43276
43354
|
for (const harness of harnesses) {
|
|
43277
43355
|
if (harness.skills !== undefined) {
|
|
43278
|
-
directories.add(
|
|
43356
|
+
directories.add(join11(projectPath, harness.skills.dir, SKILL_NAME));
|
|
43279
43357
|
}
|
|
43280
43358
|
}
|
|
43281
43359
|
return [...directories];
|
|
@@ -43284,51 +43362,51 @@ function removeSkill(directories, projectPath) {
|
|
|
43284
43362
|
const removed = [];
|
|
43285
43363
|
for (const directory of directories) {
|
|
43286
43364
|
if (existsSync9(directory)) {
|
|
43287
|
-
|
|
43288
|
-
pruneEmpty(
|
|
43365
|
+
rmSync6(directory, { recursive: true, force: true });
|
|
43366
|
+
pruneEmpty(dirname6(directory), projectPath);
|
|
43289
43367
|
removed.push(directory);
|
|
43290
43368
|
}
|
|
43291
43369
|
}
|
|
43292
43370
|
return removed;
|
|
43293
43371
|
}
|
|
43294
43372
|
function pruneEmpty(directory, projectPath) {
|
|
43295
|
-
const shared =
|
|
43373
|
+
const shared = join11(projectPath, ".agents");
|
|
43296
43374
|
let path = directory;
|
|
43297
|
-
while (path !== projectPath && (
|
|
43375
|
+
while (path !== projectPath && (basename2(path) === "skills" || path === shared)) {
|
|
43298
43376
|
if (readdirSync5(path).length > 0) {
|
|
43299
43377
|
return;
|
|
43300
43378
|
}
|
|
43301
|
-
|
|
43302
|
-
path =
|
|
43379
|
+
rmSync6(path, { recursive: true, force: true });
|
|
43380
|
+
path = dirname6(path);
|
|
43303
43381
|
}
|
|
43304
43382
|
}
|
|
43305
43383
|
function writeSkill(directories, version) {
|
|
43306
43384
|
const files = skillFiles(version);
|
|
43307
43385
|
return directories.map((directory) => {
|
|
43308
43386
|
const replaced = existsSync9(directory);
|
|
43309
|
-
|
|
43387
|
+
rmSync6(directory, { recursive: true, force: true });
|
|
43310
43388
|
for (const [name, contents] of files) {
|
|
43311
|
-
const path =
|
|
43312
|
-
|
|
43313
|
-
|
|
43389
|
+
const path = join11(directory, name);
|
|
43390
|
+
mkdirSync6(dirname6(path), { recursive: true });
|
|
43391
|
+
writeFileSync8(path, contents, "utf8");
|
|
43314
43392
|
}
|
|
43315
43393
|
return { path: directory, replaced };
|
|
43316
43394
|
});
|
|
43317
43395
|
}
|
|
43318
43396
|
|
|
43319
43397
|
// src/version.ts
|
|
43320
|
-
import { readFileSync as
|
|
43321
|
-
import { dirname as
|
|
43398
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
43399
|
+
import { dirname as dirname7, join as join12 } from "node:path";
|
|
43322
43400
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
43323
43401
|
function getLocalVersion() {
|
|
43324
|
-
const currentDirectory =
|
|
43402
|
+
const currentDirectory = dirname7(fileURLToPath3(import.meta.url));
|
|
43325
43403
|
const packageCandidates = [
|
|
43326
|
-
|
|
43327
|
-
|
|
43404
|
+
join12(currentDirectory, "..", "package.json"),
|
|
43405
|
+
join12(currentDirectory, "..", "..", "package.json")
|
|
43328
43406
|
];
|
|
43329
43407
|
for (const packagePath of packageCandidates) {
|
|
43330
43408
|
try {
|
|
43331
|
-
const value = JSON.parse(
|
|
43409
|
+
const value = JSON.parse(readFileSync10(packagePath, "utf-8"));
|
|
43332
43410
|
if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
|
|
43333
43411
|
return value.version;
|
|
43334
43412
|
}
|
|
@@ -43341,12 +43419,12 @@ function getLocalVersion() {
|
|
|
43341
43419
|
var args = process.argv.slice(2);
|
|
43342
43420
|
var command = args[0];
|
|
43343
43421
|
|
|
43344
|
-
class UsageError extends
|
|
43422
|
+
class UsageError extends Refusal2 {
|
|
43345
43423
|
}
|
|
43346
43424
|
function projectArgument(at) {
|
|
43347
43425
|
const named = args.slice(at).find((value) => !value.startsWith("--"));
|
|
43348
43426
|
const projectPath = resolve5(named ?? ".");
|
|
43349
|
-
if (!existsSync16(
|
|
43427
|
+
if (!existsSync16(join24(projectPath, "project.godot"))) {
|
|
43350
43428
|
throw new UsageError(`Not a Godot project: ${projectPath} holds no project.godot.`);
|
|
43351
43429
|
}
|
|
43352
43430
|
return projectPath;
|
|
@@ -43365,7 +43443,7 @@ async function engine(projectPath) {
|
|
|
43365
43443
|
}
|
|
43366
43444
|
function said2(outcome, what) {
|
|
43367
43445
|
if (!outcome.ok) {
|
|
43368
|
-
throw new
|
|
43446
|
+
throw new Refusal2(`${what}: ${outcome.message}`);
|
|
43369
43447
|
}
|
|
43370
43448
|
for (const entry of outcome.messages) {
|
|
43371
43449
|
console.error(` engine ${entry.severity}: ${entry.text}`);
|
|
@@ -43385,7 +43463,7 @@ async function registerRuntime(godot, projectPath) {
|
|
|
43385
43463
|
return;
|
|
43386
43464
|
}
|
|
43387
43465
|
console.log(`${RUNTIME_AUTOLOAD.name} autoload left at ${named}, which this project registers itself`);
|
|
43388
|
-
if (!existsSync16(
|
|
43466
|
+
if (!existsSync16(join24(projectPath, (named ?? "").replace(/^res:\/\//, "")))) {
|
|
43389
43467
|
console.log(` that file is not in this project, so it boots with a missing script: restore it, or point the entry at res://${RUNTIME_AUTOLOAD.path}`);
|
|
43390
43468
|
}
|
|
43391
43469
|
}
|
|
@@ -43620,7 +43698,8 @@ On ${version}. What is left for you:`);
|
|
|
43620
43698
|
` + ` so it gives an open editor nothing to restart for. editor_status says addonIsStale
|
|
43621
43699
|
` + " if the editor is older than that." : ` 1. The open editor is still running the addons it loaded at startup. Restart it with the
|
|
43622
43700
|
` + " editor_launch restart tool, which closes and reopens the window.");
|
|
43623
|
-
|
|
43701
|
+
const serving = serverServing(projectPath);
|
|
43702
|
+
console.log(harnessNote({ moved, written, byHand }, [launch.command, ...launch.args].join(" "), serving === null ? null : { server: serving, isThisVersion: serving.version === version }));
|
|
43624
43703
|
}
|
|
43625
43704
|
function doctorReport(projectPath) {
|
|
43626
43705
|
const report = inspectProject(projectPath);
|
|
@@ -43780,7 +43859,7 @@ async function main() {
|
|
|
43780
43859
|
}
|
|
43781
43860
|
}
|
|
43782
43861
|
await main().catch((error) => {
|
|
43783
|
-
if (error instanceof
|
|
43862
|
+
if (error instanceof Refusal2) {
|
|
43784
43863
|
console.error("gdharness:", error.message);
|
|
43785
43864
|
process.exit(error instanceof UsageError ? 2 : 1);
|
|
43786
43865
|
}
|