gdharness 1.0.30 → 1.0.32
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
|
@@ -6,10 +6,28 @@ import { closeSync, openSync as openSync2 } from "node:fs";
|
|
|
6
6
|
|
|
7
7
|
// src/outside.ts
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
function withChanges(base, changes) {
|
|
10
|
+
const env = { ...base };
|
|
11
|
+
for (const [name, value] of Object.entries(changes)) {
|
|
12
|
+
if (value === null) {
|
|
13
|
+
delete env[name];
|
|
14
|
+
} else {
|
|
15
|
+
env[name] = value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return env;
|
|
19
|
+
}
|
|
20
|
+
function sendSpec(child, spec) {
|
|
21
|
+
child.stdin?.end(JSON.stringify(spec), "utf8");
|
|
22
|
+
}
|
|
23
|
+
async function receivedSpec() {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
for await (const chunk of process.stdin) {
|
|
26
|
+
chunks.push(chunk);
|
|
27
|
+
}
|
|
28
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
12
29
|
}
|
|
30
|
+
var KEEPER_SCRIPT = fileURLToPath(new URL("./keeper.js", import.meta.url));
|
|
13
31
|
function readLaunched(printed) {
|
|
14
32
|
const line = printed.split(`
|
|
15
33
|
`).find((one) => one.trim() !== "")?.trim() ?? "";
|
|
@@ -21,8 +39,18 @@ function readLaunched(printed) {
|
|
|
21
39
|
}
|
|
22
40
|
|
|
23
41
|
// src/run-record.ts
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
42
|
+
import { createHash } from "node:crypto";
|
|
43
|
+
import {
|
|
44
|
+
mkdirSync,
|
|
45
|
+
openSync,
|
|
46
|
+
readdirSync,
|
|
47
|
+
readFileSync,
|
|
48
|
+
realpathSync,
|
|
49
|
+
rmSync,
|
|
50
|
+
statSync,
|
|
51
|
+
writeFileSync
|
|
52
|
+
} from "node:fs";
|
|
53
|
+
import { basename, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
26
54
|
|
|
27
55
|
// src/process-children.ts
|
|
28
56
|
import { execFile, execFileSync, spawnSync } from "node:child_process";
|
|
@@ -57,15 +85,36 @@ var lateAnswers = new Map;
|
|
|
57
85
|
function runsDirectory() {
|
|
58
86
|
return join2(runtimeDirectory(), "runs");
|
|
59
87
|
}
|
|
60
|
-
function
|
|
61
|
-
|
|
88
|
+
function realAsFarAsItExists(path) {
|
|
89
|
+
const missing = [];
|
|
90
|
+
let at = path;
|
|
91
|
+
for (;; ) {
|
|
92
|
+
try {
|
|
93
|
+
return join2(realpathSync.native(at), ...missing);
|
|
94
|
+
} catch {
|
|
95
|
+
const parent = dirname2(at);
|
|
96
|
+
if (parent === at) {
|
|
97
|
+
return path;
|
|
98
|
+
}
|
|
99
|
+
missing.unshift(basename(at));
|
|
100
|
+
at = parent;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function projectKey(projectPath) {
|
|
105
|
+
const real = realAsFarAsItExists(resolve2(projectPath)).replace(/[\\/]+$/, "");
|
|
106
|
+
const folded = process.platform === "win32" || process.platform === "darwin" ? real.toLowerCase() : real;
|
|
107
|
+
return createHash("sha256").update(folded.replaceAll("\\", "/")).digest("hex").slice(0, 16);
|
|
108
|
+
}
|
|
109
|
+
function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
110
|
+
return join2(directory, "runs", `note-${projectKey(projectPath)}.json`);
|
|
62
111
|
}
|
|
63
112
|
function writeRunRecord(record) {
|
|
64
113
|
mkdirSync(runsDirectory(), { recursive: true });
|
|
65
|
-
writeFileSync(
|
|
114
|
+
writeFileSync(runRecordPath(record.projectPath), JSON.stringify(record, null, 2), "utf8");
|
|
66
115
|
}
|
|
67
|
-
function recordRunEnded(pid, ending) {
|
|
68
|
-
const path =
|
|
116
|
+
function recordRunEnded(projectPath, pid, ending) {
|
|
117
|
+
const path = runRecordPath(projectPath);
|
|
69
118
|
const record = recordAt(path);
|
|
70
119
|
if (record === null || record.pid !== pid) {
|
|
71
120
|
return;
|
|
@@ -115,7 +164,7 @@ async function startDetached(spec, output) {
|
|
|
115
164
|
const child = spawn(spec.command, [...spec.args], {
|
|
116
165
|
stdio: ["ignore", output, output],
|
|
117
166
|
detached: true,
|
|
118
|
-
|
|
167
|
+
env: withChanges(process.env, spec.envChanges)
|
|
119
168
|
});
|
|
120
169
|
child.once("error", (error) => {
|
|
121
170
|
resolve({ error: error.message });
|
|
@@ -125,8 +174,8 @@ async function startDetached(spec, output) {
|
|
|
125
174
|
});
|
|
126
175
|
});
|
|
127
176
|
}
|
|
128
|
-
async function launch(
|
|
129
|
-
const spec =
|
|
177
|
+
async function launch() {
|
|
178
|
+
const spec = await receivedSpec();
|
|
130
179
|
if (spec.run === undefined) {
|
|
131
180
|
const started = await startDetached(spec, "ignore");
|
|
132
181
|
if ("error" in started) {
|
|
@@ -139,8 +188,8 @@ async function launch(encoded) {
|
|
|
139
188
|
}
|
|
140
189
|
process.exit(0);
|
|
141
190
|
}
|
|
142
|
-
const keeper = spawn(process.execPath, [KEEPER_SCRIPT, "keep"
|
|
143
|
-
stdio: ["
|
|
191
|
+
const keeper = spawn(process.execPath, [KEEPER_SCRIPT, "keep"], {
|
|
192
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
144
193
|
detached: true,
|
|
145
194
|
windowsHide: true
|
|
146
195
|
});
|
|
@@ -151,6 +200,7 @@ async function launch(encoded) {
|
|
|
151
200
|
`);
|
|
152
201
|
process.exit(0);
|
|
153
202
|
});
|
|
203
|
+
sendSpec(keeper, spec);
|
|
154
204
|
keeper.stderr.on("data", (chunk) => {
|
|
155
205
|
complained += chunk.toString();
|
|
156
206
|
});
|
|
@@ -173,8 +223,8 @@ async function launch(encoded) {
|
|
|
173
223
|
process.exit(0);
|
|
174
224
|
});
|
|
175
225
|
}
|
|
176
|
-
async function keep(
|
|
177
|
-
const spec =
|
|
226
|
+
async function keep() {
|
|
227
|
+
const spec = await receivedSpec();
|
|
178
228
|
if (spec.run === undefined) {
|
|
179
229
|
process.stdout.write(`error a keeper was started without a run
|
|
180
230
|
`);
|
|
@@ -203,20 +253,20 @@ async function keep(encoded) {
|
|
|
203
253
|
command: spec.command
|
|
204
254
|
});
|
|
205
255
|
child.once("exit", (code, signal) => {
|
|
206
|
-
recordRunEnded(pid, { exitCode: code, exitSignal: code === null ? signal : null });
|
|
256
|
+
recordRunEnded(run.projectPath, pid, { exitCode: code, exitSignal: code === null ? signal : null });
|
|
207
257
|
process.exit(0);
|
|
208
258
|
});
|
|
209
259
|
process.stdout.write(`pid ${pid}
|
|
210
260
|
`);
|
|
211
261
|
process.stdout.end();
|
|
212
262
|
}
|
|
213
|
-
var
|
|
214
|
-
if (mode === "launch"
|
|
215
|
-
await launch(
|
|
216
|
-
} else if (mode === "keep"
|
|
217
|
-
await keep(
|
|
263
|
+
var mode = process.argv[2];
|
|
264
|
+
if (mode === "launch") {
|
|
265
|
+
await launch();
|
|
266
|
+
} else if (mode === "keep") {
|
|
267
|
+
await keep();
|
|
218
268
|
} else {
|
|
219
|
-
process.stderr.write(`keeper.js launch|keep
|
|
269
|
+
process.stderr.write(`keeper.js launch|keep, with the spec on stdin
|
|
220
270
|
`);
|
|
221
271
|
process.exit(2);
|
|
222
272
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.32",
|
|
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",
|