gdharness 0.5.0 → 0.5.1
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 +282 -246
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +9 -1
- package/build/index.js +260 -224
- package/package.json +1 -1
package/build/cli.js
CHANGED
|
@@ -7228,15 +7228,196 @@ var init_game_log = __esm(() => {
|
|
|
7228
7228
|
COLOUR_CODE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
7229
7229
|
});
|
|
7230
7230
|
|
|
7231
|
+
// src/update-check.ts
|
|
7232
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
7233
|
+
import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
|
|
7234
|
+
import { join as join4 } from "node:path";
|
|
7235
|
+
function cacheDirectory(environment) {
|
|
7236
|
+
const set = (name) => {
|
|
7237
|
+
const value = environment[name];
|
|
7238
|
+
return value !== undefined && value !== "" ? value : null;
|
|
7239
|
+
};
|
|
7240
|
+
const home = set("HOME") ?? homedir3();
|
|
7241
|
+
if (process.platform === "win32") {
|
|
7242
|
+
return join4(set("LOCALAPPDATA") ?? home, "gdharness");
|
|
7243
|
+
}
|
|
7244
|
+
if (process.platform === "darwin") {
|
|
7245
|
+
return join4(home, "Library", "Caches", "gdharness");
|
|
7246
|
+
}
|
|
7247
|
+
return join4(set("XDG_CACHE_HOME") ?? join4(home, ".cache"), "gdharness");
|
|
7248
|
+
}
|
|
7249
|
+
function cacheFile(environment = process.env) {
|
|
7250
|
+
try {
|
|
7251
|
+
const directory = cacheDirectory(environment);
|
|
7252
|
+
mkdirSync2(directory, { recursive: true, mode: 448 });
|
|
7253
|
+
return join4(directory, "update-check.json");
|
|
7254
|
+
} catch {
|
|
7255
|
+
return join4(tmpdir2(), "gdharness-update-check.json");
|
|
7256
|
+
}
|
|
7257
|
+
}
|
|
7258
|
+
function readCache(path) {
|
|
7259
|
+
try {
|
|
7260
|
+
if (!existsSync4(path)) {
|
|
7261
|
+
return null;
|
|
7262
|
+
}
|
|
7263
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
7264
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
7265
|
+
return null;
|
|
7266
|
+
}
|
|
7267
|
+
const record = parsed;
|
|
7268
|
+
const checkedAt = record["checkedAt"];
|
|
7269
|
+
const latest = record["latest"];
|
|
7270
|
+
if (typeof checkedAt !== "number" || typeof latest !== "string" || !VERSION.test(latest)) {
|
|
7271
|
+
return null;
|
|
7272
|
+
}
|
|
7273
|
+
return { checkedAt, latest };
|
|
7274
|
+
} catch {
|
|
7275
|
+
return null;
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
function writeCache(path, entry) {
|
|
7279
|
+
try {
|
|
7280
|
+
writeFileSync3(path, JSON.stringify(entry), { encoding: "utf8", mode: 384 });
|
|
7281
|
+
} catch {}
|
|
7282
|
+
}
|
|
7283
|
+
function parts(version) {
|
|
7284
|
+
const withoutBuild = version.split("+")[0] ?? version;
|
|
7285
|
+
const dash = withoutBuild.indexOf("-");
|
|
7286
|
+
const numeric = dash === -1 ? withoutBuild : withoutBuild.slice(0, dash);
|
|
7287
|
+
return {
|
|
7288
|
+
numbers: numeric.split(".").map((piece) => Number.parseInt(piece, 10) || 0),
|
|
7289
|
+
prerelease: dash !== -1
|
|
7290
|
+
};
|
|
7291
|
+
}
|
|
7292
|
+
function isNewer(candidate, current) {
|
|
7293
|
+
const left = parts(candidate);
|
|
7294
|
+
const right = parts(current);
|
|
7295
|
+
for (let index = 0;index < 3; index += 1) {
|
|
7296
|
+
const a = left.numbers[index] ?? 0;
|
|
7297
|
+
const b = right.numbers[index] ?? 0;
|
|
7298
|
+
if (a !== b) {
|
|
7299
|
+
return a > b;
|
|
7300
|
+
}
|
|
7301
|
+
}
|
|
7302
|
+
return !left.prerelease && right.prerelease;
|
|
7303
|
+
}
|
|
7304
|
+
async function fetchLatest() {
|
|
7305
|
+
const response = await fetch(REGISTRY, {
|
|
7306
|
+
headers: { accept: "application/vnd.npm.install-v1+json, application/json" },
|
|
7307
|
+
redirect: "error",
|
|
7308
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
7309
|
+
});
|
|
7310
|
+
if (!response.ok || response.body === null) {
|
|
7311
|
+
return null;
|
|
7312
|
+
}
|
|
7313
|
+
const declared = Number.parseInt(response.headers.get("content-length") ?? "", 10);
|
|
7314
|
+
if (Number.isFinite(declared) && declared > MAX_BODY_BYTES) {
|
|
7315
|
+
return null;
|
|
7316
|
+
}
|
|
7317
|
+
const chunks = [];
|
|
7318
|
+
let size = 0;
|
|
7319
|
+
for await (const chunk of response.body) {
|
|
7320
|
+
size += chunk.byteLength;
|
|
7321
|
+
if (size > MAX_BODY_BYTES) {
|
|
7322
|
+
return null;
|
|
7323
|
+
}
|
|
7324
|
+
chunks.push(chunk);
|
|
7325
|
+
}
|
|
7326
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
7327
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
7328
|
+
return null;
|
|
7329
|
+
}
|
|
7330
|
+
const version = parsed["version"];
|
|
7331
|
+
return typeof version === "string" && VERSION.test(version) ? version : null;
|
|
7332
|
+
}
|
|
7333
|
+
|
|
7334
|
+
class UpdateCheck {
|
|
7335
|
+
latest = null;
|
|
7336
|
+
checking = false;
|
|
7337
|
+
checkedAt = 0;
|
|
7338
|
+
retryAt = 0;
|
|
7339
|
+
backoffMs = FIRST_RETRY_MS;
|
|
7340
|
+
enabled;
|
|
7341
|
+
current;
|
|
7342
|
+
cachePath;
|
|
7343
|
+
constructor(current, environment = process.env) {
|
|
7344
|
+
this.current = current;
|
|
7345
|
+
this.enabled = (environment["GDHARNESS_NO_UPDATE_CHECK"] ?? "") === "";
|
|
7346
|
+
this.cachePath = cacheFile(environment);
|
|
7347
|
+
const cached = this.enabled ? readCache(this.cachePath) : null;
|
|
7348
|
+
if (cached !== null) {
|
|
7349
|
+
this.latest = cached.latest;
|
|
7350
|
+
this.checkedAt = cached.checkedAt;
|
|
7351
|
+
}
|
|
7352
|
+
}
|
|
7353
|
+
refresh(now = Date.now()) {
|
|
7354
|
+
if (!this.enabled || this.checking || now < this.retryAt || now - this.checkedAt < CACHE_MS) {
|
|
7355
|
+
return;
|
|
7356
|
+
}
|
|
7357
|
+
this.checking = true;
|
|
7358
|
+
fetchLatest().then((version) => {
|
|
7359
|
+
if (version === null) {
|
|
7360
|
+
this.scheduleRetry(now);
|
|
7361
|
+
return;
|
|
7362
|
+
}
|
|
7363
|
+
this.latest = version;
|
|
7364
|
+
this.checkedAt = Date.now();
|
|
7365
|
+
this.backoffMs = FIRST_RETRY_MS;
|
|
7366
|
+
this.retryAt = 0;
|
|
7367
|
+
writeCache(this.cachePath, { checkedAt: this.checkedAt, latest: version });
|
|
7368
|
+
}).catch(() => {
|
|
7369
|
+
this.scheduleRetry(now);
|
|
7370
|
+
}).finally(() => {
|
|
7371
|
+
this.checking = false;
|
|
7372
|
+
});
|
|
7373
|
+
}
|
|
7374
|
+
scheduleRetry(now) {
|
|
7375
|
+
this.retryAt = now + this.backoffMs;
|
|
7376
|
+
this.backoffMs = Math.min(this.backoffMs * 2, MAX_RETRY_MS);
|
|
7377
|
+
}
|
|
7378
|
+
notice() {
|
|
7379
|
+
const latest = this.latest;
|
|
7380
|
+
if (!this.enabled || latest === null || !isNewer(latest, this.current)) {
|
|
7381
|
+
return null;
|
|
7382
|
+
}
|
|
7383
|
+
return {
|
|
7384
|
+
current: this.current,
|
|
7385
|
+
latest,
|
|
7386
|
+
releaseNotes: `${RELEASES}/v${latest}`,
|
|
7387
|
+
upgrade: runLine(currentRunner(), latest, "upgrade")
|
|
7388
|
+
};
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
7391
|
+
var REGISTRY = "https://registry.npmjs.org/gdharness/latest", RELEASES = "https://github.com/Aureliolo/gdharness/releases/tag", CACHE_MS, REQUEST_TIMEOUT_MS = 1e4, MAX_BODY_BYTES, FIRST_RETRY_MS = 30000, MAX_RETRY_MS, VERSION;
|
|
7392
|
+
var init_update_check = __esm(() => {
|
|
7393
|
+
CACHE_MS = 4 * 60 * 60 * 1000;
|
|
7394
|
+
MAX_BODY_BYTES = 1 << 20;
|
|
7395
|
+
MAX_RETRY_MS = 60 * 60 * 1000;
|
|
7396
|
+
VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
7397
|
+
});
|
|
7398
|
+
|
|
7231
7399
|
// src/server-version.ts
|
|
7232
|
-
import { readFileSync as
|
|
7233
|
-
|
|
7400
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7401
|
+
function addonMismatch(addonVersion, serverVersion) {
|
|
7402
|
+
if (addonVersion === serverVersion) {
|
|
7403
|
+
return;
|
|
7404
|
+
}
|
|
7405
|
+
const reported = addonVersion ?? "";
|
|
7406
|
+
const editor = reported === "" ? UNVERSIONED : reported;
|
|
7407
|
+
const both = `The editor is running the ${editor} addon while this server ships ${serverVersion}.`;
|
|
7408
|
+
if (reported !== "" && isNewer(reported, serverVersion)) {
|
|
7409
|
+
return `${both} This server is the older half: reconnect it in your harness so it spawns ${reported}.`;
|
|
7410
|
+
}
|
|
7411
|
+
return `${both} Restart it with editor_launch restart to pick the new one up.`;
|
|
7412
|
+
}
|
|
7413
|
+
var DEBUG_MODE, GODOT_DEBUG_MODE_DEFAULT, SERVER_VERSION, UNVERSIONED = "addon from before versions were reported";
|
|
7234
7414
|
var init_server_version = __esm(() => {
|
|
7415
|
+
init_update_check();
|
|
7235
7416
|
DEBUG_MODE = process.env["DEBUG"] === "true";
|
|
7236
7417
|
GODOT_DEBUG_MODE_DEFAULT = process.env["GODOT_DEBUG"] === "true" || DEBUG_MODE;
|
|
7237
7418
|
SERVER_VERSION = (() => {
|
|
7238
7419
|
try {
|
|
7239
|
-
const pkg = JSON.parse(
|
|
7420
|
+
const pkg = JSON.parse(readFileSync3(new URL("../package.json", import.meta.url), "utf8"));
|
|
7240
7421
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
7241
7422
|
} catch {
|
|
7242
7423
|
return "0.0.0";
|
|
@@ -7245,8 +7426,8 @@ var init_server_version = __esm(() => {
|
|
|
7245
7426
|
});
|
|
7246
7427
|
|
|
7247
7428
|
// src/class-cache.ts
|
|
7248
|
-
import { existsSync as
|
|
7249
|
-
import { join as
|
|
7429
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
7430
|
+
import { join as join5 } from "node:path";
|
|
7250
7431
|
function declaredClasses(projectPath) {
|
|
7251
7432
|
const declared = new Map;
|
|
7252
7433
|
const visit = (directory, prefix) => {
|
|
@@ -7254,11 +7435,11 @@ function declaredClasses(projectPath) {
|
|
|
7254
7435
|
if (entry.name.startsWith(".")) {
|
|
7255
7436
|
continue;
|
|
7256
7437
|
}
|
|
7257
|
-
const path =
|
|
7438
|
+
const path = join5(directory, entry.name);
|
|
7258
7439
|
if (entry.isDirectory()) {
|
|
7259
7440
|
visit(path, `${prefix}${entry.name}/`);
|
|
7260
7441
|
} else if (entry.isFile() && entry.name.endsWith(".gd")) {
|
|
7261
|
-
const found = /^class_name\s+([A-Za-z_][A-Za-z0-9_]*)/m.exec(
|
|
7442
|
+
const found = /^class_name\s+([A-Za-z_][A-Za-z0-9_]*)/m.exec(readFileSync5(path, "utf8"));
|
|
7262
7443
|
if (found?.[1]) {
|
|
7263
7444
|
declared.set(found[1], `res://${prefix}${entry.name}`);
|
|
7264
7445
|
}
|
|
@@ -7269,12 +7450,12 @@ function declaredClasses(projectPath) {
|
|
|
7269
7450
|
return declared;
|
|
7270
7451
|
}
|
|
7271
7452
|
function cachedClasses(projectPath) {
|
|
7272
|
-
const cache =
|
|
7273
|
-
if (!
|
|
7453
|
+
const cache = join5(projectPath, ".godot", "global_script_class_cache.cfg");
|
|
7454
|
+
if (!existsSync5(cache)) {
|
|
7274
7455
|
return null;
|
|
7275
7456
|
}
|
|
7276
7457
|
const listed = new Map;
|
|
7277
|
-
const text =
|
|
7458
|
+
const text = readFileSync5(cache, "utf8");
|
|
7278
7459
|
for (const entry of text.matchAll(/"class":\s*&"([^"]+)"[\s\S]*?"path":\s*"([^"]+)"/g)) {
|
|
7279
7460
|
listed.set(entry[1] ?? "", entry[2] ?? "");
|
|
7280
7461
|
}
|
|
@@ -7291,9 +7472,9 @@ var init_class_cache = () => {};
|
|
|
7291
7472
|
|
|
7292
7473
|
// src/headless.ts
|
|
7293
7474
|
import { execFile as execFile3 } from "node:child_process";
|
|
7294
|
-
import { mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as
|
|
7295
|
-
import { tmpdir as
|
|
7296
|
-
import { join as
|
|
7475
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
7476
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
7477
|
+
import { join as join6 } from "node:path";
|
|
7297
7478
|
import { promisify as promisify3 } from "node:util";
|
|
7298
7479
|
function snakeCased2(params) {
|
|
7299
7480
|
const result = emptyRecord();
|
|
@@ -7333,9 +7514,9 @@ function reason2(stdout, stderr) {
|
|
|
7333
7514
|
return stdout.trim().split(/\r?\n/).at(-1) ?? "no output at all";
|
|
7334
7515
|
}
|
|
7335
7516
|
async function runOperation2(engine, operation, params, projectPath) {
|
|
7336
|
-
const paramsDir = mkdtempSync2(
|
|
7337
|
-
const paramsFile =
|
|
7338
|
-
|
|
7517
|
+
const paramsDir = mkdtempSync2(join6(tmpdir3(), "gdharness-params-"));
|
|
7518
|
+
const paramsFile = join6(paramsDir, `${operation}.json`);
|
|
7519
|
+
writeFileSync4(paramsFile, JSON.stringify(snakeCased2(params)), "utf8");
|
|
7339
7520
|
const args = [
|
|
7340
7521
|
"--headless",
|
|
7341
7522
|
"--path",
|
|
@@ -14537,7 +14718,7 @@ var init_paths = __esm(() => {
|
|
|
14537
14718
|
});
|
|
14538
14719
|
|
|
14539
14720
|
// src/resources.ts
|
|
14540
|
-
import { readFileSync as
|
|
14721
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
14541
14722
|
import { extname, resolve as resolve2 } from "node:path";
|
|
14542
14723
|
function ensureProjectPath(getProjectPath) {
|
|
14543
14724
|
const projectPath = getProjectPath();
|
|
@@ -14679,7 +14860,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
14679
14860
|
const parsedUri = parseGodotUri(uri);
|
|
14680
14861
|
if (parsedUri.kind === "project-info") {
|
|
14681
14862
|
const projectFilePath = resolveProjectFile(projectPath, "project.godot");
|
|
14682
|
-
const rawProject =
|
|
14863
|
+
const rawProject = readFileSync6(projectFilePath, "utf-8");
|
|
14683
14864
|
const parsedProject = parseProjectGodot(rawProject);
|
|
14684
14865
|
return {
|
|
14685
14866
|
mimeType: "application/json",
|
|
@@ -14688,7 +14869,7 @@ function readResourceText(uri, getProjectPath) {
|
|
|
14688
14869
|
}
|
|
14689
14870
|
const filePath = resolveProjectFile(projectPath, parsedUri.resourcePath);
|
|
14690
14871
|
ensureAllowedExtension(parsedUri.kind, filePath);
|
|
14691
|
-
const text =
|
|
14872
|
+
const text = readFileSync6(filePath, "utf-8");
|
|
14692
14873
|
return {
|
|
14693
14874
|
mimeType: parsedUri.kind === "script" ? "text/x-gdscript" : "text/plain",
|
|
14694
14875
|
text
|
|
@@ -34297,7 +34478,7 @@ var init_godot_bridge = __esm(() => {
|
|
|
34297
34478
|
|
|
34298
34479
|
// src/godot-path.ts
|
|
34299
34480
|
import { execFile as execFile4 } from "node:child_process";
|
|
34300
|
-
import { existsSync as
|
|
34481
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
34301
34482
|
import { normalize as normalize2 } from "node:path";
|
|
34302
34483
|
import { promisify as promisify4 } from "node:util";
|
|
34303
34484
|
var run4, GodotLocator2;
|
|
@@ -34339,7 +34520,7 @@ var init_godot_path = __esm(() => {
|
|
|
34339
34520
|
return known;
|
|
34340
34521
|
}
|
|
34341
34522
|
let ok = false;
|
|
34342
|
-
if (path === "godot" ||
|
|
34523
|
+
if (path === "godot" || existsSync8(path)) {
|
|
34343
34524
|
try {
|
|
34344
34525
|
await run4(path, ["--version"]);
|
|
34345
34526
|
ok = true;
|
|
@@ -35142,8 +35323,8 @@ var init_lsp_client = __esm(() => {
|
|
|
35142
35323
|
});
|
|
35143
35324
|
|
|
35144
35325
|
// src/project-scan.ts
|
|
35145
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
35146
|
-
import { join as
|
|
35326
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync9 } from "node:fs";
|
|
35327
|
+
import { join as join10 } from "node:path";
|
|
35147
35328
|
function projectStructure(projectPath) {
|
|
35148
35329
|
const structure = { scenes: 0, scripts: 0, assets: 0, other: 0 };
|
|
35149
35330
|
const visit = (directory) => {
|
|
@@ -35152,7 +35333,7 @@ function projectStructure(projectPath) {
|
|
|
35152
35333
|
continue;
|
|
35153
35334
|
}
|
|
35154
35335
|
if (entry.isDirectory()) {
|
|
35155
|
-
visit(
|
|
35336
|
+
visit(join10(directory, entry.name));
|
|
35156
35337
|
} else if (entry.isFile()) {
|
|
35157
35338
|
const extension = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
35158
35339
|
if (extension === "tscn") {
|
|
@@ -35194,7 +35375,7 @@ function searchProject(projectPath, options) {
|
|
|
35194
35375
|
if (SKIPPED.has(entry.name)) {
|
|
35195
35376
|
continue;
|
|
35196
35377
|
}
|
|
35197
|
-
const entryPath =
|
|
35378
|
+
const entryPath = join10(directory, entry.name);
|
|
35198
35379
|
if (entry.isDirectory()) {
|
|
35199
35380
|
visit(entryPath);
|
|
35200
35381
|
continue;
|
|
@@ -35205,7 +35386,7 @@ function searchProject(projectPath, options) {
|
|
|
35205
35386
|
}
|
|
35206
35387
|
result.summary.files_searched += 1;
|
|
35207
35388
|
const matches = [];
|
|
35208
|
-
for (const [index, line] of
|
|
35389
|
+
for (const [index, line] of readFileSync9(entryPath, "utf8").split(`
|
|
35209
35390
|
`).entries()) {
|
|
35210
35391
|
if (full()) {
|
|
35211
35392
|
break;
|
|
@@ -35233,17 +35414,25 @@ var init_project_scan = __esm(() => {
|
|
|
35233
35414
|
});
|
|
35234
35415
|
|
|
35235
35416
|
// src/runtime-client.ts
|
|
35236
|
-
import { existsSync as
|
|
35417
|
+
import { existsSync as existsSync9, readdirSync as readdirSync5, readFileSync as readFileSync10, unlinkSync } from "node:fs";
|
|
35237
35418
|
import { createConnection as createConnection3 } from "node:net";
|
|
35238
|
-
import { tmpdir as
|
|
35239
|
-
import { join as
|
|
35419
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
35420
|
+
import { join as join11, resolve as resolve4 } from "node:path";
|
|
35240
35421
|
function runtimeDirectory(variables = process.env) {
|
|
35241
35422
|
const explicit = envValue("GDHARNESS_RUNTIME_DIR", variables);
|
|
35242
35423
|
if (explicit) {
|
|
35243
35424
|
return explicit;
|
|
35244
35425
|
}
|
|
35245
35426
|
const perUser = envValue("XDG_RUNTIME_DIR", variables);
|
|
35246
|
-
return
|
|
35427
|
+
return join11(perUser ?? tmpdir4(), "gdharness");
|
|
35428
|
+
}
|
|
35429
|
+
function runtimeDirectories(variables = process.env) {
|
|
35430
|
+
const candidates = [runtimeDirectory(variables)];
|
|
35431
|
+
const fallbacks = process.platform === "win32" ? [envValue("SystemRoot", variables) ?? envValue("windir", variables) ?? "C:\\Windows"] : ["/tmp", "/var/tmp"];
|
|
35432
|
+
for (const base of fallbacks) {
|
|
35433
|
+
candidates.push(join11(base, process.platform === "win32" ? "Temp" : "", "gdharness"));
|
|
35434
|
+
}
|
|
35435
|
+
return [...new Set(candidates.map((path) => resolve4(path)))];
|
|
35247
35436
|
}
|
|
35248
35437
|
function processAlive(pid) {
|
|
35249
35438
|
try {
|
|
@@ -35256,7 +35445,7 @@ function processAlive(pid) {
|
|
|
35256
35445
|
function parseAnnouncement(file, pid) {
|
|
35257
35446
|
let fields;
|
|
35258
35447
|
try {
|
|
35259
|
-
fields = asParams(JSON.parse(
|
|
35448
|
+
fields = asParams(JSON.parse(readFileSync10(file, "utf8")));
|
|
35260
35449
|
} catch {
|
|
35261
35450
|
return null;
|
|
35262
35451
|
}
|
|
@@ -35274,8 +35463,19 @@ function parseAnnouncement(file, pid) {
|
|
|
35274
35463
|
file
|
|
35275
35464
|
};
|
|
35276
35465
|
}
|
|
35277
|
-
function discoverRuntimes(
|
|
35278
|
-
|
|
35466
|
+
function discoverRuntimes(directories = runtimeDirectories()) {
|
|
35467
|
+
const found = new Map;
|
|
35468
|
+
for (const directory of directories) {
|
|
35469
|
+
for (const endpoint of announcedIn(directory)) {
|
|
35470
|
+
if (!found.has(endpoint.pid)) {
|
|
35471
|
+
found.set(endpoint.pid, endpoint);
|
|
35472
|
+
}
|
|
35473
|
+
}
|
|
35474
|
+
}
|
|
35475
|
+
return [...found.values()].sort((a, b) => b.pid - a.pid);
|
|
35476
|
+
}
|
|
35477
|
+
function announcedIn(directory) {
|
|
35478
|
+
if (!existsSync9(directory)) {
|
|
35279
35479
|
return [];
|
|
35280
35480
|
}
|
|
35281
35481
|
const found = [];
|
|
@@ -35284,7 +35484,7 @@ function discoverRuntimes(directory = runtimeDirectory()) {
|
|
|
35284
35484
|
if (!match) {
|
|
35285
35485
|
continue;
|
|
35286
35486
|
}
|
|
35287
|
-
const file =
|
|
35487
|
+
const file = join11(directory, entry);
|
|
35288
35488
|
const pid = Number.parseInt(match[1] ?? "", 10);
|
|
35289
35489
|
const endpoint = processAlive(pid) ? parseAnnouncement(file, pid) : null;
|
|
35290
35490
|
if (endpoint) {
|
|
@@ -35295,7 +35495,7 @@ function discoverRuntimes(directory = runtimeDirectory()) {
|
|
|
35295
35495
|
} catch {}
|
|
35296
35496
|
}
|
|
35297
35497
|
}
|
|
35298
|
-
return found
|
|
35498
|
+
return found;
|
|
35299
35499
|
}
|
|
35300
35500
|
function describe2(endpoint) {
|
|
35301
35501
|
return `pid ${endpoint.pid} on ${endpoint.address}:${endpoint.port} (${endpoint.project.name || "unnamed"} at ${endpoint.project.path})`;
|
|
@@ -35420,174 +35620,6 @@ var init_runtime_client = __esm(() => {
|
|
|
35420
35620
|
ANNOUNCEMENT_PATTERN = /^runtime-(\d+)\.json$/;
|
|
35421
35621
|
});
|
|
35422
35622
|
|
|
35423
|
-
// src/update-check.ts
|
|
35424
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "node:fs";
|
|
35425
|
-
import { homedir as homedir3, tmpdir as tmpdir4 } from "node:os";
|
|
35426
|
-
import { join as join11 } from "node:path";
|
|
35427
|
-
function cacheDirectory(environment) {
|
|
35428
|
-
const set = (name) => {
|
|
35429
|
-
const value = environment[name];
|
|
35430
|
-
return value !== undefined && value !== "" ? value : null;
|
|
35431
|
-
};
|
|
35432
|
-
const home = set("HOME") ?? homedir3();
|
|
35433
|
-
if (process.platform === "win32") {
|
|
35434
|
-
return join11(set("LOCALAPPDATA") ?? home, "gdharness");
|
|
35435
|
-
}
|
|
35436
|
-
if (process.platform === "darwin") {
|
|
35437
|
-
return join11(home, "Library", "Caches", "gdharness");
|
|
35438
|
-
}
|
|
35439
|
-
return join11(set("XDG_CACHE_HOME") ?? join11(home, ".cache"), "gdharness");
|
|
35440
|
-
}
|
|
35441
|
-
function cacheFile(environment = process.env) {
|
|
35442
|
-
try {
|
|
35443
|
-
const directory = cacheDirectory(environment);
|
|
35444
|
-
mkdirSync4(directory, { recursive: true, mode: 448 });
|
|
35445
|
-
return join11(directory, "update-check.json");
|
|
35446
|
-
} catch {
|
|
35447
|
-
return join11(tmpdir4(), "gdharness-update-check.json");
|
|
35448
|
-
}
|
|
35449
|
-
}
|
|
35450
|
-
function readCache(path) {
|
|
35451
|
-
try {
|
|
35452
|
-
if (!existsSync9(path)) {
|
|
35453
|
-
return null;
|
|
35454
|
-
}
|
|
35455
|
-
const parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
35456
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
35457
|
-
return null;
|
|
35458
|
-
}
|
|
35459
|
-
const record = parsed;
|
|
35460
|
-
const checkedAt = record["checkedAt"];
|
|
35461
|
-
const latest = record["latest"];
|
|
35462
|
-
if (typeof checkedAt !== "number" || typeof latest !== "string" || !VERSION.test(latest)) {
|
|
35463
|
-
return null;
|
|
35464
|
-
}
|
|
35465
|
-
return { checkedAt, latest };
|
|
35466
|
-
} catch {
|
|
35467
|
-
return null;
|
|
35468
|
-
}
|
|
35469
|
-
}
|
|
35470
|
-
function writeCache(path, entry) {
|
|
35471
|
-
try {
|
|
35472
|
-
writeFileSync6(path, JSON.stringify(entry), { encoding: "utf8", mode: 384 });
|
|
35473
|
-
} catch {}
|
|
35474
|
-
}
|
|
35475
|
-
function parts(version) {
|
|
35476
|
-
const withoutBuild = version.split("+")[0] ?? version;
|
|
35477
|
-
const dash = withoutBuild.indexOf("-");
|
|
35478
|
-
const numeric = dash === -1 ? withoutBuild : withoutBuild.slice(0, dash);
|
|
35479
|
-
return {
|
|
35480
|
-
numbers: numeric.split(".").map((piece) => Number.parseInt(piece, 10) || 0),
|
|
35481
|
-
prerelease: dash !== -1
|
|
35482
|
-
};
|
|
35483
|
-
}
|
|
35484
|
-
function isNewer(candidate, current) {
|
|
35485
|
-
const left = parts(candidate);
|
|
35486
|
-
const right = parts(current);
|
|
35487
|
-
for (let index = 0;index < 3; index += 1) {
|
|
35488
|
-
const a = left.numbers[index] ?? 0;
|
|
35489
|
-
const b = right.numbers[index] ?? 0;
|
|
35490
|
-
if (a !== b) {
|
|
35491
|
-
return a > b;
|
|
35492
|
-
}
|
|
35493
|
-
}
|
|
35494
|
-
return !left.prerelease && right.prerelease;
|
|
35495
|
-
}
|
|
35496
|
-
async function fetchLatest() {
|
|
35497
|
-
const response = await fetch(REGISTRY, {
|
|
35498
|
-
headers: { accept: "application/vnd.npm.install-v1+json, application/json" },
|
|
35499
|
-
redirect: "error",
|
|
35500
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
35501
|
-
});
|
|
35502
|
-
if (!response.ok || response.body === null) {
|
|
35503
|
-
return null;
|
|
35504
|
-
}
|
|
35505
|
-
const declared = Number.parseInt(response.headers.get("content-length") ?? "", 10);
|
|
35506
|
-
if (Number.isFinite(declared) && declared > MAX_BODY_BYTES) {
|
|
35507
|
-
return null;
|
|
35508
|
-
}
|
|
35509
|
-
const chunks = [];
|
|
35510
|
-
let size = 0;
|
|
35511
|
-
for await (const chunk of response.body) {
|
|
35512
|
-
size += chunk.byteLength;
|
|
35513
|
-
if (size > MAX_BODY_BYTES) {
|
|
35514
|
-
return null;
|
|
35515
|
-
}
|
|
35516
|
-
chunks.push(chunk);
|
|
35517
|
-
}
|
|
35518
|
-
const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
35519
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
35520
|
-
return null;
|
|
35521
|
-
}
|
|
35522
|
-
const version = parsed["version"];
|
|
35523
|
-
return typeof version === "string" && VERSION.test(version) ? version : null;
|
|
35524
|
-
}
|
|
35525
|
-
|
|
35526
|
-
class UpdateCheck {
|
|
35527
|
-
latest = null;
|
|
35528
|
-
checking = false;
|
|
35529
|
-
checkedAt = 0;
|
|
35530
|
-
retryAt = 0;
|
|
35531
|
-
backoffMs = FIRST_RETRY_MS;
|
|
35532
|
-
enabled;
|
|
35533
|
-
current;
|
|
35534
|
-
cachePath;
|
|
35535
|
-
constructor(current, environment = process.env) {
|
|
35536
|
-
this.current = current;
|
|
35537
|
-
this.enabled = (environment["GDHARNESS_NO_UPDATE_CHECK"] ?? "") === "";
|
|
35538
|
-
this.cachePath = cacheFile(environment);
|
|
35539
|
-
const cached = this.enabled ? readCache(this.cachePath) : null;
|
|
35540
|
-
if (cached !== null) {
|
|
35541
|
-
this.latest = cached.latest;
|
|
35542
|
-
this.checkedAt = cached.checkedAt;
|
|
35543
|
-
}
|
|
35544
|
-
}
|
|
35545
|
-
refresh(now = Date.now()) {
|
|
35546
|
-
if (!this.enabled || this.checking || now < this.retryAt || now - this.checkedAt < CACHE_MS) {
|
|
35547
|
-
return;
|
|
35548
|
-
}
|
|
35549
|
-
this.checking = true;
|
|
35550
|
-
fetchLatest().then((version) => {
|
|
35551
|
-
if (version === null) {
|
|
35552
|
-
this.scheduleRetry(now);
|
|
35553
|
-
return;
|
|
35554
|
-
}
|
|
35555
|
-
this.latest = version;
|
|
35556
|
-
this.checkedAt = Date.now();
|
|
35557
|
-
this.backoffMs = FIRST_RETRY_MS;
|
|
35558
|
-
this.retryAt = 0;
|
|
35559
|
-
writeCache(this.cachePath, { checkedAt: this.checkedAt, latest: version });
|
|
35560
|
-
}).catch(() => {
|
|
35561
|
-
this.scheduleRetry(now);
|
|
35562
|
-
}).finally(() => {
|
|
35563
|
-
this.checking = false;
|
|
35564
|
-
});
|
|
35565
|
-
}
|
|
35566
|
-
scheduleRetry(now) {
|
|
35567
|
-
this.retryAt = now + this.backoffMs;
|
|
35568
|
-
this.backoffMs = Math.min(this.backoffMs * 2, MAX_RETRY_MS);
|
|
35569
|
-
}
|
|
35570
|
-
notice() {
|
|
35571
|
-
const latest = this.latest;
|
|
35572
|
-
if (!this.enabled || latest === null || !isNewer(latest, this.current)) {
|
|
35573
|
-
return null;
|
|
35574
|
-
}
|
|
35575
|
-
return {
|
|
35576
|
-
current: this.current,
|
|
35577
|
-
latest,
|
|
35578
|
-
releaseNotes: `${RELEASES}/v${latest}`,
|
|
35579
|
-
upgrade: runLine(currentRunner(), latest, "upgrade")
|
|
35580
|
-
};
|
|
35581
|
-
}
|
|
35582
|
-
}
|
|
35583
|
-
var REGISTRY = "https://registry.npmjs.org/gdharness/latest", RELEASES = "https://github.com/Aureliolo/gdharness/releases/tag", CACHE_MS, REQUEST_TIMEOUT_MS = 1e4, MAX_BODY_BYTES, FIRST_RETRY_MS = 30000, MAX_RETRY_MS, VERSION;
|
|
35584
|
-
var init_update_check = __esm(() => {
|
|
35585
|
-
CACHE_MS = 4 * 60 * 60 * 1000;
|
|
35586
|
-
MAX_BODY_BYTES = 1 << 20;
|
|
35587
|
-
MAX_RETRY_MS = 60 * 60 * 1000;
|
|
35588
|
-
VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
35589
|
-
});
|
|
35590
|
-
|
|
35591
35623
|
// src/server.ts
|
|
35592
35624
|
import { execFile as execFile5, spawn } from "node:child_process";
|
|
35593
35625
|
import { existsSync as existsSync10, mkdtempSync as mkdtempSync3, readdirSync as readdirSync6, readFileSync as readFileSync11, realpathSync as realpathSync2, rmSync as rmSync6 } from "node:fs";
|
|
@@ -36528,7 +36560,7 @@ class GodotServer {
|
|
|
36528
36560
|
addonIsStale: status.connected ? stale : undefined,
|
|
36529
36561
|
bridgeAvailable: this.bridgeStartupError === null,
|
|
36530
36562
|
startupError: this.bridgeStartupError,
|
|
36531
|
-
staleNote: stale ?
|
|
36563
|
+
staleNote: stale ? addonMismatch(status.addonVersion, SERVER_VERSION) : undefined,
|
|
36532
36564
|
note: isPortConflict ? "Bridge port is already in use. Another gdharness instance may own the editor bridge, so this server cannot report that editor connection." : undefined,
|
|
36533
36565
|
suggestion: isPortConflict ? "Stop duplicate gdharness/MCP server instances or re-run the command from the same server process that owns the bridge port." : undefined
|
|
36534
36566
|
};
|
|
@@ -36606,6 +36638,7 @@ class GodotServer {
|
|
|
36606
36638
|
addonVersion: now.addonVersion,
|
|
36607
36639
|
serverVersion: SERVER_VERSION,
|
|
36608
36640
|
addonIsStale: now.addonVersion !== SERVER_VERSION,
|
|
36641
|
+
staleNote: addonMismatch(now.addonVersion, SERVER_VERSION),
|
|
36609
36642
|
tookMs: Date.now() - began
|
|
36610
36643
|
});
|
|
36611
36644
|
}
|
|
@@ -36639,7 +36672,8 @@ class GodotServer {
|
|
|
36639
36672
|
this.logDebug(`Launching Godot editor for project: ${project.value.path}`);
|
|
36640
36673
|
const editor = spawn(engine.value, editorArguments(project.value.path), {
|
|
36641
36674
|
stdio: "ignore",
|
|
36642
|
-
detached: true
|
|
36675
|
+
detached: true,
|
|
36676
|
+
env: { ...process.env, GDHARNESS_RUNTIME_DIR: runtimeDirectory() }
|
|
36643
36677
|
});
|
|
36644
36678
|
const started = await new Promise((resolve) => {
|
|
36645
36679
|
editor.once("spawn", () => {
|
|
@@ -38133,12 +38167,13 @@ class Ask {
|
|
|
38133
38167
|
}
|
|
38134
38168
|
|
|
38135
38169
|
// src/server-version.ts
|
|
38136
|
-
|
|
38170
|
+
init_update_check();
|
|
38171
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
38137
38172
|
var DEBUG_MODE2 = process.env["DEBUG"] === "true";
|
|
38138
38173
|
var GODOT_DEBUG_MODE_DEFAULT2 = process.env["GODOT_DEBUG"] === "true" || DEBUG_MODE2;
|
|
38139
38174
|
var SERVER_VERSION2 = (() => {
|
|
38140
38175
|
try {
|
|
38141
|
-
const pkg = JSON.parse(
|
|
38176
|
+
const pkg = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8"));
|
|
38142
38177
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
38143
38178
|
} catch {
|
|
38144
38179
|
return "0.0.0";
|
|
@@ -38150,8 +38185,8 @@ init_class_cache();
|
|
|
38150
38185
|
init_headless();
|
|
38151
38186
|
init_resources();
|
|
38152
38187
|
init_server_version();
|
|
38153
|
-
import { cpSync, existsSync as
|
|
38154
|
-
import { dirname as dirname2, join as
|
|
38188
|
+
import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync7, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
38189
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
38155
38190
|
import { fileURLToPath } from "node:url";
|
|
38156
38191
|
var ADDONS = ["gdharness_editor", "gdharness_runtime", "auto_reload"];
|
|
38157
38192
|
var EDITOR_PLUGINS = ["gdharness_editor", "auto_reload"];
|
|
@@ -38161,24 +38196,24 @@ var RUNTIME_AUTOLOAD = {
|
|
|
38161
38196
|
};
|
|
38162
38197
|
var VERSION_MARKER = ".gdharness-version";
|
|
38163
38198
|
function shippedAddonsDirectory() {
|
|
38164
|
-
return
|
|
38199
|
+
return join7(dirname2(fileURLToPath(import.meta.url)), "godot", "addons");
|
|
38165
38200
|
}
|
|
38166
38201
|
function shippedOperationsScript() {
|
|
38167
|
-
return
|
|
38202
|
+
return join7(dirname2(fileURLToPath(import.meta.url)), "godot", "operations", "godot_operations.gd");
|
|
38168
38203
|
}
|
|
38169
38204
|
function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
38170
38205
|
const installed = [];
|
|
38171
38206
|
for (const name of ADDONS) {
|
|
38172
|
-
const source =
|
|
38173
|
-
if (!
|
|
38207
|
+
const source = join7(from, name);
|
|
38208
|
+
if (!existsSync6(join7(source, name === "gdharness_runtime" ? "runtime_autoload.gd" : "plugin.cfg"))) {
|
|
38174
38209
|
throw new Error(`The package holds no ${name} addon at ${source}.`);
|
|
38175
38210
|
}
|
|
38176
|
-
const target =
|
|
38177
|
-
const replaced =
|
|
38211
|
+
const target = join7(projectPath, "addons", name);
|
|
38212
|
+
const replaced = existsSync6(target);
|
|
38178
38213
|
rmSync4(target, { recursive: true, force: true });
|
|
38179
|
-
|
|
38214
|
+
mkdirSync3(dirname2(target), { recursive: true });
|
|
38180
38215
|
cpSync(source, target, { recursive: true });
|
|
38181
|
-
|
|
38216
|
+
writeFileSync5(join7(target, VERSION_MARKER), `${SERVER_VERSION}
|
|
38182
38217
|
`);
|
|
38183
38218
|
installed.push({ name, path: target, replaced });
|
|
38184
38219
|
}
|
|
@@ -38187,8 +38222,8 @@ function installAddons(projectPath, from = shippedAddonsDirectory()) {
|
|
|
38187
38222
|
function removeAddons(projectPath) {
|
|
38188
38223
|
const removed = [];
|
|
38189
38224
|
for (const name of ADDONS) {
|
|
38190
|
-
const target =
|
|
38191
|
-
if (
|
|
38225
|
+
const target = join7(projectPath, "addons", name);
|
|
38226
|
+
if (existsSync6(target)) {
|
|
38192
38227
|
rmSync4(target, { recursive: true, force: true });
|
|
38193
38228
|
removed.push(target);
|
|
38194
38229
|
}
|
|
@@ -38222,10 +38257,10 @@ function enabledPlugins(settings) {
|
|
|
38222
38257
|
function inspectProject(projectPath) {
|
|
38223
38258
|
const problems = [];
|
|
38224
38259
|
const addons = ADDONS.map((name) => {
|
|
38225
|
-
const directory =
|
|
38226
|
-
const marker =
|
|
38227
|
-
const installed =
|
|
38228
|
-
const version =
|
|
38260
|
+
const directory = join7(projectPath, "addons", name);
|
|
38261
|
+
const marker = join7(directory, VERSION_MARKER);
|
|
38262
|
+
const installed = existsSync6(directory);
|
|
38263
|
+
const version = existsSync6(marker) ? readFileSync7(marker, "utf8").trim() : null;
|
|
38229
38264
|
const current = version === SERVER_VERSION;
|
|
38230
38265
|
if (!installed) {
|
|
38231
38266
|
problems.push(`addons/${name} is not installed; run gdharness setup`);
|
|
@@ -38234,7 +38269,7 @@ function inspectProject(projectPath) {
|
|
|
38234
38269
|
}
|
|
38235
38270
|
return { name, installed, version, current };
|
|
38236
38271
|
});
|
|
38237
|
-
const settings = parseProjectGodot(
|
|
38272
|
+
const settings = parseProjectGodot(readFileSync7(join7(projectPath, "project.godot"), "utf8"));
|
|
38238
38273
|
const pluginsEnabled = enabledPlugins(settings);
|
|
38239
38274
|
for (const name of EDITOR_PLUGINS) {
|
|
38240
38275
|
if (!pluginsEnabled.includes(name)) {
|
|
@@ -38263,8 +38298,8 @@ function inspectProject(projectPath) {
|
|
|
38263
38298
|
|
|
38264
38299
|
// src/skill.ts
|
|
38265
38300
|
init_tool_definitions();
|
|
38266
|
-
import { existsSync as
|
|
38267
|
-
import { basename, dirname as dirname3, join as
|
|
38301
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
38302
|
+
import { basename, dirname as dirname3, join as join8 } from "node:path";
|
|
38268
38303
|
|
|
38269
38304
|
// src/tool-reference.ts
|
|
38270
38305
|
init_tool_definitions();
|
|
@@ -38311,7 +38346,7 @@ function renderToolsMarkdown() {
|
|
|
38311
38346
|
|
|
38312
38347
|
// src/skill.ts
|
|
38313
38348
|
var SKILL_NAME = "gdharness";
|
|
38314
|
-
var SHARED_SKILLS =
|
|
38349
|
+
var SHARED_SKILLS = join8(".agents", "skills");
|
|
38315
38350
|
function skillMarkdown(version) {
|
|
38316
38351
|
return `---
|
|
38317
38352
|
name: ${SKILL_NAME}
|
|
@@ -38333,7 +38368,8 @@ that is running, and the project on disk. ${TOOL_SPECS.length} tools, named \`do
|
|
|
38333
38368
|
- Every call takes \`projectPath\`, except \`runtime_*\` and \`debug_*\`, where it picks between
|
|
38334
38369
|
running games. There is no ambient project.
|
|
38335
38370
|
- \`editor_status\` says whether an editor is connected and whether its addon matches the server.
|
|
38336
|
-
\`addonIsStale\` means
|
|
38371
|
+
\`addonIsStale\` means they differ, and \`staleNote\` says which half is behind: an editor that
|
|
38372
|
+
needs restarting, or a server that needs reconnecting in your harness.
|
|
38337
38373
|
- Start the game with \`editor_run start\`, never by spawning an engine. The editor plays it, so
|
|
38338
38374
|
its debugger holds it, which is what gives the \`debug_*\` tools something to talk to.
|
|
38339
38375
|
- Read \`editor_output\` after every run. It returns the engine's errors and warnings as entries
|
|
@@ -38392,27 +38428,27 @@ whatever the engine said on stderr comes back under \`engine_messages\`.
|
|
|
38392
38428
|
function skillFiles(version) {
|
|
38393
38429
|
return new Map([
|
|
38394
38430
|
["SKILL.md", skillMarkdown(version)],
|
|
38395
|
-
[
|
|
38431
|
+
[join8("references", "tools.md"), renderToolsMarkdown()]
|
|
38396
38432
|
]);
|
|
38397
38433
|
}
|
|
38398
38434
|
function skillDirectories(harnesses, projectPath, exists) {
|
|
38399
|
-
const directories = [
|
|
38435
|
+
const directories = [join8(projectPath, SHARED_SKILLS, SKILL_NAME)];
|
|
38400
38436
|
for (const harness of harnesses) {
|
|
38401
38437
|
if (harness.skills === undefined) {
|
|
38402
38438
|
continue;
|
|
38403
38439
|
}
|
|
38404
|
-
const own =
|
|
38405
|
-
if ((!harness.skills.shared || exists(own)) && !directories.includes(
|
|
38406
|
-
directories.push(
|
|
38440
|
+
const own = join8(projectPath, harness.skills.dir);
|
|
38441
|
+
if ((!harness.skills.shared || exists(own)) && !directories.includes(join8(own, SKILL_NAME))) {
|
|
38442
|
+
directories.push(join8(own, SKILL_NAME));
|
|
38407
38443
|
}
|
|
38408
38444
|
}
|
|
38409
38445
|
return directories;
|
|
38410
38446
|
}
|
|
38411
38447
|
function everySkillDirectory(projectPath, harnesses) {
|
|
38412
|
-
const directories = new Set([
|
|
38448
|
+
const directories = new Set([join8(projectPath, SHARED_SKILLS, SKILL_NAME)]);
|
|
38413
38449
|
for (const harness of harnesses) {
|
|
38414
38450
|
if (harness.skills !== undefined) {
|
|
38415
|
-
directories.add(
|
|
38451
|
+
directories.add(join8(projectPath, harness.skills.dir, SKILL_NAME));
|
|
38416
38452
|
}
|
|
38417
38453
|
}
|
|
38418
38454
|
return [...directories];
|
|
@@ -38420,7 +38456,7 @@ function everySkillDirectory(projectPath, harnesses) {
|
|
|
38420
38456
|
function removeSkill(directories, projectPath) {
|
|
38421
38457
|
const removed = [];
|
|
38422
38458
|
for (const directory of directories) {
|
|
38423
|
-
if (
|
|
38459
|
+
if (existsSync7(directory)) {
|
|
38424
38460
|
rmSync5(directory, { recursive: true, force: true });
|
|
38425
38461
|
pruneEmpty(dirname3(directory), projectPath);
|
|
38426
38462
|
removed.push(directory);
|
|
@@ -38429,7 +38465,7 @@ function removeSkill(directories, projectPath) {
|
|
|
38429
38465
|
return removed;
|
|
38430
38466
|
}
|
|
38431
38467
|
function pruneEmpty(directory, projectPath) {
|
|
38432
|
-
const shared =
|
|
38468
|
+
const shared = join8(projectPath, ".agents");
|
|
38433
38469
|
let path = directory;
|
|
38434
38470
|
while (path !== projectPath && (basename(path) === "skills" || path === shared)) {
|
|
38435
38471
|
if (readdirSync3(path).length > 0) {
|
|
@@ -38442,30 +38478,30 @@ function pruneEmpty(directory, projectPath) {
|
|
|
38442
38478
|
function writeSkill(directories, version) {
|
|
38443
38479
|
const files = skillFiles(version);
|
|
38444
38480
|
return directories.map((directory) => {
|
|
38445
|
-
const replaced =
|
|
38481
|
+
const replaced = existsSync7(directory);
|
|
38446
38482
|
rmSync5(directory, { recursive: true, force: true });
|
|
38447
38483
|
for (const [name, contents] of files) {
|
|
38448
|
-
const path =
|
|
38449
|
-
|
|
38450
|
-
|
|
38484
|
+
const path = join8(directory, name);
|
|
38485
|
+
mkdirSync4(dirname3(path), { recursive: true });
|
|
38486
|
+
writeFileSync6(path, contents, "utf8");
|
|
38451
38487
|
}
|
|
38452
38488
|
return { path: directory, replaced };
|
|
38453
38489
|
});
|
|
38454
38490
|
}
|
|
38455
38491
|
|
|
38456
38492
|
// src/version.ts
|
|
38457
|
-
import { readFileSync as
|
|
38458
|
-
import { dirname as dirname4, join as
|
|
38493
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
38494
|
+
import { dirname as dirname4, join as join9 } from "node:path";
|
|
38459
38495
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
38460
38496
|
function getLocalVersion() {
|
|
38461
38497
|
const currentDirectory = dirname4(fileURLToPath2(import.meta.url));
|
|
38462
38498
|
const packageCandidates = [
|
|
38463
|
-
|
|
38464
|
-
|
|
38499
|
+
join9(currentDirectory, "..", "package.json"),
|
|
38500
|
+
join9(currentDirectory, "..", "..", "package.json")
|
|
38465
38501
|
];
|
|
38466
38502
|
for (const packagePath of packageCandidates) {
|
|
38467
38503
|
try {
|
|
38468
|
-
const value = JSON.parse(
|
|
38504
|
+
const value = JSON.parse(readFileSync8(packagePath, "utf-8"));
|
|
38469
38505
|
if (typeof value === "object" && value !== null && "name" in value && value.name === "gdharness" && "version" in value && typeof value.version === "string") {
|
|
38470
38506
|
return value.version;
|
|
38471
38507
|
}
|