gdharness 1.3.59 → 1.3.61
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 +2264 -1706
- 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 +18 -11
- 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 +13 -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 +18 -11
- 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 +28 -10
- package/build/keeper.js +511 -161
- 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,11 +7671,12 @@ function throughHelper(how, command, args, files, assembly = helperAssembly()) {
|
|
|
7435
7671
|
// src/engine-slots.ts
|
|
7436
7672
|
import {
|
|
7437
7673
|
closeSync as closeSync2,
|
|
7674
|
+
existsSync as existsSync3,
|
|
7438
7675
|
mkdirSync,
|
|
7439
7676
|
openSync as openSync2,
|
|
7440
|
-
readdirSync,
|
|
7441
|
-
readFileSync as
|
|
7442
|
-
rmSync as
|
|
7677
|
+
readdirSync as readdirSync2,
|
|
7678
|
+
readFileSync as readFileSync6,
|
|
7679
|
+
rmSync as rmSync4,
|
|
7443
7680
|
statSync as statSync3,
|
|
7444
7681
|
watch,
|
|
7445
7682
|
writeSync as writeSync2
|
|
@@ -7485,18 +7722,19 @@ var buffered = "";
|
|
|
7485
7722
|
var next = 1;
|
|
7486
7723
|
var out = null;
|
|
7487
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
|
+
}
|
|
7488
7731
|
var held = false;
|
|
7489
7732
|
function holding(child, wanted) {
|
|
7490
7733
|
if (held === wanted) {
|
|
7491
7734
|
return;
|
|
7492
7735
|
}
|
|
7493
7736
|
held = wanted;
|
|
7494
|
-
|
|
7495
|
-
if (wanted) {
|
|
7496
|
-
stdout.ref?.();
|
|
7497
|
-
} else {
|
|
7498
|
-
stdout.unref?.();
|
|
7499
|
-
}
|
|
7737
|
+
holdOn(child.stdout, wanted);
|
|
7500
7738
|
}
|
|
7501
7739
|
function running() {
|
|
7502
7740
|
if (helper?.exitCode === null && helper.signalCode === null) {
|
|
@@ -7538,8 +7776,8 @@ function running() {
|
|
|
7538
7776
|
child.once("exit", gone);
|
|
7539
7777
|
child.once("error", gone);
|
|
7540
7778
|
child.unref();
|
|
7541
|
-
child.stdin
|
|
7542
|
-
child.stderr
|
|
7779
|
+
holdOn(child.stdin, false);
|
|
7780
|
+
holdOn(child.stderr, false);
|
|
7543
7781
|
held = true;
|
|
7544
7782
|
holding(child, false);
|
|
7545
7783
|
helper = child;
|
|
@@ -7968,14 +8206,14 @@ async function loadingTheTable() {
|
|
|
7968
8206
|
return `$null = [Reflection.Assembly]::LoadFrom('${TABLE.assembly().replaceAll("'", "''")}')`;
|
|
7969
8207
|
}
|
|
7970
8208
|
async function askProcessTable(call, withinMs) {
|
|
7971
|
-
return askWindows(`${await loadingTheTable()}; [GdhProcessTable]::${call}`, withinMs);
|
|
8209
|
+
return await askWindows(`${await loadingTheTable()}; [GdhProcessTable]::${call}`, withinMs);
|
|
7972
8210
|
}
|
|
7973
8211
|
|
|
7974
8212
|
// src/engine-spent.ts
|
|
7975
8213
|
var watched = new Set;
|
|
7976
8214
|
|
|
7977
8215
|
// src/harnesses.ts
|
|
7978
|
-
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";
|
|
7979
8217
|
|
|
7980
8218
|
// node_modules/yaml/dist/index.js
|
|
7981
8219
|
var composer = require_composer();
|
|
@@ -8025,13 +8263,13 @@ var $visitAsync = visit.visitAsync;
|
|
|
8025
8263
|
|
|
8026
8264
|
// src/paths.ts
|
|
8027
8265
|
import { realpathSync, statSync as statSync2 } from "node:fs";
|
|
8028
|
-
import { basename, dirname, isAbsolute, join as
|
|
8266
|
+
import { basename, dirname, isAbsolute as isAbsolute2, join as join3, relative, resolve as resolve2, sep } from "node:path";
|
|
8029
8267
|
function realAsFarAsItExists(path) {
|
|
8030
8268
|
const missing = [];
|
|
8031
8269
|
let at = path;
|
|
8032
8270
|
for (;; ) {
|
|
8033
8271
|
try {
|
|
8034
|
-
return
|
|
8272
|
+
return join3(realpathSync.native(at), ...missing);
|
|
8035
8273
|
} catch {
|
|
8036
8274
|
const parent = dirname(at);
|
|
8037
8275
|
if (parent === at) {
|
|
@@ -8043,6 +8281,14 @@ function realAsFarAsItExists(path) {
|
|
|
8043
8281
|
}
|
|
8044
8282
|
}
|
|
8045
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
|
+
|
|
8046
8292
|
// src/harnesses.ts
|
|
8047
8293
|
var SERVER_KEY = "gdharness";
|
|
8048
8294
|
function tomlArray(values) {
|
|
@@ -8065,7 +8311,7 @@ var HARNESSES = [
|
|
|
8065
8311
|
shape: "plain",
|
|
8066
8312
|
home: ".claude",
|
|
8067
8313
|
marker: ".claude",
|
|
8068
|
-
skills: { dir:
|
|
8314
|
+
skills: { dir: join4(".claude", "skills"), shared: false }
|
|
8069
8315
|
},
|
|
8070
8316
|
{
|
|
8071
8317
|
id: "copilot-cli",
|
|
@@ -8075,7 +8321,7 @@ var HARNESSES = [
|
|
|
8075
8321
|
container: "mcpServers",
|
|
8076
8322
|
shape: "plain",
|
|
8077
8323
|
home: ".copilot",
|
|
8078
|
-
skills: { dir:
|
|
8324
|
+
skills: { dir: join4(".github", "skills"), shared: true },
|
|
8079
8325
|
manual: "Trust the folder when Copilot CLI first asks, or it reads no config here."
|
|
8080
8326
|
},
|
|
8081
8327
|
{
|
|
@@ -8101,22 +8347,22 @@ var HARNESSES = [
|
|
|
8101
8347
|
id: "cursor",
|
|
8102
8348
|
name: "Cursor",
|
|
8103
8349
|
scope: "project",
|
|
8104
|
-
file:
|
|
8350
|
+
file: join4(".cursor", "mcp.json"),
|
|
8105
8351
|
container: "mcpServers",
|
|
8106
8352
|
shape: "plain",
|
|
8107
8353
|
home: ".cursor",
|
|
8108
|
-
skills: { dir:
|
|
8354
|
+
skills: { dir: join4(".cursor", "skills"), shared: true },
|
|
8109
8355
|
manual: "Cursor asks before each tool call by default, and the server can be toggled off."
|
|
8110
8356
|
},
|
|
8111
8357
|
{
|
|
8112
8358
|
id: "vscode",
|
|
8113
8359
|
name: "VS Code",
|
|
8114
8360
|
scope: "project",
|
|
8115
|
-
file:
|
|
8361
|
+
file: join4(".vscode", "mcp.json"),
|
|
8116
8362
|
container: "servers",
|
|
8117
8363
|
shape: "typed",
|
|
8118
8364
|
home: ".vscode",
|
|
8119
|
-
skills: { dir:
|
|
8365
|
+
skills: { dir: join4(".github", "skills"), shared: true },
|
|
8120
8366
|
manual: "VS Code asks you to trust a server the first time it starts one."
|
|
8121
8367
|
},
|
|
8122
8368
|
{
|
|
@@ -8126,45 +8372,45 @@ var HARNESSES = [
|
|
|
8126
8372
|
file: "opencode.json",
|
|
8127
8373
|
container: "mcp",
|
|
8128
8374
|
shape: "opencode",
|
|
8129
|
-
home:
|
|
8375
|
+
home: join4(".config", "opencode"),
|
|
8130
8376
|
marker: ".opencode",
|
|
8131
|
-
skills: { dir:
|
|
8377
|
+
skills: { dir: join4(".opencode", "skills"), shared: true }
|
|
8132
8378
|
},
|
|
8133
8379
|
{
|
|
8134
8380
|
id: "junie",
|
|
8135
8381
|
name: "Junie",
|
|
8136
8382
|
scope: "project",
|
|
8137
|
-
file:
|
|
8383
|
+
file: join4(".junie", "mcp", "mcp.json"),
|
|
8138
8384
|
container: "mcpServers",
|
|
8139
8385
|
shape: "plain",
|
|
8140
8386
|
home: ".junie",
|
|
8141
|
-
skills: { dir:
|
|
8387
|
+
skills: { dir: join4(".junie", "skills"), shared: true }
|
|
8142
8388
|
},
|
|
8143
8389
|
{
|
|
8144
8390
|
id: "kiro",
|
|
8145
8391
|
name: "Kiro",
|
|
8146
8392
|
scope: "project",
|
|
8147
|
-
file:
|
|
8393
|
+
file: join4(".kiro", "settings", "mcp.json"),
|
|
8148
8394
|
container: "mcpServers",
|
|
8149
8395
|
shape: "plain",
|
|
8150
8396
|
home: ".kiro",
|
|
8151
|
-
skills: { dir:
|
|
8397
|
+
skills: { dir: join4(".kiro", "skills"), shared: false }
|
|
8152
8398
|
},
|
|
8153
8399
|
{
|
|
8154
8400
|
id: "gemini",
|
|
8155
8401
|
name: "Gemini CLI",
|
|
8156
8402
|
scope: "project",
|
|
8157
|
-
file:
|
|
8403
|
+
file: join4(".gemini", "settings.json"),
|
|
8158
8404
|
container: "mcpServers",
|
|
8159
8405
|
shape: "plain",
|
|
8160
8406
|
home: ".gemini",
|
|
8161
|
-
skills: { dir:
|
|
8407
|
+
skills: { dir: join4(".gemini", "skills"), shared: true }
|
|
8162
8408
|
},
|
|
8163
8409
|
{
|
|
8164
8410
|
id: "roo",
|
|
8165
8411
|
name: "Roo Code",
|
|
8166
8412
|
scope: "project",
|
|
8167
|
-
file:
|
|
8413
|
+
file: join4(".roo", "mcp.json"),
|
|
8168
8414
|
container: "mcpServers",
|
|
8169
8415
|
shape: "plain"
|
|
8170
8416
|
},
|
|
@@ -8172,7 +8418,7 @@ var HARNESSES = [
|
|
|
8172
8418
|
id: "kilo",
|
|
8173
8419
|
name: "Kilo Code",
|
|
8174
8420
|
scope: "project",
|
|
8175
|
-
file:
|
|
8421
|
+
file: join4(".kilocode", "mcp.json"),
|
|
8176
8422
|
container: "mcpServers",
|
|
8177
8423
|
shape: "plain"
|
|
8178
8424
|
},
|
|
@@ -8180,16 +8426,16 @@ var HARNESSES = [
|
|
|
8180
8426
|
id: "amazon-q",
|
|
8181
8427
|
name: "Amazon Q Developer CLI",
|
|
8182
8428
|
scope: "project",
|
|
8183
|
-
file:
|
|
8429
|
+
file: join4(".amazonq", "mcp.json"),
|
|
8184
8430
|
container: "mcpServers",
|
|
8185
8431
|
shape: "plain",
|
|
8186
|
-
home:
|
|
8432
|
+
home: join4(".aws", "amazonq")
|
|
8187
8433
|
},
|
|
8188
8434
|
{
|
|
8189
8435
|
id: "zed",
|
|
8190
8436
|
name: "Zed",
|
|
8191
8437
|
scope: "project",
|
|
8192
|
-
file:
|
|
8438
|
+
file: join4(".zed", "settings.json"),
|
|
8193
8439
|
container: "context_servers",
|
|
8194
8440
|
shape: "plain"
|
|
8195
8441
|
},
|
|
@@ -8197,16 +8443,16 @@ var HARNESSES = [
|
|
|
8197
8443
|
id: "amp",
|
|
8198
8444
|
name: "Amp",
|
|
8199
8445
|
scope: "project",
|
|
8200
|
-
file:
|
|
8446
|
+
file: join4(".amp", "settings.json"),
|
|
8201
8447
|
container: "amp.mcpServers",
|
|
8202
8448
|
shape: "plain",
|
|
8203
|
-
home:
|
|
8449
|
+
home: join4(".config", "amp")
|
|
8204
8450
|
},
|
|
8205
8451
|
{
|
|
8206
8452
|
id: "warp",
|
|
8207
8453
|
name: "Warp",
|
|
8208
8454
|
scope: "project",
|
|
8209
|
-
file:
|
|
8455
|
+
file: join4(".warp", ".mcp.json"),
|
|
8210
8456
|
container: "mcpServers",
|
|
8211
8457
|
shape: "plain",
|
|
8212
8458
|
home: ".warp",
|
|
@@ -8216,7 +8462,7 @@ var HARNESSES = [
|
|
|
8216
8462
|
id: "trae",
|
|
8217
8463
|
name: "Trae",
|
|
8218
8464
|
scope: "project",
|
|
8219
|
-
file:
|
|
8465
|
+
file: join4(".trae", "mcp.json"),
|
|
8220
8466
|
container: "mcpServers",
|
|
8221
8467
|
shape: "plain",
|
|
8222
8468
|
home: ".trae"
|
|
@@ -8225,7 +8471,7 @@ var HARNESSES = [
|
|
|
8225
8471
|
id: "factory",
|
|
8226
8472
|
name: "Factory Droid",
|
|
8227
8473
|
scope: "project",
|
|
8228
|
-
file:
|
|
8474
|
+
file: join4(".factory", "mcp.json"),
|
|
8229
8475
|
container: "mcpServers",
|
|
8230
8476
|
shape: "typed",
|
|
8231
8477
|
home: ".factory"
|
|
@@ -8234,7 +8480,7 @@ var HARNESSES = [
|
|
|
8234
8480
|
id: "tabnine",
|
|
8235
8481
|
name: "Tabnine",
|
|
8236
8482
|
scope: "project",
|
|
8237
|
-
file:
|
|
8483
|
+
file: join4(".tabnine", "mcp_servers.json"),
|
|
8238
8484
|
container: "mcpServers",
|
|
8239
8485
|
shape: "plain",
|
|
8240
8486
|
home: ".tabnine"
|
|
@@ -8251,7 +8497,7 @@ var HARNESSES = [
|
|
|
8251
8497
|
id: "pi",
|
|
8252
8498
|
name: "pi",
|
|
8253
8499
|
scope: "project",
|
|
8254
|
-
file:
|
|
8500
|
+
file: join4(".pi", "mcp.json"),
|
|
8255
8501
|
container: "mcpServers",
|
|
8256
8502
|
shape: "plain",
|
|
8257
8503
|
home: ".pi"
|
|
@@ -8260,7 +8506,7 @@ var HARNESSES = [
|
|
|
8260
8506
|
id: "mistral-vibe",
|
|
8261
8507
|
name: "Mistral Vibe",
|
|
8262
8508
|
scope: "project",
|
|
8263
|
-
file:
|
|
8509
|
+
file: join4(".vibe", "config.toml"),
|
|
8264
8510
|
container: "mcp_servers",
|
|
8265
8511
|
shape: "plain",
|
|
8266
8512
|
toml: {
|
|
@@ -8316,7 +8562,7 @@ var HARNESSES = [
|
|
|
8316
8562
|
id: "codex",
|
|
8317
8563
|
name: "Codex CLI",
|
|
8318
8564
|
scope: "home",
|
|
8319
|
-
file:
|
|
8565
|
+
file: join4(".codex", "config.toml"),
|
|
8320
8566
|
container: "mcp_servers",
|
|
8321
8567
|
shape: "plain",
|
|
8322
8568
|
manual: "Codex reads its config at startup, so restart it.",
|
|
@@ -8335,20 +8581,20 @@ var HARNESSES = [
|
|
|
8335
8581
|
id: "cline",
|
|
8336
8582
|
name: "Cline",
|
|
8337
8583
|
scope: "home",
|
|
8338
|
-
file:
|
|
8584
|
+
file: join4(".cline", "data", "settings", "cline_mcp_settings.json"),
|
|
8339
8585
|
container: "mcpServers",
|
|
8340
8586
|
shape: "plain",
|
|
8341
8587
|
marker: ".cline",
|
|
8342
|
-
skills: { dir:
|
|
8588
|
+
skills: { dir: join4(".cline", "skills"), shared: false }
|
|
8343
8589
|
},
|
|
8344
8590
|
{
|
|
8345
8591
|
id: "goose",
|
|
8346
8592
|
name: "Goose",
|
|
8347
8593
|
scope: "home",
|
|
8348
8594
|
file: {
|
|
8349
|
-
win32: { appData:
|
|
8350
|
-
darwin:
|
|
8351
|
-
linux:
|
|
8595
|
+
win32: { appData: join4("Block", "goose", "config", "config.yaml") },
|
|
8596
|
+
darwin: join4(".config", "goose", "config.yaml"),
|
|
8597
|
+
linux: join4(".config", "goose", "config.yaml")
|
|
8352
8598
|
},
|
|
8353
8599
|
container: "extensions",
|
|
8354
8600
|
shape: "plain",
|
|
@@ -8369,19 +8615,19 @@ var HARNESSES = [
|
|
|
8369
8615
|
id: "windsurf",
|
|
8370
8616
|
name: "Windsurf",
|
|
8371
8617
|
scope: "home",
|
|
8372
|
-
file:
|
|
8618
|
+
file: join4(".codeium", "windsurf", "mcp_config.json"),
|
|
8373
8619
|
container: "mcpServers",
|
|
8374
8620
|
shape: "plain",
|
|
8375
|
-
skills: { dir:
|
|
8621
|
+
skills: { dir: join4(".windsurf", "skills"), shared: true }
|
|
8376
8622
|
},
|
|
8377
8623
|
{
|
|
8378
8624
|
id: "hermes",
|
|
8379
8625
|
name: "Hermes",
|
|
8380
8626
|
scope: "home",
|
|
8381
|
-
file:
|
|
8627
|
+
file: join4(".hermes", "config.yaml"),
|
|
8382
8628
|
container: "mcp_servers",
|
|
8383
8629
|
shape: "plain",
|
|
8384
|
-
skills: { dir:
|
|
8630
|
+
skills: { dir: join4(".hermes", "skills"), shared: true },
|
|
8385
8631
|
yaml: {
|
|
8386
8632
|
path: ["mcp_servers", SERVER_KEY],
|
|
8387
8633
|
entry: (launch) => ({
|
|
@@ -8396,7 +8642,7 @@ var HARNESSES = [
|
|
|
8396
8642
|
id: "openclaw",
|
|
8397
8643
|
name: "OpenClaw",
|
|
8398
8644
|
scope: "home",
|
|
8399
|
-
file:
|
|
8645
|
+
file: join4(".openclaw", "openclaw.json"),
|
|
8400
8646
|
container: "mcpServers",
|
|
8401
8647
|
shape: "plain"
|
|
8402
8648
|
},
|
|
@@ -8405,9 +8651,9 @@ var HARNESSES = [
|
|
|
8405
8651
|
name: "Claude Desktop",
|
|
8406
8652
|
scope: "home",
|
|
8407
8653
|
file: {
|
|
8408
|
-
win32: { appData:
|
|
8409
|
-
darwin:
|
|
8410
|
-
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")
|
|
8411
8657
|
},
|
|
8412
8658
|
container: "mcpServers",
|
|
8413
8659
|
shape: "plain"
|
|
@@ -8416,7 +8662,7 @@ var HARNESSES = [
|
|
|
8416
8662
|
id: "zeroclaw",
|
|
8417
8663
|
name: "ZeroClaw",
|
|
8418
8664
|
scope: "home",
|
|
8419
|
-
file:
|
|
8665
|
+
file: join4(".zeroclaw", "config.toml"),
|
|
8420
8666
|
container: "mcp.servers",
|
|
8421
8667
|
shape: "plain",
|
|
8422
8668
|
toml: {
|
|
@@ -8437,7 +8683,7 @@ var HARNESSES = [
|
|
|
8437
8683
|
id: "deepcode",
|
|
8438
8684
|
name: "Deep Code",
|
|
8439
8685
|
scope: "home",
|
|
8440
|
-
file:
|
|
8686
|
+
file: join4(".deepcode", "settings.json"),
|
|
8441
8687
|
container: "mcpServers",
|
|
8442
8688
|
shape: "plain"
|
|
8443
8689
|
},
|
|
@@ -8445,7 +8691,7 @@ var HARNESSES = [
|
|
|
8445
8691
|
id: "nanobot",
|
|
8446
8692
|
name: "nanobot",
|
|
8447
8693
|
scope: "home",
|
|
8448
|
-
file:
|
|
8694
|
+
file: join4(".nanobot", "config.json"),
|
|
8449
8695
|
container: "mcpServers",
|
|
8450
8696
|
shape: "plain",
|
|
8451
8697
|
snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
|
|
@@ -8454,7 +8700,7 @@ var HARNESSES = [
|
|
|
8454
8700
|
id: "autohand",
|
|
8455
8701
|
name: "Autohand",
|
|
8456
8702
|
scope: "home",
|
|
8457
|
-
file:
|
|
8703
|
+
file: join4(".autohand", "config.json"),
|
|
8458
8704
|
container: "mcpServers",
|
|
8459
8705
|
shape: "plain",
|
|
8460
8706
|
snippet: (launch) => jsonSnippet(launch, "mcpServers", "plain")
|
|
@@ -8463,7 +8709,7 @@ var HARNESSES = [
|
|
|
8463
8709
|
var OURS = ["GODOT_PATH", "GDHARNESS_PROJECT"];
|
|
8464
8710
|
function environmentFor(launch, held) {
|
|
8465
8711
|
const kept = {};
|
|
8466
|
-
if (
|
|
8712
|
+
if (isRecord(held)) {
|
|
8467
8713
|
for (const [name, value] of Object.entries(held)) {
|
|
8468
8714
|
if (typeof value === "string" && !OURS.includes(name)) {
|
|
8469
8715
|
kept[name] = value;
|
|
@@ -8473,7 +8719,7 @@ function environmentFor(launch, held) {
|
|
|
8473
8719
|
return { ...kept, ...launch.env };
|
|
8474
8720
|
}
|
|
8475
8721
|
function entryFor(shape, launch, held) {
|
|
8476
|
-
const before =
|
|
8722
|
+
const before = isRecord(held) ? { ...held } : {};
|
|
8477
8723
|
if (shape === "opencode") {
|
|
8478
8724
|
return {
|
|
8479
8725
|
...before,
|
|
@@ -8499,7 +8745,15 @@ var LOG_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
|
8499
8745
|
var DECLARING = new Set(["var", "const", "func", "signal", "enum", "class", "for", "class_name"]);
|
|
8500
8746
|
var NAME = "[\\p{L}_][\\p{L}\\p{N}_]*";
|
|
8501
8747
|
var ANNOTATIONS = "(?:@[\\p{L}_][\\p{L}\\p{N}_]*(?:\\([^)]*\\))?\\s+)*";
|
|
8502
|
-
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");
|
|
8503
8757
|
var CLASS_NAME_LINE = new RegExp(`^${ANNOTATIONS}class_name\\s+(${NAME})`, "u");
|
|
8504
8758
|
var EXTENDS_LINE = new RegExp(`^${ANNOTATIONS}(?:class_name\\s+${NAME}\\s+)?extends\\s`, "u");
|
|
8505
8759
|
var FUNC_LINE = new RegExp(`^[ \\t]*${ANNOTATIONS}(?:static\\s+)?func\\s+(${NAME})\\s*\\(`, "u");
|
|
@@ -8553,7 +8807,7 @@ var KEYWORDS = new Set([
|
|
|
8553
8807
|
]);
|
|
8554
8808
|
|
|
8555
8809
|
// src/whole-file.ts
|
|
8556
|
-
import { readFileSync as
|
|
8810
|
+
import { readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
8557
8811
|
var HELD_FILE_MS = 1000;
|
|
8558
8812
|
var HELD_FILE_RETRY_MS = 10;
|
|
8559
8813
|
var HELD_BY_A_READER = new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
@@ -8561,9 +8815,9 @@ function readWhole(path) {
|
|
|
8561
8815
|
const until = Date.now() + HELD_FILE_MS;
|
|
8562
8816
|
for (;; ) {
|
|
8563
8817
|
try {
|
|
8564
|
-
return
|
|
8818
|
+
return readFileSync4(path, "utf8");
|
|
8565
8819
|
} catch (error) {
|
|
8566
|
-
const code = error
|
|
8820
|
+
const code = errorCode(error) ?? "";
|
|
8567
8821
|
if (code === "ENOENT") {
|
|
8568
8822
|
return null;
|
|
8569
8823
|
}
|
|
@@ -8577,20 +8831,20 @@ function readWhole(path) {
|
|
|
8577
8831
|
function writeWhole(path, text) {
|
|
8578
8832
|
const partial = `${path}.${process.pid}.partial`;
|
|
8579
8833
|
try {
|
|
8580
|
-
|
|
8834
|
+
writeFileSync4(partial, text, "utf8");
|
|
8581
8835
|
} catch {
|
|
8582
8836
|
return false;
|
|
8583
8837
|
}
|
|
8584
8838
|
const until = Date.now() + HELD_FILE_MS;
|
|
8585
8839
|
for (;; ) {
|
|
8586
8840
|
try {
|
|
8587
|
-
|
|
8841
|
+
renameSync2(partial, path);
|
|
8588
8842
|
return true;
|
|
8589
8843
|
} catch (error) {
|
|
8590
|
-
const code = error
|
|
8844
|
+
const code = errorCode(error) ?? "";
|
|
8591
8845
|
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
8592
8846
|
try {
|
|
8593
|
-
|
|
8847
|
+
rmSync3(partial, { force: true });
|
|
8594
8848
|
} catch {}
|
|
8595
8849
|
return false;
|
|
8596
8850
|
}
|
|
@@ -8602,10 +8856,10 @@ function removeWhole(path) {
|
|
|
8602
8856
|
const until = Date.now() + HELD_FILE_MS;
|
|
8603
8857
|
for (;; ) {
|
|
8604
8858
|
try {
|
|
8605
|
-
|
|
8859
|
+
rmSync3(path, { force: true });
|
|
8606
8860
|
return true;
|
|
8607
8861
|
} catch (error) {
|
|
8608
|
-
const code = error
|
|
8862
|
+
const code = errorCode(error) ?? "";
|
|
8609
8863
|
if (!HELD_BY_A_READER.has(code) || Date.now() >= until) {
|
|
8610
8864
|
return false;
|
|
8611
8865
|
}
|
|
@@ -8615,7 +8869,7 @@ function removeWhole(path) {
|
|
|
8615
8869
|
}
|
|
8616
8870
|
|
|
8617
8871
|
// src/engine-leaks.ts
|
|
8618
|
-
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.";
|
|
8619
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.";
|
|
8620
8874
|
var NAME2 = "[\\p{L}_][\\p{L}\\p{N}_]*";
|
|
8621
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");
|
|
@@ -8668,7 +8922,7 @@ var MEMORY_PER_ENGINE = 1.5 * 1024 ** 3;
|
|
|
8668
8922
|
var SCAN_BYTES = 1024 * 1024;
|
|
8669
8923
|
|
|
8670
8924
|
// src/process-children.ts
|
|
8671
|
-
import { readFileSync as
|
|
8925
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
8672
8926
|
import { basename as basename3 } from "node:path";
|
|
8673
8927
|
async function startTimesOf(pids) {
|
|
8674
8928
|
const began = new Map;
|
|
@@ -8710,7 +8964,7 @@ async function linuxStartTimes(pids) {
|
|
|
8710
8964
|
const hertz = await ticksPerSecond();
|
|
8711
8965
|
let booted;
|
|
8712
8966
|
try {
|
|
8713
|
-
booted = Number(/^btime\s+(\d+)$/m.exec(
|
|
8967
|
+
booted = Number(/^btime\s+(\d+)$/m.exec(readFileSync5("/proc/stat", "utf8"))?.[1] ?? Number.NaN) * 1000;
|
|
8714
8968
|
} catch {
|
|
8715
8969
|
return began;
|
|
8716
8970
|
}
|
|
@@ -8720,7 +8974,7 @@ async function linuxStartTimes(pids) {
|
|
|
8720
8974
|
for (const pid of pids) {
|
|
8721
8975
|
let stat;
|
|
8722
8976
|
try {
|
|
8723
|
-
stat =
|
|
8977
|
+
stat = readFileSync5(`/proc/${String(pid)}/stat`, "utf8");
|
|
8724
8978
|
} catch {
|
|
8725
8979
|
continue;
|
|
8726
8980
|
}
|
|
@@ -8750,7 +9004,7 @@ async function ticksPerSecond() {
|
|
|
8750
9004
|
}
|
|
8751
9005
|
function printedBy(command, args, env) {
|
|
8752
9006
|
return runHidden(command, args, { timeout: ASK_TIMEOUT_MS, env }).then(({ stdout }) => stdout, (error) => {
|
|
8753
|
-
const printed = error.stdout;
|
|
9007
|
+
const printed = error instanceof Error && "stdout" in error ? error.stdout : undefined;
|
|
8754
9008
|
return typeof printed === "string" ? printed : "";
|
|
8755
9009
|
});
|
|
8756
9010
|
}
|
|
@@ -8882,7 +9136,7 @@ function nameSlotEngine(lock, holder, engine) {
|
|
|
8882
9136
|
}
|
|
8883
9137
|
function giveBackSlot(lock, pid) {
|
|
8884
9138
|
try {
|
|
8885
|
-
if (holderOf(
|
|
9139
|
+
if (holderOf(readFileSync6(lock, "utf8"))?.pid === pid) {
|
|
8886
9140
|
removeWhole(lock);
|
|
8887
9141
|
}
|
|
8888
9142
|
} catch {}
|
|
@@ -8916,9 +9170,9 @@ function crashesReported() {
|
|
|
8916
9170
|
}
|
|
8917
9171
|
|
|
8918
9172
|
// src/game-debugger.ts
|
|
8919
|
-
import { readFileSync as
|
|
9173
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
8920
9174
|
import { createServer } from "node:net";
|
|
8921
|
-
import { join as
|
|
9175
|
+
import { join as join7 } from "node:path";
|
|
8922
9176
|
|
|
8923
9177
|
// src/godot-variant.ts
|
|
8924
9178
|
var NIL = 0;
|
|
@@ -9223,8 +9477,8 @@ function readMessage(body) {
|
|
|
9223
9477
|
}
|
|
9224
9478
|
|
|
9225
9479
|
// src/setup.ts
|
|
9226
|
-
import { dirname as dirname3, join as
|
|
9227
|
-
import { fileURLToPath } from "node:url";
|
|
9480
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
9481
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
9228
9482
|
|
|
9229
9483
|
// src/dictionary.ts
|
|
9230
9484
|
function emptyRecord() {
|
|
@@ -9338,25 +9592,25 @@ var IMPORTABLE = new Set(IMPORTABLE_EXTENSIONS);
|
|
|
9338
9592
|
var hashes = new Map;
|
|
9339
9593
|
|
|
9340
9594
|
// src/scratch.ts
|
|
9341
|
-
import { existsSync as
|
|
9595
|
+
import { existsSync as existsSync4, mkdtempSync as mkdtempSync2, readdirSync as readdirSync3, rmSync as rmSync5 } from "node:fs";
|
|
9342
9596
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
9343
|
-
import { join as
|
|
9597
|
+
import { join as join5 } from "node:path";
|
|
9344
9598
|
import process6 from "node:process";
|
|
9345
9599
|
var SWEPT = { recursive: true, force: true };
|
|
9346
9600
|
var AGAIN_AFTER_MS = [250, 500, 1000, 2000, 4000, 8000, 16000];
|
|
9347
9601
|
var waiting = new Set;
|
|
9348
9602
|
var atExit = new Set;
|
|
9349
9603
|
function scratchDirectory(kind) {
|
|
9350
|
-
return mkdtempSync2(
|
|
9604
|
+
return mkdtempSync2(join5(tmpdir5(), `gdharness-${kind}-${process6.pid}-`));
|
|
9351
9605
|
}
|
|
9352
|
-
function discardWith(
|
|
9606
|
+
function discardWith(removePath, paths) {
|
|
9353
9607
|
const left = [];
|
|
9354
9608
|
for (const path of paths) {
|
|
9355
9609
|
if (!path) {
|
|
9356
9610
|
continue;
|
|
9357
9611
|
}
|
|
9358
9612
|
try {
|
|
9359
|
-
|
|
9613
|
+
removePath(path);
|
|
9360
9614
|
} catch (error) {
|
|
9361
9615
|
left.push({ path, reason: error instanceof Error ? error.message : String(error) });
|
|
9362
9616
|
}
|
|
@@ -9371,7 +9625,7 @@ function discard(...paths) {
|
|
|
9371
9625
|
return left;
|
|
9372
9626
|
}
|
|
9373
9627
|
function remove(path) {
|
|
9374
|
-
|
|
9628
|
+
rmSync5(path, SWEPT);
|
|
9375
9629
|
}
|
|
9376
9630
|
function tryAgain(path, attempt) {
|
|
9377
9631
|
if (attempt === 0) {
|
|
@@ -9383,7 +9637,7 @@ function tryAgain(path, attempt) {
|
|
|
9383
9637
|
lastTryOnExit();
|
|
9384
9638
|
}
|
|
9385
9639
|
const after = AGAIN_AFTER_MS[attempt];
|
|
9386
|
-
if (after === undefined || !
|
|
9640
|
+
if (after === undefined || !existsSync4(path)) {
|
|
9387
9641
|
waiting.delete(path);
|
|
9388
9642
|
if (after === undefined) {
|
|
9389
9643
|
atExit.add(path);
|
|
@@ -9532,7 +9786,7 @@ function parseIniLikeValue(value) {
|
|
|
9532
9786
|
}
|
|
9533
9787
|
|
|
9534
9788
|
// src/server-version.ts
|
|
9535
|
-
import { readFileSync as
|
|
9789
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
9536
9790
|
|
|
9537
9791
|
// src/update-check.ts
|
|
9538
9792
|
var CACHE_MS = 10 * 60 * 1000;
|
|
@@ -9543,8 +9797,9 @@ var MAX_RETRY_MS = 60 * 60 * 1000;
|
|
|
9543
9797
|
var DEBUG_MODE = process.env["GDHARNESS_DEBUG"] === "1";
|
|
9544
9798
|
var SERVER_VERSION = (() => {
|
|
9545
9799
|
try {
|
|
9546
|
-
const pkg = JSON.parse(
|
|
9547
|
-
|
|
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";
|
|
9548
9803
|
} catch {
|
|
9549
9804
|
return "0.0.0";
|
|
9550
9805
|
}
|
|
@@ -9556,7 +9811,7 @@ var RUNTIME_AUTOLOAD = {
|
|
|
9556
9811
|
path: "gdharness/loader.gd"
|
|
9557
9812
|
};
|
|
9558
9813
|
function shippedAddonsDirectory() {
|
|
9559
|
-
return
|
|
9814
|
+
return join6(dirname3(fileURLToPath2(import.meta.url)), "godot", "addons");
|
|
9560
9815
|
}
|
|
9561
9816
|
|
|
9562
9817
|
// src/game-debugger.ts
|
|
@@ -9567,9 +9822,12 @@ var ADDON_LINES = 200;
|
|
|
9567
9822
|
var RUNTIME_ADDON = "res://addons/gdharness_runtime/";
|
|
9568
9823
|
var RUNTIME_AUTOLOAD2 = `${RUNTIME_ADDON}runtime_autoload.gd`;
|
|
9569
9824
|
var frameEnd = null;
|
|
9825
|
+
function topIsTheAddon(frames) {
|
|
9826
|
+
return frames[0]?.script.startsWith(RUNTIME_ADDON) ?? false;
|
|
9827
|
+
}
|
|
9570
9828
|
function frameEndLine() {
|
|
9571
9829
|
if (frameEnd === null) {
|
|
9572
|
-
const lines =
|
|
9830
|
+
const lines = readFileSync8(join7(shippedAddonsDirectory(), "gdharness_runtime", "runtime_autoload.gd"), "utf8").split(`
|
|
9573
9831
|
`);
|
|
9574
9832
|
const declared = lines.findIndex((line) => line.startsWith("func _notification("));
|
|
9575
9833
|
if (declared === -1) {
|
|
@@ -9969,7 +10227,7 @@ class GameDebugger {
|
|
|
9969
10227
|
if (entered === null) {
|
|
9970
10228
|
return {
|
|
9971
10229
|
paused: false,
|
|
9972
|
-
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.`
|
|
9973
10231
|
};
|
|
9974
10232
|
}
|
|
9975
10233
|
}
|
|
@@ -9984,7 +10242,7 @@ class GameDebugger {
|
|
|
9984
10242
|
if (again === null) {
|
|
9985
10243
|
return {
|
|
9986
10244
|
paused: false,
|
|
9987
|
-
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.`
|
|
9988
10246
|
};
|
|
9989
10247
|
}
|
|
9990
10248
|
}
|
|
@@ -9992,7 +10250,7 @@ class GameDebugger {
|
|
|
9992
10250
|
if (past === "lost") {
|
|
9993
10251
|
return {
|
|
9994
10252
|
paused: false,
|
|
9995
|
-
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.`
|
|
9996
10254
|
};
|
|
9997
10255
|
}
|
|
9998
10256
|
this.stoppedBy("Paused");
|
|
@@ -10012,7 +10270,7 @@ class GameDebugger {
|
|
|
10012
10270
|
let frames = await this.stack();
|
|
10013
10271
|
let framesLeft = ADDON_FRAMES;
|
|
10014
10272
|
let linesLeft = ADDON_LINES;
|
|
10015
|
-
while (frames !== null && this.held !== null && (frames
|
|
10273
|
+
while (frames !== null && this.held !== null && topIsTheAddon(frames)) {
|
|
10016
10274
|
if (until !== undefined && Date.now() >= until) {
|
|
10017
10275
|
return { frames, gaveUp: "time" };
|
|
10018
10276
|
}
|
|
@@ -10092,7 +10350,7 @@ class GameDebugger {
|
|
|
10092
10350
|
return {
|
|
10093
10351
|
stepped: true,
|
|
10094
10352
|
heldAgain: false,
|
|
10095
|
-
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.`
|
|
10096
10354
|
};
|
|
10097
10355
|
}
|
|
10098
10356
|
this.stoppedBy("Stepped");
|
|
@@ -10210,7 +10468,7 @@ class GameDebugger {
|
|
|
10210
10468
|
return null;
|
|
10211
10469
|
}
|
|
10212
10470
|
return {
|
|
10213
|
-
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(", ")}.`
|
|
10214
10472
|
};
|
|
10215
10473
|
}
|
|
10216
10474
|
close() {
|
|
@@ -10221,10 +10479,10 @@ class GameDebugger {
|
|
|
10221
10479
|
|
|
10222
10480
|
// src/keeper-channel.ts
|
|
10223
10481
|
import { randomUUID } from "node:crypto";
|
|
10224
|
-
import { mkdtempSync as mkdtempSync3, rmSync as
|
|
10482
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync6 } from "node:fs";
|
|
10225
10483
|
import { connect, createServer as createServer2 } from "node:net";
|
|
10226
10484
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
10227
|
-
import { join as
|
|
10485
|
+
import { join as join8 } from "node:path";
|
|
10228
10486
|
import process7 from "node:process";
|
|
10229
10487
|
var DEBUG_PREFIX = "debug ";
|
|
10230
10488
|
function endedOrWhyNot(end) {
|
|
@@ -10240,11 +10498,41 @@ async function debuggedOrWhyNot(debug, asked) {
|
|
|
10240
10498
|
return JSON.stringify({ refused: "This run has no debugger." });
|
|
10241
10499
|
}
|
|
10242
10500
|
try {
|
|
10243
|
-
|
|
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));
|
|
10244
10506
|
} catch (error) {
|
|
10245
10507
|
return JSON.stringify({ refused: `The debugger could not answer: ${errorText(error)}` });
|
|
10246
10508
|
}
|
|
10247
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
|
+
}
|
|
10248
10536
|
function errorText(error) {
|
|
10249
10537
|
return (error instanceof Error ? error.message : String(error)).replaceAll(`
|
|
10250
10538
|
`, " ");
|
|
@@ -10252,8 +10540,8 @@ function errorText(error) {
|
|
|
10252
10540
|
async function listenForTheServer(end, debug) {
|
|
10253
10541
|
let directory = null;
|
|
10254
10542
|
try {
|
|
10255
|
-
directory = process7.platform === "win32" ? null : mkdtempSync3(
|
|
10256
|
-
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");
|
|
10257
10545
|
const server = createServer2((socket) => {
|
|
10258
10546
|
socket.setEncoding("utf8");
|
|
10259
10547
|
socket.on("error", () => {});
|
|
@@ -10289,13 +10577,13 @@ async function listenForTheServer(end, debug) {
|
|
|
10289
10577
|
close: () => {
|
|
10290
10578
|
server.close();
|
|
10291
10579
|
if (made !== null) {
|
|
10292
|
-
|
|
10580
|
+
rmSync6(made, { recursive: true, force: true });
|
|
10293
10581
|
}
|
|
10294
10582
|
}
|
|
10295
10583
|
};
|
|
10296
10584
|
} catch {
|
|
10297
10585
|
if (directory !== null) {
|
|
10298
|
-
|
|
10586
|
+
rmSync6(directory, { recursive: true, force: true });
|
|
10299
10587
|
}
|
|
10300
10588
|
return null;
|
|
10301
10589
|
}
|
|
@@ -10311,7 +10599,9 @@ function listening(server, address) {
|
|
|
10311
10599
|
}
|
|
10312
10600
|
|
|
10313
10601
|
// src/outside.ts
|
|
10314
|
-
import
|
|
10602
|
+
import process8 from "node:process";
|
|
10603
|
+
import { text } from "node:stream/consumers";
|
|
10604
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
10315
10605
|
function withChanges(base, changes) {
|
|
10316
10606
|
const env = { ...base };
|
|
10317
10607
|
for (const [name, value] of Object.entries(changes)) {
|
|
@@ -10327,13 +10617,70 @@ function sendSpec(child, spec) {
|
|
|
10327
10617
|
child.stdin?.end(JSON.stringify(spec), "utf8");
|
|
10328
10618
|
}
|
|
10329
10619
|
async function receivedSpec() {
|
|
10330
|
-
const
|
|
10331
|
-
|
|
10332
|
-
|
|
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)}`);
|
|
10624
|
+
}
|
|
10625
|
+
return spec;
|
|
10626
|
+
}
|
|
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;
|
|
10333
10643
|
}
|
|
10334
|
-
|
|
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
|
+
};
|
|
10335
10682
|
}
|
|
10336
|
-
var KEEPER_SCRIPT =
|
|
10683
|
+
var KEEPER_SCRIPT = fileURLToPath3(new URL("./keeper.js", import.meta.url));
|
|
10337
10684
|
function readLaunched(printed) {
|
|
10338
10685
|
const line = printed.split(`
|
|
10339
10686
|
`).find((one) => one.trim() !== "")?.trim() ?? "";
|
|
@@ -10346,12 +10693,12 @@ function readLaunched(printed) {
|
|
|
10346
10693
|
|
|
10347
10694
|
// src/run-record.ts
|
|
10348
10695
|
import { createHash as createHash2 } from "node:crypto";
|
|
10349
|
-
import { mkdirSync as mkdirSync2, openSync as openSync3, readdirSync as
|
|
10350
|
-
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";
|
|
10351
10698
|
|
|
10352
10699
|
// src/runtime-client.ts
|
|
10353
10700
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
10354
|
-
import { dirname as dirname4, join as
|
|
10701
|
+
import { dirname as dirname4, join as join9, resolve as resolve4 } from "node:path";
|
|
10355
10702
|
|
|
10356
10703
|
// src/launch.ts
|
|
10357
10704
|
function envValue(name, variables = process.env) {
|
|
@@ -10396,7 +10743,7 @@ function runtimeDirectory(variables = process.env) {
|
|
|
10396
10743
|
return explicit;
|
|
10397
10744
|
}
|
|
10398
10745
|
const perUser = envValue("XDG_RUNTIME_DIR", variables);
|
|
10399
|
-
return
|
|
10746
|
+
return join9(perUser ?? tmpdir7(), "gdharness");
|
|
10400
10747
|
}
|
|
10401
10748
|
var ERROR_REPORT_KEEP_MS = 60 * 60 * 1000;
|
|
10402
10749
|
var verdicts = new Map;
|
|
@@ -10406,15 +10753,15 @@ var untaken = new Map;
|
|
|
10406
10753
|
|
|
10407
10754
|
// src/run-record.ts
|
|
10408
10755
|
function runsDirectory() {
|
|
10409
|
-
return
|
|
10756
|
+
return join10(runtimeDirectory(), "runs");
|
|
10410
10757
|
}
|
|
10411
10758
|
function projectKey(projectPath) {
|
|
10412
|
-
const real = realAsFarAsItExists(
|
|
10759
|
+
const real = realAsFarAsItExists(resolve5(projectPath)).replace(/[\\/]+$/, "");
|
|
10413
10760
|
const folded = process.platform === "win32" || process.platform === "darwin" ? real.toLowerCase() : real;
|
|
10414
10761
|
return createHash2("sha256").update(folded.replaceAll("\\", "/")).digest("hex").slice(0, 16);
|
|
10415
10762
|
}
|
|
10416
10763
|
function runRecordPath(projectPath, directory = runtimeDirectory()) {
|
|
10417
|
-
return
|
|
10764
|
+
return join10(directory, "runs", `note-${projectKey(projectPath)}.json`);
|
|
10418
10765
|
}
|
|
10419
10766
|
function writeRunRecord(record) {
|
|
10420
10767
|
mkdirSync2(runsDirectory(), { recursive: true });
|
|
@@ -10442,11 +10789,11 @@ function recordRunEnded(projectPath, pid, ending) {
|
|
|
10442
10789
|
function recordAt(path) {
|
|
10443
10790
|
let parsed;
|
|
10444
10791
|
try {
|
|
10445
|
-
parsed = JSON.parse(
|
|
10792
|
+
parsed = JSON.parse(readFileSync9(path, "utf8"));
|
|
10446
10793
|
} catch {
|
|
10447
10794
|
return null;
|
|
10448
10795
|
}
|
|
10449
|
-
if (!parsed
|
|
10796
|
+
if (!isRecord(parsed)) {
|
|
10450
10797
|
return null;
|
|
10451
10798
|
}
|
|
10452
10799
|
const fields = parsed;
|
|
@@ -10484,11 +10831,10 @@ function recordAt(path) {
|
|
|
10484
10831
|
};
|
|
10485
10832
|
}
|
|
10486
10833
|
function restartedFromAt(value) {
|
|
10487
|
-
if (!value
|
|
10834
|
+
if (!isRecord(value)) {
|
|
10488
10835
|
return [];
|
|
10489
10836
|
}
|
|
10490
|
-
const
|
|
10491
|
-
const { pid, endedAt, exitCode, exitSignal } = fields;
|
|
10837
|
+
const { pid, endedAt, exitCode, exitSignal } = value;
|
|
10492
10838
|
if (typeof pid !== "number" || typeof endedAt !== "number") {
|
|
10493
10839
|
return [];
|
|
10494
10840
|
}
|
|
@@ -10862,9 +11208,9 @@ async function startDirectly(spec, output, hidden, detached = true, errors = out
|
|
|
10862
11208
|
}
|
|
10863
11209
|
async function startThroughHelper(spec, output, stopFile) {
|
|
10864
11210
|
const scratch = scratchDirectory("desktop");
|
|
10865
|
-
const pidFile =
|
|
10866
|
-
const errorFile =
|
|
10867
|
-
const stepFile =
|
|
11211
|
+
const pidFile = join11(scratch, "pid");
|
|
11212
|
+
const errorFile = join11(scratch, "error");
|
|
11213
|
+
const stepFile = join11(scratch, "step");
|
|
10868
11214
|
const where = spec.desktop !== undefined ? `on the ${spec.desktop} desktop` : spec.noActivate === true ? "without activation" : "through the desktop helper";
|
|
10869
11215
|
try {
|
|
10870
11216
|
const compiled = await ensureHelperCompiled();
|
|
@@ -10872,7 +11218,7 @@ async function startThroughHelper(spec, output, stopFile) {
|
|
|
10872
11218
|
return { error: `it could not be started ${where}: ${compiled}` };
|
|
10873
11219
|
}
|
|
10874
11220
|
const wrapper = throughHelper({ ...spec, directory: process.cwd() }, spec.command, spec.args, {
|
|
10875
|
-
spec:
|
|
11221
|
+
spec: join11(scratch, "spec.json"),
|
|
10876
11222
|
pid: pidFile,
|
|
10877
11223
|
error: errorFile,
|
|
10878
11224
|
stop: stopFile,
|
|
@@ -10888,7 +11234,7 @@ async function startThroughHelper(spec, output, stopFile) {
|
|
|
10888
11234
|
exited.now = true;
|
|
10889
11235
|
});
|
|
10890
11236
|
for (let waited = 0;waited < DESKTOP_START_MS; waited += 50) {
|
|
10891
|
-
const pid =
|
|
11237
|
+
const pid = existsSync5(pidFile) ? Number(readFileSync10(pidFile, "utf8").trim()) : Number.NaN;
|
|
10892
11238
|
if (Number.isInteger(pid) && pid > 0) {
|
|
10893
11239
|
return { child: started.child, pid };
|
|
10894
11240
|
}
|
|
@@ -10919,7 +11265,7 @@ function profiledBy(path, projectPath) {
|
|
|
10919
11265
|
};
|
|
10920
11266
|
let projectGodot = null;
|
|
10921
11267
|
try {
|
|
10922
|
-
projectGodot =
|
|
11268
|
+
projectGodot = readFileSync10(join11(projectPath, "project.godot"), "utf8");
|
|
10923
11269
|
} catch {}
|
|
10924
11270
|
const observer = new ProfileObserver((totals) => {
|
|
10925
11271
|
const first = latest === null;
|
|
@@ -10937,9 +11283,13 @@ function profiledBy(path, projectPath) {
|
|
|
10937
11283
|
if (timer !== null) {
|
|
10938
11284
|
clearTimeout(timer);
|
|
10939
11285
|
}
|
|
10940
|
-
|
|
11286
|
+
const last = observer.totals() ?? latest;
|
|
11287
|
+
latest = last;
|
|
11288
|
+
if (last === null) {
|
|
11289
|
+
return;
|
|
11290
|
+
}
|
|
10941
11291
|
let tries = 0;
|
|
10942
|
-
while (
|
|
11292
|
+
while (!writeProfileFile(path, { ...last, connected: true }) && tries < LAST_WRITE_TRIES) {
|
|
10943
11293
|
tries += 1;
|
|
10944
11294
|
}
|
|
10945
11295
|
}
|
|
@@ -11020,12 +11370,12 @@ async function keep() {
|
|
|
11020
11370
|
}
|
|
11021
11371
|
const profiled = run?.profile === undefined ? null : profiledBy(run.profile, run.projectPath);
|
|
11022
11372
|
const debuggerPeer = run === undefined || run.debugged === false ? null : await GameDebugger.open(run.breakpoints ?? [], profiled === null ? [] : [profiled.observer]);
|
|
11023
|
-
const exitNotes = run === undefined ? null : mkdtempSync4(
|
|
11373
|
+
const exitNotes = run === undefined ? null : mkdtempSync4(join11(tmpdir8(), "gdharness-exit-"));
|
|
11024
11374
|
const noted = exitNotes === null ? spec : { ...spec, envChanges: { ...spec.envChanges, [EXIT_NOTES_VARIABLE]: exitNotes } };
|
|
11025
11375
|
const toStart = debuggerPeer === null ? noted : { ...noted, args: withEngineArguments(noted.args, debuggerPeer.engineArguments) };
|
|
11026
11376
|
const transcript = run === undefined ? "ignore" : openSync4(run.transcript, "a");
|
|
11027
|
-
const own = run !== undefined && throughTheHelper(spec) ? mkdtempSync4(
|
|
11028
|
-
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");
|
|
11029
11379
|
let started;
|
|
11030
11380
|
const keeperStarted = run?.slot === undefined ? undefined : ownStart();
|
|
11031
11381
|
const spawnedAt = Date.now();
|
|
@@ -11062,7 +11412,7 @@ async function keep() {
|
|
|
11062
11412
|
let listening = null;
|
|
11063
11413
|
let end = () => {
|
|
11064
11414
|
if (stopFile !== "") {
|
|
11065
|
-
|
|
11415
|
+
writeFileSync5(stopFile, "");
|
|
11066
11416
|
return "signalled";
|
|
11067
11417
|
}
|
|
11068
11418
|
return child.kill() ? "signalled" : "gone";
|
|
@@ -11164,7 +11514,7 @@ async function keep() {
|
|
|
11164
11514
|
listening?.close();
|
|
11165
11515
|
for (const made of [own, exitNotes]) {
|
|
11166
11516
|
if (made !== null) {
|
|
11167
|
-
|
|
11517
|
+
rmSync8(made, { recursive: true, force: true });
|
|
11168
11518
|
}
|
|
11169
11519
|
}
|
|
11170
11520
|
process.exit(0);
|
|
@@ -11175,7 +11525,7 @@ function restartSaid(notes, pid) {
|
|
|
11175
11525
|
return null;
|
|
11176
11526
|
}
|
|
11177
11527
|
try {
|
|
11178
|
-
const said = JSON.parse(
|
|
11528
|
+
const said = JSON.parse(readFileSync10(join11(notes, `exit-${String(pid)}.json`), "utf8"));
|
|
11179
11529
|
return typeof said === "object" && said !== null && "restart" in said && typeof said.restart === "boolean" ? said.restart : null;
|
|
11180
11530
|
} catch {
|
|
11181
11531
|
return null;
|