新增 `dws skill setup` 交互式安装命令,支持单产品(mono)和多产品(multi,标记为试验版)两种 skill 布局,并与开源 dws v1.0.30 命令对齐。 主要变更: - 骨架:skills/ 拆为 skills/mono/ 和 skills/multi/(29 个产品 skill),git rename 保留历史 - 命令:新增 `skill setup` cobra 子命令,支持 --mode、--target、--source、--yes,huh 交互 - multi 模式支持 -s/--skill、-x/--exclude 按产品选择 - 覆盖全部 14 个 agent home 目录(与 install.sh 一致) - 发布:install.sh / install.ps1 / post-goreleaser.sh 改读 skills/mono;dws-skills.zip 同时包含 mono 和 multi 内容;~/.dws 本地缓存 - 内容对齐:删除 8 个仅内部使用的产品 skill、dingtalk-a2a;修正 mono/multi 共 15+ 处命令引用以匹配 OSS dws v1.0.30;chat skill 从 dws-wukong 回移更新 - 漂移清理:物理删除 skill 文档中 OSS 未暴露的命令,true-fail 命令转为 caveat;--help diff 100% 覆盖审计 - 测试:新增 Layer A 静态命令调度验证 + Layer B 端到端 mock 调度验证 - 同步 main:drive 9 个命令同步到 mono/multi skill
113 lines
3.3 KiB
Python
113 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
用机器人向多个群批量发送相同消息(如日报提醒)
|
|
|
|
用法:
|
|
python bot_broadcast.py \
|
|
--robot-code <ROBOT_CODE> \
|
|
--chats "conv_id1,conv_id2,conv_id3" \
|
|
--title "日报提醒" \
|
|
--text "请大家今天下班前提交日报"
|
|
|
|
python bot_broadcast.py \
|
|
--robot-code <ROBOT_CODE> \
|
|
--chats-file groups.txt \
|
|
--title "周会通知" \
|
|
--text "明天下午3点周会"
|
|
|
|
python bot_broadcast.py --dry-run ...
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import subprocess
|
|
import argparse
|
|
from pathlib import Path
|
|
from typing import List, Any, Optional
|
|
|
|
|
|
def run_dws(
|
|
args: List[str], dry_run: bool = False,
|
|
) -> Optional[Any]:
|
|
cmd = ['dws'] + args
|
|
if dry_run:
|
|
print(f"[dry-run] {' '.join(cmd)}")
|
|
return {'dry_run': True}
|
|
try:
|
|
result = subprocess.run(
|
|
cmd, capture_output=True, text=True, timeout=60
|
|
)
|
|
if result.returncode != 0:
|
|
print(f" ✗ 错误:{result.stderr.strip()}")
|
|
return None
|
|
return json.loads(result.stdout)
|
|
except (subprocess.TimeoutExpired, json.JSONDecodeError,
|
|
FileNotFoundError) as e:
|
|
print(f" ✗ 错误:{e}")
|
|
return None
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description='向多个群批量发送机器人消息'
|
|
)
|
|
parser.add_argument(
|
|
'--robot-code', required=True, help='机器人 Code'
|
|
)
|
|
parser.add_argument('--chats', default='', help='会话 ID 列表')
|
|
parser.add_argument(
|
|
'--chats-file', default='',
|
|
help='会话 ID 文件 (每行一个)',
|
|
)
|
|
parser.add_argument('--title', required=True, help='消息标题')
|
|
parser.add_argument(
|
|
'--text', required=True, help='消息内容 Markdown'
|
|
)
|
|
parser.add_argument('--dry-run', action='store_true')
|
|
args = parser.parse_args()
|
|
|
|
chat_ids: List[str] = []
|
|
if args.chats:
|
|
chat_ids = [c.strip() for c in args.chats.split(',')
|
|
if c.strip()]
|
|
elif args.chats_file:
|
|
p = Path(args.chats_file)
|
|
if not p.exists():
|
|
print(f"错误:文件不存在: {p}")
|
|
sys.exit(1)
|
|
chat_ids = [line.strip() for line in
|
|
p.read_text(encoding='utf-8').splitlines()
|
|
if line.strip() and not line.startswith('#')]
|
|
if not chat_ids:
|
|
print('错误:需要 --chats 或 --chats-file')
|
|
sys.exit(1)
|
|
|
|
print(f"📢 批量发送消息到 {len(chat_ids)} 个群")
|
|
print(f" 标题: {args.title}")
|
|
print(f" 机器人: {args.robot_code}")
|
|
print('=' * 50)
|
|
|
|
success, fail = 0, 0
|
|
for i, chat_id in enumerate(chat_ids, 1):
|
|
result = run_dws([
|
|
'chat', 'message', 'send-by-bot',
|
|
'--robot-code', args.robot_code,
|
|
'--group', chat_id,
|
|
'--title', args.title,
|
|
'--text', args.text,
|
|
'--format', 'json',
|
|
], dry_run=args.dry_run)
|
|
if result:
|
|
print(f" ✓ [{i}/{len(chat_ids)}] {chat_id}")
|
|
success += 1
|
|
else:
|
|
print(f" ✗ [{i}/{len(chat_ids)}] {chat_id}")
|
|
fail += 1
|
|
|
|
print(f"\n完成: 成功 {success}, 失败 {fail}")
|
|
sys.exit(0 if fail == 0 else 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|