@phidiassj/aiyoperps-mcp-installer 0.6.6 → 0.6.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.
@@ -147,13 +147,23 @@ async function detectClaudeCode(url) {
147
147
 
148
148
  async function detectClaudeDesktop(url) {
149
149
  const candidates = getClaudeDesktopCandidates();
150
- const configPath = candidates.find(fileExists) ?? candidates[0];
150
+ const configPath = candidates.find(fileExists) ??
151
+ candidates.find(candidate => fs.existsSync(path.dirname(candidate))) ??
152
+ candidates[0];
151
153
  const exists = fileExists(configPath);
152
154
  const parentExists = fs.existsSync(path.dirname(configPath));
153
- const detected = exists || parentExists;
154
- let supported = parentExists;
155
+ const baseConfigRoot = path.dirname(path.dirname(configPath));
156
+ const baseRootExists = fs.existsSync(baseConfigRoot);
157
+ const detected = exists || parentExists || baseRootExists;
158
+ let supported = baseRootExists;
155
159
  let installed = false;
156
- let reason = detected ? 'ready for JSON config merge' : 'config directory not found';
160
+ let reason = exists
161
+ ? 'ready for JSON config merge'
162
+ : parentExists
163
+ ? 'ready for JSON config merge'
164
+ : baseRootExists
165
+ ? 'default config path can be created'
166
+ : 'config root not found';
157
167
 
158
168
  if (exists) {
159
169
  try {
@@ -571,9 +581,14 @@ async function resolveInstallUrl(defaultUrl, urlExplicit) {
571
581
 
572
582
  stdout.write('\nProbing MCP endpoint candidates...\n');
573
583
  for (const candidate of candidates) {
574
- const ok = await canReachMcpEndpoint(candidate);
575
- stdout.write(` ${ok ? 'ok' : 'fail'} ${candidate}\n`);
576
- if (ok) {
584
+ const result = await probeMcpEndpoint(candidate);
585
+ stdout.write(` ${result.ok ? 'ok' : 'fail'} ${candidate}`);
586
+ if (!result.ok) {
587
+ const detail = result.stderr || result.stdout || result.error?.message || `exit=${result.status ?? 'unknown'}`;
588
+ stdout.write(` (${truncateText(detail, 180)})`);
589
+ }
590
+ stdout.write('\n');
591
+ if (result.ok) {
577
592
  return candidate;
578
593
  }
579
594
  }
@@ -618,8 +633,97 @@ async function canReachMcpEndpoint(url) {
618
633
  const commandLine = resolveCommandLineSpec(process.platform, url, {
619
634
  healthCheck: true
620
635
  });
621
- const result = runCommand(commandLine.command, commandLine.args);
622
- return result.ok;
636
+ return runCommand(commandLine.command, commandLine.args);
637
+ }
638
+
639
+ async function probeMcpEndpoint(url) {
640
+ const httpResult = await probeMcpEndpointHttp(url);
641
+ if (!httpResult.ok) {
642
+ return httpResult;
643
+ }
644
+
645
+ if (!bridgeRuntimePrepared && bridgeRuntimeAttempted) {
646
+ return httpResult;
647
+ }
648
+
649
+ const bridgeResult = await canReachMcpEndpoint(url);
650
+ if (!bridgeResult.ok) {
651
+ stdout.write(` note bridge health check failed but HTTP MCP is reachable; continuing with ${url}\n`);
652
+ }
653
+
654
+ return httpResult;
655
+ }
656
+
657
+ async function probeMcpEndpointHttp(url) {
658
+ const controller = new AbortController();
659
+ const timeout = setTimeout(() => controller.abort(), 5000);
660
+
661
+ try {
662
+ const response = await fetch(url, {
663
+ method: 'POST',
664
+ headers: {
665
+ 'Content-Type': 'application/json'
666
+ },
667
+ body: JSON.stringify({
668
+ jsonrpc: '2.0',
669
+ id: 'installer-probe',
670
+ method: 'ping',
671
+ params: {}
672
+ }),
673
+ signal: controller.signal
674
+ });
675
+
676
+ const text = await response.text();
677
+ if (!response.ok) {
678
+ return {
679
+ ok: false,
680
+ status: response.status,
681
+ stdout: '',
682
+ stderr: `HTTP ${response.status}: ${text || response.statusText}`
683
+ };
684
+ }
685
+
686
+ let payload;
687
+ try {
688
+ payload = JSON.parse(text);
689
+ } catch (error) {
690
+ return {
691
+ ok: false,
692
+ status: response.status,
693
+ stdout: '',
694
+ stderr: `Invalid JSON: ${error.message}`
695
+ };
696
+ }
697
+
698
+ if (payload?.error) {
699
+ return {
700
+ ok: false,
701
+ status: response.status,
702
+ stdout: '',
703
+ stderr: payload.error.message || 'JSON-RPC error'
704
+ };
705
+ }
706
+
707
+ return {
708
+ ok: true,
709
+ status: response.status,
710
+ stdout: '',
711
+ stderr: ''
712
+ };
713
+ } catch (error) {
714
+ const message = error?.name === 'AbortError'
715
+ ? 'Request timeout after 5000ms'
716
+ : error?.message || 'Unknown fetch error';
717
+ return {
718
+ ok: false,
719
+ status: null,
720
+ stdout: '',
721
+ stderr: message,
722
+ error
723
+ };
724
+ } finally {
725
+ clearTimeout(timeout);
726
+ }
623
727
  }
624
728
 
625
729
  function hasCodexBlock(content) {
@@ -802,6 +906,16 @@ function resolveCommandLineSpec(platform, url, options = {}) {
802
906
  };
803
907
  }
804
908
 
909
+ function truncateText(value, maxLength) {
910
+ if (!value) {
911
+ return '';
912
+ }
913
+
914
+ return value.length <= maxLength
915
+ ? value
916
+ : `${value.slice(0, maxLength)}...`;
917
+ }
918
+
805
919
  async function ensureBridgeRuntimePrepared() {
806
920
  if (bridgeRuntimeAttempted) {
807
921
  return bridgeRuntimePrepared;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phidiassj/aiyoperps-mcp-installer",
3
- "version": "0.6.6",
3
+ "version": "0.6.7",
4
4
  "description": "Interactive installer for registering AiyoPerps MCP with supported AI agent hosts.",
5
5
  "license": "MIT",
6
6
  "type": "module",