gdharness 0.9.3 → 0.9.4
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 +33 -11
- package/build/index.js +14 -10
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -15668,7 +15668,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
15668
15668
|
},
|
|
15669
15669
|
{
|
|
15670
15670
|
name: "editor_run",
|
|
15671
|
-
description: "The run: starting the project, stopping it, or booting it once to see whether it comes up clean. start keeps it running and collecting output until
|
|
15671
|
+
description: "The run: starting the project, stopping it, or booting it once to see whether it comes up clean. start keeps it running and collecting output until it quits or is stopped, windowed where there is a display and headless where there is not, unless headless says otherwise; only runtime_capture needs the window. A run that quits on its own is kept, so a scene that prints an answer and quits is start, then editor_output until running is false. check boots it headless for a few frames, waits for it to quit, and answers with the verdict: whether it came up, and every error and warning it printed on the way.",
|
|
15672
15672
|
parameters: {
|
|
15673
15673
|
projectPath: PROJECT_PATH,
|
|
15674
15674
|
scene: { type: "string", description: "A scene to run instead of the main scene." },
|
|
@@ -15681,7 +15681,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
15681
15681
|
},
|
|
15682
15682
|
requires: ["projectPath"],
|
|
15683
15683
|
operations: {
|
|
15684
|
-
start: { summary: "run the project until
|
|
15684
|
+
start: { summary: "run the project until it quits or is stopped", requires: [] },
|
|
15685
15685
|
stop: { summary: "end the run and answer with what it printed last", requires: [] },
|
|
15686
15686
|
check: { summary: "boot headless, quit after a few frames, and report the verdict", requires: [] }
|
|
15687
15687
|
},
|
|
@@ -15689,7 +15689,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
15689
15689
|
},
|
|
15690
15690
|
{
|
|
15691
15691
|
name: "editor_output",
|
|
15692
|
-
description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries.",
|
|
15692
|
+
description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries. A run that has quit still answers here, with running false and its exit code, until the next one starts.",
|
|
15693
15693
|
parameters: {
|
|
15694
15694
|
severity: {
|
|
15695
15695
|
type: "string",
|
|
@@ -36708,6 +36708,15 @@ class GodotServer {
|
|
|
36708
36708
|
}
|
|
36709
36709
|
async debuggedGame() {
|
|
36710
36710
|
const game = this.activeProcess;
|
|
36711
|
+
if (game !== null && game.exitCode !== null) {
|
|
36712
|
+
return {
|
|
36713
|
+
ok: false,
|
|
36714
|
+
response: this.createErrorResponse(`The last run has already finished (exit code ${game.exitCode}), so there is no debug session to answer for.`, [
|
|
36715
|
+
"editor_output still reads what it printed, until the next run starts",
|
|
36716
|
+
"editor_run start plays another, which the debugger can hold"
|
|
36717
|
+
])
|
|
36718
|
+
};
|
|
36719
|
+
}
|
|
36711
36720
|
if (game === null) {
|
|
36712
36721
|
return {
|
|
36713
36722
|
ok: false,
|
|
@@ -37200,7 +37209,7 @@ class GodotServer {
|
|
|
37200
37209
|
version: godotPath === null ? null : await this.godotVersion(godotPath)
|
|
37201
37210
|
},
|
|
37202
37211
|
game: {
|
|
37203
|
-
processActive: this.activeProcess
|
|
37212
|
+
processActive: this.activeProcess?.exitCode === null,
|
|
37204
37213
|
playingInEditor: playing,
|
|
37205
37214
|
runtimeConnected: games.some((game) => game.reachable),
|
|
37206
37215
|
runtimes: games
|
|
@@ -37364,7 +37373,7 @@ class GodotServer {
|
|
|
37364
37373
|
if (op === "check") {
|
|
37365
37374
|
return await this.checkBoot(engine.value, project.value.path, sceneArgument, args);
|
|
37366
37375
|
}
|
|
37367
|
-
if (this.activeProcess) {
|
|
37376
|
+
if (this.activeProcess?.exitCode === null) {
|
|
37368
37377
|
this.logDebug("Ending the running game before starting another");
|
|
37369
37378
|
await this.endActiveGame();
|
|
37370
37379
|
}
|
|
@@ -37383,11 +37392,6 @@ class GodotServer {
|
|
|
37383
37392
|
this.logDebug(`Running Godot project: ${engine.value} ${cmdArgs.join(" ")}`);
|
|
37384
37393
|
const started = this.spawnGame(engine.value, cmdArgs);
|
|
37385
37394
|
this.activeProcess = started;
|
|
37386
|
-
started.process.on("exit", () => {
|
|
37387
|
-
if (this.activeProcess === started) {
|
|
37388
|
-
this.activeProcess = null;
|
|
37389
|
-
}
|
|
37390
|
-
});
|
|
37391
37395
|
return this.jsonTextResponse({
|
|
37392
37396
|
started: true,
|
|
37393
37397
|
through: "gdharness",
|
|
@@ -38603,6 +38607,17 @@ function disconnect(harness, projectPath) {
|
|
|
38603
38607
|
`, "utf8");
|
|
38604
38608
|
return { harness, path, action: "removed" };
|
|
38605
38609
|
}
|
|
38610
|
+
function launchedBy(entry) {
|
|
38611
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
38612
|
+
return;
|
|
38613
|
+
}
|
|
38614
|
+
const held = entry;
|
|
38615
|
+
const whole = held["command"];
|
|
38616
|
+
const args = Array.isArray(held["args"]) ? held["args"] : [];
|
|
38617
|
+
const parts = Array.isArray(whole) ? whole : [whole, ...args];
|
|
38618
|
+
const said = parts.filter((part) => typeof part === "string");
|
|
38619
|
+
return said.length === 0 ? undefined : said.join(" ");
|
|
38620
|
+
}
|
|
38606
38621
|
function connect(harness, projectPath, launch) {
|
|
38607
38622
|
const path = configPath(harness, projectPath);
|
|
38608
38623
|
if (harness.snippet !== undefined) {
|
|
@@ -38627,8 +38642,11 @@ function connect(harness, projectPath, launch) {
|
|
|
38627
38642
|
}
|
|
38628
38643
|
const container = typeof existing === "object" && existing !== null && !Array.isArray(existing) ? existing[harness.container] : undefined;
|
|
38629
38644
|
const already = typeof container === "object" && container !== null && SERVER_KEY in container;
|
|
38630
|
-
|
|
38645
|
+
const written = put(harness, path, `${JSON.stringify(merged(existing, harness, launch), null, 2)}
|
|
38631
38646
|
`, already);
|
|
38647
|
+
const was = launchedBy(container?.[SERVER_KEY]);
|
|
38648
|
+
const now = launchedBy(entryFor(harness.shape, launch));
|
|
38649
|
+
return was === undefined || was === now ? written : { ...written, wasLaunchedBy: was };
|
|
38632
38650
|
}
|
|
38633
38651
|
function put(harness, path, contents, already) {
|
|
38634
38652
|
mkdirSync(dirname2(path), { recursive: true });
|
|
@@ -39315,6 +39333,10 @@ function reportConnection(group, launch, projectPath) {
|
|
|
39315
39333
|
return;
|
|
39316
39334
|
}
|
|
39317
39335
|
console.log(`${who}: ${written.action} ${written.path}`);
|
|
39336
|
+
if (written.wasLaunchedBy !== undefined) {
|
|
39337
|
+
console.log(` it was launched by ${written.wasLaunchedBy}`);
|
|
39338
|
+
console.log(` now by ${[launch.command, ...launch.args].join(" ")}`);
|
|
39339
|
+
}
|
|
39318
39340
|
for (const harness of group.harnesses) {
|
|
39319
39341
|
if (harness.manual !== undefined) {
|
|
39320
39342
|
console.log(` ${harness.name}: ${harness.manual}`);
|
package/build/index.js
CHANGED
|
@@ -28262,7 +28262,7 @@ var TOOL_SPECS = [
|
|
|
28262
28262
|
},
|
|
28263
28263
|
{
|
|
28264
28264
|
name: "editor_run",
|
|
28265
|
-
description: "The run: starting the project, stopping it, or booting it once to see whether it comes up clean. start keeps it running and collecting output until
|
|
28265
|
+
description: "The run: starting the project, stopping it, or booting it once to see whether it comes up clean. start keeps it running and collecting output until it quits or is stopped, windowed where there is a display and headless where there is not, unless headless says otherwise; only runtime_capture needs the window. A run that quits on its own is kept, so a scene that prints an answer and quits is start, then editor_output until running is false. check boots it headless for a few frames, waits for it to quit, and answers with the verdict: whether it came up, and every error and warning it printed on the way.",
|
|
28266
28266
|
parameters: {
|
|
28267
28267
|
projectPath: PROJECT_PATH,
|
|
28268
28268
|
scene: { type: "string", description: "A scene to run instead of the main scene." },
|
|
@@ -28275,7 +28275,7 @@ var TOOL_SPECS = [
|
|
|
28275
28275
|
},
|
|
28276
28276
|
requires: ["projectPath"],
|
|
28277
28277
|
operations: {
|
|
28278
|
-
start: { summary: "run the project until
|
|
28278
|
+
start: { summary: "run the project until it quits or is stopped", requires: [] },
|
|
28279
28279
|
stop: { summary: "end the run and answer with what it printed last", requires: [] },
|
|
28280
28280
|
check: { summary: "boot headless, quit after a few frames, and report the verdict", requires: [] }
|
|
28281
28281
|
},
|
|
@@ -28283,7 +28283,7 @@ var TOOL_SPECS = [
|
|
|
28283
28283
|
},
|
|
28284
28284
|
{
|
|
28285
28285
|
name: "editor_output",
|
|
28286
|
-
description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries.",
|
|
28286
|
+
description: "What the project started by editor_run has printed, as entries with a severity: the errors and warnings the engine reported, each with where it happened, and everything else as info. Answers with the counts and the verdict as well as the entries. A run that has quit still answers here, with running false and its exit code, until the next one starts.",
|
|
28287
28287
|
parameters: {
|
|
28288
28288
|
severity: {
|
|
28289
28289
|
type: "string",
|
|
@@ -29488,6 +29488,15 @@ class GodotServer {
|
|
|
29488
29488
|
}
|
|
29489
29489
|
async debuggedGame() {
|
|
29490
29490
|
const game = this.activeProcess;
|
|
29491
|
+
if (game !== null && game.exitCode !== null) {
|
|
29492
|
+
return {
|
|
29493
|
+
ok: false,
|
|
29494
|
+
response: this.createErrorResponse(`The last run has already finished (exit code ${game.exitCode}), so there is no debug session to answer for.`, [
|
|
29495
|
+
"editor_output still reads what it printed, until the next run starts",
|
|
29496
|
+
"editor_run start plays another, which the debugger can hold"
|
|
29497
|
+
])
|
|
29498
|
+
};
|
|
29499
|
+
}
|
|
29491
29500
|
if (game === null) {
|
|
29492
29501
|
return {
|
|
29493
29502
|
ok: false,
|
|
@@ -29980,7 +29989,7 @@ class GodotServer {
|
|
|
29980
29989
|
version: godotPath === null ? null : await this.godotVersion(godotPath)
|
|
29981
29990
|
},
|
|
29982
29991
|
game: {
|
|
29983
|
-
processActive: this.activeProcess
|
|
29992
|
+
processActive: this.activeProcess?.exitCode === null,
|
|
29984
29993
|
playingInEditor: playing,
|
|
29985
29994
|
runtimeConnected: games.some((game) => game.reachable),
|
|
29986
29995
|
runtimes: games
|
|
@@ -30144,7 +30153,7 @@ class GodotServer {
|
|
|
30144
30153
|
if (op === "check") {
|
|
30145
30154
|
return await this.checkBoot(engine.value, project.value.path, sceneArgument, args);
|
|
30146
30155
|
}
|
|
30147
|
-
if (this.activeProcess) {
|
|
30156
|
+
if (this.activeProcess?.exitCode === null) {
|
|
30148
30157
|
this.logDebug("Ending the running game before starting another");
|
|
30149
30158
|
await this.endActiveGame();
|
|
30150
30159
|
}
|
|
@@ -30163,11 +30172,6 @@ class GodotServer {
|
|
|
30163
30172
|
this.logDebug(`Running Godot project: ${engine.value} ${cmdArgs.join(" ")}`);
|
|
30164
30173
|
const started = this.spawnGame(engine.value, cmdArgs);
|
|
30165
30174
|
this.activeProcess = started;
|
|
30166
|
-
started.process.on("exit", () => {
|
|
30167
|
-
if (this.activeProcess === started) {
|
|
30168
|
-
this.activeProcess = null;
|
|
30169
|
-
}
|
|
30170
|
-
});
|
|
30171
30175
|
return this.jsonTextResponse({
|
|
30172
30176
|
started: true,
|
|
30173
30177
|
through: "gdharness",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
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",
|