@edgemodders/edgedeck-mcp 0.29.0 → 0.29.2
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/dist/core.js +57 -21
- package/dist/mcp.js +38 -7
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -3842,6 +3842,7 @@ __export(core_exports, {
|
|
|
3842
3842
|
registerNxmHandler: () => registerNxmHandler,
|
|
3843
3843
|
removeMod: () => removeMod,
|
|
3844
3844
|
removeOlderBridges: () => removeOlderBridges,
|
|
3845
|
+
removeTemp: () => removeTemp,
|
|
3845
3846
|
renameFamily: () => renameFamily,
|
|
3846
3847
|
renameLoadout: () => renameLoadout,
|
|
3847
3848
|
renameSection: () => renameSection,
|
|
@@ -3858,6 +3859,7 @@ __export(core_exports, {
|
|
|
3858
3859
|
settleNewVersion: () => settleNewVersion,
|
|
3859
3860
|
signIn: () => signIn,
|
|
3860
3861
|
signInWithOAuth: () => signInWithOAuth,
|
|
3862
|
+
singleRednodeApp: () => singleRednodeApp,
|
|
3861
3863
|
snapshot: () => snapshot,
|
|
3862
3864
|
sourcePath: () => sourcePath,
|
|
3863
3865
|
ssoPageUrl: () => ssoPageUrl,
|
|
@@ -4003,6 +4005,14 @@ function findRarTool() {
|
|
|
4003
4005
|
if (unrar) return { exe: unrar, args: (file, dest) => ["x", "-y", "-o+", file, dest + path2.sep] };
|
|
4004
4006
|
return void 0;
|
|
4005
4007
|
}
|
|
4008
|
+
function removeTemp(dir) {
|
|
4009
|
+
try {
|
|
4010
|
+
fs2.rmSync(dir, { recursive: true, force: true, maxRetries: 6, retryDelay: 250 });
|
|
4011
|
+
return void 0;
|
|
4012
|
+
} catch (err) {
|
|
4013
|
+
return `could not remove the temporary folder ${dir} (${err instanceof Error ? err.message : String(err)}); Windows clears its temp folder in time`;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4006
4016
|
async function unpackOrCopy(file, dest, sevenZa) {
|
|
4007
4017
|
if (isArchiveFile(file)) return extractArchive(file, dest, sevenZa);
|
|
4008
4018
|
fs2.mkdirSync(dest, { recursive: true });
|
|
@@ -4181,7 +4191,7 @@ ${stderr}`.split(/\r?\n/)) if (line.trim()) log(` ${line.trim()}`);
|
|
|
4181
4191
|
});
|
|
4182
4192
|
});
|
|
4183
4193
|
} finally {
|
|
4184
|
-
|
|
4194
|
+
removeTemp(temp);
|
|
4185
4195
|
}
|
|
4186
4196
|
if (!hasNet10(root)) throw new Error("The .NET 10 runtime did not install. See the log.");
|
|
4187
4197
|
return root;
|
|
@@ -4231,7 +4241,7 @@ async function installBridge(release, storageDir, sevenZa, progress, log) {
|
|
|
4231
4241
|
fs4.mkdirSync(target, { recursive: true });
|
|
4232
4242
|
await extractArchive(zip, target, sevenZa);
|
|
4233
4243
|
} finally {
|
|
4234
|
-
|
|
4244
|
+
removeTemp(temp);
|
|
4235
4245
|
}
|
|
4236
4246
|
if (!fs4.existsSync(exe)) throw new Error("The zip did not contain REDbridge.exe.");
|
|
4237
4247
|
log(`REDbridge ${release.version} installed at ${exe}`);
|
|
@@ -4306,7 +4316,8 @@ function folderName(name) {
|
|
|
4306
4316
|
return name.replace(/[<>:"/\\|?*]+/g, "").trim() || "Mod";
|
|
4307
4317
|
}
|
|
4308
4318
|
function rednodeManifest(placements) {
|
|
4309
|
-
const
|
|
4319
|
+
const to = singleRednodeApp(placements.map((x) => x.to));
|
|
4320
|
+
const p = to === void 0 ? void 0 : placements.find((x) => x.to === to);
|
|
4310
4321
|
if (!p) return void 0;
|
|
4311
4322
|
try {
|
|
4312
4323
|
const m = JSON.parse(fs5.readFileSync(p.from, "utf8"));
|
|
@@ -4316,6 +4327,12 @@ function rednodeManifest(placements) {
|
|
|
4316
4327
|
return void 0;
|
|
4317
4328
|
}
|
|
4318
4329
|
}
|
|
4330
|
+
function singleRednodeApp(paths) {
|
|
4331
|
+
const manifests = paths.filter((f) => /^red4ext\/plugins\/REDnode\/apps\/[^/]+\/rednode-app\.json$/i.test(f));
|
|
4332
|
+
if (manifests.length !== 1) return void 0;
|
|
4333
|
+
const folder = manifests[0].slice(0, -"rednode-app.json".length).toLowerCase();
|
|
4334
|
+
return paths.every((f) => f.toLowerCase().startsWith(folder)) ? manifests[0] : void 0;
|
|
4335
|
+
}
|
|
4319
4336
|
function rednodeId(manifest) {
|
|
4320
4337
|
try {
|
|
4321
4338
|
const m = JSON.parse(fs5.readFileSync(manifest, "utf8"));
|
|
@@ -5073,11 +5090,8 @@ function baseName(name) {
|
|
|
5073
5090
|
return name.toLowerCase().replace(/[_\-]+/g, " ").replace(/\bv?\d+(?:\.\d+)+[a-z0-9]*\b/g, " ").replace(/[^a-z0-9]+/g, " ").trim();
|
|
5074
5091
|
}
|
|
5075
5092
|
function rednodePackageId(mod) {
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
if (m) return m[1].toLowerCase();
|
|
5079
|
-
}
|
|
5080
|
-
return void 0;
|
|
5093
|
+
const manifest = singleRednodeApp(mod.files);
|
|
5094
|
+
return manifest ? /^red4ext\/plugins\/REDnode\/apps\/([^/]+)\//i.exec(manifest)[1].toLowerCase() : void 0;
|
|
5081
5095
|
}
|
|
5082
5096
|
function familyKey(mod) {
|
|
5083
5097
|
if (mod.family) return mod.family;
|
|
@@ -5098,11 +5112,11 @@ function families(lib) {
|
|
|
5098
5112
|
for (const [key2, mods] of byKey) {
|
|
5099
5113
|
const sorted = [...mods].sort(newestFirst);
|
|
5100
5114
|
const active = sorted.find((m) => m.enabled) ?? sorted[0];
|
|
5101
|
-
const
|
|
5115
|
+
const newest = sorted[0];
|
|
5102
5116
|
let update;
|
|
5103
5117
|
for (const m of mods) {
|
|
5104
5118
|
const latest = m.nexus?.latestVersion;
|
|
5105
|
-
if (latest && versionNewer(latest,
|
|
5119
|
+
if (latest && versionNewer(latest, newest.version) && (!update || versionNewer(latest, update.version))) update = { version: latest, fileId: m.nexus?.latestFileId };
|
|
5106
5120
|
}
|
|
5107
5121
|
out.push({ key: key2, name: active.name, nexusId: active.source.modId ?? mods.find((m) => m.source.modId)?.source.modId, mods: sorted, active, on: mods.some((m) => m.enabled), update });
|
|
5108
5122
|
}
|
|
@@ -5252,8 +5266,8 @@ async function frameworkStates(lib, fetchImpl, api) {
|
|
|
5252
5266
|
const family = frameworkFamily(lib, source);
|
|
5253
5267
|
try {
|
|
5254
5268
|
const release = await latestFrameworkRelease(source, fetchImpl, api);
|
|
5255
|
-
const
|
|
5256
|
-
return { source, family, release, wanted: !family || !!
|
|
5269
|
+
const newest = family?.mods[0]?.version ?? "";
|
|
5270
|
+
return { source, family, release, wanted: !family || !!newest && versionNewer(release.version, newest) };
|
|
5257
5271
|
} catch (err) {
|
|
5258
5272
|
return { source, family, error: err instanceof Error ? err.message : String(err), wanted: !family };
|
|
5259
5273
|
}
|
|
@@ -5833,6 +5847,7 @@ function describeHandler(command) {
|
|
|
5833
5847
|
}
|
|
5834
5848
|
|
|
5835
5849
|
// src/project.ts
|
|
5850
|
+
var import_node_crypto = require("node:crypto");
|
|
5836
5851
|
var fs11 = __toESM(require("node:fs"));
|
|
5837
5852
|
var path10 = __toESM(require("node:path"));
|
|
5838
5853
|
function addToProject(lib, mod, files, projectFile, replace = /* @__PURE__ */ new Set()) {
|
|
@@ -5884,13 +5899,22 @@ function classifyProject(projectFile) {
|
|
|
5884
5899
|
if (!fs11.existsSync(packed)) return { placements: [], kinds: [], unplaced: [], ignored: [] };
|
|
5885
5900
|
return classify(packed, projectName(projectFile));
|
|
5886
5901
|
}
|
|
5887
|
-
function
|
|
5888
|
-
let
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5902
|
+
function packedState(dir) {
|
|
5903
|
+
let newest = 0;
|
|
5904
|
+
const files = [];
|
|
5905
|
+
const walk2 = (d, rel) => {
|
|
5906
|
+
for (const e of fs11.readdirSync(d, { withFileTypes: true })) {
|
|
5907
|
+
const p = path10.join(d, e.name);
|
|
5908
|
+
const r = rel ? `${rel}/${e.name}` : e.name;
|
|
5909
|
+
if (e.isDirectory()) walk2(p, r);
|
|
5910
|
+
else {
|
|
5911
|
+
newest = Math.max(newest, fs11.statSync(p).mtimeMs);
|
|
5912
|
+
files.push(r.toLowerCase());
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
};
|
|
5916
|
+
walk2(dir, "");
|
|
5917
|
+
return { newest, list: (0, import_node_crypto.createHash)("sha1").update(files.sort().join("\n")).digest("hex").slice(0, 16) };
|
|
5894
5918
|
}
|
|
5895
5919
|
function syncProjects(lib) {
|
|
5896
5920
|
const refreshed = [];
|
|
@@ -5905,7 +5929,15 @@ function syncProjects(lib) {
|
|
|
5905
5929
|
return t;
|
|
5906
5930
|
}
|
|
5907
5931
|
}, 0);
|
|
5908
|
-
|
|
5932
|
+
const state = packedState(packed);
|
|
5933
|
+
const listChanged = mod.packedList !== void 0 && mod.packedList !== state.list;
|
|
5934
|
+
if (state.newest <= libNewest + 1e3 && !listChanged) {
|
|
5935
|
+
if (mod.packedList === void 0) {
|
|
5936
|
+
mod.packedList = state.list;
|
|
5937
|
+
saveMod(lib, mod);
|
|
5938
|
+
}
|
|
5939
|
+
continue;
|
|
5940
|
+
}
|
|
5909
5941
|
const c = classifyProject(mod.source.path);
|
|
5910
5942
|
if (!c.placements.length) continue;
|
|
5911
5943
|
const keep = /* @__PURE__ */ new Set();
|
|
@@ -5918,6 +5950,7 @@ function syncProjects(lib) {
|
|
|
5918
5950
|
for (const f of mod.files) if (!keep.has(f)) fs11.rmSync(sourcePath(lib, mod, f), { force: true });
|
|
5919
5951
|
mod.files = [...keep].sort();
|
|
5920
5952
|
mod.kinds = c.kinds;
|
|
5953
|
+
mod.packedList = state.list;
|
|
5921
5954
|
saveMod(lib, mod);
|
|
5922
5955
|
refreshed.push(mod);
|
|
5923
5956
|
}
|
|
@@ -5978,6 +6011,7 @@ function installProject(lib, projectFile, beside) {
|
|
|
5978
6011
|
for (const f of existing.files) if (!keep.has(f)) fs11.rmSync(sourcePath(lib, existing, f), { force: true });
|
|
5979
6012
|
existing.files = [...keep].sort();
|
|
5980
6013
|
existing.kinds = c.kinds;
|
|
6014
|
+
existing.packedList = packedState(packedFolder(projectFile)).list;
|
|
5981
6015
|
activateVersion(lib, existing);
|
|
5982
6016
|
existing.enabled = true;
|
|
5983
6017
|
saveMod(lib, existing);
|
|
@@ -6442,7 +6476,7 @@ ${mod.files.join("\n")}`;
|
|
|
6442
6476
|
const note = settled.replaced ? `; a new version of ${settled.replaced.name} ${settled.replaced.version}, which is off now` : settled.older ? `; older than ${settled.older.version}, so it is off` : "";
|
|
6443
6477
|
return { data: { added: { id: mod.id, name: mod.name, version: mod.version, kinds: mod.kinds, files: mod.files.length, enabled: mod.enabled }, replaced: settled.replaced?.id, unplaced: c.unplaced }, text: `added ${mod.id} (${mod.files.length} files, ${mod.kinds.join(", ")})${note}; ${mod.enabled ? "it is on, " : ""}deploy to put it in the game${c.unplaced.length ? `; not placed: ${c.unplaced.join(", ")}` : ""}` };
|
|
6444
6478
|
} finally {
|
|
6445
|
-
if (temp)
|
|
6479
|
+
if (temp) removeTemp(temp);
|
|
6446
6480
|
}
|
|
6447
6481
|
},
|
|
6448
6482
|
/** Adds a REDcode or WolvenKit project's packed output, or refreshes the mod that follows it, and turns it on. */
|
|
@@ -6704,6 +6738,7 @@ ${mod.files.join("\n")}`;
|
|
|
6704
6738
|
registerNxmHandler,
|
|
6705
6739
|
removeMod,
|
|
6706
6740
|
removeOlderBridges,
|
|
6741
|
+
removeTemp,
|
|
6707
6742
|
renameFamily,
|
|
6708
6743
|
renameLoadout,
|
|
6709
6744
|
renameSection,
|
|
@@ -6720,6 +6755,7 @@ ${mod.files.join("\n")}`;
|
|
|
6720
6755
|
settleNewVersion,
|
|
6721
6756
|
signIn,
|
|
6722
6757
|
signInWithOAuth,
|
|
6758
|
+
singleRednodeApp,
|
|
6723
6759
|
snapshot,
|
|
6724
6760
|
sourcePath,
|
|
6725
6761
|
ssoPageUrl,
|
package/dist/mcp.js
CHANGED
|
@@ -36665,7 +36665,8 @@ function folderName(name) {
|
|
|
36665
36665
|
return name.replace(/[<>:"/\\|?*]+/g, "").trim() || "Mod";
|
|
36666
36666
|
}
|
|
36667
36667
|
function rednodeManifest(placements) {
|
|
36668
|
-
const
|
|
36668
|
+
const to = singleRednodeApp(placements.map((x) => x.to));
|
|
36669
|
+
const p = to === void 0 ? void 0 : placements.find((x) => x.to === to);
|
|
36669
36670
|
if (!p) return void 0;
|
|
36670
36671
|
try {
|
|
36671
36672
|
const m = JSON.parse(fs.readFileSync(p.from, "utf8"));
|
|
@@ -36675,6 +36676,12 @@ function rednodeManifest(placements) {
|
|
|
36675
36676
|
return void 0;
|
|
36676
36677
|
}
|
|
36677
36678
|
}
|
|
36679
|
+
function singleRednodeApp(paths) {
|
|
36680
|
+
const manifests = paths.filter((f) => /^red4ext\/plugins\/REDnode\/apps\/[^/]+\/rednode-app\.json$/i.test(f));
|
|
36681
|
+
if (manifests.length !== 1) return void 0;
|
|
36682
|
+
const folder = manifests[0].slice(0, -"rednode-app.json".length).toLowerCase();
|
|
36683
|
+
return paths.every((f) => f.toLowerCase().startsWith(folder)) ? manifests[0] : void 0;
|
|
36684
|
+
}
|
|
36678
36685
|
function rednodeId(manifest) {
|
|
36679
36686
|
try {
|
|
36680
36687
|
const m = JSON.parse(fs.readFileSync(manifest, "utf8"));
|
|
@@ -36925,11 +36932,8 @@ function baseName(name) {
|
|
|
36925
36932
|
return name.toLowerCase().replace(/[_\-]+/g, " ").replace(/\bv?\d+(?:\.\d+)+[a-z0-9]*\b/g, " ").replace(/[^a-z0-9]+/g, " ").trim();
|
|
36926
36933
|
}
|
|
36927
36934
|
function rednodePackageId(mod) {
|
|
36928
|
-
|
|
36929
|
-
|
|
36930
|
-
if (m) return m[1].toLowerCase();
|
|
36931
|
-
}
|
|
36932
|
-
return void 0;
|
|
36935
|
+
const manifest = singleRednodeApp(mod.files);
|
|
36936
|
+
return manifest ? /^red4ext\/plugins\/REDnode\/apps\/([^/]+)\//i.exec(manifest)[1].toLowerCase() : void 0;
|
|
36933
36937
|
}
|
|
36934
36938
|
function familyKey(mod) {
|
|
36935
36939
|
if (mod.family) return mod.family;
|
|
@@ -37530,6 +37534,14 @@ function findRarTool() {
|
|
|
37530
37534
|
if (unrar) return { exe: unrar, args: (file2, dest) => ["x", "-y", "-o+", file2, dest + path5.sep] };
|
|
37531
37535
|
return void 0;
|
|
37532
37536
|
}
|
|
37537
|
+
function removeTemp(dir) {
|
|
37538
|
+
try {
|
|
37539
|
+
fs5.rmSync(dir, { recursive: true, force: true, maxRetries: 6, retryDelay: 250 });
|
|
37540
|
+
return void 0;
|
|
37541
|
+
} catch (err) {
|
|
37542
|
+
return `could not remove the temporary folder ${dir} (${err instanceof Error ? err.message : String(err)}); Windows clears its temp folder in time`;
|
|
37543
|
+
}
|
|
37544
|
+
}
|
|
37533
37545
|
async function unpackOrCopy(file2, dest, sevenZa) {
|
|
37534
37546
|
if (isArchiveFile(file2)) return extractArchive(file2, dest, sevenZa);
|
|
37535
37547
|
fs5.mkdirSync(dest, { recursive: true });
|
|
@@ -37707,6 +37719,7 @@ function importLoadout(lib, file2) {
|
|
|
37707
37719
|
}
|
|
37708
37720
|
|
|
37709
37721
|
// src/project.ts
|
|
37722
|
+
var import_node_crypto = require("node:crypto");
|
|
37710
37723
|
var fs7 = __toESM(require("node:fs"));
|
|
37711
37724
|
var path7 = __toESM(require("node:path"));
|
|
37712
37725
|
function projectName(projectFile) {
|
|
@@ -37726,6 +37739,23 @@ function classifyProject(projectFile) {
|
|
|
37726
37739
|
if (!fs7.existsSync(packed)) return { placements: [], kinds: [], unplaced: [], ignored: [] };
|
|
37727
37740
|
return classify(packed, projectName(projectFile));
|
|
37728
37741
|
}
|
|
37742
|
+
function packedState(dir) {
|
|
37743
|
+
let newest = 0;
|
|
37744
|
+
const files = [];
|
|
37745
|
+
const walk2 = (d, rel) => {
|
|
37746
|
+
for (const e of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
37747
|
+
const p = path7.join(d, e.name);
|
|
37748
|
+
const r = rel ? `${rel}/${e.name}` : e.name;
|
|
37749
|
+
if (e.isDirectory()) walk2(p, r);
|
|
37750
|
+
else {
|
|
37751
|
+
newest = Math.max(newest, fs7.statSync(p).mtimeMs);
|
|
37752
|
+
files.push(r.toLowerCase());
|
|
37753
|
+
}
|
|
37754
|
+
}
|
|
37755
|
+
};
|
|
37756
|
+
walk2(dir, "");
|
|
37757
|
+
return { newest, list: (0, import_node_crypto.createHash)("sha1").update(files.sort().join("\n")).digest("hex").slice(0, 16) };
|
|
37758
|
+
}
|
|
37729
37759
|
function projectMod(lib, projectFile) {
|
|
37730
37760
|
return lib.mods.find((m) => m.source.type === "project" && m.source.path?.toLowerCase() === projectFile.toLowerCase());
|
|
37731
37761
|
}
|
|
@@ -37781,6 +37811,7 @@ function installProject(lib, projectFile, beside) {
|
|
|
37781
37811
|
for (const f of existing.files) if (!keep.has(f)) fs7.rmSync(sourcePath(lib, existing, f), { force: true });
|
|
37782
37812
|
existing.files = [...keep].sort();
|
|
37783
37813
|
existing.kinds = c.kinds;
|
|
37814
|
+
existing.packedList = packedState(packedFolder(projectFile)).list;
|
|
37784
37815
|
activateVersion(lib, existing);
|
|
37785
37816
|
existing.enabled = true;
|
|
37786
37817
|
saveMod(lib, existing);
|
|
@@ -38130,7 +38161,7 @@ ${mod.files.join("\n")}`;
|
|
|
38130
38161
|
const note = settled.replaced ? `; a new version of ${settled.replaced.name} ${settled.replaced.version}, which is off now` : settled.older ? `; older than ${settled.older.version}, so it is off` : "";
|
|
38131
38162
|
return { data: { added: { id: mod.id, name: mod.name, version: mod.version, kinds: mod.kinds, files: mod.files.length, enabled: mod.enabled }, replaced: settled.replaced?.id, unplaced: c.unplaced }, text: `added ${mod.id} (${mod.files.length} files, ${mod.kinds.join(", ")})${note}; ${mod.enabled ? "it is on, " : ""}deploy to put it in the game${c.unplaced.length ? `; not placed: ${c.unplaced.join(", ")}` : ""}` };
|
|
38132
38163
|
} finally {
|
|
38133
|
-
if (temp)
|
|
38164
|
+
if (temp) removeTemp(temp);
|
|
38134
38165
|
}
|
|
38135
38166
|
},
|
|
38136
38167
|
/** Adds a REDcode or WolvenKit project's packed output, or refreshes the mod that follows it, and turns it on. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgemodders/edgedeck-mcp",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.2",
|
|
4
4
|
"description": "EDGEdeck's MCP server and command line: manage Cyberpunk 2077 mods (add, turn on or off, order, deploy, undo, conflicts, loadouts) from an AI assistant or a script.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Edgemodders",
|