Files
superpowers-zh/scripts/sync-plugin-version.js
AI不止语 48c4d0d417 fix(scripts): sync-plugin-version 支持嵌套字段路径 (#23)
补上之前简化版未实现的 plugins.0.version 路径,把
.claude-plugin/marketplace.json 纳入版本同步目标。

修复 marketplace.json 卡在 1.1.8 的老漂移(自 v1.1.8 起没动过):
plugins[0].version 1.1.8 -> 1.2.1(追上其他 4 个 manifest)。

实现:
- TARGETS 改为对象数组 { path, field },对齐上游 .version-bump.json 格式
- field='version' 走顶层 regex(保留原行为)
- field='plugins.0.version' 走嵌套 regex(锚定到 plugins 数组首项)
- 都用 regex 替换而非 JSON.stringify,保持原文件格式(缩进/数组写法等)

测试:
- 升级场景 1.2.1 → 1.3.0:4 个 manifest 全部同步
- 幂等性:版本相同时输出 "already at"
- 边界:marketplace.json 其他字段完全未动(diff 仅 version 一行)
- npm pack:90 文件 228KB 不变
2026-05-10 22:48:09 +08:00

58 lines
2.3 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' },
];
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}`);