gdharness 1.3.4 → 1.3.5
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 +428 -383
- package/build/godot/addons/gdharness_editor/declared_values.gd +24 -0
- package/build/godot/addons/gdharness_editor/property_values.gd +5 -18
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +20 -12
- package/build/godot/addons/gdharness_runtime/declared_values.gd +293 -0
- package/build/godot/addons/gdharness_runtime/declared_values.gd.uid +1 -0
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +4 -0
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +29 -1
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +16 -13
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +18 -0
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +32 -5
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +48 -15
- package/build/godot/operations/classdb_queries.gd +112 -46
- package/build/godot/operations/declared_values.gd +24 -0
- package/build/godot/operations/gdscript_authoring.gd +15 -2
- package/build/godot/operations/property_values.gd +5 -18
- package/build/keeper.js +83 -69
- package/package.json +1 -1
package/build/keeper.js
CHANGED
|
@@ -3,9 +3,33 @@
|
|
|
3
3
|
// src/keeper.ts
|
|
4
4
|
import { closeSync as closeSync2, existsSync as existsSync3, mkdtempSync as mkdtempSync4, openSync as openSync3, readFileSync as readFileSync3, rmSync as rmSync6, writeFileSync as writeFileSync3 } from "node:fs";
|
|
5
5
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
6
|
-
import { join as
|
|
6
|
+
import { join as join7 } from "node:path";
|
|
7
7
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
8
8
|
|
|
9
|
+
// src/alive.ts
|
|
10
|
+
import process2 from "node:process";
|
|
11
|
+
function exitOf(child) {
|
|
12
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
13
|
+
return Promise.resolve({ code: child.exitCode, signal: child.signalCode });
|
|
14
|
+
}
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
child.once("exit", (code, signal) => {
|
|
17
|
+
resolve({ code, signal });
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function alive(pid) {
|
|
22
|
+
if (pid === undefined || pid === null) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
process2.kill(pid, 0);
|
|
27
|
+
return true;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return error.code === "EPERM";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
9
33
|
// src/desktop.ts
|
|
10
34
|
import { createHash } from "node:crypto";
|
|
11
35
|
import {
|
|
@@ -23,20 +47,6 @@ import { tmpdir } from "node:os";
|
|
|
23
47
|
import { join } from "node:path";
|
|
24
48
|
import { setTimeout as delay } from "node:timers/promises";
|
|
25
49
|
|
|
26
|
-
// src/alive.ts
|
|
27
|
-
import process2 from "node:process";
|
|
28
|
-
function alive(pid) {
|
|
29
|
-
if (pid === undefined || pid === null) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
process2.kill(pid, 0);
|
|
34
|
-
return true;
|
|
35
|
-
} catch (error) {
|
|
36
|
-
return error.code === "EPERM";
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
50
|
// src/spawn.ts
|
|
41
51
|
import {
|
|
42
52
|
execFile,
|
|
@@ -1031,7 +1041,7 @@ class GameDebugger {
|
|
|
1031
1041
|
}
|
|
1032
1042
|
if (!held.hasStack) {
|
|
1033
1043
|
this.forget("debug_enter");
|
|
1034
|
-
this.send("
|
|
1044
|
+
this.send("step", [], held.thread);
|
|
1035
1045
|
const again = await this.next(GameDebugger.named("debug_enter"), STEP_MS);
|
|
1036
1046
|
if (again === null) {
|
|
1037
1047
|
return {
|
|
@@ -1253,8 +1263,28 @@ function readLaunched(printed) {
|
|
|
1253
1263
|
|
|
1254
1264
|
// src/run-record.ts
|
|
1255
1265
|
import { createHash as createHash2 } from "node:crypto";
|
|
1256
|
-
import { mkdirSync, openSync as openSync2, readdirSync, readFileSync as readFileSync2,
|
|
1257
|
-
import { basename
|
|
1266
|
+
import { mkdirSync, openSync as openSync2, readdirSync, readFileSync as readFileSync2, rmSync as rmSync4, statSync as statSync3 } from "node:fs";
|
|
1267
|
+
import { basename as basename2, join as join5, resolve as resolve3 } from "node:path";
|
|
1268
|
+
|
|
1269
|
+
// src/paths.ts
|
|
1270
|
+
import { realpathSync, statSync as statSync2 } from "node:fs";
|
|
1271
|
+
import { basename, dirname, isAbsolute, join as join3, relative, resolve, sep } from "node:path";
|
|
1272
|
+
function realAsFarAsItExists(path) {
|
|
1273
|
+
const missing = [];
|
|
1274
|
+
let at = path;
|
|
1275
|
+
for (;; ) {
|
|
1276
|
+
try {
|
|
1277
|
+
return join3(realpathSync.native(at), ...missing);
|
|
1278
|
+
} catch {
|
|
1279
|
+
const parent = dirname(at);
|
|
1280
|
+
if (parent === at) {
|
|
1281
|
+
return path;
|
|
1282
|
+
}
|
|
1283
|
+
missing.unshift(basename(at));
|
|
1284
|
+
at = parent;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1258
1288
|
|
|
1259
1289
|
// src/windows-ask.ts
|
|
1260
1290
|
var SCRIPT = [
|
|
@@ -1278,7 +1308,7 @@ var SCRIPT = [
|
|
|
1278
1308
|
|
|
1279
1309
|
// src/runtime-client.ts
|
|
1280
1310
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
1281
|
-
import { dirname, join as
|
|
1311
|
+
import { dirname as dirname2, join as join4, resolve as resolve2 } from "node:path";
|
|
1282
1312
|
|
|
1283
1313
|
// src/launch.ts
|
|
1284
1314
|
function envValue(name, variables = process.env) {
|
|
@@ -1323,7 +1353,7 @@ function runtimeDirectory(variables = process.env) {
|
|
|
1323
1353
|
return explicit;
|
|
1324
1354
|
}
|
|
1325
1355
|
const perUser = envValue("XDG_RUNTIME_DIR", variables);
|
|
1326
|
-
return
|
|
1356
|
+
return join4(perUser ?? tmpdir3(), "gdharness");
|
|
1327
1357
|
}
|
|
1328
1358
|
var ERROR_REPORT_KEEP_MS = 60 * 60 * 1000;
|
|
1329
1359
|
var verdicts = new Map;
|
|
@@ -1363,31 +1393,15 @@ function writeWhole(path, text) {
|
|
|
1363
1393
|
|
|
1364
1394
|
// src/run-record.ts
|
|
1365
1395
|
function runsDirectory() {
|
|
1366
|
-
return
|
|
1367
|
-
}
|
|
1368
|
-
function realAsFarAsItExists(path) {
|
|
1369
|
-
const missing = [];
|
|
1370
|
-
let at = path;
|
|
1371
|
-
for (;; ) {
|
|
1372
|
-
try {
|
|
1373
|
-
return join4(realpathSync.native(at), ...missing);
|
|
1374
|
-
} catch {
|
|
1375
|
-
const parent = dirname2(at);
|
|
1376
|
-
if (parent === at) {
|
|
1377
|
-
return path;
|
|
1378
|
-
}
|
|
1379
|
-
missing.unshift(basename(at));
|
|
1380
|
-
at = parent;
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1396
|
+
return join5(runtimeDirectory(), "runs");
|
|
1383
1397
|
}
|
|
1384
1398
|
function projectKey(projectPath) {
|
|
1385
|
-
const real = realAsFarAsItExists(
|
|
1399
|
+
const real = realAsFarAsItExists(resolve3(projectPath)).replace(/[\\/]+$/, "");
|
|
1386
1400
|
const folded = process.platform === "win32" || process.platform === "darwin" ? real.toLowerCase() : real;
|
|
1387
1401
|
return createHash2("sha256").update(folded.replaceAll("\\", "/")).digest("hex").slice(0, 16);
|
|
1388
1402
|
}
|
|
1389
1403
|
function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
1390
|
-
return
|
|
1404
|
+
return join5(directory, "runs", `note-${projectKey(projectPath)}.json`);
|
|
1391
1405
|
}
|
|
1392
1406
|
function writeRunRecord(record) {
|
|
1393
1407
|
mkdirSync(runsDirectory(), { recursive: true });
|
|
@@ -1454,14 +1468,14 @@ function recordAt(path) {
|
|
|
1454
1468
|
// src/scratch.ts
|
|
1455
1469
|
import { existsSync as existsSync2, mkdtempSync as mkdtempSync3, readdirSync as readdirSync2, rmSync as rmSync5 } from "node:fs";
|
|
1456
1470
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
1457
|
-
import { join as
|
|
1471
|
+
import { join as join6 } from "node:path";
|
|
1458
1472
|
import process4 from "node:process";
|
|
1459
1473
|
var SWEPT = { recursive: true, force: true };
|
|
1460
1474
|
var AGAIN_AFTER_MS = [250, 500, 1000, 2000, 4000, 8000, 16000];
|
|
1461
1475
|
var waiting = new Set;
|
|
1462
1476
|
var atExit = new Set;
|
|
1463
1477
|
function scratchDirectory(kind) {
|
|
1464
|
-
return mkdtempSync3(
|
|
1478
|
+
return mkdtempSync3(join6(tmpdir4(), `gdharness-${kind}-${process4.pid}-`));
|
|
1465
1479
|
}
|
|
1466
1480
|
function discardWith(remove, paths) {
|
|
1467
1481
|
const left = [];
|
|
@@ -1921,8 +1935,8 @@ async function startDirectly(spec, output, hidden, detached = true, errors = out
|
|
|
1921
1935
|
}
|
|
1922
1936
|
async function startThroughHelper(spec, output, stopFile) {
|
|
1923
1937
|
const scratch = scratchDirectory("desktop");
|
|
1924
|
-
const pidFile =
|
|
1925
|
-
const errorFile =
|
|
1938
|
+
const pidFile = join7(scratch, "pid");
|
|
1939
|
+
const errorFile = join7(scratch, "error");
|
|
1926
1940
|
const where = spec.desktop === undefined ? "without activation" : `on the ${spec.desktop} desktop`;
|
|
1927
1941
|
try {
|
|
1928
1942
|
const compiled = await ensureHelperCompiled();
|
|
@@ -1930,7 +1944,7 @@ async function startThroughHelper(spec, output, stopFile) {
|
|
|
1930
1944
|
return { error: `it could not be started ${where}: ${compiled}` };
|
|
1931
1945
|
}
|
|
1932
1946
|
const wrapper = throughHelper({ ...spec, directory: process.cwd() }, spec.command, spec.args, {
|
|
1933
|
-
spec:
|
|
1947
|
+
spec: join7(scratch, "spec.json"),
|
|
1934
1948
|
pid: pidFile,
|
|
1935
1949
|
error: errorFile,
|
|
1936
1950
|
stop: stopFile
|
|
@@ -1974,7 +1988,7 @@ function profiledBy(path, projectPath) {
|
|
|
1974
1988
|
};
|
|
1975
1989
|
let projectGodot = null;
|
|
1976
1990
|
try {
|
|
1977
|
-
projectGodot = readFileSync3(
|
|
1991
|
+
projectGodot = readFileSync3(join7(projectPath, "project.godot"), "utf8");
|
|
1978
1992
|
} catch {}
|
|
1979
1993
|
const observer = new ProfileObserver((totals) => {
|
|
1980
1994
|
const first = latest === null;
|
|
@@ -2077,8 +2091,8 @@ async function keep() {
|
|
|
2077
2091
|
const debuggerPeer = run === undefined || run.debugged === false ? null : await GameDebugger.open(run.breakpoints ?? [], profiled === null ? [] : [profiled.observer]);
|
|
2078
2092
|
const toStart = debuggerPeer === null ? spec : { ...spec, args: withEngineArguments(spec.args, debuggerPeer.engineArguments) };
|
|
2079
2093
|
const transcript = run === undefined ? "ignore" : openSync3(run.transcript, "a");
|
|
2080
|
-
const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(
|
|
2081
|
-
const stopFile = own === null ? "" :
|
|
2094
|
+
const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(join7(tmpdir5(), "gdharness-stop-")) : null;
|
|
2095
|
+
const stopFile = own === null ? "" : join7(own, "stop");
|
|
2082
2096
|
let started;
|
|
2083
2097
|
try {
|
|
2084
2098
|
started = await startDetached(toStart, transcript, run === undefined, stopFile);
|
|
@@ -2108,26 +2122,8 @@ async function keep() {
|
|
|
2108
2122
|
if (record !== null) {
|
|
2109
2123
|
writeNoteIfItCan(record);
|
|
2110
2124
|
}
|
|
2125
|
+
const exited = exitOf(child);
|
|
2111
2126
|
let listening = null;
|
|
2112
|
-
child.once("exit", (code, signal) => {
|
|
2113
|
-
const finish = () => {
|
|
2114
|
-
profiled?.finish();
|
|
2115
|
-
if (run !== undefined) {
|
|
2116
|
-
recordRunEnded(run.projectPath, pid, { exitCode: code, exitSignal: code === null ? signal : null });
|
|
2117
|
-
}
|
|
2118
|
-
debuggerPeer?.close();
|
|
2119
|
-
listening?.close();
|
|
2120
|
-
if (own !== null) {
|
|
2121
|
-
rmSync6(own, { recursive: true, force: true });
|
|
2122
|
-
}
|
|
2123
|
-
process.exit(0);
|
|
2124
|
-
};
|
|
2125
|
-
if (debuggerPeer === null) {
|
|
2126
|
-
finish();
|
|
2127
|
-
} else {
|
|
2128
|
-
debuggerPeer.drained(DRAIN_MS).then(finish);
|
|
2129
|
-
}
|
|
2130
|
-
});
|
|
2131
2127
|
if (record !== null) {
|
|
2132
2128
|
listening = await listenForTheServer(() => {
|
|
2133
2129
|
if (stopFile !== "") {
|
|
@@ -2140,9 +2136,27 @@ async function keep() {
|
|
|
2140
2136
|
writeNoteIfItCan({ ...record, keeper: listening.address });
|
|
2141
2137
|
}
|
|
2142
2138
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2139
|
+
await new Promise((resolve) => {
|
|
2140
|
+
process.stdout.once("error", () => {
|
|
2141
|
+
resolve();
|
|
2142
|
+
});
|
|
2143
|
+
process.stdout.end(`pid ${pid}
|
|
2144
|
+
`, resolve);
|
|
2145
|
+
});
|
|
2146
|
+
const { code, signal } = await exited;
|
|
2147
|
+
if (debuggerPeer !== null) {
|
|
2148
|
+
await debuggerPeer.drained(DRAIN_MS);
|
|
2149
|
+
}
|
|
2150
|
+
profiled?.finish();
|
|
2151
|
+
if (run !== undefined) {
|
|
2152
|
+
recordRunEnded(run.projectPath, pid, { exitCode: code, exitSignal: code === null ? signal : null });
|
|
2153
|
+
}
|
|
2154
|
+
debuggerPeer?.close();
|
|
2155
|
+
listening?.close();
|
|
2156
|
+
if (own !== null) {
|
|
2157
|
+
rmSync6(own, { recursive: true, force: true });
|
|
2158
|
+
}
|
|
2159
|
+
process.exit(0);
|
|
2146
2160
|
}
|
|
2147
2161
|
var mode = process.argv[2];
|
|
2148
2162
|
if (mode === "launch") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|