@oneciel-ai/claude-any 0.1.83 → 0.1.84

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 +201 -44
  2. package/package.json +1 -1
package/claude_any.py CHANGED
@@ -104,7 +104,7 @@ OFFICIAL_CHANNEL_PLUGINS = {
104
104
  "fakechat": "plugin:fakechat@claude-plugins-official",
105
105
  }
106
106
  APP_NAME = "Claude Any"
107
- VERSION = "0.1.83"
107
+ VERSION = "0.1.84"
108
108
  CREDITS = "Credits: One Ciel LLC"
109
109
 
110
110
  LOG_LEVELS = {"SILENT": 0, "ERROR": 1, "WARN": 2, "INFO": 3, "DEBUG": 4, "TRACE": 5}
@@ -1052,6 +1052,7 @@ UI_TEXT = {
1052
1052
  "advisor_model": "Advisor Model",
1053
1053
  "test": "Test compatibility",
1054
1054
  "options": "LLM options",
1055
+ "channel_delivery": "Channel delivery",
1055
1056
  "log_level": "Log level",
1056
1057
  "presets": "LLM presets",
1057
1058
  "context_setup": "Context setup",
@@ -1073,6 +1074,7 @@ UI_TEXT = {
1073
1074
  "advisor_model": "Advisor Model",
1074
1075
  "test": "호환성 테스트",
1075
1076
  "options": "LLM 옵션",
1077
+ "channel_delivery": "채널 전달 방식",
1076
1078
  "log_level": "로그 레벨",
1077
1079
  "presets": "LLM 프리셋",
1078
1080
  "context_setup": "컨텍스트 설정",
@@ -1094,6 +1096,7 @@ UI_TEXT = {
1094
1096
  "advisor_model": "Advisor Model",
1095
1097
  "test": "互換性テスト",
1096
1098
  "options": "LLMオプション",
1099
+ "channel_delivery": "チャンネル配信方式",
1097
1100
  "log_level": "ログレベル",
1098
1101
  "presets": "LLMプリセット",
1099
1102
  "context_setup": "コンテキスト設定",
@@ -1115,6 +1118,7 @@ UI_TEXT = {
1115
1118
  "advisor_model": "Advisor Model",
1116
1119
  "test": "兼容性测试",
1117
1120
  "options": "LLM 选项",
1121
+ "channel_delivery": "频道投递方式",
1118
1122
  "log_level": "日志级别",
1119
1123
  "presets": "LLM 预设",
1120
1124
  "context_setup": "上下文设置",
@@ -1261,6 +1265,7 @@ DEFAULT_CONFIG: dict[str, Any] = {
1261
1265
  "compat_prompt_for_non_anthropic": True,
1262
1266
  "channels": [],
1263
1267
  "development_channels": False,
1268
+ "channel_delivery": "stdin",
1264
1269
  },
1265
1270
  "cleanup": {
1266
1271
  "managed_services_on_launch": True,
@@ -4836,27 +4841,63 @@ def _channel_mcp_session_id() -> str:
4836
4841
  return f"s{os.getpid()}-{time.time_ns()}"
4837
4842
 
4838
4843
 
4844
+ def _native_channel_meta_value(value: Any) -> str:
4845
+ if value is None:
4846
+ return ""
4847
+ if isinstance(value, str):
4848
+ return value
4849
+ if isinstance(value, bool):
4850
+ return "true" if value else "false"
4851
+ if isinstance(value, (int, float)):
4852
+ return str(value)
4853
+ return json.dumps(_json_safe_metadata(value), ensure_ascii=False, separators=(",", ":"), default=str)
4854
+
4855
+
4856
+ def _native_channel_meta(message: dict[str, Any]) -> dict[str, str]:
4857
+ raw_meta = message.get("meta") if isinstance(message.get("meta"), dict) else {}
4858
+ meta: dict[str, str] = {}
4859
+ for key, value in raw_meta.items():
4860
+ name = str(key or "").strip()
4861
+ if not name:
4862
+ continue
4863
+ meta[name] = _native_channel_meta_value(value)
4864
+ base = {
4865
+ "claude_any_message_id": message.get("id"),
4866
+ "channel": message.get("channel") or "default",
4867
+ "sender_id": message.get("sender_id") or "channel",
4868
+ "thread_id": message.get("thread_id"),
4869
+ "parent_id": message.get("parent_id"),
4870
+ "kind": message.get("kind"),
4871
+ }
4872
+ for key, value in base.items():
4873
+ if value is not None:
4874
+ meta[key] = _native_channel_meta_value(value)
4875
+ if raw_meta:
4876
+ meta["claude_any_meta_json"] = json.dumps(_json_safe_metadata(raw_meta), ensure_ascii=False, separators=(",", ":"), default=str)
4877
+ return meta
4878
+
4879
+
4839
4880
  def _channel_mcp_notification(message: dict[str, Any]) -> dict[str, Any]:
4840
4881
  text = re.sub(r"\s+", " ", str(message.get("message") or "")).strip()
4841
4882
  channel = str(message.get("channel") or "default")
4842
4883
  sender = str(message.get("sender_id") or "channel")
4843
4884
  prefix = f"[{channel}] {sender}"
4844
4885
  content = f"{prefix}: {text}" if text else prefix
4845
- meta = message.get("meta") if isinstance(message.get("meta"), dict) else {}
4846
- merged_meta = {
4847
- **meta,
4848
- "claude_any_message_id": message.get("id"),
4849
- "channel": channel,
4850
- "sender_id": sender,
4851
- "thread_id": message.get("thread_id"),
4852
- "parent_id": message.get("parent_id"),
4853
- }
4854
4886
  return {
4855
4887
  "jsonrpc": "2.0",
4856
4888
  "method": "notifications/claude/channel",
4857
4889
  "params": {
4858
4890
  "content": content,
4859
- "meta": merged_meta,
4891
+ "meta": _native_channel_meta(message),
4892
+ },
4893
+ }
4894
+
4895
+
4896
+ def _channel_mcp_capabilities() -> dict[str, Any]:
4897
+ return {
4898
+ "tools": {"listChanged": False},
4899
+ "experimental": {
4900
+ "claude/channel": {},
4860
4901
  },
4861
4902
  }
4862
4903
 
@@ -4941,7 +4982,7 @@ def handle_channel_mcp_post(handler: BaseHTTPRequestHandler, path: str, body: di
4941
4982
  "id": request_id,
4942
4983
  "result": {
4943
4984
  "protocolVersion": protocol,
4944
- "capabilities": {"tools": {"listChanged": False}},
4985
+ "capabilities": _channel_mcp_capabilities(),
4945
4986
  "serverInfo": {"name": "claude-any-router", "version": VERSION},
4946
4987
  },
4947
4988
  },
@@ -8949,6 +8990,7 @@ def status_lines() -> list[str]:
8949
8990
  f"claude_model: {current_upstream_model_id(provider, pcfg) if direct_native else current_alias(cfg)}",
8950
8991
  f"log_level: {log_level_status()}",
8951
8992
  f"channels: {channel_status_text(cfg)}",
8993
+ f"channel_delivery: {channel_delivery_mode(cfg)}",
8952
8994
  f"router: {'bypassed for native provider compatibility' if direct_native else (('up' if router_up() else 'down') + ' ' + ROUTER_BASE)}",
8953
8995
  f"config: {CONFIG_PATH}",
8954
8996
  ]
@@ -9384,6 +9426,33 @@ def set_channel_development_enabled(enabled: bool) -> list[str]:
9384
9426
  return ["Channel wake delivery is always enabled by Claude Any."]
9385
9427
 
9386
9428
 
9429
+ def normalize_channel_delivery(value: Any) -> str:
9430
+ text = str(value or "").strip().lower().replace("_", "-")
9431
+ if text in {"native", "native-channel", "native-channel-bridge", "claude-channel", "claude/native"}:
9432
+ return "native"
9433
+ if text in {"stdin", "pty", "terminal", "wake", "wake-proxy", "legacy", "auto", ""}:
9434
+ return "stdin"
9435
+ return "stdin"
9436
+
9437
+
9438
+ def channel_delivery_mode(cfg: dict[str, Any] | None = None) -> str:
9439
+ env_value = os.environ.get("CLAUDE_ANY_CHANNEL_DELIVERY")
9440
+ if env_value is not None:
9441
+ return normalize_channel_delivery(env_value)
9442
+ cfg = cfg or load_config()
9443
+ return normalize_channel_delivery(cfg.setdefault("claude_code", {}).get("channel_delivery", "stdin"))
9444
+
9445
+
9446
+ def set_channel_delivery_config(value: Any) -> list[str]:
9447
+ mode = normalize_channel_delivery(value)
9448
+ cfg = load_config()
9449
+ cfg.setdefault("claude_code", {})["channel_delivery"] = mode
9450
+ save_config(cfg)
9451
+ if mode == "native":
9452
+ return ["Channel delivery set to native claude/channel bridge."]
9453
+ return ["Channel delivery set to stdin wake proxy."]
9454
+
9455
+
9387
9456
  def add_channel_spec(spec: str, *, development: bool = False) -> list[str]:
9388
9457
  spec = spec.strip()
9389
9458
  if not spec:
@@ -9422,6 +9491,7 @@ def cmd_channels(args: argparse.Namespace) -> None:
9422
9491
  values = list(getattr(args, "values", []) or [])
9423
9492
  if not values:
9424
9493
  print(f"channels: {channel_status_text(cfg)}")
9494
+ print(f"delivery: {channel_delivery_mode(cfg)}")
9425
9495
  for name, spec in OFFICIAL_CHANNEL_PLUGINS.items():
9426
9496
  mark = "*" if spec in channel_specs(cfg) else " "
9427
9497
  print(f" {mark} {name:<10} {spec}")
@@ -9456,6 +9526,13 @@ def cmd_channels(args: argparse.Namespace) -> None:
9456
9526
  for line in clear_channel_specs():
9457
9527
  print(line)
9458
9528
  return
9529
+ if head in ("delivery", "mode"):
9530
+ if len(values) < 2:
9531
+ print(f"channel_delivery: {channel_delivery_mode(cfg)}")
9532
+ return
9533
+ for line in set_channel_delivery_config(values[1]):
9534
+ print(line)
9535
+ return
9459
9536
  if head in OFFICIAL_CHANNEL_PLUGINS:
9460
9537
  spec = OFFICIAL_CHANNEL_PLUGINS[head]
9461
9538
  if spec in channel_specs(cfg):
@@ -9469,6 +9546,15 @@ def cmd_channels(args: argparse.Namespace) -> None:
9469
9546
  print(line)
9470
9547
 
9471
9548
 
9549
+ def cmd_channel_delivery(args: argparse.Namespace) -> None:
9550
+ value = getattr(args, "value", None)
9551
+ if value:
9552
+ for line in set_channel_delivery_config(value):
9553
+ print(line)
9554
+ else:
9555
+ print(f"channel_delivery: {channel_delivery_mode()}")
9556
+
9557
+
9472
9558
  def cmd_ollama_native(args: argparse.Namespace) -> None:
9473
9559
  cfg = load_config()
9474
9560
  pcfg = cfg["providers"]["ollama"]
@@ -12646,18 +12732,19 @@ def compact_text(value: Any, width: int = 72) -> str:
12646
12732
  return fit_cells(value, width)
12647
12733
 
12648
12734
 
12649
- def main_menu_rows(cfg: dict[str, Any], provider: str, pcfg: dict[str, Any], lang: str) -> list[str]:
12650
- return [
12651
- f"0. {ui_text('language', lang)} [{LANGUAGES.get(lang, lang)}]",
12652
- f"1. {ui_text('provider', lang)} [{provider}]",
12653
- f"2. {ui_text('api_key', lang)} [{stored_api_key_mask(provider, pcfg)}]",
12654
- f"3. {ui_text('base_url', lang)} [{compact_text(pcfg.get('base_url', 'unset'), 62)}]",
12735
+ def main_menu_rows(cfg: dict[str, Any], provider: str, pcfg: dict[str, Any], lang: str) -> list[str]:
12736
+ return [
12737
+ f"0. {ui_text('language', lang)} [{LANGUAGES.get(lang, lang)}]",
12738
+ f"1. {ui_text('provider', lang)} [{provider}]",
12739
+ f"2. {ui_text('api_key', lang)} [{stored_api_key_mask(provider, pcfg)}]",
12740
+ f"3. {ui_text('base_url', lang)} [{compact_text(pcfg.get('base_url', 'unset'), 62)}]",
12655
12741
  f"4. {ui_text('model', lang)} [{compact_text(pcfg.get('current_model', 'unset'), 62)}]",
12656
12742
  f"5. {ui_text('advisor_model', lang)} [{compact_text(pcfg.get('advisor_model') or 'off', 62)}]",
12657
12743
  f"6. {ui_text('options', lang)} [{compact_text(llm_options_status(provider, pcfg), 62)}]",
12658
- f"7. {ui_text('log_level', lang)} [{log_level_status()}]",
12659
- f"8. {ui_text('test', lang)}",
12660
- f"9. {ui_text('launch', lang)}",
12744
+ f"7. {ui_text('channel_delivery', lang)} [{channel_delivery_mode(cfg)}]",
12745
+ f"8. {ui_text('log_level', lang)} [{log_level_status()}]",
12746
+ f"9. {ui_text('test', lang)}",
12747
+ f"10. {ui_text('launch', lang)}",
12661
12748
  ui_text("quit", lang),
12662
12749
  ]
12663
12750
 
@@ -12773,6 +12860,16 @@ def channel_panel_rows(cfg: dict[str, Any]) -> tuple[list[str], list[str]]:
12773
12860
  return rows, values
12774
12861
 
12775
12862
 
12863
+ def channel_delivery_panel_rows(cfg: dict[str, Any]) -> tuple[list[str], list[str]]:
12864
+ current = channel_delivery_mode(cfg)
12865
+ rows = [
12866
+ f"{'*' if current == 'stdin' else ' '} stdin PTY wake proxy; works broadly, uses terminal input",
12867
+ f"{'*' if current == 'native' else ' '} native Claude Code claude/channel queue bridge",
12868
+ "Back",
12869
+ ]
12870
+ return rows, ["stdin", "native", "back"]
12871
+
12872
+
12776
12873
  def api_key_panel_rows(provider: str) -> tuple[list[str], list[str]]:
12777
12874
  rows = [
12778
12875
  "Type or paste API key as hidden input",
@@ -12866,13 +12963,16 @@ def render_prelaunch_screen(
12866
12963
  "api-key": "API key",
12867
12964
  "base-url": "Base URL",
12868
12965
  "model": "Model",
12869
- "advisor-model": "Advisor Model",
12870
- "test": "Compatibility test",
12871
- "options": ui_text("options", lang),
12872
- "context": ui_text("context_setup", lang),
12873
- "preset": ui_text("presets", lang),
12874
- "timeout": ui_text("timeout_preset", lang),
12875
- }
12966
+ "advisor-model": "Advisor Model",
12967
+ "test": "Compatibility test",
12968
+ "options": ui_text("options", lang),
12969
+ "channel-delivery": ui_text("channel_delivery", lang),
12970
+ "log-level": ui_text("log_level", lang),
12971
+ "channels": "Channels",
12972
+ "context": ui_text("context_setup", lang),
12973
+ "preset": ui_text("presets", lang),
12974
+ "timeout": ui_text("timeout_preset", lang),
12975
+ }
12876
12976
  add("")
12877
12977
  add("-" * render_width, "38;5;208")
12878
12978
  panel_title = titles.get(panel, panel)
@@ -13073,7 +13173,7 @@ def portable_language_menu() -> int:
13073
13173
 
13074
13174
  def portable_prelaunch_menu() -> int:
13075
13175
  enable_ansi()
13076
- main_idx = 9 if settings_ready_except_api_key() else 0
13176
+ main_idx = 10 if settings_ready_except_api_key() else 0
13077
13177
  panel: str | None = None
13078
13178
  panel_idx = 0
13079
13179
  panel_rows: list[str] = []
@@ -13115,6 +13215,8 @@ def portable_prelaunch_menu() -> int:
13115
13215
  panel_rows, panel_values = ["Run compatibility test", "Back"], ["run", "back"]
13116
13216
  elif name == "options":
13117
13217
  panel_rows, panel_values = llm_option_panel_rows(provider, pcfg, cfg.get("language", "en"))
13218
+ elif name == "channel-delivery":
13219
+ panel_rows, panel_values = channel_delivery_panel_rows(cfg)
13118
13220
  elif name == "log-level":
13119
13221
  panel_rows, panel_values = log_level_panel_rows(cfg)
13120
13222
  elif name == "channels":
@@ -13295,7 +13397,7 @@ def portable_prelaunch_menu() -> int:
13295
13397
  messages = lines[-8:] if lines else ["Test produced no output."]
13296
13398
  panel_rows, panel_values = ["Run compatibility test again", "Back"], ["run", "back"]
13297
13399
  refresh_checks()
13298
- main_idx = 9 if "Compatibility: OK" in out else 4
13400
+ main_idx = 10 if "Compatibility: OK" in out else 4
13299
13401
  elif panel == "log-level":
13300
13402
  if value == "back":
13301
13403
  close_panel()
@@ -13305,6 +13407,15 @@ def portable_prelaunch_menu() -> int:
13305
13407
  cfg = load_config()
13306
13408
  panel_rows, panel_values = log_level_panel_rows(cfg)
13307
13409
  panel_idx = max(0, min(panel_idx, len(panel_rows) - 1))
13410
+ elif panel == "channel-delivery":
13411
+ if value == "back":
13412
+ close_panel()
13413
+ elif value:
13414
+ messages = set_channel_delivery_config(value)
13415
+ refresh_checks()
13416
+ cfg = load_config()
13417
+ panel_rows, panel_values = channel_delivery_panel_rows(cfg)
13418
+ panel_idx = max(0, min(panel_idx, len(panel_rows) - 1))
13308
13419
  elif panel == "channels":
13309
13420
  if value == "back":
13310
13421
  close_panel()
@@ -13431,14 +13542,18 @@ def portable_prelaunch_menu() -> int:
13431
13542
  continue
13432
13543
 
13433
13544
  if key in ("up", "k"):
13434
- main_idx = (main_idx - 1) % 11
13545
+ cfg = load_config()
13546
+ provider, pcfg = get_current_provider(cfg)
13547
+ main_idx = (main_idx - 1) % len(main_menu_rows(cfg, provider, pcfg, cfg.get("language", "en")))
13435
13548
  elif key in ("down", "j"):
13436
- main_idx = (main_idx + 1) % 11
13549
+ cfg = load_config()
13550
+ provider, pcfg = get_current_provider(cfg)
13551
+ main_idx = (main_idx + 1) % len(main_menu_rows(cfg, provider, pcfg, cfg.get("language", "en")))
13437
13552
  elif key in ("esc", "q"):
13438
13553
  return 10
13439
13554
  elif key == "enter":
13440
- actions = ["language", "provider", "api-key", "base-url", "model", "advisor-model", "options", "log-level", "test", "launch", "quit"]
13441
- action = actions[main_idx]
13555
+ actions = ["language", "provider", "api-key", "base-url", "model", "advisor-model", "options", "channel-delivery", "log-level", "test", "launch", "quit"]
13556
+ action = actions[main_idx]
13442
13557
  if action == "launch":
13443
13558
  blockers = launch_readiness_errors()
13444
13559
  if blockers:
@@ -13563,6 +13678,10 @@ def claude_channels_requested(cfg: dict[str, Any], passthrough: list[str], extra
13563
13678
  return native_channel_passthrough_requested(passthrough)
13564
13679
 
13565
13680
 
13681
+ def should_use_native_channel_bridge(use_router_mode: bool, cfg: dict[str, Any], passthrough: list[str]) -> bool:
13682
+ return bool(use_router_mode and channel_delivery_mode(cfg) == "native" and not native_channel_passthrough_requested(passthrough))
13683
+
13684
+
13566
13685
  def write_web_tools_mcp_config(cfg: dict[str, Any]) -> Path:
13567
13686
  web = cfg.get("web_search", {})
13568
13687
  package = web.get("package") or "ddg-mcp-search"
@@ -13674,8 +13793,12 @@ def write_mcp_proxy_config(
13674
13793
  return MCP_PROXY_CONFIG
13675
13794
 
13676
13795
 
13677
- def should_use_channel_stdin_proxy(use_router_mode: bool, passthrough: list[str]) -> bool:
13678
- return bool(use_router_mode and not native_channel_passthrough_requested(passthrough))
13796
+ def should_use_channel_stdin_proxy(use_router_mode: bool, passthrough: list[str], cfg: dict[str, Any] | None = None) -> bool:
13797
+ if not use_router_mode or native_channel_passthrough_requested(passthrough):
13798
+ return False
13799
+ if cfg is not None and channel_delivery_mode(cfg) == "native":
13800
+ return False
13801
+ return True
13679
13802
 
13680
13803
 
13681
13804
  def format_channel_wake_prompt(message: dict[str, Any]) -> str:
@@ -14490,7 +14613,9 @@ def launch_claude(
14490
14613
  env["PATH"] = str(HOME / ".local" / "bin") + os.pathsep + env.get("PATH", "")
14491
14614
  launch_env = env_vars(cfg)
14492
14615
  launch_passthrough = normalize_channel_passthrough(passthrough)
14493
- if claude_channels_requested(cfg, launch_passthrough):
14616
+ native_channel_bridge = should_use_native_channel_bridge(use_router_mode, cfg, launch_passthrough)
14617
+ stdin_channel_proxy = should_use_channel_stdin_proxy(use_router_mode, launch_passthrough, cfg)
14618
+ if claude_channels_requested(cfg, launch_passthrough) or native_channel_bridge:
14494
14619
  env.pop("CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS", None)
14495
14620
  launch_env.pop("CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS", None)
14496
14621
  if use_native_anthropic:
@@ -14525,8 +14650,10 @@ def launch_claude(
14525
14650
  mcp_config_paths: list[str] = []
14526
14651
  if should_attach_web_search(provider, cfg, web_search_override):
14527
14652
  mcp_config_paths.append(str(write_duckduckgo_mcp_config(cfg)))
14653
+ if native_channel_bridge:
14654
+ mcp_config_paths.append(str(write_channel_mcp_config()))
14528
14655
  claude_passthrough = list(launch_passthrough)
14529
- if should_use_channel_stdin_proxy(use_router_mode, launch_passthrough):
14656
+ if stdin_channel_proxy or native_channel_bridge:
14530
14657
  auto_start_sse_channels_from_mcp_configs(launch_passthrough)
14531
14658
  proxy_config = write_mcp_proxy_config(
14532
14659
  launch_passthrough,
@@ -14549,7 +14676,7 @@ def launch_claude(
14549
14676
  cmd.extend(["--model", model])
14550
14677
  cmd.extend(extra_args)
14551
14678
  cmd.extend(claude_passthrough)
14552
- if should_use_channel_stdin_proxy(use_router_mode, launch_passthrough):
14679
+ if stdin_channel_proxy:
14553
14680
  return subprocess_call_with_channel_wake_proxy(cmd, env)
14554
14681
  return subprocess.call(cmd, env=env)
14555
14682
 
@@ -14574,7 +14701,9 @@ Control plane, runs before Claude Code and does not require LLM connectivity:
14574
14701
  claude-any web-fetch [on|off] Auto-attach fetch MCP for web page content
14575
14702
  claude-any log-level [LEVEL] Show or set router log level
14576
14703
  claude-any channels [cmd] Configure external channel specs
14577
- claude-any ollama-native [on|off] Use Ollama's official Claude Code env path
14704
+ claude-any channel-delivery [stdin|native]
14705
+ Select PTY wake proxy or native claude/channel bridge
14706
+ claude-any ollama-native [on|off] Use Ollama's official Claude Code env path
14578
14707
  claude-any ollama-options [provider] [key=value ...]
14579
14708
  Set Ollama num_ctx/options/keep_alive/think
14580
14709
  claude-any provider-options [provider] [key=value ...]
@@ -14614,6 +14743,8 @@ Headless setup flags, namespaced to avoid Claude CLI collisions:
14614
14743
  claude-any --ca-web-fetch Enable fetch MCP
14615
14744
  claude-any --ca-no-web-fetch Disable fetch MCP
14616
14745
  claude-any --ca-channel SPEC Add an official/approved Claude Code channel
14746
+ claude-any --ca-channel-delivery MODE
14747
+ Set channel delivery: stdin or native
14617
14748
  claude-any --ca-clear-channels Clear saved channel specs
14618
14749
  claude-any --ca-no-self-update-check
14619
14750
  Skip Claude Any npm self-update check
@@ -14738,6 +14869,10 @@ def apply_headless_env_config() -> tuple[bool, bool | None, bool | None, bool |
14738
14869
  for channel_value in dev_channel_values:
14739
14870
  add_channel_spec(channel_value)
14740
14871
  skip_menu = True
14872
+ channel_delivery = os.environ.get("CLAUDE_ANY_CHANNEL_DELIVERY", "").strip()
14873
+ if channel_delivery:
14874
+ set_channel_delivery_config(channel_delivery)
14875
+ skip_menu = True
14741
14876
  return skip_menu, web_search_override, update_check_override, self_update_check_override, force_menu
14742
14877
 
14743
14878
 
@@ -14805,9 +14940,16 @@ def run_cli(argv: list[str]) -> int:
14805
14940
  if head in ("channels", "channel"):
14806
14941
  cmd_channels(argparse.Namespace(values=rest))
14807
14942
  return 0
14808
- if head in ("ollama-native", "ollama-compat"):
14809
- cmd_ollama_native(argparse.Namespace(value=rest[0] if rest else None))
14810
- return 0
14943
+ if head in ("channel-delivery", "channel_delivery"):
14944
+ if rest:
14945
+ for line in set_channel_delivery_config(rest[0]):
14946
+ print(line)
14947
+ else:
14948
+ print(f"channel_delivery: {channel_delivery_mode()}")
14949
+ return 0
14950
+ if head in ("ollama-native", "ollama-compat"):
14951
+ cmd_ollama_native(argparse.Namespace(value=rest[0] if rest else None))
14952
+ return 0
14811
14953
  if head in ("ollama-options", "ollama-option", "ollama-opts"):
14812
14954
  cmd_ollama_options(argparse.Namespace(values=rest))
14813
14955
  return 0
@@ -15163,6 +15305,18 @@ def run_cli(argv: list[str]) -> int:
15163
15305
  for line in add_channel_spec(value):
15164
15306
  print(line)
15165
15307
  skip_menu = True
15308
+ elif arg == "--ca-channel-delivery" or arg.startswith("--ca-channel-delivery="):
15309
+ value = arg.split("=", 1)[1] if "=" in arg else None
15310
+ if value is None:
15311
+ if i + 1 >= len(argv):
15312
+ raise SystemExit("Missing mode for --ca-channel-delivery")
15313
+ value = argv[i + 1]
15314
+ i += 2
15315
+ else:
15316
+ i += 1
15317
+ for line in set_channel_delivery_config(value):
15318
+ print(line)
15319
+ skip_menu = True
15166
15320
  elif arg == "--ca-dev-channel" or arg.startswith("--ca-dev-channel="):
15167
15321
  value = arg.split("=", 1)[1] if "=" in arg else None
15168
15322
  if value is None:
@@ -15268,7 +15422,10 @@ def build_parser() -> argparse.ArgumentParser:
15268
15422
  ch = sub.add_parser("channels")
15269
15423
  ch.add_argument("values", nargs="*")
15270
15424
  ch.set_defaults(func=cmd_channels)
15271
- on = sub.add_parser("ollama-native")
15425
+ cd = sub.add_parser("channel-delivery")
15426
+ cd.add_argument("value", nargs="?")
15427
+ cd.set_defaults(func=cmd_channel_delivery)
15428
+ on = sub.add_parser("ollama-native")
15272
15429
  on.add_argument("value", nargs="?")
15273
15430
  on.set_defaults(func=cmd_ollama_native)
15274
15431
  oo = sub.add_parser("ollama-options")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneciel-ai/claude-any",
3
- "version": "0.1.83",
3
+ "version": "0.1.84",
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",