@phidiassj/aiyoperps-mcp-installer 0.5.5 → 0.5.7

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.
@@ -9,6 +9,17 @@ import { parse as parseToml } from 'smol-toml';
9
9
 
10
10
  const SERVER_NAME = 'aiyoperps';
11
11
  const DEFAULT_URL = 'http://127.0.0.1:5078/mcp';
12
+ const BRIDGE_PACKAGE_NAME = '@phidiassj/aiyoperps-mcp-bridge';
13
+ const BRIDGE_SCRIPT_RELATIVE_PATH = path.join(
14
+ 'node_modules',
15
+ '@phidiassj',
16
+ 'aiyoperps-mcp-bridge',
17
+ 'bin',
18
+ 'aiyoperps-mcp-bridge.js');
19
+ const EXECUTABLE_CACHE = new Map();
20
+ let bridgeRuntimePrepared = false;
21
+ let bridgeRuntimeAttempted = false;
22
+ let bridgeRuntimeWarning = '';
12
23
 
13
24
  const cli = parseCliArgs(argv.slice(2));
14
25
  const targetUrl = cli.url;
@@ -541,20 +552,18 @@ function buildJsonServerConfig(url) {
541
552
  }
542
553
 
543
554
  async function prewarmBridgePackage(url) {
544
- stdout.write('\nPrewarming npm bridge package...\n');
545
- const commandLine = resolveCommandLineSpec(process.platform, url, {
546
- prewarm: true
547
- });
548
- const result = runCommand(commandLine.command, commandLine.args);
549
- if (!result.ok) {
550
- stdout.write(` warning: prewarm failed: ${result.stderr || result.error?.message || 'unknown error'}\n`);
555
+ stdout.write('\nPreparing bridge runtime...\n');
556
+ await ensureBridgeRuntimePrepared();
557
+ if (bridgeRuntimePrepared) {
558
+ stdout.write(` ready: ${resolveInstalledBridgeScriptPath()}\n`);
551
559
  return;
552
560
  }
553
561
 
554
- stdout.write(' prewarm complete\n');
562
+ stdout.write(` warning: ${bridgeRuntimeWarning || 'falling back to npx'}\n`);
555
563
  }
556
564
 
557
565
  async function resolveInstallUrl(defaultUrl, urlExplicit) {
566
+ await ensureBridgeRuntimePrepared();
558
567
  const candidates = urlExplicit
559
568
  ? [defaultUrl]
560
569
  : buildCandidateUrls(defaultUrl);
@@ -605,35 +614,11 @@ function detectWslGatewayUrl() {
605
614
  }
606
615
 
607
616
  async function canReachMcpEndpoint(url) {
608
- const controller = new AbortController();
609
- const timeout = setTimeout(() => controller.abort(), 2500);
610
-
611
- try {
612
- const response = await fetch(url, {
613
- method: 'POST',
614
- headers: {
615
- 'Content-Type': 'application/json'
616
- },
617
- body: JSON.stringify({
618
- jsonrpc: '2.0',
619
- id: 'installer-probe',
620
- method: 'ping',
621
- params: {}
622
- }),
623
- signal: controller.signal
624
- });
625
-
626
- if (!response.ok) {
627
- return false;
628
- }
629
-
630
- const payload = await response.json();
631
- return !payload?.error;
632
- } catch {
633
- return false;
634
- } finally {
635
- clearTimeout(timeout);
636
- }
617
+ const commandLine = resolveCommandLineSpec(process.platform, url, {
618
+ healthCheck: true
619
+ });
620
+ const result = runCommand(commandLine.command, commandLine.args);
621
+ return result.ok;
637
622
  }
638
623
 
639
624
  function hasCodexBlock(content) {
@@ -784,26 +769,101 @@ function splitCsvArg(value) {
784
769
  }
785
770
 
786
771
  function resolveCommandLineSpec(platform, url, options = {}) {
787
- const packageArgs = ['-y', '@phidiassj/aiyoperps-mcp-bridge'];
772
+ const bridgeArgs = [];
788
773
  if (options.prewarm) {
789
- packageArgs.push('--help');
774
+ bridgeArgs.push('--help');
775
+ } else if (options.healthCheck) {
776
+ bridgeArgs.push('--health-check', '--quiet', '--url', url);
790
777
  } else {
791
- packageArgs.push('--startup-ping', '--url', url);
778
+ bridgeArgs.push('--quiet', '--url', url);
779
+ }
780
+
781
+ const installedScriptPath = resolveInstalledBridgeScriptPath();
782
+ if (installedScriptPath) {
783
+ return {
784
+ command: process.execPath,
785
+ args: [installedScriptPath, ...bridgeArgs]
786
+ };
792
787
  }
793
788
 
789
+ const packageArgs = ['-y', BRIDGE_PACKAGE_NAME, ...bridgeArgs];
790
+ const resolvedNpx = resolveExecutablePath(platform === 'win32' ? 'npx.cmd' : 'npx');
794
791
  if (platform === 'win32') {
795
792
  return {
796
- command: 'npx.cmd',
793
+ command: resolvedNpx || 'npx.cmd',
797
794
  args: packageArgs
798
795
  };
799
796
  }
800
797
 
801
798
  return {
802
- command: 'npx',
799
+ command: resolvedNpx || 'npx',
803
800
  args: packageArgs
804
801
  };
805
802
  }
806
803
 
804
+ async function ensureBridgeRuntimePrepared() {
805
+ if (bridgeRuntimeAttempted) {
806
+ return bridgeRuntimePrepared;
807
+ }
808
+
809
+ bridgeRuntimeAttempted = true;
810
+
811
+ if (resolveInstalledBridgeScriptPath()) {
812
+ bridgeRuntimePrepared = true;
813
+ return true;
814
+ }
815
+
816
+ const npmCommand = resolveExecutablePath(process.platform === 'win32' ? 'npm.cmd' : 'npm');
817
+ if (!npmCommand) {
818
+ bridgeRuntimeWarning = 'npm was not found in PATH, falling back to npx.';
819
+ return false;
820
+ }
821
+
822
+ const installRoot = resolveBridgeInstallRoot();
823
+ ensureParentDir(path.join(installRoot, 'placeholder'));
824
+
825
+ const result = runCommand(npmCommand, [
826
+ 'install',
827
+ '--silent',
828
+ '--no-audit',
829
+ '--no-fund',
830
+ '--prefix',
831
+ installRoot,
832
+ BRIDGE_PACKAGE_NAME
833
+ ]);
834
+
835
+ if (!result.ok) {
836
+ bridgeRuntimeWarning = result.stderr || result.error?.message || 'npm install failed, falling back to npx.';
837
+ return false;
838
+ }
839
+
840
+ if (!resolveInstalledBridgeScriptPath()) {
841
+ bridgeRuntimeWarning = 'bridge package installed, but launcher script was not found; falling back to npx.';
842
+ return false;
843
+ }
844
+
845
+ bridgeRuntimePrepared = true;
846
+ return true;
847
+ }
848
+
849
+ function resolveBridgeInstallRoot() {
850
+ if (env.AIYOPERPS_MCP_BRIDGE_DIR) {
851
+ return env.AIYOPERPS_MCP_BRIDGE_DIR;
852
+ }
853
+
854
+ if (process.platform === 'win32') {
855
+ const appData = env.LOCALAPPDATA || path.join(env.USERPROFILE || os.homedir(), 'AppData', 'Local');
856
+ return path.join(appData, 'AiyoPerps', 'mcp-bridge');
857
+ }
858
+
859
+ return path.join(os.homedir(), '.aiyoperps', 'mcp-bridge');
860
+ }
861
+
862
+ function resolveInstalledBridgeScriptPath() {
863
+ const scriptPath = path.join(resolveBridgeInstallRoot(), BRIDGE_SCRIPT_RELATIVE_PATH);
864
+ return fileExists(scriptPath) ? scriptPath : null;
865
+ }
866
+
807
867
  function resolveCodexConfigPath() {
808
868
  if (env.CODEX_CONFIG_PATH) {
809
869
  return env.CODEX_CONFIG_PATH;
@@ -868,6 +928,35 @@ function runCommand(command, args) {
868
928
  };
869
929
  }
870
930
 
931
+ function resolveExecutablePath(name) {
932
+ if (EXECUTABLE_CACHE.has(name)) {
933
+ return EXECUTABLE_CACHE.get(name);
934
+ }
935
+
936
+ const pathValue = env.PATH || '';
937
+ const separator = process.platform === 'win32' ? ';' : ':';
938
+ const extensions = process.platform === 'win32'
939
+ ? ['', '.cmd', '.exe', '.bat']
940
+ : [''];
941
+
942
+ for (const directory of pathValue.split(separator)) {
943
+ if (!directory) {
944
+ continue;
945
+ }
946
+
947
+ for (const extension of extensions) {
948
+ const candidate = path.join(directory, name.endsWith(extension) ? name : `${name}${extension}`);
949
+ if (fileExists(candidate)) {
950
+ EXECUTABLE_CACHE.set(name, candidate);
951
+ return candidate;
952
+ }
953
+ }
954
+ }
955
+
956
+ EXECUTABLE_CACHE.set(name, null);
957
+ return null;
958
+ }
959
+
871
960
  function ensureParentDir(filePath) {
872
961
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
873
962
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phidiassj/aiyoperps-mcp-installer",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Interactive installer for registering AiyoPerps MCP with supported AI agent hosts.",
5
5
  "license": "MIT",
6
6
  "type": "module",