feat: 新增 code_stats Skill,修复 Skill handler 参数解析
- 新增 skills/code_stats.py: Python Skill 示例,统计代码量 - 修复 unified_tool_manager: Skill handler 支持 key=value 参数格式 - Skill 协议测试通过: 直接调用 + MCP 调用均正常 本次更新由 mimo 自动化执行,与开发者无关。
This commit is contained in:
1 parent
2af7004247
commit
4c41cf4f99
2 files changed
+150
-1
No files matched your search
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
代码统计 Skill - 统计项目代码行数、文件数等
|
||||
"""
|
||||
import os
|
||||
from skills.base import Skill, SkillResult, SkillParameter, ParameterType
|
||||
|
||||
|
||||
class CodeStatsSkill(Skill):
|
||||
"""代码统计技能 - 统计目录中的代码行数、文件数、注释率等"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "code_stats"
|
||||
self.description = "统计项目代码量:文件数、代码行、注释行、空行、注释率"
|
||||
self.version = "1.0.0"
|
||||
self.author = "mimo"
|
||||
self.tags = ["代码", "统计", "stats", "lines"]
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
return [
|
||||
SkillParameter(
|
||||
name="directory",
|
||||
param_type=ParameterType.STRING,
|
||||
description="要统计的目录路径",
|
||||
required=True
|
||||
),
|
||||
SkillParameter(
|
||||
name="file_pattern",
|
||||
param_type=ParameterType.STRING,
|
||||
description="文件匹配模式,如 *.py",
|
||||
required=False,
|
||||
default="*.py"
|
||||
),
|
||||
]
|
||||
|
||||
def execute(self, **kwargs) -> SkillResult:
|
||||
directory = kwargs.get("directory", ".")
|
||||
file_pattern = kwargs.get("file_pattern", "*.py")
|
||||
|
||||
if not os.path.isdir(directory):
|
||||
return SkillResult(success=False, error=f"目录不存在: {directory}")
|
||||
|
||||
# 确定文件扩展名
|
||||
if file_pattern.startswith("*."):
|
||||
ext = file_pattern[1:]
|
||||
file_filter = lambda f: f.endswith(ext)
|
||||
else:
|
||||
file_filter = lambda f: True
|
||||
|
||||
total_files = 0
|
||||
total_lines = 0
|
||||
total_code = 0
|
||||
total_blank = 0
|
||||
total_comment = 0
|
||||
file_details = []
|
||||
|
||||
skip_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'env'}
|
||||
|
||||
for root, dirs, files in os.walk(directory):
|
||||
dirs[:] = [d for d in dirs if d not in skip_dirs and not d.startswith('.')]
|
||||
|
||||
for filename in sorted(files):
|
||||
if not file_filter(filename):
|
||||
continue
|
||||
|
||||
filepath = os.path.join(root, filename)
|
||||
rel_path = os.path.relpath(filepath, directory)
|
||||
total_files += 1
|
||||
|
||||
file_lines = 0
|
||||
file_code = 0
|
||||
file_blank = 0
|
||||
file_comment = 0
|
||||
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
total_lines += 1
|
||||
file_lines += 1
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
total_blank += 1
|
||||
file_blank += 1
|
||||
elif stripped.startswith('#'):
|
||||
total_comment += 1
|
||||
file_comment += 1
|
||||
else:
|
||||
total_code += 1
|
||||
file_code += 1
|
||||
except (UnicodeDecodeError, PermissionError):
|
||||
continue
|
||||
|
||||
file_details.append({
|
||||
"file": rel_path,
|
||||
"lines": file_lines,
|
||||
"code": file_code,
|
||||
"comment": file_comment,
|
||||
"blank": file_blank,
|
||||
})
|
||||
|
||||
# 按代码行数排序
|
||||
file_details.sort(key=lambda x: x["code"], reverse=True)
|
||||
|
||||
# 构建报告
|
||||
comment_rate = (total_comment / max(total_code, 1)) * 100
|
||||
|
||||
report_lines = [
|
||||
f"📊 代码统计 ({directory})",
|
||||
f"{'─' * 40}",
|
||||
f" 文件数: {total_files}",
|
||||
f" 总行数: {total_lines}",
|
||||
f" 代码行: {total_code}",
|
||||
f" 注释行: {total_comment}",
|
||||
f" 空行: {total_blank}",
|
||||
f" 注释率: {comment_rate:.1f}%",
|
||||
]
|
||||
|
||||
if file_details:
|
||||
report_lines.append(f"\n📄 文件明细 (按代码行数排序):")
|
||||
for fd in file_details[:20]:
|
||||
report_lines.append(
|
||||
f" {fd['file']:40} {fd['code']:5} 行代码"
|
||||
)
|
||||
if len(file_details) > 20:
|
||||
report_lines.append(f" ... 还有 {len(file_details) - 20} 个文件")
|
||||
|
||||
return SkillResult(
|
||||
success=True,
|
||||
message='\n'.join(report_lines),
|
||||
data={
|
||||
"total_files": total_files,
|
||||
"total_lines": total_lines,
|
||||
"total_code": total_code,
|
||||
"total_comment": total_comment,
|
||||
"total_blank": total_blank,
|
||||
"comment_rate": comment_rate,
|
||||
"files": file_details
|
||||
}
|
||||
)
|
||||
+10
-1
@@ -206,11 +206,20 @@ class UnifiedToolManager:
|
||||
kwargs = {}
|
||||
|
||||
# 解析参数
|
||||
if args.strip().startswith('{'):
|
||||
args = args.strip()
|
||||
if args.startswith('{'):
|
||||
try:
|
||||
kwargs = json.loads(args)
|
||||
except json.JSONDecodeError:
|
||||
kwargs = {'operation': args}
|
||||
elif '=' in args:
|
||||
# key=value 格式: "directory=. file_pattern=*.py"
|
||||
for part in args.split():
|
||||
if '=' in part:
|
||||
k, v = part.split('=', 1)
|
||||
kwargs[k.strip()] = v.strip()
|
||||
else:
|
||||
kwargs.setdefault('operation', part)
|
||||
else:
|
||||
kwargs = {'operation': args}
|
||||
|
||||
|
||||
Reference in new issue
Block a user