# Remote Cli **Repository Path**: sunshinewithmoonlight/remote-cli ## Basic Information - **Project Name**: Remote Cli - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-02-28 - **Last Updated**: 2026-06-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # remote-cli `remote-cli` 是一个把飞书机器人接到本机 AI 运行时的常驻服务。它可以把飞书消息送入 Codex 或 Claude Code,把回复实时回写到飞书;也可以通过远端 Agent 控制另一台可信设备,执行命令和传输文件。 如果你只想快速跑起来,看这份 README 就够了。完整配置字段可参考仓库内的 [remotecli.example.yaml](remotecli.example.yaml)。 ## 文档边界 - 当前入口:本文件,覆盖构建、最小配置、远端 Agent 基本用法和日常运维。 - 完整配置示例:仓库内的 [remotecli.example.yaml](remotecli.example.yaml),列出所有可用字段和占位值,可直接复制后填入真实值。 - 架构与排障细节:[docs/architecture.md](docs/architecture.md),覆盖组件职责、远端 Agent 身份模型、安全边界和运维口径。 - 长版部署:[docs/quick-deploy.md](docs/quick-deploy.md),首次部署、配置规则、LaunchAgent 与日常运维。 ## 能做什么 - 飞书消息进入 Codex RPC 或 Claude Code 后端。 - 多个飞书 bot 可分别绑定不同后端和 `codex_home`。 - 回复默认以飞书交互式卡片回写,并持续 patch 当前回复。 - 支持 `/new` 开新会话、空闲自动续会话、可选历史恢复。 - 飞书附件可下载到本地运行时目录,并按配置决定是否立即处理。 - 支持 PaddleOCR:飞书图片可自动 OCR,本地图片/PDF 也可用 `remote-cli ocr --path` 手工识别。 - 支持系统任务:解析自然语言任务、安装为 macOS LaunchAgent、按时执行并回写飞书。 - 支持远端 Agent:可信设备主动连到 relay,控制端可 `list`、`exec`、`send-file`、`fetch-file`;Agent WebSocket 断线后会自动退避重连。 ## 依赖 - macOS 或类 Unix 环境。 - Go 1.23+。 - `codex` CLI;如果使用 Claude 后端,还需要 `claude` CLI。 - 可用的飞书应用凭证。 - 可选:Cloudflare Workers relay,用于远端 Agent。 ## 构建 ```bash make test make build-all make build-agent-release ``` 输出: ```text bin/remote-cli bin/remote-agent_darwin_arm64 bin/remote-agent_darwin_amd64 bin/remote-agent_linux_amd64 bin/remote-agent_linux_arm64 bin/remote-agent_windows_amd64.exe bin/remote-agent_windows_arm64.exe bin/remote-agent_windows_386_win7.exe bin/remote-agent_termux_aarch64 bin/remote-agent_SHA256SUMS.txt ``` `bin/remote-agent` 无架构构建已弃用,不再作为部署或 release 资产使用。 Windows 7 仅支持 `remote-agent_windows_386_win7.exe`,需要用 Go 1.20.x legacy toolchain 构建。 普通构建和 release 构建都输出到 `bin/`;项目不再使用 `dist/` 作为构建目录。 常用命令: ```bash ./bin/remote-cli --help ./bin/remote-cli agent --help ./bin/remote-cli ocr --help ./bin/remote-agent_darwin_arm64 --help ``` ## 快速开始 1. 生成配置: ```bash ./bin/remote-cli config ``` `setup` 是等价别名: ```bash ./bin/remote-cli setup ``` 2. 校验配置: ```bash ./bin/remote-cli --dry-run ``` 3. 前台启动: ```bash ./bin/remote-cli ``` 4. 检查健康: ```bash ./bin/remote-cli health curl -fsS http://127.0.0.1:6230/readyz ``` 5. 安装为 macOS 自启动服务: ```bash ./bin/remote-cli autorun ./bin/remote-cli status ./bin/remote-cli logs ``` 默认配置路径是: ```text ~/.runtime/remote-cli.yaml ``` 也可以显式指定: ```bash ./bin/remote-cli --config /path/to/remote-cli.yaml --dry-run ./bin/remote-cli autorun --config /path/to/remote-cli.yaml ``` ## 最小配置示例 ```yaml port: 6230 codex_full_access: true claude_full_access: true main_chat_history_auto_resume: true main_chat_auto_renew_idle_timeout_h: 24 main_chat_auto_compact_idle_timeout_h: 0 feishu-api: timeout_s: 8 upload_timeout_s: 120 immediately-process: image: true file: false audio: true media: false paddle-OCR: status: false access-token: "[REDACTED_PADDLEOCR_TOKEN]" base-url: https://paddleocr.aistudio-app.com model: PaddleOCR-VL-1.6 request-timeout-s: 300 poll-timeout-s: 600 max-result-chars: 12000 audio-doubao-STT: status: false app-id: your-doubao-app-id access-token: "[REDACTED_DOUBAO_TOKEN]" bots: - bot-type: feishu backend: codex codex_home: "" id: cli_xxx secret: "[REDACTED_FEISHU_SECRET]" schedule: system_tasks_root: /absolute/path/for/system-tasks ``` 切到 Claude Code 后端: ```yaml claude-code: command: claude permission_mode: default include_partial_messages: true bots: - bot-type: feishu backend: claude id: cli_xxx secret: "[REDACTED_FEISHU_SECRET]" ``` ## OCR 启用 `paddle-OCR.status: true` 并配置 `access-token` 后,飞书 `image` 附件可在立即处理时先识别为文本;同一配置也可直接用于本地文件: ```bash ./bin/remote-cli ocr --path /absolute/path/to/photo.jfif ./bin/remote-cli ocr --path /absolute/path/to/report.pdf ./bin/remote-cli ocr --path /tmp/a.jfif --path /tmp/b.png ``` `ocr` 支持本地图片/PDF,`--path` 可重复。`.jfif` 等上传端不直接接受的图片会按文件头临时规范化为受支持扩展名后提交,不改动原文件。 ## 远端 Agent 远端 Agent 适合控制自己的可信设备。Agent 不开放公网入站端口,而是主动连出到 relay;`remote-cli` 控制端也主动连到 relay。公网链路按不可信处理,需要 relay key、relay 生成的在线身份、控制端本机权限、受限权限配置、审计日志和危险命令开关共同约束;飞书 sender 不再作为 remote-agent 授权边界。 Remote Agent 不暴露飞书 `/ra` 聊天命令。飞书用户只发送自然语言请求,例如: - "列出在线远程设备" - "让 Mac mini 执行 pwd" - "把这个文件发到远程 Mac 的 Downloads" 是否调用远程控制能力由后端 Agent/LLM 决定。后端和本地运维都通过 `remote-cli agent` CLI 调用控制能力。 推荐使用 `--url-key-env REMOTE_AGENT_RELAY_KEY` 从环境变量读取受控端 key,避免真实 key 出现在进程参数中。`--url-key` 参数名保留用于兼容,但它表示部署级 agent relay key,不是由飞书聊天创建的一次性 URL key。真实 key 必须通过 Worker secret、系统服务环境变量或受限权限环境文件注入,不写入 YAML、日志或文档。 控制端配置示例: ```yaml remote-agent: enabled: true server-relay: cloudflare-workers-url: "wss://relay.example.com/" key: "control-relay-key-here" ``` `heartbeat_interval_s`、`request_timeout_s`、`command_timeout_s` 和 `access` 节点已弃用;命令默认无限等待,需要单次限时时使用 `remote-cli agent --timeout --exec ...`。 `remote-agent.server-relay.key` 是 control relay key 明文。它只应写入本机受限权限的运行时 YAML,例如 `~/.runtime/remote-cli.yaml`;不要把真实 key 写入仓库示例、日志或 release 资产。 `remote-agent.server-relay.cloudflare-workers-url` 推荐填写 relay 根 URL,例如 `wss://relay.example.com/`。程序会自动补齐为控制端 WebSocket 路径 `/control/ws`;被控端 `remote-agent --url` 仍自动补齐到 `/agent/ws`。 被控设备启动 Agent: ```bash ./bin/remote-agent_darwin_arm64 relay.example.com ./bin/remote-agent_darwin_arm64 \ -u relay.example.com \ -k \ --hint "Mac mini at home" ./bin/remote-agent_darwin_arm64 \ --url relay.example.com \ --url-key-env REMOTE_AGENT_RELAY_KEY \ --hint "Mac mini at home" ``` 前两种会让 key 出现在进程 argv 中,只适合本机临时启动或受控环境;长期服务仍推荐 `--url-key-env REMOTE_AGENT_RELAY_KEY`。将示例中的二进制替换为目标设备对应的显式平台资产;Windows 7 使用 `remote-agent_windows_386_win7.exe`。 `remote-agent --url` 可以只填写 relay host,例如 `relay.example.com`。程序会自动补齐为 `wss://relay.example.com/agent/ws`。仍兼容显式填写 `wss://relay.example.com/agent/ws`;不要把被控端指向 `/control/ws`。 Android/Termux note: `remote-agent` always uses `/system/bin/sh -c` as the direct child process on `GOOS=android`. This avoids Android/HarmonyOS cases where Go reports `os.Executable()` and `/proc/self/exe` as `/apex/com.android.runtime/bin/linker64`, and direct `fork/exec` of Termux private shells such as `/data/data/com.termux/files/usr/bin/fish` or `sh` can fail with `permission denied`. The existing `PATH` is preserved, so commands can still resolve Termux tools. Windows 桌面与会话(desktop 诊断): Windows `remote-agent` 在 `agent_hello` 中上报 `desktop` 字段,控制端可在 `remote-cli agent --list --json` 一眼看到当前会话状态,无需先截图失败再反查: - 从当前用户 PowerShell/CMD 启动:`desktop.attached=true`、`interactive=true`、`session_id == active_session_id`、`run_as` 为当前用户,可截图/剪贴板/GUI 自动化。 - 从用户 `AtLogon + InteractiveToken` 计划任务启动:同样 attach 用户桌面。 - 从 SYSTEM 服务或「不管用户是否登录都运行」的计划任务启动:`desktop.attached=false` 是预期诊断,不能截图、剪贴板或 GUI 自动化;`remote-cli agent` 文本列表会显示 `desktop=detached session=0 ... reason=...`。 启动 Windows 交互 agent(relay key 只走环境变量,不落 argv): ```powershell $env:REMOTE_AGENT_RELAY_KEY = "[REDACTED_SECRET]" .\remote-agent_windows_amd64.exe --url relay.cshine.top --url-key-env REMOTE_AGENT_RELAY_KEY --hint "$env:COMPUTERNAME" ``` 不要把真实 relay key 写入文档、日志或脚本;需要持久化时由 `--autorun install --persist-current-key` 写入仅当前用户可读的受限 env 文件。 跨平台 autorun(远程安装/查询/卸载 agent 自启动): `remote-cli agent --autorun` 让控制端远程管理目标 agent 的开机自启;具体安装由 agent 侧按平台执行(Windows 计划任务、macOS launchd、Linux systemd user service、OpenWrt procd、Termux:Boot best-effort),控制端只透传请求和结果。 ```bash # 查询当前自启动状态(含 desktop/interactive 诊断) ./bin/remote-cli agent --uid agt_xxx --autorun status --json # 安装用户态自启动并持久化当前 relay key(Windows 下这是能访问桌面的唯一默认路径) ./bin/remote-cli agent --uid agt_xxx --autorun install --mode user --persist-current-key --json # 卸载 ./bin/remote-cli agent --uid agt_xxx --autorun uninstall --json ``` Windows SYSTEM/Session 0 agent 请求 `--mode user` 安装会失败并返回 `requires interactive user session; current process is Session 0`;正确迁移路径是在 Administrator 交互桌面手动启动新 agent,再对其执行 install,最后停用旧 SYSTEM 任务。 OpenWrt root 环境使用 `/etc/init.d/remote-agent` + `/etc/remote-agent.env` 的 procd 自启动;Termux 会写入 `$HOME/.termux/boot/remote-agent.sh`,但真实开机自启仍依赖已安装 Termux:Boot。 受控端认证和身份分离: - `REMOTE_AGENT_RELAY_KEY` 只证明受控端允许接入 `/agent/ws`。 - `remote-agent` 不生成、不保存、不发送 `instance_id`。 - Worker relay 在 agent WebSocket 接入时生成 `instance_id`,派生当前在线连接的 `agent_id`。 - `remote-cli agent --json` 从 `agent_list` 中读取 `agent_id` / `instance_id`;后续控制命令仍使用 `agent_id`。 - 如果未传 `--hint`,`remote-agent` 会默认使用本机 hostname 作为展示名称;`--hint` 仍可显式覆盖该默认值。 - `hint` 只用于展示和调试,不参与认证、`agent_id` 或 `instance_id` 生成,也不作为稳定身份。 控制端 CLI: ```bash ./bin/remote-cli agent --list --json # zsh/bash/fish: 单引号让本机 shell 把整段内容作为一个 argv 值传给 remote-cli。 ./bin/remote-cli agent --uid agt_xxx --exec 'pwd && uname -m' --json # Windows target 默认走 PowerShell,不再隐式经过 cmd.exe /C。 # 建议在 --exec 内容里显式声明目标 shell,方便阅读和排错。 remote-cli.exe agent --uid agt_xxx --exec 'powershell -NoProfile -Command "Write-Output ''hello''; $PSVersionTable.PSVersion"' --json # 需要 cmd 内建命令或 cmd 语法时,显式从 PowerShell 环境中调用 cmd.exe /C。 remote-cli.exe agent --uid agt_xxx --exec 'cmd.exe /C ver' --json # 不带 cmd.exe /C 或 powershell -Command 前缀时,命令内容仍按 PowerShell 脚本直接执行。 remote-cli.exe agent --uid agt_xxx --exec 'Write-Output "hello"; $PSVersionTable.PSVersion' --json # Windows target 复杂命令推荐 --exec-from:文件内容默认写 PowerShell 脚本正文。 # --exec-from: 直接读取 control 本机纯文本文件中的完整命令。 # 文件内容不会经过本地 shell 的命令行解析,适合包含大量引号、管道、&&、$() 等复杂命令。 # 推荐使用系统临时目录,并在执行后删除。 cmd_file="$(mktemp /tmp/remote-agent-command.XXXXXX.ps1)" chmod 600 "$cmd_file" cat > "$cmd_file" <<'PWSH' $ErrorActionPreference = 'Stop' Write-Output "BEGIN" Get-CimInstance Win32_Process -Filter "name='remote-agent.exe'" | Select-Object -First 1 -ExpandProperty ExecutablePath Write-Output "END" PWSH ./bin/remote-cli agent --uid "$AGENT_ID" --exec-from "$cmd_file" --json rm -f "$cmd_file" ./bin/remote-cli agent --uid agt_xxx --send-file ./local.txt --remote-path ~/Downloads/local.txt --json ./bin/remote-cli agent --uid agt_xxx --fetch-file ~/Downloads/local.txt --output /tmp/local.txt --json ``` `--exec` 的参数在 remote-cli 内部按不透明字符串处理,不会再按空格拆分或重新解释。 base64 传输从 remote-cli 已经拿到完整 argv 值之后开始生效:control 发 `command_b64`, agent 返回 `stdout_b64` / `stderr_b64` / `command_b64`。在 remote-cli 进程启动之前, 本机 shell 仍会先把用户输入转换成 argv;文档示例只用于保证 `--exec` 在 argv 中是用户预期的一个完整字符串。 `--json` 模式下,长命令有进度时会先输出一行或多行 `command_output` JSON,最后再输出一行 `command_result` JSON。 ## 系统任务 标准链路: ```bash ./bin/remote-cli task resolve --request '明天上午 9:30 给当前会话发送提醒' --json ./bin/remote-cli task create --task-dir /path/to/task_dir --json ``` `task resolve` 负责自然语言解析和草稿目录生成;`task create` 负责安装为系统任务。任务的真实状态以 bundle 文件和对应 LaunchAgent 为准。 ## 日常运维 ```bash ./bin/remote-cli start ./bin/remote-cli restart ./bin/remote-cli stop ./bin/remote-cli status ./bin/remote-cli logs ./bin/remote-cli service paths ``` 健康检查优先看: ```bash ./bin/remote-cli health curl -fsS http://127.0.0.1:6230/livez curl -fsS http://127.0.0.1:6230/readyz ``` 不要只用 pid、旧 tmux session 或历史 helper script 判断服务是否可用。 ## 本地调试 注入一条模拟飞书入站消息: ```bash ./bin/remote-cli inject-feishu-text --text "请回复 pong" ``` 发送飞书消息: ```bash ./bin/remote-cli send-feishu-text --text "hello" ./bin/remote-cli send-feishu-message --msg-type file --local-file /absolute/path/report.pdf --file-type stream ``` 常用日志: ```text /tmp/remote-cli/remote-cli.log /tmp/remote-cli/remote-cli.error.log /tmp/remote-cli/remote-cli.debug.log ``` ## 更多文档 - [remotecli.example.yaml](remotecli.example.yaml):完整配置字段示例,可直接复制后填入真实值。 - [docs/architecture.md](docs/architecture.md):架构、远端 Agent、安全边界和排障。 - [docs/quick-deploy.md](docs/quick-deploy.md):长版部署手册。