@oneciel-ai/claude-any 0.1.69 → 0.1.71

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.
package/README.md CHANGED
@@ -68,7 +68,7 @@ arguments through unchanged.
68
68
 
69
69
  Credits: One Ciel LLC
70
70
 
71
- Current version: `0.1.69`
71
+ Current version: `0.1.71`
72
72
 
73
73
  ## Why This Exists
74
74
 
@@ -495,6 +495,22 @@ steps under that larger model's supervision.
495
495
 
496
496
  ## Changelog
497
497
 
498
+ ### 0.1.71
499
+
500
+ - **MCP SSE channel initialization**: the channel bridge now handles MCP
501
+ `endpoint` events by sending `initialize` and `notifications/initialized`,
502
+ so AI-Net style push notifications can start flowing into Claude Any.
503
+ - **Channel SSE diagnostics**: connector status now reports the MCP endpoint,
504
+ initialization state, and last MCP initialization error.
505
+
506
+ ### 0.1.70
507
+
508
+ - **Linux menu debug log fix**: key-debug logging now writes under the user's
509
+ Claude Any config directory instead of global `/tmp`, avoiding permission
510
+ crashes on locked-down Linux systems.
511
+ - **Best-effort key logging**: menu input no longer fails if the optional
512
+ key-debug log cannot be written.
513
+
498
514
  ### 0.1.69
499
515
 
500
516
  - **Realtime channel bridge**: added `/ca/channel/messages`, `/ca/channel/wait`,
package/claude_any.py CHANGED
@@ -51,6 +51,7 @@ CONTEXT_USAGE_PATH = CONFIG_DIR / "context-usage.json"
51
51
  OLLAMA_MODEL_CATALOG_PATH = CONFIG_DIR / "ollama-model-catalog.json"
52
52
  CHAT_MESSAGES_PATH = CONFIG_DIR / "chat-messages.jsonl"
53
53
  CHAT_FILES_DIR = CONFIG_DIR / "chat-files"
54
+ MENU_KEY_DEBUG_PATH = CONFIG_DIR / "ca-key-debug.log"
54
55
  PLAN_ARTIFACTS_DIR = CONFIG_DIR / "plan-artifacts"
55
56
  PID_PATH = CONFIG_DIR / "router.pid"
56
57
  MODEL_LIST_CACHE_PATH = CONFIG_DIR / "model-list-cache.json"
@@ -95,7 +96,7 @@ PROVIDER_LABELS = {
95
96
  "self-hosted-nim": "Self Hosted NIM",
96
97
  }
97
98
  APP_NAME = "Claude Any"
98
- VERSION = "0.1.69"
99
+ VERSION = "0.1.71"
99
100
  CREDITS = "Credits: One Ciel LLC"
100
101
 
101
102
  LOG_LEVELS = {"SILENT": 0, "ERROR": 1, "WARN": 2, "INFO": 3, "DEBUG": 4, "TRACE": 5}
@@ -4337,6 +4338,9 @@ def _channel_sse_status_public(name: str, state: dict[str, Any]) -> dict[str, An
4337
4338
  "messages_received": int(state.get("messages_received") or 0),
4338
4339
  "event_filter": state.get("event_filter") or [],
4339
4340
  "read_timeout_seconds": state.get("read_timeout_seconds"),
4341
+ "mcp_endpoint": state.get("mcp_endpoint"),
4342
+ "mcp_initialized": bool(state.get("mcp_initialized")),
4343
+ "mcp_last_error": state.get("mcp_last_error"),
4340
4344
  "last_error": state.get("last_error"),
4341
4345
  }
4342
4346
 
@@ -4401,8 +4405,78 @@ def _sse_payload_to_chat_payload(data_text: str, event_name: str, defaults: dict
4401
4405
  }
4402
4406
 
4403
4407
 
