NDJSON 接口协议规范 v1.0

August 7, 2026 · View on GitHub

编写日期: 2026-05-17 | 版本: 0.4.36

NDJSON 接口协议规范 v1.0

1. 概述

xlings interface 提供面向程序的结构化 API,使外部客户端(IDE 插件、CI 脚本、AI agent 等)可通过标准 IO 与 xlings 交互。协议版本为 1.0,基于 NDJSON(Newline-Delimited JSON)。

2. 传输层

方向通道格式
请求 / 控制stdin每行一个 JSON 对象
响应 / 事件stdout每行一个 JSON 对象
  • 每行以 \n 结尾,不含内嵌换行。
  • stderr 保留用于调试日志,客户端不应解析。
  • 编码固定为 UTF-8。

3. 会话启动

客户端通过命令行启动会话:

xlings interface [--version] [--list] [<capability> --args '<json>']

3.1 查询协议版本

xlings interface --version

服务端输出一行后退出:

{"protocol_version":"1.0"}

3.2 查询可用能力

xlings interface --list

服务端输出能力清单后退出:

{"protocol_version":"1.0","capabilities":[{"name":"install_packages","description":"...","destructive":true,"inputSchema":{...},"outputSchema":{...}}, ...]}

3.3 执行能力

xlings interface install_packages --args '{"targets":["gcc@14"],"yes":true}'

服务端进入事件流模式:持续向 stdout 输出事件行,直到发出 result 行后退出。

--args-file <path> 可替代 --args,从文件读取 JSON 参数(用于 Windows 引号转义问题)。

4. stdin 控制请求格式

会话执行期间,客户端可通过 stdin 发送控制指令:

{"action":"cancel"}
{"action":"pause"}
{"action":"resume"}
{"action":"prompt-reply","id":"<prompt-id>","value":"<answer>"}
action说明
cancel取消当前执行,能力将抛出 CancelledException
pause暂停执行
resume恢复执行
prompt-reply回复服务端发出的交互式提示

未识别的 action 会触发一条 kind: log(warn 级别)事件。

5. stdout 事件格式

每行为一个 JSON 对象,必含 "kind" 字段标识类型。

6. 事件类型

6.1 progress

报告任务进度。

{"kind":"progress","phase":"downloading","percent":42,"message":"gcc-14.2.0.tar.xz"}
字段类型说明
phasestring当前阶段标识
percentnumber0-100 整数,-1 表示不确定
messagestring人类可读描述

6.2 log

日志消息。

{"kind":"log","level":"info","message":"extracting archive..."}
字段类型说明
levelstringdebug / info / warn / error
messagestring日志内容

6.3 data

结构化数据载荷,用于返回查询结果等。

{"kind":"data","dataKind":"env","payload":{"xlingsHome":"/home/user/.xlings",...}}
字段类型说明
dataKindstring数据类别标识
payloadobject/string结构化数据;若原始 JSON 解析失败则为字符串

6.4 prompt

服务端向客户端请求用户输入。

{"kind":"prompt","id":"confirm-remove","question":"Remove gcc@14?","options":["yes","no"],"defaultValue":"no"}
字段类型说明
idstring提示 ID,回复时引用
questionstring提示问题
optionsarray可选项列表(可为空数组)
defaultValuestring默认值

客户端应通过 stdin 发送 {"action":"prompt-reply","id":"<id>","value":"<answer>"} 回复。

6.5 error

错误事件。不一定是终止性的——recoverable 指示能力是否仍在运行。

{"kind":"error","code":"E_NOT_FOUND","message":"unknown capability: foo","recoverable":false,"hint":"run `xlings interface --list`"}
字段类型说明
codestring错误码(见下表)
messagestring错误描述
recoverablebooleantrue 表示执行仍继续
hintstring?可选修复建议

错误码枚举:

