feat: add bilingual support (zh/en) for research skills
- Rename skills/research to skills/research-en (English version) - Add skills/research-zh (Chinese version with SKILL.md structure) - Update README.md with bilingual documentation - Add web-search-agent.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
92b47e006e
commit
10377e95e2
@@ -0,0 +1,143 @@
|
||||
---
|
||||
allowed-tools: Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
description: Conduct preliminary research on a topic and generate research outline. For academic research, benchmark research, technology selection, etc.
|
||||
---
|
||||
|
||||
# Research Skill - Preliminary Research
|
||||
|
||||
## Trigger
|
||||
`/research <topic>`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Generate Initial Framework from Model Knowledge
|
||||
Based on topic, use model's existing knowledge to generate:
|
||||
- Main research objects/items list in this domain
|
||||
- Suggested research field framework
|
||||
|
||||
Output {step1_output}, use AskUserQuestion to confirm:
|
||||
- Need to add/remove items?
|
||||
- Does field framework meet requirements?
|
||||
|
||||
### Step 2: Web Search Supplement
|
||||
Use AskUserQuestion to ask for time range (e.g., last 6 months, since 2024, unlimited).
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: User input research topic
|
||||
- `{YYYY-MM-DD}`: Current date
|
||||
- `{step1_output}`: Complete output from Step 1
|
||||
- `{time_range}`: User specified time range
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
Launch 1 web-search-agent (background), **Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research topic: {topic}
|
||||
Current date: {YYYY-MM-DD}
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
{step1_output}
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for {topic} related items within {time_range} and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching AI Coding History):
|
||||
```
|
||||
## Task
|
||||
Research topic: AI Coding History
|
||||
Current date: 2025-12-30
|
||||
|
||||
Based on the following initial framework, supplement latest items and recommended research fields.
|
||||
|
||||
## Existing Framework
|
||||
### Items List
|
||||
1. GitHub Copilot: Developed by Microsoft/GitHub, first mainstream AI coding assistant
|
||||
2. Cursor: AI-first IDE, based on VSCode
|
||||
...
|
||||
|
||||
### Field Framework
|
||||
- Basic Info: name, release_date, company
|
||||
- Technical Features: underlying_model, context_window
|
||||
...
|
||||
|
||||
## Goals
|
||||
1. Verify if existing items are missing important objects
|
||||
2. Supplement items based on missing objects
|
||||
3. Continue searching for AI Coding History related items within since 2024 and supplement
|
||||
4. Supplement new fields
|
||||
|
||||
## Output Requirements
|
||||
Return structured results directly (do not write files):
|
||||
|
||||
### Supplementary Items
|
||||
- item_name: Brief explanation (why it should be added)
|
||||
...
|
||||
|
||||
### Recommended Supplementary Fields
|
||||
- field_name: Field description (why this dimension is needed)
|
||||
...
|
||||
|
||||
### Sources
|
||||
- [Source1](url1)
|
||||
- [Source2](url2)
|
||||
```
|
||||
|
||||
### Step 3: Ask User for Existing Fields
|
||||
Use AskUserQuestion to ask if user has existing field definition file, if so read and merge.
|
||||
|
||||
### Step 4: Generate Outline (Separate Files)
|
||||
Merge {step1_output}, {step2_output} and user's existing fields, generate two files:
|
||||
|
||||
**outline.yaml** (items + config):
|
||||
- topic: Research topic
|
||||
- items: Research objects list
|
||||
- execution:
|
||||
- batch_size: Number of parallel agents (confirm with AskUserQuestion)
|
||||
- items_per_agent: Items per agent (confirm with AskUserQuestion)
|
||||
- output_dir: Results output directory (default: ./results)
|
||||
|
||||
**fields.yaml** (field definitions):
|
||||
- Field categories and definitions
|
||||
- Each field's name, description, detail_level
|
||||
- detail_level hierarchy: brief -> moderate -> detailed
|
||||
- uncertain: Uncertain fields list (reserved field, auto-filled in deep phase)
|
||||
|
||||
### Step 5: Output and Confirm
|
||||
- Create directory: `./{topic_slug}/`
|
||||
- Save: `outline.yaml` and `fields.yaml`
|
||||
- Show to user for confirmation
|
||||
|
||||
## Output Path
|
||||
```
|
||||
{current_working_directory}/{topic_slug}/
|
||||
├── outline.yaml # items list + execution config
|
||||
└── fields.yaml # field definitions
|
||||
```
|
||||
|
||||
## Follow-up Commands
|
||||
- `/research-add-items` - Supplement items
|
||||
- `/research-add-fields` - Supplement fields
|
||||
- `/research-deep` - Start deep research
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: Add field definitions to existing research outline.
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Add Fields - Supplement Research Fields
|
||||
|
||||
## Trigger
|
||||
`/research-add-fields`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Fields File
|
||||
Find `*/fields.yaml` file in current working directory, auto-read existing fields definitions.
|
||||
|
||||
### Step 2: Get Supplement Source
|
||||
Ask user to choose:
|
||||
- **A. User direct input**: User provides field names and descriptions
|
||||
- **B. Web Search**: Launch agent to search common fields in this domain
|
||||
|
||||
### Step 3: Display and Confirm
|
||||
- Display suggested new fields list
|
||||
- User confirms which fields to add
|
||||
- User specifies field category and detail_level
|
||||
|
||||
### Step 4: Save Update
|
||||
Append confirmed fields to fields.yaml, save file.
|
||||
|
||||
## Output
|
||||
Updated `{topic}/fields.yaml` file (in-place modification, requires user confirmation)
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
description: Add items (research objects) to existing research outline.
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task, AskUserQuestion
|
||||
---
|
||||
|
||||
# Research Add Items - Supplement Research Objects
|
||||
|
||||
## Trigger
|
||||
`/research-add-items`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, auto-read.
|
||||
|
||||
### Step 2: Get Supplement Sources in Parallel
|
||||
Simultaneously:
|
||||
- **A. Ask user**: What items to supplement? Any specific names?
|
||||
- **B. Ask if Web Search needed**: Launch agent to search for more items?
|
||||
|
||||
### Step 3: Merge and Update
|
||||
- Append new items to outline.yaml
|
||||
- Display to user for confirmation
|
||||
- Avoid duplicates
|
||||
- Save updated outline
|
||||
|
||||
## Output
|
||||
Updated `{topic}/outline.yaml` file (in-place modification)
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
description: Read research outline, launch independent agent for each item for deep research. Disable task output.
|
||||
allowed-tools: Bash, Read, Write, Glob, WebSearch, Task
|
||||
---
|
||||
|
||||
# Research Deep - Deep Research
|
||||
|
||||
## Trigger
|
||||
`/research-deep`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Auto-locate Outline
|
||||
Find `*/outline.yaml` file in current working directory, read items list, execution config (including items_per_agent).
|
||||
|
||||
### Step 2: Resume Check
|
||||
- Check completed JSON files in output_dir
|
||||
- Skip completed items
|
||||
|
||||
### Step 3: Batch Execution
|
||||
- Batch by batch_size (need user approval before next batch)
|
||||
- Each agent handles items_per_agent items
|
||||
- Launch web-search-agent (background parallel, disable task output)
|
||||
|
||||
**Parameter Retrieval**:
|
||||
- `{topic}`: topic field from outline.yaml
|
||||
- `{item_name}`: item's name field
|
||||
- `{item_related_info}`: item's complete yaml content (name + category + description etc.)
|
||||
- `{output_dir}`: execution.output_dir from outline.yaml (default: ./results)
|
||||
- `{fields_path}`: absolute path to {topic}/fields.yaml
|
||||
- `{output_path}`: absolute path to {output_dir}/{item_name}.json
|
||||
|
||||
**Hard Constraint**: The following prompt must be strictly reproduced, only replacing variables in {xxx}, do not modify structure or wording.
|
||||
|
||||
**Prompt Template**:
|
||||
```python
|
||||
prompt = f"""## Task
|
||||
Research {item_related_info}, output structured JSON to {output_path}
|
||||
|
||||
## Field Definitions
|
||||
Read {fields_path} to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in Chinese (research can be in English, but final JSON values in Chinese)
|
||||
|
||||
## Output Path
|
||||
{output_path}
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.claude/commands/research/validate_json.py -f {fields_path} -j {output_path}
|
||||
Task is complete only after validation passes.
|
||||
"""
|
||||
```
|
||||
|
||||
**One-shot Example** (assuming researching GitHub Copilot):
|
||||
```
|
||||
## Task
|
||||
Research name: GitHub Copilot
|
||||
category: International Product
|
||||
description: Developed by Microsoft/GitHub, first mainstream AI coding assistant, ~40% market share, output structured JSON to /home/weizhena/AIcoding/aicoding-history/results/GitHub_Copilot.json
|
||||
|
||||
## Field Definitions
|
||||
Read /home/weizhena/AIcoding/aicoding-history/fields.yaml to get all field definitions
|
||||
|
||||
## Output Requirements
|
||||
1. Output JSON according to fields defined in fields.yaml
|
||||
2. Mark uncertain field values with [uncertain]
|
||||
3. Add uncertain array at the end of JSON, listing all uncertain field names
|
||||
4. All field values must be in Chinese (research can be in English, but final JSON values in Chinese)
|
||||
|
||||
## Output Path
|
||||
/home/weizhena/AIcoding/aicoding-history/results/GitHub_Copilot.json
|
||||
|
||||
## Validation
|
||||
After completing JSON output, run validation script to ensure complete field coverage:
|
||||
python ~/.claude/commands/research/validate_json.py -f /home/weizhena/AIcoding/aicoding-history/fields.yaml -j /home/weizhena/AIcoding/aicoding-history/results/GitHub_Copilot.json
|
||||
Task is complete only after validation passes.
|
||||
```
|
||||
|
||||
### Step 4: Wait and Monitor
|
||||
- Wait for current batch to complete
|
||||
- Launch next batch
|
||||
- Display progress
|
||||
|
||||
### Step 5: Summary Report
|
||||
After all complete, output:
|
||||
- Completion count
|
||||
- Failed/uncertain marked items
|
||||
- Output directory
|
||||
|
||||
## Agent Config
|
||||
- Background execution: Yes
|
||||
- Task Output: Disabled (agent has explicit output file when complete)
|
||||
- Resume support: Yes
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
description: Summarize deep research results into markdown report, cover all fields, skip uncertain values.
|
||||
allowed-tools: Read, Write, Glob, Bash
|
||||
---
|
||||
|
||||
# Research Report - Summary Report
|
||||
|
||||
## Trigger
|
||||
`/research-report`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Locate Results Directory
|
||||
Find `*/outline.yaml` in current working directory, read topic and output_dir config.
|
||||
|
||||
### Step 2: Scan Optional Summary Fields
|
||||
Read all JSON results, extract fields suitable for TOC display (numeric, short metrics), e.g.:
|
||||
- github_stars
|
||||
- google_scholar_cites
|
||||
- swe_bench_score
|
||||
- user_scale
|
||||
- valuation
|
||||
- release_date
|
||||
|
||||
Use AskUserQuestion to ask user:
|
||||
- Which fields to display in TOC besides item name?
|
||||
- Provide dynamic options list (based on actual fields in JSON)
|
||||
|
||||
### Step 3: Generate Python Conversion Script
|
||||
Generate `generate_report.py` in `{topic}/` directory, script requirements:
|
||||
- Read all JSON from output_dir
|
||||
- Read fields.yaml to get field structure
|
||||
- Cover all field values from each JSON
|
||||
- Skip fields with values containing [uncertain]
|
||||
- Skip fields listed in uncertain array
|
||||
- Generate markdown report format: Table of contents (with anchor links + user-selected summary fields) + Detailed content (by field category)
|
||||
- Save to `{topic}/report.md`
|
||||
|
||||
**TOC Format Requirements**:
|
||||
- Must include every item
|
||||
- Each item displays: number, name (anchor link), user-selected summary fields
|
||||
- Example: `1. [GitHub Copilot](#github-copilot) - Stars: 10k | Score: 85%`
|
||||
|
||||
#### Script Technical Requirements (Must Follow)
|
||||
|
||||
**1. JSON Structure Compatibility**
|
||||
Support two JSON structures:
|
||||
- Flat structure: Fields directly at top level `{"name": "xxx", "release_date": "xxx"}`
|
||||
- Nested structure: Fields in category sub-dict `{"basic_info": {"name": "xxx"}, "technical_features": {...}}`
|
||||
|
||||
Field lookup order: Top level -> category mapping key -> Traverse all nested dicts
|
||||
|
||||
**2. Category Multi-language Mapping**
|
||||
fields.yaml category names and JSON keys can be any combination (CN-CN, CN-EN, EN-CN, EN-EN). Must establish bidirectional mapping:
|
||||
```python
|
||||
CATEGORY_MAPPING = {
|
||||
"Basic Info": ["basic_info", "Basic Info"],
|
||||
"Technical Features": ["technical_features", "technical_characteristics", "Technical Features"],
|
||||
"Performance Metrics": ["performance_metrics", "performance", "Performance Metrics"],
|
||||
"Milestone Significance": ["milestone_significance", "milestones", "Milestone Significance"],
|
||||
"Business Info": ["business_info", "commercial_info", "Business Info"],
|
||||
"Competition & Ecosystem": ["competition_ecosystem", "competition", "Competition & Ecosystem"],
|
||||
"History": ["history", "History"],
|
||||
"Market Positioning": ["market_positioning", "market", "Market Positioning"],
|
||||
}
|
||||
```
|
||||
|
||||
**3. Complex Value Formatting**
|
||||
- list of dicts (e.g., key_events, funding_history): Format each dict as one line, separate kv with ` | `
|
||||
- Normal list: Short lists joined with comma, long lists displayed with line breaks
|
||||
- Nested dict: Recursive formatting, display with semicolon or line breaks
|
||||
- Long text strings (over 100 chars): Add line breaks `<br>` or use blockquote format for readability
|
||||
|
||||
**4. Extra Fields Collection**
|
||||
Collect fields that exist in JSON but not defined in fields.yaml, put in "Other Info" category. Note to filter:
|
||||
- Internal fields: `_source_file`, `uncertain`
|
||||
- Nested structure top-level keys: `basic_info`, `technical_features` etc.
|
||||
- `uncertain_fields` list: Display each field name on separate line, don't compress into one line
|
||||
|
||||
**5. Uncertain Value Skipping**
|
||||
Skip conditions:
|
||||
- Field value contains `[uncertain]` string
|
||||
- Field name is in `uncertain` array
|
||||
- Field value is None or empty string
|
||||
|
||||
### Step 4: Execute Script
|
||||
Run `python {topic}/generate_report.py`
|
||||
|
||||
## Output
|
||||
- `{topic}/generate_report.py` - Conversion script
|
||||
- `{topic}/report.md` - Summary report
|
||||
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
JSON字段验证脚本
|
||||
验证JSON文件是否完整覆盖fields.yaml中定义的所有字段
|
||||
"""
|
||||
|
||||
import json
|
||||
import yaml
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Set, Any, Tuple
|
||||
|
||||
# Category中英文映射
|
||||
CATEGORY_MAPPING = {
|
||||
"基本信息": ["basic_info", "基本信息"],
|
||||
"技术特性": ["technical_features", "technical_characteristics", "技术特性"],
|
||||
"性能指标": ["performance_metrics", "performance", "性能指标"],
|
||||
"里程碑意义": ["milestone_significance", "milestones", "里程碑意义"],
|
||||
"商业信息": ["business_info", "commercial_info", "商业信息"],
|
||||
"竞争与生态": ["competition_ecosystem", "competition", "竞争与生态"],
|
||||
"历史沿革": ["history", "历史沿革"],
|
||||
"市场定位": ["market_positioning", "market", "市场定位"],
|
||||
}
|
||||
|
||||
|
||||
def load_fields_yaml(fields_path: Path) -> Tuple[Set[str], Set[str], Dict[str, str]]:
|
||||
"""
|
||||
加载fields.yaml,返回:
|
||||
- all_fields: 所有字段名集合
|
||||
- required_fields: required=true的字段名集合
|
||||
- field_categories: 字段名到类别的映射
|
||||
"""
|
||||
with open(fields_path, 'r', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
all_fields = set()
|
||||
required_fields = set()
|
||||
field_categories = {}
|
||||
|
||||
for category_info in data.get("field_categories", []):
|
||||
category_name = category_info["category"]
|
||||
for field in category_info.get("fields", []):
|
||||
field_name = field["name"]
|
||||
all_fields.add(field_name)
|
||||
field_categories[field_name] = category_name
|
||||
if field.get("required", False):
|
||||
required_fields.add(field_name)
|
||||
|
||||
return all_fields, required_fields, field_categories
|
||||
|
||||
|
||||
def extract_json_fields(data: Dict, category_mapping: Dict = None) -> Set[str]:
|
||||
"""
|
||||
从JSON中提取所有字段名(支持扁平和嵌套结构)
|
||||
"""
|
||||
if category_mapping is None:
|
||||
category_mapping = CATEGORY_MAPPING
|
||||
|
||||
# 获取所有可能的嵌套key
|
||||
nested_keys = set()
|
||||
for keys in category_mapping.values():
|
||||
nested_keys.update(keys)
|
||||
|
||||
fields = set()
|
||||
|
||||
def collect_fields(d: Dict, is_top_level: bool = True):
|
||||
for k, v in d.items():
|
||||
# 跳过内部字段
|
||||
if k in {"_source_file", "uncertain"}:
|
||||
continue
|
||||
# 如果是嵌套结构的顶级key,递归进入
|
||||
if is_top_level and k in nested_keys:
|
||||
if isinstance(v, dict):
|
||||
collect_fields(v, is_top_level=False)
|
||||
else:
|
||||
fields.add(k)
|
||||
if isinstance(v, dict):
|
||||
collect_fields(v, is_top_level=False)
|
||||
|
||||
collect_fields(data)
|
||||
return fields
|
||||
|
||||
|
||||
def validate_json(json_path: Path, all_fields: Set[str], required_fields: Set[str],
|
||||
field_categories: Dict[str, str]) -> Dict:
|
||||
"""
|
||||
验证单个JSON文件
|
||||
返回验证结果字典
|
||||
"""
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
json_fields = extract_json_fields(data)
|
||||
|
||||
# 计算覆盖情况
|
||||
covered = all_fields & json_fields
|
||||
missing = all_fields - json_fields
|
||||
extra = json_fields - all_fields
|
||||
|
||||
# 分类缺失字段
|
||||
missing_required = missing & required_fields
|
||||
missing_optional = missing - required_fields
|
||||
|
||||
# 按类别分组缺失字段
|
||||
missing_by_category = {}
|
||||
for field in missing:
|
||||
cat = field_categories.get(field, "未知")
|
||||
if cat not in missing_by_category:
|
||||
missing_by_category[cat] = []
|
||||
missing_by_category[cat].append(field)
|
||||
|
||||
return {
|
||||
"file": json_path.name,
|
||||
"total_defined": len(all_fields),
|
||||
"covered": len(covered),
|
||||
"missing": len(missing),
|
||||
"extra": len(extra),
|
||||
"coverage_rate": len(covered) / len(all_fields) * 100 if all_fields else 100,
|
||||
"missing_required": list(missing_required),
|
||||
"missing_optional": list(missing_optional),
|
||||
"missing_by_category": missing_by_category,
|
||||
"extra_fields": list(extra),
|
||||
"valid": len(missing_required) == 0, # required字段全覆盖则valid
|
||||
}
|
||||
|
||||
|
||||
def print_result(result: Dict, verbose: bool = True):
|
||||
"""打印验证结果"""
|
||||
status = "PASS" if result["valid"] else "FAIL"
|
||||
print(f"\n{'='*60}")
|
||||
print(f"[{status}] {result['file']}")
|
||||
print(f"{'='*60}")
|
||||
print(f"覆盖率: {result['coverage_rate']:.1f}% ({result['covered']}/{result['total_defined']})")
|
||||
|
||||
if result["missing_required"]:
|
||||
print(f"\n[ERROR] 缺失必需字段 ({len(result['missing_required'])}):")
|
||||
for field in result["missing_required"]:
|
||||
print(f" - {field}")
|
||||
|
||||
if verbose and result["missing_optional"]:
|
||||
print(f"\n[WARN] 缺失可选字段 ({len(result['missing_optional'])}):")
|
||||
for cat, fields in result["missing_by_category"].items():
|
||||
optional_fields = [f for f in fields if f not in result["missing_required"]]
|
||||
if optional_fields:
|
||||
print(f" [{cat}]: {', '.join(optional_fields)}")
|
||||
|
||||
if verbose and result["extra_fields"]:
|
||||
print(f"\n[INFO] 额外字段 ({len(result['extra_fields'])}):")
|
||||
print(f" {', '.join(result['extra_fields'][:10])}")
|
||||
if len(result["extra_fields"]) > 10:
|
||||
print(f" ... 及 {len(result['extra_fields']) - 10} 个其他字段")
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="验证JSON文件是否覆盖fields.yaml定义的所有字段")
|
||||
parser.add_argument("--fields", "-f", type=str, help="fields.yaml路径", default="fields.yaml")
|
||||
parser.add_argument("--json", "-j", type=str, nargs="*", help="要验证的JSON文件路径")
|
||||
parser.add_argument("--dir", "-d", type=str, help="JSON文件目录", default="results")
|
||||
parser.add_argument("--quiet", "-q", action="store_true", help="只显示摘要")
|
||||
args = parser.parse_args()
|
||||
|
||||
# 定位fields.yaml
|
||||
fields_path = Path(args.fields)
|
||||
if not fields_path.exists():
|
||||
# 尝试在当前目录和父目录查找
|
||||
for p in [Path.cwd() / "fields.yaml", Path.cwd().parent / "fields.yaml"]:
|
||||
if p.exists():
|
||||
fields_path = p
|
||||
break
|
||||
|
||||
if not fields_path.exists():
|
||||
print(f"[ERROR] fields.yaml不存在: {fields_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"字段定义文件: {fields_path}")
|
||||
all_fields, required_fields, field_categories = load_fields_yaml(fields_path)
|
||||
print(f"总字段数: {len(all_fields)} (必需: {len(required_fields)}, 可选: {len(all_fields) - len(required_fields)})")
|
||||
|
||||
# 收集JSON文件
|
||||
json_files = []
|
||||
if args.json:
|
||||
json_files = [Path(p) for p in args.json]
|
||||
else:
|
||||
json_dir = Path(args.dir)
|
||||
if json_dir.exists():
|
||||
json_files = sorted(json_dir.glob("*.json"))
|
||||
|
||||
if not json_files:
|
||||
print(f"[WARN] 未找到JSON文件")
|
||||
sys.exit(0)
|
||||
|
||||
# 验证每个文件
|
||||
results = []
|
||||
for json_path in json_files:
|
||||
if not json_path.exists():
|
||||
print(f"[WARN] 文件不存在: {json_path}")
|
||||
continue
|
||||
result = validate_json(json_path, all_fields, required_fields, field_categories)
|
||||
results.append(result)
|
||||
print_result(result, verbose=not args.quiet)
|
||||
|
||||
# 汇总
|
||||
print(f"\n{'='*60}")
|
||||
print("汇总")
|
||||
print(f"{'='*60}")
|
||||
passed = sum(1 for r in results if r["valid"])
|
||||
avg_coverage = sum(r["coverage_rate"] for r in results) / len(results) if results else 0
|
||||
print(f"验证通过: {passed}/{len(results)}")
|
||||
print(f"平均覆盖率: {avg_coverage:.1f}%")
|
||||
|
||||
if passed < len(results):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user