publish-moviepilot-plugin · v6 · 2026-10-26 · sha256 8f576dbf09b47579
publish-moviepilot-plugin v6A
Immutable. This exact content never changes and is served at /api/v1/blob/8f576dbf09b47579.
---
name: publish-moviepilot-plugin
version: 6
description: >-
Use this skill when the user asks to publish, upload, sync, pull, push, diff,
or maintain a MoviePilot local plugin in a GitHub repository. Covers using the
configured MoviePilot GitHub token, PLUGIN_LOCAL_REPO_PATHS local plugin
repositories, package.json/package.v2.json/package.v3.json metadata,
plugins/plugins.v2/plugins.v3
layouts, safe file exclusion, diff preview before publishing, incremental
GitHub Contents API updates, and syncing local plugin changes back from GitHub.
Includes asking whether to use an existing repository or create a new public
repository when no target repository is available.
Also use for Chinese requests mentioning 插件发布, 插件维护, 推送插件到 GitHub,
从 GitHub 拉取插件, 同步本地插件仓库, 增量发布插件, 插件仓库维护.
allowed-tools: read_file write_file edit_file apply_patch execute_command moviepilot_api
allowed-api-operations: config.system.get config.system.update
---
# Publish MoviePilot Plugin
Use this skill to publish and maintain a MoviePilot local plugin repository
through GitHub while protecting local secrets and unrelated plugins.
## Scope
- Publish one local plugin under `plugins.v3/<plugin_id_lower>/`,
`plugins.v2/<plugin_id_lower>/` or `plugins/<plugin_id_lower>/` to a GitHub
repository.
- Merge only that plugin's entry into `package.v3.json`, `package.v2.json` or
`package.json`.
- Preview local/remote differences before writing.
- Pull remote plugin files back to the local plugin source.
- Create the target GitHub repository when the user explicitly chooses automatic
creation; repositories are public by default unless the user asks for private.
- Reuse MoviePilot settings `GITHUB_TOKEN`, `REPO_GITHUB_TOKEN`,
and `PLUGIN_LOCAL_REPO_PATHS` when available.
## Ground Truth
- Local plugin development rules: `skills/create-moviepilot-plugin/SKILL.md`.
- Local plugin source discovery: `app/adapters/external/market.py`,
`PluginHelper.get_local_repo_paths()`.
- GitHub token settings: `app/runtime/config.py`, especially `GITHUB_TOKEN` and
`REPO_GITHUB_TOKEN`.
- Plugin package layouts:
- V3: `package.v3.json` and `plugins.v3/<plugin_id_lower>/`
- V2: `package.v2.json` and `plugins.v2/<plugin_id_lower>/`
- Legacy: `package.json` and `plugins/<plugin_id_lower>/`
## Pre-Flight
1. Identify the target plugin ID and local source repository.
- If the user gives a path, use it.
- Otherwise query `PLUGIN_LOCAL_REPO_PATHS`; if exactly one configured
repository contains the plugin, use it.
- If several configured repositories contain the plugin, ask which one.
2. Identify the GitHub repository as `owner/repo`.
- Use the user's explicit repository first.
- If omitted, infer only when the local source has an obvious Git remote.
- If neither is available, ask whether to use an existing repository or
automatically create a new public repository.
- If the user chooses an existing repository, ask for `owner/repo`.
- If the user chooses automatic creation, ask for the target `owner/repo`
and state that the repository will be public by default.
- Do not create a private repository unless the user explicitly asks for it.
3. Select the package version layout.
- Prefer `v3` when the plugin lives under `plugins.v3/<plugin_id_lower>/`
or the repository ships `package.v3.json` (current MoviePilot V3 hosts).
- Prefer `v2` when `package.v2.json` or `plugins.v2/<plugin_id_lower>/`
exists.
- Use legacy only when the local plugin is under `plugins/`.
4. Verify token availability.
- Prefer `REPO_GITHUB_TOKEN` for the target repo when configured.
- Fall back to `GITHUB_TOKEN`.
- If no token is configured, ask the user to configure one before pushing.
Read-only preview may still run without a token for public repositories.
## Script
Use `scripts/publish_plugin.py` for deterministic GitHub operations.
```bash
python skills/publish-moviepilot-plugin/scripts/publish_plugin.py preview \
--repo owner/repo \
--plugin-id MyPlugin \
--local-repo /path/to/MoviePilot-Plugins \
--package-version v2
python skills/publish-moviepilot-plugin/scripts/publish_plugin.py push \
--repo owner/repo \
--plugin-id MyPlugin \
--local-repo /path/to/MoviePilot-Plugins \
--package-version v2 \
--message "Publish MyPlugin v1.0.0"
python skills/publish-moviepilot-plugin/scripts/publish_plugin.py pull \
--repo owner/repo \
--plugin-id MyPlugin \
--local-repo /path/to/MoviePilot-Plugins \
--package-version v2
# V3 插件仓库(package.v3.json + plugins.v3/)
python skills/publish-moviepilot-plugin/scripts/publish_plugin.py push \
--repo owner/repo \
--plugin-id MyPlugin \
--local-repo /path/to/MoviePilot-Plugins \
--package-version v3 \
--message "Publish MyPlugin v1.0.0"
python skills/publish-moviepilot-plugin/scripts/publish_plugin.py create-repo \
--repo owner/repo
```
Options:
- `--package-version v3|v2|legacy|auto`: layout selector. `auto` resolves the
layout from where the plugin directory actually lives
(`plugins.v3` → `plugins.v2` → `plugins`), then falls back to the manifest
files, so repositories that still keep both manifests stay correct. Pass
`v3` explicitly for current MoviePilot V3 plugin repositories.
- `create-repo`: create the target GitHub repository. Default visibility is
public; use `--private` only when the user explicitly asked for private.
- `preview`: compare local filtered files with remote files and print JSON.
- `push`: upload changed files and merge the plugin package entry.
- `pull`: write remote plugin files and package entry into local source.
- `--create-repo-if-missing`: on push, create the target public repository when
GitHub reports that it does not exist.
- `--delete-remote`: on push, delete remote plugin files that no longer exist
locally after exclusions.
- `--force`: on pull, allow overwriting local files that differ from remote.
- `--include PATTERN`: add files otherwise excluded by default.
- `--exclude PATTERN`: add an extra ignore pattern.
- `--dry-run`: print planned changes without writing.
- `--proxy URL`: use an explicit HTTP/HTTPS proxy for GitHub API requests.
`push` 通过 Git Data API(blob → tree → commit → 移动分支引用)提交:无论一次改动
多少文件都只产生**一个 commit**,CI 只会触发一次、diff 完整,`package` 版本与源码
版本不会出现中间态;返回 JSON 中带 `commit_sha`。空仓库会自动创建根提交并建立分支。
## GitHub Release 与 README
`push` 只同步插件源码与 package 条目,**不会创建 GitHub Release,也不会修改
README**。目标仓库若用 GitHub Actions 打包(例如
`.github/workflows/plugins-release.yml`,产物为 `Plugin_vX.Y.Z` tag 与
zip/tar.gz + sha256 资产):
- package 条目必须显式写 `"release": true`,否则工作流即使运行也不会发版。
- 自动触发依赖**同一次 push 中 package 文件的 version 发生变化**。逐文件提交时
`package.v3.json` 的变更可能落在另一个提交,diff 里看不到它,于是静默跳过;
这种情况改用 `workflow_dispatch`(`source_directory` + `plugin_id`)手动触发。
- README 的插件表格与说明需要单独编辑并推送(Contents API 或 git),不在
`push` 的职责范围内。
## Safety Rules
- Always run `preview` before `push` unless the user explicitly asks for a
direct push and already reviewed the diff.
- When no repository is known, ask the user to choose:
`使用已有 GitHub 仓库` or `自动创建 GitHub 仓库(默认 public)`.
- Only run `create-repo` or `push --create-repo-if-missing` after the user has
explicitly chosen automatic creation.
- Never upload these files unless explicitly included:
`.env`, `.env.*`, `config/`, `data/`, `cache/`, `logs/`, `tmp/`,
`__pycache__/`, `.pytest_cache/`, `.mypy_cache/`, `.ruff_cache/`,
`.DS_Store`, `*.pyc`, `*.pyo`, `*.db`, `*.sqlite`, `*.sqlite3`, `*.log`,
`*.bak`, `*.tmp`, `*.secret`, `*.key`, `*.pem`, `*.crt`, `*.p12`, `*.pfx`,
`node_modules/`.
- For Vue federation plugins, publish built runtime assets under `dist/assets/`
when they are present; do not exclude them as generated files.
- Do not overwrite or remove package entries for other plugins.
- Pin the remote commit before reading the package or plugin files. Build the
single publish commit from that same tree and parent. If the target branch
advances meanwhile, stop on the non-fast-forward conflict, then preview again
against a fresh snapshot; never force-push or reuse stale merged content.
- Do not log or print GitHub token values.
- For push operations, report created, updated, deleted, skipped, and rejected
files separately.
- For pull operations, preserve excluded local files even with `--force`.
Invalid local package JSON stops the pull before any local file is written,
including in `--force` mode.
Differing local plugin files or package metadata stop the entire pull unless
`--force` is used. Package entries for other plugins remain untouched.
- With the `auto` layout, inspect each configured local repository separately;
the working directory does not determine the layout of other repositories.
## Examples
User asks: `把本地 MyPlugin 发布到我的 GitHub 插件仓库`
1. Find `MyPlugin` under configured `PLUGIN_LOCAL_REPO_PATHS`.
2. Ask whether to use an existing repository or create a new public repository
if `owner/repo` cannot be inferred.
3. Run `preview` and summarize the diff.
4. Run `push` only after the user confirms or requested immediate publish.
User asks: `发布插件,没有 GitHub 仓库`
1. Ask for the target `owner/repo` and confirm automatic creation.
2. Run `create-repo` or use `push --create-repo-if-missing`.
3. Continue with `preview` and `push` after repository creation succeeds.
User asks: `同步 GitHub 上 MyPlugin 的最新代码到本地`
1. Run `pull` without `--force`.
2. If local conflicts are reported, show the conflicting paths and ask whether
to force overwrite or resolve manually.
## Final Checklist
- The plugin ID matches the package object key.
- The package file and plugin directory layout match the selected version.
- Sensitive and runtime-local files were rejected or skipped.
- The preview was shown before push, unless explicitly bypassed.
- The final response mentions whether local agent restart is needed only when
this built-in skill itself changed.