feat: devops智能——clone已存在自动pull + 多步任务(克隆→扫描技能)
This commit is contained in:
parent
9c84c3dcbc
commit
fb1b65f389
@ -878,29 +878,60 @@ if action == 'send_message':
|
|||||||
elif intent_type == 'devops':
|
elif intent_type == 'devops':
|
||||||
# 从自然语言中提取实际命令:剥前缀 + 识别 git URL 自动构造 git clone
|
# 从自然语言中提取实际命令:剥前缀 + 识别 git URL 自动构造 git clone
|
||||||
cmd = message_text.strip()
|
cmd = message_text.strip()
|
||||||
import re
|
import re, os
|
||||||
cmd = re.sub(r'^(执行命令[::]|运行[::]|帮我\s*|克隆仓库\s*|从.*克隆\s*)', '', cmd).strip()
|
cmd = re.sub(r'^(执行命令[::]|运行[::]|帮我\s*|克隆仓库\s*|从.*克隆\s*)', '', cmd).strip()
|
||||||
# 如果包含 git@ 或 https://...git 但没有 git clone 前缀,自动补全
|
# 如果包含 git@ 或 https://...git 但没有 git clone 前缀,自动补全
|
||||||
|
repo_url = None
|
||||||
|
repo_target = None
|
||||||
if re.search(r'(git@[\w.]+:[\w./-]+\.git|https?://[\w./-]+\.git)', cmd):
|
if re.search(r'(git@[\w.]+:[\w./-]+\.git|https?://[\w./-]+\.git)', cmd):
|
||||||
if not cmd.startswith('git '):
|
if not cmd.startswith('git '):
|
||||||
# 提取 URL 和可选目标路径
|
|
||||||
m = re.search(r'(git@[\w.]+:[\w./-]+\.git|https?://[\w./-]+\.git)', cmd)
|
m = re.search(r'(git@[\w.]+:[\w./-]+\.git|https?://[\w./-]+\.git)', cmd)
|
||||||
repo_url = m.group(0)
|
repo_url = m.group(0)
|
||||||
rest = cmd[m.end():].strip()
|
rest = cmd[m.end():].strip()
|
||||||
target = rest.split()[0] if rest else ''
|
target = rest.split()[0] if rest else ''
|
||||||
if target and not target.startswith('-'):
|
if target and not target.startswith('-'):
|
||||||
|
repo_target = target
|
||||||
cmd = f'git clone {repo_url} {target}'
|
cmd = f'git clone {repo_url} {target}'
|
||||||
else:
|
else:
|
||||||
|
repo_target = repo_url.rstrip('/').split('/')[-1].replace('.git', '')
|
||||||
cmd = f'git clone {repo_url}'
|
cmd = f'git clone {repo_url}'
|
||||||
# 特殊处理:包含"到本地""到工作区"→只保留 git clone url
|
# 特殊处理:包含"到本地""到工作区"→只保留 git clone url
|
||||||
cmd = re.sub(r'(\s+(到本地|到工作区|到workspace).*)', '', cmd).strip()
|
cmd = re.sub(r'(\s+(到本地|到工作区|到workspace).*)', '', cmd).strip()
|
||||||
workdir = ctx.get('workspace_dir', '') or '/d/pipeline/workspaces'
|
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)
|
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:
|
if result['rc'] == 0:
|
||||||
out = result['stdout'].strip()
|
out = result['stdout'].strip()
|
||||||
agent_reply = f"执行成功。{'输出:' + out[:500] if out else '(无输出)'}"
|
agent_reply = f"执行成功。{'输出:' + out[:500] if out else '(无输出)'}"
|
||||||
else:
|
else:
|
||||||
agent_reply = f"执行失败(rc={result['rc']}):{result['stderr'][:500] or result['stdout'][:500]}"
|
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:
|
else:
|
||||||
# chat: general conversation
|
# chat: general conversation
|
||||||
messages = await _build_context(sor, iteration_id or ctx['iteration_id'], '',
|
messages = await _build_context(sor, iteration_id or ctx['iteration_id'], '',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user