Read SKILL.md content for a specific skill.
(agent_id, skill_name)
| 286 | |
| 287 | |
| 288 | def read_skill_content(agent_id, skill_name): |
| 289 | """Read SKILL.md content for a specific skill.""" |
| 290 | # 输入校验:防止路径遍历 |
| 291 | if not _SAFE_NAME_RE.match(agent_id) or not _SAFE_NAME_RE.match(skill_name): |
| 292 | return {'ok': False, 'error': '参数含非法字符'} |
| 293 | cfg = read_json(DATA / 'agent_config.json', {}) |
| 294 | agents = cfg.get('agents', []) |
| 295 | ag = next((a for a in agents if a.get('id') == agent_id), None) |
| 296 | if not ag: |
| 297 | return {'ok': False, 'error': f'Agent {agent_id} 不存在'} |
| 298 | sk = next((s for s in ag.get('skills', []) if s.get('name') == skill_name), None) |
| 299 | if not sk: |
| 300 | return {'ok': False, 'error': f'技能 {skill_name} 不存在'} |
| 301 | skill_path = pathlib.Path(sk.get('path', '')).resolve() |
| 302 | # 路径遍历保护:确保路径在 OCLAW_HOME 或项目目录下 |
| 303 | allowed_roots = (OCLAW_HOME.resolve(), BASE.parent.resolve()) |
| 304 | if not any(str(skill_path).startswith(str(root)) for root in allowed_roots): |
| 305 | return {'ok': False, 'error': '路径不在允许的目录范围内'} |
| 306 | if not skill_path.exists(): |
| 307 | return {'ok': True, 'name': skill_name, 'agent': agent_id, 'content': '(SKILL.md 文件不存在)', 'path': str(skill_path)} |
| 308 | try: |
| 309 | content = skill_path.read_text() |
| 310 | return {'ok': True, 'name': skill_name, 'agent': agent_id, 'content': content, 'path': str(skill_path)} |
| 311 | except Exception as e: |
| 312 | return {'ok': False, 'error': str(e)} |
| 313 | |
| 314 | |
| 315 | def add_skill_to_agent(agent_id, skill_name, description, trigger=''): |