feat: devops智能——clone已存在自动pull + 多步任务(克隆→扫描技能)

This commit is contained in:
yumoqing 2026-08-06 14:46:04 +08:00
parent 9c84c3dcbc
commit fb1b65f389

View File

@ -878,29 +878,60 @@ if action == 'send_message':
elif intent_type == 'devops':
# 从自然语言中提取实际命令:剥前缀 + 识别 git URL 自动构造 git clone
cmd = message_text.strip()
import re
import re, os
cmd = re.sub(r'^(执行命令[:]|运行[:]|帮我\s*|克隆仓库\s*|从.*克隆\s*)', '', cmd).strip()
# 如果包含 git@ 或 https://...git 但没有 git clone 前缀,自动补全
repo_url = None
repo_target = None
if re.search(r'(git@[\w.]+:[\w./-]+\.git|https?://[\w./-]+\.git)', cmd):
if not cmd.startswith('git '):
# 提取 URL 和可选目标路径
m = re.search(r'(git@[\w.]+:[\w./-]+\.git|https?://[\w./-]+\.git)', cmd)
repo_url = m.group(0)
rest = cmd[m.end():].strip()
target = rest.split()[0] if rest else ''
if target and not target.startswith('-'):
repo_target = target
cmd = f'git clone {repo_url} {target}'
else:
repo_target = repo_url.rstrip('/').split('/')[-1].replace('.git', '')
cmd = f'git clone {repo_url}'
# 特殊处理:包含"到本地""到工作区"→只保留 git clone url
cmd = re.sub(r'(\s+(到本地|到工作区|到workspace).*)', '', cmd).strip()
workdir = ctx.get('workspace_dir', '') or '/d/pipeline/workspaces'
result = await shell_exec(cmd, workdir=workdir, timeout=120 if 'git clone' in cmd else 60)
# git clone already exists → git pull
if result['rc'] != 0 and 'already exists' in result.get('stderr', '') and repo_target and cmd.startswith('git clone'):
pull_dir = os.path.join(workdir, repo_target) if not os.path.isabs(repo_target) else repo_target
debug(f'devops: clone already exists, pulling {pull_dir}')
result = await shell_exec(f'git -C {pull_dir} pull', workdir=workdir, timeout=60)
if result['rc'] == 0:
out = result['stdout'].strip()
agent_reply = f"执行成功。{'输出:' + out[:500] if out else '(无输出)'}"
else:
agent_reply = f"执行失败rc={result['rc']}{result['stderr'][:500] or result['stdout'][:500]}"
# 多步任务:如果 git clone 成功且消息中含有"技能""skill""安装",自动触发 skill_import
if result['rc'] == 0 and repo_target and re.search(r'(技能|skill|安装技能|导入技能)', message_text):
clone_dir = os.path.join(workdir, repo_target) if not os.path.isabs(repo_target) else repo_target
if os.path.isdir(clone_dir):
try:
import_result = await skill_import_git('', skills_dir='skills')
# skill_import_git 的 repo_url 为空时不 clone改用已有目录
from pipeline_service.init import _resolve_workdir
full_skills = os.path.join(clone_dir, 'skills')
if os.path.isdir(full_skills):
found = []
for entry in sorted(os.listdir(full_skills)):
entry_path = os.path.join(full_skills, entry)
if os.path.isdir(entry_path):
found.append(entry)
if found:
agent_reply += f'\n\n✅ 发现 {len(found)} 个技能:' + ', '.join(found[:15])
else:
agent_reply += '\n\n⚠ skills 目录下未找到技能子目录'
else:
agent_reply += '\n\n⚠ 仓库中无 skills 目录'
except Exception as e2:
debug(f'skill scan error: {e2}')
else:
# chat: general conversation
messages = await _build_context(sor, iteration_id or ctx['iteration_id'], '',