gdharness 1.3.67 → 1.3.68
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 +33537 -32369
- package/build/godot/addons/gdharness_editor/bridge_client.gd +5 -3
- package/build/godot/addons/gdharness_editor/headless_check.gd +52 -0
- package/build/godot/addons/gdharness_editor/plugin.gd +80 -2
- package/build/godot/addons/gdharness_editor/scene_file.gd +128 -12
- package/build/godot/addons/gdharness_editor/tool_executor.gd +1 -0
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +3 -1
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +9 -13
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +87 -13
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +20 -4
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +43 -11
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +469 -7
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +2 -0
- package/build/godot/operations/editor_tools.gd +1 -0
- package/build/keeper.js +116 -114
- package/package.json +1 -1
package/build/keeper.js
CHANGED
|
@@ -7265,14 +7265,16 @@ class CompiledHelper {
|
|
|
7265
7265
|
file;
|
|
7266
7266
|
source;
|
|
7267
7267
|
digest;
|
|
7268
|
-
|
|
7268
|
+
program;
|
|
7269
|
+
constructor(named, file, source, program = false) {
|
|
7269
7270
|
this.named = named;
|
|
7270
7271
|
this.file = file;
|
|
7271
7272
|
this.source = source;
|
|
7273
|
+
this.program = program;
|
|
7272
7274
|
this.digest = createHash("sha256").update(source).digest("hex").slice(0, 16);
|
|
7273
7275
|
}
|
|
7274
7276
|
assembly(directory = tmpdir()) {
|
|
7275
|
-
return join2(directory, `${this.file}-${this.digest}.dll`);
|
|
7277
|
+
return join2(directory, `${this.file}-${this.digest}.${this.program ? "exe" : "dll"}`);
|
|
7276
7278
|
}
|
|
7277
7279
|
async ensure(directory = tmpdir(), budgetMs = HELPER_COMPILE_MS, wait = true) {
|
|
7278
7280
|
const assembly = this.assembly(directory);
|
|
@@ -7319,8 +7321,8 @@ class CompiledHelper {
|
|
|
7319
7321
|
const script = [
|
|
7320
7322
|
"$ErrorActionPreference = 'Stop'",
|
|
7321
7323
|
"try {",
|
|
7322
|
-
` $partial = ${literal(assembly)} + '.' + $PID`,
|
|
7323
|
-
` Add-Type -TypeDefinition ([IO.File]::ReadAllText(${literal(source)}, [Text.Encoding]::UTF8)) -OutputAssembly $partial`,
|
|
7324
|
+
` $partial = ${literal(assembly.slice(0, -4))} + '.' + $PID + ${literal(assembly.slice(-4))}`,
|
|
7325
|
+
` Add-Type -TypeDefinition ([IO.File]::ReadAllText(${literal(source)}, [Text.Encoding]::UTF8)) -OutputAssembly $partial${this.program ? " -OutputType ConsoleApplication" : ""}`,
|
|
7324
7326
|
` Move-Item -LiteralPath $partial -Destination ${literal(assembly)}`,
|
|
7325
7327
|
"} catch {",
|
|
7326
7328
|
" [Console]::Error.WriteLine($_.Exception.Message)",
|
|
@@ -7466,6 +7468,18 @@ public static class GdharnessDesktop {
|
|
|
7466
7468
|
}
|
|
7467
7469
|
}
|
|
7468
7470
|
|
|
7471
|
+
// The spec, the error file and the step file, by path. What stops it before the pid is written
|
|
7472
|
+
// goes to the error file, since its own streams are the ones the process inherits.
|
|
7473
|
+
public static int Main(string[] args) {
|
|
7474
|
+
try {
|
|
7475
|
+
Step(args[2], "reading its spec");
|
|
7476
|
+
return RunSpec(args[0]);
|
|
7477
|
+
} catch (Exception e) {
|
|
7478
|
+
File.WriteAllText(args[1], e.Message);
|
|
7479
|
+
return 1;
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
|
|
7469
7483
|
// Starts the command line, both of its streams on this process's output, writes its pid, and
|
|
7470
7484
|
// waits for it: the answer is its exit code. On the named desktop when there is one, whose handle
|
|
7471
7485
|
// is held until then, since a desktop goes when the last handle to it does, and on this process's
|
|
@@ -7474,10 +7488,8 @@ public static class GdharnessDesktop {
|
|
|
7474
7488
|
// and the foreground is held while it starts, since Godot also asks for it outright. The process
|
|
7475
7489
|
// is ended through the handle held here once stopFile appears, which is how a keeper ends a game
|
|
7476
7490
|
// it did not start itself: a handle names one process, where a pid can name the next one too. The
|
|
7477
|
-
// process starts in directory rather than in this one's, which is a temporary directory
|
|
7478
|
-
//
|
|
7479
|
-
// The spec is one field a line, each base64 of its UTF-8, read with no PowerShell cmdlet: a cmdlet
|
|
7480
|
-
// has PowerShell prepare its modules first, on every start.
|
|
7491
|
+
// process starts in directory rather than in this one's, which is a temporary directory. The spec
|
|
7492
|
+
// is one field a line, each base64 of its UTF-8.
|
|
7481
7493
|
public static int RunSpec(string specFile) {
|
|
7482
7494
|
string[] lines = File.ReadAllLines(specFile);
|
|
7483
7495
|
Func<int, string> field = delegate(int index) { return Encoding.UTF8.GetString(Convert.FromBase64String(lines[index])); };
|
|
@@ -7537,8 +7549,8 @@ public static class GdharnessDesktop {
|
|
|
7537
7549
|
Started started;
|
|
7538
7550
|
// Inherited by what it starts: without SEM_NOGPFAULTERRORBOX, Windows Error Reporting runs when
|
|
7539
7551
|
// the target crashes and writes its dump, and with the other two no hard-error box can open.
|
|
7540
|
-
// Set outright rather than cleared from this process's own
|
|
7541
|
-
//
|
|
7552
|
+
// Set outright rather than cleared from this process's own, which is whatever started it chose:
|
|
7553
|
+
// a Windows PowerShell host was seen reading 0x1 here, without the open-file bit.
|
|
7542
7554
|
SetErrorMode(FailCriticalErrors | NoOpenFileErrorBox);
|
|
7543
7555
|
if (noActivate) {
|
|
7544
7556
|
LockSetForegroundWindow(LockForeground);
|
|
@@ -7586,7 +7598,7 @@ public static class GdharnessDesktop {
|
|
|
7586
7598
|
}
|
|
7587
7599
|
}
|
|
7588
7600
|
`;
|
|
7589
|
-
var HELPER = new CompiledHelper("desktop helper", "gdharness-desktop", SOURCE);
|
|
7601
|
+
var HELPER = new CompiledHelper("desktop helper", "gdharness-desktop", SOURCE, true);
|
|
7590
7602
|
function helperAssembly(directory = tmpdir2()) {
|
|
7591
7603
|
return HELPER.assembly(directory);
|
|
7592
7604
|
}
|
|
@@ -7625,7 +7637,7 @@ function helperStep(stepFile) {
|
|
|
7625
7637
|
try {
|
|
7626
7638
|
step = readFileSync3(stepFile, "utf8").trim();
|
|
7627
7639
|
} catch {}
|
|
7628
|
-
return step === null || step === "" ? "
|
|
7640
|
+
return step === null || step === "" ? "the helper had not begun" : `the helper was ${step}`;
|
|
7629
7641
|
}
|
|
7630
7642
|
function throughHelper(how, command, args, files, assembly = helperAssembly()) {
|
|
7631
7643
|
mendBeforeStart(args, how.directory);
|
|
@@ -7641,31 +7653,7 @@ function throughHelper(how, command, args, files, assembly = helperAssembly()) {
|
|
|
7641
7653
|
];
|
|
7642
7654
|
writeFileSync3(files.spec, fields.map((field) => Buffer.from(field, "utf8").toString("base64")).join(`
|
|
7643
7655
|
`), "utf8");
|
|
7644
|
-
|
|
7645
|
-
const script = [
|
|
7646
|
-
"$ErrorActionPreference = 'Stop'",
|
|
7647
|
-
"try {",
|
|
7648
|
-
` [IO.File]::WriteAllText(${literal(files.step)}, 'loading its assembly')`,
|
|
7649
|
-
` $null = [Reflection.Assembly]::LoadFrom(${literal(assembly)})`,
|
|
7650
|
-
` $code = [GdharnessDesktop]::RunSpec(${literal(files.spec)})`,
|
|
7651
|
-
"} catch {",
|
|
7652
|
-
` [IO.File]::WriteAllText(${literal(files.error)}, $_.Exception.Message)`,
|
|
7653
|
-
" exit 1",
|
|
7654
|
-
"}",
|
|
7655
|
-
"exit $code"
|
|
7656
|
-
].join(`
|
|
7657
|
-
`);
|
|
7658
|
-
return {
|
|
7659
|
-
command: "powershell.exe",
|
|
7660
|
-
args: [
|
|
7661
|
-
"-NoProfile",
|
|
7662
|
-
"-NonInteractive",
|
|
7663
|
-
"-ExecutionPolicy",
|
|
7664
|
-
"Bypass",
|
|
7665
|
-
"-EncodedCommand",
|
|
7666
|
-
Buffer.from(script, "utf16le").toString("base64")
|
|
7667
|
-
]
|
|
7668
|
-
};
|
|
7656
|
+
return { command: assembly, args: [files.spec, files.error, files.step] };
|
|
7669
7657
|
}
|
|
7670
7658
|
|
|
7671
7659
|
// src/engine-slots.ts
|
|
@@ -9505,6 +9493,97 @@ var WINDOWS_STATUSES = new Map([
|
|
|
9505
9493
|
[3221226505, "a stack buffer overrun or a fast fail, so it crashed"]
|
|
9506
9494
|
]);
|
|
9507
9495
|
|
|
9496
|
+
// src/scratch.ts
|
|
9497
|
+
import { existsSync as existsSync4, mkdtempSync as mkdtempSync2, readdirSync as readdirSync3, rmSync as rmSync5 } from "node:fs";
|
|
9498
|
+
import { tmpdir as tmpdir5 } from "node:os";
|
|
9499
|
+
import { join as join5 } from "node:path";
|
|
9500
|
+
import process6 from "node:process";
|
|
9501
|
+
var SWEPT = { recursive: true, force: true };
|
|
9502
|
+
var AGAIN_AFTER_MS = [250, 500, 1000, 2000, 4000, 8000, 16000];
|
|
9503
|
+
var waiting = new Set;
|
|
9504
|
+
var atExit = new Set;
|
|
9505
|
+
function scratchDirectory(kind) {
|
|
9506
|
+
return mkdtempSync2(join5(tmpdir5(), `gdharness-${kind}-${process6.pid}-`));
|
|
9507
|
+
}
|
|
9508
|
+
function discardWith(removePath, paths) {
|
|
9509
|
+
const left = [];
|
|
9510
|
+
for (const path of paths) {
|
|
9511
|
+
if (!path) {
|
|
9512
|
+
continue;
|
|
9513
|
+
}
|
|
9514
|
+
try {
|
|
9515
|
+
removePath(path);
|
|
9516
|
+
} catch (error) {
|
|
9517
|
+
left.push({ path, reason: error instanceof Error ? error.message : String(error) });
|
|
9518
|
+
}
|
|
9519
|
+
}
|
|
9520
|
+
return left;
|
|
9521
|
+
}
|
|
9522
|
+
function discard(...paths) {
|
|
9523
|
+
const left = discardWith(remove, paths);
|
|
9524
|
+
for (const { path } of left) {
|
|
9525
|
+
tryAgain(path, 0);
|
|
9526
|
+
}
|
|
9527
|
+
return left;
|
|
9528
|
+
}
|
|
9529
|
+
function remove(path) {
|
|
9530
|
+
rmSync5(path, SWEPT);
|
|
9531
|
+
}
|
|
9532
|
+
function tryAgain(path, attempt) {
|
|
9533
|
+
if (attempt === 0) {
|
|
9534
|
+
if (waiting.has(path)) {
|
|
9535
|
+
return;
|
|
9536
|
+
}
|
|
9537
|
+
waiting.add(path);
|
|
9538
|
+
atExit.delete(path);
|
|
9539
|
+
lastTryOnExit();
|
|
9540
|
+
}
|
|
9541
|
+
const after = AGAIN_AFTER_MS[attempt];
|
|
9542
|
+
if (after === undefined || !existsSync4(path)) {
|
|
9543
|
+
waiting.delete(path);
|
|
9544
|
+
if (after === undefined) {
|
|
9545
|
+
atExit.add(path);
|
|
9546
|
+
}
|
|
9547
|
+
return;
|
|
9548
|
+
}
|
|
9549
|
+
setTimeout(() => {
|
|
9550
|
+
try {
|
|
9551
|
+
remove(path);
|
|
9552
|
+
waiting.delete(path);
|
|
9553
|
+
} catch {
|
|
9554
|
+
tryAgain(path, attempt + 1);
|
|
9555
|
+
}
|
|
9556
|
+
}, after).unref();
|
|
9557
|
+
}
|
|
9558
|
+
var lastTryWatched = false;
|
|
9559
|
+
function lastTryOnExit() {
|
|
9560
|
+
if (lastTryWatched) {
|
|
9561
|
+
return;
|
|
9562
|
+
}
|
|
9563
|
+
lastTryWatched = true;
|
|
9564
|
+
process6.once("exit", () => {
|
|
9565
|
+
for (const path of [...waiting, ...atExit]) {
|
|
9566
|
+
try {
|
|
9567
|
+
remove(path);
|
|
9568
|
+
} catch {}
|
|
9569
|
+
}
|
|
9570
|
+
});
|
|
9571
|
+
}
|
|
9572
|
+
|
|
9573
|
+
// src/doc-cache.ts
|
|
9574
|
+
var EMPTY_SCRIPT_DOCS = [
|
|
9575
|
+
"extends SceneTree",
|
|
9576
|
+
"",
|
|
9577
|
+
"",
|
|
9578
|
+
"func _initialize() -> void:",
|
|
9579
|
+
"\tvar cache: Resource = Resource.new()",
|
|
9580
|
+
'\tcache.set_meta("classes", [])',
|
|
9581
|
+
"\tvar saved: Error = ResourceSaver.save(cache, OS.get_cmdline_user_args()[0], ResourceSaver.FLAG_COMPRESS)",
|
|
9582
|
+
"\tquit(0 if saved == OK else 1)",
|
|
9583
|
+
""
|
|
9584
|
+
].join(`
|
|
9585
|
+
`);
|
|
9586
|
+
|
|
9508
9587
|
// src/project-scan.ts
|
|
9509
9588
|
var SKIPPED = new Set(["node_modules"]);
|
|
9510
9589
|
var SCENE_EXTENSIONS = new Set(["tscn", "scn"]);
|
|
@@ -9591,83 +9670,6 @@ var IMPORTABLE_EXTENSIONS = [
|
|
|
9591
9670
|
var IMPORTABLE = new Set(IMPORTABLE_EXTENSIONS);
|
|
9592
9671
|
var hashes = new Map;
|
|
9593
9672
|
|
|
9594
|
-
// src/scratch.ts
|
|
9595
|
-
import { existsSync as existsSync4, mkdtempSync as mkdtempSync2, readdirSync as readdirSync3, rmSync as rmSync5 } from "node:fs";
|
|
9596
|
-
import { tmpdir as tmpdir5 } from "node:os";
|
|
9597
|
-
import { join as join5 } from "node:path";
|
|
9598
|
-
import process6 from "node:process";
|
|
9599
|
-
var SWEPT = { recursive: true, force: true };
|
|
9600
|
-
var AGAIN_AFTER_MS = [250, 500, 1000, 2000, 4000, 8000, 16000];
|
|
9601
|
-
var waiting = new Set;
|
|
9602
|
-
var atExit = new Set;
|
|
9603
|
-
function scratchDirectory(kind) {
|
|
9604
|
-
return mkdtempSync2(join5(tmpdir5(), `gdharness-${kind}-${process6.pid}-`));
|
|
9605
|
-
}
|
|
9606
|
-
function discardWith(removePath, paths) {
|
|
9607
|
-
const left = [];
|
|
9608
|
-
for (const path of paths) {
|
|
9609
|
-
if (!path) {
|
|
9610
|
-
continue;
|
|
9611
|
-
}
|
|
9612
|
-
try {
|
|
9613
|
-
removePath(path);
|
|
9614
|
-
} catch (error) {
|
|
9615
|
-
left.push({ path, reason: error instanceof Error ? error.message : String(error) });
|
|
9616
|
-
}
|
|
9617
|
-
}
|
|
9618
|
-
return left;
|
|
9619
|
-
}
|
|
9620
|
-
function discard(...paths) {
|
|
9621
|
-
const left = discardWith(remove, paths);
|
|
9622
|
-
for (const { path } of left) {
|
|
9623
|
-
tryAgain(path, 0);
|
|
9624
|
-
}
|
|
9625
|
-
return left;
|
|
9626
|
-
}
|
|
9627
|
-
function remove(path) {
|
|
9628
|
-
rmSync5(path, SWEPT);
|
|
9629
|
-
}
|
|
9630
|
-
function tryAgain(path, attempt) {
|
|
9631
|
-
if (attempt === 0) {
|
|
9632
|
-
if (waiting.has(path)) {
|
|
9633
|
-
return;
|
|
9634
|
-
}
|
|
9635
|
-
waiting.add(path);
|
|
9636
|
-
atExit.delete(path);
|
|
9637
|
-
lastTryOnExit();
|
|
9638
|
-
}
|
|
9639
|
-
const after = AGAIN_AFTER_MS[attempt];
|
|
9640
|
-
if (after === undefined || !existsSync4(path)) {
|
|
9641
|
-
waiting.delete(path);
|
|
9642
|
-
if (after === undefined) {
|
|
9643
|
-
atExit.add(path);
|
|
9644
|
-
}
|
|
9645
|
-
return;
|
|
9646
|
-
}
|
|
9647
|
-
setTimeout(() => {
|
|
9648
|
-
try {
|
|
9649
|
-
remove(path);
|
|
9650
|
-
waiting.delete(path);
|
|
9651
|
-
} catch {
|
|
9652
|
-
tryAgain(path, attempt + 1);
|
|
9653
|
-
}
|
|
9654
|
-
}, after).unref();
|
|
9655
|
-
}
|
|
9656
|
-
var lastTryWatched = false;
|
|
9657
|
-
function lastTryOnExit() {
|
|
9658
|
-
if (lastTryWatched) {
|
|
9659
|
-
return;
|
|
9660
|
-
}
|
|
9661
|
-
lastTryWatched = true;
|
|
9662
|
-
process6.once("exit", () => {
|
|
9663
|
-
for (const path of [...waiting, ...atExit]) {
|
|
9664
|
-
try {
|
|
9665
|
-
remove(path);
|
|
9666
|
-
} catch {}
|
|
9667
|
-
}
|
|
9668
|
-
});
|
|
9669
|
-
}
|
|
9670
|
-
|
|
9671
9673
|
// src/answer-json.ts
|
|
9672
9674
|
var SCALAR = String.raw`(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)`;
|
|
9673
9675
|
var SCALAR_ARRAY = new RegExp(String.raw`\[\n\s+(${SCALAR}(?:,\n\s+${SCALAR})*)\n\s*\]`, "g");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.68",
|
|
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",
|