gdharness 1.3.67 → 1.3.69

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/keeper.js CHANGED
@@ -7265,14 +7265,16 @@ class CompiledHelper {
7265
7265
  file;
7266
7266
  source;
7267
7267
  digest;
7268
- constructor(named, file, source) {
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: Windows
7478
- // PowerShell saves its module cache relative to where it runs when the profile does not resolve.
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: Windows PowerShell changes the mode
7541
- // it inherited as it starts, and was seen reading 0x1 here, without the open-file bit.
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 === "" ? "Windows PowerShell had not begun running the helper" : `the helper was ${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
- const literal = (path) => `'${path.replaceAll("'", "''")}'`;
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.67",
3
+ "version": "1.3.69",
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",