@oneciel-ai/claude-any 0.1.91 → 0.1.92

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 (2) hide show
  1. package/claude_any.py +75 -9
  2. package/package.json +1 -1
package/claude_any.py CHANGED
@@ -105,7 +105,7 @@ OFFICIAL_CHANNEL_PLUGINS = {
105
105
  "fakechat": "plugin:fakechat@claude-plugins-official",
106
106
  }
107
107
  APP_NAME = "Claude Any"
108
- VERSION = "0.1.91"
108
+ VERSION = "0.1.92"
109
109
  CREDITS = "Credits: One Ciel LLC"
110
110
 
111
111
  LOG_LEVELS = {"SILENT": 0, "ERROR": 1, "WARN": 2, "INFO": 3, "DEBUG": 4, "TRACE": 5}
@@ -1675,6 +1675,11 @@ def executable_candidates(name: str) -> list[str]:
1675
1675
 
1676
1676
  def executable_extra_dirs() -> list[Path]:
1677
1677
  dirs = [HOME / ".local" / "bin"]
1678
+ for env_name in ("UV_INSTALL_DIR", "CARGO_HOME"):
1679
+ root = os.environ.get(env_name)
1680
+ if root:
1681
+ path = Path(root)
1682
+ dirs.append(path if path.name == "bin" else path / "bin")
1678
1683
  if os.name == "nt":
1679
1684
  pyver = f"Python{sys.version_info.major}{sys.version_info.minor}"
1680
1685
  for env_name in ("APPDATA", "LOCALAPPDATA"):
@@ -1688,7 +1693,27 @@ def executable_extra_dirs() -> list[Path]:
1688
1693
  except Exception:
1689
1694
  pass
1690
1695
  dirs.append(Path(sys.executable).resolve().parent / "Scripts")
1691
- return dirs
1696
+ else:
1697
+ dirs.extend(
1698
+ [
1699
+ HOME / ".cargo" / "bin",
1700
+ HOME / ".npm-global" / "bin",
1701
+ HOME / ".bun" / "bin",
1702
+ Path(sys.executable).resolve().parent,
1703
+ Path("/usr/local/bin"),
1704
+ Path("/usr/bin"),
1705
+ Path("/bin"),
1706
+ Path("/opt/homebrew/bin"),
1707
+ ]
1708
+ )
1709
+ out: list[Path] = []
1710
+ seen: set[str] = set()
1711
+ for directory in dirs:
1712
+ key = str(directory)
1713
+ if key and key not in seen:
1714
+ seen.add(key)
1715
+ out.append(directory)
1716
+ return out
1692
1717
 
1693
1718
 
1694
1719
  def find_executable(name: str) -> str | None:
@@ -1704,6 +1729,29 @@ def find_executable(name: str) -> str | None:
1704
1729
  return None
1705
1730
 
1706
1731
 
1732
+ def resolve_executable_for_subprocess(command: str) -> str:
1733
+ command = str(command or "").strip()
1734
+ if not command:
1735
+ return command
1736
+ pathish = Path(command).is_absolute() or os.sep in command or bool(os.altsep and os.altsep in command)
1737
+ if pathish:
1738
+ return command
1739
+ return find_executable(command) or command
1740
+
1741
+
1742
+ def resolve_mcp_server_process(command: str, args: list[str]) -> tuple[str, list[str]]:
1743
+ command = str(command or "").strip()
1744
+ resolved = resolve_executable_for_subprocess(command)
1745
+ name = Path(command).name.lower()
1746
+ if resolved == command and name in ("uvx", "uvx.exe", "uvx.cmd", "uvx.bat"):
1747
+ uv = find_executable("uv")
1748
+ if uv:
1749
+ return uv, ["tool", "run", *args]
1750
+ if importlib.util.find_spec("uv") is not None:
1751
+ return sys.executable, ["-m", "uv", "tool", "run", *args]
1752
+ return resolved, args
1753
+
1754
+
1707
1755
  def shell_command_string(args: list[str]) -> str:
1708
1756
  if os.name == "nt":