4408
+ def _channel_sse_set_state(name: str, **updates: Any) -> None:
4409
+ with _CHANNEL_SSE_LOCK:
4410
+ state = _CHANNEL_SSE_CONNECTIONS.get(name)
4411
+ if state:
4412
+ state.update(updates)
4413
+
4414
+
4415
+ def _channel_sse_absolute_endpoint(stream_url: str, endpoint: str) -> str:
4416
+ endpoint = (endpoint or "").strip()
4417
+ if endpoint.startswith(("http://", "https://")):
4418
+ return endpoint
4419
+ return urllib.parse.urljoin(stream_url, endpoint)
4420
+
4421
+
4422
+ def _mcp_sse_post_json(endpoint: str, headers: dict[str, str], payload: dict[str, Any], timeout: float) -> Any:
4423
+ request_headers = {**headers, "Content-Type": "application/json", "Accept": "application/json, text/event-stream"}
4424
+ req = urllib.request.Request(
4425
+ endpoint,
4426
+ data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
4427
+ headers=request_headers,
4428
+ method="POST",
4429
+ )
4430
+ with urllib.request.urlopen(req, timeout=timeout) as response:
4431
+ data = response.read()
4432
+ if not data:
4433
+ return None
4434
+ try:
4435
+ return json.loads(data.decode("utf-8"))
4436
+ except Exception:
4437
+ return data.decode("utf-8", errors="replace")
4438
+
4439
+
4440
+ def _channel_sse_maybe_initialize_mcp(name: str, endpoint_text: str) -> None:
4441
+ with _CHANNEL_SSE_LOCK:
4442
+ state = _CHANNEL_SSE_CONNECTIONS.get(name)
4443
+ if not state:
4444
+ return
4445
+ if not bool(state.get("mcp_enabled", True)):
4446
+ return
4447
+ if state.get("mcp_initialized"):
4448
+ return
4449
+ stream_url = str(state.get("url") or "")
4450
+ headers = dict(state.get("headers") or {})
4451
+ timeout = max(5.0, min(120.0, float(state.get("mcp_timeout_seconds") or 20.0)))
4452
+ protocol_version = str(state.get("mcp_protocol_version") or "2024-11-05")
4453
+ endpoint = _channel_sse_absolute_endpoint(stream_url, endpoint_text)
4454
+ try:
4455
+ initialize = {
4456
+ "jsonrpc": "2.0",
4457
+ "id": 1,
4458
+ "method": "initialize",
4459
+ "params": {
4460
+ "protocolVersion": protocol_version,
4461
+ "capabilities": {},
4462
+ "clientInfo": {"name": "claude-any-channel-bridge", "version": VERSION},
4463
+ },
4464
+ }
4465
+ _mcp_sse_post_json(endpoint, headers, initialize, timeout)
4466
+ initialized = {"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}
4467
+ _mcp_sse_post_json(endpoint, headers, initialized, timeout)
4468
+ _channel_sse_set_state(name, mcp_endpoint=endpoint, mcp_initialized=True, mcp_last_error=None)
4469
+ router_log("INFO", f"channel_sse_mcp_initialized name={name} endpoint={endpoint}")
4470
+ except Exception as exc:
4471
+ _channel_sse_set_state(name, mcp_endpoint=endpoint, mcp_initialized=False, mcp_last_error=f"{type(exc).__name__}: {exc}")
4472
+ router_log("WARN", f"channel_sse_mcp_initialize_failed name={name} endpoint={endpoint} error={type(exc).__name__}: {exc}")
4473
+
4474
+
4404
4475
  def _channel_sse_dispatch(name: str, event_name: str, data_lines: list[str]) -> None:
4405
4476
  data_text = "\n".join(data_lines)
4477
+ if (event_name or "").strip().lower() == "endpoint":
4478
+ _channel_sse_maybe_initialize_mcp(name, data_text)
4479
+ return
4406
4480
  with _CHANNEL_SSE_LOCK:
4407
4481
  state = _CHANNEL_SSE_CONNECTIONS.get(name)
4408
4482
  if not state:
@@ -4510,6 +4584,12 @@ def start_channel_sse_connection(config: dict[str, Any]) -> dict[str, Any]:
4510
4584
  "event_filter": event_filter,
4511
4585
  "read_timeout_seconds": float(config.get("read_timeout_seconds") or config.get("timeout") or 300.0),
4512
4586
  "retry_seconds": float(config.get("retry_seconds") or 5.0),
4587
+ "mcp_enabled": bool(config.get("mcp", config.get("mcp_enabled", True))),
4588
+ "mcp_endpoint": None,
4589
+ "mcp_initialized": False,
4590
+ "mcp_last_error": None,
4591
+ "mcp_protocol_version": str(config.get("mcp_protocol_version") or "2024-11-05"),
4592
+ "mcp_timeout_seconds": float(config.get("mcp_timeout_seconds") or 20.0),
4513
4593
  }
