remote-claude 0.1.5 → 0.1.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-claude",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "双端共享 Claude CLI 工具",
5
5
  "bin": {
6
6
  "remote-claude": "bin/remote-claude",
package/remote_claude.py CHANGED
@@ -30,7 +30,8 @@ from utils.session import (
30
30
  list_active_sessions, is_session_active, cleanup_session,
31
31
  is_lark_running, get_lark_pid, get_lark_status, get_lark_pid_file,
32
32
  save_lark_status, cleanup_lark,
33
- USER_DATA_DIR, ensure_user_data_dir, get_lark_log_file
33
+ USER_DATA_DIR, ensure_user_data_dir, get_lark_log_file,
34
+ get_env_snapshot_path
34
35
  )
35
36
 
36
37
 
@@ -56,6 +57,15 @@ def cmd_start(args):
56
57
 
57
58
  ensure_socket_dir()
58
59
 
60
+ # 将当前 shell 的完整环境变量保存到快照文件(权限 0600 防止密钥泄露)
61
+ # tmux new-session 继承的是 tmux 服务器的全局环境,而非调用方 shell 的环境,
62
+ # 通过快照文件将完整环境传递给 server.py 的 _start_pty()
63
+ import json
64
+ env_snapshot_path = get_env_snapshot_path(session_name)
65
+ env_fd = os.open(str(env_snapshot_path), os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
66
+ with os.fdopen(env_fd, 'w') as f:
67
+ json.dump(dict(os.environ), f)
68
+
59
69
  # 构建 server 命令
60
70
  server_script = SCRIPT_DIR / "server" / "server.py"
61
71
  claude_args = args.claude_args if args.claude_args else []
package/server/server.py CHANGED
@@ -606,9 +606,32 @@ class ProxyServer:
606
606
 
607
607
  def _start_pty(self):
608
608
  """启动 PTY 并运行 Claude"""
609
- pid, fd = pty.fork()
609
+ # 加载环境变量快照(从 cmd_start 保存的快照文件恢复调用方 shell 的完整环境)
610
+ from utils.session import get_env_snapshot_path
611
+ import json as _json
612
+ env_snapshot_path = get_env_snapshot_path(self.session_name)
613
+ _extra_env = {}
614
+ try:
615
+ with open(env_snapshot_path) as _f:
616
+ _extra_env = _json.load(_f)
617
+ except Exception:
618
+ pass
619
+
620
+ try:
621
+ pid, fd = pty.fork()
622
+ except OSError:
623
+ env_snapshot_path.unlink(missing_ok=True)
624
+ raise
610
625
 
611
626
  if pid == 0:
627
+ # 子进程:恢复调用方 shell 的完整环境变量
628
+ for k, v in _extra_env.items():
629
+ os.environ[k] = v
630
+ # 环境已加载到内存,立即删除快照文件(execvp 前销毁)
631
+ try:
632
+ env_snapshot_path.unlink()
633
+ except Exception:
634
+ pass
612
635
  # 恢复 TERM 以支持 kitty keyboard protocol(Shift+Enter 等扩展键)
613
636
  # tmux 会将 TERM 改为 tmux-256color,导致 Claude CLI 不启用 kitty protocol
614
637
  os.environ['TERM'] = 'xterm-256color'
@@ -616,6 +639,7 @@ class ProxyServer:
616
639
  for key in ('TMUX', 'TMUX_PANE'):
617
640
  os.environ.pop(key, None)
618
641
  os.execvp("claude", ["claude"] + self.claude_args)
642
+ os._exit(1) # execvp 失败时兜底退出
619
643
  else:
620
644
  # 父进程
621
645
  self.master_fd = fd
package/utils/session.py CHANGED
@@ -60,6 +60,11 @@ def get_mq_path(session_name: str) -> Path:
60
60
  return SOCKET_DIR / f"{_safe_filename(session_name)}.mq"
61
61
 
62
62
 
63
+ def get_env_snapshot_path(session_name: str) -> Path:
64
+ """获取环境变量快照文件路径(cmd_start 写入,_start_pty 读取后删除)"""
65
+ return SOCKET_DIR / f"{_safe_filename(session_name)}_env.json"
66
+
67
+
63
68
  def ensure_socket_dir():
64
69
  """确保 socket 目录存在"""
65
70
  SOCKET_DIR.mkdir(parents=True, exist_ok=True)
@@ -248,6 +253,7 @@ def cleanup_session(session_name: str):
248
253
  sock_path.unlink(missing_ok=True)
249
254
  pid_file.unlink(missing_ok=True)
250
255
  get_mq_path(session_name).unlink(missing_ok=True)
256
+ get_env_snapshot_path(session_name).unlink(missing_ok=True)
251
257
 
252
258
 
253
259
  def is_session_active(session_name: str) -> bool: