mirror of
https://github.com/jnMetaCode/superpowers-zh.git
synced 2026-09-03 07:23:56 +08:00
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 经过验证的集成方式。
60 lines
2.4 KiB
JavaScript
60 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: '.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}`);
|