关于 run-full-release
此技能用于运行仓库的 mise 发布流程,或在流程缺失时指导搭建。它会先区分可发布的软件包与文档或配置仓库,再按项目情况安排发布步骤。
主要功能
- 01检测现有 mise 发布任务
- 02搭建前识别仓库类型
- 03按仓库定制发布任务
- 04说明发布失败后的恢复方法
适用场景
- 01运行现有 mise 发布流程
- 02为软件包设置发布任务
- 03将配置仓库同步到 origin
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill run-full-release安装后在 Claude Code 中输入/run-full-release确认已加载。
附带文件references/evolution-log.md
详细介绍
/mise:run-full-release
运行当前仓库的 mise 发布流水线;如果尚不存在,则创建一个。
自我演进技能:此技能会在使用过程中不断改进。如果指令有误、参数已偏移,或需要使用变通方案,请立即修复此文件,不要推迟。仅在遇到真实且可复现的问题时更新。
第 1 步:检测现有发布任务
mise tasks ls 2>/dev/null | grep -i release
如果任务存在 → 跳至第 3 步:执行。 如果未找到任务 → 继续第 1b 步。
第 1b 步:创建脚手架前先对仓库分类
并非每个仓库都是可发布的软件包。在创建版本管理/发布流水线之前,先判断仓库的类型:
ls pyproject.toml Cargo.toml package.json setup.py go.mod 2>/dev/null || echo "NO_PACKAGE_MANIFEST"
-
有软件包清单(Python/Rust/Node/Go)→ 可发布仓库。继续第 2 步(创建版本管理+发布流水线)。
-
没有软件包清单,且没有现有发布基础设施 → 这是一个文档/配置/同步仓库(个人 dotfiles、笔记或多机器间通过
git同步的配置仓库)。没有需要管理版本或发布的内容。不要创建semantic-release。 对于这些仓库,“发布”=同步到 origin:git fetch origin git rev-list --left-right --count origin/<branch>...HEAD # behind ahead [ -z "$(git status --porcelain)" ] || echo "DIRTY — commit or stash first" # Only when the user has asked to release/ship (push only on request): git push origin <branch> git fetch origin && [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/<branch>)" ] && echo "✅ synced — release complete"如果
behind > 0,请先协调差异(git pull --rebase或合并),再推送。也可以创建一个最简的release:full,包含preflight(工作树干净+分支正确+已同步最新)→push→verify(origin == HEAD),不包含版本管理/发布阶段——但仅当用户希望重复执行同步时才这样做;否则,上面的一次性推送就是完整的发布流程。依据(2026-06-04):在
claude-sys上调用此流程时,该仓库是一个在多台机器间通过 git 同步的配置/文档仓库——没有软件包清单、没有.mise.toml,也没有 semantic-release。正确操作是快速前推执行git push origin main,并验证 HEAD==origin,而不是创建流水线。先审计(第 2a 步的生态系统检查)发现了这一点;将其提升为明确的第 1b 步关卡,可以避免在没有任何内容可发布的仓库中,本能地创建发布流水线。
第 2 步:创建发布工作流
此步骤将为当前仓库创建专属的发布流水线。每个仓库都不一样——不要照搬模板。先审计,再创建适用的内容。
2a. 审计仓库
运行以下所有命令,了解此仓库的需求:
# Ecosystem detection
ls pyproject.toml Cargo.toml package.json setup.py 2>/dev/null
# Existing mise config
cat .mise.toml 2>/dev/null || cat mise.toml 2>/dev/null
# Existing release infra (semantic-release, Makefile, GitHub Actions)
ls .releaserc* release.config.* 2>/dev/null
ls .github/workflows/*release* 2>/dev/null
grep -i release Makefile 2>/dev/null
# Credentials already configured
grep -E 'GH_TOKEN|GITHUB_TOKEN|UV_PUBLISH_TOKEN|CARGO_REGISTRY_TOKEN|NPM_TOKEN' .mise.toml mise.toml 2>/dev/null
2b. 阅读参考实现
阅读 cc-skills 自身的发布任务,将其作为可运行的示例——应根据实际情况调整,而非照搬:
ls $HOME/.claude/plugins/marketplaces/cc-skills/tasks/release/
另请阅读:$HOME/.claude/plugins/marketplaces/cc-skills/docs/RELEASE.md
2c. 创建 tasks/release/
仅创建此仓库实际需要的任务。五阶段模式如下:
| 阶段 | 任务 | 用途 | 是否必需? |
|---|---|---|---|
| 1. 发布前检查 | preflight | 目录干净、身份验证、分支检查 | 始终需要 |
| 2. 版本管理 | version | semantic-release(或仓库专用的版本管理方式) | 始终需要 |
| 3. 发布 | pypi | uv publish 或自定义脚本 | Python 项目需要 |
crates | cargo publish --workspace(Rust 1.90+) | Rust 项目需要 | |
npm | npm publish | Node 项目需要 | |
| 4. 验证 | verify | 标签存在、发布版本存在、制品已发布 | 始终需要 |
| 5. 发布后检查 | postflight | Git 状态干净、没有未推送内容、重置锁文件 | 始终需要 |
编排器:full 任务通过 depends = [...] 串联各阶段。
关键规则:
- 凭据放在
.mise.toml[env]中,不要硬编码在脚本里 - 工具版本放在
.mise.toml[tools]中 - 在
preflight和postflight中都要重置锁文件偏移(构建产物,而非有意更改) - 提供
--dry和--status便捷任务
2d. 已知问题
过时的 cc-skills marketplace-path hook 条目泄漏到 ~/.claude/settings.json:cc-skills 的 release:preflight hook 验证关卡因 ✗ N cc-skills marketplace-path entries found in settings.json 而失败。原因:从先前 Claude Code 会话加载的 hooks 可能会将解析后的 marketplace 路径持久化到 settings.json,但插件 hooks 会从各插件的 hooks/hooks.json 自动加载,因此 settings.json 不应包含重复项。修复已内置:运行 ./scripts/sync-hooks-to-settings.sh(可幂等运行——仅清除泄漏的 marketplace-path 条目,保留用户编写的 hooks),然后重新运行 mise run release:full。此问题会在各次发布中反复出现,并非一次性问题。已于 2026-05-09 在发布过程中验证:清除了 4 个条目,重新运行后成功。
@semantic-release/git 未跟踪文件激增:v10.x 运行 git ls-files -m -o 时没有使用 --exclude-standard。安装后打补丁:
find $(npm root -g 2>/dev/null) node_modules \
-path "*/@semantic-release/git/lib/git.js" 2>/dev/null | while read f; do
grep -q 'exclude-standard' "$f" || \
sed -i '' "s/\['ls-files', '-m', '-o'\]/['ls-files', '-m', '-o', '--exclude-standard']/" "$f"
done
semantic-release 部分失败(版本已递增,但没有标签):不要重新运行 semantic-release。手动创建标签和 GitHub release,然后继续执行发布任务。
Cargo 工作区锁文件级联更新(使用 version.workspace = true 的 Rust 工作区):prepareCmd 中基于 perl 的版本递增只会修改 Cargo.toml,但工作区版本会级联更新 Cargo.lock 中每个成员 crate 的条目。@semantic-release/git 插件只会暂存 assets 中列出的文件,因此如果没有显式调用 cargo 并将 Cargo.lock 加入 assets,锁文件就会保留旧版本。表现为:成功运行 release:version 后,release:preflight 因 M Cargo.lock 而失败,导致 cargo publish 受阻。在 release.config.cjs 中修复:
- - "@semantic-release/exec"
- prepareCmd: |
perl -i -pe 's/^version = ".*"/version = "${nextRelease.version}"/' Cargo.toml
cargo update --workspace --offline 2>/dev/null \
|| cargo metadata --format-version=1 --offline >/dev/null 2>&1 \
|| true
- - "@semantic-release/git"
- assets:
- Cargo.toml
- Cargo.lock # ← critical: capture the cascading version bump
message: "chore(release): ${nextRelease.version} [skip ci]"
--offline 可确保同步在本地完成(不会访问注册表)。|| true 备用处理可避免 cargo 命令均无法运行时阻塞 prepareCmd,但如果锁文件确实需要同步,下一次 preflight 会发现问题。
mise 的 depends 会并行运行(release:full 依赖项为 [preflight, version]):preflight 和 version 会发生竞争。如果 version 修改了工作树(例如上文提到的锁文件级联更新),preflight 可能会在执行过程中报告失败,而 version 仍会完成,从而留下不可撤销的标签和 GitHub release,但尚未运行 release:crates/verify/postflight。恢复方法:修复脏状态,然后手动运行剩余阶段(release:crates → release:verify → release:postflight)——不要重新运行 release:full,否则会再次尝试运行 semantic-release。
release:verify 对 crates.io API 使用简单 grep 导致误报:如果 verify 的实现采用 if curl ... | grep -q "version" 这种形式,也会匹配 API 的 错误 响应,因为 JSON 错误详情中含有单词 "version"(例如,"crate <name> does not have a version <X.Y.Z>")。结果:即使实际的 cargo publish 失败,每次发布运行仍会报告“✓ published on crates.io”。此问题是在一段持续多版本、历时数天的静默失败后发现的:所有已标记的版本都未出现在 crates.io 上,但 verify 却报告成功。修复方法:匹配仅在成功响应中出现的唯一 JSON 结构 "num":"<exact-version>"(或者使用 Python 解析 JSON,避免 TOML 的转义规则破坏 run = """ ... """ 块中的引号)。未匹配时必须硬失败,并记录实际 API 响应。参考修复:
RESPONSE=$(curl -s "https://crates.io/api/v1/crates/<crate>/${VERSION}")
PUBLISHED_NUM=$(echo "$RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('version',{}).get('num',''))" 2>/dev/null || echo "")
if [[ "$PUBLISHED_NUM" == "$VERSION" ]]; then
echo "✓ <crate> v${VERSION} confirmed on crates.io"
else
echo "⚠ <crate> v${VERSION} NOT on crates.io (API returned: '${PUBLISHED_NUM:-error}')"
echo " raw: $(echo "$RESPONSE" | head -c 200)"
exit 1
fi
release:full 静默吞掉 crates 发布失败:任何采用 mise run release:crates || { echo "non-fatal" } 形式的编排模式,都会屏蔽实际的 cargo publish 错误,并继续执行,造成表面成功的假象。再加上上述 verify 误报问题,可能让多个版本的发布缺失情况被掩盖数天。Crates 发布失败必须硬失败;操作人员应在诊断问题(令牌、网络、注册表速率限制等)后手动运行 release:crates。将任何吞掉错误的 || 替换为直接调用,不要添加包装。
Schema 漂移门禁解析器在缩进的 ) 处退出:形如 awk '... in_table { if ($0 ~ /^[[:space:]]*\)/) { in_table = 0; exit } ... }' 的解析器会在表格中途截断,因为某列的多行 DEFAULT 表达式可能会在单独一行的缩进位置出现右括号(例如嵌套的 multiIf(\n ...,\n ) 或算术分组的闭合括号)。后面的列会被静默漏掉,并在 live-CH 端被误报为漂移。ClickHouse 的格式约定是,实际的表格结尾 ) 位于第 0 列——将退出条件改为 ^\)(不带前导空格)即可确保正确。
pre-push 门禁中的并行 SSH ControlMaster 竞态:当多个 mise 任务并行(depends)打开 SSH 连接时,未能抢到连接的任务会向 stderr 打印 ControlSocket /Users/.../control-host:22 already exists, disabling multiplexing。如果门禁脚本使用 ssh ... 2>&1(将 stderr 合并到 stdout),这条警告就会泄漏到数据管道,并导致基于标识符格式的健全性检查误报“额外”条目。修复方法:将 SSH 的 stderr 重定向到 /dev/null(提取列时不需要它;真正的错误会通过下游显式传播退出码来显示),并添加一道纵深防御过滤器 grep -E '^[a-zA-Z_][a-zA-Z0-9_]*$',这样即使将来有其他 stderr 路径泄漏,也只有符合有效标识符格式的字符串能通过。
幂等的 git push 返回非零值:如果编排器在 release:version 步骤之后还包含手动执行的 git push --follow-tags origin main 步骤(此时 semantic-release 的 @semantic-release/git 插件已经推送过),那么在重新推送已是最新的分支和现有标签时可能会失败。应将这种情况视为成功:推送前通过 [[ $(git rev-parse HEAD) == $(git rev-parse origin/main) ]] 检查,并且只有在 git ls-remote --tags origin "refs/tags/$LATEST_TAG" 返回空结果时才推送最新标签。否则,即使发布实际上已成功,包装脚本也会以非零值退出,污染成功/失败信号。
git stash -u 会使 WIP .gitignore 忽略的目录重新显现,导致预检失败(PII 风险):如果脏工作树包含未提交的 .gitignore 更改,且这些更改用于忽略未跟踪目录,那么 git stash -u 会将 .gitignore 恢复到已提交状态——这会_取消忽略_这些目录,并将它们显示为 ?? 未跟踪文件。随后,预检的干净工作树门禁(通常只豁免 archive/sessions/ 和 node_modules/)就会因此失败;在临床/PII 仓库中,这还会导致敏感目录(例如 correspondence/、site/、cdanet/)暂时暴露,可能被意外执行的 git add -A 添加。根本原因:未提交的 .gitignore 是_承载关键功能的基础设施_,而非功能 WIP——将其存入 stash 会反转忽略状态。修复方法:分开处理。将 .gitignore 清理工作(以及它引用的任何受跟踪配套文件,例如不含机密的部署脚本)作为单独的 chore: 提交提交,这样忽略规则就会保持生效,工作树也会保持干净;然后使用带路径规格的 git stash push -- <files> 仅存入真正的功能代码(不要使用 -u,否则目录会重新显现)。发布后,git stash pop 会恢复功能 WIP。2026-06-02 已在一个临床 PII 仓库中验证:直接执行 git stash -u 暴露了三个 PII 目录和一个本机 TOML 覆盖文件;恢复 stash 后,先单独提交 .gitignore 和它引用的不含机密的部署脚本,再按路径规格存入功能文件,最终预检通过,且发布范围正确。
第 3 步:执行
零提交门禁(先检查):如果 git log --oneline "$(git describe --tags --abbrev=0)..HEAD" 为空且工作树干净,就表示没有可发布内容——release:full 在 semantic-release 中会空操作。报告 HEAD 与最新标签相同,并提供实用的替代方案:mise run release:status(生成报告),或仅运行流水线的同步 + 验证阶段(mise run release:sync && mise run release:verify),以再次确认实时运行时产物(marketplace 克隆、插件缓存、已安装/已启用列表、已同步命令)与已发布版本完全一致。证据(2026-07-19):在一次发布完成约 30 分钟后,于 cc-skills 上调用;自标签以来没有提交;操作者选择了同步 + 验证——确认四个产物存储中的全部 39 个插件一致,避免了无意义的空操作流水线运行。
# Pre-release sync
git pull origin main
# Check for unpushed commits
git log --oneline @{u}..HEAD
# (cc-skills only) Preemptively prune leaked marketplace-path hook entries.
# This recurs across sessions — see Known Issues. Running this BEFORE
# release:full saves a preflight-fail/retry round trip. No-op if clean.
[[ -x ./scripts/sync-hooks-to-settings.sh ]] && ./scripts/sync-hooks-to-settings.sh
# Ensure GH_TOKEN is in the env — release:preflight checks `[ -n "$GH_TOKEN" ]`
# but many repos (incl. cc-skills) do NOT define it in .mise.toml [env]; auth
# lives in the gh keyring instead. Source it for the run. The Process Storm
# Guard blocks `$(gh auth token)` as a gh-recursion pattern, so the
# `# PROCESS-STORM-OK` escape hatch is REQUIRED here (this is a one-shot
# interactive release step, not a hook/credential-helper — the intended use).
if [ -z "${GH_TOKEN:-}" ]; then
export GH_TOKEN="$(gh auth token)" && export GITHUB_TOKEN="$GH_TOKEN" # PROCESS-STORM-OK
fi
# Route by flags
mise run release:full # default
mise run release:dry # --dry
mise run release:status # --status
如果工作目录不干净:先提交相关更改,或暂存未完成的工作。注意:如果未提交更改包含 .gitignore 变更,请将其视为关键变更——将其作为 chore: 提交,而不要暂存,因为 git stash -u 会还原 .gitignore,并重新显示其中忽略的目录(预检随后会在这些目录上失败;存在 PII 风险——请参阅已知问题)。仅使用路径规格暂存真正的功能代码:git stash push -- <files>。如果存在锁文件漂移,则重置:
git diff --name-only | grep -E '(uv\.lock|package-lock\.json|Cargo\.lock|bun\.lockb)$' | xargs -r git checkout --
执行后复盘
此技能完成后,请先进行复盘,再结束任务:
- 确认自身位置。——编辑前,找到此 SKILL.md 的规范路径。
- 哪里失败了?——修正导致失败的指令。
- 哪些做法比预期更有效?——将其提升为推荐做法。
- 哪里出现了偏差?——修正任何与实际情况不再相符的脚本、参考资料或依赖项。
- 记录下来。——添加演进日志条目,记录触发原因、修复内容和证据。
不要拖延。下次调用会继承你留下的一切。