mirror of
https://github.com/jnMetaCode/superpowers-zh.git
synced 2026-09-03 07:23:56 +08:00
跟 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 仍可用)
59 lines
2.4 KiB
JavaScript
59 lines
2.4 KiB
JavaScript
#!/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}`);
|