gdharness 1.3.46 → 1.3.48

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
@@ -6946,8 +6946,8 @@ var require_public_api = __commonJS(function(exports) {
6946
6946
  });
6947
6947
 
6948
6948
  // src/keeper.ts
6949
- import { closeSync as closeSync2, existsSync as existsSync3, mkdtempSync as mkdtempSync4, openSync as openSync3, readFileSync as readFileSync7, rmSync as rmSync6, writeFileSync as writeFileSync3 } from "node:fs";
6950
- import { tmpdir as tmpdir5 } from "node:os";
6949
+ import { closeSync as closeSync3, existsSync as existsSync3, mkdtempSync as mkdtempSync4, openSync as openSync4, readFileSync as readFileSync8, rmSync as rmSync7, writeFileSync as writeFileSync3 } from "node:fs";
6950
+ import { tmpdir as tmpdir6 } from "node:os";
6951
6951
  import { join as join10 } from "node:path";
6952
6952
  import { setTimeout as delay3 } from "node:timers/promises";
6953
6953
 
@@ -7407,344 +7407,541 @@ function throughHelper(how, command, args, files, assembly = helperAssembly()) {
7407
7407
  };
7408
7408
  }
7409
7409
 
7410
- // src/error-mode.ts
7411
- import process3 from "node:process";
7412
- var NO_FAULT_ERROR_BOX = 2;
7413
- var cleared = process3.platform !== "win32";
7414
- async function letWindowsReportCrashes() {
7415
- if (cleared || !("bun" in process3.versions)) {
7416
- return;
7417
- }
7418
- try {
7419
- const { dlopen, FFIType } = await import("bun:ffi");
7420
- const kernel32 = dlopen("kernel32.dll", {
7421
- GetErrorMode: { args: [], returns: FFIType.u32 },
7422
- SetErrorMode: { args: [FFIType.u32], returns: FFIType.u32 }
7423
- });
7424
- try {
7425
- const mode = kernel32.symbols.GetErrorMode();
7426
- kernel32.symbols.SetErrorMode(mode & ~NO_FAULT_ERROR_BOX);
7427
- cleared = true;
7428
- } finally {
7429
- kernel32.close();
7430
- }
7431
- } catch {}
7432
- }
7433
- function crashesReported() {
7434
- return cleared;
7435
- }
7410
+ // src/engine-slots.ts
7411
+ import {
7412
+ closeSync as closeSync2,
7413
+ mkdirSync,
7414
+ openSync as openSync2,
7415
+ readFileSync as readFileSync4,
7416
+ rmSync as rmSync3,
7417
+ statSync as statSync3,
7418
+ watch,
7419
+ writeSync as writeSync2
7420
+ } from "node:fs";
7421
+ import process4 from "node:process";
7436
7422
 
7437
- // src/game-debugger.ts
7438
- import { readFileSync as readFileSync5 } from "node:fs";
7439
- import { createServer } from "node:net";
7440
- import { join as join6 } from "node:path";
7423
+ // src/call-signal.ts
7424
+ import { AsyncLocalStorage } from "node:async_hooks";
7425
+ var current = new AsyncLocalStorage;
7441
7426
 
7442
- // src/godot-variant.ts
7443
- var NIL = 0;
7444
- var BOOL = 1;
7445
- var INT = 2;
7446
- var FLOAT = 3;
7447
- var STRING = 4;
7448
- var ARRAY = 28;
7449
- var FLAG_64 = 1 << 16;
7450
- var MATH = {
7451
- 5: { name: "Vector2", count: 2 },
7452
- 6: { name: "Vector2i", count: 2, ints: true },
7453
- 7: { name: "Rect2", count: 4 },
7454
- 8: { name: "Rect2i", count: 4, ints: true },
7455
- 9: { name: "Vector3", count: 3 },
7456
- 10: { name: "Vector3i", count: 3, ints: true },
7457
- 11: { name: "Transform2D", count: 6 },
7458
- 12: { name: "Vector4", count: 4 },
7459
- 13: { name: "Vector4i", count: 4, ints: true },
7460
- 14: { name: "Plane", count: 4 },
7461
- 15: { name: "Quaternion", count: 4 },
7462
- 16: { name: "AABB", count: 6 },
7463
- 17: { name: "Basis", count: 9 },
7464
- 18: { name: "Transform3D", count: 12 },
7465
- 19: { name: "Projection", count: 16 }
7466
- };
7467
- var PACKED_VECTORS = { 35: 2, 36: 3, 38: 4 };
7427
+ // src/harnesses.ts
7428
+ import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve as resolve2 } from "node:path";
7468
7429
 
