toc-ocra
v0.2.31
Published
Echo device agent: local CLI execution service plus its desktop plugin (heartbeat + long-poll, headless CLIs)
Readme
toc-ocra
运行在用户电脑上的 CLI 执行端。它接收 echo_admin 派发的任务,在本机以无界面模式运行 codex / claude / kiro / grok / gemini / opencode 等 CLI,并把运行状态和结果报回服务端。它也可以在设备开启相应开关后执行脚本和 SQL(SQL 执行器目前是预留接口)。
参照 Orca 和 api/api_ocra 重构而来;api_ocra 保持原样不动。
快速开始(本地开发)
npm install
npm run build
# 1. 在 Echo 的「设备」页,打开设备的「连接与 CLI」,点「生成配对码」
# 2. 在这台电脑上配对(默认后端 http://127.0.0.1:3000)
node dist/src/index.js enroll --code ABCD-EFGH
# 3. 启动
node dist/src/index.js run全局安装后命令是 toc-ocra:toc-ocra setup --code … --server …(配对 + 安装后台服务,一步完成)、toc-ocra enroll --code …、toc-ocra run、toc-ocra service:install(安装为后台服务)。
其它命令:toc-ocra code(查看插件连接码)、toc-ocra detect(本机 CLI 探测)、toc-ocra doctor(配置 + 探测)、toc-ocra version。
桌面插件「设备代理」
同一个 npm 包也是 Echo 桌面插件 echo.device-agent(package.json › tocPlugin,界面源码在 plugin/,构建产物 dist/plugin/renderer.js)。页面分三个页签:
本机(一键启用 / 关闭)
- 打开「本机设备代理」开关:桌面端用自带的 Node 运行唯一 npm 全局安装里的
dist/service/agent.mjs(tocPlugin.entries.service,权限service:local),不需要终端,也不需要另装 Node。 - 桌面端给这次启动生成令牌(
TOC_PLUGIN_SERVICE_TOKEN)并交给插件,插件直接用它访问本机控制接口,不再输入 6 位连接码,随后自动绑定到当前登录的服务器。 - 设备代理跟随桌面端:开关保持打开时,下次打开桌面端自动启动;退出桌面端、关闭开关、禁用或卸载插件时停止。
- 这台电脑已有 toc-ocra 在运行(后台服务或终端启动)时,桌面端不会再启动第二个:开关直接显示「已启用」并连接已有实例(首次需输入连接码;此时开关不可操作,它不随桌面端退出而停止,停用请
toc-ocra service:uninstall)。若桌面端仍启动了实例,会因端口被占用退出(退出码 3),插件同样按已有实例处理,保证一台设备只有一个 Agent。 - 旧版桌面端没有这个能力时,插件仍显示终端命令:
npx toc-ocra@latest run,或npm i -g toc-ocra && toc-ocra service:install。
其他电脑(一条命令接入)
- 选择系统(Linux / macOS / Windows)和设备名,插件在当前工作空间创建设备、生成配对码,并给出一条命令,例如
npm install -g toc-ocra@latest && toc-ocra setup --code ABCD-EFGH --server https://echo.example.com(Windows PowerShell:npm install -g toc-ocra@latest; if ($?) { toc-ocra setup ... })。 toc-ocra setup= 配对 + 安装后台服务(macOS LaunchAgent / Linux systemd 用户服务 / Windows 计划任务),执行完设备即上线;插件轮询到新凭据且在线后显示「已匹配」。- 「接收任务」开关调用
PUT /api/devices/:id/enabled:关闭即停用,保留配对、不再派发任务,重新打开立即恢复,不需要操作那台电脑。彻底卸载在那台电脑执行toc-ocra service:uninstall。 - 服务器地址必须能被那台电脑访问,填
127.0.0.1/localhost时插件会提示。
TB Switch(跨设备切换已配置项)
- 在页面上方选择工作空间中的设备;插件会记住每个工作空间上次选择的设备。
- 选择 Codex、Claude Code 或 Gemini CLI,查看并切换该设备上已配置的供应商模式、供应商或默认路由。
- 只允许设备所有者或工作空间管理员修改;离线、未配对或已暂停的设备显示状态并禁用操作。插件不负责安装或编辑供应商与路由。
插件通过 http://127.0.0.1:17339 连接本机服务;手动启动的服务仍用 6 位连接码(toc-ocra code 查看)换取控制令牌。
本机控制接口(/control/*)只接受 127.0.0.1 / localhost 的 Host 和来源,除 info、pair 外都要 Authorization: Bearer <控制令牌>。控制令牌保存在数据目录的 control-token(0600),连接码在 connection-code(0600,使用后或连续输错 5 次后更换)。
发布:./publish-latest.sh(或 npm run publish:latest)。脚本会先校验 npm 身份,再构建、校验插件包;本地版本不高于 npm 上的版本时自动升一个补丁号,再发布到 npm 的 latest。可复用 npm login 的登录状态,也可在终端输入令牌,或通过环境变量 NPM_TOKEN 传入;显式传入的令牌仅写入临时认证文件,退出时删除,认证失败时不会继续构建和发布。管理员在「系统管理 › 插件目录」收录包名 toc-ocra 并批准版本后,用户即可在插件市场安装。
配置
Kiro CLI 模型与推理档位
本机登录 Kiro 后,代理从 kiro-cli chat --list-models --format json 读取当前账号的完整模型列表与默认模型,再通过 Kiro ACP 的原生 /effort 选项读取每个模型支持的档位。默认档位还会读取 ~/.kiro/settings/cli.json 的 chat.modelDefaults;修改该文件会触发重新上报。
后台服务会补充继承用户登录终端配置的 HTTP / HTTPS / SOCKS / NO_PROXY 环境,保持模型可见范围一致;后台进程已有的显式配置优先,代理值不写入诊断日志。
Echo 工位中选择“默认”并保存会清除 Echo 覆盖值。设备执行权限为完整权限时,无确认启动命令为:
kiro-cli chat --no-interactive --trust-all-tools --model gpt-5.6-luna --effort high -- 'test'受限权限仅信任 @doer/echo_report_task_progress。Kiro 的 doer MCP 配置需指向 Echo /mcp 并使用有效 Echo Access Token;CLI 登录与 MCP 凭证分别校验。
代理配置项
优先级:环境变量 > 配置文件(enroll 写入,权限 0600)> 默认值。
| 环境变量 | 配置文件键 | 默认 | 说明 |
|---|---|---|---|
| TOC_OCRA_SERVER_URL | serverUrl | http://127.0.0.1:3000 | echo_admin 地址 |
| TOC_OCRA_TOKEN | token | — | 设备凭据,配对时写入 |
| TOC_OCRA_ALLOWED_ROOTS | allowedRoots | 用户主目录 | CLI 可使用的工作目录根,PATH 风格列表 |
| TOC_OCRA_MAX_RUNS | maxConcurrentRuns | 4 | 本机同时运行的 CLI 回合上限 |
| TOC_OCRA_MAX_RUN_SECONDS | maxRunSeconds | 14400 | 单个回合最长时间,超时结束 |
| TOC_OCRA_DISABLE_SCRIPT / TOC_OCRA_DISABLE_SQL | disableScript / disableSql | false | 本机强制关闭脚本 / SQL(优先于服务端开关) |
| TOC_OCRA_DATA_DIR / TOC_OCRA_CONFIG | — | 见下 | 数据目录 / 配置文件路径 |
| TOC_OCRA_HEALTH_HOST / TOC_OCRA_HEALTH_PORT | healthHost / healthPort | 127.0.0.1 / 17339 | 本机状态页(仅本机可访问) |
| TOC_OCRA_LOG_LEVEL | logLevel | info | 诊断日志级别 |
| TOC_OCRA_CODEX_PATH 等 | — | 自动查找 | 指定某个 CLI 的可执行文件 |
数据目录:macOS ~/Library/Application Support/toc-ocra,Linux ~/.local/state/toc-ocra,Windows %APPDATA%\toc-ocra。与旧的 echo-cli-agent 互不影响,可以同时安装。
设计要点
- 不保持长连接:每 30 秒一次心跳,另有一个长轮询拉指令(有指令立即返回,最长等 25 秒)。超过 90 秒没有心跳,服务端判定设备离线。
- 一个回合一个进程,进程退出即完成:各 CLI 用无界面 JSON 模式运行,从输出中解析原生会话 ID 和最终回复。如果 CLI 已声明本轮结束、但进程 15 秒内没退出,会被结束,避免"做完了还占着工位"。
- 停止会结束整棵进程树:先对进程组和所有子孙进程发 SIGTERM,3 秒后仍存活的发 SIGKILL(Windows 用
taskkill /T /F)。 - 服务端对账兜底:心跳会上报本机正在运行的任务,服务端据此释放本机已经不存在的运行;Agent 崩溃重启时,会清理上次遗留的 CLI 进程。
- 加一个 CLI:在
src/providers/cli/新增一个文件,实现HeadlessProvider(启动参数 + 解析每一行输出),再在src/providers/registry.ts加一行。
看板附件
任务链附件在 CLI 启动前由本机代理下载到本次实际工作目录的 .echo/attachments/message-{message_id}/,完成大小与 SHA-256 校验后,提示词中的附件引用会替换为本机绝对路径。下载目录必须属于已允许的 CLI 工作目录,不能通过符号链接跳出;未配置设备默认目录或工位工作目录时会拒绝附件任务。每条消息最多 16 个附件,准备过程可取消、可复用已校验文件,最长等待 15 分钟。
窗口工位使用同机代理的 run.files.prepare 先下载文件,然后由服务端转发路径;同机设备代理必须在线。更新后的代理通过心跳声明 task_attachments.version=1,服务端会拒绝把附件任务发给不支持此协议的旧代理。请更新并重启设备代理与对应后端后使用。
下载文件暂时保留,可手工清理;.echo 不进入设备目录扫描,并带有仅作用于该内部目录的 Git 忽略规则。视频也可下载为文件,实际解析取决于 CLI 的能力。
终端 toc-ocra update 和 Echo 插件中心升级都会更新同一份 npm 全局安装,并在空闲时重启实际运行的 Agent。插件界面、后台服务和 toc-ocra --version 都读取该目录的真实版本;Echo 插件缓存只保留版本记录,不存放第二份包。桌面端每 5 秒读取当前版本,终端升级后会同步刷新。源码开发模式仍直接运行工作目录中的构建。
~/Library/Application Support/toc-ocra/installation/current.json 只记录唯一安装位置。macOS 本机保留 nvm 下的一份 toc-ocra;Homebrew 副本、共享程序副本和额外启动入口都不再使用。
从 0.2.25 起,一台电脑只允许一个主 Agent,任务链与聊天统一在该进程中处理。重复执行 toc-ocra run 会提示已有实例并退出;改变配置目录或健康端口不能绕过本机单实例锁。安装或升级会检查活动任务,等待旧服务退出后只启动一次;正常退出释放本机锁和服务器租约,崩溃后的服务器租约最多等待 90 秒再恢复。
CLI 聊天的流式文字保留空格、缩进和换行;内容清理使用独立于终端日志行的处理,避免把仅含空白的片段误变成空数据或破坏 Markdown 排版。
开发
npm run typecheck
npm test # 包含用假 codex 测试停止杀进程树、完成后进程不退出等场景