@vertu-tech/vps-cli
v0.1.10
Published
Vertu CLI - bridge Odoo ai_cli + ai_skills to a local Node.js command and one-click install skills into Cursor / Claude Code / Trae.
Downloads
93
Maintainers
Readme
@vertu-tech/vps-cli
把 Odoo ai_cli + ai_skills 两个模块的 HTTP 网关包装成一个本地 CLI(vertu),并支持把服务端定义的 Skill 一键安装到 Cursor / Claude Code / Trae / OpenClaw / Hermes 这些 AI Agent 的用户级目录。
- CLI 是运行时:调用真实的
/ai/cli/v1/execute、/ai/skills/v1/execute等接口 - Skill 是知识层:
SKILL.md告诉 AI Agent 在什么场景下、用什么参数去调vertu
设计理念、接口契约的更深背景见 vertu_addons/ai_cli/README.md 与 vertu_addons/ai_skills/README.md。
特性
- 单二进制
vertu,子命令分组:login/logout/whoami/caps/<program> <leaf...>/skill ... - 统一认证:用户登录走
/ai/cli/v1/login,session_id 写 OS 钥匙串(keytar),不可用时降级到~/.vertu/config.json(POSIX 0600);CI 走VERTU_BOT_INBOUND_KEY环境变量 - 动态命令:每次启动按需读取
/ai/cli/v1/capabilities,根据leaves[].argv_prefix还原嵌套命令、按parameters_schema渲染--<flag>,并按invoke_kind自动选择payload.arguments(ai_tool)或payload.json_params(http_json) - Skill 跨 Agent 同步:
vertu skill update默认扫描全部 Adapter 的.vertu-manifest.json,按(agent, skill_key) → sha256与远端比对:内容漂移会重写、远端新增的 skill 会自动安装到「已经在用此 Agent」的本机、远端已删除的 skill 会本地物理 prune;--dry-run仅打印对齐表,--no-include-new/--no-prune可分别关闭新增/删除同步 - 支持的 Agent 安装目标(仅用户级):
- Cursor →
~/.cursor/skills/<skill_key>/ - Claude Code →
~/.claude/skills/<skill_key>/ - Trae 国际版 →
~/.trae/skills/<skill_key>/ - Trae 国内版 →
~/.trae-cn/skills/<skill_key>/(与国际版完全分离) - OpenClaw →
~/.openclaw/skills/<skill_key>/(OpenClaw 的 Managed/local skills 根目录,可被~/.openclaw/openclaw.json的 allowlist 进一步过滤) - Hermes →
~/.hermes/skills/<skill_key>/(Nous Research Hermes Agent 的唯一 source-of-truth 目录) - 任意目录(v0.1.5+)→ 通过
--dir <path>直接安装到自定义路径,用于尚未在内置列表里的「未知 Agent」;支持~与相对路径,可与--agent混用
- Cursor →
- AI-friendly 输入纠错(v0.1.3+):
- 单
required: string字段的 leaf 自动暴露 positional shorthand:vertu odoo knowledge business "罗来"等价于... business --query "罗来",无需先--help一次再写 - 智能 unknown-flag 提示:
--model→(Did you mean one of --model-name, --model-name-file?)、--field→(Did you mean --fields?),覆盖 commander 默认maxDistance=3算法漏掉的「短前缀 vs 长 kebab 名」常见 AI 误用
- 单
一句话自举(推荐,AI Agent 引导安装)
把「装 vertu + 登录 + 把业务 skills 同步到当前 agent」交给 AI agent 完成。bootstrap skill 由 Odoo ai_skills 静态托管,无需登录即可访问:
https://admin.vertu.cn/ai_skills/static/skills/vps-cli/SKILL.md
仓库内真源:vertu-erp/vertu_addons/ai_skills/static/skills/vps-cli/SKILL.md
在 Cursor / Claude Code / Trae / OpenClaw / Hermes 里跟 agent 说(或等价表述):
安装 https://admin.vertu.cn/ai_skills/static/skills/vps-cli/SKILL.md 这个 skill,并按 skill 初始化 vertu CLI、把业务 skill 装到当前 agent
agent 会自行 wget/curl 该文件到本机 agent 的 skills/vps-cli/,再按 SKILL.md 走完:检测 Node 20+ → npm i -g @vertu-tech/vps-cli@latest → 引导你 vertu login(密码须本人填写)→ vertu skill update(或 vertu skill install --all --agent all -y)→ vertu whoami / vertu caps list 自检。
Hermes 用户对照:与「先装 hermes-agent skill 再自举」类似;区别是 bootstrap skill 由 Odoo 静态托管,agent 按 URL 拉取即可。
快速开始(手动)
公网安装(推荐,使用方)
npm install -g @vertu-tech/vps-cli
vertu --version
vertu login # 默认登录 https://admin.vertu.cn,无需 --base-url / --db
vertu --help最低 Node 版本 20+(包内已声明 engines.node)。
从源码安装(贡献方)
git clone https://gitee.com/he-linyan/vps-cli.git
cd vps-cli
npm install
npm run build
node dist/vertu.cjs --help
# 或者把工作区链成全局 `vertu`,改 `src/` 后只需 `npm run build` 即生效:
npm link
vertu --help完整流程示例见 examples/README.md。
升级 / 卸载
npm update -g @vertu-tech/vps-cli # 升级到最新
npm uninstall -g @vertu-tech/vps-cli # 卸载命令一览
会话与缓存
| 命令 | 说明 |
|------|------|
| vertu login [--base-url --db --login --password] | 调用 /ai/cli/v1/login,把 session 存进钥匙串。--base-url 省略时默认 https://admin.vertu.cn(Vertu 正式环境,单 db,无需传 --db;仅当本机还没登记过任何 endpoint 时生效) |
| vertu logout [--forget] | 调用 /ai/cli/v1/logout,清除本地 session(--forget 同时清理整个 profile) |
| vertu whoami | 调用 /ai/cli/v1/whoami,附带打印凭据来源、缓存路径 |
| vertu caps refresh | 强刷 /ai/cli/v1/capabilities 缓存 |
| vertu caps list [--program --json] | 渲染当前缓存里的命令树 |
动态命令
vertu <program_slug> <segment...> 会从 capabilities 里找到对应 leaf,根据 JSON Schema 渲染 --<flag>。flag 名是 schema key 的 kebab-case(model_name → --model-name,knowledge_types → --knowledge-types);snake_case 也接受,会在入口被归一化:
# 标准 ai_tool leaf:每个字段都是 --kebab-flag
vertu odoo data search --model-name res.partner --domain '[]' --fields 'id,name' --limit 5
# 单 required string 字段的 leaf 支持 positional shorthand(v0.1.3+)
vertu odoo knowledge business "罗来"
# 等价于:vertu odoo knowledge business --query "罗来"
# http_json leaf
vertu odoo skills execute --skill-key sample --params '{"foo":1}'
# 兜底:直接传整个 payload
vertu odoo data search --payload-json '{"arguments":{"model_name":"res.partner","limit":3}}'写错 flag 名时(--model 这种 AI 高频肌肉记忆)会得到上下文相关的提示:
$ vertu odoo data search --model res.users --domain "..."
error: unknown option '--model'
(Did you mean one of --model-name, --model-name-file?)
(use -h or --help for usage)Skill 子命令
| 命令 | 说明 |
|------|------|
| vertu skill list [--source remote\|caps] [--json] | 列出所有可用 skill |
| vertu skill pull <skill_key\|all> [--out DIR] | 仅下载 SKILL.md + assets,不写入 Agent |
| vertu skill run <skill_key> [--script-key --params --validate-only] | 调用 /ai/skills/v1/execute |
| vertu skill install [skill_keys...] [--all] [--agent ...] [--dir ...] [-y] | 交互式多选向导(不传任何参数时进入),亦可显式列 key 或用 --all;TTY 缺省会同时让你多选 Agent,并在末尾要求确认 |
| vertu skill update [--agent --dir --skill-key --dry-run --no-include-new --no-prune] | 跨 Agent 同步:默认扫描所有 builtin agent + ~/.vertu/known-dirs.json 中所有自定义目录,比对远端 sha256,自动重写漂移、安装远端新增、prune 远端已删除 |
| vertu skill uninstall <skill_key> [--agent ...] [--dir ...] | 从一个/若干/全部目标移除(默认与 update 同源:含全部 builtin agent + 全部已登记的自定义目录) |
| vertu skill known-dirs list / add <path> / forget <path> / scrub | 维护 ~/.vertu/known-dirs.json 注册表(普通流程不需要直接调用,install/uninstall 会自动维护) |
--agent 接受逗号或空格分隔的 id:cursor / claude / claude-code / trae(国际版) / trae-cn(国内版) / openclaw(别名 open-claw / claw) / hermes(别名 hermes-agent / nous),或 all。
--dir <path...>(v0.1.5+)支持把同一份 skill 安装/更新/卸载到任意自定义目录,专门用于尚未在 builtin agent 列表里的「未知 Agent」。每个 <path> 会被展开成 <path>/<skill_key>/SKILL.md 并写一份 .vertu-manifest.json,所以后续 vertu skill update 可以同步该目录。要点:
- 支持
~展开(~/Library/AgentX/skills)与相对路径(按当前 shell 的 cwd 解析) - 多路径用空格或逗号分隔:
--dir ./skills ./agents/foo/skills或--dir "./a,./b" - 与
--agent可混用;同一物理路径只会写一次(按绝对路径去重) - 与 builtin adapter 不同的是:dir adapter 不会改写 frontmatter(不加
disable-model-invocation、不加allowed-tools),仅保证name字段存在 —— 让目标 Agent 自己解释 frontmatter install --dir <path>会自动把绝对路径登记到~/.vertu/known-dirs.json,让后续不带任何参数的vertu skill update与vertu skill uninstall也会自动覆盖这些目录(详见下一节)
# 安装到自定义目录(首次会自动建目录 + 登记到 known-dirs)
vertu skill install hello-world --dir ~/work/my-agent/skills
# 同时装到 cursor + 一个本地原型 agent
vertu skill install --all --agent cursor --dir ./prototype-agent/skills
# 不带任何参数即可同步全部目标(含 known-dirs 中的自定义目录)
vertu skill update
# 仅同步指定目录(跳过 known-dirs 自动发现)
vertu skill update --dir ~/work/my-agent/skills
# 仅同步特定 builtin agent(跳过 known-dirs 自动发现)
vertu skill update --agent cursor
# 移除(不带参数同样会扫到 known-dirs)
vertu skill uninstall hello-world自动发现自定义目录:~/.vertu/known-dirs.json
为了让用户无需在每次 update 都重复 --dir <path>,CLI 维护一份全局注册表 ~/.vertu/known-dirs.json:
{
"version": 1,
"dirs": [
{
"path": "C:\\work\\my-agent\\skills",
"registeredAt": "2026-05-08T...",
"lastUsedAt": "2026-05-08T..."
}
]
}生命周期完全自动:
install --dir <path>成功后把绝对路径写入注册表(已存在则刷新lastUsedAt)update/uninstall在「未传--agent也未传--dir」时,把注册表内全部还活着的目录展开为dir:<abs>adapter 一并参与同步;扫描前会自动 scrub 掉两类过期条目:- 目录已被手动删掉(
stat返回 ENOENT) - 目录还在,但
.vertu-manifest.json已空(最后一条 skill 已被 uninstall)
- 目录已被手动删掉(
uninstall <skill>把某 dir 的最后一条 skill 移除后,会主动从注册表中删除该路径
「显式优先」:一旦传了 --agent 或 --dir,不会再去展开 known-dirs,遵循 commander 一贯的"用户给了就尊重"语义。
如果需要手动管理注册表,使用 vertu skill known-dirs 子命令簇:
vertu skill known-dirs list # 看现在 update 会自动覆盖哪些目录
vertu skill known-dirs add ~/foo/skills # 把已经手动拷过 skill 文件的目录纳入自动同步
vertu skill known-dirs forget ~/foo/skills # 从注册表移除(不删盘上文件)
vertu skill known-dirs scrub # 主动 scrub 一遍vertu skill install 的交互规则(v0.1.4+):
- TTY 下「skill 维度」与「agent 维度」中任意一个没有显式给出就会进入对应的 inquirer 多选面板(
<space>切换、<a>全选、<i>反选、<enter>确认)。 - 多选 Agent 默认会勾选「该 Agent 的 manifest 已经至少装过一个 skill」的本机已有 Agent;首次使用则全部预选。
- 进入过任一交互面板后,末尾默认还会有一次预览 +
Confirm?,加-y/--yes跳过。 - CI 或纯命令行场景:完整给出
<skill_keys>/--all与--agent即可绕过所有交互;想强制非交互(让缺参数直接报错而不是 prompt)可加--no-interactive。
跨 Agent 同步是怎么工作的
vertu skill install 时会在每个目标 Agent 的根目录写一份 .vertu-manifest.json,结构:
{
"version": 1,
"entries": {
"hello-world": {
"skillKey": "hello-world",
"baseUrl": "https://erp.example.com",
"installedAt": "2026-...",
"skillMdSha256": "ab12...",
"files": [
{ "path": "SKILL.md", "sha256": "ab12..." },
{ "path": "reference.md", "sha256": "cd34..." }
],
"sourceRoute": "/ai/skills/v1/skill_file"
}
}
}vertu skill update 流程:
- 扫描各 Adapter 的
.vertu-manifest.json(Cursor / Claude Code / Trae 国际版 / Trae 国内版 / OpenClaw / Hermes)→ 汇总(agent, skill_key) → installed_sha256,并记下「该 Agent 是否已经至少装过任意 skill」 - 一次性
POST /ai/skills/v1/catalog取远端content_sha256与全量skill_key列表 - 计算并打印对齐表:
AGENT SKILL_KEY LOCAL_SHA REMOTE_SHA ACTION(skip|update|install|prune|orphan)install:远端有但本地未装;默认自动补装到「已经在用此 Agent」(manifest 非空)的目录,避免给从未碰过的 Agent 创建文件夹。--no-include-new关掉这一类prune:本地装过但远端已不存在;默认物理删除目录 + 移除 manifest 条目。--no-prune关掉后会以orphan仅展示不动手
- 非
--dry-run时,对update/install复用一份缓存~/.vertu/skills-cache/<base_hash>/<skill_key>/后分发到各 Agent;对prune调用uninstallSkillFromAdapter清理本地
凭据与缓存路径
| 类型 | 默认位置 |
|------|----------|
| 钥匙串条目 | service=vertu-cli,account=session:<base_url> / account=bearer:<base_url> |
| 配置文件(钥匙串不可用时) | %USERPROFILE%\.vertu\config.json(Windows) / ~/.vertu/config.json(macOS/Linux),mode 0600 |
| Capabilities 缓存 | ~/.vertu/capabilities.<sha1(base_url)[:12]>.json,TTL 1h |
| Skill 文件缓存 | ~/.vertu/skills-cache/<sha1(base_url)[:12]>/<skill_key>/ |
| Cursor Skill 安装位置 | ~/.cursor/skills/<skill_key>/ |
| Claude Code Skill 安装位置 | ~/.claude/skills/<skill_key>/ |
| Trae 国际版 Skill 安装位置 | ~/.trae/skills/<skill_key>/ |
| Trae 国内版 Skill 安装位置 | ~/.trae-cn/skills/<skill_key>/ |
| OpenClaw Skill 安装位置 | ~/.openclaw/skills/<skill_key>/ |
| Hermes Skill 安装位置 | ~/.hermes/skills/<skill_key>/ |
| 自定义目录(--dir) | <--dir 给的绝对路径>/<skill_key>/,每个目录一份独立 .vertu-manifest.json |
| 已注册自定义目录的全局注册表 | ~/.vertu/known-dirs.json(v0.1.5+,install --dir 自动写入,update / uninstall 默认扫描) |
环境变量
| 变量 | 说明 |
|------|------|
| VERTU_BASE_URL | 默认 base URL(优先级:--base-url > VERTU_BASE_URL > ~/.vertu/config.json 的 defaultBaseUrl > 内置默认值 https://admin.vertu.cn) |
| VERTU_BOT_INBOUND_KEY | Bot Bearer token;设了就走 Bearer 模式(CI 推荐) |
| VERTU_DISABLE_KEYTAR=1 | 强制走文件存储(CI/容器/裸机调试用) |
| VERTU_DEBUG=1 | 打印 dynamic capabilities 加载失败的原因 |
常见问题
1. npm install 报 keytar 编译失败?
keytar 是可选依赖。设 VERTU_DISABLE_KEYTAR=1 或 npm install --no-optional,CLI 会自动降级到文件存储。Windows 上若需要 keytar,先装 windows-build-tools(或者直接用文件模式,零依赖)。
2. 我能用 user session 调 /ai/skills/v1/* 吗?
本 CLI 始终用同一个 session/Bearer 头,对 CLI 网关与 Skills 网关无差别处理。前提是 Odoo 侧的 skills_gateway.py 已改造成统一认证(你已确认会做此改造)。
3. 同一台机器同时装了 Trae 国际版和国内版会冲突吗?
不会,但两版互不共享 SKILL 目录:国际版读写 ~/.trae/skills/,国内版读写 ~/.trae-cn/skills/。vertu skill install --all 默认会同时写入两份;如果只装了其中一版,可用 --agent trae 或 --agent trae-cn 限定。
4. 怎么把 SKILL.md 提供给项目级的 .cursor/rules/*.mdc 或 AGENTS.md?
当前版本只覆盖用户级目录。如需项目级或者 AGENTS.md 整合,请提 issue 说明使用场景,会作为后续 adapter 类型加入。
开发
npm install # 含 keytar(可选)
npm run dev -- --help
npm run typecheck
npm test
npm run build测试用 vitest,覆盖:JSON-RPC 客户端(用 undici MockAgent)、Schema → Commander Option、Frontmatter 解析/改写、Adapter 写入、跨 Adapter manifest 扫描。
