メニュー

ipanel CLI:一套命令行工具同时管理 InnoShop 与 InnoCMS

ipanel-cli 2026-06-19 47
ipanel CLI:一套命令行工具同时管理 InnoShop 与 InnoCMS
ipanel 是 Inno 系产品 Panel API 的统一命令行入口,Python 脚本默认 + Go 二进制分发的双实现,支持多实例 profile 切换、token 自动缓存,覆盖文章、商品、订单、咨询、文件等 40+ 端点。本文拆架构、安装、配置、常用命令,并用一个「本文自动发布」的实战流程把全链路讲透。

当我们同时运营 InnoShop(电商)和 InnoCMS(内容管理)几十个实例的时候,最痛苦的事情不是写代码,而是「日常运维」。给十几个线上实例批量改一篇文章、回查一段咨询、临时把某张图传上去 —— 如果每次都要打开浏览器登录后台,工程师会疯掉。ipanel 就是为这种场景写的:一套命令行,调用所有走 /api/panel/ 协议的 Inno 系产品。

这篇文章把 ipanel 的真实架构、安装方式、实例配置、常用命令和一个完整的「本文自动发布」实战流程拆开讲清楚。

ipanel 多实例多产品多端点架构图

它解决的是什么问题

InnoShop 和 InnoCMS 都暴露了 /api/panel/ REST 接口,鉴权统一走 Sanctum token。两个产品的接口重叠度很高(articles / catalogs / pages / tags / file_manager / settings / locales 都有),各自的专属资源是:

  • InnoShop 独有productscategoriesbrandsordersshipmentscustomerscurrenciesattributesoptionsreviewstax_ratesorder_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.jsonrunner 字段("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/passwordPOST /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 工作流。我把全过程记录下来,作为最贴切的案例:

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": {...}} 是错的。
  • positionviewed 必须显式传,否则线上 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 强制刷新 token
  • 422 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 或迁移到其他语言的人一张地图。