4514
4594
  _CHANNEL_SSE_CONNECTIONS[name] = state
4515
4595
  thread = threading.Thread(target=_channel_sse_worker, args=(name,), daemon=True, name=f"claude-any-channel-sse-{name}")
@@ -11693,6 +11773,15 @@ def print_intro_panel(width: int) -> None:
11693
11773
  print("\n".join(intro_panel_lines(width)))
11694
11774
 
11695
11775
 
11776
+ def append_menu_key_debug_log(line: str) -> None:
11777
+ try:
11778
+ MENU_KEY_DEBUG_PATH.parent.mkdir(parents=True, exist_ok=True)
11779
+ with MENU_KEY_DEBUG_PATH.open("a", encoding="utf-8") as f:
11780
+ f.write(line)
11781
+ except OSError:
11782
+ pass
11783
+
11784
+
11696
11785
  def read_menu_key(fd: int | None = None) -> str:
11697
11786
  if os.name == "nt":
11698
11787
  import msvcrt
@@ -11707,7 +11796,6 @@ def read_menu_key(fd: int | None = None) -> str:
11707
11796
  return ch.lower()
11708
11797
 
11709
11798
  import time
11710
- debug_path = "/tmp/ca-key-debug.log"
11711
11799
  if fd is None or fd < 0:
11712
11800
  fd = sys.stdin.fileno()
11713
11801
  ch = os.read(fd, 1)
@@ -11717,8 +11805,7 @@ def read_menu_key(fd: int | None = None) -> str:
11717
11805
  b = os.read(fd, 1)
11718
11806
  log += f" next={b!r}"
11719
11807
  if not b:
11720
- with open(debug_path, "a", encoding="utf-8") as f:
11721
- f.write(log + " result='esc'\n")
11808
+ append_menu_key_debug_log(log + " result='esc'\n")
11722
11809
  return "esc"
11723
11810
  seq += b.decode("latin-1")
11724
11811
  if b == b"[":
@@ -11741,15 +11828,13 @@ def read_menu_key(fd: int | None = None) -> str:
11741
11828
  "\x1b[H": "home", "\x1b[F": "end",
11742
11829
  }.get(seq, "esc")
11743
11830
  log += f" seq={seq!r} result={result!r}"
11744
- with open(debug_path, "a", encoding="utf-8") as f:
11745
- f.write(log + "\n")
11831
+ append_menu_key_debug_log(log + "\n")
11746
11832
  return result
11747
11833
  if ch in (b"\r", b"\n"):
11748
11834
  result = "enter"
11749
11835
  else:
11750
11836
  result = ch.decode("latin-1").lower()
11751
- with open(debug_path, "a", encoding="utf-8") as f:
11752
- f.write(log + f" result={result!r}\n")
11837
+ append_menu_key_debug_log(log + f" result={result!r}\n")
11753
11838
  return result
11754
11839
 
11755
11840
 
package/docs/README.ja.md CHANGED
@@ -61,7 +61,7 @@ vLLM、NVIDIA hosted、self-hosted NIM を選択し、通常の Claude Code 引
61
61
 
62
62
  Credits: One Ciel LLC
63
63
 
64
- 現在のバージョン: `0.1.69`
64
+ 現在のバージョン: `0.1.71`
65
65
 
66
66
  ## 作られた理由
67
67
 
@@ -365,6 +365,22 @@ Windows/Linux 管理、クリーンアップスクリプト、定期的なセキ
365
365
 
366
366
  ## 変更履歴
367
367
 
368
+ ### 0.1.71
369
+
370
+ - **MCP SSE channel 初期化**: channel bridge は MCP `endpoint` event を受けると
371
+ `initialize` と `notifications/initialized` を自動送信し、AI-Net 型 push
372
+ notification が Claude Any に流れ始めるようになりました。
373
+ - **Channel SSE 診断情報**: connector status に MCP endpoint、初期化状態、
374
+ 最後の MCP 初期化エラーを表示します。
375
+
376
+ ### 0.1.70
377
+
378
+ - **Linux menu debug log 修正**: key-debug log は global `/tmp` ではなく
379
+ user の Claude Any config directory に書き込むようになり、制限された Linux
380
+ 環境での permission crash を避けます。
381
+ - **best-effort key logging**: 任意の key-debug log を書けない場合でも menu
382
+ input は失敗しません。
383
+
368
384
  ### 0.1.69
