@kwonye/mcpx 0.1.95 → 0.1.97

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.
@@ -1,14 +1,14 @@
1
1
  import {
2
+ mutateConfig,
2
3
  persistSyncState,
3
4
  syncAllClients
4
- } from "./cli-wxw1t3rr.js";
5
+ } from "./cli-vy81xjm0.js";
5
6
  import {
6
- loadConfig,
7
- saveConfig
8
- } from "./cli-v27bt25d.js";
7
+ loadConfig
8
+ } from "./cli-g4w6k655.js";
9
9
  import {
10
10
  SecretsManager
11
- } from "./cli-tk8bggg5.js";
11
+ } from "./cli-remv48t3.js";
12
12
  import {
13
13
  ensureDir,
14
14
  getConfigPath,
@@ -226,7 +226,9 @@ function computeTreeHash(dir) {
226
226
  const crypto = __require("node:crypto");
227
227
  const hash = crypto.createHash("sha256");
228
228
  for (const entry of entries) {
229
- if (entry.name.startsWith("."))
229
+ if (entry.name.startsWith(".git"))
230
+ continue;
231
+ if (entry.name === ".DS_Store")
230
232
  continue;
231
233
  if (entry.isDirectory()) {
232
234
  hash.update(entry.name);
@@ -244,6 +246,8 @@ function copyDirSync(src, dest) {
244
246
  for (const entry of entries) {
245
247
  if (entry.name.startsWith(".git"))
246
248
  continue;
249
+ if (entry.name === ".DS_Store")
250
+ continue;
247
251
  const srcPath = path.join(src, entry.name);
248
252
  const destPath = path.join(dest, entry.name);
249
253
  if (entry.isDirectory()) {
@@ -692,24 +696,11 @@ class PluginManager {
692
696
  const info = await this.inspectSource(sourceStr);
693
697
  const pluginName = options?.name || info.manifest?.name || path5.basename(info.root);
694
698
  const pluginId = `${pluginName}@${info.sha.slice(0, 8)}`;
695
- const config = loadConfig(this.configPath);
696
- if (!config.plugins)
697
- config.plugins = {};
698
- if (config.plugins[pluginId]) {
699
- throw new Error(`Plugin ${pluginId} is already installed`);
700
- }
701
- const serverNames = info.components.mcpServers.map((s) => `${pluginName}__${s.id}`);
702
- for (const existing of Object.values(config.plugins)) {
703
- for (const sn of serverNames) {
704
- if (existing.serverNames.includes(sn)) {
705
- throw new Error(`Server name collision: "${sn}" is already claimed by plugin "${existing.name}". Use --name to specify a different plugin name.`);
706
- }
707
- }
708
- }
709
699
  const dataDir = path5.join(getPluginDataRoot(), pluginId);
710
700
  ensureDir(dataDir);
711
701
  const enabled = options?.enabled ?? true;
712
702
  const discovered = info.components;
703
+ const serverNames = discovered.mcpServers.map((s) => `${pluginName}__${s.id}`);
713
704
  const plugin = {
714
705
  id: pluginId,
715
706
  name: pluginName,
@@ -734,132 +725,168 @@ class PluginManager {
734
725
  projectedClients: [],
735
726
  approvals: options?.approvals || {}
736
727
  };
737
- config.plugins[pluginId] = plugin;
738
- saveConfig(config, this.configPath);
739
- for (const mcp of discovered.mcpServers) {
740
- const nsName = `${pluginName}__${mcp.id}`;
741
- const approved = plugin.approvals?.mcpServers !== false;
742
- config.servers[nsName] = {
743
- transport: "stdio",
744
- command: "npx",
745
- args: ["-y", "@kwonye/mcpx@latest", "plugin-host", pluginId, mcp.id],
746
- enabled: enabled && approved
747
- };
748
- }
749
- saveConfig(config, this.configPath);
728
+ await mutateConfig((config) => {
729
+ if (!config.plugins)
730
+ config.plugins = {};
731
+ if (config.plugins[pluginId]) {
732
+ throw new Error(`Plugin ${pluginId} is already installed`);
733
+ }
734
+ for (const existing of Object.values(config.plugins)) {
735
+ for (const sn of serverNames) {
736
+ if (existing.serverNames.includes(sn)) {
737
+ throw new Error(`Server name collision: "${sn}" is already claimed by plugin "${existing.name}". Use --name to specify a different plugin name.`);
738
+ }
739
+ }
740
+ }
741
+ for (const sn of serverNames) {
742
+ if (config.servers?.[sn]) {
743
+ throw new Error(`Server name collision: "${sn}" is already registered as a server. Remove that server or use --name to choose a different plugin name.`);
744
+ }
745
+ }
746
+ config.plugins[pluginId] = plugin;
747
+ for (const mcp of discovered.mcpServers) {
748
+ const nsName = `${pluginName}__${mcp.id}`;
749
+ const approved = plugin.approvals?.mcpServers !== false;
750
+ config.servers[nsName] = {
751
+ transport: "stdio",
752
+ command: "npx",
753
+ args: ["-y", "@kwonye/mcpx@latest", "plugin-host", pluginId, mcp.id],
754
+ enabled: enabled && approved
755
+ };
756
+ }
757
+ }, this.configPath);
750
758
  this.lifecycle.initData(pluginId);
751
759
  const syncConfig = loadConfig(this.configPath);
752
760
  const summary = syncAllClients(syncConfig, this.secrets);
753
- persistSyncState(summary, syncConfig);
754
- saveConfig(syncConfig, this.configPath);
761
+ await mutateConfig((freshConfig) => {
762
+ persistSyncState(summary, freshConfig);
763
+ }, this.configPath);
755
764
  return plugin;
756
765
  }
757
766
  async updatePlugin(pluginId) {
758
- const config = loadConfig(this.configPath);
759
- if (!config.plugins)
760
- throw new Error(`Plugin ${pluginId} not found`);
761
- const current = config.plugins[pluginId];
762
- if (!current)
763
- throw new Error(`Plugin ${pluginId} not found`);
764
- const info = await this.inspectSource(current.source);
765
- const pluginName = info.manifest?.name || current.name;
766
- for (const oldName of current.serverNames) {
767
- delete config.servers[oldName];
768
- }
769
- current.version = info.manifest?.version || current.version;
770
- current.resolvedSha = info.sha;
771
- current.root = info.root;
772
- current.discovered = info.components;
773
- current.serverNames = info.components.mcpServers.map((s) => `${pluginName}__${s.id}`);
774
- const approved = current.approvals?.mcpServers !== false;
775
- for (const mcp of info.components.mcpServers) {
776
- const nsName = `${pluginName}__${mcp.id}`;
777
- config.servers[nsName] = {
778
- transport: "stdio",
779
- command: "npx",
780
- args: ["-y", "@kwonye/mcpx@latest", "plugin-host", pluginId, mcp.id],
781
- enabled: current.enabled && approved
782
- };
783
- }
784
- current.approvals = {};
785
- config.plugins[pluginId] = current;
786
- saveConfig(config, this.configPath);
767
+ let currentPlugin;
768
+ let info;
769
+ await mutateConfig((config) => {
770
+ if (!config.plugins)
771
+ throw new Error(`Plugin ${pluginId} not found`);
772
+ const current = config.plugins[pluginId];
773
+ if (!current)
774
+ throw new Error(`Plugin ${pluginId} not found`);
775
+ currentPlugin = current;
776
+ }, this.configPath);
777
+ const source = currentPlugin.source;
778
+ info = await this.inspectSource(source);
779
+ const pluginName = info.manifest?.name || currentPlugin.name;
780
+ let updatedPlugin;
781
+ await mutateConfig((config) => {
782
+ if (!config.plugins)
783
+ throw new Error(`Plugin ${pluginId} not found`);
784
+ const current = config.plugins[pluginId];
785
+ if (!current)
786
+ throw new Error(`Plugin ${pluginId} not found`);
787
+ for (const oldName of current.serverNames) {
788
+ delete config.servers[oldName];
789
+ }
790
+ current.version = info.manifest?.version || current.version;
791
+ current.resolvedSha = info.sha;
792
+ current.root = info.root;
793
+ current.discovered = info.components;
794
+ current.serverNames = info.components.mcpServers.map((s) => `${pluginName}__${s.id}`);
795
+ const approved = current.approvals?.mcpServers !== false;
796
+ for (const mcp of info.components.mcpServers) {
797
+ const nsName = `${pluginName}__${mcp.id}`;
798
+ config.servers[nsName] = {
799
+ transport: "stdio",
800
+ command: "npx",
801
+ args: ["-y", "@kwonye/mcpx@latest", "plugin-host", pluginId, mcp.id],
802
+ enabled: current.enabled && approved
803
+ };
804
+ }
805
+ current.approvals = {};
806
+ config.plugins[pluginId] = current;
807
+ updatedPlugin = current;
808
+ }, this.configPath);
787
809
  const syncConfig = loadConfig(this.configPath);
788
810
  const summary = syncAllClients(syncConfig, this.secrets);
789
- persistSyncState(summary, syncConfig);
790
- saveConfig(syncConfig, this.configPath);
791
- return current;
811
+ await mutateConfig((freshConfig) => {
812
+ persistSyncState(summary, freshConfig);
813
+ }, this.configPath);
814
+ return updatedPlugin;
792
815
  }
793
816
  async uninstallPlugin(pluginId, keepData = false) {
794
- const config = loadConfig(this.configPath);
795
- if (!config.plugins)
796
- throw new Error(`Plugin ${pluginId} not found`);
797
- const plugin = config.plugins[pluginId];
798
- if (!plugin)
799
- throw new Error(`Plugin ${pluginId} not found`);
800
- for (const name of plugin.serverNames) {
801
- delete config.servers[name];
802
- }
803
- delete config.plugins[pluginId];
804
- saveConfig(config, this.configPath);
817
+ await mutateConfig((config) => {
818
+ if (!config.plugins)
819
+ throw new Error(`Plugin ${pluginId} not found`);
820
+ const plugin = config.plugins[pluginId];
821
+ if (!plugin)
822
+ throw new Error(`Plugin ${pluginId} not found`);
823
+ for (const name of plugin.serverNames) {
824
+ delete config.servers[name];
825
+ }
826
+ delete config.plugins[pluginId];
827
+ }, this.configPath);
805
828
  if (!keepData) {
806
829
  await this.lifecycle.removeData(pluginId);
807
830
  }
808
831
  const syncConfig = loadConfig(this.configPath);
809
832
  const summary = syncAllClients(syncConfig, this.secrets);
810
- persistSyncState(summary, syncConfig);
811
- saveConfig(syncConfig, this.configPath);
833
+ await mutateConfig((freshConfig) => {
834
+ persistSyncState(summary, freshConfig);
835
+ }, this.configPath);
812
836
  }
813
837
  async enablePlugin(pluginId) {
814
- const config = loadConfig(this.configPath);
815
- if (!config.plugins)
816
- throw new Error(`Plugin ${pluginId} not found`);
817
- const plugin = config.plugins[pluginId];
818
- if (!plugin)
819
- throw new Error(`Plugin ${pluginId} not found`);
820
- plugin.enabled = true;
821
- saveConfig(config, this.configPath);
838
+ await mutateConfig((config) => {
839
+ if (!config.plugins)
840
+ throw new Error(`Plugin ${pluginId} not found`);
841
+ const plugin = config.plugins[pluginId];
842
+ if (!plugin)
843
+ throw new Error(`Plugin ${pluginId} not found`);
844
+ plugin.enabled = true;
845
+ }, this.configPath);
822
846
  const syncConfig = loadConfig(this.configPath);
823
847
  const summary = syncAllClients(syncConfig, this.secrets);
824
- persistSyncState(summary, syncConfig);
825
- saveConfig(syncConfig, this.configPath);
848
+ await mutateConfig((freshConfig) => {
849
+ persistSyncState(summary, freshConfig);
850
+ }, this.configPath);
826
851
  }
827
852
  async disablePlugin(pluginId) {
828
- const config = loadConfig(this.configPath);
829
- if (!config.plugins)
830
- throw new Error(`Plugin ${pluginId} not found`);
831
- const plugin = config.plugins[pluginId];
832
- if (!plugin)
833
- throw new Error(`Plugin ${pluginId} not found`);
834
- plugin.enabled = false;
835
- saveConfig(config, this.configPath);
853
+ await mutateConfig((config) => {
854
+ if (!config.plugins)
855
+ throw new Error(`Plugin ${pluginId} not found`);
856
+ const plugin = config.plugins[pluginId];
857
+ if (!plugin)
858
+ throw new Error(`Plugin ${pluginId} not found`);
859
+ plugin.enabled = false;
860
+ }, this.configPath);
836
861
  const syncConfig = loadConfig(this.configPath);
837
862
  const summary = syncAllClients(syncConfig, this.secrets);
838
- persistSyncState(summary, syncConfig);
839
- saveConfig(syncConfig, this.configPath);
863
+ await mutateConfig((freshConfig) => {
864
+ persistSyncState(summary, freshConfig);
865
+ }, this.configPath);
840
866
  }
841
867
  async approveComponent(pluginId, component) {
842
- const config = loadConfig(this.configPath);
843
- if (!config.plugins)
844
- throw new Error(`Plugin ${pluginId} not found`);
845
- const plugin = config.plugins[pluginId];
846
- if (!plugin)
847
- throw new Error(`Plugin ${pluginId} not found`);
848
- if (!plugin.approvals)
849
- plugin.approvals = {};
850
- plugin.approvals[component] = true;
851
- if (component === "mcpServers") {
852
- for (const name of plugin.serverNames) {
853
- if (config.servers[name]) {
854
- config.servers[name].enabled = plugin.enabled;
868
+ await mutateConfig((config) => {
869
+ if (!config.plugins)
870
+ throw new Error(`Plugin ${pluginId} not found`);
871
+ const plugin = config.plugins[pluginId];
872
+ if (!plugin)
873
+ throw new Error(`Plugin ${pluginId} not found`);
874
+ if (!plugin.approvals)
875
+ plugin.approvals = {};
876
+ plugin.approvals[component] = true;
877
+ if (component === "mcpServers") {
878
+ for (const name of plugin.serverNames) {
879
+ if (config.servers[name]) {
880
+ config.servers[name].enabled = plugin.enabled;
881
+ }
855
882
  }
856
883
  }
857
- }
858
- saveConfig(config, this.configPath);
884
+ }, this.configPath);
859
885
  const syncConfig = loadConfig(this.configPath);
860
886
  const summary = syncAllClients(syncConfig, this.secrets);
861
- persistSyncState(summary, syncConfig);
862
- saveConfig(syncConfig, this.configPath);
887
+ await mutateConfig((freshConfig) => {
888
+ persistSyncState(summary, freshConfig);
889
+ }, this.configPath);
863
890
  }
864
891
  async getPluginStatus(pluginId) {
865
892
  const config = loadConfig(this.configPath);
@@ -912,23 +939,24 @@ async function disablePlugin(nameOrId) {
912
939
  await manager.disablePlugin(id);
913
940
  }
914
941
  async function setPluginProjectOverride(nameOrId, projectPath, override) {
915
- const config = loadConfig();
916
- const id = resolvePluginId(config, nameOrId);
917
- const plugin = config.plugins?.[id];
918
- if (!plugin)
919
- throw new Error(`Plugin ${id} not found`);
920
- if (!config.projects?.[projectPath]) {
921
- throw new Error(`Project "${projectPath}" is not registered. Run "mcpx project init" there first.`);
922
- }
923
- if (!plugin.projectOverrides)
924
- plugin.projectOverrides = {};
925
- plugin.projectOverrides[projectPath] = { ...plugin.projectOverrides[projectPath], ...override };
926
- saveConfig(config);
942
+ await mutateConfig((config) => {
943
+ const id = resolvePluginId(config, nameOrId);
944
+ const plugin = config.plugins?.[id];
945
+ if (!plugin)
946
+ throw new Error(`Plugin ${id} not found`);
947
+ if (!config.projects?.[projectPath]) {
948
+ throw new Error(`Project "${projectPath}" is not registered. Run "mcpx project init" there first.`);
949
+ }
950
+ if (!plugin.projectOverrides)
951
+ plugin.projectOverrides = {};
952
+ plugin.projectOverrides[projectPath] = { ...plugin.projectOverrides[projectPath], ...override };
953
+ });
927
954
  const secrets = new SecretsManager;
928
955
  const syncConfig = loadConfig();
929
956
  const summary = syncAllClients(syncConfig, secrets);
930
- persistSyncState(summary, syncConfig);
931
- saveConfig(syncConfig);
957
+ await mutateConfig((freshConfig) => {
958
+ persistSyncState(summary, freshConfig);
959
+ });
932
960
  }
933
961
  async function approvePluginComponent(nameOrId, component) {
934
962
  const manager = new PluginManager;
@@ -964,32 +992,34 @@ function resolvePluginId(config, nameOrId) {
964
992
  }
965
993
  async function pluginConfigSet(nameOrId, key, value, projectPath) {
966
994
  const manager = new PluginManager;
967
- const config = loadConfig(manager["configPath"]);
968
- const id = resolvePluginId(config, nameOrId);
969
- const plugin = config.plugins?.[id];
970
- if (!plugin)
971
- throw new Error(`Plugin ${id} not found`);
972
- if (projectPath) {
973
- if (!plugin.projectOverrides)
974
- plugin.projectOverrides = {};
975
- if (!plugin.projectOverrides[projectPath])
976
- plugin.projectOverrides[projectPath] = {};
977
- if (!plugin.projectOverrides[projectPath].config)
978
- plugin.projectOverrides[projectPath].config = {};
979
- plugin.projectOverrides[projectPath].config[key] = value;
980
- } else {
981
- if (!plugin.config)
982
- plugin.config = {};
983
- plugin.config[key] = value;
984
- }
985
- saveConfig(config, manager["configPath"]);
995
+ const configPath = manager["configPath"];
996
+ await mutateConfig((config) => {
997
+ const id = resolvePluginId(config, nameOrId);
998
+ const plugin = config.plugins?.[id];
999
+ if (!plugin)
1000
+ throw new Error(`Plugin ${id} not found`);
1001
+ if (projectPath) {
1002
+ if (!plugin.projectOverrides)
1003
+ plugin.projectOverrides = {};
1004
+ if (!plugin.projectOverrides[projectPath])
1005
+ plugin.projectOverrides[projectPath] = {};
1006
+ if (!plugin.projectOverrides[projectPath].config)
1007
+ plugin.projectOverrides[projectPath].config = {};
1008
+ plugin.projectOverrides[projectPath].config[key] = value;
1009
+ } else {
1010
+ if (!plugin.config)
1011
+ plugin.config = {};
1012
+ plugin.config[key] = value;
1013
+ }
1014
+ }, configPath);
986
1015
  }
987
1016
  async function pluginSync() {
988
1017
  const config = loadConfig();
989
1018
  const secrets = new SecretsManager;
990
1019
  const summary = syncAllClients(config, secrets);
991
- persistSyncState(summary, config);
992
- saveConfig(config);
1020
+ await mutateConfig((freshConfig) => {
1021
+ persistSyncState(summary, freshConfig);
1022
+ });
993
1023
  }
994
1024
  async function preparePlugin(name) {
995
1025
  const manager = new PluginManager;