gdharness 1.3.60 → 1.3.62
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/README.md +20 -20
- package/build/cli.js +2198 -1757
- package/build/godot/addons/auto_reload/auto_reload.gd +3 -3
- package/build/godot/addons/gdharness_editor/bridge_client.gd +4 -4
- package/build/godot/addons/gdharness_editor/declared_values.gd +13 -13
- package/build/godot/addons/gdharness_editor/file_reads.gd +6 -6
- package/build/godot/addons/gdharness_editor/headless_check.gd +9 -6
- package/build/godot/addons/gdharness_editor/property_paths.gd +3 -3
- package/build/godot/addons/gdharness_editor/property_values.gd +10 -10
- package/build/godot/addons/gdharness_editor/reading.gd +22 -18
- package/build/godot/addons/gdharness_editor/scene_file.gd +5 -5
- package/build/godot/addons/gdharness_editor/serialisation.gd +4 -4
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +5 -5
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +6 -6
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +9 -9
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +3 -3
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +5 -5
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +5 -5
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +2 -2
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +1 -1
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +5 -5
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +3 -3
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +3 -3
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +4 -4
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +3 -3
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +10 -10
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +1 -1
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +5 -5
- package/build/godot/addons/gdharness_runtime/declared_values.gd +13 -13
- package/build/godot/addons/gdharness_runtime/reading.gd +22 -18
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +89 -18
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +6 -6
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +10 -10
- package/build/godot/addons/gdharness_runtime/runtime_frames.gd +5 -4
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +3 -4
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +8 -8
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +1 -1
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +3 -3
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +5 -5
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +20 -20
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +19 -13
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +5 -5
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +39 -39
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +3 -3
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +7 -7
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +8 -8
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +5 -5
- package/build/godot/addons/gdharness_runtime/serialisation.gd +4 -4
- package/build/godot/addons/gdharness_tests/bench.gd +1 -1
- package/build/godot/addons/gdharness_tests/share.gd +6 -6
- package/build/godot/addons/gdharness_tests/suites.gd +1 -1
- package/build/godot/operations/audio_buses.gd +4 -4
- package/build/godot/operations/class_cache.gd +3 -3
- package/build/godot/operations/classdb_queries.gd +1 -1
- package/build/godot/operations/declared_values.gd +13 -13
- package/build/godot/operations/dependencies.gd +6 -6
- package/build/godot/operations/export_presets.gd +7 -7
- package/build/godot/operations/file_reads.gd +6 -6
- package/build/godot/operations/gdscript_analysis.gd +6 -6
- package/build/godot/operations/gdscript_authoring.gd +11 -11
- package/build/godot/operations/godot_operations.gd +1 -1
- package/build/godot/operations/import_pipeline.gd +12 -12
- package/build/godot/operations/input_actions.gd +3 -3
- package/build/godot/operations/logger.gd +1 -1
- package/build/godot/operations/plugins.gd +2 -2
- package/build/godot/operations/project_config.gd +11 -11
- package/build/godot/operations/project_validation.gd +1 -1
- package/build/godot/operations/property_paths.gd +3 -3
- package/build/godot/operations/property_values.gd +10 -10
- package/build/godot/operations/reading.gd +22 -18
- package/build/godot/operations/resource_files.gd +1 -1
- package/build/godot/operations/script_check.gd +2 -2
- package/build/godot/operations/serialisation.gd +4 -4
- package/build/godot/tests/listed.gd +9 -9
- package/build/keeper.js +511 -162
- package/package.json +1 -1
package/build/keeper.js
CHANGED
|
@@ -6946,13 +6946,20 @@ var require_public_api = __commonJS(function(exports) {
|
|
|
6946
6946
|
});
|
|
6947
6947
|
|
|
6948
6948
|
// src/keeper.ts
|
|
6949
|
-
import { closeSync as closeSync3, existsSync as
|
|
6949
|
+
import { closeSync as closeSync3, existsSync as existsSync5, mkdtempSync as mkdtempSync4, openSync as openSync4, readFileSync as readFileSync10, rmSync as rmSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
6950
6950
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
6951
|
-
import { join as
|
|
6951
|
+
import { join as join11 } from "node:path";
|
|
6952
6952
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
6953
6953
|
|
|
6954
6954
|
// src/alive.ts
|
|
6955
6955
|
import process2 from "node:process";
|
|
6956
|
+
|
|
6957
|
+
// src/errors.ts
|
|
6958
|
+
function errorCode(error) {
|
|
6959
|
+
return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
6960
|
+
}
|
|
6961
|
+
|
|
6962
|
+
// src/alive.ts
|
|
6956
6963
|
function exitOf(child) {
|
|
6957
6964
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
6958
6965
|
return Promise.resolve({ code: child.exitCode, signal: child.signalCode });
|
|
@@ -6971,29 +6978,29 @@ function alive(pid) {
|
|
|
6971
6978
|
process2.kill(pid, 0);
|
|
6972
6979
|
return true;
|
|
6973
6980
|
} catch (error) {
|
|
6974
|
-
return error
|
|
6981
|
+
return errorCode(error) === "EPERM";
|
|
6975
6982
|
}
|
|
6976
6983
|
}
|
|
6977
6984
|
|
|
6978
6985
|
// src/desktop.ts
|
|
6979
|
-
import { readFileSync as
|
|
6986
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
6980
6987
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
6981
6988
|
|
|
6982
6989
|
// src/compiled-helper.ts
|
|
6983
6990
|
import { createHash } from "node:crypto";
|
|
6984
6991
|
import {
|
|
6985
6992
|
closeSync,
|
|
6986
|
-
existsSync,
|
|
6993
|
+
existsSync as existsSync2,
|
|
6987
6994
|
mkdtempSync,
|
|
6988
6995
|
openSync,
|
|
6989
|
-
readFileSync,
|
|
6990
|
-
rmSync,
|
|
6996
|
+
readFileSync as readFileSync2,
|
|
6997
|
+
rmSync as rmSync2,
|
|
6991
6998
|
statSync,
|
|
6992
|
-
writeFileSync,
|
|
6999
|
+
writeFileSync as writeFileSync2,
|
|
6993
7000
|
writeSync
|
|
6994
7001
|
} from "node:fs";
|
|
6995
7002
|
import { tmpdir } from "node:os";
|
|
6996
|
-
import { join } from "node:path";
|
|
7003
|
+
import { join as join2 } from "node:path";
|
|
6997
7004
|
import { setTimeout as delay } from "node:timers/promises";
|
|
6998
7005
|
|
|
6999
7006
|
// src/spawn.ts
|
|
@@ -7003,13 +7010,241 @@ import {
|
|
|
7003
7010
|
spawn,
|
|
7004
7011
|
spawnSync
|
|
7005
7012
|
} from "node:child_process";
|
|
7013
|
+
|
|
7014
|
+
// src/uid-cache.ts
|
|
7015
|
+
import {
|
|
7016
|
+
existsSync,
|
|
7017
|
+
readdirSync,
|
|
7018
|
+
readFileSync,
|
|
7019
|
+
renameSync,
|
|
7020
|
+
rmSync,
|
|
7021
|
+
writeFileSync
|
|
7022
|
+
} from "node:fs";
|
|
7023
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
7024
|
+
import { fileURLToPath } from "node:url";
|
|
7025
|
+
var CACHE = join(".godot", "uid_cache.bin");
|
|
7026
|
+
var RES = "res://";
|
|
7027
|
+
var UID = "uid://";
|
|
7028
|
+
var NOTHING = { moved: [], dropped: [] };
|
|
7029
|
+
function uidCacheEntries(data) {
|
|
7030
|
+
if (data.length < 4) {
|
|
7031
|
+
return null;
|
|
7032
|
+
}
|
|
7033
|
+
const count = data.readUInt32LE(0);
|
|
7034
|
+
const paths = new Map;
|
|
7035
|
+
let at = 4;
|
|
7036
|
+
for (let entry = 0;entry < count; entry++) {
|
|
7037
|
+
if (at + 12 > data.length) {
|
|
7038
|
+
return null;
|
|
7039
|
+
}
|
|
7040
|
+
const id = data.readBigUInt64LE(at);
|
|
7041
|
+
const length = data.readUInt32LE(at + 8);
|
|
7042
|
+
at += 12;
|
|
7043
|
+
if (at + length > data.length) {
|
|
7044
|
+
return null;
|
|
7045
|
+
}
|
|
7046
|
+
paths.set(id, data.toString("utf8", at, at + length));
|
|
7047
|
+
at += length;
|
|
7048
|
+
}
|
|
7049
|
+
return [...paths];
|
|
7050
|
+
}
|
|
7051
|
+
function encodedUidCache(entries) {
|
|
7052
|
+
const parts = [Buffer.alloc(4)];
|
|
7053
|
+
parts[0]?.writeUInt32LE(entries.length, 0);
|
|
7054
|
+
for (const [id, path] of entries) {
|
|
7055
|
+
const named = Buffer.from(path, "utf8");
|
|
7056
|
+
const head = Buffer.alloc(12);
|
|
7057
|
+
head.writeBigUInt64LE(id, 0);
|
|
7058
|
+
head.writeUInt32LE(named.length, 8);
|
|
7059
|
+
parts.push(head, named);
|
|
7060
|
+
}
|
|
7061
|
+
return Buffer.concat(parts);
|
|
7062
|
+
}
|
|
7063
|
+
function uidOfText(text) {
|
|
7064
|
+
if (!text.startsWith(UID) || text.length === UID.length) {
|
|
7065
|
+
return null;
|
|
7066
|
+
}
|
|
7067
|
+
let id = 0n;
|
|
7068
|
+
for (const character of text.slice(UID.length)) {
|
|
7069
|
+
const code = character.charCodeAt(0);
|
|
7070
|
+
let digit;
|
|
7071
|
+
if (code >= 97 && code <= 122) {
|
|
7072
|
+
digit = code - 97;
|
|
7073
|
+
} else if (code >= 48 && code <= 57) {
|
|
7074
|
+
digit = code - 48 + 25;
|
|
7075
|
+
} else {
|
|
7076
|
+
return null;
|
|
7077
|
+
}
|
|
7078
|
+
id = id * 34n + BigInt(digit);
|
|
7079
|
+
}
|
|
7080
|
+
return id & 0x7fffffffffffffffn;
|
|
7081
|
+
}
|
|
7082
|
+
function presenceIn(projectPath) {
|
|
7083
|
+
const listed = new Map;
|
|
7084
|
+
return (path) => {
|
|
7085
|
+
const inside = path.slice(RES.length);
|
|
7086
|
+
const slash = inside.lastIndexOf("/");
|
|
7087
|
+
const folder = slash < 0 ? "" : inside.slice(0, slash);
|
|
7088
|
+
let names = listed.get(folder);
|
|
7089
|
+
if (names === undefined) {
|
|
7090
|
+
try {
|
|
7091
|
+
names = new Set(readdirSync(join(projectPath, folder)));
|
|
7092
|
+
} catch {
|
|
7093
|
+
names = new Set;
|
|
7094
|
+
}
|
|
7095
|
+
listed.set(folder, names);
|
|
7096
|
+
}
|
|
7097
|
+
return names.has(inside.slice(slash + 1));
|
|
7098
|
+
};
|
|
7099
|
+
}
|
|
7100
|
+
var IMPORT_UID = /^uid="(uid:\/\/[^"]*)"/m;
|
|
7101
|
+
var HEADER_UID = /^\[gd_(?:scene|resource)\b[^\]\n]*\buid="(uid:\/\/[^"]*)"/;
|
|
7102
|
+
function declared(path, name) {
|
|
7103
|
+
const read = () => {
|
|
7104
|
+
try {
|
|
7105
|
+
return readFileSync(path, "utf8");
|
|
7106
|
+
} catch {
|
|
7107
|
+
return null;
|
|
7108
|
+
}
|
|
7109
|
+
};
|
|
7110
|
+
if (name.endsWith(".uid")) {
|
|
7111
|
+
const text = read()?.trim();
|
|
7112
|
+
return text === undefined ? null : [text, name.slice(0, -".uid".length)];
|
|
7113
|
+
}
|
|
7114
|
+
const pattern = name.endsWith(".import") ? IMPORT_UID : name.endsWith(".tscn") || name.endsWith(".tres") ? HEADER_UID : null;
|
|
7115
|
+
const text = pattern === null ? undefined : read()?.match(pattern)?.[1];
|
|
7116
|
+
if (text === undefined) {
|
|
7117
|
+
return null;
|
|
7118
|
+
}
|
|
7119
|
+
return [text, name.endsWith(".import") ? name.slice(0, -".import".length) : name];
|
|
7120
|
+
}
|
|
7121
|
+
function declaringFiles(projectPath, wanted) {
|
|
7122
|
+
const found = new Map;
|
|
7123
|
+
const visit = (directory, prefix) => {
|
|
7124
|
+
let entries;
|
|
7125
|
+
try {
|
|
7126
|
+
entries = readdirSync(directory, { withFileTypes: true });
|
|
7127
|
+
} catch {
|
|
7128
|
+
return;
|
|
7129
|
+
}
|
|
7130
|
+
if (entries.some((entry) => entry.name === ".gdignore")) {
|
|
7131
|
+
return;
|
|
7132
|
+
}
|
|
7133
|
+
for (const entry of entries) {
|
|
7134
|
+
if (found.size === wanted.size) {
|
|
7135
|
+
return;
|
|
7136
|
+
}
|
|
7137
|
+
if (entry.name.startsWith(".")) {
|
|
7138
|
+
continue;
|
|
7139
|
+
}
|
|
7140
|
+
const path = join(directory, entry.name);
|
|
7141
|
+
const spelled = `${prefix}${entry.name}`;
|
|
7142
|
+
if (entry.isDirectory()) {
|
|
7143
|
+
visit(path, `${spelled}/`);
|
|
7144
|
+
continue;
|
|
7145
|
+
}
|
|
7146
|
+
const declaration = entry.isFile() ? declared(path, spelled) : null;
|
|
7147
|
+
const id = declaration === null ? null : uidOfText(declaration[0]);
|
|
7148
|
+
if (declaration !== null && id !== null && wanted.has(id) && !found.has(id)) {
|
|
7149
|
+
found.set(id, `${RES}${declaration[1]}`);
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
};
|
|
7153
|
+
visit(projectPath, "");
|
|
7154
|
+
return found;
|
|
7155
|
+
}
|
|
7156
|
+
function mendUidCache(projectPath) {
|
|
7157
|
+
const cache = join(projectPath, CACHE);
|
|
7158
|
+
let data;
|
|
7159
|
+
try {
|
|
7160
|
+
data = readFileSync(cache);
|
|
7161
|
+
} catch {
|
|
7162
|
+
return NOTHING;
|
|
7163
|
+
}
|
|
7164
|
+
const entries = uidCacheEntries(data);
|
|
7165
|
+
if (entries === null) {
|
|
7166
|
+
return NOTHING;
|
|
7167
|
+
}
|
|
7168
|
+
const present = presenceIn(projectPath);
|
|
7169
|
+
const gone = entries.filter(([, path]) => path.startsWith(RES) && !present(path));
|
|
7170
|
+
if (gone.length === 0) {
|
|
7171
|
+
return NOTHING;
|
|
7172
|
+
}
|
|
7173
|
+
const goneIds = new Set(gone.map(([id]) => id));
|
|
7174
|
+
const now = declaringFiles(projectPath, goneIds);
|
|
7175
|
+
const moved = [];
|
|
7176
|
+
const dropped = [];
|
|
7177
|
+
for (const [id, path] of gone) {
|
|
7178
|
+
const to = now.get(id);
|
|
7179
|
+
if (to === undefined) {
|
|
7180
|
+
dropped.push([id, path]);
|
|
7181
|
+
} else {
|
|
7182
|
+
moved.push([id, path, to]);
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
const written = `${cache}.${String(process.pid)}.mending`;
|
|
7186
|
+
const kept = entries.flatMap(([id, path]) => {
|
|
7187
|
+
if (!goneIds.has(id)) {
|
|
7188
|
+
return [[id, path]];
|
|
7189
|
+
}
|
|
7190
|
+
const to = now.get(id);
|
|
7191
|
+
return to === undefined ? [] : [[id, to]];
|
|
7192
|
+
});
|
|
7193
|
+
writeFileSync(written, encodedUidCache(kept));
|
|
7194
|
+
try {
|
|
7195
|
+
renameSync(written, cache);
|
|
7196
|
+
} catch (error) {
|
|
7197
|
+
rmSync(written, { force: true });
|
|
7198
|
+
throw error;
|
|
7199
|
+
}
|
|
7200
|
+
return { moved, dropped };
|
|
7201
|
+
}
|
|
7202
|
+
function projectStarted(args, cwd) {
|
|
7203
|
+
const at = args.indexOf("--path");
|
|
7204
|
+
const named = at < 0 ? undefined : args[at + 1];
|
|
7205
|
+
if (named === undefined) {
|
|
7206
|
+
return null;
|
|
7207
|
+
}
|
|
7208
|
+
const from = cwd === undefined ? process.cwd() : cwd instanceof URL ? fileURLToPath(cwd) : cwd;
|
|
7209
|
+
const project = isAbsolute(named) ? named : resolve(from, named);
|
|
7210
|
+
return existsSync(join(project, "project.godot")) ? project : null;
|
|
7211
|
+
}
|
|
7212
|
+
function mendBeforeStart(args, cwd) {
|
|
7213
|
+
const project = projectStarted(args, cwd);
|
|
7214
|
+
if (project === null) {
|
|
7215
|
+
return;
|
|
7216
|
+
}
|
|
7217
|
+
const where = join(project, CACHE);
|
|
7218
|
+
try {
|
|
7219
|
+
const { moved, dropped } = mendUidCache(project);
|
|
7220
|
+
if (moved.length > 0) {
|
|
7221
|
+
const named = moved.map(([, from, to]) => `${from} to ${to}`).join(", ");
|
|
7222
|
+
process.stderr.write(`uid cache: moved what names a file gone in ${where}: ${named}
|
|
7223
|
+
`);
|
|
7224
|
+
}
|
|
7225
|
+
if (dropped.length > 0) {
|
|
7226
|
+
const named = dropped.map(([, path]) => path).join(", ");
|
|
7227
|
+
process.stderr.write(`uid cache: dropped what names a file gone from ${where}: ${named}
|
|
7228
|
+
`);
|
|
7229
|
+
}
|
|
7230
|
+
} catch (error) {
|
|
7231
|
+
const said = error instanceof Error ? error.message : String(error);
|
|
7232
|
+
process.stderr.write(`uid cache: could not rewrite ${where}, which names files gone: ${said}
|
|
7233
|
+
`);
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
|
|
7237
|
+
// src/spawn.ts
|
|
7006
7238
|
function spawnHidden(command, args, options = {}) {
|
|
7239
|
+
mendBeforeStart(args, options.cwd);
|
|
7007
7240
|
return spawn(command, [...args], { ...options, windowsHide: true });
|
|
7008
7241
|
}
|
|
7009
7242
|
function spawnShown(command, args, options = {}) {
|
|
7243
|
+
mendBeforeStart(args, options.cwd);
|
|
7010
7244
|
return spawn(command, [...args], { ...options, windowsHide: false });
|
|
7011
7245
|
}
|
|
7012
7246
|
function runHidden(command, args, options = {}) {
|
|
7247
|
+
mendBeforeStart(args, options.cwd ?? undefined);
|
|
7013
7248
|
return new Promise((resolve, reject) => {
|
|
7014
7249
|
execFile(command, [...args], { ...options, encoding: "utf8", windowsHide: true }, (error, stdout, stderr) => {
|
|
7015
7250
|
if (error !== null) {
|
|
@@ -7037,14 +7272,14 @@ class CompiledHelper {
|
|
|
7037
7272
|
this.digest = createHash("sha256").update(source).digest("hex").slice(0, 16);
|
|
7038
7273
|
}
|
|
7039
7274
|
assembly(directory = tmpdir()) {
|
|
7040
|
-
return
|
|
7275
|
+
return join2(directory, `${this.file}-${this.digest}.dll`);
|
|
7041
7276
|
}
|
|
7042
7277
|
async ensure(directory = tmpdir(), budgetMs = HELPER_COMPILE_MS, wait = true) {
|
|
7043
7278
|
const assembly = this.assembly(directory);
|
|
7044
7279
|
const lock = `${assembly}.compiling`;
|
|
7045
7280
|
const until = Date.now() + budgetMs;
|
|
7046
7281
|
while (Date.now() < until) {
|
|
7047
|
-
if (
|
|
7282
|
+
if (existsSync2(assembly)) {
|
|
7048
7283
|
return null;
|
|
7049
7284
|
}
|
|
7050
7285
|
let mine = false;
|
|
@@ -7058,14 +7293,14 @@ class CompiledHelper {
|
|
|
7058
7293
|
try {
|
|
7059
7294
|
return await this.compile(directory, assembly, until - Date.now());
|
|
7060
7295
|
} finally {
|
|
7061
|
-
|
|
7296
|
+
rmSync2(lock, { force: true });
|
|
7062
7297
|
}
|
|
7063
7298
|
}
|
|
7064
7299
|
try {
|
|
7065
|
-
const holder = Number(
|
|
7300
|
+
const holder = Number(readFileSync2(lock, "utf8").trim());
|
|
7066
7301
|
const old = Date.now() - statSync(lock).mtimeMs > budgetMs;
|
|
7067
7302
|
if (old || Number.isInteger(holder) && holder > 0 && !alive(holder)) {
|
|
7068
|
-
|
|
7303
|
+
rmSync2(lock, { force: true });
|
|
7069
7304
|
continue;
|
|
7070
7305
|
}
|
|
7071
7306
|
} catch {}
|
|
@@ -7077,9 +7312,9 @@ class CompiledHelper {
|
|
|
7077
7312
|
return `the ${this.named} was not compiled within ${String(budgetMs)} ms`;
|
|
7078
7313
|
}
|
|
7079
7314
|
async compile(directory, assembly, budgetMs) {
|
|
7080
|
-
const scratch = mkdtempSync(
|
|
7081
|
-
const source =
|
|
7082
|
-
|
|
7315
|
+
const scratch = mkdtempSync(join2(directory, `${this.file}-source-`));
|
|
7316
|
+
const source = join2(scratch, "helper.cs");
|
|
7317
|
+
writeFileSync2(source, this.source, "utf8");
|
|
7083
7318
|
const literal = (path) => `'${path.replaceAll("'", "''")}'`;
|
|
7084
7319
|
const script = [
|
|
7085
7320
|
"$ErrorActionPreference = 'Stop'",
|
|
@@ -7116,11 +7351,11 @@ class CompiledHelper {
|
|
|
7116
7351
|
});
|
|
7117
7352
|
compiler.once("close", (code) => {
|
|
7118
7353
|
clearTimeout(timer);
|
|
7119
|
-
resolve(
|
|
7354
|
+
resolve(existsSync2(assembly) ? null : `Windows PowerShell could not compile the ${this.named}${code === null ? " in time" : ""}: ${complained.trim() || `exit code ${String(code)}`}`);
|
|
7120
7355
|
});
|
|
7121
7356
|
});
|
|
7122
7357
|
} finally {
|
|
7123
|
-
|
|
7358
|
+
rmSync2(scratch, { recursive: true, force: true });
|
|
7124
7359
|
}
|
|
7125
7360
|
}
|
|
7126
7361
|
}
|
|
@@ -7379,7 +7614,7 @@ function windowsCommandLine(command, args) {
|
|
|
7379
7614
|
}
|
|
7380
7615
|
function helperFailure(file) {
|
|
7381
7616
|
try {
|
|
7382
|
-
const said =
|
|
7617
|
+
const said = readFileSync3(file, "utf8").trim();
|
|
7383
7618
|
return said === "" ? null : said;
|
|
7384
7619
|
} catch {
|
|
7385
7620
|
return null;
|
|
@@ -7388,11 +7623,12 @@ function helperFailure(file) {
|
|
|
7388
7623
|
function helperStep(stepFile) {
|
|
7389
7624
|
let step = null;
|
|
7390
7625
|
try {
|
|
7391
|
-
step =
|
|
7626
|
+
step = readFileSync3(stepFile, "utf8").trim();
|
|
7392
7627
|
} catch {}
|
|
7393
7628
|
return step === null || step === "" ? "Windows PowerShell had not begun running the helper" : `the helper was ${step}`;
|
|
7394
7629
|
}
|
|
7395
7630
|
function throughHelper(how, command, args, files, assembly = helperAssembly()) {
|
|
7631
|
+
mendBeforeStart(args, how.directory);
|
|
7396
7632
|
const fields = [
|
|
7397
7633
|
how.desktop ?? "",
|
|
7398
7634
|
windowsCommandLine(command, args),
|
|
@@ -7403,7 +7639,7 @@ function throughHelper(how, command, args, files, assembly = helperAssembly()) {
|
|
|
7403
7639
|
files.step,
|
|
7404
7640
|
how.affinity === undefined ? "" : how.affinity.toString()
|
|
7405
7641
|
];
|
|
7406
|
-
|
|
7642
|
+
writeFileSync3(files.spec, fields.map((field) => Buffer.from(field, "utf8").toString("base64")).join(`
|
|
7407
7643
|
`), "utf8");
|
|
7408
7644
|
const literal = (path) => `'${path.replaceAll("'", "''")}'`;
|
|
7409
7645
|
const script = [
|
|
@@ -7435,12 +7671,12 @@ function throughHelper(how, command, args, files, assembly = helperAssembly()) {
|
|
|
7435
7671
|
// src/engine-slots.ts
|
|
7436
7672
|
import {
|
|
7437
7673
|
closeSync as closeSync2,
|
|
7438
|
-
existsSync as
|
|
7674
|
+
existsSync as existsSync3,
|
|
7439
7675
|
mkdirSync,
|
|
7440
7676
|
openSync as openSync2,
|
|
7441
|
-
readdirSync,
|
|
7442
|
-
readFileSync as
|
|
7443
|
-
rmSync as
|
|
7677
|
+
readdirSync as readdirSync2,
|
|
7678
|
+
readFileSync as readFileSync6,
|
|
7679
|
+
rmSync as rmSync4,
|
|
7444
7680
|
statSync as statSync3,
|
|
7445
7681
|
watch,
|
|
7446
7682
|
writeSync as writeSync2
|
|
@@ -7486,18 +7722,19 @@ var buffered = "";
|
|
|
7486
7722
|
var next = 1;
|
|
7487
7723
|
var out = null;
|
|
7488
7724
|
var queued = [];
|
|
7725
|
+
function holdOn(pipe, wanted) {
|
|
7726
|
+
const call = Reflect.get(pipe, wanted ? "ref" : "unref");
|
|
7727
|
+
if (typeof call === "function") {
|
|
7728
|
+
Reflect.apply(call, pipe, []);
|
|
7729
|
+
}
|
|
7730
|
+
}
|
|
7489
7731
|
var held = false;
|
|
7490
7732
|
function holding(child, wanted) {
|
|
7491
7733
|
if (held === wanted) {
|
|
7492
7734
|
return;
|
|
7493
7735
|
}
|
|
7494
7736
|
held = wanted;
|
|
7495
|
-
|
|
7496
|
-
if (wanted) {
|
|
7497
|
-
stdout.ref?.();
|
|
7498
|
-
} else {
|
|
7499
|
-
stdout.unref?.();
|
|
7500
|
-
}
|
|
7737
|
+
holdOn(child.stdout, wanted);
|
|
7501
7738
|
}
|
|
7502
7739
|
function running() {
|
|
7503
7740
|
if (helper?.exitCode === null && helper.signalCode === null) {
|
|
@@ -7539,8 +7776,8 @@ function running() {
|
|
|
7539
7776
|
child.once("exit", gone);
|
|
7540
7777
|
child.once("error", gone);
|
|
7541
7778
|
child.unref();
|
|
7542
|
-
child.stdin
|
|
7543
|
-
child.stderr
|
|
7779
|
+
holdOn(child.stdin, false);
|
|
7780
|
+
holdOn(child.stderr, false);
|
|
7544
7781
|
held = true;
|
|
7545
7782
|
holding(child, false);
|
|
7546
7783
|
helper = child;
|
|
@@ -7969,14 +8206,14 @@ async function loadingTheTable() {
|
|
|
7969
8206
|
return `$null = [Reflection.Assembly]::LoadFrom('${TABLE.assembly().replaceAll("'", "''")}')`;
|
|
7970
8207
|
}
|
|
7971
8208
|
async function askProcessTable(call, withinMs) {
|
|
7972
|
-
return askWindows(`${await loadingTheTable()}; [GdhProcessTable]::${call}`, withinMs);
|
|
8209
|
+
return await askWindows(`${await loadingTheTable()}; [GdhProcessTable]::${call}`, withinMs);
|
|
7973
8210
|
}
|
|
7974
8211
|
|
|
7975
8212
|
// src/engine-spent.ts
|
|
7976
8213
|
var watched = new Set;
|
|
7977
8214
|
|
|
7978
8215
|
// src/harnesses.ts
|
|
7979
|
-
import { basename as basename2, dirname as dirname2, isAbsolute as
|
|
8216
|
+
import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute3, join as join4, relative as relative2, resolve as resolve3 } from "node:path";
|
|
7980
8217
|
|
|
7981
8218
|
// node_modules/yaml/dist/index.js
|
|
7982
8219
|
var composer = require_composer();
|
|
@@ -8026,13 +8263,13 @@ var $visitAsync = visit.visitAsync;
|
|
|
8026
8263
|
|
|
8027
8264
|
// src/paths.ts
|
|
8028
8265
|
import { realpathSync, statSync as statSync2 } from "node:fs";
|
|
8029
|
-
import { basename, dirname, isAbsolute, join as
|
|
8266
|
+
import { basename, dirname, isAbsolute as isAbsolute2, join as join3, relative, resolve as resolve2, sep } from "node:path";
|
|
8030
8267
|
function realAsFarAsItExists(path) {
|
|
8031
8268
|
const missing = [];
|
|
8032
8269
|
let at = path;
|
|
8033
8270
|
for (;; ) {
|
|
8034
8271
|
try {
|
|
8035
|
-
return
|
|
8272
|
+
return join3(realpathSync.native(at), ...missing);
|
|
8036
8273
|
} catch {
|
|
8037
8274
|
const parent = dirname(at);
|
|
8038
8275
|
if (parent === at) {
|
|
@@ -8044,6 +8281,14 @@ function realAsFarAsItExists(path) {
|
|
|
8044
8281
|
}
|
|
8045
8282
|
}
|
|
8046
8283
|
|
|
8284
|
+
// src/records.ts
|
|
8285
|
+
function isRecord(value) {
|
|
8286
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8287
|
+
}
|
|
8288
|
+
function isStringList(value) {
|
|
8289
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
8290
|
+
}
|
|
8291
|
+
|
|
8047
8292
|
// src/harnesses.ts
|
|
8048
8293
|
var SERVER_KEY = "gdharness";
|
|
8049
8294
|
function tomlArray(values) {
|
|
@@ -8066,7 +8311,7 @@ var HARNESSES = [
|
|
|
8066
8311
|
shape: "plain",
|
|
8067
8312
|
home: ".claude",
|
|
8068
8313
|
marker: ".claude",
|
|
8069
|
-
skills: { dir:
|
|
8314
|
+
skills: { dir: join4(".claude", "skills"), shared: false }
|
|
8070
8315
|
},
|
|
8071
8316
|
{
|
|
8072
8317
|
id: "copilot-cli",
|
|
@@ -8076,7 +8321,7 @@ var HARNESSES = [
|
|
|
8076
8321
|
container: "mcpServers",
|
|
8077
8322
|
shape: "plain",
|
|
8078
8323
|
home: ".copilot",
|
|
8079
|
-
skills: { dir:
|
|
8324
|
+
skills: { dir: join4(".github", "skills"), shared: true },
|
|
8080
8325
|
manual: "Trust the folder when Copilot CLI first asks, or it reads no config here."
|
|
8081
8326
|
},
|
|
8082
8327
|
{
|
|
@@ -8102,22 +8347,22 @@ var HARNESSES = [
|
|
|
8102
8347
|
id: "cursor",
|
|
8103
8348
|
name: "Cursor",
|
|
8104
8349
|
scope: "project",
|
|
8105
|
-
file:
|
|
8350
|
+
file: join4(".cursor", "mcp.json"),
|
|
8106
8351
|
container: "mcpServers",
|
|
8107
8352
|
shape: "plain",
|
|
8108
8353
|
home: ".cursor",
|
|
8109
|
-
skills: { dir:
|
|
8354
|
+
skills: { dir: join4(".cursor", "skills"), shared: true },
|
|
8110
8355
|
manual: "Cursor asks before each tool call by default, and the server can be toggled off."
|
|
8111
8356
|
},
|
|
8112
8357
|
{
|
|
8113
8358
|
id: "vscode",
|
|
8114
8359
|
name: "VS Code",
|
|
8115
8360
|
scope: "project",
|
|
8116
|
-
file:
|
|
8361
|
+
file: join4(".vscode", "mcp.json"),
|
|
8117
8362
|
container: "servers",
|
|
8118
8363
|
shape: "typed",
|
|
8119
8364
|
home: ".vscode",
|
|
8120
|
-
skills: { dir:
|
|
8365
|
+
skills: { dir: join4(".github", "skills"), shared: true },
|
|
8121
8366
|
manual: "VS Code asks you to trust a server the first time it starts one."
|
|
8122
8367
|
},
|
|
8123
8368
|
{
|
|
@@ -8127,45 +8372,45 @@ var HARNESSES = [
|
|
|
8127
8372
|
file: "opencode.json",
|
|
8128
8373
|
container: "mcp",
|
|
8129
8374
|
shape: "opencode",
|
|
8130
|
-
home:
|
|
8375
|
+
home: join4(".config", "opencode"),
|
|
8131
8376
|
marker: ".opencode",
|
|
8132
|
-
skills: { dir:
|
|
8377
|
+
skills: { dir: join4(".opencode", "skills"), shared: true }
|
|
8133
8378
|
},
|
|
8134
8379
|
{
|
|
8135
8380
|
id: "junie",
|
|
8136
8381
|
name: "Junie",
|
|
8137
8382
|
scope: "project",
|
|
8138
|
-
file:
|
|
8383
|
+
file: join4(".junie", "mcp", "mcp.json"),
|
|
8139
8384
|
container: "mcpServers",
|
|
8140
8385
|
shape: "plain",
|
|
8141
8386
|
home: ".junie",
|
|
8142
|
-
skills: { dir:
|
|
8387
|
+
skills: { dir: join4(".junie", "skills"), shared: true }
|
|
8143
8388
|
},
|
|
8144
8389
|
{
|
|
8145
8390
|
id: "kiro",
|
|
8146
8391
|
name: "Kiro",
|
|
8147
8392
|
scope: "project",
|
|
8148
|
-
file:
|
|
8393
|
+
file: join4(".kiro", "settings", "mcp.json"),
|
|
8149
8394
|
container: "mcpServers",
|
|
8150
8395
|
shape: "plain",
|
|
8151
8396
|
home: ".kiro",
|
|
8152
|
-
skills: { dir:
|
|
8397
|
+
skills: { dir: join4(".kiro", "skills"), shared: false }
|
|
8153
8398
|
},
|
|
8154
8399
|
{
|
|
8155
8400
|
id: "gemini",
|
|
8156
8401
|
name: "Gemini CLI",
|
|
8157
8402
|
scope: "project",
|
|
8158
|
-
file:
|
|
8403
|
+
file: join4(".gemini", "settings.json"),
|
|
8159
8404
|
container: "mcpServers",
|
|
8160
8405
|
shape: "plain",
|
|
8161
8406
|
home: ".gemini",
|
|
8162
|
-
skills: { dir:
|
|
8407
|
+
skills: { dir: join4(".gemini", "skills"), shared: true }
|
|
8163
8408
|
},
|
|
8164
8409
|
{
|
|
8165
8410
|
id: "roo",
|
|
8166
8411
|
name: "Roo Code",
|
|
8167
8412
|
scope: "project",
|
|
8168
|
-
file:
|
|
8413
|
+
file: join4(".roo", "mcp.json"),
|
|
8169
8414
|
container: "mcpServers",
|
|
8170
8415
|
shape: "plain"
|
|
8171
8416
|
},
|
|
@@ -8173,7 +8418,7 @@ var HARNESSES = [
|
|
|
8173
8418
|
id: "kilo",
|
|
8174
8419
|
name: "Kilo Code",
|
|
8175
8420
|
scope: "project",
|
|
8176
|
-
file:
|
|
8421
|
+
file: join4(".kilocode", "mcp.json"),
|
|
8177
8422
|
container: "mcpServers",
|
|
8178
8423
|
shape: "plain"
|
|
8179
8424
|
},
|
|
@@ -8181,16 +8426,16 @@ var HARNESSES = [
|
|
|
8181
8426
|
id: "amazon-q",
|
|
8182
8427
|
name: "Amazon Q Developer CLI",
|
|
8183
8428
|
scope: "project",
|
|
8184
|
-
file:
|
|
8429
|
+
file: join4(".amazonq", "mcp.json"),
|
|
8185
8430
|
container: "mcpServers",
|
|
8186
8431
|
shape: "plain",
|
|
8187
|
-
home:
|
|
8432
|
+
home: join4(".aws", "amazonq")
|
|
8188
8433
|
},
|
|
8189
8434
|
{
|
|
8190
8435
|
id: "zed",
|
|
8191
8436
|
name: "Zed",
|
|
8192
8437
|
scope: "project",
|
|
8193
|
-
file:
|
|
8438
|
+
file: join4(".zed", "settings.json"),
|
|
8194
8439
|
container: "context_servers",
|
|
8195
8440
|
shape: "plain"
|
|
8196
8441
|
},
|
|
@@ -8198,16 +8443,16 @@ var HARNESSES = [
|
|
|
8198
8443
|
id: "amp",
|
|
8199
8444
|
name: "Amp",
|
|
8200
8445
|
scope: "project",
|
|
8201
|
-
file:
|
|
8446
|
+
file: join4(".amp", "settings.json"),
|
|
8202
8447
|
container: "amp.mcpServers",
|
|
8203
8448
|
shape: "plain",
|
|
8204
|
-
home:
|
|
8449
|
+
home: join4(".config", "amp")
|
|
8205
8450
|
},
|
|
8206
8451
|
{
|
|
8207
8452
|
id: "warp",
|
|
8208
8453
|
name: "Warp",
|
|
8209
8454
|
scope: "project",
|
|
8210
|
-
file:
|
|
8455
|
+
file: join4(".warp", ".mcp.json"),
|
|
8211
8456
|
container: "mcpServers",
|
|
8212
8457
|
shape: "plain",
|
|
8213
8458
|
home: ".warp",
|
|
@@ -8217,7 +8462,7 @@ var HARNESSES = [
|
|
|
8217
8462
|
id: "trae",
|
|
8218
8463
|
name: "Trae",
|
|
8219
8464
|
scope: "project",
|
|
8220
|
-
file:
|
|
8465
|
+
file: join4(".trae", "mcp.json"),
|
|
8221
8466
|
container: "mcpServers",
|
|
8222
8467
|
shape: "plain",
|
|
8223
8468
|
home: ".trae"
|
|
@@ -8226,7 +8471,7 @@ var HARNESSES = [
|
|
|
8226
8471
|
id: "factory",
|
|
8227
8472
|
name: "Factory Droid",
|
|
8228
8473
|
scope: "project",
|
|
8229
|
-
file:
|
|
8474
|
+
file: join4(".factory", "mcp.json"),
|
|
8230
8475
|
container: "mcpServers",
|
|
8231
8476
|
shape: "typed",
|
|
8232
8477
|
home: ".factory"
|
|
@@ -8235,7 +8480,7 @@ var HARNESSES = [
|
|
|
8235
8480
|
id: "tabnine",
|
|
8236
8481
|
name: "Tabnine",
|
|
8237
8482
|
scope: "project",
|
|
8238
|
-
file:
|
|
8483
|
+
file: join4(".tabnine", "mcp_servers.json"),
|
|
8239
8484
|
container: "mcpServers",
|
|
8240
8485
|
shape: "plain",
|
|
8241
8486
|
home: ".tabnine"
|
|
@@ -8252,7 +8497,7 @@ var HARNESSES = [
|
|
|
8252
8497
|
id: "pi",
|
|
8253
8498
|
name: "pi",
|
|
8254
8499
|
scope: "project",
|
|
8255
|
-
file:
|
|
8500
|
+
file: join4(".pi", "mcp.json"),
|
|
8256
8501
|
container: "mcpServers",
|
|
8257
8502
|
shape: "plain",
|
|
8258
8503
|
home: ".pi"
|
|
@@ -8261,7 +8506,7 @@ var HARNESSES = [
|
|
|
8261
8506
|
id: "mistral-vibe",
|
|
8262
8507
|
name: "Mistral Vibe",
|
|
8263
8508
|
scope: "project",
|
|
8264
|
-
file:
|
|
8509
|
+
file: join4(".vibe", "config.toml"),
|
|
8265
8510
|
container: "mcp_servers",
|
|
8266
8511
|
shape: "plain",
|
|
8267
8512
|
toml: {
|
|
@@ -8317,7 +8562,7 @@ var HARNESSES = [
|
|
|
8317
8562
|
id: "codex",
|
|
8318
8563
|
name: "Codex CLI",
|
|
8319
8564
|
scope: "home",
|
|
8320
|
-
file:
|
|
8565
|
+
file: join4(".codex", "config.toml"),
|
|
8321
8566
|
container: "mcp_servers",
|
|
8322
8567
|
shape: "plain",
|
|
8323
8568
|
manual: "Codex reads its config at startup, so restart it.",
|
|
@@ -8336,20 +8581,20 @@ var HARNESSES = [
|
|
|
8336
8581
|
id: "cline",
|
|
8337
8582
|
name: "Cline",
|
|
8338
8583
|
scope: "home",
|
|
8339
|
-
file:
|
|
8584
|
+
file: join4(".cline", "data", "settings", "cline_mcp_settings.json"),
|
|
8340
8585
|
container: "mcpServers",
|
|
8341
8586
|
shape: "plain",
|
|
8342
8587
|
marker: ".cline",
|
|
8343
|
-
skills: { dir:
|
|
8588
|
+
skills: { dir: join4(".cline", "skills"), shared: false }
|
|
8344
8589
|
},
|
|
8345
8590
|
{
|
|
8346
8591
|
id: "goose",
|
|
8347
8592
|
name: "Goose",
|
|
8348
8593
|
scope: "home",
|
|
8349
8594
|
file: {
|
|
8350
|
-
win32: { appData:
|
|
8351
|
-
darwin:
|
|
8352
|
-
linux:
|
|
8595
|
+
win32: { appData: join4("Block", "goose", "config", "config.yaml") },
|
|
8596
|
+
darwin: join4(".config", "goose", "config.yaml"),
|
|
8597
|
+
linux: join4(".config", "goose", "config.yaml")
|
|
8353
8598
|
},
|
|
8354
8599
|
container: "extensions",
|
|
8355
8600
|
shape: "plain",
|
|
@@ -8370,19 +8615,19 @@ var HARNESSES = [
|
|
|
8370
8615
|
id: "windsurf",
|
|
8371
8616
|
name: "Windsurf",
|
|
8372
8617
|
scope: "home",
|
|
8373
|
-
file:
|
|
8618
|
+
file: join4(".codeium", "windsurf", "mcp_config.json"),
|
|
8374
8619
|
container: "mcpServers",
|
|
8375
8620
|
shape: "plain",
|
|
8376
|
-
skills: { dir:
|
|
8621
|
+
skills: { dir: join4(".windsurf", "skills"), shared: true }
|
|
8377
8622
|
},
|
|
8378
8623
|
{
|
|
8379
8624
|
id: "hermes",
|
|
8380
8625
|
name: "Hermes",
|
|
8381
8626
|
scope: "home",
|
|
8382
|
-
file:
|
|
8627
|
+
file: join4(".hermes", "config.yaml"),
|
|
8383
8628
|
container: "mcp_servers",
|
|
8384
8629
|
shape: "plain",
|
|
8385
|
-
skills: { dir:
|
|
8630
|
+
skills: { dir: join4(".hermes", "skills"), shared: true },
|
|
8386
8631
|
yaml: {
|
|
8387
8632
|
path: ["mcp_servers", SERVER_KEY],
|
|
8388
8633
|
entry: (launch) => ({
|
|
@@ -8397,7 +8642,7 @@ var HARNESSES = [
|
|
|
8397
8642
|
id: "openclaw",
|
|
8398
8643
|
name: "OpenClaw",
|
|
8399
8644
|
scope: "home",
|
|
8400
|
-
file:
|
|
8645
|
+
file: join4(".openclaw", "openclaw.json"),
|
|
8401
8646
|
container: "mcpServers",
|
|
8402
8647
|
shape: "plain"
|
|
8403
8648
|
},
|
|
@@ -8406,9 +8651,9 @@ var HARNESSES = [
|
|
|
8406
8651
|
name: "Claude Desktop",
|
|
8407
8652
|
scope: "home",
|
|
8408
8653
|
file: {
|
|
8409
|
-
win32: { appData:
|
|
8410
|
-
darwin:
|
|
8411
|
-
linux:
|
|
8654
|
+
win32: { appData: join4("Claude", "claude_desktop_config.json") },
|
|
8655
|
+
darwin: join4("Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
8656
|
+
linux: join4(".config", "Claude", "claude_desktop_config.json")
|
|
8412
8657
|
},
|
|
8413
8658
|
container: "mcpServers",
|
|
8414
8659
|
shape: "plain"
|
|
@@ -8417,7 +8662,7 @@ var HARNESSES = [
|
|
|
8417
8662
|
id: "zeroclaw",
|
|
8418
8663
|
name: "ZeroClaw",
|
|
8419
8664
|
scope: "home",
|
|
8420
|
-
file:
|
|
8665
|
+
file: join4(".zeroclaw", "config.toml"),
|
|
8421
8666
|
container: "mcp.servers",
|
|
8422
8667
|
shape: "plain",
|
|
8423
8668
|
toml: {
|
|
@@ -8438,7 +8683,7 @@ var HARNESSES = [
|
|
|
8438
8683
|
id: "deepcode",
|
|
8439
8684
|
name: "Deep Code",
|
|
8440
8685
|
scope: "home",
|
|
8441
|
-
file:
|
|
8686
|
+
file: join4(".deepcode", "settings.json"),
|
|
8442
8687
|
container: "mcpServers",
|
|
8443
8688
|
shape: "plain"
|
|
8444
8689
|
},
|
|
@@ -8446,7 +8691,7 @@ var HARNESSES = [
|
|
|
8446
8691
|
id: "nanobot",
|
|
8447
8692
|
name: "nanobot",
|
|
8448
8693
|
scope: "home",
|
|
8449
|
-
file:
|
|
8694
|
+
file: join4(".nanobot", "config.json"),
|
|
8450
8695
|
container: "mcpServers",
|
|
8451
8696
|
shape: "plain",
|
|
8452
8697
|
snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
|
|
@@ -8455,7 +8700,7 @@ var HARNESSES = [
|
|
|
8455
8700
|
id: "autohand",
|
|
8456
8701
|
name: "Autohand",
|
|
8457
8702
|
scope: "home",
|
|
8458
|
-
file:
|
|
8703
|
+
file: join4(".autohand", "config.json"),
|
|
8459
8704
|
container: "mcpServers",
|
|
8460
8705
|
shape: "plain",
|
|
8461
8706
|
snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
|
|
@@ -8464,7 +8709,7 @@ var HARNESSES = [
|
|
|
8464
8709
|
var OURS = ["GODOT_PATH", "GDHARNESS_PROJECT"];
|
|
8465
8710
|
function environmentFor(launch, held) {
|
|
8466
8711
|
const kept = {};
|
|
8467
|
-
if (
|
|
8712
|
+
if (isRecord(held)) {
|
|
8468
8713
|
for (const [name, value] of Object.entries(held)) {
|
|
8469
8714
|
if (typeof value === "string" && !OURS.includes(name)) {
|
|
8470
8715
|
kept[name] = value;
|
|
@@ -8474,7 +8719,7 @@ function environmentFor(launch, held) {
|
|
|
8474
8719
|
return { ...kept, ...launch.env };
|
|
8475
8720
|
}
|
|
8476
8721
|
function entryFor(shape, launch, held) {
|
|
8477
|
-
const before =
|
|
8722
|
+
const before = isRecord(held) ? { ...held } : {};
|
|
8478
8723
|
if (shape === "opencode") {
|
|
8479
8724
|
return {
|
|
8480
8725
|
...before,
|
|
@@ -8500,7 +8745,15 @@ var LOG_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
|
8500
8745
|
var DECLARING = new Set(["var", "const", "func", "signal", "enum", "class", "for", "class_name"]);
|
|
8501
8746
|
var NAME = "[\\p{L}_][\\p{L}\\p{N}_]*";
|
|
8502
8747
|
var ANNOTATIONS = "(?:@[\\p{L}_][\\p{L}\\p{N}_]*(?:\\([^)]*\\))?\\s+)*";
|
|
8503
|
-
var
|
|
8748
|
+
var DECLARATION_KEYWORDS = [
|
|
8749
|
+
"func",
|
|
8750
|
+
"var",
|
|
8751
|
+
"const",
|
|
8752
|
+
"signal",
|
|
8753
|
+
"enum",
|
|
8754
|
+
"class"
|
|
8755
|
+
];
|
|
8756
|
+
var DECLARATION_LINE = new RegExp(`^(${ANNOTATIONS})(static\\s+)?(${DECLARATION_KEYWORDS.join("|")})\\s+(${NAME})`, "u");
|
|
8504
8757
|
var CLASS_NAME_LINE = new RegExp(`^${ANNOTATIONS}class_name\\s+(${NAME})`, "u");
|
|
8505
8758
|
var EXTENDS_LINE = new RegExp(`^${ANNOTATIONS}(?:class_name\\s+${NAME}\\s+)?extends\\s`, "u");
|
|
8506
8759
|
var FUNC_LINE = new RegExp(`^[ \\t]*${ANNOTATIONS}(?:static\\s+)?func\\s+(${NAME})\\s*\\(`, "u");
|
|
@@ -8554,7 +8807,7 @@ var KEYWORDS = new Set([
|
|
|
8554
8807
|
]);
|
|
8555
8808
|
|
|
8556
8809
|
// src/whole-file.ts
|
|
8557
|
-
import { readFileSync as
|
|
8810
|
+
import { readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
8558
8811
|
var HELD_FILE_MS = 1000;
|
|
8559
8812
|
var HELD_FILE_RETRY_MS = 10;
|
|
8560
8813
|
var HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
@@ -8562,9 +8815,9 @@ function readWhole(path) {
|
|
|
8562
8815
|
const until = Date.now() + HELD_FILE_MS;
|
|
8563
8816
|
for (;; ) {
|
|
8564
8817
|
try {
|
|
8565
|
-
return
|
|
8818
|
+
return readFileSync4(path, "utf8");
|
|
8566
8819
|
} catch (error) {
|
|
8567
|
-
const code = error
|
|
8820
|
+
const code = errorCode(error) ?? "";
|
|
8568
8821
|
if (code === "ENOENT") {
|
|
8569
8822
|
return null;
|
|
8570
8823
|
}
|
|
@@ -8578,20 +8831,20 @@ function readWhole(path) {
|
|
|
8578
8831
|
function writeWhole(path, text) {
|
|
8579
8832
|
const partial = `${path}.${process.pid}.partial`;
|
|
8580
8833
|
try {
|
|
8581
|
-
|
|
8834
|
+
writeFileSync4(partial, text, "utf8");
|
|
8582
8835
|
} catch {
|
|
8583
8836
|
return false;
|
|
8584
8837
|
}
|
|
8585
8838
|
const until = Date.now() + HELD_FILE_MS;
|
|
8586
8839
|
for (;; ) {
|
|
8587
8840
|
try {
|
|
8588
|
-
|
|
8841
|
+
renameSync2(partial, path);
|
|
8589
8842
|
return true;
|
|
8590
8843
|
} catch (error) {
|
|
8591
|
-
const code = error
|
|
8844
|
+
const code = errorCode(error) ?? "";
|
|
8592
8845
|
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
8593
8846
|
try {
|
|
8594
|
-
|
|
8847
|
+
rmSync3(partial, { force: true });
|
|
8595
8848
|
} catch {}
|
|
8596
8849
|
return false;
|
|
8597
8850
|
}
|
|
@@ -8603,10 +8856,10 @@ function removeWhole(path) {
|
|
|
8603
8856
|
const until = Date.now() + HELD_FILE_MS;
|
|
8604
8857
|
for (;; ) {
|
|
8605
8858
|
try {
|
|
8606
|
-
|
|
8859
|
+
rmSync3(path, { force: true });
|
|
8607
8860
|
return true;
|
|
8608
8861
|
} catch (error) {
|
|
8609
|
-
const code = error
|
|
8862
|
+
const code = errorCode(error) ?? "";
|
|
8610
8863
|
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
8611
8864
|
return false;
|
|
8612
8865
|
}
|
|
@@ -8616,7 +8869,7 @@ function removeWhole(path) {
|
|
|
8616
8869
|
}
|
|
8617
8870
|
|
|
8618
8871
|
// src/engine-leaks.ts
|
|
8619
|
-
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
|
|
8872
|
+
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.";
|
|
8620
8873
|
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.";
|
|
8621
8874
|
var NAME2 = "[\\p{L}_][\\p{L}\\p{N}_]*";
|
|
8622
8875
|
var EXPORTED = new RegExp(`@export(?!_(?:group|subgroup|category)\\b)\\w*(?:\\([^)]*\\))?\\s+(?:@${NAME2}(?:\\([^)]*\\))?\\s+)*` + `(?:static\\s+)?var\\s+(${NAME2})\\s*:\\s*(?:Array|Dictionary)\\s*\\[([^\\]]*)\\]`, "gu");
|
|
@@ -8669,7 +8922,7 @@ var MEMORY_PER_ENGINE = 1.5 * 1024 ** 3;
|
|
|
8669
8922
|
var SCAN_BYTES = 1024 * 1024;
|
|
8670
8923
|
|
|
8671
8924
|
// src/process-children.ts
|
|
8672
|
-
import { readFileSync as
|
|
8925
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
8673
8926
|
import { basename as basename3 } from "node:path";
|
|
8674
8927
|
async function startTimesOf(pids) {
|
|
8675
8928
|
const began = new Map;
|
|
@@ -8711,7 +8964,7 @@ async function linuxStartTimes(pids) {
|
|
|
8711
8964
|
const hertz = await ticksPerSecond();
|
|
8712
8965
|
let booted;
|
|
8713
8966
|
try {
|
|
8714
|
-
booted = Number(/^btime\s+(\d+)$/m.exec(
|
|
8967
|
+
booted = Number(/^btime\s+(\d+)$/m.exec(readFileSync5("/proc/stat", "utf8"))?.[1] ?? Number.NaN) * 1000;
|
|
8715
8968
|
} catch {
|
|
8716
8969
|
return began;
|
|
8717
8970
|
}
|
|
@@ -8721,7 +8974,7 @@ async function linuxStartTimes(pids) {
|
|
|
8721
8974
|
for (const pid of pids) {
|
|
8722
8975
|
let stat;
|
|
8723
8976
|
try {
|
|
8724
|
-
stat =
|
|
8977
|
+
stat = readFileSync5(`/proc/${String(pid)}/stat`, "utf8");
|
|
8725
8978
|
} catch {
|
|
8726
8979
|
continue;
|
|
8727
8980
|
}
|
|
@@ -8751,7 +9004,7 @@ async function ticksPerSecond() {
|
|
|
8751
9004
|
}
|
|
8752
9005
|
function printedBy(command, args, env) {
|
|
8753
9006
|
return runHidden(command, args, { timeout: ASK_TIMEOUT_MS, env }).then(({ stdout }) => stdout, (error) => {
|
|
8754
|
-
const printed = error.stdout;
|
|
9007
|
+
const printed = error instanceof Error && "stdout" in error ? error.stdout : undefined;
|
|
8755
9008
|
return typeof printed === "string" ? printed : "";
|
|
8756
9009
|
});
|
|
8757
9010
|
}
|
|
@@ -8883,7 +9136,7 @@ function nameSlotEngine(lock, holder, engine) {
|
|
|
8883
9136
|
}
|
|
8884
9137
|
function giveBackSlot(lock, pid) {
|
|
8885
9138
|
try {
|
|
8886
|
-
if (holderOf(
|
|
9139
|
+
if (holderOf(readFileSync6(lock, "utf8"))?.pid === pid) {
|
|
8887
9140
|
removeWhole(lock);
|
|
8888
9141
|
}
|
|
8889
9142
|
} catch {}
|
|
@@ -8917,9 +9170,9 @@ function crashesReported() {
|
|
|
8917
9170
|
}
|
|
8918
9171
|
|
|
8919
9172
|
// src/game-debugger.ts
|
|
8920
|
-
import { readFileSync as
|
|
9173
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
8921
9174
|
import { createServer } from "node:net";
|
|
8922
|
-
import { join as
|
|
9175
|
+
import { join as join7 } from "node:path";
|
|
8923
9176
|
|
|
8924
9177
|
// src/godot-variant.ts
|
|
8925
9178
|
var NIL = 0;
|
|
@@ -9224,8 +9477,8 @@ function readMessage(body) {
|
|
|
9224
9477
|
}
|
|
9225
9478
|
|
|
9226
9479
|
// src/setup.ts
|
|
9227
|
-
import { dirname as dirname3, join as
|
|
9228
|
-
import { fileURLToPath } from "node:url";
|
|
9480
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
9481
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
9229
9482
|
|
|
9230
9483
|
// src/dictionary.ts
|
|
9231
9484
|
function emptyRecord() {
|
|
@@ -9339,25 +9592,25 @@ var IMPORTABLE = new Set(IMPORTABLE_EXTENSIONS);
|
|
|
9339
9592
|
var hashes = new Map;
|
|
9340
9593
|
|
|
9341
9594
|
// src/scratch.ts
|
|
9342
|
-
import { existsSync as
|
|
9595
|
+
import { existsSync as existsSync4, mkdtempSync as mkdtempSync2, readdirSync as readdirSync3, rmSync as rmSync5 } from "node:fs";
|
|
9343
9596
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
9344
|
-
import { join as
|
|
9597
|
+
import { join as join5 } from "node:path";
|
|
9345
9598
|
import process6 from "node:process";
|
|
9346
9599
|
var SWEPT = { recursive: true, force: true };
|
|
9347
9600
|
var AGAIN_AFTER_MS = [250, 500, 1000, 2000, 4000, 8000, 16000];
|
|
9348
9601
|
var waiting = new Set;
|
|
9349
9602
|
var atExit = new Set;
|
|
9350
9603
|
function scratchDirectory(kind) {
|
|
9351
|
-
return mkdtempSync2(
|
|
9604
|
+
return mkdtempSync2(join5(tmpdir5(), `gdharness-${kind}-${process6.pid}-`));
|
|
9352
9605
|
}
|
|
9353
|
-
function discardWith(
|
|
9606
|
+
function discardWith(removePath, paths) {
|
|
9354
9607
|
const left = [];
|
|
9355
9608
|
for (const path of paths) {
|
|
9356
9609
|
if (!path) {
|
|
9357
9610
|
continue;
|
|
9358
9611
|
}
|
|
9359
9612
|
try {
|
|
9360
|
-
|
|
9613
|
+
removePath(path);
|
|
9361
9614
|
} catch (error) {
|
|
9362
9615
|
left.push({ path, reason: error instanceof Error ? error.message : String(error) });
|
|
9363
9616
|
}
|
|
@@ -9372,7 +9625,7 @@ function discard(...paths) {
|
|
|
9372
9625
|
return left;
|
|
9373
9626
|
}
|
|
9374
9627
|
function remove(path) {
|
|
9375
|
-
|
|
9628
|
+
rmSync5(path, SWEPT);
|
|
9376
9629
|
}
|
|
9377
9630
|
function tryAgain(path, attempt) {
|
|
9378
9631
|
if (attempt === 0) {
|
|
@@ -9384,7 +9637,7 @@ function tryAgain(path, attempt) {
|
|
|
9384
9637
|
lastTryOnExit();
|
|
9385
9638
|
}
|
|
9386
9639
|
const after = AGAIN_AFTER_MS[attempt];
|
|
9387
|
-
if (after === undefined || !
|
|
9640
|
+
if (after === undefined || !existsSync4(path)) {
|
|
9388
9641
|
waiting.delete(path);
|
|
9389
9642
|
if (after === undefined) {
|
|
9390
9643
|
atExit.add(path);
|
|
@@ -9533,7 +9786,7 @@ function parseIniLikeValue(value) {
|
|
|
9533
9786
|
}
|
|
9534
9787
|
|
|
9535
9788
|
// src/server-version.ts
|
|
9536
|
-
import { readFileSync as
|
|
9789
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
9537
9790
|
|
|
9538
9791
|
// src/update-check.ts
|
|
9539
9792
|
var CACHE_MS = 10 * 60 * 1000;
|
|
@@ -9544,8 +9797,9 @@ var MAX_RETRY_MS = 60 * 60 * 1000;
|
|
|
9544
9797
|
var DEBUG_MODE = process.env["GDHARNESS_DEBUG"] === "1";
|
|
9545
9798
|
var SERVER_VERSION = (() => {
|
|
9546
9799
|
try {
|
|
9547
|
-
const pkg = JSON.parse(
|
|
9548
|
-
|
|
9800
|
+
const pkg = JSON.parse(readFileSync7(new URL("../package.json", import.meta.url), "utf8"));
|
|
9801
|
+
const version = isRecord(pkg) ? pkg["version"] : undefined;
|
|
9802
|
+
return typeof version === "string" ? version : "0.0.0";
|
|
9549
9803
|
} catch {
|
|
9550
9804
|
return "0.0.0";
|
|
9551
9805
|
}
|
|
@@ -9557,7 +9811,7 @@ var RUNTIME_AUTOLOAD = {
|
|
|
9557
9811
|
path: "gdharness/loader.gd"
|
|
9558
9812
|
};
|
|
9559
9813
|
function shippedAddonsDirectory() {
|
|
9560
|
-
return
|
|
9814
|
+
return join6(dirname3(fileURLToPath2(import.meta.url)), "godot", "addons");
|
|
9561
9815
|
}
|
|
9562
9816
|
|
|
9563
9817
|
// src/game-debugger.ts
|
|
@@ -9568,9 +9822,12 @@ var ADDON_LINES = 200;
|
|
|
9568
9822
|
var RUNTIME_ADDON = "res://addons/gdharness_runtime/";
|
|
9569
9823
|
var RUNTIME_AUTOLOAD2 = `${RUNTIME_ADDON}runtime_autoload.gd`;
|
|
9570
9824
|
var frameEnd = null;
|
|
9825
|
+
function topIsTheAddon(frames) {
|
|
9826
|
+
return frames[0]?.script.startsWith(RUNTIME_ADDON) ?? false;
|
|
9827
|
+
}
|
|
9571
9828
|
function frameEndLine() {
|
|
9572
9829
|
if (frameEnd === null) {
|
|
9573
|
-
const lines =
|
|
9830
|
+
const lines = readFileSync8(join7(shippedAddonsDirectory(), "gdharness_runtime", "runtime_autoload.gd"), "utf8").split(`
|
|
9574
9831
|
`);
|
|
9575
9832
|
const declared = lines.findIndex((line) => line.startsWith("func _notification("));
|
|
9576
9833
|
if (declared === -1) {
|
|
@@ -9970,7 +10227,7 @@ class GameDebugger {
|
|
|
9970
10227
|
if (entered === null) {
|
|
9971
10228
|
return {
|
|
9972
10229
|
paused: false,
|
|
9973
|
-
note: `The game has been asked to stop and had not within ${PAUSE_MS / 1000}s. It takes the request between frames, and in a script every 2048 lines it runs, so its main thread is in a loop that sleeps between few lines, or inside one long engine call or a native extension's own loop. The request stays with the game, which stops when it next reaches that point
|
|
10230
|
+
note: `The game has been asked to stop and had not within ${PAUSE_MS / 1000}s. It takes the request between frames, and in a script every 2048 lines it runs, so its main thread is in a loop that sleeps between few lines, or inside one long engine call or a native extension's own loop. The request stays with the game, which stops when it next reaches that point. debug_state stack reads where once it has.`
|
|
9974
10231
|
};
|
|
9975
10232
|
}
|
|
9976
10233
|
}
|
|
@@ -9985,7 +10242,7 @@ class GameDebugger {
|
|
|
9985
10242
|
if (again === null) {
|
|
9986
10243
|
return {
|
|
9987
10244
|
paused: false,
|
|
9988
|
-
note: `The game stopped between frames, where no script runs, so it was let go to stop at the next line of script it runs, and none ran within ${STEP_MS / 1000}s. It stops there when one does
|
|
10245
|
+
note: `The game stopped between frames, where no script runs, so it was let go to stop at the next line of script it runs, and none ran within ${STEP_MS / 1000}s. It stops there when one does, and debug_state stack reads it then.`
|
|
9989
10246
|
};
|
|
9990
10247
|
}
|
|
9991
10248
|
}
|
|
@@ -9993,7 +10250,7 @@ class GameDebugger {
|
|
|
9993
10250
|
if (past === "lost") {
|
|
9994
10251
|
return {
|
|
9995
10252
|
paused: false,
|
|
9996
|
-
note: `The game stopped in gdharness's runtime addon and was let go on to reach its own script, and did not stop again within ${STEP_MS / 1000}s. It stops at the next line of script it runs
|
|
10253
|
+
note: `The game stopped in gdharness's runtime addon and was let go on to reach its own script, and did not stop again within ${STEP_MS / 1000}s. It stops at the next line of script it runs, and debug_state stack reads it then.`
|
|
9997
10254
|
};
|
|
9998
10255
|
}
|
|
9999
10256
|
this.stoppedBy("Paused");
|
|
@@ -10013,7 +10270,7 @@ class GameDebugger {
|
|
|
10013
10270
|
let frames = await this.stack();
|
|
10014
10271
|
let framesLeft = ADDON_FRAMES;
|
|
10015
10272
|
let linesLeft = ADDON_LINES;
|
|
10016
|
-
while (frames !== null && this.held !== null && (frames
|
|
10273
|
+
while (frames !== null && this.held !== null && topIsTheAddon(frames)) {
|
|
10017
10274
|
if (until !== undefined && Date.now() >= until) {
|
|
10018
10275
|
return { frames, gaveUp: "time" };
|
|
10019
10276
|
}
|
|
@@ -10093,7 +10350,7 @@ class GameDebugger {
|
|
|
10093
10350
|
return {
|
|
10094
10351
|
stepped: true,
|
|
10095
10352
|
heldAgain: false,
|
|
10096
|
-
note: `The step stopped in gdharness's runtime addon and was let go on to reach the game's own script, and did not stop again within ${STEP_MS / 1000}s. It stops at the next line of script the game runs
|
|
10353
|
+
note: `The step stopped in gdharness's runtime addon and was let go on to reach the game's own script, and did not stop again within ${STEP_MS / 1000}s. It stops at the next line of script the game runs, and debug_state stack reads it then.`
|
|
10097
10354
|
};
|
|
10098
10355
|
}
|
|
10099
10356
|
this.stoppedBy("Stepped");
|
|
@@ -10211,7 +10468,7 @@ class GameDebugger {
|
|
|
10211
10468
|
return null;
|
|
10212
10469
|
}
|
|
10213
10470
|
return {
|
|
10214
|
-
refused: frames.length === 0 ? "The game is held where no script runs, so it has no frames: debug_control step_over takes it to the next line of script." : `The stack has no frame ${frame}
|
|
10471
|
+
refused: frames.length === 0 ? "The game is held where no script runs, so it has no frames: debug_control step_over takes it to the next line of script." : `The stack has no frame ${frame}. Its frames are ${frames.map((each) => each.id).join(", ")}.`
|
|
10215
10472
|
};
|
|
10216
10473
|
}
|
|
10217
10474
|
close() {
|
|
@@ -10222,10 +10479,10 @@ class GameDebugger {
|
|
|
10222
10479
|
|
|
10223
10480
|
// src/keeper-channel.ts
|
|
10224
10481
|
import { randomUUID } from "node:crypto";
|
|
10225
|
-
import { mkdtempSync as mkdtempSync3, rmSync as
|
|
10482
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync6 } from "node:fs";
|
|
10226
10483
|
import { connect, createServer as createServer2 } from "node:net";
|
|
10227
10484
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
10228
|
-
import { join as
|
|
10485
|
+
import { join as join8 } from "node:path";
|
|
10229
10486
|
import process7 from "node:process";
|
|
10230
10487
|
var DEBUG_PREFIX = "debug ";
|
|
10231
10488
|
function endedOrWhyNot(end) {
|
|
@@ -10241,11 +10498,41 @@ async function debuggedOrWhyNot(debug, asked) {
|
|
|
10241
10498
|
return JSON.stringify({ refused: "This run has no debugger." });
|
|
10242
10499
|
}
|
|
10243
10500
|
try {
|
|
10244
|
-
|
|
10501
|
+
const request = debugRequestOf(JSON.parse(asked));
|
|
10502
|
+
if (request === null) {
|
|
10503
|
+
return JSON.stringify({ refused: `The debugger takes no request like ${asked.slice(0, 200)}.` });
|
|
10504
|
+
}
|
|
10505
|
+
return JSON.stringify(await debug(request));
|
|
10245
10506
|
} catch (error) {
|
|
10246
10507
|
return JSON.stringify({ refused: `The debugger could not answer: ${errorText(error)}` });
|
|
10247
10508
|
}
|
|
10248
10509
|
}
|
|
10510
|
+
var RESUMED_HOW = ["continue", "next", "step", "out"];
|
|
10511
|
+
function debugRequestOf(asked) {
|
|
10512
|
+
if (!isRecord(asked)) {
|
|
10513
|
+
return null;
|
|
10514
|
+
}
|
|
10515
|
+
const { op, script, line, set, how, frame, expression } = asked;
|
|
10516
|
+
switch (op) {
|
|
10517
|
+
case "breakpoint":
|
|
10518
|
+
return typeof script === "string" && typeof line === "number" && typeof set === "boolean" ? { op, script, line, set } : null;
|
|
10519
|
+
case "pause":
|
|
10520
|
+
case "stack":
|
|
10521
|
+
case "output":
|
|
10522
|
+
case "state":
|
|
10523
|
+
return { op };
|
|
10524
|
+
case "resume": {
|
|
10525
|
+
const resumed = RESUMED_HOW.find((one) => one === how);
|
|
10526
|
+
return resumed === undefined ? null : { op, how: resumed };
|
|
10527
|
+
}
|
|
10528
|
+
case "variables":
|
|
10529
|
+
return typeof frame === "number" ? { op, frame } : null;
|
|
10530
|
+
case "evaluate":
|
|
10531
|
+
return typeof frame === "number" && typeof expression === "string" ? { op, frame, expression } : null;
|
|
10532
|
+
default:
|
|
10533
|
+
return null;
|
|
10534
|
+
}
|
|
10535
|
+
}
|
|
10249
10536
|
function errorText(error) {
|
|
10250
10537
|
return (error instanceof Error ? error.message : String(error)).replaceAll(`
|
|
10251
10538
|
`, " ");
|
|
@@ -10253,8 +10540,8 @@ function errorText(error) {
|
|
|
10253
10540
|
async function listenForTheServer(end, debug) {
|
|
10254
10541
|
let directory = null;
|
|
10255
10542
|
try {
|
|
10256
|
-
directory = process7.platform === "win32" ? null : mkdtempSync3(
|
|
10257
|
-
const address = directory === null ? `\\\\.\\pipe\\gdharness-keeper-${randomUUID()}` :
|
|
10543
|
+
directory = process7.platform === "win32" ? null : mkdtempSync3(join8(tmpdir6(), "gdharness-keeper-"));
|
|
10544
|
+
const address = directory === null ? `\\\\.\\pipe\\gdharness-keeper-${randomUUID()}` : join8(directory, "keeper.sock");
|
|
10258
10545
|
const server = createServer2((socket) => {
|
|
10259
10546
|
socket.setEncoding("utf8");
|
|
10260
10547
|
socket.on("error", () => {});
|
|
@@ -10290,13 +10577,13 @@ async function listenForTheServer(end, debug) {
|
|
|
10290
10577
|
close: () => {
|
|
10291
10578
|
server.close();
|
|
10292
10579
|
if (made !== null) {
|
|
10293
|
-
|
|
10580
|
+
rmSync6(made, { recursive: true, force: true });
|
|
10294
10581
|
}
|
|
10295
10582
|
}
|
|
10296
10583
|
};
|
|
10297
10584
|
} catch {
|
|
10298
10585
|
if (directory !== null) {
|
|
10299
|
-
|
|
10586
|
+
rmSync6(directory, { recursive: true, force: true });
|
|
10300
10587
|
}
|
|
10301
10588
|
return null;
|
|
10302
10589
|
}
|
|
@@ -10312,7 +10599,9 @@ function listening(server, address) {
|
|
|
10312
10599
|
}
|
|
10313
10600
|
|
|
10314
10601
|
// src/outside.ts
|
|
10315
|
-
import
|
|
10602
|
+
import process8 from "node:process";
|
|
10603
|
+
import { text } from "node:stream/consumers";
|
|
10604
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
10316
10605
|
function withChanges(base, changes) {
|
|
10317
10606
|
const env = { ...base };
|
|
10318
10607
|
for (const [name, value] of Object.entries(changes)) {
|
|
@@ -10328,13 +10617,70 @@ function sendSpec(child, spec) {
|
|
|
10328
10617
|
child.stdin?.end(JSON.stringify(spec), "utf8");
|
|
10329
10618
|
}
|
|
10330
10619
|
async function receivedSpec() {
|
|
10331
|
-
const
|
|
10332
|
-
|
|
10333
|
-
|
|
10620
|
+
const received = await text(process8.stdin);
|
|
10621
|
+
const spec = sentSpecOf(JSON.parse(received));
|
|
10622
|
+
if (spec === null) {
|
|
10623
|
+
throw new Error(`What came down stdin is not a spec a server sends: ${received.slice(0, 200)}`);
|
|
10334
10624
|
}
|
|
10335
|
-
return
|
|
10625
|
+
return spec;
|
|
10336
10626
|
}
|
|
10337
|
-
|
|
10627
|
+
function envChangesOf(value) {
|
|
10628
|
+
if (!isRecord(value)) {
|
|
10629
|
+
return null;
|
|
10630
|
+
}
|
|
10631
|
+
const changes = {};
|
|
10632
|
+
for (const [name, change] of Object.entries(value)) {
|
|
10633
|
+
if (typeof change !== "string" && change !== null) {
|
|
10634
|
+
return null;
|
|
10635
|
+
}
|
|
10636
|
+
changes[name] = change;
|
|
10637
|
+
}
|
|
10638
|
+
return changes;
|
|
10639
|
+
}
|
|
10640
|
+
function runOf(value) {
|
|
10641
|
+
if (!isRecord(value)) {
|
|
10642
|
+
return null;
|
|
10643
|
+
}
|
|
10644
|
+
const { transcript, startedAt, projectPath, servedBy, profile, breakpoints, debugged, slot } = value;
|
|
10645
|
+
const held = slot === undefined ? undefined : slotOf(slot);
|
|
10646
|
+
if (typeof transcript !== "string" || typeof startedAt !== "number" || typeof projectPath !== "string" || servedBy !== undefined && typeof servedBy !== "string" || profile !== undefined && typeof profile !== "string" || breakpoints !== undefined && !isStringList(breakpoints) || debugged !== undefined && typeof debugged !== "boolean" || held === null) {
|
|
10647
|
+
return null;
|
|
10648
|
+
}
|
|
10649
|
+
return {
|
|
10650
|
+
transcript,
|
|
10651
|
+
startedAt,
|
|
10652
|
+
projectPath,
|
|
10653
|
+
...servedBy === undefined ? {} : { servedBy },
|
|
10654
|
+
...profile === undefined ? {} : { profile },
|
|
10655
|
+
...breakpoints === undefined ? {} : { breakpoints },
|
|
10656
|
+
...debugged === undefined ? {} : { debugged },
|
|
10657
|
+
...held === undefined ? {} : { slot: held }
|
|
10658
|
+
};
|
|
10659
|
+
}
|
|
10660
|
+
function slotOf(value) {
|
|
10661
|
+
const { lock, from, by } = isRecord(value) ? value : {};
|
|
10662
|
+
return typeof lock === "string" && typeof from === "number" && typeof by === "string" ? { lock, from, by } : null;
|
|
10663
|
+
}
|
|
10664
|
+
function sentSpecOf(value) {
|
|
10665
|
+
if (!isRecord(value)) {
|
|
10666
|
+
return null;
|
|
10667
|
+
}
|
|
10668
|
+
const { command, args, envChanges, run, desktop, noActivate } = value;
|
|
10669
|
+
const changes = envChangesOf(envChanges);
|
|
10670
|
+
const ran = run === undefined ? undefined : runOf(run);
|
|
10671
|
+
if (typeof command !== "string" || !isStringList(args) || changes === null || ran === null || desktop !== undefined && typeof desktop !== "string" || noActivate !== undefined && typeof noActivate !== "boolean") {
|
|
10672
|
+
return null;
|
|
10673
|
+
}
|
|
10674
|
+
return {
|
|
10675
|
+
command,
|
|
10676
|
+
args,
|
|
10677
|
+
envChanges: changes,
|
|
10678
|
+
...ran === undefined ? {} : { run: ran },
|
|
10679
|
+
...desktop === undefined ? {} : { desktop },
|
|
10680
|
+
...noActivate === undefined ? {} : { noActivate }
|
|
10681
|
+
};
|
|
10682
|
+
}
|
|
10683
|
+
var KEEPER_SCRIPT = fileURLToPath3(new URL("./keeper.js", import.meta.url));
|
|
10338
10684
|
function readLaunched(printed) {
|
|
10339
10685
|
const line = printed.split(`
|
|
10340
10686
|
`).find((one) => one.trim() !== "")?.trim() ?? "";
|
|
@@ -10347,12 +10693,12 @@ function readLaunched(printed) {
|
|
|
10347
10693
|
|
|
10348
10694
|
// src/run-record.ts
|
|
10349
10695
|
import { createHash as createHash2 } from "node:crypto";
|
|
10350
|
-
import { mkdirSync as mkdirSync2, openSync as openSync3, readdirSync as
|
|
10351
|
-
import { basename as basename4, join as
|
|
10696
|
+
import { mkdirSync as mkdirSync2, openSync as openSync3, readdirSync as readdirSync4, readFileSync as readFileSync9, rmSync as rmSync7, statSync as statSync4 } from "node:fs";
|
|
10697
|
+
import { basename as basename4, join as join10, resolve as resolve5 } from "node:path";
|
|
10352
10698
|
|
|
10353
10699
|
// src/runtime-client.ts
|
|
10354
10700
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
10355
|
-
import { dirname as dirname4, join as
|
|
10701
|
+
import { dirname as dirname4, join as join9, resolve as resolve4 } from "node:path";
|
|
10356
10702
|
|
|
10357
10703
|
// src/launch.ts
|
|
10358
10704
|
function envValue(name, variables = process.env) {
|
|
@@ -10397,7 +10743,7 @@ function runtimeDirectory(variables = process.env) {
|
|
|
10397
10743
|
return explicit;
|
|
10398
10744
|
}
|
|
10399
10745
|
const perUser = envValue("XDG_RUNTIME_DIR", variables);
|
|
10400
|
-
return
|
|
10746
|
+
return join9(perUser ?? tmpdir7(), "gdharness");
|
|
10401
10747
|
}
|
|
10402
10748
|
var ERROR_REPORT_KEEP_MS = 60 * 60 * 1000;
|
|
10403
10749
|
var verdicts = new Map;
|
|
@@ -10407,15 +10753,15 @@ var untaken = new Map;
|
|
|
10407
10753
|
|
|
10408
10754
|
// src/run-record.ts
|
|
10409
10755
|
function runsDirectory() {
|
|
10410
|
-
return
|
|
10756
|
+
return join10(runtimeDirectory(), "runs");
|
|
10411
10757
|
}
|
|
10412
10758
|
function projectKey(projectPath) {
|
|
10413
|
-
const real = realAsFarAsItExists(
|
|
10759
|
+
const real = realAsFarAsItExists(resolve5(projectPath)).replace(/[\\/]+$/, "");
|
|
10414
10760
|
const folded = process.platform === "win32" || process.platform === "darwin" ? real.toLowerCase() : real;
|
|
10415
10761
|
return createHash2("sha256").update(folded.replaceAll("\\", "/")).digest("hex").slice(0, 16);
|
|
10416
10762
|
}
|
|
10417
10763
|
function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
10418
|
-
return
|
|
10764
|
+
return join10(directory, "runs", `note-${projectKey(projectPath)}.json`);
|
|
10419
10765
|
}
|
|
10420
10766
|
function writeRunRecord(record) {
|
|
10421
10767
|
mkdirSync2(runsDirectory(), { recursive: true });
|
|
@@ -10443,11 +10789,11 @@ function recordRunEnded(projectPath, pid, ending) {
|
|
|
10443
10789
|
function recordAt(path) {
|
|
10444
10790
|
let parsed;
|
|
10445
10791
|
try {
|
|
10446
|
-
parsed = JSON.parse(
|
|
10792
|
+
parsed = JSON.parse(readFileSync9(path, "utf8"));
|
|
10447
10793
|
} catch {
|
|
10448
10794
|
return null;
|
|
10449
10795
|
}
|
|
10450
|
-
if (!parsed
|
|
10796
|
+
if (!isRecord(parsed)) {
|
|
10451
10797
|
return null;
|
|
10452
10798
|
}
|
|
10453
10799
|
const fields = parsed;
|
|
@@ -10485,11 +10831,10 @@ function recordAt(path) {
|
|
|
10485
10831
|
};
|
|
10486
10832
|
}
|
|
10487
10833
|
function restartedFromAt(value) {
|
|
10488
|
-
if (!value
|
|
10834
|
+
if (!isRecord(value)) {
|
|
10489
10835
|
return [];
|
|
10490
10836
|
}
|
|
10491
|
-
const
|
|
10492
|
-
const { pid, endedAt, exitCode, exitSignal } = fields;
|
|
10837
|
+
const { pid, endedAt, exitCode, exitSignal } = value;
|
|
10493
10838
|
if (typeof pid !== "number" || typeof endedAt !== "number") {
|
|
10494
10839
|
return [];
|
|
10495
10840
|
}
|
|
@@ -10863,9 +11208,9 @@ async function startDirectly(spec, output, hidden, detached = true, errors = out
|
|
|
10863
11208
|
}
|
|
10864
11209
|
async function startThroughHelper(spec, output, stopFile) {
|
|
10865
11210
|
const scratch = scratchDirectory("desktop");
|
|
10866
|
-
const pidFile =
|
|
10867
|
-
const errorFile =
|
|
10868
|
-
const stepFile =
|
|
11211
|
+
const pidFile = join11(scratch, "pid");
|
|
11212
|
+
const errorFile = join11(scratch, "error");
|
|
11213
|
+
const stepFile = join11(scratch, "step");
|
|
10869
11214
|
const where = spec.desktop !== undefined ? `on the ${spec.desktop} desktop` : spec.noActivate === true ? "without activation" : "through the desktop helper";
|
|
10870
11215
|
try {
|
|
10871
11216
|
const compiled = await ensureHelperCompiled();
|
|
@@ -10873,7 +11218,7 @@ async function startThroughHelper(spec, output, stopFile) {
|
|
|
10873
11218
|
return { error: `it could not be started ${where}: ${compiled}` };
|
|
10874
11219
|
}
|
|
10875
11220
|
const wrapper = throughHelper({ ...spec, directory: process.cwd() }, spec.command, spec.args, {
|
|
10876
|
-
spec:
|
|
11221
|
+
spec: join11(scratch, "spec.json"),
|
|
10877
11222
|
pid: pidFile,
|
|
10878
11223
|
error: errorFile,
|
|
10879
11224
|
stop: stopFile,
|
|
@@ -10889,7 +11234,7 @@ async function startThroughHelper(spec, output, stopFile) {
|
|
|
10889
11234
|
exited.now = true;
|
|
10890
11235
|
});
|
|
10891
11236
|
for (let waited = 0;waited < DESKTOP_START_MS; waited += 50) {
|
|
10892
|
-
const pid =
|
|
11237
|
+
const pid = existsSync5(pidFile) ? Number(readFileSync10(pidFile, "utf8").trim()) : Number.NaN;
|
|
10893
11238
|
if (Number.isInteger(pid) && pid > 0) {
|
|
10894
11239
|
return { child: started.child, pid };
|
|
10895
11240
|
}
|
|
@@ -10920,7 +11265,7 @@ function profiledBy(path, projectPath) {
|
|
|
10920
11265
|
};
|
|
10921
11266
|
let projectGodot = null;
|
|
10922
11267
|
try {
|
|
10923
|
-
projectGodot =
|
|
11268
|
+
projectGodot = readFileSync10(join11(projectPath, "project.godot"), "utf8");
|
|
10924
11269
|
} catch {}
|
|
10925
11270
|
const observer = new ProfileObserver((totals) => {
|
|
10926
11271
|
const first = latest === null;
|
|
@@ -10938,9 +11283,13 @@ function profiledBy(path, projectPath) {
|
|
|
10938
11283
|
if (timer !== null) {
|
|
10939
11284
|
clearTimeout(timer);
|
|
10940
11285
|
}
|
|
10941
|
-
|
|
11286
|
+
const last = observer.totals() ?? latest;
|
|
11287
|
+
latest = last;
|
|
11288
|
+
if (last === null) {
|
|
11289
|
+
return;
|
|
11290
|
+
}
|
|
10942
11291
|
let tries = 0;
|
|
10943
|
-
while (
|
|
11292
|
+
while (!writeProfileFile(path, { ...last, connected: true }) && tries < LAST_WRITE_TRIES) {
|
|
10944
11293
|
tries += 1;
|
|
10945
11294
|
}
|
|
10946
11295
|
}
|
|
@@ -11021,12 +11370,12 @@ async function keep() {
|
|
|
11021
11370
|
}
|
|
11022
11371
|
const profiled = run?.profile === undefined ? null : profiledBy(run.profile, run.projectPath);
|
|
11023
11372
|
const debuggerPeer = run === undefined || run.debugged === false ? null : await GameDebugger.open(run.breakpoints ?? [], profiled === null ? [] : [profiled.observer]);
|
|
11024
|
-
const exitNotes = run === undefined ? null : mkdtempSync4(
|
|
11373
|
+
const exitNotes = run === undefined ? null : mkdtempSync4(join11(tmpdir8(), "gdharness-exit-"));
|
|
11025
11374
|
const noted = exitNotes === null ? spec : { ...spec, envChanges: { ...spec.envChanges, [EXIT_NOTES_VARIABLE]: exitNotes } };
|
|
11026
11375
|
const toStart = debuggerPeer === null ? noted : { ...noted, args: withEngineArguments(noted.args, debuggerPeer.engineArguments) };
|
|
11027
11376
|
const transcript = run === undefined ? "ignore" : openSync4(run.transcript, "a");
|
|
11028
|
-
const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(
|
|
11029
|
-
const stopFile = own === null ? "" :
|
|
11377
|
+
const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(join11(tmpdir8(), "gdharness-stop-")) : null;
|
|
11378
|
+
const stopFile = own === null ? "" : join11(own, "stop");
|
|
11030
11379
|
let started;
|
|
11031
11380
|
const keeperStarted = run?.slot === undefined ? undefined : ownStart();
|
|
11032
11381
|
const spawnedAt = Date.now();
|
|
@@ -11063,7 +11412,7 @@ async function keep() {
|
|
|
11063
11412
|
let listening = null;
|
|
11064
11413
|
let end = () => {
|
|
11065
11414
|
if (stopFile !== "") {
|
|
11066
|
-
|
|
11415
|
+
writeFileSync5(stopFile, "");
|
|
11067
11416
|
return "signalled";
|
|
11068
11417
|
}
|
|
11069
11418
|
return child.kill() ? "signalled" : "gone";
|
|
@@ -11165,7 +11514,7 @@ async function keep() {
|
|
|
11165
11514
|
listening?.close();
|
|
11166
11515
|
for (const made of [own, exitNotes]) {
|
|
11167
11516
|
if (made !== null) {
|
|
11168
|
-
|
|
11517
|
+
rmSync8(made, { recursive: true, force: true });
|
|
11169
11518
|
}
|
|
11170
11519
|
}
|
|
11171
11520
|
process.exit(0);
|
|
@@ -11176,7 +11525,7 @@ function restartSaid(notes, pid) {
|
|
|
11176
11525
|
return null;
|
|
11177
11526
|
}
|
|
11178
11527
|
try {
|
|
11179
|
-
const said = JSON.parse(
|
|
11528
|
+
const said = JSON.parse(readFileSync10(join11(notes, `exit-${String(pid)}.json`), "utf8"));
|
|
11180
11529
|
return typeof said === "object" && said !== null && "restart" in said && typeof said.restart === "boolean" ? said.restart : null;
|
|
11181
11530
|
} catch {
|
|
11182
11531
|
return null;
|