mirror of
https://github.com/jnMetaCode/superpowers-zh.git
synced 2026-09-02 22:54:06 +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 经过验证的集成方式。
87 lines
2.3 KiB
Bash
Executable File
87 lines
2.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
MANIFEST="$REPO_ROOT/.kimi-plugin/plugin.json"
|
|
|
|
python3 - "$MANIFEST" <<'PY'
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
manifest_path = Path(sys.argv[1])
|
|
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
|
|
|
def assert_equal(actual, expected, label):
|
|
if actual != expected:
|
|
raise AssertionError(f"{label}: expected {expected!r}, got {actual!r}")
|
|
|
|
def assert_present(text, needle, label):
|
|
if needle not in text:
|
|
raise AssertionError(f"{label}: missing {needle!r}")
|
|
|
|
assert_equal(manifest.get("name"), "superpowers-zh", "plugin name")
|
|
assert_equal(manifest.get("skills"), "./skills/", "skills path")
|
|
assert_equal(
|
|
manifest.get("sessionStart", {}).get("skill"),
|
|
"using-superpowers",
|
|
"sessionStart.skill",
|
|
)
|
|
|
|
instructions = manifest.get("skillInstructions")
|
|
if not isinstance(instructions, str) or not instructions.strip():
|
|
raise AssertionError("skillInstructions must be a non-empty string")
|
|
|
|
for token in [
|
|
"AskUserQuestion",
|
|
"TodoList",
|
|
"Agent",
|
|
"Skill",
|
|
"Read",
|
|
"Write",
|
|
"Edit",
|
|
"Bash",
|
|
"Grep",
|
|
"Glob",
|
|
"FetchURL",
|
|
"WebSearch",
|
|
]:
|
|
assert_present(instructions, token, "skillInstructions")
|
|
|
|
version_config = json.loads(
|
|
(manifest_path.parents[1] / ".version-bump.json").read_text(encoding="utf-8")
|
|
)
|
|
version_entries = version_config.get("files")
|
|
if not isinstance(version_entries, list):
|
|
raise AssertionError(".version-bump.json must contain files list")
|
|
|
|
if not any(
|
|
entry.get("path") == ".kimi-plugin/plugin.json" and entry.get("field") == "version"
|
|
for entry in version_entries
|
|
if isinstance(entry, dict)
|
|
):
|
|
raise AssertionError(
|
|
".version-bump.json must update .kimi-plugin/plugin.json version"
|
|
)
|
|
|
|
unsupported_fields = [
|
|
"tools",
|
|
"commands",
|
|
"hooks",
|
|
"apps",
|
|
"inject",
|
|
"configFile",
|
|
"config_file",
|
|
"bootstrap",
|
|
]
|
|
present_unsupported = sorted(field for field in unsupported_fields if field in manifest)
|
|
if present_unsupported:
|
|
raise AssertionError(
|
|
"unsupported Kimi runtime fields present: "
|
|
+ ", ".join(present_unsupported)
|
|
)
|
|
|
|
print("Kimi plugin manifest looks good")
|
|
PY
|