369
385
 
370
386
  - **リアルタイム channel bridge**: `/ca/channel/messages`, `/ca/channel/wait`,
package/docs/README.ko.md CHANGED
@@ -67,7 +67,7 @@ NVIDIA hosted, self-hosted NIM을 선택하고, Claude Code의 일반 인자는
67
67
 
68
68
  Credits: One Ciel LLC
69
69
 
70
- 현재 버전: `0.1.69`
70
+ 현재 버전: `0.1.71`
71
71
 
72
72
  ## 왜 만들었나
73
73
 
@@ -371,6 +371,22 @@ Windows 이벤트 로그 리뷰, 바이러스/랜섬웨어 침입 시도 정리,
371
371
 
372
372
  ## 변경 이력
373
373
 
374
+ ### 0.1.71
375
+
376
+ - **MCP SSE channel 초기화**: channel bridge가 MCP `endpoint` 이벤트를 받으면
377
+ `initialize`와 `notifications/initialized`를 자동 전송하므로, AI-Net 스타일
378
+ push notification이 Claude Any로 흐를 수 있습니다.
379
+ - **Channel SSE 진단 정보**: connector 상태에 MCP endpoint, 초기화 여부, 마지막
380
+ MCP 초기화 오류를 표시합니다.
381
+
382
+ ### 0.1.70
383
+
384
+ - **Linux 메뉴 디버그 로그 수정**: key-debug 로그를 전역 `/tmp`가 아니라 사용자
385
+ Claude Any config 디렉터리 아래에 기록해, 제한된 Linux 환경에서 permission
386
+ crash가 발생하지 않도록 했습니다.
387
+ - **best-effort key logging**: 선택적 key-debug 로그를 쓸 수 없어도 메뉴 입력이
388
+ 실패하지 않습니다.
389
+
374
390
  ### 0.1.69
375
391
 
376
392
  - **실시간 채널 브리지**: `/ca/channel/messages`, `/ca/channel/wait`,
package/docs/README.zh.md CHANGED
@@ -61,7 +61,7 @@ NIM,并把普通 Claude Code 参数原样传递。
61
61
 
62
62
  Credits: One Ciel LLC
63
63
 
64
- 当前版本: `0.1.69`
64
+ 当前版本: `0.1.71`
65
65
 
66
66
  ## 为什么存在
67
67
 
@@ -351,6 +351,20 @@ Hermes 格式模型或部分较旧的 Qwen tool template。
351
351
 
352
352
  ## 更新日志
353
353
 
354
+ ### 0.1.71
355
+
356
+ - **MCP SSE channel 初始化**:channel bridge 收到 MCP `endpoint` 事件后会自动发送
357
+ `initialize` 与 `notifications/initialized`,让 AI-Net 风格的 push
358
+ notification 可以流入 Claude Any。
359
+ - **Channel SSE 诊断信息**:connector status 现在会显示 MCP endpoint、初始化状态
360
+ 以及最后一次 MCP 初始化错误。
361
+
362
+ ### 0.1.70
363
+
364
+ - **Linux 菜单调试日志修复**:key-debug 日志现在写入用户的 Claude Any config
365
+ 目录,而不是全局 `/tmp`,避免受限 Linux 环境中的 permission crash。
366
+ - **best-effort key logging**:即使可选 key-debug 日志无法写入,菜单输入也不会失败。
367
+
354
368
  ### 0.1.69
355
369
 
356
370
  - **实时 channel bridge**:新增 `/ca/channel/messages`、`/ca/channel/wait`、
package/docs/manual.md CHANGED
@@ -10,7 +10,7 @@ Code starts, while passing normal Claude Code arguments through unchanged.
10
10
 
11
11
  Credits: One Ciel LLC
12
12
 
13
- Current version: `0.1.69`
13
+ Current version: `0.1.71`
14
14
 
15
15
  ## Install
16
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneciel-ai/claude-any",
3
- "version": "0.1.69",
3
+ "version": "0.1.71",
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",