code含义
E_INVALID_INPUT参数校验失败
E_NOT_FOUND目标不存在
E_NETWORK网络错误
E_DISK_FULL磁盘空间不足
E_PERMISSION权限不足
E_CANCELLED被用户取消
E_INTERNAL内部错误

6.6 result

终止行,标志会话结束。每次执行恰好输出一行。

{"kind":"result","exitCode":0,"data":{"installed":["gcc@14.2.0"]}}
字段类型说明
exitCodeinteger0 成功,非 0 失败,130 表示取消
dataobject?能力返回的结构化结果(可选)

6.7 heartbeat

空闲超过 5 秒时自动发出,表示进程仍存活。

{"kind":"heartbeat","ts":"2026-05-17T08:30:00Z"}

7. 支持的能力(Capabilities)

名称说明破坏性
search_packages关键字模糊搜索包
install_packages安装一个或多个包
plan_install安装预演(dry-run)
remove_package移除一个包
update_packages刷新索引或升级指定包
list_packages列出已安装的包
package_info查询包详细信息
list_installed_versions列出已安装版本
use_version切换激活版本
system_status系统状态
list_subos列出所有 sub-OS
list_subos_shims列出活跃 sub-OS 的 shim
create_subos创建 sub-OS
switch_subos切换活跃 sub-OS
remove_subos删除 sub-OS
env返回当前环境信息
list_repos列出索引仓库
add_repo添加/更新索引仓库
remove_repo移除索引仓库

各能力的 inputSchema / outputSchema 通过 xlings interface --list 获取。

8. 错误处理

  • 启动阶段错误(如未知能力名):服务端先输出一行 error 事件,再输出 result(exitCode=1),然后退出。
  • 执行阶段错误:通过事件流中的 error 事件报告。recoverable=true 表示执行未中断;recoverable=false 后通常紧跟 result 终止行。
  • 内部异常:code 为 E_INTERNAL,exitCode=1。
  • 取消:exitCode=130。
  • 被策略拒绝:exitCode=2。命令是合法的、也没有出错,但 xlings 拒绝执行它。 与 1 分开,是因为客户端对这两者该做的事不同:1 是"出问题了",2 是"你要的这件事 我不做,除非你明确覆盖"。

8.1 remove_package 的反向依赖拒绝(2026.8.8.1+)

当活跃 subos 里有已安装的包直接依赖移除目标时,remove_package 会拒绝执行, 先发一条 remove_blocked,再以 exitCode=2 结束:

{"kind":"data","dataKind":"remove_blocked","payload":{
  "subos":"default","name":"glibc","version":"2.39",
  "required_by":[{"name":"xim:binutils","version":"2.42"},
                 {"name":"xim:llvm","version":"22.1.8"}]}}
{"kind":"result","exitCode":2}

{"force": true} 可越过这一检查(remove_plan / remove_summary 照常)。

只看直接依赖:依赖方的 libdirs 只有在被直接声明时才会进入其载荷的 RPATH 闭包, 所以隔了一跳的包并没有把这个载荷放在任何搜索路径上,删掉它不会经由 loader 影响到它。

9. 完整会话示例

$ xlings interface install_packages --args '{"targets":["node@22"],"yes":true}'

stdout 输出(每行一个 JSON):

{"kind":"progress","phase":"resolving","percent":0,"message":"resolving node@22"}
{"kind":"progress","phase":"downloading","percent":25,"message":"node-v22.4.0-linux-x64.tar.xz"}
{"kind":"progress","phase":"downloading","percent":80,"message":"node-v22.4.0-linux-x64.tar.xz"}
{"kind":"log","level":"info","message":"extracting node-v22.4.0-linux-x64.tar.xz"}
{"kind":"progress","phase":"installing","percent":90,"message":"linking shims"}
{"kind":"data","dataKind":"install_summary","payload":{"installed":["node@22.4.0"]}}
{"kind":"result","exitCode":0,"data":{"installed":["node@22.4.0"]}}

客户端收到 kind: result 后即可关闭 stdin 并退出。