@edgemodders/edgedeck-mcp 0.29.1 → 0.29.3

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.
Files changed (3) hide show
  1. package/dist/core.js +45 -19
  2. package/dist/mcp.js +21 -2
  3. package/package.json +1 -1
package/dist/core.js CHANGED
@@ -3769,6 +3769,7 @@ __export(core_exports, {
3769
3769
  forgetSizes: () => forgetSizes,
3770
3770
  formatBytes: () => formatBytes,
3771
3771
  forwarderCommand: () => forwarderCommand,
3772
+ forwarderExe: () => forwarderExe,
3772
3773
  frameworkDetail: () => frameworkDetail,
3773
3774
  frameworkFamily: () => frameworkFamily,
3774
3775
  frameworkStates: () => frameworkStates,
@@ -4330,8 +4331,8 @@ function rednodeManifest(placements) {
4330
4331
  function singleRednodeApp(paths) {
4331
4332
  const manifests = paths.filter((f) => /^red4ext\/plugins\/REDnode\/apps\/[^/]+\/rednode-app\.json$/i.test(f));
4332
4333
  if (manifests.length !== 1) return void 0;
4333
- if (paths.some((f) => /^red4ext\/plugins\/REDnode\//i.test(f) && !/^red4ext\/plugins\/REDnode\/apps\//i.test(f))) return void 0;
4334
- return manifests[0];
4334
+ const folder = manifests[0].slice(0, -"rednode-app.json".length).toLowerCase();
4335
+ return paths.every((f) => f.toLowerCase().startsWith(folder)) ? manifests[0] : void 0;
4335
4336
  }
4336
4337
  function rednodeId(manifest) {
4337
4338
  try {
@@ -5112,11 +5113,11 @@ function families(lib) {
5112
5113
  for (const [key2, mods] of byKey) {
5113
5114
  const sorted = [...mods].sort(newestFirst);
5114
5115
  const active = sorted.find((m) => m.enabled) ?? sorted[0];
5115
- const newest2 = sorted[0];
5116
+ const newest = sorted[0];
5116
5117
  let update;
5117
5118
  for (const m of mods) {
5118
5119
  const latest = m.nexus?.latestVersion;
5119
- if (latest && versionNewer(latest, newest2.version) && (!update || versionNewer(latest, update.version))) update = { version: latest, fileId: m.nexus?.latestFileId };
5120
+ if (latest && versionNewer(latest, newest.version) && (!update || versionNewer(latest, update.version))) update = { version: latest, fileId: m.nexus?.latestFileId };
5120
5121
  }
5121
5122
  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 });
5122
5123
  }
@@ -5266,8 +5267,8 @@ async function frameworkStates(lib, fetchImpl, api) {
5266
5267
  const family = frameworkFamily(lib, source);
5267
5268
  try {
5268
5269
  const release = await latestFrameworkRelease(source, fetchImpl, api);
5269
- const newest2 = family?.mods[0]?.version ?? "";
5270
- return { source, family, release, wanted: !family || !!newest2 && versionNewer(release.version, newest2) };
5270
+ const newest = family?.mods[0]?.version ?? "";
5271
+ return { source, family, release, wanted: !family || !!newest && versionNewer(release.version, newest) };
5271
5272
  } catch (err) {
5272
5273
  return { source, family, error: err instanceof Error ? err.message : String(err), wanted: !family };
5273
5274
  }
@@ -5808,16 +5809,20 @@ function parseNxm(link) {
5808
5809
  userId: userId ? Number(userId) : void 0
5809
5810
  };
5810
5811
  }
5811
- function forwarderCommand() {
5812
- const ps = `Start-Process ('${UriScheme}://${UriAuthority}/nxm?url=' + [uri]::EscapeDataString('%1'))`;
5813
- return `powershell.exe -NoProfile -WindowStyle Hidden -Command "${ps}"`;
5812
+ function forwarderCommand(target = {}) {
5813
+ const url = `$u = '${target.scheme ?? UriScheme}://${UriAuthority}/nxm?url=' + [uri]::EscapeDataString('%1')`;
5814
+ const open = target.exe ? `Start-Process -FilePath '${target.exe.replace(/'/g, "''")}' -ArgumentList '--open-url','--',$u` : "Start-Process $u";
5815
+ return `powershell.exe -NoProfile -WindowStyle Hidden -Command "${url}; ${open}"`;
5816
+ }
5817
+ function forwarderExe(command) {
5818
+ return /-FilePath '((?:[^']|'')+)'/.exec(command)?.[1].replace(/''/g, "'");
5814
5819
  }
5815
5820
  var Key = "HKCU\\Software\\Classes\\nxm";
5816
- async function registerNxmHandler() {
5821
+ async function registerNxmHandler(target = {}) {
5817
5822
  const before = await currentNxmHandler();
5818
5823
  await run3("reg", ["add", Key, "/ve", "/d", "URL:Nexus Mods link", "/f"], { windowsHide: true });
5819
5824
  await run3("reg", ["add", Key, "/v", "URL Protocol", "/d", "", "/f"], { windowsHide: true });
5820
- await run3("reg", ["add", `${Key}\\shell\\open\\command`, "/ve", "/d", forwarderCommand(), "/f"], { windowsHide: true });
5825
+ await run3("reg", ["add", `${Key}\\shell\\open\\command`, "/ve", "/d", forwarderCommand(target), "/f"], { windowsHide: true });
5821
5826
  return before;
5822
5827
  }
5823
5828
  async function unregisterNxmHandler() {
@@ -5847,6 +5852,7 @@ function describeHandler(command) {
5847
5852
  }
5848
5853
 
5849
5854
  // src/project.ts
5855
+ var import_node_crypto = require("node:crypto");
5850
5856
  var fs11 = __toESM(require("node:fs"));
5851
5857
  var path10 = __toESM(require("node:path"));
5852
5858
  function addToProject(lib, mod, files, projectFile, replace = /* @__PURE__ */ new Set()) {
@@ -5898,13 +5904,22 @@ function classifyProject(projectFile) {
5898
5904
  if (!fs11.existsSync(packed)) return { placements: [], kinds: [], unplaced: [], ignored: [] };
5899
5905
  return classify(packed, projectName(projectFile));
5900
5906
  }
5901
- function newest(dir) {
5902
- let t = 0;
5903
- for (const e of fs11.readdirSync(dir, { withFileTypes: true })) {
5904
- const p = path10.join(dir, e.name);
5905
- t = Math.max(t, e.isDirectory() ? newest(p) : fs11.statSync(p).mtimeMs);
5906
- }
5907
- return t;
5907
+ function packedState(dir) {
5908
+ let newest = 0;
5909
+ const files = [];
5910
+ const walk2 = (d, rel) => {
5911
+ for (const e of fs11.readdirSync(d, { withFileTypes: true })) {
5912
+ const p = path10.join(d, e.name);
5913
+ const r = rel ? `${rel}/${e.name}` : e.name;
5914
+ if (e.isDirectory()) walk2(p, r);
5915
+ else {
5916
+ newest = Math.max(newest, fs11.statSync(p).mtimeMs);
5917
+ files.push(r.toLowerCase());
5918
+ }
5919
+ }
5920
+ };
5921
+ walk2(dir, "");
5922
+ return { newest, list: (0, import_node_crypto.createHash)("sha1").update(files.sort().join("\n")).digest("hex").slice(0, 16) };
5908
5923
  }
5909
5924
  function syncProjects(lib) {
5910
5925
  const refreshed = [];
@@ -5919,7 +5934,15 @@ function syncProjects(lib) {
5919
5934
  return t;
5920
5935
  }
5921
5936
  }, 0);
5922
- if (newest(packed) <= libNewest + 1e3) continue;
5937
+ const state = packedState(packed);
5938
+ const listChanged = mod.packedList !== void 0 && mod.packedList !== state.list;
5939
+ if (state.newest <= libNewest + 1e3 && !listChanged) {
5940
+ if (mod.packedList === void 0) {
5941
+ mod.packedList = state.list;
5942
+ saveMod(lib, mod);
5943
+ }
5944
+ continue;
5945
+ }
5923
5946
  const c = classifyProject(mod.source.path);
5924
5947
  if (!c.placements.length) continue;
5925
5948
  const keep = /* @__PURE__ */ new Set();
@@ -5932,6 +5955,7 @@ function syncProjects(lib) {
5932
5955
  for (const f of mod.files) if (!keep.has(f)) fs11.rmSync(sourcePath(lib, mod, f), { force: true });
5933
5956
  mod.files = [...keep].sort();
5934
5957
  mod.kinds = c.kinds;
5958
+ mod.packedList = state.list;
5935
5959
  saveMod(lib, mod);
5936
5960
  refreshed.push(mod);
5937
5961
  }
@@ -5992,6 +6016,7 @@ function installProject(lib, projectFile, beside) {
5992
6016
  for (const f of existing.files) if (!keep.has(f)) fs11.rmSync(sourcePath(lib, existing, f), { force: true });
5993
6017
  existing.files = [...keep].sort();
5994
6018
  existing.kinds = c.kinds;
6019
+ existing.packedList = packedState(packedFolder(projectFile)).list;
5995
6020
  activateVersion(lib, existing);
5996
6021
  existing.enabled = true;
5997
6022
  saveMod(lib, existing);
@@ -6645,6 +6670,7 @@ ${mod.files.join("\n")}`;
6645
6670
  forgetSizes,
6646
6671
  formatBytes,
6647
6672
  forwarderCommand,
6673
+ forwarderExe,
6648
6674
  frameworkDetail,
6649
6675
  frameworkFamily,
6650
6676
  frameworkStates,
package/dist/mcp.js CHANGED
@@ -36679,8 +36679,8 @@ function rednodeManifest(placements) {
36679
36679
  function singleRednodeApp(paths) {
36680
36680
  const manifests = paths.filter((f) => /^red4ext\/plugins\/REDnode\/apps\/[^/]+\/rednode-app\.json$/i.test(f));
36681
36681
  if (manifests.length !== 1) return void 0;
36682
- if (paths.some((f) => /^red4ext\/plugins\/REDnode\//i.test(f) && !/^red4ext\/plugins\/REDnode\/apps\//i.test(f))) return void 0;
36683
- return manifests[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
36684
  }
36685
36685
  function rednodeId(manifest) {
36686
36686
  try {
@@ -37719,6 +37719,7 @@ function importLoadout(lib, file2) {
37719
37719
  }
37720
37720
 
37721
37721
  // src/project.ts
37722
+ var import_node_crypto = require("node:crypto");
37722
37723
  var fs7 = __toESM(require("node:fs"));
37723
37724
  var path7 = __toESM(require("node:path"));
37724
37725
  function projectName(projectFile) {
@@ -37738,6 +37739,23 @@ function classifyProject(projectFile) {
37738
37739
  if (!fs7.existsSync(packed)) return { placements: [], kinds: [], unplaced: [], ignored: [] };
37739
37740
  return classify(packed, projectName(projectFile));
37740
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
+ }
37741
37759
  function projectMod(lib, projectFile) {
37742
37760
  return lib.mods.find((m) => m.source.type === "project" && m.source.path?.toLowerCase() === projectFile.toLowerCase());
37743
37761
  }
@@ -37793,6 +37811,7 @@ function installProject(lib, projectFile, beside) {
37793
37811
  for (const f of existing.files) if (!keep.has(f)) fs7.rmSync(sourcePath(lib, existing, f), { force: true });
37794
37812
  existing.files = [...keep].sort();
37795
37813
  existing.kinds = c.kinds;
37814
+ existing.packedList = packedState(packedFolder(projectFile)).list;
37796
37815
  activateVersion(lib, existing);
37797
37816
  existing.enabled = true;
37798
37817
  saveMod(lib, existing);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgemodders/edgedeck-mcp",
3
- "version": "0.29.1",
3
+ "version": "0.29.3",
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",