ipanel CLI:一套命令行工具同时管理 InnoShop 与 InnoCMS
当我们同时运营 InnoShop(电商)和 InnoCMS(内容管理)几十个实例的时候,最痛苦的事情不是写代码,而是「日常运维」。给十几个线上实例批量改一篇文章、回查一段咨询、临时把某张图传上去 —— 如果每次都要打开浏览器登录后台,工程师会疯掉。ipanel 就是为这种场景写的:一套命令行,调用所有走 /api/panel/ 协议的 Inno 系产品。
这篇文章把 ipanel 的真实架构、安装方式、实例配置、常用命令和一个完整的「本文自动发布」实战流程拆开讲清楚。
它解决的是什么问题
InnoShop 和 InnoCMS 都暴露了 /api/panel/ REST 接口,鉴权统一走 Sanctum token。两个产品的接口重叠度很高(articles / catalogs / pages / tags / file_manager / settings / locales 都有),各自的专属资源是:
- InnoShop 独有:
products、categories、brands、orders、shipments、customers、currencies、attributes、options、reviews、tax_rates、order_returns等电商域资源 - InnoCMS 独有:
consultations(前台咨询留资) - 两者都有:内容、文件、设置、地区语言、管理员
所以从工具角度,完全可以一个 CLI 吃掉所有走 Panel API 的 Inno 产品 —— 旧的 ishop 命令名只覆盖电商语义,换掉它只是时间问题。
真实架构:Python 默认 + Go 分发
ipanel 在仓库里有两份实现,分工明确:
| 入口 | 路径 | 用途 |
|---|---|---|
| Python 脚本(默认) | ~/.claude/skills/ipanel/ipanel.py |
日常使用、迭代新端点、修 API 兼容性 bug。改完直接生效,无 build。 |
| Go 二进制(分发) | /usr/local/bin/ipanel-go(源码 ~/Funnlink/ipanel-cli/) |
客户交付、系统级安装。只在明确要求时才从 Python 同步过去。 |
调用方永远只看到一个 ipanel 命令。dispatcher 根据 ~/.config/ipanel/config.json 的 runner 字段("python" 或 "go")把请求转发到对应实现,临时切 backend 用 IPANEL_RUNNER=go ipanel ...。
为什么默认 Python?因为 Panel API 接口经常因为版本演化、字段补丁、新端点上线要打补丁。Python 改完直接生效,5 秒钟发版;Go 二进制要走 build + 分发流程,对日常迭代太重。Go 版本是给客户机器上「装一次跑半年」的场景用的。
安装
两条路径,按场景选:
1. 开发机日常使用(推荐) —— 直接用 Python 脚本:
# 脚本已经放在 ~/.claude/skills/ipanel/ipanel.py
# 加个 alias 或 symlink 到 PATH 即可
ln -sf ~/.claude/skills/ipanel/ipanel.py /usr/local/bin/ipanel
chmod +x ~/.claude/skills/ipanel/ipanel.py
# 验证
ipanel instances
2. 客户机器 / 系统级安装 —— 用 Go 二进制:
go install ./cmd/ipanel@latest
# 或下载预编译二进制到 /usr/local/bin/ipanel
两者都依赖 ~/.config/ipanel/config.json 这个统一配置文件,区别只是底层实现。
配置实例:多 profile 是核心
ipanel 最常用的能力是「同一台机器切多个实例」。每个实例一条 profile,存在 ~/.config/ipanel/config.json:
{
"current_instance": "innocms",
"runner": "python",
"instances": {
"innocms": {
"url": "https://www.innocms.com",
"email": "admin@innocms.com",
"password": "***",
"token": "6|xSf8...(自动缓存)",
"token_updated": "2026-06-19T12:16:21+08:00"
},
"demo": {
"url": "https://demo.innoshop.cn",
"email": "...",
"password": "***",
"token": "9198|...",
"token_updated": "..."
},
"celocal": { "url": "http://community.test", ... }
}
}
第一次调用 ipanel -i innocms articles list 时,脚本会用 email/password 走 POST /api/panel/login 拿到 Bearer Token,然后写回 token 字段;之后所有请求带 Authorization: Bearer ...,token 失效自动重新登录。整个过程对调用方透明,平时根本不需要手动 login。
常用命令速查
每个资源(articles、products、files 等)的子命令都是同一套:list / get / create / update / patch / delete。files 多了 upload、mkdir、move 等文件管理动作。
# 看 dashboard
ipanel -i innocms dashboard index
# 文章 CRUD(InnoShop / InnoCMS 都支持)
ipanel -i innocms articles list
ipanel -i innocms articles get 12
ipanel -i innocms articles patch -j '{"active": false}' 12
# 文件上传(关键细节:base-folder 是相对 static/media 的子路径)
ipanel -i innocms files upload \
--file ./cover.png \
--base-folder images/articles
# InnoShop 独有资源
ipanel -i demo products list
ipanel -i demo orders get 5
ipanel -i demo customers list --keyword alice
# InnoCMS 独有资源
ipanel -i innocms consultations list
ipanel -i innocms consultations mark_all_read
# 实例管理
ipanel instances # 列出所有 profile
ipanel -i innocms login # 强制重新登录、刷新 token
输出默认是格式化的 JSON。-q 静默、--raw 不美化,方便管道解析。
实战:本文就是用 ipanel 自动发布的
写这篇文章本身就是一个完整的 ipanel 工作流。我把全过程记录下来,作为最贴切的案例:
步骤 1:生成配图并上传。用 AI 画两张图到本地,然后传到线上 static/media/images/articles/:
ipanel -i innocms files upload \
--file ./ipanel-architecture.png \
--base-folder images/articles
# 返回
# {
# "success": true,
# "data": {
# "path": "static/media/images/articles/ipanel-architecture.png",
# "url": "https://www.innocms.com/static/media/images/articles/ipanel-architecture.png"
# }
# }
步骤 2:用文件内容创建文章。把文章字段写到 JSON 文件,避免 shell 转义地雷:
cat > /tmp/article.json <<'EOF'
{
"slug": "ipanel-cli-unifies-innoshop-and-innocms",
"catalog_id": 4,
"active": true,
"position": 0,
"viewed": 0,
"author": "ipanel-cli",
"image": "static/media/images/articles/ipanel-architecture.png",
"translations": [
{
"locale": "zh-cn",
"title": "ipanel CLI:一套命令行工具同时管理 InnoShop 与 InnoCMS",
"summary": "...",
"content": "<p>...</p>",
"meta_title": "...",
"meta_description": "..."
}
]
}
EOF
ipanel -i innocms articles create -f /tmp/article.json
注意几个踩过坑的字段:
translations是数组([{...}]),不是对象。早期文档把它写成{"zh-cn": {...}}是错的。position和viewed必须显式传,否则线上icms_articles这两个字段无默认值,create会 422。content里的图片用绝对路径/static/media/images/articles/<filename>.png,跟站点同源直接生效。
步骤 3:验证。从写 JSON 到详情页可访问,全程 800 毫秒。如果十年前告诉我「CMS 发布文章不用打开后台」,我会觉得在开玩笑。
进阶与避坑
切换 backend。默认 Python,要测 Go 二进制时不用改配置:
IPANEL_RUNNER=go ipanel -i innocms articles list
持久切换把 runner 字段改成 "go" 即可。
修 ipanel 行为。发现某个端点字段对不上、某个返回结构变了 —— 直接改 ~/.claude/skills/ipanel/ipanel.py,下次调用立即生效。不要主动同步到 Go 二进制,那是分发版本,客户机器上的事。
永远优先走 API。遇到 Panel API 出 bug,不要绕路去 php artisan tinker 改数据库、不要手写 curl,而是修 ipanel 脚本本身。这样所有调用方一起受益,问题修一次就好。
token 缓存。默认 60 天有效,过期前调用 login 会自动刷新。token_updated 字段方便排查「为啥这个实例突然 401」。
常见报错排查:
401 Unauthorized——ipanel -i <name> login强制刷新 token422 position/viewed 不能为空—— 早期数据库迁移没给字段默认值,传position: 0, viewed: 0即可path 不存在(files upload)——base-folder是相对static/media/的子路径,不要重复带static/media/前缀
写在最后
ipanel 的设计哲学很简单:所有走 Panel API 的产品共用一套工具,新端点上线 5 分钟就能在 CLI 里用上,运维多实例不再依赖浏览器。Python 默认、Go 分发的双实现让"快迭代"和"分发稳定"两者兼得。下一篇会拆 Panel API 本身的鉴权流程、字段约定和常见资源结构,给想自己写 SDK 或迁移到其他语言的人一张地图。