Files
superpowers-zh/scripts/sync-plugin-version.js
AI不止语 af4c03c1e0 feat(kimi): 新增 Kimi Code harness 支持(对齐上游 v6.0.0 集成模型)
issue #37:Kimi Code 已支持 Skills 能力,希望原生支持。上游 obra/superpowers
在 v6.0.0 已用插件清单模型原生集成 Kimi,本提交把同样的集成方式落到本 fork。

Kimi 走插件清单模型(与 CC plugin 同类),直接指向仓库现有 skills/,
不复制 skill、不建 symlink、不装 hook、无运行时依赖,因此无需改 npx
安装器(安装器面向需要复制 skills 的工具)。

- .kimi-plugin/plugin.json:fork 品牌清单,skills 指向 ./skills/,
  sessionStart.skill = using-superpowers(会话开始自动加载 bootstrap),
  skillInstructions 提供 Kimi 工具映射(AskUserQuestion/TodoList/Agent/
  Skill/Read/Write/Edit/Bash/Grep/Glob/FetchURL/WebSearch,保留上游权威
  英文映射以免破坏真实工具名)
- 版本同步:.version-bump.json 与 scripts/sync-plugin-version.js 双向接入
- docs/README.kimi.md:中文安装/工具映射/排错指南;README.md 工具列表加链接
- tests/kimi/:清单结构测试(适配 fork:name=superpowers-zh、校验版本同步条目)

验证:bash tests/kimi/run-tests.sh 通过;manifest 合法 JSON;版本同步双机制
均含 kimi 条目;scripts/audit.sh 静态校验 0 FAIL;README→docs/README.kimi.md
链接可解析。

注:Kimi 实际 skill 自动触发需在 Kimi Code 内验证(与本 fork 其它 harness
同样限制),清单结构已对齐上游 v6.0.0 经过验证的集成方式。
2026-06-20 02:37:31 +08:00

60 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: '.kimi-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}`);