目录结构:parse-skill-to-json—scripts—generate_manifest.json—SKILL.mdname: parse-skill-to-jsondescription: 从 skill.md 和 API 契约文档自动解析并生成 skill-manifest.json。当用户要求生成技能清单、解析 skill 文档为 JSON、生成 manifest、导出技能配置、转换 skill 为结构化数据、生成技能元数据时使用。关键词:manifest、skill-manifest、技能清单、生成 JSON、解析 skill、导出配置、skill 转 JSON、技能元数据、skill.md。使用方式用户提供模块名,例如:为 llmengine 模块生成 skill-manifest.json解析 alarm 的 skill.md 生成 manifest执行步骤1. 获取模块名从用户输入中提取模块名{module-name}(kebab-case 格式)。如果用户未提供,询问用户。2. 验证输入文件确认以下两个文件存在:docs/skills/{module-name}/skill.md— 技能文档(元信息 + 使用指南)docs/modules/{module-name}/tech/03-api-contracts.md— API 契约文档如果文件不存在,提示用户先创建对应文档。3. 执行生成脚本运行通用生成脚本:python .kiro/skills/parse-skill-to-json/scripts/generate_manifest.py{module-name}脚本会自动:解析skill.md中的元信息表格(名称、模块、SDK 入口、最低 API、依赖等)解析03-api-contracts.md中的:对外暴露接口(方法签名 + 参数表格)→ 转为tools列表常量定义表格 → 转为constants字典错误码定义表格 → 转为errorCodes字典组装为标准skill-manifest.json并输出到docs/skills/{module-name}/skill-manifest.json4. 验证输出检查生成的 JSON 是否合法:python-c"import json; json.load(open('docs/skills/{module-name}/skill-manifest.json', encoding='utf-8')); print('✓ JSON 合法')"5. 人工确认提示用户 Review 生成的skill-manifest.json,重点检查:tools中的参数是否完整(脚本从表格自动提取,复杂参数可能需要手动补充)constants分组是否正确errorCodes是否遗漏约束脚本基于 Markdown 表格格式解析,要求 skill.md 和 03-api-contracts.md 遵循项目标准模板自动提取的 tools 参数来自 API 契约中的参数表格,endpoint和httpMethod需要手动补充或在文档中标注生成的 manifest 遵循skill-manifest.json标准 schema不会覆盖已有的手动修改,如果目标文件已存在会提示用户确认#!/usr/bin/env python3""" 通用 skill-manifest.json 生成器 从 skill.md + API 契约文档自动解析并生成 skill-manifest.json。 用法: python generate_manifest.py module-name 示例: python generate_manifest.py llmengine python generate_manifest.py alarm 输入: docs/skills/module/skill.md docs/modules/module/tech/03-api-contracts.md 输出: docs/skills/module/skill-manifest.json """importjsonimportreimportsysfrompathlibimportPath# 项目根目录(从脚本位置向上推导)PROJECT_ROOT=Path(__file__).resolve().parent.parent.parent.parent.parent# ─────────────────────────────────────────────# 通用 Markdown 表格解析# ─────────────────────────────────────────────defparse_md_tables(text:str)-list[dict]:""" 解析 Markdown 中所有表格,返回列表。 每个元素: {"heading": "最近的标题", "headers": [...], "rows": [{...}, ...]} """tables=[]lines=text.split("\n")current_heading=""i=0whileilen(lines):line=lines[i].strip()# 记录最近的标题ifline.startswith("#"):current_heading=re.sub(r"^#+\s*","",line).strip()i+=1continue# 检测表格:当前行是 | 开头,下一行是分隔线if(line.startswith("|")andi+1len(lines)andre.match(r"\s*\|[\s:|-]+\|\s*$",lines[i+1])):headers=[h.strip()forhinline.split("|")[1:-1]]i+=2# 跳过表头和分隔线rows=[]whileilen(lines)andlines[i].strip().startswith("|"):cells=[c.strip()forcinlines[i].strip().split("|")[1:-1]]iflen(cells)==len(headers):rows.append(dict(zip(headers,cells)))i+=1tables.append({"heading":current_heading,"headers":headers,"rows":rows,})continuei+=1returntablesdeffind_table(tables:list[dict],heading_pattern:str)-list[dict]:"""根据标题模式查找表格,返回匹配的行"""fortintables:ifre.search(heading_pattern,t["heading"],re.IGNORECASE):returnt["rows"]return[]deffind_tables(tables:list[dict],heading_pattern:str)-list[dict]:"""根据标题模式查找所有匹配的表格"""return[tfortintablesifre.search(heading_pattern,t["heading"],re.IGNORECASE)]# ─────────────────────────────────────────────# 元信息提取(从 skill.md)# ─────────────────────────────────────────────# 元信息字段映射:skill.md 表格中的"属性"列 → manifest 字段META_FIELD_MAP={"名称":"displayName","技能名称":"displayName","模块":"name","SDK 入口":"sdkEntry","SDK入口":"sdkEntry","包路径":"sdkEntry","入口类":"entryClass","最低 API":"minApi","最低API":"minApi","依赖 AAR":"dependency","依赖AAR":"dependency","构建类型":"buildType","语言":"language",}defextract_meta(skill_text:str)-dict:"""从 skill.md 提取元信息表格"""tables=parse_md_tables(skill_text)meta={}# 查找元信息表格(通常标题含"元信息")meta_rows=find_table(tables,r"元信息")ifnotmeta_rows:# 兜底:查找第一个含"属性|值"列的表格fortintables:ifset(t["headers"])={"属性","值"}:meta_rows=t["rows"]breakforrowinmeta_rows:key=row.get("属性","").strip()val=row.get("值","").strip()field=META_FIELD_MAP.get(key)ifnotfield:continueiffield=="minApi":m=re.search(r"(\d+)",val)ifm:meta[field]=int