# 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-07-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # remote-cli `remote-cli` 是一个把飞书机器人接到本机 AI 运行时的常驻服务。它可以把飞书消息送入 Codex 或 Claude Code,把回复实时回写到飞书;也可以通过远端 Agent 控制另一台可信设备,执行命令和传输文件。 如果你只想快速跑起来,看这份 README 就够了。完整配置字段可参考仓库内的 [config.example.yaml](config.example.yaml)。 ## 文档边界 - 当前入口:本文件,覆盖构建、最小配置、远端 Agent 基本用法和日常运维。 - 完整配置示例:仓库内的 [config.example.yaml](config.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`。 - 回复默认以飞书交互式卡片回写;同一卡片的首个可见输出只启动刷新窗口,若随后出现第二个刷新请求则立即发送当时最新正文,否则约 `1s` 后兜底发送首个正文;后续同一卡片最多每秒 patch 一次,正文无变化时只保留 turn 完成的标题勾选更新。 - 支持 `/new` 开新会话、空闲自动续会话、可选 native 会话恢复,以及可选 completed turn 飞书历史注入。 - 飞书附件可下载到本地运行时目录,并按配置决定是否立即处理。 - 支持 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-cli update --dry-run ./bin/remote-agent_darwin_arm64 --help ./bin/remote-agent_darwin_arm64 update --dry-run ``` ## 快速开始 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 ``` `remote-cli autorun` 直接写入 LaunchAgent `ProgramArguments` 和 `EnvironmentVariables`,不会生成额外的 `remote-cli.env` 或 shell wrapper。 默认配置路径是: ```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 ``` ## 最小配置示例 ### Prompt recall CSV 服务启动时会严格校验 `prompt_recall_csv_path` 指向的 CSV;启动后会每 5 秒检测该文件的大小和修改时间。检测到变化后,remote-cli 会重新解析 CSV 并在成功后替换当前内存规则;如果新 CSV 无法解析,会保留上一份可用规则并写入服务日志,不会中断正在运行的服务。 `prompt_recall_csv_path` 默认为空,表示禁用。设置为 CSV 文件路径后,remote-cli 会跳过第一行表头,用后续数据行的第一列正则匹配原始飞书文本,命中后把第二列 callback memory 注入到本 turn 的当前用户请求块内,并以 `Remote-cli recalled context for this request:` 标明来源。第三列 `description` 只用于调试日志,不会注入模型。 CSV 第一行必须是 `RE表达式,回忆,描述`,后续数据行严格三列: ```csv "RE表达式","回忆","描述" "周报|日报","记住:输出使用正式公文风格,并包含进展、问题、计划。","日报周报格式" "(?i)project\\s+alpha","Project Alpha 的内部代号是 PA,回复时不要展开敏感简称。","Project Alpha recall" ``` 字段内包含逗号、双引号或换行时,按 CSV 规则用双引号包绕,字段内双引号写成两个双引号。 ```yaml port: 6230 codex_full_access: true claude_full_access: true main_chat_history_auto_resume: true main_chat_inject_completed_turn_history: false main_chat_completed_turn_history_session_idle_timeout_s: 0 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 # 0 keeps the complete OCR result; use a positive Unicode character limit only when needed. max-result-chars: 0 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 ``` 启用 `main_chat_inject_completed_turn_history` 后,连续飞书消息仍在同一 native Codex RPC session 内由连续 `turn/start` 处理,不会等待前一轮最终卡片送达。history 按 native logical turn 独立保存该轮用户 prompt 和每次成功 `SendCard`/`PatchCard` 的内容修订,只有最终卡成功送达后才 durable promote。`main_chat_completed_turn_history_session_idle_timeout_s: 0` 会在 promote 后、当前 native thread 的 start/active/final-card pending turn 全部排空时切换 session;正整数则从最终卡 ACK 后空闲指定秒数再切换,若 renew 或 compact 同时到期则它们优先。B rollover 保留 history 并刷新持久化 session epoch,使 renew 重新等待完整硬过期窗口。只有 fresh session 首轮会在当前请求边界前注入可见 completed-turn history;renew 清空 history,compact 保持 native replacement session 语义,`/new` 始终清空并抢占。 切到 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-agent 请求默认无限等待,需要单次限时时使用 `remote-cli agent --timeout ...`。该超时适用于 `--exec`、`--send-file`、`--fetch-file` 和 `--update`。 `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 --url-key-env REMOTE_AGENT_RELAY_KEY --hint "$env:COMPUTERNAME" ``` 不要把真实 relay key 写入文档、日志或脚本。`remote-cli agent --autorun install` 不再生成 `remote-agent.env`、`remote-agent-autorun.zsh`、`remote-agent-start.cmd` 或自写 keepalive 脚本;macOS 和 Windows 把当前 agent 连接参数直接写入 LaunchAgent / Scheduled Task 的命令,Termux 只写 Termux:Boot 必需脚本并直接内嵌 key,普通 Linux 只输出 Arch/Fedora systemd user 配置说明、不自动写文件,OpenWrt 不再自动写 procd/env。`--persist-current-key` 保留为兼容参数,不再表示“写 env 文件”。 安全提示:直接命令模式会让 relay key 出现在本机启动项配置中。该配置必须只保存在可信设备本机,不要提交到仓库、日志或截图;排障输出会使用 `[REDACTED_SECRET]`。 跨平台 autorun(远程安装/查询/卸载 agent 自启动): `remote-cli agent --autorun` 让控制端远程管理目标 agent 的开机自启;具体安装由 agent 侧按平台执行(Windows 计划任务、macOS launchd、Linux systemd user service 说明、Termux:Boot 脚本),控制端只透传请求和结果。 ```bash # 查询当前自启动状态(含 desktop/interactive 诊断与 instructions 说明) ./bin/remote-cli agent --uid agt_xxx --autorun status --json # 安装用户态自启动(直接把 --url/--url-key 嵌入系统启动项命令) ./bin/remote-cli agent --uid agt_xxx --autorun install --mode user --json # 卸载 ./bin/remote-cli agent --uid agt_xxx --autorun uninstall --json ``` 普通 Linux 的 install 返回 `installed=false` 和 `instructions`,给出手工 systemd user 单元配置步骤,不在目标机器写文件。OpenWrt 不再自动写 `/etc/init.d/remote-agent` 或 `/etc/remote-agent.env`。 agent 启动时会确保系统临时目录下存在 `remote-cli-agent`(macOS/Linux 多为 `/tmp/remote-cli-agent`),输出中会显示日志路径: ```text logs: /tmp/remote-cli-agent ``` ### 自更新 `remote-cli update` 会从 Gitee latest release 下载 `remote-cli` 资产,生成 `/tmp` 或系统临时目录下的更新脚本,备份当前二进制,替换后重启 LaunchAgent 或当前进程。 `remote-cli agent --uid --update` 会通过 control relay 请求目标 `remote-agent` 在自身进程内执行自更新,下载当前平台对应的显式资产,例如 `remote-agent_darwin_arm64` 或 `remote-agent_windows_amd64.exe`。如果 latest release 缺少该资产,命令会失败,不会下载源码 zip/tar.gz。 `remote-cli agent --uid --update --update-dry-run --json` 只准备并校验目标端更新脚本,不替换二进制。首次部署本功能时,旧 agent 尚不支持 `agent_update_request`,需要先用现有部署路径升级一次 agent;之后再用 `remote-cli agent --uid ... --update` 做后续升级。 本机 `remote-agent update` 作为兼容维护入口保留,常规远程升级以 `remote-cli agent --update` 为准。 受控端认证和身份分离: - `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 --timeout 120 --json ./bin/remote-cli agent --uid agt_xxx --fetch-file ~/Downloads/local.txt --output /tmp/local.txt --timeout 120 --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。 `remote-cli agent --timeout ` 是单次请求超时,适用于 `--exec`、`--send-file`、`--fetch-file` 和 `--update`;默认 `0` 表示无限等待。文件传输走 base64 分片 over WebSocket,公网链路不稳定或文件较大时建议显式设置足够大的 `--timeout`,例如 `120` 秒。 ## 系统任务 标准链路: ```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 ``` ## 更多文档 - [config.example.yaml](config.example.yaml):完整配置字段示例,可直接复制后填入真实值。 - [docs/architecture.md](docs/architecture.md):架构、远端 Agent、安全边界和排障。 - [docs/quick-deploy.md](docs/quick-deploy.md):长版部署手册。