gdharness 0.12.13 → 0.12.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.js +43 -10
- package/build/index.js +10 -2
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -15759,7 +15759,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
15759
15759
|
},
|
|
15760
15760
|
{
|
|
15761
15761
|
name: "editor_status",
|
|
15762
|
-
description:
|
|
15762
|
+
description: 'Whether the editor addon is connected, which Godot answers, whether the editor is playing something, and whether a game with the runtime addon is reachable. When connected is false, mayYetConnect says whether that is final: the editor dials this server rather than the other way round and backs off between tries, so for the first half-minute after a server starts, false means "not reached yet" as often as it means "no editor". True is worth waiting out; false is an editor that is not there.',
|
|
15763
15763
|
parameters: {},
|
|
15764
15764
|
requires: []
|
|
15765
15765
|
},
|
|
@@ -34405,17 +34405,21 @@ function resolveDefaultBridgeHost() {
|
|
|
34405
34405
|
function servedPort(said) {
|
|
34406
34406
|
return typeof said === "number" && Number.isInteger(said) && said > 0 && said <= 65535 ? said : undefined;
|
|
34407
34407
|
}
|
|
34408
|
+
function mayYetConnect(listeningSince, now = Date.now()) {
|
|
34409
|
+
return listeningSince === undefined || now - listeningSince < CONNECT_WINDOW_MS;
|
|
34410
|
+
}
|
|
34408
34411
|
function getDefaultBridge(ownProject = null) {
|
|
34409
34412
|
defaultBridge ??= new GodotBridge(resolveDefaultBridgePort(), resolveDefaultBridgeHost(), DEFAULT_TIMEOUT_MS, ownProject);
|
|
34410
34413
|
return defaultBridge;
|
|
34411
34414
|
}
|
|
34412
|
-
var DEFAULT_PORT = 6505, DEFAULT_HOST = "127.0.0.1", DEFAULT_TIMEOUT_MS = 30000, KEEPALIVE_INTERVAL_MS = 1e4, SECOND_CONNECTION_CLOSE_CODE = 4000, OTHER_PROJECT_CLOSE_CODE = 4001, GodotBridge, defaultBridge = null;
|
|
34415
|
+
var DEFAULT_PORT = 6505, DEFAULT_HOST = "127.0.0.1", DEFAULT_TIMEOUT_MS = 30000, KEEPALIVE_INTERVAL_MS = 1e4, SECOND_CONNECTION_CLOSE_CODE = 4000, OTHER_PROJECT_CLOSE_CODE = 4001, CONNECT_WINDOW_MS = 35000, GodotBridge, defaultBridge = null;
|
|
34413
34416
|
var init_godot_bridge = __esm(() => {
|
|
34414
34417
|
init_wrapper();
|
|
34415
34418
|
init_errors();
|
|
34416
34419
|
init_paths();
|
|
34417
34420
|
init_ports();
|
|
34418
34421
|
GodotBridge = class GodotBridge extends EventEmitter {
|
|
34422
|
+
listeningSince = null;
|
|
34419
34423
|
httpServer = null;
|
|
34420
34424
|
godotWss = null;
|
|
34421
34425
|
socket = null;
|
|
@@ -34478,6 +34482,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
34478
34482
|
});
|
|
34479
34483
|
server.once("listening", () => {
|
|
34480
34484
|
settled = true;
|
|
34485
|
+
this.listeningSince = Date.now();
|
|
34481
34486
|
this.httpServer = server;
|
|
34482
34487
|
this.godotWss = godotWss;
|
|
34483
34488
|
const bound = server.address();
|
|
@@ -34554,7 +34559,8 @@ var init_godot_bridge = __esm(() => {
|
|
|
34554
34559
|
debugPort: this.connectionInfo?.debugPort,
|
|
34555
34560
|
openedByAServer: this.connectionInfo?.openedByAServer,
|
|
34556
34561
|
pendingRequests: this.pendingRequests.size,
|
|
34557
|
-
queuedResources: this.resourceQueues.size
|
|
34562
|
+
queuedResources: this.resourceQueues.size,
|
|
34563
|
+
listeningSince: this.listeningSince ?? undefined
|
|
34558
34564
|
};
|
|
34559
34565
|
}
|
|
34560
34566
|
invokeTool(toolName, args) {
|
|
@@ -37609,6 +37615,7 @@ class GodotServer {
|
|
|
37609
37615
|
serverVersion: SERVER_VERSION,
|
|
37610
37616
|
addonIsStale: status.connected ? stale : undefined,
|
|
37611
37617
|
bridgeAvailable: this.bridgeStartupError === null,
|
|
37618
|
+
mayYetConnect: status.connected ? undefined : mayYetConnect(status.listeningSince),
|
|
37612
37619
|
startupError: this.bridgeStartupError,
|
|
37613
37620
|
staleNote: stale ? addonMismatch(status.addonVersion, SERVER_VERSION) : undefined,
|
|
37614
37621
|
retryingBridge: this.bridgeRetry === null ? undefined : true,
|
|
@@ -39268,6 +39275,32 @@ function registered(harness, projectPath) {
|
|
|
39268
39275
|
const held = existing[harness.container];
|
|
39269
39276
|
return typeof held === "object" && held !== null && !Array.isArray(held) && SERVER_KEY in held;
|
|
39270
39277
|
}
|
|
39278
|
+
function recordedEnginePath(projectPath) {
|
|
39279
|
+
for (const harness of HARNESSES) {
|
|
39280
|
+
if (harness.scope !== "project" || harness.toml || harness.yaml || harness.snippet) {
|
|
39281
|
+
continue;
|
|
39282
|
+
}
|
|
39283
|
+
const path = configPath(harness, projectPath);
|
|
39284
|
+
if (!existsSync4(path)) {
|
|
39285
|
+
continue;
|
|
39286
|
+
}
|
|
39287
|
+
let parsed;
|
|
39288
|
+
try {
|
|
39289
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
39290
|
+
} catch {
|
|
39291
|
+
continue;
|
|
39292
|
+
}
|
|
39293
|
+
const entry = reach(reach(parsed, harness.container), SERVER_KEY);
|
|
39294
|
+
const named = reach(reach(entry, harness.shape === "opencode" ? "environment" : "env"), "GODOT_PATH");
|
|
39295
|
+
if (typeof named === "string" && named !== "" && existsSync4(named)) {
|
|
39296
|
+
return named;
|
|
39297
|
+
}
|
|
39298
|
+
}
|
|
39299
|
+
return null;
|
|
39300
|
+
}
|
|
39301
|
+
function reach(held, key) {
|
|
39302
|
+
return typeof held === "object" && held !== null && !Array.isArray(held) ? held[key] : undefined;
|
|
39303
|
+
}
|
|
39271
39304
|
function disconnect(harness, projectPath) {
|
|
39272
39305
|
const path = configPath(harness, projectPath);
|
|
39273
39306
|
if (!existsSync4(path)) {
|
|
@@ -40057,8 +40090,8 @@ function projectArgument(at) {
|
|
|
40057
40090
|
}
|
|
40058
40091
|
return projectPath;
|
|
40059
40092
|
}
|
|
40060
|
-
async function engine() {
|
|
40061
|
-
const godotPath = await new GodotLocator().find();
|
|
40093
|
+
async function engine(projectPath) {
|
|
40094
|
+
const godotPath = await new GodotLocator().find() ?? (projectPath === undefined ? null : recordedEnginePath(projectPath));
|
|
40062
40095
|
if (godotPath === null) {
|
|
40063
40096
|
throw new UsageError(`No Godot executable found. ${GodotLocator.ADVICE.join(". ")}.`);
|
|
40064
40097
|
}
|
|
@@ -40181,7 +40214,7 @@ export, so turn it off before you ship: gdharness runtime off${where}`);
|
|
|
40181
40214
|
async function setup() {
|
|
40182
40215
|
const projectPath = projectArgument(1);
|
|
40183
40216
|
const runtime = !args.includes("--no-runtime");
|
|
40184
|
-
const godot = await engine();
|
|
40217
|
+
const godot = await engine(projectPath);
|
|
40185
40218
|
for (const addon of installAddons(projectPath)) {
|
|
40186
40219
|
console.log(`${addon.replaced ? "replaced" : "installed"} ${addon.path}`);
|
|
40187
40220
|
}
|
|
@@ -40231,7 +40264,7 @@ async function setup() {
|
|
|
40231
40264
|
}
|
|
40232
40265
|
async function uninstall() {
|
|
40233
40266
|
const projectPath = projectArgument(1);
|
|
40234
|
-
const godot = await engine();
|
|
40267
|
+
const godot = await engine(projectPath);
|
|
40235
40268
|
const named = namedHarnesses();
|
|
40236
40269
|
const from = named.length > 0 ? named : HARNESSES;
|
|
40237
40270
|
for (const harness of from) {
|
|
@@ -40282,8 +40315,8 @@ async function upgrade() {
|
|
|
40282
40315
|
const where = projectPath === process.cwd() ? "" : ` ${projectPath}`;
|
|
40283
40316
|
throw new UsageError(`gdharness is not installed in ${projectPath}. Run gdharness setup${where} instead.`);
|
|
40284
40317
|
}
|
|
40318
|
+
const godot = await engine(projectPath);
|
|
40285
40319
|
console.log(installed === version ? `already ${version}; reinstalling` : `${installed} -> ${version}`);
|
|
40286
|
-
const godot = await engine();
|
|
40287
40320
|
for (const addon of installAddons(projectPath)) {
|
|
40288
40321
|
console.log(`${addon.replaced ? "replaced" : "installed"} ${addon.path}`);
|
|
40289
40322
|
}
|
|
@@ -40341,7 +40374,7 @@ async function runtime3() {
|
|
|
40341
40374
|
throw new UsageError("gdharness runtime takes on or off, then the project directory.");
|
|
40342
40375
|
}
|
|
40343
40376
|
const projectPath = projectArgument(2);
|
|
40344
|
-
const godot = await engine();
|
|
40377
|
+
const godot = await engine(projectPath);
|
|
40345
40378
|
if (state === "on") {
|
|
40346
40379
|
await registerRuntime(godot, projectPath);
|
|
40347
40380
|
return;
|
|
@@ -40363,7 +40396,7 @@ async function runtime3() {
|
|
|
40363
40396
|
}
|
|
40364
40397
|
async function classes() {
|
|
40365
40398
|
const projectPath = projectArgument(1);
|
|
40366
|
-
const godot = await engine();
|
|
40399
|
+
const godot = await engine(projectPath);
|
|
40367
40400
|
const outcome = await runOperation(godot, "refresh_class_cache", {}, projectPath);
|
|
40368
40401
|
said2(outcome, "rebuilding the class list");
|
|
40369
40402
|
if (outcome.ok) {
|
package/build/index.js
CHANGED
|
@@ -25611,8 +25611,13 @@ function resolveDefaultBridgeHost() {
|
|
|
25611
25611
|
function servedPort(said) {
|
|
25612
25612
|
return typeof said === "number" && Number.isInteger(said) && said > 0 && said <= 65535 ? said : undefined;
|
|
25613
25613
|
}
|
|
25614
|
+
var CONNECT_WINDOW_MS = 35000;
|
|
25615
|
+
function mayYetConnect(listeningSince, now = Date.now()) {
|
|
25616
|
+
return listeningSince === undefined || now - listeningSince < CONNECT_WINDOW_MS;
|
|
25617
|
+
}
|
|
25614
25618
|
|
|
25615
25619
|
class GodotBridge extends EventEmitter {
|
|
25620
|
+
listeningSince = null;
|
|
25616
25621
|
httpServer = null;
|
|
25617
25622
|
godotWss = null;
|
|
25618
25623
|
socket = null;
|
|
@@ -25675,6 +25680,7 @@ class GodotBridge extends EventEmitter {
|
|
|
25675
25680
|
});
|
|
25676
25681
|
server.once("listening", () => {
|
|
25677
25682
|
settled = true;
|
|
25683
|
+
this.listeningSince = Date.now();
|
|
25678
25684
|
this.httpServer = server;
|
|
25679
25685
|
this.godotWss = godotWss;
|
|
25680
25686
|
const bound = server.address();
|
|
@@ -25751,7 +25757,8 @@ class GodotBridge extends EventEmitter {
|
|
|
25751
25757
|
debugPort: this.connectionInfo?.debugPort,
|
|
25752
25758
|
openedByAServer: this.connectionInfo?.openedByAServer,
|
|
25753
25759
|
pendingRequests: this.pendingRequests.size,
|
|
25754
|
-
queuedResources: this.resourceQueues.size
|
|
25760
|
+
queuedResources: this.resourceQueues.size,
|
|
25761
|
+
listeningSince: this.listeningSince ?? undefined
|
|
25755
25762
|
};
|
|
25756
25763
|
}
|
|
25757
25764
|
invokeTool(toolName, args) {
|
|
@@ -28655,7 +28662,7 @@ var TOOL_SPECS = [
|
|
|
28655
28662
|
},
|
|
28656
28663
|
{
|
|
28657
28664
|
name: "editor_status",
|
|
28658
|
-
description:
|
|
28665
|
+
description: 'Whether the editor addon is connected, which Godot answers, whether the editor is playing something, and whether a game with the runtime addon is reachable. When connected is false, mayYetConnect says whether that is final: the editor dials this server rather than the other way round and backs off between tries, so for the first half-minute after a server starts, false means "not reached yet" as often as it means "no editor". True is worth waiting out; false is an editor that is not there.',
|
|
28659
28666
|
parameters: {},
|
|
28660
28667
|
requires: []
|
|
28661
28668
|
},
|
|
@@ -30391,6 +30398,7 @@ class GodotServer {
|
|
|
30391
30398
|
serverVersion: SERVER_VERSION,
|
|
30392
30399
|
addonIsStale: status.connected ? stale : undefined,
|
|
30393
30400
|
bridgeAvailable: this.bridgeStartupError === null,
|
|
30401
|
+
mayYetConnect: status.connected ? undefined : mayYetConnect(status.listeningSince),
|
|
30394
30402
|
startupError: this.bridgeStartupError,
|
|
30395
30403
|
staleNote: stale ? addonMismatch(status.addonVersion, SERVER_VERSION) : undefined,
|
|
30396
30404
|
retryingBridge: this.bridgeRetry === null ? undefined : true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.14",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|