@oneciel-ai/claude-any 0.1.91 → 0.1.93

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 +119 -12
  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.93"
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
@@ -5035,6 +5083,45 @@ def _channel_mcp_update_cursor(last_id: int) -> None:
5035
5083
  router_log("WARN", f"channel_mcp_cursor_write_failed error={type(exc).__name__}: {exc}")
5036
5084
 
5037
5085
 
5086
+ def _channel_mcp_parse_event_id(value: Any) -> int | None:
5087
+ text = str(value or "").strip()
5088
+ if not text:
5089
+ return None
5090
+ try:
5091
+ return max(0, int(text))
5092
+ except Exception:
5093
+ return None
5094
+
5095
+
5096
+ def _channel_mcp_client_last_event_id(handler: BaseHTTPRequestHandler) -> int | None:
5097
+ try:
5098
+ event_id = _channel_mcp_parse_event_id(handler.headers.get("Last-Event-ID"))
5099
+ if event_id is not None:
5100
+ return event_id
5101
+ except Exception:
5102
+ pass
5103
+ try:
5104
+ params = _query_params(handler)
5105
+ for key in ("lastEventId", "last_event_id", "last_id"):
5106
+ event_id = _channel_mcp_parse_event_id(_first_param(params, key))
5107
+ if event_id is not None:
5108
+ return event_id
5109
+ except Exception:
5110
+ pass
5111
+ return None
5112
+
5113
+
5114
+ def _channel_mcp_session_start_last_id(handler: BaseHTTPRequestHandler) -> int:
5115
+ cursor_last_id = _channel_mcp_ensure_cursor_initialized()
5116
+ client_last_id = _channel_mcp_client_last_event_id(handler)
5117
+ if client_last_id is None:
5118
+ return cursor_last_id
5119
+ if client_last_id > cursor_last_id:
5120
+ _channel_mcp_update_cursor(client_last_id)
5121
+ router_log("INFO", f"channel_mcp_resume client_last_id={client_last_id} cursor_last_id={cursor_last_id}")
5122
+ return client_last_id
5123
+
5124
+
5038
5125
  def _channel_mcp_notifications_for_messages(
5039
5126
  messages: list[dict[str, Any]],
5040
5127
  session: str = "",
@@ -5054,7 +5141,7 @@ def _channel_mcp_notifications_for_messages(
5054
5141
  events.append((last_id, _channel_mcp_notification(message)))
5055
5142
  router_log(
5056
5143
  "INFO",
5057
- f"channel_mcp_notification_sent session={session or '-'} message_id={message.get('id')} channel={message.get('channel')}",
5144
+ f"channel_mcp_notification_prepared session={session or '-'} message_id={message.get('id')} channel={message.get('channel')}",
5058
5145
  )
5059
5146
  return last_id, events
5060
5147
 
@@ -5066,7 +5153,7 @@ def handle_channel_mcp_get(handler: BaseHTTPRequestHandler, path: str) -> bool:
5066
5153
  if path != "/ca/mcp/sse":
5067
5154
  return False
5068
5155
  session = _channel_mcp_session_id()
5069
- last_id = _channel_mcp_ensure_cursor_initialized()
5156
+ last_id = _channel_mcp_session_start_last_id(handler)
5070
5157
  with _CHANNEL_MCP_LOCK:
5071
5158
  _CHANNEL_MCP_SESSIONS[session] = {"created_at": time.time(), "last_id": last_id, "initialized": False, "outbox": []}
5072
5159
  router_log("INFO", f"channel_mcp_session_started session={session} last_id={last_id}")
@@ -5101,7 +5188,9 @@ def handle_channel_mcp_get(handler: BaseHTTPRequestHandler, path: str) -> bool:
5101
5188
  last_id = max(last_id, delivered_last_id)
5102
5189
  for event_id, notification in events:
5103
5190
  _write_sse_event(handler, "message", notification, event_id)
5104
- _channel_mcp_update_cursor(last_id)
5191
+ router_log("INFO", f"channel_mcp_notification_written session={session} message_id={event_id}")
5192
+ if not events:
5193
+ _channel_mcp_update_cursor(last_id)
5105
5194
  with _CHANNEL_MCP_LOCK:
5106
5195
  state = _CHANNEL_MCP_SESSIONS.get(session)
5107
5196
  if state:
@@ -9392,7 +9481,7 @@ def _mcp_server_is_stdio(server: dict[str, Any]) -> bool:
9392
9481
  server_type = str(server.get("type") or "").strip().lower()
9393
9482
  if server_type and server_type not in ("stdio", "command"):
9394
9483
  return False
9395
- command = str(server.get("command") or "").strip()
9484
+ command = resolve_executable_for_subprocess(str(server.get("command") or "").strip())
9396
9485
  if not command:
9397
9486
  return False
9398
9487
  args = [str(item) for item in server.get("args", []) if item is not None] if isinstance(server.get("args", []), list) else []
@@ -13854,7 +13943,6 @@ def write_web_tools_mcp_config(cfg: dict[str, Any]) -> Path:
13854
13943
  web = cfg.get("web_search", {})
13855
13944
  package = web.get("package") or "ddg-mcp-search"
13856
13945
  npx = find_executable("npx") or ("npx.cmd" if os.name == "nt" else "npx")
13857
- uvx = find_executable("uvx") or "uvx"
13858
13946
  servers: dict[str, Any] = {
13859
13947
  "duckduckgo": {
13860
13948
  "command": npx,
@@ -13867,11 +13955,29 @@ def write_web_tools_mcp_config(cfg: dict[str, Any]) -> Path:
13867
13955
  fetch_args.extend(["--user-agent", str(web["fetch_user_agent"])])
13868
13956
  if web.get("fetch_ignore_robots_txt", False):
13869
13957
  fetch_args.append("--ignore-robots-txt")
13870
- servers["web_fetch"] = {
13871
- "command": uvx,
13872
- "args": fetch_args,
13873
- "claude_any_stdio": "jsonl",
13874
- }
13958
+ fetch_command = find_executable("uvx")
13959
+ fetch_command_args = fetch_args
13960
+ if not fetch_command:
13961
+ uv = find_executable("uv")
13962
+ if uv:
13963
+ fetch_command = uv
13964
+ fetch_command_args = ["tool", "run", *fetch_args]
13965
+ elif importlib.util.find_spec("uv") is not None:
13966
+ fetch_command = sys.executable
13967
+ fetch_command_args = ["-m", "uv", "tool", "run", *fetch_args]
13968
+ else:
13969
+ pipx = find_executable("pipx")
13970
+ if pipx:
13971
+ fetch_command = pipx
13972
+ fetch_command_args = ["run", *fetch_args]
13973
+ if fetch_command:
13974
+ servers["web_fetch"] = {
13975
+ "command": fetch_command,
13976
+ "args": fetch_command_args,
13977
+ "claude_any_stdio": "jsonl",
13978
+ }
13979
+ else:
13980
+ router_log("WARN", "web_fetch_disabled_missing_runner install=uvx_or_uv")
13875
13981
  data = {"mcpServers": servers}
13876
13982
  CONFIG_DIR.mkdir(parents=True, exist_ok=True)
13877
13983
  WEB_TOOLS_MCP_CONFIG.write_text(json.dumps(data, indent=2) + "\n")
@@ -14600,6 +14706,7 @@ def run_mcp_stdio_proxy(server_name: str, server_config_path: Path) -> int:
14600
14706
  return 2
14601
14707
  command = str(server.get("command") or "").strip()
14602
14708
  args = [str(item) for item in server.get("args", [])] if isinstance(server.get("args"), list) else []
14709
+ command, args = resolve_mcp_server_process(command, args)
14603
14710
  env = os.environ.copy()
14604
14711
  raw_env = server.get("env")
14605
14712
  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.93",
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",