Files
superpowers-zh/scripts/sync-plugin-version.js
AI不止语 c5b4fa446b chore: release v1.4.0 — 上游漂移 P0 全量修复 + 防回归基建 (#32)
跟 PR #28 + #30 + #31 一起构成 v1.4.0 的完整内容。本 PR 仅做发布层
(版本号 bump + plugin manifest 同步 + release notes),不动 skill 内容。

版本号 1.3.0 → 1.4.0:
- package.json
- .claude-plugin/plugin.json + marketplace.json
- .cursor-plugin/plugin.json
- .codex-plugin/plugin.json
- gemini-extension.json(之前卡在 1.1.6,本次顺带追上)

工具链小修:
- scripts/sync-plugin-version.js TARGETS 加入 gemini-extension.json
  (之前漏掉,是 gemini-extension.json 长期卡在老版本的根因)
- package.json 的 version 钩子 git add 列表加上 gemini-extension.json

RELEASE-NOTES.zh.md 新增 v1.4.0 段,按"上游同步"性质分组列出 9 项
修复内容,明确标注每项的上游 ref + 本 fork PR 号。

注意:本 PR 应在 #28 + #30 + #31 merge 之后才 merge —— 顺序错了
会导致 release notes 描述的 PR 在 git log 里还没有。

不影响:
- 上游 marketplace 安装路径(仍按主站路径正常工作)
- 现有 npm 用户向后兼容(npx superpowers-zh 仍可用)
2026-05-12 18:14:02 +08:00

59 lines
2.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
// 把 package.json 的 version 同步到所有 plugin manifest含嵌套字段
// 由 npm version 钩子触发,跑在 version commit 创建之前。
//
// 设计:用 regex 替换而不是 JSON.parse + stringify目的是保留原文件格式
// (缩进、行内/多行数组、空白等不被破坏)。每种 field 路径对应一个专用 regex。
import { readFileSync, writeFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
// targets 字段对齐上游 .version-bump.json 格式path + field 路径)。
// 顶层用 "version",嵌套用 dot-path如 "plugins.0.version")。
const TARGETS = [
{ path: '.claude-plugin/plugin.json', field: 'version' },
{ path: '.cursor-plugin/plugin.json', field: 'version' },
{ path: '.codex-plugin/plugin.json', field: 'version' },
{ path: '.claude-plugin/marketplace.json', field: 'plugins.0.version' },
{ path: 'gemini-extension.json', field: 'version' },
];
function buildPattern(field) {
if (field === 'version') {
return /("version"\s*:\s*")[^"]+(")/;
}
if (field === 'plugins.0.version') {
// 锚定到 "plugins": [ { ... 第一个对象内的 version 字段
return /("plugins"\s*:\s*\[\s*\{[\s\S]*?"version"\s*:\s*")[^"]+(")/;
}
throw new Error(`Unsupported field path: ${field}`);
}
function readField(json, field) {
if (field === 'version') return json.version;
if (field === 'plugins.0.version') return json.plugins?.[0]?.version;
throw new Error(`Unsupported field path: ${field}`);
}
let touched = 0;
for (const { path: rel, field } of TARGETS) {
const fullPath = resolve(root, rel);
const text = readFileSync(fullPath, 'utf8');
const json = JSON.parse(text);
const current = readField(json, field);
if (current === pkg.version) continue;
const pattern = buildPattern(field);
const updated = text.replace(pattern, `$1${pkg.version}$2`);
if (updated === text) {
throw new Error(`未能在 ${rel} 中定位字段 ${field}`);
}
writeFileSync(fullPath, updated, 'utf8');
console.log(` ${rel} (${field}): ${current} -> ${pkg.version}`);
touched++;
}
if (touched === 0) console.log(` plugin manifests already at ${pkg.version}`);