1709
1757
  # Claude Code on Windows runs hook commands through sh/bash, which treats
@@ -9392,7 +9440,7 @@ def _mcp_server_is_stdio(server: dict[str, Any]) -> bool:
9392
9440
  server_type = str(server.get("type") or "").strip().lower()
9393
9441
  if server_type and server_type not in ("stdio", "command"):
9394
9442
  return False
9395
- command = str(server.get("command") or "").strip()
9443
+ command = resolve_executable_for_subprocess(str(server.get("command") or "").strip())
9396
9444
  if not command:
9397
9445
  return False
9398
9446
  args = [str(item) for item in server.get("args", []) if item is not None] if isinstance(server.get("args", []), list) else []
@@ -13854,7 +13902,6 @@ def write_web_tools_mcp_config(cfg: dict[str, Any]) -> Path:
13854
13902
  web = cfg.get("web_search", {})
13855
13903
  package = web.get("package") or "ddg-mcp-search"
13856
13904
  npx = find_executable("npx") or ("npx.cmd" if os.name == "nt" else "npx")
13857
- uvx = find_executable("uvx") or "uvx"
13858
13905
  servers: dict[str, Any] = {
13859
13906
  "duckduckgo": {
13860
13907
  "command": npx,
@@ -13867,11 +13914,29 @@ def write_web_tools_mcp_config(cfg: dict[str, Any]) -> Path:
13867
13914
  fetch_args.extend(["--user-agent", str(web["fetch_user_agent"])])
13868
13915
  if web.get("fetch_ignore_robots_txt", False):
13869
13916
  fetch_args.append("--ignore-robots-txt")
13870
- servers["web_fetch"] = {
13871
- "command": uvx,
13872
- "args": fetch_args,
13873
- "claude_any_stdio": "jsonl",
13874
- }
13917
+ fetch_command = find_executable("uvx")
13918
+ fetch_command_args = fetch_args
13919
+ if not fetch_command:
13920
+ uv = find_executable("uv")
13921
+ if uv:
13922
+ fetch_command = uv
13923
+ fetch_command_args = ["tool", "run", *fetch_args]
13924
+ elif importlib.util.find_spec("uv") is not None:
13925
+ fetch_command = sys.executable
13926
+ fetch_command_args = ["-m", "uv", "tool", "run", *fetch_args]
13927
+ else:
13928
+ pipx = find_executable("pipx")
13929
+ if pipx:
13930
+ fetch_command = pipx
13931
+ fetch_command_args = ["run", *fetch_args]
13932
+ if fetch_command:
13933
+ servers["web_fetch"] = {
13934
+ "command": fetch_command,
13935
+ "args": fetch_command_args,
13936
+ "claude_any_stdio": "jsonl",
13937
+ }
13938
+ else:
13939
+ router_log("WARN", "web_fetch_disabled_missing_runner install=uvx_or_uv")
13875
13940
  data = {"mcpServers": servers}
13876
13941
  CONFIG_DIR.mkdir(parents=True, exist_ok=True)
13877
13942
  WEB_TOOLS_MCP_CONFIG.write_text(json.dumps(data, indent=2) + "\n")
@@ -14600,6 +14665,7 @@ def run_mcp_stdio_proxy(server_name: str, server_config_path: Path) -> int:
14600
14665
  return 2
14601
14666
  command = str(server.get("command") or "").strip()
14602
14667
  args = [str(item) for item in server.get("args", [])] if isinstance(server.get("args"), list) else []
14668
+ command, args = resolve_mcp_server_process(command, args)
14603
14669
  env = os.environ.copy()
14604
14670
  raw_env = server.get("env")
14605
14671
  if isinstance(raw_env, dict):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneciel-ai/claude-any",
3
- "version": "0.1.91",
3
+ "version": "0.1.92",
4
4
  "description": "Claude Code provider selector for Anthropic, Ollama, Ollama Cloud, vLLM, NVIDIA hosted, and self-hosted NIM.",
5
5
  "license": "MIT",
6
6
  "author": "One Ciel LLC",