7469
- class Reader {
7470
- offset = 0;
7471
- view;
7472
- constructor(view) {
7473
- this.view = view;
7474
- }
7475
- get remaining() {
7476
- return this.view.byteLength - this.offset;
7477
- }
7478
- need(bytes) {
7479
- if (bytes < 0 || bytes > this.remaining) {
7480
- throw new RangeError(`a value runs past the end of its message (${bytes} bytes wanted, ${this.remaining} left)`);
7430
+ // node_modules/yaml/dist/index.js
7431
+ var composer = require_composer();
7432
+ var Document = require_Document();
7433
+ var Schema = require_Schema();
7434
+ var errors = require_errors();
7435
+ var Alias = require_Alias();
7436
+ var identity = require_identity();
7437
+ var Pair = require_Pair();
7438
+ var Scalar = require_Scalar();
7439
+ var YAMLMap = require_YAMLMap();
7440
+ var YAMLSeq = require_YAMLSeq();
7441
+ var cst = require_cst();
7442
+ var lexer = require_lexer();
7443
+ var lineCounter = require_line_counter();
7444
+ var parser = require_parser();
7445
+ var publicApi = require_public_api();
7446
+ var visit = require_visit();
7447
+ var $Composer = composer.Composer;
7448
+ var $Document = Document.Document;
7449
+ var $Schema = Schema.Schema;
7450
+ var $YAMLError = errors.YAMLError;
7451
+ var $YAMLParseError = errors.YAMLParseError;
7452
+ var $YAMLWarning = errors.YAMLWarning;
7453
+ var $Alias = Alias.Alias;
7454
+ var $isAlias = identity.isAlias;
7455
+ var $isCollection = identity.isCollection;
7456
+ var $isDocument = identity.isDocument;
7457
+ var $isMap = identity.isMap;
7458
+ var $isNode = identity.isNode;
7459
+ var $isPair = identity.isPair;
7460
+ var $isScalar = identity.isScalar;
7461
+ var $isSeq = identity.isSeq;
7462
+ var $Pair = Pair.Pair;
7463
+ var $Scalar = Scalar.Scalar;
7464
+ var $YAMLMap = YAMLMap.YAMLMap;
7465
+ var $YAMLSeq = YAMLSeq.YAMLSeq;
7466
+ var $Lexer = lexer.Lexer;
7467
+ var $LineCounter = lineCounter.LineCounter;
7468
+ var $Parser = parser.Parser;
7469
+ var $parse = publicApi.parse;
7470
+ var $parseAllDocuments = publicApi.parseAllDocuments;
7471
+ var $parseDocument = publicApi.parseDocument;
7472
+ var $stringify = publicApi.stringify;
7473
+ var $visit = visit.visit;
7474
+ var $visitAsync = visit.visitAsync;
7475
+
7476
+ // src/paths.ts
7477
+ import { realpathSync, statSync as statSync2 } from "node:fs";
7478
+ import { basename, dirname, isAbsolute, join as join2, relative, resolve, sep } from "node:path";
7479
+ function realAsFarAsItExists(path) {
7480
+ const missing = [];
7481
+ let at = path;
7482
+ for (;; ) {
7483
+ try {
7484
+ return join2(realpathSync.native(at), ...missing);
7485
+ } catch {
7486
+ const parent = dirname(at);
7487
+ if (parent === at) {
7488
+ return path;
7489
+ }
7490
+ missing.unshift(basename(at));
7491
+ at = parent;
7481
7492
  }
7482
7493
  }
7483
- u32() {
7484
- this.need(4);
7485
- const value = this.view.getUint32(this.offset, true);
7486
- this.offset += 4;
7487
- return value;
7488
- }
7489
- i32() {
7490
- this.need(4);
7491
- const value = this.view.getInt32(this.offset, true);
7492
- this.offset += 4;
7493
- return value;
7494
- }
7495
- i64() {
7496
- this.need(8);
7497
- const value = Number(this.view.getBigInt64(this.offset, true));
7498
- this.offset += 8;
7499
- return value;
7500
- }
7501
- u64() {
7502
- this.need(8);
7503
- const value = Number(this.view.getBigUint64(this.offset, true));
7504
- this.offset += 8;
7505
- return value;
7506
- }
7507
- f32() {
7508
- this.need(4);
7509
- const value = this.view.getFloat32(this.offset, true);
7510
- this.offset += 4;
7511
- return value;
7512
- }
7513
- f64() {
7514
- this.need(8);
7515
- const value = this.view.getFloat64(this.offset, true);
7516
- this.offset += 8;
7517
- return value;
7518
- }
7519
- real(wide) {
7520
- return wide ? this.f64() : this.f32();
7521
- }
7522
- bytes(count) {
7523
- this.need(count);
7524
- const out = new Uint8Array(this.view.buffer, this.view.byteOffset + this.offset, count);
7525
- this.offset += count;
7526
- return out;
7527
- }
7528
- string() {
7529
- const length = this.u32();
7530
- const text = new TextDecoder().decode(this.bytes(length));
7531
- this.bytes((4 - length % 4) % 4);
7532
- return text;
7533
- }
7534
7494
  }
7535
- var MAX_DEPTH = 1024;
7536
- function containerType(reader, kind) {
7537
- if (kind === 1) {
7538
- reader.u32();
7539
- } else if (kind === 2 || kind === 3) {
7540
- reader.string();
7541
- }
7495
+
7496
+ // src/harnesses.ts
7497
+ var SERVER_KEY = "gdharness";
7498
+ function tomlArray(values) {
7499
+ return `[${values.map((value) => `"${value}"`).join(", ")}]`;
7542
7500
  }
7543
- function decodeValue(reader, depth) {
7544
- if (depth > MAX_DEPTH) {
7545
- throw new RangeError("a value nests deeper than the engine allows");
7546
- }
7547
- const header = reader.u32();
7548
- const type = header & 255;
7549
- const wide = (header & FLAG_64) !== 0;
7550
- const math = MATH[type];
7551
- if (math !== undefined) {
7552
- return {
7553
- kind: math.name,
7554
- values: Array.from({ length: math.count }, () => math.ints === true ? reader.i32() : reader.real(wide))
7555
- };
7556
- }
7557
- const vectorWidth = PACKED_VECTORS[type];
7558
- if (vectorWidth !== undefined) {
7559
- const count = reader.u32();
7560
- return Array.from({ length: count }, () => ({
7561
- kind: "Vector",
7562
- values: Array.from({ length: vectorWidth }, () => reader.real(wide))
7563
- }));
7564
- }
7565
- switch (type) {
7566
- case NIL:
7567
- return null;
7568
- case BOOL:
7569
- return reader.u32() !== 0;
7570
- case INT:
7571
- return wide ? reader.i64() : reader.i32();
7572
- case FLOAT:
7573
- return wide ? reader.f64() : reader.f32();
7574
- case STRING:
7575
- case 21:
7576
- return reader.string();
7577
- case 20:
7578
- return { kind: "Color", values: [reader.f32(), reader.f32(), reader.f32(), reader.f32()] };
7579
- case 22: {
7580
- const first = reader.u32();
7581
- if ((first & 2147483648) === 0) {
7582
- throw new RangeError("a node path in the format before 3.0");
7583
- }
7584
- const names = first & 2147483647;
7585
- let subnames = reader.u32();
7586
- const flags = reader.u32();
7587
- if ((flags & 2) !== 0) {
7588
- subnames += 1;
7589
- }
7590
- return { kind: "NodePath", values: Array.from({ length: names + subnames }, () => reader.string()) };
7591
- }
7592
- case 23:
7593
- return { kind: "RID", values: [reader.u64()] };
7594
- case 24:
7595
- if ((header & FLAG_64) === 0) {
7596
- throw new RangeError("a full object, which this reader does not take");
7597
- }
7598
- return { kind: "Object", values: [reader.u64()] };
7599
- case 25:
7600
- return { kind: "Callable", values: [] };
7601
- case 26:
7602
- return { kind: "Signal", values: [reader.string(), reader.u64()] };
7603
- case 27: {
7604
- containerType(reader, header >> 16 & 3);
7605
- containerType(reader, header >> 18 & 3);
7606
- const count = reader.u32() & 2147483647;
7607
- const entries = [];
7608
- for (let index = 0;index < count; index += 1) {
7609
- const key = decodeValue(reader, depth + 1);
7610
- entries.push([key, decodeValue(reader, depth + 1)]);
7611
- }
7612
- return { kind: "dictionary", entries };
7501
+ function tomlEnv(launch) {
7502
+ const pairs = Object.entries(launch.env).map(([name, value]) => `${name} = "${value}"`);
7503
+ return `env = { ${pairs.join(", ")} }`;
7504
+ }
7505
+ function jsonSnippet(launch, container, shape) {
7506
+ return JSON.stringify({ [container]: { [SERVER_KEY]: entryFor(shape, launch) } }, null, 2);
7507
+ }
7508
+ var HARNESSES = [
7509
+ {
7510
+ id: "claude-code",
7511
+ name: "Claude Code",
7512
+ scope: "project",
7513
+ file: ".mcp.json",
7514
+ container: "mcpServers",
7515
+ shape: "plain",
7516
+ home: ".claude",
7517
+ marker: ".claude",
7518
+ skills: { dir: join3(".claude", "skills"), shared: false }
7519
+ },
7520
+ {
7521
+ id: "copilot-cli",
7522
+ name: "Copilot CLI",
7523
+ scope: "project",
7524
+ file: ".mcp.json",
7525
+ container: "mcpServers",
7526
+ shape: "plain",
7527
+ home: ".copilot",
7528
+ skills: { dir: join3(".github", "skills"), shared: true },
7529
+ manual: "Trust the folder when Copilot CLI first asks, or it reads no config here."
7530
+ },
7531
+ {
7532
+ id: "qoder",
7533
+ name: "Qoder",
7534
+ scope: "project",
7535
+ file: ".mcp.json",
7536
+ container: "mcpServers",
7537
+ shape: "plain",
7538
+ home: ".qoder",
7539
+ marker: ".qoder"
7540
+ },
7541
+ {
7542
+ id: "command-code",
7543
+ name: "Command Code",
7544
+ scope: "project",
7545
+ file: ".mcp.json",
7546
+ container: "mcpServers",
7547
+ shape: "plain",
7548
+ home: ".commandcode"
7549
+ },
7550
+ {
7551
+ id: "cursor",
7552
+ name: "Cursor",
7553
+ scope: "project",
7554
+ file: join3(".cursor", "mcp.json"),
7555
+ container: "mcpServers",
7556
+ shape: "plain",
7557
+ home: ".cursor",
7558
+ skills: { dir: join3(".cursor", "skills"), shared: true },
7559
+ manual: "Cursor asks before each tool call by default, and the server can be toggled off."
7560
+ },
7561
+ {
7562
+ id: "vscode",
7563
+ name: "VS Code",
7564
+ scope: "project",
7565
+ file: join3(".vscode", "mcp.json"),
7566
+ container: "servers",
7567
+ shape: "typed",
7568
+ home: ".vscode",
7569
+ skills: { dir: join3(".github", "skills"), shared: true },
7570
+ manual: "VS Code asks you to trust a server the first time it starts one."
7571
+ },
7572
+ {
7573
+ id: "opencode",
7574
+ name: "opencode",
7575
+ scope: "project",
7576
+ file: "opencode.json",
7577
+ container: "mcp",
7578
+ shape: "opencode",
7579
+ home: join3(".config", "opencode"),
7580
+ marker: ".opencode",
7581
+ skills: { dir: join3(".opencode", "skills"), shared: true }
7582
+ },
7583
+ {
7584
+ id: "junie",
7585
+ name: "Junie",
7586
+ scope: "project",
7587
+ file: join3(".junie", "mcp", "mcp.json"),
7588
+ container: "mcpServers",
7589
+ shape: "plain",
7590
+ home: ".junie",
7591
+ skills: { dir: join3(".junie", "skills"), shared: true }
7592
+ },
7593
+ {
7594
+ id: "kiro",
7595
+ name: "Kiro",
7596
+ scope: "project",
7597
+ file: join3(".kiro", "settings", "mcp.json"),
7598
+ container: "mcpServers",
7599
+ shape: "plain",
7600
+ home: ".kiro",
7601
+ skills: { dir: join3(".kiro", "skills"), shared: false }
7602
+ },
7603
+ {
7604
+ id: "gemini",
7605
+ name: "Gemini CLI",
7606
+ scope: "project",
7607
+ file: join3(".gemini", "settings.json"),
7608
+ container: "mcpServers",
7609
+ shape: "plain",
7610
+ home: ".gemini",
7611
+ skills: { dir: join3(".gemini", "skills"), shared: true }
7612
+ },
7613
+ {
7614
+ id: "roo",
7615
+ name: "Roo Code",
7616
+ scope: "project",
7617
+ file: join3(".roo", "mcp.json"),
7618
+ container: "mcpServers",
7619
+ shape: "plain"
7620
+ },
7621
+ {
7622
+ id: "kilo",
7623
+ name: "Kilo Code",
7624
+ scope: "project",
7625
+ file: join3(".kilocode", "mcp.json"),
7626
+ container: "mcpServers",
7627
+ shape: "plain"
7628
+ },
7629
+ {
7630
+ id: "amazon-q",
7631
+ name: "Amazon Q Developer CLI",
7632
+ scope: "project",
7633
+ file: join3(".amazonq", "mcp.json"),
7634
+ container: "mcpServers",
7635
+ shape: "plain",
7636
+ home: join3(".aws", "amazonq")
7637
+ },
7638
+ {
7639
+ id: "zed",
7640
+ name: "Zed",
7641
+ scope: "project",
7642
+ file: join3(".zed", "settings.json"),
7643
+ container: "context_servers",
7644
+ shape: "plain"
7645
+ },
7646
+ {
7647
+ id: "amp",
7648
+ name: "Amp",
7649
+ scope: "project",
7650
+ file: join3(".amp", "settings.json"),
7651
+ container: "amp.mcpServers",
7652
+ shape: "plain",
7653
+ home: join3(".config", "amp")
7654
+ },
7655
+ {
7656
+ id: "warp",
7657
+ name: "Warp",
7658
+ scope: "project",
7659
+ file: join3(".warp", ".mcp.json"),
7660
+ container: "mcpServers",
7661
+ shape: "plain",
7662
+ home: ".warp",
7663
+ manual: "Warp starts a project server only once you toggle it on, on its MCP servers page."
7664
+ },
7665
+ {
7666
+ id: "trae",
7667
+ name: "Trae",
7668
+ scope: "project",
7669
+ file: join3(".trae", "mcp.json"),
7670
+ container: "mcpServers",
7671
+ shape: "plain",
7672
+ home: ".trae"
7673
+ },
7674
+ {
7675
+ id: "factory",
7676
+ name: "Factory Droid",
7677
+ scope: "project",
7678
+ file: join3(".factory", "mcp.json"),
7679
+ container: "mcpServers",
7680
+ shape: "typed",
7681
+ home: ".factory"
7682
+ },
7683
+ {
7684
+ id: "tabnine",
7685
+ name: "Tabnine",
7686
+ scope: "project",
7687
+ file: join3(".tabnine", "mcp_servers.json"),
7688
+ container: "mcpServers",
7689
+ shape: "plain",
7690
+ home: ".tabnine"
7691
+ },
7692
+ {
7693
+ id: "firebender",
7694
+ name: "Firebender",
7695
+ scope: "project",
7696
+ file: "firebender.json",
7697
+ container: "mcpServers",
7698
+ shape: "plain"
7699
+ },
7700
+ {
7701
+ id: "pi",
7702
+ name: "pi",
7703
+ scope: "project",
7704
+ file: join3(".pi", "mcp.json"),
7705
+ container: "mcpServers",
7706
+ shape: "plain",
7707
+ home: ".pi"
7708
+ },
7709
+ {
7710
+ id: "mistral-vibe",
7711
+ name: "Mistral Vibe",
7712
+ scope: "project",
7713
+ file: join3(".vibe", "config.toml"),
7714
+ container: "mcp_servers",
7715
+ shape: "plain",
7716
+ toml: {
7717
+ header: "[[mcp_servers]]",
7718
+ identity: `name = "${SERVER_KEY}"`,
7719
+ block: (launch) => [
7720
+ "[[mcp_servers]]",
7721
+ `name = "${SERVER_KEY}"`,
7722
+ 'transport = "stdio"',
7723
+ `command = "${launch.command}"`,
7724
+ `args = ${tomlArray(launch.args)}`,
7725
+ tomlEnv(launch)
7726
+ ].join(`
7727
+ `)
7613
7728
  }
7614
- case ARRAY: {
7615
- containerType(reader, header >> 16 & 3);
7616
- const count = reader.u32() & 2147483647;
7617
- return Array.from({ length: count }, () => decodeValue(reader, depth + 1));
7729
+ },
7730
+ {
7731
+ id: "vtcode",
7732
+ name: "VT Code",
7733
+ scope: "project",
7734
+ file: "vtcode.toml",
7735
+ container: "mcp.providers",
7736
+ shape: "plain",
7737
+ marker: ".vtcode",
7738
+ toml: {
7739
+ header: "[[mcp.providers]]",
7740
+ identity: `name = "${SERVER_KEY}"`,
7741
+ enable: { header: "[mcp]", line: "enabled = true" },
7742
+ block: (launch) => [
7743
+ "[[mcp.providers]]",
7744
+ `name = "${SERVER_KEY}"`,
7745
+ "enabled = true",
7746
+ `command = "${launch.command}"`,
7747
+ `args = ${tomlArray(launch.args)}`,
7748
+ tomlEnv(launch)
7749
+ ].join(`
7750
+ `)
7618
7751
  }
7619
- case 29: {
7620
- const count = reader.u32();
7621
- const bytes = [...reader.bytes(count)];
7622
- reader.bytes((4 - count % 4) % 4);
7623
- return bytes;
7752
+ },
7753
+ {
7754
+ id: "fast-agent",
7755
+ name: "fast-agent",
7756
+ scope: "project",
7757
+ file: "fastagent.config.yaml",
7758
+ container: "mcp",
7759
+ shape: "plain",
7760
+ yaml: {
7761
+ path: ["mcp", "servers", SERVER_KEY],
7762
+ entry: (launch) => ({ command: launch.command, args: [...launch.args], env: { ...launch.env } })
7763
+ }
7764
+ },
7765
+ {
7766
+ id: "codex",
7767
+ name: "Codex CLI",
7768
+ scope: "home",
7769
+ file: join3(".codex", "config.toml"),
7770
+ container: "mcp_servers",
7771
+ shape: "plain",
7772
+ manual: "Codex reads its config at startup, so restart it.",
7773
+ toml: {
7774
+ header: `[mcp_servers.${SERVER_KEY}]`,
7775
+ block: (launch) => [
7776
+ `[mcp_servers.${SERVER_KEY}]`,
7777
+ `command = "${launch.command}"`,
7778
+ `args = ${tomlArray(launch.args)}`,
7779
+ tomlEnv(launch)
7780
+ ].join(`
7781
+ `)
7782
+ }
7783
+ },
7784
+ {
7785
+ id: "cline",
7786
+ name: "Cline",
7787
+ scope: "home",
7788
+ file: join3(".cline", "data", "settings", "cline_mcp_settings.json"),
7789
+ container: "mcpServers",
7790
+ shape: "plain",
7791
+ marker: ".cline",
7792
+ skills: { dir: join3(".cline", "skills"), shared: false }
7793
+ },
7794
+ {
7795
+ id: "goose",
7796
+ name: "Goose",
7797
+ scope: "home",
7798
+ file: {
7799
+ win32: { appData: join3("Block", "goose", "config", "config.yaml") },
7800
+ darwin: join3(".config", "goose", "config.yaml"),
7801
+ linux: join3(".config", "goose", "config.yaml")
7802
+ },
7803
+ container: "extensions",
7804
+ shape: "plain",
7805
+ yaml: {
7806
+ path: ["extensions", SERVER_KEY],
7807
+ entry: (launch) => ({
7808
+ name: SERVER_KEY,
7809
+ type: "stdio",
7810
+ enabled: true,
7811
+ cmd: launch.command,
7812
+ args: [...launch.args],
7813
+ envs: { ...launch.env },
7814
+ timeout: 300
7815
+ })
7624
7816
  }
7625
- case 30:
7626
- return Array.from({ length: reader.u32() }, () => reader.i32());
7627
- case 31:
7628
- return Array.from({ length: reader.u32() }, () => reader.i64());
7629
- case 32:
7630
- return Array.from({ length: reader.u32() }, () => reader.f32());
7631
- case 33:
7632
- return Array.from({ length: reader.u32() }, () => reader.f64());
7633
- case 34:
7634
- return Array.from({ length: reader.u32() }, () => reader.string().replace(/\0$/, ""));
7635
- case 37:
7636
- return Array.from({ length: reader.u32() }, () => ({
7637
- kind: "Color",
7638
- values: [reader.f32(), reader.f32(), reader.f32(), reader.f32()]
7639
- }));
7640
- default:
7641
- throw new RangeError(`a value of type ${type}, which Godot 4.7 does not have`);
7642
- }
7643
- }
7644
- function decodeVariant(bytes) {
7645
- const reader = new Reader(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength));
7646
- const value = decodeValue(reader, 0);
7647
- if (reader.remaining !== 0) {
7648
- throw new RangeError(`${reader.remaining} bytes left over after the value`);
7649
- }
7650
- return value;
7651
- }
7652
- function pushU32(out, value) {
7653
- out.push(value & 255, value >>> 8 & 255, value >>> 16 & 255, value >>> 24 & 255);
7654
- }
7655
- function encodeInto(out, value) {
7656
- if (value === null) {
7657
- pushU32(out, NIL);
7658
- } else if (typeof value === "boolean") {
7659
- pushU32(out, BOOL);
7660
- pushU32(out, value ? 1 : 0);
7661
- } else if (typeof value === "number") {
7662
- const view = new DataView(new ArrayBuffer(8));
7663
- if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {
7664
- pushU32(out, INT);
7665
- view.setInt32(0, value, true);
7666
- out.push(...new Uint8Array(view.buffer, 0, 4));
7667
- } else if (Number.isInteger(value)) {
7668
- pushU32(out, INT | FLAG_64);
7669
- view.setBigInt64(0, BigInt(value), true);
7670
- out.push(...new Uint8Array(view.buffer));
7671
- } else {
7672
- pushU32(out, FLOAT | FLAG_64);
7673
- view.setFloat64(0, value, true);
7674
- out.push(...new Uint8Array(view.buffer));
7817
+ },
7818
+ {
7819
+ id: "windsurf",
7820
+ name: "Windsurf",
7821
+ scope: "home",
7822
+ file: join3(".codeium", "windsurf", "mcp_config.json"),
7823
+ container: "mcpServers",
7824
+ shape: "plain",
7825
+ skills: { dir: join3(".windsurf", "skills"), shared: true }
7826
+ },
7827
+ {
7828
+ id: "hermes",
7829
+ name: "Hermes",
7830
+ scope: "home",
7831
+ file: join3(".hermes", "config.yaml"),
7832
+ container: "mcp_servers",
7833
+ shape: "plain",
7834
+ skills: { dir: join3(".hermes", "skills"), shared: true },
7835
+ yaml: {
7836
+ path: ["mcp_servers", SERVER_KEY],
7837
+ entry: (launch) => ({
7838
+ command: launch.command,
7839
+ args: [...launch.args],
7840
+ env: { ...launch.env },
7841
+ enabled: true
7842
+ })
7675
7843
  }
7676
- } else if (typeof value === "string") {
7677
- const bytes = new TextEncoder().encode(value);
7678
- pushU32(out, STRING);
7679
- pushU32(out, bytes.length);
7680
- out.push(...bytes, ...Array.from({ length: (4 - bytes.length % 4) % 4 }, () => 0));
7681
- } else {
7682
- pushU32(out, ARRAY);
7683
- pushU32(out, value.length);
7684
- for (const element of value) {
7685
- encodeInto(out, element);
7844
+ },
7845
+ {
7846
+ id: "openclaw",
7847
+ name: "OpenClaw",
7848
+ scope: "home",
7849
+ file: join3(".openclaw", "openclaw.json"),
7850
+ container: "mcpServers",
7851
+ shape: "plain"
7852
+ },
7853
+ {
7854
+ id: "claude-desktop",
7855
+ name: "Claude Desktop",
7856
+ scope: "home",
7857
+ file: {
7858
+ win32: { appData: join3("Claude", "claude_desktop_config.json") },
7859
+ darwin: join3("Library", "Application Support", "Claude", "claude_desktop_config.json"),
7860
+ linux: join3(".config", "Claude", "claude_desktop_config.json")
7861
+ },
7862
+ container: "mcpServers",
7863
+ shape: "plain"
7864
+ },
7865
+ {
7866
+ id: "zeroclaw",
7867
+ name: "ZeroClaw",
7868
+ scope: "home",
7869
+ file: join3(".zeroclaw", "config.toml"),
7870
+ container: "mcp.servers",
7871
+ shape: "plain",
7872
+ toml: {
7873
+ header: "[[mcp.servers]]",
7874
+ identity: `name = "${SERVER_KEY}"`,
7875
+ enable: { header: "[mcp]", line: "enabled = true" },
7876
+ block: (launch) => [
7877
+ "[[mcp.servers]]",
7878
+ `name = "${SERVER_KEY}"`,
7879
+ `command = "${launch.command}"`,
7880
+ `args = ${tomlArray(launch.args)}`,
7881
+ tomlEnv(launch)
7882
+ ].join(`
7883
+ `)
7686
7884
  }
7885
+ },
7886
+ {
7887
+ id: "deepcode",
7888
+ name: "Deep Code",
7889
+ scope: "home",
7890
+ file: join3(".deepcode", "settings.json"),
7891
+ container: "mcpServers",
7892
+ shape: "plain"
7893
+ },
7894
+ {
7895
+ id: "nanobot",
7896
+ name: "nanobot",
7897
+ scope: "home",
7898
+ file: join3(".nanobot", "config.json"),
7899
+ container: "mcpServers",
7900
+ shape: "plain",
7901
+ snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
7902
+ },
7903
+ {
7904
+ id: "autohand",
7905
+ name: "Autohand",
7906
+ scope: "home",
7907
+ file: join3(".autohand", "config.json"),
7908
+ container: "mcpServers",
7909
+ shape: "plain",
7910
+ snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
7687
7911
  }
7688
- }
7689
- function encodeVariant(value) {
7690
- const out = [];
7691
- encodeInto(out, value);
7692
- return Uint8Array.from(out);
7693
- }
7694
- var MAIN_THREAD = 1;
7695
- function framedCommand(message, data, thread = MAIN_THREAD) {
7696
- const body = encodeVariant([message, thread, data]);
7697
- const framed = new Uint8Array(body.length + 4);
7698
- new DataView(framed.buffer).setUint32(0, body.length, true);
7699
- framed.set(body, 4);
7700
- return framed;
7701
- }
7702
- var MOST_MESSAGE_BYTES = (8 << 20) + 4;
7703
-
7704
- class DebuggerStream {
7705
- pending = new Uint8Array(0);
7706
- push(chunk) {
7707
- const joined = new Uint8Array(this.pending.length + chunk.length);
7708
- joined.set(this.pending, 0);
7709
- joined.set(chunk, this.pending.length);
7710
- const out = [];
7711
- let at = 0;
7712
- while (joined.length - at >= 4) {
7713
- const length = new DataView(joined.buffer, joined.byteOffset + at, 4).getUint32(0, true);
7714
- if (length > MOST_MESSAGE_BYTES) {
7715
- throw new RangeError(`a message of ${length} bytes, more than the engine sends`);
7716
- }
7717
- if (joined.length - at - 4 < length) {
7718
- break;
7912
+ ];
7913
+ var OURS = ["GODOT_PATH", "GDHARNESS_PROJECT"];
7914
+ function environmentFor(launch, held) {
7915
+ const kept = {};
7916
+ if (typeof held === "object" && held !== null && !Array.isArray(held)) {
7917
+ for (const [name, value] of Object.entries(held)) {
7918
+ if (typeof value === "string" && !OURS.includes(name)) {
7919
+ kept[name] = value;
7719
7920
  }
7720
- out.push(readMessage(joined.subarray(at + 4, at + 4 + length)));
7721
- at += 4 + length;
7722
7921
  }
7723
- this.pending = joined.slice(at);
7724
- return out;
7725
7922
  }
7923
+ return { ...kept, ...launch.env };
7726
7924
  }
7727
- function readMessage(body) {
7728
- let value;
7729
- try {
7730
- value = decodeVariant(body);
7731
- } catch (error) {
7732
- return { unreadable: error instanceof Error ? error.message : String(error) };
7733
- }
7734
- if (!Array.isArray(value) || value.length !== 3) {
7735
- return { unreadable: "a message that is not [message, thread, data]" };
7736
- }
7737
- const [message, thread, data] = value;
7738
- if (typeof message !== "string" || typeof thread !== "number" || !Array.isArray(data)) {
7739
- return { unreadable: "a message whose name, thread or data is the wrong type" };
7925
+ function entryFor(shape, launch, held) {
7926
+ const before = typeof held === "object" && held !== null && !Array.isArray(held) ? { ...held } : {};
7927
+ if (shape === "opencode") {
7928
+ return {
7929
+ ...before,
7930
+ type: "local",
7931
+ command: [launch.command, ...launch.args],
7932
+ environment: environmentFor(launch, before["environment"]),
7933
+ enabled: true
7934
+ };
7740
7935
  }
7741
- return { message, thread, data };
7936
+ return {
7937
+ ...before,
7938
+ ...shape === "typed" ? { type: "stdio" } : {},
7939
+ command: launch.command,
7940
+ args: [...launch.args],
7941
+ env: environmentFor(launch, before["env"])
7942
+ };
7742
7943
  }
7743
7944
 
7744
- // src/setup.ts
7745
- import { dirname as dirname3, join as join5 } from "node:path";
7746
- import { fileURLToPath } from "node:url";
7747
-
7748
7945
  // src/gdscript-source.ts
7749
7946
  var DECLARING = new Set(["var", "const", "func", "signal", "enum", "class", "for", "class_name"]);
7750
7947
  var NAME = "[\\p{L}_][\\p{L}\\p{N}_]*";
@@ -7807,6 +8004,23 @@ import { readFileSync as readFileSync2, renameSync, rmSync as rmSync2, writeFile
7807
8004
  var HELD_FILE_MS = 1000;
7808
8005
  var HELD_FILE_RETRY_MS = 10;
7809
8006
  var HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
8007
+ function readWhole(path) {
8008
+ const until = Date.now() + HELD_FILE_MS;
8009
+ for (;; ) {
8010
+ try {
8011
+ return readFileSync2(path, "utf8");
8012
+ } catch (error) {
8013
+ const code = error.code ?? "";
8014
+ if (code === "ENOENT") {
8015
+ return null;
8016
+ }
8017
+ if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
8018
+ throw error;
8019
+ }
8020
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
8021
+ }
8022
+ }
8023
+ }
7810
8024
  function writeWhole(path, text) {
7811
8025
  const partial = `${path}.${process.pid}.partial`;
7812
8026
  try {
@@ -7831,719 +8045,757 @@ function writeWhole(path, text) {
7831
8045
  }
7832
8046
  }
7833
8047
  }
7834
-
7835
- // src/dictionary.ts
7836
- function emptyRecord() {
7837
- return Object.create(null);
8048
+ function removeWhole(path) {
8049
+ const until = Date.now() + HELD_FILE_MS;
8050
+ for (;; ) {
8051
+ try {
8052
+ rmSync2(path, { force: true });
8053
+ return true;
8054
+ } catch (error) {
8055
+ const code = error.code ?? "";
8056
+ if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
8057
+ return false;
8058
+ }
8059
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, HELD_FILE_RETRY_MS);
8060
+ }
8061
+ }
7838
8062
  }
7839
8063
 
7840
- // src/call-signal.ts
7841
- import { AsyncLocalStorage } from "node:async_hooks";
7842
- var current = new AsyncLocalStorage;
8064
+ // src/engine-leaks.ts
8065
+ var REFCOUNTED_HELD = "A RefCounted alive at exit is held by a cycle of references (two holding each other, or one " + "holding a lambda that captures it) or by an Object never freed, rather than by a node left out " + "of the tree; a WeakRef on one side of the cycle, or clearing the reference once done, frees it.";
8066
+ var WALK_STOPPED_SENTENCE = "The engine's shutdown stopped part way through its scripts (godot#117991, fixed in 4.8 by " + "godot#120976), so it reported as leaked at exit what it never got to free, and the report is the " + "engine's rather than the run's. gdharness holds every script loaded from a file past that walk, " + "which keeps it whole, so this one stopped on a script it could not hold, such as one made in code. " + "A leak of the run's own is not told apart in such a run.";
8067
+ var NAME2 = "[\\p{L}_][\\p{L}\\p{N}_]*";
8068
+ var EXPORTED = new RegExp(`@export(?!_(?:group|subgroup|category)\\b)\\w*(?:\\([^)]*\\))?\\s+(?:@${NAME2}(?:\\([^)]*\\))?\\s+)*` + `(?:static\\s+)?var\\s+(${NAME2})\\s*:\\s*(?:Array|Dictionary)\\s*\\[([^\\]]*)\\]`, "gu");
7843
8069
 
7844
- // src/harnesses.ts
7845
- import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute2, join as join3, relative as relative2, resolve as resolve2 } from "node:path";
8070
+ // src/junit.ts
8071
+ var ESCAPE = String.fromCharCode(27);
8072
+ var LOCATION = `'[^'\\n]*' in \\S+:\\d+`;
8073
+ var IGNORING_CASE = " \\(ignoring case\\)";
8074
+ var PRINTED_ACTUAL = new RegExp(` but was\\n '((?:(?!\\tat ${LOCATION})[\\s\\S])*?)'((?:${ESCAPE}\\[[0-9;]*m)*)(${IGNORING_CASE})?((?:${ESCAPE}\\[[0-9;]*m)*)\\tat (${LOCATION})`, "g");
8075
+ var QUOTED_EQUALITY = new RegExp(`^Expecting(?: error message)?:\\n '([\\s\\S]*)'\\n but was\\n '([\\s\\S]*)'(?:${IGNORING_CASE})?\\n\\tat `);
8076
+ var COLOUR = new RegExp(`${ESCAPE}\\[([0-9;]*)m`, "g");
8077
+ var HOOKS_LEFT = new Map([
8078
+ ["before", "before()"],
8079
+ ["after", "after()"],
8080
+ ["before or after", "before() or after()"]
8081
+ ]);
7846
8082
 
7847
- // node_modules/yaml/dist/index.js
7848
- var composer = require_composer();
7849
- var Document = require_Document();
7850
- var Schema = require_Schema();
7851
- var errors = require_errors();
7852
- var Alias = require_Alias();
7853
- var identity = require_identity();
7854
- var Pair = require_Pair();
7855
- var Scalar = require_Scalar();
7856
- var YAMLMap = require_YAMLMap();
7857
- var YAMLSeq = require_YAMLSeq();
7858
- var cst = require_cst();
7859
- var lexer = require_lexer();
7860
- var lineCounter = require_line_counter();
7861
- var parser = require_parser();
7862
- var publicApi = require_public_api();
7863
- var visit = require_visit();
7864
- var $Composer = composer.Composer;
7865
- var $Document = Document.Document;
7866
- var $Schema = Schema.Schema;
7867
- var $YAMLError = errors.YAMLError;
7868
- var $YAMLParseError = errors.YAMLParseError;
7869
- var $YAMLWarning = errors.YAMLWarning;
7870
- var $Alias = Alias.Alias;
7871
- var $isAlias = identity.isAlias;
7872
- var $isCollection = identity.isCollection;
7873
- var $isDocument = identity.isDocument;
7874
- var $isMap = identity.isMap;
7875
- var $isNode = identity.isNode;
7876
- var $isPair = identity.isPair;
7877
- var $isScalar = identity.isScalar;
7878
- var $isSeq = identity.isSeq;
7879
- var $Pair = Pair.Pair;
7880
- var $Scalar = Scalar.Scalar;
7881
- var $YAMLMap = YAMLMap.YAMLMap;
7882
- var $YAMLSeq = YAMLSeq.YAMLSeq;
7883
- var $Lexer = lexer.Lexer;
7884
- var $LineCounter = lineCounter.LineCounter;
7885
- var $Parser = parser.Parser;
7886
- var $parse = publicApi.parse;
7887
- var $parseAllDocuments = publicApi.parseAllDocuments;
7888
- var $parseDocument = publicApi.parseDocument;
7889
- var $stringify = publicApi.stringify;
7890
- var $visit = visit.visit;
7891
- var $visitAsync = visit.visitAsync;
8083
+ // src/suite-judge.ts
8084
+ var TIME = String.raw`(?:\d+h )?(?:\d+min )?(?:\d+s )?\d+ms`;
8085
+ var CASE_LINE = new RegExp(String.raw`^\s*(res://.+?\.gd) > (.+?) (STARTED|PASSED|FAILED|FLAKY|SKIPPED|WARNING)(?: \((?:retry \d+|\d+ retries)\))?(?: (${TIME}))?\s*$`);
8086
+ var STATISTICS = new RegExp(String.raw`^Statistics:.*\|\s*([A-Z]+)(?:\s+\(.*?\))?\s+(${TIME})\s*$`);
8087
+ var WINDOWS_EXITS = new Map([
8088
+ [3221225477, "STATUS_ACCESS_VIOLATION"],
8089
+ [3221225495, "STATUS_NO_MEMORY"],
8090
+ [3221225773, "STATUS_COMMITMENT_LIMIT"],
8091
+ [3221225794, "STATUS_DLL_INIT_FAILED"],
8092
+ [3221226505, "STATUS_STACK_BUFFER_OVERRUN"],
8093
+ [3228369022, "a module that could not be found (VcppException)"],
8094
+ [3228369023, "a procedure that could not be found (VcppException)"]
8095
+ ]);
8096
+ var MEMORY_EXITS = new Set([3221225495, 3221225773]);
8097
+ var GDUNIT_FAILED = 100;
8098
+ var GDUNIT_ORPHANS = 101;
8099
+ var GDUNIT_EXITS = new Map([
8100
+ [GDUNIT_FAILED, "gdUnit4's code for a case that failed or errored"],
8101
+ [GDUNIT_ORPHANS, "gdUnit4's code for orphan nodes left behind"],
8102
+ [103, "gdUnit4's code for a suite that cannot run headless"],
8103
+ [104, "gdUnit4's code for a Godot version it does not support"],
8104
+ [105, "gdUnit4's code for scripts that did not compile"]
8105
+ ]);
8106
+ var GODOT_EXITS = new Set([1, 255]);
7892
8107
 
7893
- // src/paths.ts
7894
- import { realpathSync, statSync as statSync2 } from "node:fs";
7895
- import { basename, dirname, isAbsolute, join as join2, relative, resolve, sep } from "node:path";
7896
- function realAsFarAsItExists(path) {
7897
- const missing = [];
7898
- let at = path;
7899
- for (;; ) {
8108
+ // src/windows-ask.ts
8109
+ import { tmpdir as tmpdir2 } from "node:os";
8110
+ import process3 from "node:process";
8111
+ var SCRIPT = [
8112
+ "[Console]::OutputEncoding = [Text.Encoding]::UTF8",
8113
+ "$in = [Console]::In",
8114
+ "while ($null -ne ($line = $in.ReadLine())) {",
8115
+ ' $parts = $line.Split(" ", 2)',
8116
+ " try {",
8117
+ " $asked = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($parts[1]))",
8118
+ " $said = (& ([ScriptBlock]::Create($asked)) | Out-String -Width 1000000)",
8119
+ ' $tag = "OK"',
8120
+ " } catch {",
8121
+ " $said = $_.Exception.Message",
8122
+ ' $tag = "ERR"',
8123
+ " }",
8124
+ ' [Console]::Out.Write($parts[0] + " " + $tag + " " + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($said)) + "`n")',
8125
+ " [Console]::Out.Flush()",
8126
+ "}"
8127
+ ].join(`
8128
+ `);
8129
+
8130
+ class WindowsAskFailure extends Error {
8131
+ constructor(how) {
8132
+ super(`PowerShell ${how}`);
8133
+ }
8134
+ }
8135
+ var helper = null;
8136
+ var buffered = "";
8137
+ var next = 1;
8138
+ var out = null;
8139
+ var queued = [];
8140
+ var held = false;
8141
+ function holding(child, wanted) {
8142
+ if (held === wanted) {
8143
+ return;
8144
+ }
8145
+ held = wanted;
8146
+ const stdout = child.stdout;
8147
+ if (wanted) {
8148
+ stdout.ref?.();
8149
+ } else {
8150
+ stdout.unref?.();
8151
+ }
8152
+ }
8153
+ function running() {
8154
+ if (helper?.exitCode === null && helper.signalCode === null) {
8155
+ return helper;
8156
+ }
8157
+ const child = spawnHidden("powershell.exe", [
8158
+ "-NoProfile",
8159
+ "-NonInteractive",
8160
+ "-ExecutionPolicy",
8161
+ "Bypass",
8162
+ "-EncodedCommand",
8163
+ Buffer.from(SCRIPT, "utf16le").toString("base64")
8164
+ ], { cwd: tmpdir2() });
8165
+ buffered = "";
8166
+ child.stdout.setEncoding("utf8");
8167
+ child.stdout.on("data", (chunk) => {
8168
+ buffered += chunk;
8169
+ for (let end = buffered.indexOf(`
8170
+ `);end !== -1; end = buffered.indexOf(`
8171
+ `)) {
8172
+ answered(buffered.slice(0, end).trim());
8173
+ buffered = buffered.slice(end + 1);
8174
+ }
8175
+ });
8176
+ child.stderr.resume();
8177
+ child.stdin.on("error", () => {});
8178
+ const gone = () => {
8179
+ if (helper !== child) {
8180
+ return;
8181
+ }
8182
+ helper = null;
8183
+ if (out !== null) {
8184
+ clearTimeout(out.timer);
8185
+ out.question.reject(new WindowsAskFailure("exited before it answered"));
8186
+ out = null;
8187
+ }
8188
+ sendNext();
8189
+ };
8190
+ child.once("exit", gone);
8191
+ child.once("error", gone);
8192
+ child.unref();
8193
+ child.stdin.unref?.();
8194
+ child.stderr.unref?.();
8195
+ held = true;
8196
+ holding(child, false);
8197
+ helper = child;
8198
+ return child;
8199
+ }
8200
+ function answered(line) {
8201
+ const [id, tag, body] = line.split(" ");
8202
+ if (out === null || out.id !== Number(id)) {
8203
+ return;
8204
+ }
8205
+ const { question, timer } = out;
8206
+ clearTimeout(timer);
8207
+ out = null;
8208
+ const said = Buffer.from(body ?? "", "base64").toString("utf8");
8209
+ if (tag === "OK") {
8210
+ question.resolve(said);
8211
+ } else {
8212
+ question.reject(new WindowsAskFailure(`refused the question: ${said.trim() || "no reason given"}`));
8213
+ }
8214
+ sendNext();
8215
+ }
8216
+ function sendNext() {
8217
+ const question = queued.shift();
8218
+ if (question === undefined) {
8219
+ if (helper !== null) {
8220
+ holding(helper, false);
8221
+ }
8222
+ return;
8223
+ }
8224
+ const child = running();
8225
+ holding(child, true);
8226
+ const id = next;
8227
+ next += 1;
8228
+ const timer = setTimeout(() => {
8229
+ if (out?.id !== id) {
8230
+ return;
8231
+ }
8232
+ out = null;
8233
+ question.reject(new WindowsAskFailure(`did not answer within ${question.withinMs}ms`));
8234
+ if (helper === child) {
8235
+ helper = null;
8236
+ }
8237
+ child.kill();
8238
+ sendNext();
8239
+ }, question.withinMs);
8240
+ out = { id, question, timer };
8241
+ child.stdin.write(`${id} ${Buffer.from(question.script, "utf8").toString("base64")}
8242
+ `);
8243
+ }
8244
+ function askWindows(script, withinMs) {
8245
+ if (process3.platform !== "win32") {
8246
+ return Promise.reject(new WindowsAskFailure("is asked only on Windows"));
8247
+ }
8248
+ return new Promise((resolve, reject) => {
8249
+ queued.push({ script, withinMs, resolve, reject });
8250
+ if (out === null) {
8251
+ sendNext();
8252
+ }
8253
+ });
8254
+ }
8255
+
8256
+ // src/engine-launch.ts
8257
+ var CONTROL_SEQUENCE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[A-Za-z]`, "g");
8258
+ var MEMORY_KEPT = 4 * 1024 ** 3;
8259
+ var MEMORY_PER_ENGINE = 1.5 * 1024 ** 3;
8260
+
8261
+ // src/process-children.ts
8262
+ import { readFileSync as readFileSync3 } from "node:fs";
8263
+ import { basename as basename3 } from "node:path";
8264
+ async function startTimesOf(pids) {
8265
+ const began = new Map;
8266
+ if (pids.length === 0) {
8267
+ return began;
8268
+ }
8269
+ try {
8270
+ if (process.platform === "win32") {
8271
+ const filter = pids.map((pid) => `ProcessId=${pid}`).join(" OR ");
8272
+ const said = await askWindows(`Get-CimInstance Win32_Process -Filter "${filter}" | ForEach-Object { "$($_.ProcessId) $(([DateTimeOffset]$_.CreationDate).ToUnixTimeMilliseconds())" }`, ASK_TIMEOUT_MS);
8273
+ for (const line of said.split(`
8274
+ `)) {
8275
+ const found = /^\s*(\d+)\s+(\d+)\s*$/.exec(line);
8276
+ if (found?.[1] !== undefined && found[2] !== undefined) {
8277
+ began.set(Number(found[1]), Number(found[2]));
8278
+ }
8279
+ }
8280
+ return began;
8281
+ }
8282
+ if (process.platform === "linux") {
8283
+ return await linuxStartTimes(pids);
8284
+ }
8285
+ const said = await printedBy("ps", ["-p", pids.join(","), "-o", "pid=,lstart="], {
8286
+ ...process.env,
8287
+ LC_ALL: "C"
8288
+ });
8289
+ for (const line of said.split(`
8290
+ `)) {
8291
+ const found = /^\s*(\d+)\s+(.+)$/.exec(line);
8292
+ const at = Date.parse(found?.[2]?.trim() ?? "");
8293
+ if (found?.[1] !== undefined && !Number.isNaN(at)) {
8294
+ began.set(Number(found[1]), at);
8295
+ }
8296
+ }
8297
+ } catch {}
8298
+ return began;
8299
+ }
8300
+ async function linuxStartTimes(pids) {
8301
+ const began = new Map;
8302
+ const hertz = await ticksPerSecond();
8303
+ let booted;
8304
+ try {
8305
+ booted = Number(/^btime\s+(\d+)$/m.exec(readFileSync3("/proc/stat", "utf8"))?.[1] ?? Number.NaN) * 1000;
8306
+ } catch {
8307
+ return began;
8308
+ }
8309
+ if (hertz === null || Number.isNaN(booted)) {
8310
+ return began;
8311
+ }
8312
+ for (const pid of pids) {
8313
+ let stat;
7900
8314
  try {
7901
- return join2(realpathSync.native(at), ...missing);
8315
+ stat = readFileSync3(`/proc/${String(pid)}/stat`, "utf8");
7902
8316
  } catch {
7903
- const parent = dirname(at);
7904
- if (parent === at) {
7905
- return path;
7906
- }
7907
- missing.unshift(basename(at));
7908
- at = parent;
8317
+ continue;
8318
+ }
8319
+ const ticks = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[19]);
8320
+ if (Number.isInteger(ticks) && ticks >= 0) {
8321
+ began.set(pid, booted + Math.round(ticks * 1000 / hertz));
7909
8322
  }
7910
8323
  }
8324
+ return began;
7911
8325
  }
7912
-
7913
- // src/harnesses.ts
7914
- var SERVER_KEY = "gdharness";
7915
- function tomlArray(values) {
7916
- return `[${values.map((value) => `"${value}"`).join(", ")}]`;
8326
+ async function linuxStartEarliest() {
8327
+ return 1000 + Math.ceil(1000 / (await ticksPerSecond() ?? 100));
7917
8328
  }
7918
- function tomlEnv(launch) {
7919
- const pairs = Object.entries(launch.env).map(([name, value]) => `${name} = "${value}"`);
7920
- return `env = { ${pairs.join(", ")} }`;
8329
+ var ticksAnswered;
8330
+ async function ticksPerSecond() {
8331
+ if (ticksAnswered !== undefined) {
8332
+ return ticksAnswered;
8333
+ }
8334
+ try {
8335
+ const hertz = Number((await runHidden("getconf", ["CLK_TCK"], { timeout: ASK_TIMEOUT_MS })).stdout.trim());
8336
+ if (Number.isInteger(hertz) && hertz > 0) {
8337
+ ticksAnswered = hertz;
8338
+ return hertz;
8339
+ }
8340
+ } catch {}
8341
+ return null;
7921
8342
  }
7922
- function jsonSnippet(launch, container, shape) {
7923
- return JSON.stringify({ [container]: { [SERVER_KEY]: entryFor(shape, launch) } }, null, 2);
8343
+ function printedBy(command, args, env) {
8344
+ return runHidden(command, args, { timeout: ASK_TIMEOUT_MS, env }).then(({ stdout }) => stdout, (error) => {
8345
+ const printed = error.stdout;
8346
+ return typeof printed === "string" ? printed : "";
8347
+ });
7924
8348
  }
7925
- var HARNESSES = [
7926
- {
7927
- id: "claude-code",
7928
- name: "Claude Code",
7929
- scope: "project",
7930
- file: ".mcp.json",
7931
- container: "mcpServers",
7932
- shape: "plain",
7933
- home: ".claude",
7934
- marker: ".claude",
7935
- skills: { dir: join3(".claude", "skills"), shared: false }
7936
- },
7937
- {
7938
- id: "copilot-cli",
7939
- name: "Copilot CLI",
7940
- scope: "project",
7941
- file: ".mcp.json",
7942
- container: "mcpServers",
7943
- shape: "plain",
7944
- home: ".copilot",
7945
- skills: { dir: join3(".github", "skills"), shared: true },
7946
- manual: "Trust the folder when Copilot CLI first asks, or it reads no config here."
7947
- },
7948
- {
7949
- id: "qoder",
7950
- name: "Qoder",
7951
- scope: "project",
7952
- file: ".mcp.json",
7953
- container: "mcpServers",
7954
- shape: "plain",
7955
- home: ".qoder",
7956
- marker: ".qoder"
7957
- },
7958
- {
7959
- id: "command-code",
7960
- name: "Command Code",
7961
- scope: "project",
7962
- file: ".mcp.json",
7963
- container: "mcpServers",
7964
- shape: "plain",
7965
- home: ".commandcode"
7966
- },
7967
- {
7968
- id: "cursor",
7969
- name: "Cursor",
7970
- scope: "project",
7971
- file: join3(".cursor", "mcp.json"),
7972
- container: "mcpServers",
7973
- shape: "plain",
7974
- home: ".cursor",
7975
- skills: { dir: join3(".cursor", "skills"), shared: true },
7976
- manual: "Cursor asks before each tool call by default, and the server can be toggled off."
7977
- },
7978
- {
7979
- id: "vscode",
7980
- name: "VS Code",
7981
- scope: "project",
7982
- file: join3(".vscode", "mcp.json"),
7983
- container: "servers",
7984
- shape: "typed",
7985
- home: ".vscode",
7986
- skills: { dir: join3(".github", "skills"), shared: true },
7987
- manual: "VS Code asks you to trust a server the first time it starts one."
7988
- },
7989
- {
7990
- id: "opencode",
7991
- name: "opencode",
7992
- scope: "project",
7993
- file: "opencode.json",
7994
- container: "mcp",
7995
- shape: "opencode",
7996
- home: join3(".config", "opencode"),
7997
- marker: ".opencode",
7998
- skills: { dir: join3(".opencode", "skills"), shared: true }
7999
- },
8000
- {
8001
- id: "junie",
8002
- name: "Junie",
8003
- scope: "project",
8004
- file: join3(".junie", "mcp", "mcp.json"),
8005
- container: "mcpServers",
8006
- shape: "plain",
8007
- home: ".junie",
8008
- skills: { dir: join3(".junie", "skills"), shared: true }
8009
- },
8010
- {
8011
- id: "kiro",
8012
- name: "Kiro",
8013
- scope: "project",
8014
- file: join3(".kiro", "settings", "mcp.json"),
8015
- container: "mcpServers",
8016
- shape: "plain",
8017
- home: ".kiro",
8018
- skills: { dir: join3(".kiro", "skills"), shared: false }
8019
- },
8020
- {
8021
- id: "gemini",
8022
- name: "Gemini CLI",
8023
- scope: "project",
8024
- file: join3(".gemini", "settings.json"),
8025
- container: "mcpServers",
8026
- shape: "plain",
8027
- home: ".gemini",
8028
- skills: { dir: join3(".gemini", "skills"), shared: true }
8029
- },
8030
- {
8031
- id: "roo",
8032
- name: "Roo Code",
8033
- scope: "project",
8034
- file: join3(".roo", "mcp.json"),
8035
- container: "mcpServers",
8036
- shape: "plain"
8037
- },
8038
- {
8039
- id: "kilo",
8040
- name: "Kilo Code",
8041
- scope: "project",
8042
- file: join3(".kilocode", "mcp.json"),
8043
- container: "mcpServers",
8044
- shape: "plain"
8045
- },
8046
- {
8047
- id: "amazon-q",
8048
- name: "Amazon Q Developer CLI",
8049
- scope: "project",
8050
- file: join3(".amazonq", "mcp.json"),
8051
- container: "mcpServers",
8052
- shape: "plain",
8053
- home: join3(".aws", "amazonq")
8054
- },
8055
- {
8056
- id: "zed",
8057
- name: "Zed",
8058
- scope: "project",
8059
- file: join3(".zed", "settings.json"),
8060
- container: "context_servers",
8061
- shape: "plain"
8062
- },
8063
- {
8064
- id: "amp",
8065
- name: "Amp",
8066
- scope: "project",
8067
- file: join3(".amp", "settings.json"),
8068
- container: "amp.mcpServers",
8069
- shape: "plain",
8070
- home: join3(".config", "amp")
8071
- },
8072
- {
8073
- id: "warp",
8074
- name: "Warp",
8075
- scope: "project",
8076
- file: join3(".warp", ".mcp.json"),
8077
- container: "mcpServers",
8078
- shape: "plain",
8079
- home: ".warp",
8080
- manual: "Warp starts a project server only once you toggle it on, on its MCP servers page."
8081
- },
8082
- {
8083
- id: "trae",
8084
- name: "Trae",
8085
- scope: "project",
8086
- file: join3(".trae", "mcp.json"),
8087
- container: "mcpServers",
8088
- shape: "plain",
8089
- home: ".trae"
8090
- },
8091
- {
8092
- id: "factory",
8093
- name: "Factory Droid",
8094
- scope: "project",
8095
- file: join3(".factory", "mcp.json"),
8096
- container: "mcpServers",
8097
- shape: "typed",
8098
- home: ".factory"
8099
- },
8100
- {
8101
- id: "tabnine",
8102
- name: "Tabnine",
8103
- scope: "project",
8104
- file: join3(".tabnine", "mcp_servers.json"),
8105
- container: "mcpServers",
8106
- shape: "plain",
8107
- home: ".tabnine"
8108
- },
8109
- {
8110
- id: "firebender",
8111
- name: "Firebender",
8112
- scope: "project",
8113
- file: "firebender.json",
8114
- container: "mcpServers",
8115
- shape: "plain"
8116
- },
8117
- {
8118
- id: "pi",
8119
- name: "pi",
8120
- scope: "project",
8121
- file: join3(".pi", "mcp.json"),
8122
- container: "mcpServers",
8123
- shape: "plain",
8124
- home: ".pi"
8125
- },
8126
- {
8127
- id: "mistral-vibe",
8128
- name: "Mistral Vibe",
8129
- scope: "project",
8130
- file: join3(".vibe", "config.toml"),
8131
- container: "mcp_servers",
8132
- shape: "plain",
8133
- toml: {
8134
- header: "[[mcp_servers]]",
8135
- identity: `name = "${SERVER_KEY}"`,
8136
- block: (launch) => [
8137
- "[[mcp_servers]]",
8138
- `name = "${SERVER_KEY}"`,
8139
- 'transport = "stdio"',
8140
- `command = "${launch.command}"`,
8141
- `args = ${tomlArray(launch.args)}`,
8142
- tomlEnv(launch)
8143
- ].join(`
8144
- `)
8145
- }
8146
- },
8147
- {
8148
- id: "vtcode",
8149
- name: "VT Code",
8150
- scope: "project",
8151
- file: "vtcode.toml",
8152
- container: "mcp.providers",
8153
- shape: "plain",
8154
- marker: ".vtcode",
8155
- toml: {
8156
- header: "[[mcp.providers]]",
8157
- identity: `name = "${SERVER_KEY}"`,
8158
- enable: { header: "[mcp]", line: "enabled = true" },
8159
- block: (launch) => [
8160
- "[[mcp.providers]]",
8161
- `name = "${SERVER_KEY}"`,
8162
- "enabled = true",
8163
- `command = "${launch.command}"`,
8164
- `args = ${tomlArray(launch.args)}`,
8165
- tomlEnv(launch)
8166
- ].join(`
8167
- `)
8349
+ var ASK_TIMEOUT_MS = 15000;
8350
+ var ONE_SHOT_OPTIONS = [
8351
+ "--import",
8352
+ "--quit",
8353
+ "--quit-after",
8354
+ "--export-release",
8355
+ "--export-debug",
8356
+ "--export-pack",
8357
+ "--export-patch",
8358
+ "--doctool",
8359
+ "--gdscript-docs",
8360
+ "--script",
8361
+ "-s",
8362
+ "--check-only",
8363
+ "--build-solutions",
8364
+ "--dump-gdextension-interface",
8365
+ "--dump-extension-api",
8366
+ "--dump-extension-api-with-docs",
8367
+ "--validate-extension-api",
8368
+ "--convert-3to4",
8369
+ "--validate-conversion-3to4"
8370
+ ];
8371
+ function readCommandLine(command) {
8372
+ const all = commandWords(command);
8373
+ const separator = all.findIndex((word) => word === "--" || word === "++");
8374
+ const words = separator === -1 ? all : all.slice(0, separator);
8375
+ const executable = words[0] === undefined ? "" : basename3(words[0].replaceAll("\\", "/"));
8376
+ const at = words.indexOf("--path");
8377
+ let projectPath = null;
8378
+ if (at !== -1 && at + 1 < words.length) {
8379
+ const taken = [];
8380
+ for (const word of words.slice(at + 1)) {
8381
+ if (taken.length > 0 && (word.startsWith("-") || /^[a-z]+:\/\//.test(word))) {
8382
+ break;
8383
+ }
8384
+ taken.push(word);
8168
8385
  }
8169
- },
8170
- {
8171
- id: "fast-agent",
8172
- name: "fast-agent",
8173
- scope: "project",
8174
- file: "fastagent.config.yaml",
8175
- container: "mcp",
8176
- shape: "plain",
8177
- yaml: {
8178
- path: ["mcp", "servers", SERVER_KEY],
8179
- entry: (launch) => ({ command: launch.command, args: [...launch.args], env: { ...launch.env } })
8386
+ projectPath = taken.join(" ").replaceAll("%20", " ");
8387
+ }
8388
+ return {
8389
+ executable,
8390
+ projectPath,
8391
+ editor: words.some((word) => word === "-e" || word === "--editor"),
8392
+ oneShot: words.find((word) => ONE_SHOT_OPTIONS.includes(word)) ?? null
8393
+ };
8394
+ }
8395
+ function commandWords(command) {
8396
+ const words = [];
8397
+ let word = "";
8398
+ let quoted = false;
8399
+ let started = false;
8400
+ for (const char of command) {
8401
+ if (char === '"') {
8402
+ quoted = !quoted;
8403
+ started = true;
8404
+ } else if (!quoted && /\s/.test(char)) {
8405
+ if (started) {
8406
+ words.push(word);
8407
+ word = "";
8408
+ started = false;
8409
+ }
8410
+ } else {
8411
+ word += char;
8412
+ started = true;
8180
8413
  }
8181
- },
8182
- {
8183
- id: "codex",
8184
- name: "Codex CLI",
8185
- scope: "home",
8186
- file: join3(".codex", "config.toml"),
8187
- container: "mcp_servers",
8188
- shape: "plain",
8189
- manual: "Codex reads its config at startup, so restart it.",
8190
- toml: {
8191
- header: `[mcp_servers.${SERVER_KEY}]`,
8192
- block: (launch) => [
8193
- `[mcp_servers.${SERVER_KEY}]`,
8194
- `command = "${launch.command}"`,
8195
- `args = ${tomlArray(launch.args)}`,
8196
- tomlEnv(launch)
8197
- ].join(`
8198
- `)
8414
+ }
8415
+ if (started) {
8416
+ words.push(word);
8417
+ }
8418
+ return words;
8419
+ }
8420
+
8421
+ // src/engine-slots.ts
8422
+ function holderOf(content) {
8423
+ try {
8424
+ const parsed = JSON.parse(content);
8425
+ if (typeof parsed !== "object" || parsed === null) {
8426
+ return null;
8199
8427
  }
8200
- },
8201
- {
8202
- id: "cline",
8203
- name: "Cline",
8204
- scope: "home",
8205
- file: join3(".cline", "data", "settings", "cline_mcp_settings.json"),
8206
- container: "mcpServers",
8207
- shape: "plain",
8208
- marker: ".cline",
8209
- skills: { dir: join3(".cline", "skills"), shared: false }
8210
- },
8211
- {
8212
- id: "goose",
8213
- name: "Goose",
8214
- scope: "home",
8215
- file: {
8216
- win32: { appData: join3("Block", "goose", "config", "config.yaml") },
8217
- darwin: join3(".config", "goose", "config.yaml"),
8218
- linux: join3(".config", "goose", "config.yaml")
8219
- },
8220
- container: "extensions",
8221
- shape: "plain",
8222
- yaml: {
8223
- path: ["extensions", SERVER_KEY],
8224
- entry: (launch) => ({
8225
- name: SERVER_KEY,
8226
- type: "stdio",
8227
- enabled: true,
8228
- cmd: launch.command,
8229
- args: [...launch.args],
8230
- envs: { ...launch.env },
8231
- timeout: 300
8232
- })
8428
+ const { pid, started, by } = parsed;
8429
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof started !== "number") {
8430
+ return null;
8233
8431
  }
8234
- },
8235
- {
8236
- id: "windsurf",
8237
- name: "Windsurf",
8238
- scope: "home",
8239
- file: join3(".codeium", "windsurf", "mcp_config.json"),
8240
- container: "mcpServers",
8241
- shape: "plain",
8242
- skills: { dir: join3(".windsurf", "skills"), shared: true }
8243
- },
8244
- {
8245
- id: "hermes",
8246
- name: "Hermes",
8247
- scope: "home",
8248
- file: join3(".hermes", "config.yaml"),
8249
- container: "mcp_servers",
8250
- shape: "plain",
8251
- skills: { dir: join3(".hermes", "skills"), shared: true },
8252
- yaml: {
8253
- path: ["mcp_servers", SERVER_KEY],
8254
- entry: (launch) => ({
8255
- command: launch.command,
8256
- args: [...launch.args],
8257
- env: { ...launch.env },
8258
- enabled: true
8259
- })
8432
+ return typeof by === "string" && by !== "" ? { pid, started, by } : { pid, started };
8433
+ } catch {
8434
+ return null;
8435
+ }
8436
+ }
8437
+ async function ownStart() {
8438
+ const said = (await startTimesOf([process4.pid])).get(process4.pid);
8439
+ return said ?? Math.round(Date.now() - process4.uptime() * 1000);
8440
+ }
8441
+ function handSlot(lock, from, to) {
8442
+ let content;
8443
+ try {
8444
+ content = readWhole(lock);
8445
+ } catch {
8446
+ return false;
8447
+ }
8448
+ return content !== null && holderOf(content)?.pid === from && writeWhole(lock, JSON.stringify(to));
8449
+ }
8450
+ function giveBackSlot(lock, pid) {
8451
+ try {
8452
+ if (holderOf(readFileSync4(lock, "utf8"))?.pid === pid) {
8453
+ removeWhole(lock);
8260
8454
  }
8261
- },
8262
- {
8263
- id: "openclaw",
8264
- name: "OpenClaw",
8265
- scope: "home",
8266
- file: join3(".openclaw", "openclaw.json"),
8267
- container: "mcpServers",
8268
- shape: "plain"
8269
- },
8270
- {
8271
- id: "claude-desktop",
8272
- name: "Claude Desktop",
8273
- scope: "home",
8274
- file: {
8275
- win32: { appData: join3("Claude", "claude_desktop_config.json") },
8276
- darwin: join3("Library", "Application Support", "Claude", "claude_desktop_config.json"),
8277
- linux: join3(".config", "Claude", "claude_desktop_config.json")
8278
- },
8279
- container: "mcpServers",
8280
- shape: "plain"
8281
- },
8282
- {
8283
- id: "zeroclaw",
8284
- name: "ZeroClaw",
8285
- scope: "home",
8286
- file: join3(".zeroclaw", "config.toml"),
8287
- container: "mcp.servers",
8288
- shape: "plain",
8289
- toml: {
8290
- header: "[[mcp.servers]]",
8291
- identity: `name = "${SERVER_KEY}"`,
8292
- enable: { header: "[mcp]", line: "enabled = true" },
8293
- block: (launch) => [
8294
- "[[mcp.servers]]",
8295
- `name = "${SERVER_KEY}"`,
8296
- `command = "${launch.command}"`,
8297
- `args = ${tomlArray(launch.args)}`,
8298
- tomlEnv(launch)
8299
- ].join(`
8300
- `)
8455
+ } catch {}
8456
+ }
8457
+
8458
+ // src/error-mode.ts
8459
+ import process5 from "node:process";
8460
+ var NO_FAULT_ERROR_BOX = 2;
8461
+ var cleared = process5.platform !== "win32";
8462
+ async function letWindowsReportCrashes() {
8463
+ if (cleared || !("bun" in process5.versions)) {
8464
+ return;
8465
+ }
8466
+ try {
8467
+ const { dlopen, FFIType } = await import("bun:ffi");
8468
+ const kernel32 = dlopen("kernel32.dll", {
8469
+ GetErrorMode: { args: [], returns: FFIType.u32 },
8470
+ SetErrorMode: { args: [FFIType.u32], returns: FFIType.u32 }
8471
+ });
8472
+ try {
8473
+ const mode = kernel32.symbols.GetErrorMode();
8474
+ kernel32.symbols.SetErrorMode(mode & ~NO_FAULT_ERROR_BOX);
8475
+ cleared = true;
8476
+ } finally {
8477
+ kernel32.close();
8301
8478
  }
8302
- },
8303
- {
8304
- id: "deepcode",
8305
- name: "Deep Code",
8306
- scope: "home",
8307
- file: join3(".deepcode", "settings.json"),
8308
- container: "mcpServers",
8309
- shape: "plain"
8310
- },
8311
- {
8312
- id: "nanobot",
8313
- name: "nanobot",
8314
- scope: "home",
8315
- file: join3(".nanobot", "config.json"),
8316
- container: "mcpServers",
8317
- shape: "plain",
8318
- snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
8319
- },
8320
- {
8321
- id: "autohand",
8322
- name: "Autohand",
8323
- scope: "home",
8324
- file: join3(".autohand", "config.json"),
8325
- container: "mcpServers",
8326
- shape: "plain",
8327
- snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
8479
+ } catch {}
8480
+ }
8481
+ function crashesReported() {
8482
+ return cleared;
8483
+ }
8484
+
8485
+ // src/game-debugger.ts
8486
+ import { readFileSync as readFileSync6 } from "node:fs";
8487
+ import { createServer } from "node:net";
8488
+ import { join as join6 } from "node:path";
8489
+
8490
+ // src/godot-variant.ts
8491
+ var NIL = 0;
8492
+ var BOOL = 1;
8493
+ var INT = 2;
8494
+ var FLOAT = 3;
8495
+ var STRING = 4;
8496
+ var ARRAY = 28;
8497
+ var FLAG_64 = 1 << 16;
8498
+ var MATH = {
8499
+ 5: { name: "Vector2", count: 2 },
8500
+ 6: { name: "Vector2i", count: 2, ints: true },
8501
+ 7: { name: "Rect2", count: 4 },
8502
+ 8: { name: "Rect2i", count: 4, ints: true },
8503
+ 9: { name: "Vector3", count: 3 },
8504
+ 10: { name: "Vector3i", count: 3, ints: true },
8505
+ 11: { name: "Transform2D", count: 6 },
8506
+ 12: { name: "Vector4", count: 4 },
8507
+ 13: { name: "Vector4i", count: 4, ints: true },
8508
+ 14: { name: "Plane", count: 4 },
8509
+ 15: { name: "Quaternion", count: 4 },
8510
+ 16: { name: "AABB", count: 6 },
8511
+ 17: { name: "Basis", count: 9 },
8512
+ 18: { name: "Transform3D", count: 12 },
8513
+ 19: { name: "Projection", count: 16 }
8514
+ };
8515
+ var PACKED_VECTORS = { 35: 2, 36: 3, 38: 4 };
8516
+
8517
+ class Reader {
8518
+ offset = 0;
8519
+ view;
8520
+ constructor(view) {
8521
+ this.view = view;
8328
8522
  }
8329
- ];
8330
- var OURS = ["GODOT_PATH", "GDHARNESS_PROJECT"];
8331
- function environmentFor(launch, held) {
8332
- const kept = {};
8333
- if (typeof held === "object" && held !== null && !Array.isArray(held)) {
8334
- for (const [name, value] of Object.entries(held)) {
8335
- if (typeof value === "string" && !OURS.includes(name)) {
8336
- kept[name] = value;
8337
- }
8523
+ get remaining() {
8524
+ return this.view.byteLength - this.offset;
8525
+ }
8526
+ need(bytes) {
8527
+ if (bytes < 0 || bytes > this.remaining) {
8528
+ throw new RangeError(`a value runs past the end of its message (${bytes} bytes wanted, ${this.remaining} left)`);
8338
8529
  }
8339
8530
  }
8340
- return { ...kept, ...launch.env };
8531
+ u32() {
8532
+ this.need(4);
8533
+ const value = this.view.getUint32(this.offset, true);
8534
+ this.offset += 4;
8535
+ return value;
8536
+ }
8537
+ i32() {
8538
+ this.need(4);
8539
+ const value = this.view.getInt32(this.offset, true);
8540
+ this.offset += 4;
8541
+ return value;
8542
+ }
8543
+ i64() {
8544
+ this.need(8);
8545
+ const value = Number(this.view.getBigInt64(this.offset, true));
8546
+ this.offset += 8;
8547
+ return value;
8548
+ }
8549
+ u64() {
8550
+ this.need(8);
8551
+ const value = Number(this.view.getBigUint64(this.offset, true));
8552
+ this.offset += 8;
8553
+ return value;
8554
+ }
8555
+ f32() {
8556
+ this.need(4);
8557
+ const value = this.view.getFloat32(this.offset, true);
8558
+ this.offset += 4;
8559
+ return value;
8560
+ }
8561
+ f64() {
8562
+ this.need(8);
8563
+ const value = this.view.getFloat64(this.offset, true);
8564
+ this.offset += 8;
8565
+ return value;
8566
+ }
8567
+ real(wide) {
8568
+ return wide ? this.f64() : this.f32();
8569
+ }
8570
+ bytes(count) {
8571
+ this.need(count);
8572
+ const out = new Uint8Array(this.view.buffer, this.view.byteOffset + this.offset, count);
8573
+ this.offset += count;
8574
+ return out;
8575
+ }
8576
+ string() {
8577
+ const length = this.u32();
8578
+ const text = new TextDecoder().decode(this.bytes(length));
8579
+ this.bytes((4 - length % 4) % 4);
8580
+ return text;
8581
+ }
8341
8582
  }
8342
- function entryFor(shape, launch, held) {
8343
- const before = typeof held === "object" && held !== null && !Array.isArray(held) ? { ...held } : {};
8344
- if (shape === "opencode") {
8583
+ var MAX_DEPTH = 1024;
8584
+ function containerType(reader, kind) {
8585
+ if (kind === 1) {
8586
+ reader.u32();
8587
+ } else if (kind === 2 || kind === 3) {
8588
+ reader.string();
8589
+ }
8590
+ }
8591
+ function decodeValue(reader, depth) {
8592
+ if (depth > MAX_DEPTH) {
8593
+ throw new RangeError("a value nests deeper than the engine allows");
8594
+ }
8595
+ const header = reader.u32();
8596
+ const type = header & 255;
8597
+ const wide = (header & FLAG_64) !== 0;
8598
+ const math = MATH[type];
8599
+ if (math !== undefined) {
8345
8600
  return {
8346
- ...before,
8347
- type: "local",
8348
- command: [launch.command, ...launch.args],
8349
- environment: environmentFor(launch, before["environment"]),
8350
- enabled: true
8601
+ kind: math.name,
8602
+ values: Array.from({ length: math.count }, () => math.ints === true ? reader.i32() : reader.real(wide))
8351
8603
  };
8352
8604
  }
8353
- return {
8354
- ...before,
8355
- ...shape === "typed" ? { type: "stdio" } : {},
8356
- command: launch.command,
8357
- args: [...launch.args],
8358
- env: environmentFor(launch, before["env"])
8359
- };
8360
- }
8361
-
8362
- // src/engine-leaks.ts
8363
- var REFCOUNTED_HELD = "A RefCounted alive at exit is held by a cycle of references (two holding each other, or one " + "holding a lambda that captures it) or by an Object never freed, rather than by a node left out " + "of the tree; a WeakRef on one side of the cycle, or clearing the reference once done, frees it.";
8364
- var WALK_STOPPED_SENTENCE = "The engine's shutdown stopped part way through its scripts (godot#117991, fixed in 4.8 by " + "godot#120976), so it reported as leaked at exit what it never got to free, and the report is the " + "engine's rather than the run's. gdharness holds every script loaded from a file past that walk, " + "which keeps it whole, so this one stopped on a script it could not hold, such as one made in code. " + "A leak of the run's own is not told apart in such a run.";
8365
- var NAME2 = "[\\p{L}_][\\p{L}\\p{N}_]*";
8366
- var EXPORTED = new RegExp(`@export(?!_(?:group|subgroup|category)\\b)\\w*(?:\\([^)]*\\))?\\s+(?:@${NAME2}(?:\\([^)]*\\))?\\s+)*` + `(?:static\\s+)?var\\s+(${NAME2})\\s*:\\s*(?:Array|Dictionary)\\s*\\[([^\\]]*)\\]`, "gu");
8367
-
8368
- // src/junit.ts
8369
- var ESCAPE = String.fromCharCode(27);
8370
- var LOCATION = `'[^'\\n]*' in \\S+:\\d+`;
8371
- var IGNORING_CASE = " \\(ignoring case\\)";
8372
- var PRINTED_ACTUAL = new RegExp(` but was\\n '((?:(?!\\tat ${LOCATION})[\\s\\S])*?)'((?:${ESCAPE}\\[[0-9;]*m)*)(${IGNORING_CASE})?((?:${ESCAPE}\\[[0-9;]*m)*)\\tat (${LOCATION})`, "g");
8373
- var QUOTED_EQUALITY = new RegExp(`^Expecting(?: error message)?:\\n '([\\s\\S]*)'\\n but was\\n '([\\s\\S]*)'(?:${IGNORING_CASE})?\\n\\tat `);
8374
- var COLOUR = new RegExp(`${ESCAPE}\\[([0-9;]*)m`, "g");
8375
- var HOOKS_LEFT = new Map([
8376
- ["before", "before()"],
8377
- ["after", "after()"],
8378
- ["before or after", "before() or after()"]
8379
- ]);
8380
-
8381
- // src/suite-judge.ts
8382
- var TIME = String.raw`(?:\d+h )?(?:\d+min )?(?:\d+s )?\d+ms`;
8383
- var CASE_LINE = new RegExp(String.raw`^\s*(res://.+?\.gd) > (.+?) (STARTED|PASSED|FAILED|FLAKY|SKIPPED|WARNING)(?: \((?:retry \d+|\d+ retries)\))?(?: (${TIME}))?\s*$`);
8384
- var STATISTICS = new RegExp(String.raw`^Statistics:.*\|\s*([A-Z]+)(?:\s+\(.*?\))?\s+(${TIME})\s*$`);
8385
- var WINDOWS_EXITS = new Map([
8386
- [3221225477, "STATUS_ACCESS_VIOLATION"],
8387
- [3221225495, "STATUS_NO_MEMORY"],
8388
- [3221225773, "STATUS_COMMITMENT_LIMIT"],
8389
- [3221225794, "STATUS_DLL_INIT_FAILED"],
8390
- [3221226505, "STATUS_STACK_BUFFER_OVERRUN"],
8391
- [3228369022, "a module that could not be found (VcppException)"],
8392
- [3228369023, "a procedure that could not be found (VcppException)"]
8393
- ]);
8394
- var MEMORY_EXITS = new Set([3221225495, 3221225773]);
8395
- var GDUNIT_FAILED = 100;
8396
- var GDUNIT_ORPHANS = 101;
8397
- var GDUNIT_EXITS = new Map([
8398
- [GDUNIT_FAILED, "gdUnit4's code for a case that failed or errored"],
8399
- [GDUNIT_ORPHANS, "gdUnit4's code for orphan nodes left behind"],
8400
- [103, "gdUnit4's code for a suite that cannot run headless"],
8401
- [104, "gdUnit4's code for a Godot version it does not support"],
8402
- [105, "gdUnit4's code for scripts that did not compile"]
8403
- ]);
8404
- var GODOT_EXITS = new Set([1, 255]);
8405
-
8406
- // src/windows-ask.ts
8407
- var SCRIPT = [
8408
- "[Console]::OutputEncoding = [Text.Encoding]::UTF8",
8409
- "$in = [Console]::In",
8410
- "while ($null -ne ($line = $in.ReadLine())) {",
8411
- ' $parts = $line.Split(" ", 2)',
8412
- " try {",
8413
- " $asked = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($parts[1]))",
8414
- " $said = (& ([ScriptBlock]::Create($asked)) | Out-String -Width 1000000)",
8415
- ' $tag = "OK"',
8416
- " } catch {",
8417
- " $said = $_.Exception.Message",
8418
- ' $tag = "ERR"',
8419
- " }",
8420
- ' [Console]::Out.Write($parts[0] + " " + $tag + " " + [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($said)) + "`n")',
8421
- " [Console]::Out.Flush()",
8422
- "}"
8423
- ].join(`
8424
- `);
8425
-
8426
- // src/engine-launch.ts
8427
- var CONTROL_SEQUENCE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[A-Za-z]`, "g");
8428
- var MEMORY_KEPT = 4 * 1024 ** 3;
8429
- var MEMORY_PER_ENGINE = 1.5 * 1024 ** 3;
8430
-
8431
- // src/process-children.ts
8432
- import { readFileSync as readFileSync3 } from "node:fs";
8433
- import { basename as basename3 } from "node:path";
8434
- async function linuxStartTimes(pids) {
8435
- const began = new Map;
8436
- const hertz = await ticksPerSecond();
8437
- let booted;
8438
- try {
8439
- booted = Number(/^btime\s+(\d+)$/m.exec(readFileSync3("/proc/stat", "utf8"))?.[1] ?? Number.NaN) * 1000;
8440
- } catch {
8441
- return began;
8605
+ const vectorWidth = PACKED_VECTORS[type];
8606
+ if (vectorWidth !== undefined) {
8607
+ const count = reader.u32();
8608
+ return Array.from({ length: count }, () => ({
8609
+ kind: "Vector",
8610
+ values: Array.from({ length: vectorWidth }, () => reader.real(wide))
8611
+ }));
8612
+ }
8613
+ switch (type) {
8614
+ case NIL:
8615
+ return null;
8616
+ case BOOL:
8617
+ return reader.u32() !== 0;
8618
+ case INT:
8619
+ return wide ? reader.i64() : reader.i32();
8620
+ case FLOAT:
8621
+ return wide ? reader.f64() : reader.f32();
8622
+ case STRING:
8623
+ case 21:
8624
+ return reader.string();
8625
+ case 20:
8626
+ return { kind: "Color", values: [reader.f32(), reader.f32(), reader.f32(), reader.f32()] };
8627
+ case 22: {
8628
+ const first = reader.u32();
8629
+ if ((first & 2147483648) === 0) {
8630
+ throw new RangeError("a node path in the format before 3.0");
8631
+ }
8632
+ const names = first & 2147483647;
8633
+ let subnames = reader.u32();
8634
+ const flags = reader.u32();
8635
+ if ((flags & 2) !== 0) {
8636
+ subnames += 1;
8637
+ }
8638
+ return { kind: "NodePath", values: Array.from({ length: names + subnames }, () => reader.string()) };
8639
+ }
8640
+ case 23:
8641
+ return { kind: "RID", values: [reader.u64()] };
8642
+ case 24:
8643
+ if ((header & FLAG_64) === 0) {
8644
+ throw new RangeError("a full object, which this reader does not take");
8645
+ }
8646
+ return { kind: "Object", values: [reader.u64()] };
8647
+ case 25:
8648
+ return { kind: "Callable", values: [] };
8649
+ case 26:
8650
+ return { kind: "Signal", values: [reader.string(), reader.u64()] };
8651
+ case 27: {
8652
+ containerType(reader, header >> 16 & 3);
8653
+ containerType(reader, header >> 18 & 3);
8654
+ const count = reader.u32() & 2147483647;
8655
+ const entries = [];
8656
+ for (let index = 0;index < count; index += 1) {
8657
+ const key = decodeValue(reader, depth + 1);
8658
+ entries.push([key, decodeValue(reader, depth + 1)]);
8659
+ }
8660
+ return { kind: "dictionary", entries };
8661
+ }
8662
+ case ARRAY: {
8663
+ containerType(reader, header >> 16 & 3);
8664
+ const count = reader.u32() & 2147483647;
8665
+ return Array.from({ length: count }, () => decodeValue(reader, depth + 1));
8666
+ }
8667
+ case 29: {
8668
+ const count = reader.u32();
8669
+ const bytes = [...reader.bytes(count)];
8670
+ reader.bytes((4 - count % 4) % 4);
8671
+ return bytes;
8672
+ }
8673
+ case 30:
8674
+ return Array.from({ length: reader.u32() }, () => reader.i32());
8675
+ case 31:
8676
+ return Array.from({ length: reader.u32() }, () => reader.i64());
8677
+ case 32:
8678
+ return Array.from({ length: reader.u32() }, () => reader.f32());
8679
+ case 33:
8680
+ return Array.from({ length: reader.u32() }, () => reader.f64());
8681
+ case 34:
8682
+ return Array.from({ length: reader.u32() }, () => reader.string().replace(/\0$/, ""));
8683
+ case 37:
8684
+ return Array.from({ length: reader.u32() }, () => ({
8685
+ kind: "Color",
8686
+ values: [reader.f32(), reader.f32(), reader.f32(), reader.f32()]
8687
+ }));
8688
+ default:
8689
+ throw new RangeError(`a value of type ${type}, which Godot 4.7 does not have`);
8442
8690
  }
8443
- if (hertz === null || Number.isNaN(booted)) {
8444
- return began;
8691
+ }
8692
+ function decodeVariant(bytes) {
8693
+ const reader = new Reader(new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength));
8694
+ const value = decodeValue(reader, 0);
8695
+ if (reader.remaining !== 0) {
8696
+ throw new RangeError(`${reader.remaining} bytes left over after the value`);
8445
8697
  }
8446
- for (const pid of pids) {
8447
- let stat;
8448
- try {
8449
- stat = readFileSync3(`/proc/${String(pid)}/stat`, "utf8");
8450
- } catch {
8451
- continue;
8698
+ return value;
8699
+ }
8700
+ function pushU32(out, value) {
8701
+ out.push(value & 255, value >>> 8 & 255, value >>> 16 & 255, value >>> 24 & 255);
8702
+ }
8703
+ function encodeInto(out, value) {
8704
+ if (value === null) {
8705
+ pushU32(out, NIL);
8706
+ } else if (typeof value === "boolean") {
8707
+ pushU32(out, BOOL);
8708
+ pushU32(out, value ? 1 : 0);
8709
+ } else if (typeof value === "number") {
8710
+ const view = new DataView(new ArrayBuffer(8));
8711
+ if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {
8712
+ pushU32(out, INT);
8713
+ view.setInt32(0, value, true);
8714
+ out.push(...new Uint8Array(view.buffer, 0, 4));
8715
+ } else if (Number.isInteger(value)) {
8716
+ pushU32(out, INT | FLAG_64);
8717
+ view.setBigInt64(0, BigInt(value), true);
8718
+ out.push(...new Uint8Array(view.buffer));
8719
+ } else {
8720
+ pushU32(out, FLOAT | FLAG_64);
8721
+ view.setFloat64(0, value, true);
8722
+ out.push(...new Uint8Array(view.buffer));
8452
8723
  }
8453
- const ticks = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[19]);
8454
- if (Number.isInteger(ticks) && ticks >= 0) {
8455
- began.set(pid, booted + Math.round(ticks * 1000 / hertz));
8724
+ } else if (typeof value === "string") {
8725
+ const bytes = new TextEncoder().encode(value);
8726
+ pushU32(out, STRING);
8727
+ pushU32(out, bytes.length);
8728
+ out.push(...bytes, ...Array.from({ length: (4 - bytes.length % 4) % 4 }, () => 0));
8729
+ } else {
8730
+ pushU32(out, ARRAY);
8731
+ pushU32(out, value.length);
8732
+ for (const element of value) {
8733
+ encodeInto(out, element);
8456
8734
  }
8457
8735
  }
8458
- return began;
8459
8736
  }
8460
- async function linuxStartEarliest() {
8461
- return 1000 + Math.ceil(1000 / (await ticksPerSecond() ?? 100));
8737
+ function encodeVariant(value) {
8738
+ const out = [];
8739
+ encodeInto(out, value);
8740
+ return Uint8Array.from(out);
8462
8741
  }
8463
- var ticksAnswered;
8464
- async function ticksPerSecond() {
8465
- if (ticksAnswered !== undefined) {
8466
- return ticksAnswered;
8467
- }
8468
- try {
8469
- const hertz = Number((await runHidden("getconf", ["CLK_TCK"], { timeout: ASK_TIMEOUT_MS })).stdout.trim());
8470
- if (Number.isInteger(hertz) && hertz > 0) {
8471
- ticksAnswered = hertz;
8472
- return hertz;
8473
- }
8474
- } catch {}
8475
- return null;
8742
+ var MAIN_THREAD = 1;
8743
+ function framedCommand(message, data, thread = MAIN_THREAD) {
8744
+ const body = encodeVariant([message, thread, data]);
8745
+ const framed = new Uint8Array(body.length + 4);
8746
+ new DataView(framed.buffer).setUint32(0, body.length, true);
8747
+ framed.set(body, 4);
8748
+ return framed;
8476
8749
  }
8477
- var ASK_TIMEOUT_MS = 15000;
8478
- var ONE_SHOT_OPTIONS = [
8479
- "--import",
8480
- "--quit",
8481
- "--quit-after",
8482
- "--export-release",
8483
- "--export-debug",
8484
- "--export-pack",
8485
- "--export-patch",
8486
- "--doctool",
8487
- "--gdscript-docs",
8488
- "--script",
8489
- "-s",
8490
- "--check-only",
8491
- "--build-solutions",
8492
- "--dump-gdextension-interface",
8493
- "--dump-extension-api",
8494
- "--dump-extension-api-with-docs",
8495
- "--validate-extension-api",
8496
- "--convert-3to4",
8497
- "--validate-conversion-3to4"
8498
- ];
8499
- function readCommandLine(command) {
8500
- const all = commandWords(command);
8501
- const separator = all.findIndex((word) => word === "--" || word === "++");
8502
- const words = separator === -1 ? all : all.slice(0, separator);
8503
- const executable = words[0] === undefined ? "" : basename3(words[0].replaceAll("\\", "/"));
8504
- const at = words.indexOf("--path");
8505
- let projectPath = null;
8506
- if (at !== -1 && at + 1 < words.length) {
8507
- const taken = [];
8508
- for (const word of words.slice(at + 1)) {
8509
- if (taken.length > 0 && (word.startsWith("-") || /^[a-z]+:\/\//.test(word))) {
8750
+ var MOST_MESSAGE_BYTES = (8 << 20) + 4;
8751
+
8752
+ class DebuggerStream {
8753
+ pending = new Uint8Array(0);
8754
+ push(chunk) {
8755
+ const joined = new Uint8Array(this.pending.length + chunk.length);
8756
+ joined.set(this.pending, 0);
8757
+ joined.set(chunk, this.pending.length);
8758
+ const out = [];
8759
+ let at = 0;
8760
+ while (joined.length - at >= 4) {
8761
+ const length = new DataView(joined.buffer, joined.byteOffset + at, 4).getUint32(0, true);
8762
+ if (length > MOST_MESSAGE_BYTES) {
8763
+ throw new RangeError(`a message of ${length} bytes, more than the engine sends`);
8764
+ }
8765
+ if (joined.length - at - 4 < length) {
8510
8766
  break;
8511
8767
  }
8512
- taken.push(word);
8768
+ out.push(readMessage(joined.subarray(at + 4, at + 4 + length)));
8769
+ at += 4 + length;
8513
8770
  }
8514
- projectPath = taken.join(" ").replaceAll("%20", " ");
8771
+ this.pending = joined.slice(at);
8772
+ return out;
8515
8773
  }
8516
- return {
8517
- executable,
8518
- projectPath,
8519
- editor: words.some((word) => word === "-e" || word === "--editor"),
8520
- oneShot: words.find((word) => ONE_SHOT_OPTIONS.includes(word)) ?? null
8521
- };
8522
8774
  }
8523
- function commandWords(command) {
8524
- const words = [];
8525
- let word = "";
8526
- let quoted = false;
8527
- let started = false;
8528
- for (const char of command) {
8529
- if (char === '"') {
8530
- quoted = !quoted;
8531
- started = true;
8532
- } else if (!quoted && /\s/.test(char)) {
8533
- if (started) {
8534
- words.push(word);
8535
- word = "";
8536
- started = false;
8537
- }
8538
- } else {
8539
- word += char;
8540
- started = true;
8541
- }
8775
+ function readMessage(body) {
8776
+ let value;
8777
+ try {
8778
+ value = decodeVariant(body);
8779
+ } catch (error) {
8780
+ return { unreadable: error instanceof Error ? error.message : String(error) };
8542
8781
  }
8543
- if (started) {
8544
- words.push(word);
8782
+ if (!Array.isArray(value) || value.length !== 3) {
8783
+ return { unreadable: "a message that is not [message, thread, data]" };
8545
8784
  }
8546
- return words;
8785
+ const [message, thread, data] = value;
8786
+ if (typeof message !== "string" || typeof thread !== "number" || !Array.isArray(data)) {
8787
+ return { unreadable: "a message whose name, thread or data is the wrong type" };
8788
+ }
8789
+ return { message, thread, data };
8790
+ }
8791
+
8792
+ // src/setup.ts
8793
+ import { dirname as dirname3, join as join5 } from "node:path";
8794
+ import { fileURLToPath } from "node:url";
8795
+
8796
+ // src/dictionary.ts
8797
+ function emptyRecord() {
8798
+ return Object.create(null);
8547
8799
  }
8548
8800
 
8549
8801
  // src/game-log.ts
@@ -8653,16 +8905,16 @@ var IMPORTABLE = new Set(IMPORTABLE_EXTENSIONS);
8653
8905
  var hashes = new Map;
8654
8906
 
8655
8907
  // src/scratch.ts
8656
- import { existsSync as existsSync2, mkdtempSync as mkdtempSync2, readdirSync, rmSync as rmSync3 } from "node:fs";
8657
- import { tmpdir as tmpdir2 } from "node:os";
8908
+ import { existsSync as existsSync2, mkdtempSync as mkdtempSync2, readdirSync, rmSync as rmSync4 } from "node:fs";
8909
+ import { tmpdir as tmpdir3 } from "node:os";
8658
8910
  import { join as join4 } from "node:path";
8659
- import process4 from "node:process";
8911
+ import process6 from "node:process";
8660
8912
  var SWEPT = { recursive: true, force: true };
8661
8913
  var AGAIN_AFTER_MS = [250, 500, 1000, 2000, 4000, 8000, 16000];
8662
8914
  var waiting = new Set;
8663
8915
  var atExit = new Set;
8664
8916
  function scratchDirectory(kind) {
8665
- return mkdtempSync2(join4(tmpdir2(), `gdharness-${kind}-${process4.pid}-`));
8917
+ return mkdtempSync2(join4(tmpdir3(), `gdharness-${kind}-${process6.pid}-`));
8666
8918
  }
8667
8919
  function discardWith(remove, paths) {
8668
8920
  const left = [];
@@ -8686,7 +8938,7 @@ function discard(...paths) {
8686
8938
  return left;
8687
8939
  }
8688
8940
  function remove(path) {
8689
- rmSync3(path, SWEPT);
8941
+ rmSync4(path, SWEPT);
8690
8942
  }
8691
8943
  function tryAgain(path, attempt) {
8692
8944
  if (attempt === 0) {
@@ -8720,7 +8972,7 @@ function lastTryOnExit() {
8720
8972
  return;
8721
8973
  }
8722
8974
  lastTryWatched = true;
8723
- process4.once("exit", () => {
8975
+ process6.once("exit", () => {
8724
8976
  for (const path of [...waiting, ...atExit]) {
8725
8977
  try {
8726
8978
  remove(path);
@@ -8847,7 +9099,7 @@ function parseIniLikeValue(value) {
8847
9099
  }
8848
9100
 
8849
9101
  // src/server-version.ts
8850
- import { readFileSync as readFileSync4 } from "node:fs";
9102
+ import { readFileSync as readFileSync5 } from "node:fs";
8851
9103
 
8852
9104
  // src/update-check.ts
8853
9105
  var CACHE_MS = 10 * 60 * 1000;
@@ -8858,7 +9110,7 @@ var MAX_RETRY_MS = 60 * 60 * 1000;
8858
9110
  var DEBUG_MODE = process.env["GDHARNESS_DEBUG"] === "1";
8859
9111
  var SERVER_VERSION = (() => {
8860
9112
  try {
8861
- const pkg = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8"));
9113
+ const pkg = JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf8"));
8862
9114
  return typeof pkg.version === "string" ? pkg.version : "0.0.0";
8863
9115
  } catch {
8864
9116
  return "0.0.0";
@@ -8884,7 +9136,7 @@ var RUNTIME_AUTOLOAD2 = `${RUNTIME_ADDON}runtime_autoload.gd`;
8884
9136
  var frameEnd = null;
8885
9137
  function frameEndLine() {
8886
9138
  if (frameEnd === null) {
8887
- const lines = readFileSync5(join6(shippedAddonsDirectory(), "gdharness_runtime", "runtime_autoload.gd"), "utf8").split(`
9139
+ const lines = readFileSync6(join6(shippedAddonsDirectory(), "gdharness_runtime", "runtime_autoload.gd"), "utf8").split(`
8888
9140
  `);
8889
9141
  const declared = lines.findIndex((line) => line.startsWith("func _notification("));
8890
9142
  if (declared === -1) {
@@ -9008,6 +9260,7 @@ class GameDebugger {
9008
9260
  onClosed = [];
9009
9261
  output = [];
9010
9262
  outputDropped = 0;
9263
+ expressionErrors = [];
9011
9264
  queue = Promise.resolve();
9012
9265
  server;
9013
9266
  port;
@@ -9132,6 +9385,14 @@ class GameDebugger {
9132
9385
  this.outputDropped += over;
9133
9386
  }
9134
9387
  }
9388
+ } else if (received.message === "error") {
9389
+ const [, , , , file, , , error, described] = received.data;
9390
+ if (file === "core/math/expression.cpp" && this.expressionErrors.length < 10) {
9391
+ const why = typeof described === "string" && described !== "" ? described : error;
9392
+ if (typeof why === "string") {
9393
+ this.expressionErrors.push(why);
9394
+ }
9395
+ }
9135
9396
  }
9136
9397
  const at = this.waiters.findIndex((waiter) => waiter.wanted(received));
9137
9398
  if (at !== -1) {
@@ -9478,6 +9739,7 @@ class GameDebugger {
9478
9739
  };
9479
9740
  }
9480
9741
  this.forget("evaluation_return");
9742
+ this.expressionErrors.length = 0;
9481
9743
  this.send("evaluate", [expression, frame], held.thread);
9482
9744
  const answered = await this.next(GameDebugger.named("evaluation_return"), EVALUATE_MS);
9483
9745
  if (answered === null || !("data" in answered)) {
@@ -9486,16 +9748,24 @@ class GameDebugger {
9486
9748
  };
9487
9749
  }
9488
9750
  const [, , type, value, hint] = answered.data;
9489
- return {
9751
+ const answer = {
9490
9752
  held: this.heldState(),
9491
9753
  frame,
9492
9754
  expression,
9493
9755
  value: shownValue(value ?? null, typeof hint === "string" ? hint : ""),
9494
- type: typeNamed(type, hint),
9495
- ...value === null || value === undefined ? {
9496
- note: "null is also what an expression comes to when it does not parse or fails as it runs. The game prints why as an error, which editor_output reads, since its debugger hands errors over apart from the console debug_state output keeps."
9497
- } : {}
9756
+ type: typeNamed(type, hint)
9498
9757
  };
9758
+ if (value !== null && value !== undefined) {
9759
+ return answer;
9760
+ }
9761
+ if (!await this.taken()) {
9762
+ return {
9763
+ ...answer,
9764
+ note: "null is also what an expression comes to when it does not parse or fails as it runs, and the game did not answer the question asked after it to say whether this one failed. editor_output has any error it printed."
9765
+ };
9766
+ }
9767
+ const why = this.expressionErrors.join(" ");
9768
+ return why === "" ? answer : { ...answer, failed: why };
9499
9769
  }
9500
9770
  async taken() {
9501
9771
  this.forget("scene:inspect_object");
@@ -9518,11 +9788,11 @@ class GameDebugger {
9518
9788
 
9519
9789
  // src/keeper-channel.ts
9520
9790
  import { randomUUID } from "node:crypto";
9521
- import { mkdtempSync as mkdtempSync3, rmSync as rmSync4 } from "node:fs";
9791
+ import { mkdtempSync as mkdtempSync3, rmSync as rmSync5 } from "node:fs";
9522
9792
  import { connect, createServer as createServer2 } from "node:net";
9523
- import { tmpdir as tmpdir3 } from "node:os";
9793
+ import { tmpdir as tmpdir4 } from "node:os";
9524
9794
  import { join as join7 } from "node:path";
9525
- import process5 from "node:process";
9795
+ import process7 from "node:process";
9526
9796
  var DEBUG_PREFIX = "debug ";
9527
9797
  function endedOrWhyNot(end) {
9528
9798
  try {
@@ -9549,7 +9819,7 @@ function errorText(error) {
9549
9819
  async function listenForTheServer(end, debug) {
9550
9820
  let directory = null;
9551
9821
  try {
9552
- directory = process5.platform === "win32" ? null : mkdtempSync3(join7(tmpdir3(), "gdharness-keeper-"));
9822
+ directory = process7.platform === "win32" ? null : mkdtempSync3(join7(tmpdir4(), "gdharness-keeper-"));
9553
9823
  const address = directory === null ? `\\\\.\\pipe\\gdharness-keeper-${randomUUID()}` : join7(directory, "keeper.sock");
9554
9824
  const server = createServer2((socket) => {
9555
9825
  socket.setEncoding("utf8");
@@ -9586,13 +9856,13 @@ async function listenForTheServer(end, debug) {
9586
9856
  close: () => {
9587
9857
  server.close();
9588
9858
  if (made !== null) {
9589
- rmSync4(made, { recursive: true, force: true });
9859
+ rmSync5(made, { recursive: true, force: true });
9590
9860
  }
9591
9861
  }
9592
9862
  };
9593
9863
  } catch {
9594
9864
  if (directory !== null) {
9595
- rmSync4(directory, { recursive: true, force: true });
9865
+ rmSync5(directory, { recursive: true, force: true });
9596
9866
  }
9597
9867
  return null;
9598
9868
  }
@@ -9643,11 +9913,11 @@ function readLaunched(printed) {
9643
9913
 
9644
9914
  // src/run-record.ts
9645
9915
  import { createHash as createHash2 } from "node:crypto";
9646
- import { mkdirSync, openSync as openSync2, readdirSync as readdirSync2, readFileSync as readFileSync6, rmSync as rmSync5, statSync as statSync3 } from "node:fs";
9916
+ import { mkdirSync as mkdirSync2, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync7, rmSync as rmSync6, statSync as statSync4 } from "node:fs";
9647
9917
  import { basename as basename4, join as join9, resolve as resolve4 } from "node:path";
9648
9918
 
9649
9919
  // src/runtime-client.ts
9650
- import { tmpdir as tmpdir4 } from "node:os";
9920
+ import { tmpdir as tmpdir5 } from "node:os";
9651
9921
  import { dirname as dirname4, join as join8, resolve as resolve3 } from "node:path";
9652
9922
 
9653
9923
  // src/launch.ts
@@ -9693,7 +9963,7 @@ function runtimeDirectory(variables = process.env) {
9693
9963
  return explicit;
9694
9964
  }
9695
9965
  const perUser = envValue("XDG_RUNTIME_DIR", variables);
9696
- return join8(perUser ?? tmpdir4(), "gdharness");
9966
+ return join8(perUser ?? tmpdir5(), "gdharness");
9697
9967
  }
9698
9968
  var ERROR_REPORT_KEEP_MS = 60 * 60 * 1000;
9699
9969
  var verdicts = new Map;
@@ -9714,7 +9984,7 @@ function runRecordPath(projectPath, directory = runtimeDirectory()) {
9714
9984
  return join9(directory, "runs", `note-${projectKey(projectPath)}.json`);
9715
9985
  }
9716
9986
  function writeRunRecord(record) {
9717
- mkdirSync(runsDirectory(), { recursive: true });
9987
+ mkdirSync2(runsDirectory(), { recursive: true });
9718
9988
  const path = runRecordPath(record.projectPath);
9719
9989
  if (!writeWhole(path, JSON.stringify(record, null, 2))) {
9720
9990
  throw new Error(`the run note could not be written at ${path}`);
@@ -9739,7 +10009,7 @@ function recordRunEnded(projectPath, pid, ending) {
9739
10009
  function recordAt(path) {
9740
10010
  let parsed;
9741
10011
  try {
9742
- parsed = JSON.parse(readFileSync6(path, "utf8"));
10012
+ parsed = JSON.parse(readFileSync7(path, "utf8"));
9743
10013
  } catch {
9744
10014
  return null;
9745
10015
  }
@@ -10178,7 +10448,7 @@ async function startThroughHelper(spec, output, stopFile) {
10178
10448
  step: stepFile
10179
10449
  });
10180
10450
  const envChanges = spec.desktop === undefined ? spec.envChanges : { ...spec.envChanges, [DESKTOP_VARIABLE]: spec.desktop };
10181
- const started = await startDirectly({ ...spec, command: wrapper.command, args: wrapper.args, envChanges }, output, true, false, "ignore", tmpdir5());
10451
+ const started = await startDirectly({ ...spec, command: wrapper.command, args: wrapper.args, envChanges }, output, true, false, "ignore", tmpdir6());
10182
10452
  if ("error" in started) {
10183
10453
  return started;
10184
10454
  }
@@ -10187,7 +10457,7 @@ async function startThroughHelper(spec, output, stopFile) {
10187
10457
  exited.now = true;
10188
10458
  });
10189
10459
  for (let waited = 0;waited < DESKTOP_START_MS; waited += 50) {
10190
- const pid = existsSync3(pidFile) ? Number(readFileSync7(pidFile, "utf8").trim()) : Number.NaN;
10460
+ const pid = existsSync3(pidFile) ? Number(readFileSync8(pidFile, "utf8").trim()) : Number.NaN;
10191
10461
  if (Number.isInteger(pid) && pid > 0) {
10192
10462
  return { child: started.child, pid };
10193
10463
  }
@@ -10218,7 +10488,7 @@ function profiledBy(path, projectPath) {
10218
10488
  };
10219
10489
  let projectGodot = null;
10220
10490
  try {
10221
- projectGodot = readFileSync7(join10(projectPath, "project.godot"), "utf8");
10491
+ projectGodot = readFileSync8(join10(projectPath, "project.godot"), "utf8");
10222
10492
  } catch {}
10223
10493
  const observer = new ProfileObserver((totals) => {
10224
10494
  const first = latest === null;
@@ -10319,19 +10589,20 @@ async function keep() {
10319
10589
  }
10320
10590
  const profiled = run?.profile === undefined ? null : profiledBy(run.profile, run.projectPath);
10321
10591
  const debuggerPeer = run === undefined || run.debugged === false ? null : await GameDebugger.open(run.breakpoints ?? [], profiled === null ? [] : [profiled.observer]);
10322
- const exitNotes = run === undefined ? null : mkdtempSync4(join10(tmpdir5(), "gdharness-exit-"));
10592
+ const exitNotes = run === undefined ? null : mkdtempSync4(join10(tmpdir6(), "gdharness-exit-"));
10323
10593
  const noted = exitNotes === null ? spec : { ...spec, envChanges: { ...spec.envChanges, [EXIT_NOTES_VARIABLE]: exitNotes } };
10324
10594
  const toStart = debuggerPeer === null ? noted : { ...noted, args: withEngineArguments(noted.args, debuggerPeer.engineArguments) };
10325
- const transcript = run === undefined ? "ignore" : openSync3(run.transcript, "a");
10326
- const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(join10(tmpdir5(), "gdharness-stop-")) : null;
10595
+ const transcript = run === undefined ? "ignore" : openSync4(run.transcript, "a");
10596
+ const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(join10(tmpdir6(), "gdharness-stop-")) : null;
10327
10597
  const stopFile = own === null ? "" : join10(own, "stop");
10328
10598
  let started;
10599
+ const keeperStarted = run?.slot === undefined ? undefined : ownStart();
10329
10600
  const spawnedAt = Date.now();
10330
10601
  try {
10331
10602
  started = await startDetached(toStart, transcript, run === undefined, stopFile);
10332
10603
  } finally {
10333
10604
  if (transcript !== "ignore") {
10334
- closeSync2(transcript);
10605
+ closeSync3(transcript);
10335
10606
  }
10336
10607
  }
10337
10608
  if ("error" in started) {
@@ -10382,6 +10653,14 @@ async function keep() {
10382
10653
  process.stdout.end(`pid ${pid}
10383
10654
  `, resolve);
10384
10655
  });
10656
+ const slot = run?.slot;
10657
+ if (slot !== undefined && keeperStarted !== undefined) {
10658
+ handSlot(slot.lock, slot.from, {
10659
+ pid: process.pid,
10660
+ started: await keeperStarted,
10661
+ by: `${slot.by}, through the keeper process that runs it`
10662
+ });
10663
+ }
10385
10664
  let { code, signal } = await exited;
10386
10665
  let exitedAt = Date.now();
10387
10666
  let note = record === null ? null : listening === null ? record : { ...record, keeper: listening.address };
@@ -10442,11 +10721,14 @@ async function keep() {
10442
10721
  notTold
10443
10722
  });
10444
10723
  }
10724
+ if (slot !== undefined) {
10725
+ giveBackSlot(slot.lock, process.pid);
10726
+ }
10445
10727
  debuggerPeer?.close();
10446
10728
  listening?.close();
10447
10729
  for (const made of [own, exitNotes]) {
10448
10730
  if (made !== null) {
10449
- rmSync6(made, { recursive: true, force: true });
10731
+ rmSync7(made, { recursive: true, force: true });
10450
10732
  }
10451
10733
  }
10452
10734
  process.exit(0);
@@ -10457,7 +10739,7 @@ function restartSaid(notes, pid) {
10457
10739
  return null;
10458
10740
  }
10459
10741
  try {
10460
- const said = JSON.parse(readFileSync7(join10(notes, `exit-${String(pid)}.json`), "utf8"));
10742
+ const said = JSON.parse(readFileSync8(join10(notes, `exit-${String(pid)}.json`), "utf8"));
10461
10743
  return typeof said === "object" && said !== null && "restart" in said && typeof said.restart === "boolean" ? said.restart : null;
10462
10744
  } catch {
10463
10745
  return null;